Add simple Resource manager, fix isInside for rotated elements, optimize/fix mouse/touch inputs, refactor and optimize a lot of classes

This commit is contained in:
Maschell 2020-09-04 18:36:19 +02:00
parent afe7035e07
commit 158d97cf23
40 changed files with 2458 additions and 351 deletions

View File

@ -8,14 +8,14 @@ add_executable(${PROJECT_NAME}
src/gui/GuiElement.h src/gui/GuiElement.h
src/gui/GuiFrame.cpp src/gui/GuiFrame.cpp
src/gui/GuiFrame.h src/gui/GuiFrame.h
src/gui/GuiImage.cpp
src/gui/GuiImage.h
src/gui/sigslot.h src/gui/sigslot.h
src/system/SDLSystem.cpp src/system/SDLSystem.cpp
src/system/SDLSystem.h src/system/SDLSystem.h
src/gui/GuiElement.cpp src/gui/GuiElement.cpp
src/gui/GuiText.cpp src/gui/GuiText.cpp
src/gui/GuiText.h src/gui/GuiText.h
src/gui/GuiImage.cpp
src/gui/GuiImage.h
src/gui/GuiSound.cpp src/gui/GuiSound.cpp
src/gui/GuiSound.h src/gui/GuiSound.h
src/gui/GuiTrigger.cpp src/gui/GuiTrigger.cpp
@ -23,12 +23,16 @@ add_executable(${PROJECT_NAME}
src/gui/GuiController.h src/gui/GuiController.h
src/gui/GuiButton.cpp src/gui/GuiButton.cpp
src/gui/GuiButton.h src/gui/GuiButton.h
src/resources/Resources.cpp
src/resources/Resources.h
src/fs/CFile.cpp
src/fs/CFile.hpp
src/fs/FSUtils.cpp
src/fs/FSUtils.h
src/input/SDLController.h src/menu/MainWindow.cpp src/menu/MainWindow.h src/input/SDLControllerJoystick.h src/input/SDLControllerMouse.h src/input/SDLController.h src/menu/MainWindow.cpp src/menu/MainWindow.h src/input/SDLControllerJoystick.h src/input/SDLControllerMouse.h
src/input/SDLControllerWiiUGamepad.h src/input/SDLControllerWiiUGamepad.h
src/input/SDLControllerWiiUProContoller.h src/input/SDLControllerWiiUProContoller.h
src/gui/GuiTexture.cpp src/gui/GuiTexture.h src/gui/GuiTextureData.cpp src/gui/GuiTextureData.h
src/system/video/SDL_FontCache.h src/system/video/SDL_FontCache.h
src/system/video/SDL_FontCache.cpp src/system/video/SDL_FontCache.cpp

View File

@ -22,12 +22,17 @@ TARGET := SDL2_Playground
BUILD := build BUILD := build
SOURCES := src \ SOURCES := src \
src/gui \ src/gui \
src/fs \
src/input \ src/input \
src/menu \ src/menu \
src/resources \
src/system \ src/system \
src/system/video \ src/system/video \
src/utils src/utils
DATA := data DATA := data \
data/images \
data/sounds \
data/fonts
INCLUDES := source INCLUDES := source
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
@ -45,14 +50,12 @@ LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map)
LIBS := `$(PREFIX)pkg-config --libs SDL2_mixer SDL2_ttf SDL2_image` LIBS := `$(PREFIX)pkg-config --libs SDL2_mixer SDL2_ttf SDL2_image`
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level # list of directories containing libraries, this must be the top level
# containing include and lib # containing include and lib
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(WUT_ROOT) $(WUMS_ROOT) LIBDIRS := $(PORTLIBS) $(WUT_ROOT) $(WUMS_ROOT)
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional # no real need to edit anything past this point unless you need to add additional
# rules for different file extensions # rules for different file extensions
@ -68,6 +71,7 @@ export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
export DEPSDIR := $(CURDIR)/$(BUILD) export DEPSDIR := $(CURDIR)/$(BUILD)
FILELIST := $(shell bash ./filelist.sh)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
@ -138,6 +142,26 @@ $(OFILES_SRC) : $(HFILES_BIN)
@echo $(notdir $<) @echo $(notdir $<)
@$(bin2o) @$(bin2o)
%.png.o %_png.h : %.png
@echo $(notdir $<)
@$(bin2o)
%.jpg.o %_jpg.h : %.jpg
@echo $(notdir $<)
@$(bin2o)
%.ogg.o %_ogg.h : %.ogg
@echo $(notdir $<)
@$(bin2o)
%.mp3.o %_mp3.h : %.mp3
@echo $(notdir $<)
@$(bin2o)
%.ttf.o %_ttf.h : %.ttf
@echo $(notdir $<)
@$(bin2o)
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
%.o: %.s %.o: %.s
@echo $(notdir $<) @echo $(notdir $<)

BIN
data/fonts/FreeSans.ttf Normal file

Binary file not shown.

BIN
data/images/button.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
data/sounds/bgMusic.ogg Normal file

Binary file not shown.

Binary file not shown.

91
filelist.sh Normal file
View File

@ -0,0 +1,91 @@
#! /bin/bash
#
# Automatic resource file list generation
# Created by Dimok
outFile="./src/resources/filelist.h"
count_old=$(cat $outFile 2>/dev/null | tr -d '\n\n' | sed 's/[^0-9]*\([0-9]*\).*/\1/')
count=0
if [[ $OSTYPE == darwin* ]];
then
for i in $(gfind ./data/images/ ./data/sounds/ ./data/fonts/ -maxdepth 1 -type f \( ! -printf "%f\n" \) | sort -f)
do
files[count]=$i
count=$((count+1))
done
else
for i in $(find ./data/images/ ./data/sounds/ ./data/fonts/ -maxdepth 1 -type f \( ! -printf "%f\n" \) | sort -f)
do
files[count]=$i
count=$((count+1))
done
fi
if [ "$count_old" != "$count" ] || [ ! -f $outFile ]
then
echo "Generating filelist.h for $count files." >&2
cat <<EOF > $outFile
/****************************************************************************
* Resource files.
* This file is generated automatically.
* Includes $count files.
*
* NOTE:
* Any manual modification of this file will be overwriten by the generation.
****************************************************************************/
#ifndef _FILELIST_H_
#define _FILELIST_H_
#include "Resources.h"
#ifdef __WIIU__
EOF
for i in ${files[@]}
do
filename=${i%.*}
extension=${i##*.}
echo '#include "'$filename'_'$extension'.h"' >> $outFile
done
echo '' >> $outFile
echo 'static RecourceFile RecourceList[] =' >> $outFile
echo '{' >> $outFile
for i in ${files[@]}
do
filename=${i%.*}
extension=${i##*.}
echo -e '\t{"'$i'", '$filename'_'$extension', '$filename'_'$extension'_size, NULL, 0},' >> $outFile
done
echo -e '\t{NULL, NULL, 0, NULL, 0}' >> $outFile
echo '};' >> $outFile
echo '' >> $outFile
echo '#else' >> $outFile
echo 'static RecourceFile RecourceList[] =' >> $outFile
echo '{' >> $outFile
for i in ${files[@]}
do
filename=${i%.*}
extension=${i##*.}
echo -e '\t{"'$i'", NULL, NULL, NULL, 0},' >> $outFile
done
echo -e '\t{NULL, NULL, 0, NULL, 0}' >> $outFile
echo '};' >> $outFile
echo '' >> $outFile
echo '#endif' >> $outFile
echo '#endif' >> $outFile
fi

173
src/fs/CFile.cpp Normal file
View File

@ -0,0 +1,173 @@
#include <cstdarg>
#include <cstdio>
#include <strings.h>
#include "CFile.hpp"
CFile::CFile() {
iFd = -1;
mem_file = NULL;
filesize = 0;
pos = 0;
}
CFile::CFile(const std::string &filepath, eOpenTypes mode) {
iFd = -1;
this->open(filepath, mode);
}
CFile::CFile(const uint8_t *mem, int32_t size) {
iFd = -1;
this->open(mem, size);
}
CFile::~CFile() {
this->close();
}
int32_t CFile::open(const std::string &filepath, eOpenTypes mode) {
this->close();
int32_t openMode = 0;
// This depend on the devoptab implementation.
// see https://github.com/devkitPro/wut/blob/master/libraries/wutdevoptab/devoptab_fs_open.c#L21 fpr reference
switch (mode) {
default:
case ReadOnly: // file must exist
openMode = O_RDONLY;
break;
case WriteOnly: // file will be created / zerod
openMode = O_TRUNC | O_CREAT | O_WRONLY;
break;
case ReadWrite: // file must exist
openMode = O_RDWR;
break;
case Append: // append to file, file will be created if missing. write only
openMode = O_CREAT | O_APPEND | O_WRONLY;
break;
}
//! Using fopen works only on the first launch as expected
//! on the second launch it causes issues because we don't overwrite
//! the .data sections which is needed for a normal application to re-init
//! this will be added with launching as RPX
iFd = ::open(filepath.c_str(), openMode);
if (iFd < 0)
return iFd;
filesize = ::lseek(iFd, 0, SEEK_END);
::lseek(iFd, 0, SEEK_SET);
return 0;
}
int32_t CFile::open(const uint8_t *mem, int32_t size) {
this->close();
mem_file = mem;
filesize = size;
return 0;
}
void CFile::close() {
if (iFd >= 0)
::close(iFd);
iFd = -1;
mem_file = NULL;
filesize = 0;
pos = 0;
}
int32_t CFile::read(uint8_t *ptr, size_t size) {
if (iFd >= 0) {
int32_t ret = ::read(iFd, ptr, size);
if (ret > 0)
pos += ret;
return ret;
}
int32_t readsize = size;
if (readsize > (int64_t) (filesize - pos))
readsize = filesize - pos;
if (readsize <= 0)
return readsize;
if (mem_file != NULL) {
memcpy(ptr, mem_file + pos, readsize);
pos += readsize;
return readsize;
}
return -1;
}
int32_t CFile::write(const uint8_t *ptr, size_t size) {
if (iFd >= 0) {
size_t done = 0;
while (done < size) {
int32_t ret = ::write(iFd, ptr, size - done);
if (ret <= 0)
return ret;
ptr += ret;
done += ret;
pos += ret;
}
return done;
}
return -1;
}
int32_t CFile::seek(long int offset, int32_t origin) {
int32_t ret = 0;
int64_t newPos = pos;
if (origin == SEEK_SET) {
newPos = offset;
} else if (origin == SEEK_CUR) {
newPos += offset;
} else if (origin == SEEK_END) {
newPos = filesize + offset;
}
if (newPos < 0) {
pos = 0;
} else {
pos = newPos;
}
if (iFd >= 0)
ret = ::lseek(iFd, pos, SEEK_SET);
if (mem_file != NULL) {
if (pos > filesize) {
pos = filesize;
}
}
return ret;
}
int32_t CFile::fwrite(const char *format, ...) {
char tmp[512];
tmp[0] = 0;
int32_t result = -1;
va_list va;
va_start(va, format);
if ((vsprintf(tmp, format, va) >= 0)) {
result = this->write((uint8_t *) tmp, strlen(tmp));
}
va_end(va);
return result;
}

67
src/fs/CFile.hpp Normal file
View File

@ -0,0 +1,67 @@
#pragma once
#include <cstdio>
#include <string>
#include <cstring>
#include <fcntl.h>
#include <unistd.h>
class CFile {
public:
enum eOpenTypes {
ReadOnly,
WriteOnly,
ReadWrite,
Append
};
CFile();
CFile(const std::string &filepath, eOpenTypes mode);
CFile(const uint8_t *memory, int32_t memsize);
virtual ~CFile();
int32_t open(const std::string &filepath, eOpenTypes mode);
int32_t open(const uint8_t *memory, int32_t memsize);
int32_t isOpen() const {
if (iFd >= 0)
return true;
if (mem_file)
return true;
return false;
}
void close();
int32_t read(uint8_t *ptr, size_t size);
int32_t write(const uint8_t *ptr, size_t size);
int32_t fwrite(const char *format, ...);
int32_t seek(long int offset, int32_t origin);
uint64_t tell() {
return pos;
};
uint64_t size() {
return filesize;
};
void rewind() {
this->seek(0, SEEK_SET);
};
protected:
int32_t iFd;
const uint8_t *mem_file;
uint64_t filesize;
uint64_t pos;
};

190
src/fs/FSUtils.cpp Normal file
View File

@ -0,0 +1,190 @@
#include <malloc.h>
#include <cstring>
#include <cstdio>
#include <unistd.h>
#include <fcntl.h>
#include "FSUtils.h"
#include "CFile.hpp"
#ifdef WIN32
#include "../utils/dirent.h"
#endif
int32_t FSUtils::LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size) {
//! always initialze input
*inbuffer = nullptr;
if (size)
*size = 0;
#ifdef _WIN32
int32_t iFd = open(filepath, O_RDONLY|O_BINARY);
#else
int32_t iFd = open(filepath, O_RDONLY);
#endif
if (iFd < 0){
return -1;
}
uint32_t filesize = lseek(iFd, 0, SEEK_END);
lseek(iFd, 0, SEEK_SET);
uint8_t *buffer = (uint8_t *) malloc(filesize);
if (buffer == nullptr) {
close(iFd);
return -2;
}
uint32_t blocksize = 0x4000;
uint32_t done = 0;
int32_t readBytes = 0;
while (done < filesize) {
if (done + blocksize > filesize) {
blocksize = filesize - done;
}
readBytes = read(iFd, buffer + done, blocksize);
if (readBytes <= 0)
break;
done += readBytes;
}
close(iFd);
if (done != filesize) {
free(buffer);
buffer = nullptr;
return -3;
}
*inbuffer = buffer;
//! sign is optional input
if (size) {
*size = filesize;
}
return filesize;
}
int32_t FSUtils::CheckFile(const char *filepath) {
if (!filepath)
return 0;
struct stat filestat;
char dirnoslash[strlen(filepath) + 2];
snprintf(dirnoslash, sizeof(dirnoslash), "%s", filepath);
while (dirnoslash[strlen(dirnoslash) - 1] == '/')
dirnoslash[strlen(dirnoslash) - 1] = '\0';
char *notRoot = strrchr(dirnoslash, '/');
if (!notRoot) {
strcat(dirnoslash, "/");
}
if (stat(dirnoslash, &filestat) == 0)
return 1;
return 0;
}
int32_t FSUtils::CreateSubfolder(const char *fullpath) {
if (!fullpath)
return 0;
int32_t result = 0;
char dirnoslash[strlen(fullpath) + 1];
strcpy(dirnoslash, fullpath);
int32_t pos = strlen(dirnoslash) - 1;
while (dirnoslash[pos] == '/') {
dirnoslash[pos] = '\0';
pos--;
}
if (CheckFile(dirnoslash)) {
return 1;
} else {
char parentpath[strlen(dirnoslash) + 2];
strcpy(parentpath, dirnoslash);
char *ptr = strrchr(parentpath, '/');
if (!ptr) {
//!Device root directory (must be with '/')
strcat(parentpath, "/");
struct stat filestat;
if (stat(parentpath, &filestat) == 0)
return 1;
return 0;
}
ptr++;
ptr[0] = '\0';
result = CreateSubfolder(parentpath);
}
if (!result)
return 0;
#ifdef _WIN32
if (mkdir(dirnoslash) == -1) {
return 0;
}
#else
if (mkdir(dirnoslash, 0777) == -1) {
return 0;
}
#endif
return 1;
}
bool FSUtils::copyFile(const std::string &in, const std::string &out) {
// Using C++ buffers is **really** slow. Copying in 1023 byte chunks.
// Let's do it the old way.
size_t size;
int source = open(in.c_str(), O_RDONLY, 0);
int dest = open(out.c_str(), 0x602, 0644);
if (source < 0) {
return false;
}
if (dest < 0) {
close(source);
return false;
}
auto bufferSize = 1024 * 1024;
char *buf = (char *) malloc(bufferSize);
if (buf == NULL) {
return false;
}
while ((size = read(source, buf, bufferSize)) > 0) {
write(dest, buf, size);
}
free(buf);
close(source);
close(dest);
return true;
}
int32_t FSUtils::saveBufferToFile(const char *path, void *buffer, uint32_t size) {
CFile file(path, CFile::WriteOnly);
if (!file.isOpen()) {
return -1;
}
int32_t written = file.write((const uint8_t *) buffer, size);
file.close();
return written;
}

16
src/fs/FSUtils.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include <string>
class FSUtils {
public:
static int32_t LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size);
static int32_t CreateSubfolder(const char *fullpath);
static int32_t CheckFile(const char *filepath);
static bool copyFile(const std::string &in, const std::string &out);
static int32_t saveBufferToFile(const char *path, void *buffer, uint32_t size);
};

View File

@ -25,28 +25,28 @@
GuiButton::GuiButton(float w, float h) { GuiButton::GuiButton(float w, float h) {
width = w; width = w;
height = h; height = h;
image = NULL; image = nullptr;
imageOver = NULL; imageOver = nullptr;
imageHold = NULL; imageHold = nullptr;
imageClick = NULL; imageClick = nullptr;
icon = NULL; icon = nullptr;
iconOver = NULL; iconOver = nullptr;
for (int32_t i = 0; i < 4; i++) { for (int32_t i = 0; i < 4; i++) {
label[i] = NULL; label[i] = nullptr;
labelOver[i] = NULL; labelOver[i] = nullptr;
labelHold[i] = NULL; labelHold[i] = nullptr;
labelClick[i] = NULL; labelClick[i] = nullptr;
} }
for (int32_t i = 0; i < iMaxGuiTriggers; i++) { for (auto &i : trigger) {
trigger[i] = NULL; i = nullptr;
} }
soundOver = NULL; soundOver = nullptr;
soundHold = NULL; soundHold = nullptr;
soundClick = NULL; soundClick = nullptr;
clickedTrigger = NULL; clickedTrigger = nullptr;
heldTrigger = NULL; heldTrigger = nullptr;
selectable = true; selectable = true;
holdable = false; holdable = false;
clickable = true; clickable = true;
@ -55,8 +55,7 @@ GuiButton::GuiButton(float w, float h) {
/** /**
* Destructor for the GuiButton class. * Destructor for the GuiButton class.
*/ */
GuiButton::~GuiButton() { GuiButton::~GuiButton() = default;
}
void GuiButton::setImage(GuiImage *img) { void GuiButton::setImage(GuiImage *img) {
image = img; image = img;
@ -124,9 +123,9 @@ void GuiButton::setTrigger(GuiTrigger *t, int32_t idx) {
if (idx >= 0 && idx < iMaxGuiTriggers) { if (idx >= 0 && idx < iMaxGuiTriggers) {
trigger[idx] = t; trigger[idx] = t;
} else { } else {
for (int32_t i = 0; i < iMaxGuiTriggers; i++) { for (auto &i : trigger) {
if (!trigger[i]) { if (!i) {
trigger[i] = t; i = t;
break; break;
} }
} }
@ -134,8 +133,8 @@ void GuiButton::setTrigger(GuiTrigger *t, int32_t idx) {
} }
void GuiButton::resetState() { void GuiButton::resetState() {
clickedTrigger = NULL; clickedTrigger = nullptr;
heldTrigger = NULL; heldTrigger = nullptr;
GuiElement::resetState(); GuiElement::resetState();
} }
@ -213,21 +212,21 @@ void GuiButton::update(GuiController *c) {
} }
} }
for (int32_t i = 0; i < iMaxGuiTriggers; i++) { for (auto & i : trigger) {
if (!trigger[i]) { if (!i) {
continue; continue;
} }
// button triggers // button triggers
if (clickable) { if (clickable) {
int32_t isClicked = trigger[i]->clicked(c); int32_t isClicked = i->clicked(c);
if (!clickedTrigger && (isClicked != GuiTrigger::CLICKED_NONE) if (!clickedTrigger && (isClicked != GuiTrigger::CLICKED_NONE)
&& (trigger[i]->isClickEverywhere() || (isStateSet(STATE_SELECTED | STATE_OVER, c->chanIdx) && trigger[i]->isSelectionClickEverywhere()) || this->isInside(c->data.x, c->data.y))) { && (i->isClickEverywhere() || (isStateSet(STATE_SELECTED | STATE_OVER, c->chanIdx) && i->isSelectionClickEverywhere()) || this->isInside(c->data.x, c->data.y))) {
if (soundClick) { if (soundClick) {
soundClick->Play(); soundClick->Play();
} }
clickedTrigger = trigger[i]; clickedTrigger = i;
if (!isStateSet(STATE_CLICKED, c->chanIdx)) { if (!isStateSet(STATE_CLICKED, c->chanIdx)) {
if (isClicked == GuiTrigger::CLICKED_TOUCH) { if (isClicked == GuiTrigger::CLICKED_TOUCH) {
@ -237,38 +236,38 @@ void GuiButton::update(GuiController *c) {
} }
} }
clicked(this, c, trigger[i]); clicked(this, c, i);
} else if ((isStateSet(STATE_CLICKED, c->chanIdx) || isStateSet(STATE_CLICKED_TOUCH, c->chanIdx)) && (clickedTrigger == trigger[i]) && !isStateSet(STATE_HELD, c->chanIdx) && !trigger[i]->held(c) && } else if ((isStateSet(STATE_CLICKED, c->chanIdx) || isStateSet(STATE_CLICKED_TOUCH, c->chanIdx)) && (clickedTrigger == i) && !isStateSet(STATE_HELD, c->chanIdx) && !i->held(c) &&
((isClicked == GuiTrigger::CLICKED_NONE) || trigger[i]->released(c))) { ((isClicked == GuiTrigger::CLICKED_NONE) || i->released(c))) {
if ((isStateSet(STATE_CLICKED_TOUCH, c->chanIdx) && this->isInside(c->data.x, c->data.y)) || (isStateSet(STATE_CLICKED, c->chanIdx))) { if ((isStateSet(STATE_CLICKED_TOUCH, c->chanIdx) && this->isInside(c->data.x, c->data.y)) || (isStateSet(STATE_CLICKED, c->chanIdx))) {
clickedTrigger = nullptr; clickedTrigger = nullptr;
clearState(STATE_CLICKED, c->chanIdx); clearState(STATE_CLICKED, c->chanIdx);
released(this, c, trigger[i]); released(this, c, i);
} }
} }
} }
if (holdable) { if (holdable) {
bool isHeld = trigger[i]->held(c); bool isHeld = i->held(c);
if ((!heldTrigger || heldTrigger == trigger[i]) && isHeld if ((!heldTrigger || heldTrigger == i) && isHeld
&& (trigger[i]->isHoldEverywhere() || (isStateSet(STATE_SELECTED | STATE_OVER, c->chanIdx) && trigger[i]->isSelectionClickEverywhere()) || this->isInside(c->data.x, c->data.y))) { && (i->isHoldEverywhere() || (isStateSet(STATE_SELECTED | STATE_OVER, c->chanIdx) && i->isSelectionClickEverywhere()) || this->isInside(c->data.x, c->data.y))) {
heldTrigger = trigger[i]; heldTrigger = i;
if (!isStateSet(STATE_HELD, c->chanIdx)) { if (!isStateSet(STATE_HELD, c->chanIdx)) {
setState(STATE_HELD, c->chanIdx); setState(STATE_HELD, c->chanIdx);
} }
held(this, c, trigger[i]); held(this, c, i);
} else if (isStateSet(STATE_HELD, c->chanIdx) && (heldTrigger == trigger[i]) && (!isHeld || trigger[i]->released(c))) { } else if (isStateSet(STATE_HELD, c->chanIdx) && (heldTrigger == i) && (!isHeld || i->released(c))) {
//! click is removed at this point and converted to held //! click is removed at this point and converted to held
if (clickedTrigger == trigger[i]) { if (clickedTrigger == i) {
clickedTrigger = nullptr; clickedTrigger = nullptr;
clearState(STATE_CLICKED, c->chanIdx); clearState(STATE_CLICKED, c->chanIdx);
} }
heldTrigger = nullptr; heldTrigger = nullptr;
clearState(STATE_HELD, c->chanIdx); clearState(STATE_HELD, c->chanIdx);
released(this, c, trigger[i]); released(this, c, i);
} }
} }
} }

View File

@ -61,7 +61,7 @@ public:
int32_t y; int32_t y;
} PadData; } PadData;
int32_t chan; uint32_t chan;
int32_t chanIdx; int32_t chanIdx;
PadData data; PadData data;
PadData lastData; PadData lastData;

View File

@ -33,11 +33,11 @@ GuiElement::GuiElement() {
scaleX = 1.0f; scaleX = 1.0f;
scaleY = 1.0f; scaleY = 1.0f;
scaleZ = 1.0f; scaleZ = 1.0f;
for (int32_t i = 0; i < 5; i++) { for (unsigned int & i : state) {
state[i] = STATE_DEFAULT; i = STATE_DEFAULT;
} }
stateChan = -1; stateChan = -1;
parentElement = NULL; parentElement = nullptr;
rumble = true; rumble = true;
selectable = false; selectable = false;
clickable = false; clickable = false;
@ -120,7 +120,7 @@ float GuiElement::getTop() {
return y + yoffset; return y + yoffset;
} }
void GuiElement::setEffect(int32_t eff, int32_t amount, int32_t target) { void GuiElement::setEffect(uint32_t eff, int32_t amount, int32_t target) {
if (eff & EFFECT_SLIDE_IN) { if (eff & EFFECT_SLIDE_IN) {
// these calculations overcompensate a little // these calculations overcompensate a little
if (eff & EFFECT_SLIDE_TOP) { if (eff & EFFECT_SLIDE_TOP) {
@ -163,7 +163,7 @@ void GuiElement::setEffect(int32_t eff, int32_t amount, int32_t target) {
//!\param e Effect to enable //!\param e Effect to enable
//!\param a Amount of the effect (usage varies on effect) //!\param a Amount of the effect (usage varies on effect)
//!\param t Target amount of the effect (usage varies on effect) //!\param t Target amount of the effect (usage varies on effect)
void GuiElement::setEffectOnOver(int32_t e, int32_t a, int32_t t) { void GuiElement::setEffectOnOver(uint32_t e, int32_t a, int32_t t) {
effectsOver |= e; effectsOver |= e;
effectAmountOver = a; effectAmountOver = a;
effectTargetOver = t; effectTargetOver = t;

View File

@ -69,7 +69,7 @@ public:
GuiElement(); GuiElement();
//!Destructor //!Destructor
virtual ~GuiElement() {} virtual ~GuiElement() = default;
//!Set the element's parent //!Set the element's parent
//!\param e Pointer to parent element //!\param e Pointer to parent element
@ -105,7 +105,7 @@ public:
return zParent + zoffset; return zParent + zoffset;
} }
virtual float getCenterX(void) { virtual float getCenterX() {
float pCenterX = 0.0f; float pCenterX = 0.0f;
if (parentElement) { if (parentElement) {
@ -138,7 +138,7 @@ public:
return pCenterX; return pCenterX;
} }
virtual float getCenterY(void) { virtual float getCenterY() {
float pCenterY = 0.0f; float pCenterY = 0.0f;
if (parentElement) { if (parentElement) {
@ -261,7 +261,7 @@ public:
//!Sets the element's state //!Sets the element's state
//!\param s State (STATE_DEFAULT, STATE_SELECTED, STATE_CLICKED, STATE_DISABLED) //!\param s State (STATE_DEFAULT, STATE_SELECTED, STATE_CLICKED, STATE_DISABLED)
//!\param c Controller channel (0-3, -1 = none) //!\param c Controller channel (0-3, -1 = none)
virtual void setState(int32_t s, int32_t c = -1) { virtual void setState(uint32_t s, int32_t c) {
if (c >= 0 && c < 5) { if (c >= 0 && c < 5) {
state[c] |= s; state[c] |= s;
} else { } else {
@ -273,24 +273,24 @@ public:
stateChanged(this, s, c); stateChanged(this, s, c);
} }
virtual void clearState(int32_t s, int32_t c = -1) { virtual void clearState(uint32_t s, int32_t c) {
if (c >= 0 && c < 5) { if (c >= 0 && c < 5) {
state[c] &= ~s; state[c] &= ~s;
} else { } else {
for (int32_t i = 0; i < 5; i++) { for (unsigned int & i : state) {
state[i] &= ~s; i &= ~s;
} }
} }
stateChan = c; stateChan = c;
stateChanged(this, s, c); stateChanged(this, s, c);
} }
virtual bool isStateSet(int32_t s, int32_t c = -1) const { virtual bool isStateSet(uint32_t s, int32_t c = -1) const {
if (c >= 0 && c < 5) { if (c >= 0 && c < 5) {
return (state[c] & s) != 0; return (state[c] & s) != 0;
} else { } else {
for (int32_t i = 0; i < 5; i++) { for (unsigned int i : state) {
if ((state[i] & s) != 0) { if ((i & s) != 0) {
return true; return true;
} }
} }
@ -301,7 +301,7 @@ public:
//!Gets the element's current state //!Gets the element's current state
//!\return state //!\return state
virtual int32_t getState(int32_t c = 0) { virtual int32_t getState(int32_t c) {
return state[c]; return state[c];
}; };
@ -313,8 +313,8 @@ public:
//!Resets the element's state to STATE_DEFAULT //!Resets the element's state to STATE_DEFAULT
virtual void resetState() { virtual void resetState() {
for (int32_t i = 0; i < 5; i++) { for (unsigned int & i : state) {
state[i] = STATE_DEFAULT; i = STATE_DEFAULT;
} }
stateChan = -1; stateChan = -1;
} }
@ -434,13 +434,13 @@ public:
//!\param e Effect to enable //!\param e Effect to enable
//!\param a Amount of the effect (usage varies on effect) //!\param a Amount of the effect (usage varies on effect)
//!\param t Target amount of the effect (usage varies on effect) //!\param t Target amount of the effect (usage varies on effect)
virtual void setEffect(int32_t e, int32_t a, int32_t t = 0); virtual void setEffect(uint32_t e, int32_t a, int32_t t);
//!Sets an effect to be enabled on wiimote cursor over //!Sets an effect to be enabled on wiimote cursor over
//!\param e Effect to enable //!\param e Effect to enable
//!\param a Amount of the effect (usage varies on effect) //!\param a Amount of the effect (usage varies on effect)
//!\param t Target amount of the effect (usage varies on effect) //!\param t Target amount of the effect (usage varies on effect)
virtual void setEffectOnOver(int32_t e, int32_t a, int32_t t = 0); virtual void setEffectOnOver(uint32_t e, int32_t a, int32_t t);
//!Shortcut to SetEffectOnOver(EFFECT_SCALE, 4, 110) //!Shortcut to SetEffectOnOver(EFFECT_SCALE, 4, 110)
virtual void setEffectGrow() { virtual void setEffectGrow() {
@ -466,10 +466,30 @@ public:
//!\param y Y coordinate //!\param y Y coordinate
//!\return true if contained within, false otherwise //!\return true if contained within, false otherwise
virtual bool isInside(float x, float y) { virtual bool isInside(float x, float y) {
return (x > (this->getCenterX() - getScaleX() * getWidth() * 0.5f) float rotatedX = x;
&& x < (this->getCenterX() + getScaleX() * getWidth() * 0.5f) float rotatedY = y;
&& y > (this->getCenterY() - getScaleY() * getHeight() * 0.5f)
&& y < (this->getCenterY() + getScaleY() * getHeight() * 0.5f)); if (getAngle() != 0.f) {
// translate input point
float tempX = x - getCenterX();
float tempY = y - getCenterY();
// Conver to Rad
auto angleInRad = (float) ((getAngle() * -1.0f) * M_PI / 180.0f);
// now apply rotation
rotatedX = tempX * cos((angleInRad)) - tempY * sin(angleInRad);
rotatedY = tempX * sin(angleInRad) + tempY * cos(angleInRad);
// translate back
rotatedX = rotatedX + getCenterX();
rotatedY = rotatedY + getCenterY();
}
return (rotatedX > (this->getCenterX() - getScaleX() * getWidth() * 0.5f)
&& rotatedX < (this->getCenterX() + getScaleX() * getWidth() * 0.5f)
&& rotatedY > (this->getCenterY() - getScaleY() * getHeight() * 0.5f)
&& rotatedY < (this->getCenterY() + getScaleY() * getHeight() * 0.5f));
} }
//!Sets the element's position //!Sets the element's position
@ -586,8 +606,8 @@ protected:
float scaleX; //!< Element scale (1 = 100%) float scaleX; //!< Element scale (1 = 100%)
float scaleY; //!< Element scale (1 = 100%) float scaleY; //!< Element scale (1 = 100%)
float scaleZ; //!< Element scale (1 = 100%) float scaleZ; //!< Element scale (1 = 100%)
int32_t alignment; //!< Horizontal element alignment, respective to parent element uint32_t alignment; //!< Horizontal element alignment, respective to parent element
int32_t state[5]; //!< Element state (DEFAULT, SELECTED, CLICKED, DISABLED) uint32_t state[5]{}; //!< Element state (DEFAULT, SELECTED, CLICKED, DISABLED)
int32_t stateChan; //!< Which controller channel is responsible for the last change in state int32_t stateChan; //!< Which controller channel is responsible for the last change in state
GuiElement *parentElement; //!< Parent element GuiElement *parentElement; //!< Parent element
@ -596,10 +616,10 @@ protected:
int32_t yoffsetDyn; //!< Element Y offset, dynamic (added to yoffset value for animation effects) int32_t yoffsetDyn; //!< Element Y offset, dynamic (added to yoffset value for animation effects)
float alphaDyn; //!< Element alpha, dynamic (multiplied by alpha value for blending/fading effects) float alphaDyn; //!< Element alpha, dynamic (multiplied by alpha value for blending/fading effects)
float scaleDyn; //!< Element scale, dynamic (multiplied by alpha value for blending/fading effects) float scaleDyn; //!< Element scale, dynamic (multiplied by alpha value for blending/fading effects)
int32_t effects; //!< Currently enabled effect(s). 0 when no effects are enabled uint32_t effects; //!< Currently enabled effect(s). 0 when no effects are enabled
int32_t effectAmount; //!< Effect amount. Used by different effects for different purposes int32_t effectAmount; //!< Effect amount. Used by different effects for different purposes
int32_t effectTarget; //!< Effect target amount. Used by different effects for different purposes int32_t effectTarget; //!< Effect target amount. Used by different effects for different purposes
int32_t effectsOver; //!< Effects to enable when wiimote cursor is over this element. Copied to effects variable on over event uint32_t effectsOver; //!< Effects to enable when wiimote cursor is over this element. Copied to effects variable on over event
int32_t effectAmountOver; //!< EffectAmount to set when wiimote cursor is over this element int32_t effectAmountOver; //!< EffectAmount to set when wiimote cursor is over this element
int32_t effectTargetOver; //!< EffectTarget to set when wiimote cursor is over this element int32_t effectTargetOver; //!< EffectTarget to set when wiimote cursor is over this element
}; };

View File

@ -16,6 +16,7 @@
****************************************************************************/ ****************************************************************************/
#include "GuiFrame.h" #include "GuiFrame.h"
#include "../system/video/Renderer.h" #include "../system/video/Renderer.h"
#include "../utils/logger.h"
GuiFrame::GuiFrame(GuiFrame *p) { GuiFrame::GuiFrame(GuiFrame *p) {
parent = p; parent = p;
@ -48,9 +49,10 @@ GuiFrame::~GuiFrame() {
} }
void GuiFrame::append(GuiElement *e) { void GuiFrame::append(GuiElement *e) {
if (e == NULL) { if (e == nullptr) {
return; return;
} }
DEBUG_FUNCTION_LINE("append %08X", e);
remove(e); remove(e);
mutex.lock(); mutex.lock();
@ -60,7 +62,7 @@ void GuiFrame::append(GuiElement *e) {
} }
void GuiFrame::insert(GuiElement *e, uint32_t index) { void GuiFrame::insert(GuiElement *e, uint32_t index) {
if (e == NULL || (index >= elements.size())) { if (e == nullptr || (index >= elements.size())) {
return; return;
} }
@ -94,7 +96,7 @@ void GuiFrame::removeAll() {
GuiElement *GuiFrame::getGuiElementAt(uint32_t index) const { GuiElement *GuiFrame::getGuiElementAt(uint32_t index) const {
if (index >= elements.size()) { if (index >= elements.size()) {
return NULL; return nullptr;
} }
return elements[index]; return elements[index];
@ -108,13 +110,13 @@ void GuiFrame::resetState() {
GuiElement::resetState(); GuiElement::resetState();
mutex.lock(); mutex.lock();
for (uint32_t i = 0; i < elements.size(); ++i) { for (auto & element : elements) {
elements[i]->resetState(); element->resetState();
} }
mutex.unlock(); mutex.unlock();
} }
void GuiFrame::setState(int32_t s, int32_t c) { void GuiFrame::setState(uint32_t s, int32_t c) {
GuiElement::setState(s, c); GuiElement::setState(s, c);
mutex.lock(); mutex.lock();
for (uint32_t i = 0; i < elements.size(); ++i) { for (uint32_t i = 0; i < elements.size(); ++i) {
@ -123,7 +125,7 @@ void GuiFrame::setState(int32_t s, int32_t c) {
mutex.unlock(); mutex.unlock();
} }
void GuiFrame::clearState(int32_t s, int32_t c) { void GuiFrame::clearState(uint32_t s, int32_t c) {
GuiElement::clearState(s, c); GuiElement::clearState(s, c);
mutex.lock(); mutex.lock();
@ -137,8 +139,8 @@ void GuiFrame::setVisible(bool v) {
visible = v; visible = v;
mutex.lock(); mutex.lock();
for (uint32_t i = 0; i < elements.size(); ++i) { for (auto & element : elements) {
elements[i]->setVisible(v); element->setVisible(v);
} }
mutex.unlock(); mutex.unlock();
} }

View File

@ -76,9 +76,9 @@ public:
//!Sets the window's state //!Sets the window's state
//!\param s State //!\param s State
void setState(int32_t s, int32_t c = -1) override; void setState(uint32_t s, int32_t c = -1) override;
void clearState(int32_t s, int32_t c = -1) override; void clearState(uint32_t s, int32_t c = -1) override;
//!Gets the index of the GuiElement inside the window that is currently selected //!Gets the index of the GuiElement inside the window that is currently selected
//!\return index of selected GuiElement //!\return index of selected GuiElement

View File

@ -15,11 +15,40 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/ ****************************************************************************/
#include <SDL2/SDL_image.h> #include <SDL2/SDL_image.h>
#include <iostream>
#include "GuiImage.h" #include "GuiImage.h"
#include "../system/SDLSystem.h" #include "../utils/logger.h"
GuiImage::GuiImage(const std::string& path) : GuiTexture(path){ GuiImage::GuiImage(GuiTextureData *texture) {
setTexture(texture);
} }
GuiImage::~GuiImage() = default; GuiImage::~GuiImage() {
if(this->texture && freeTextureData){
delete this->texture;
}
}
void GuiImage::draw(Renderer *renderer) {
if (!this->isVisible()) {
return;
}
if (texture) {
SDL_Rect rect;
rect.x = (int) getLeft();
rect.y = (int) getTop();
rect.w = (int) (getScaleX() * getWidth());
rect.h = (int) (getScaleY() * getHeight());
texture->draw(renderer, rect, getAngle());
}
}
void GuiImage::setTexture(GuiTextureData *tex) {
if (tex) {
if(this->texture && freeTextureData){
delete this->texture;
}
this->texture = tex;
this->setSize(tex->getWidth(), tex->getHeight());
}
}

View File

@ -18,15 +18,24 @@
#include <SDL2/SDL_render.h> #include <SDL2/SDL_render.h>
#include "GuiElement.h" #include "GuiElement.h"
#include "GuiTexture.h" #include "GuiTextureData.h"
//!Display, manage, and manipulate images in the GUI //!Display, manage, and manipulate images in the GUI
class GuiImage : public GuiTexture { class GuiImage : public GuiElement {
public: public:
//!\overload //!\overload
//!\param img Pointer to GuiImageData element //!\param img Pointer to GuiImageData element
explicit GuiImage(const std::string &path); GuiImage() = default;
explicit GuiImage(GuiTextureData *texture);
//!Destructor //!Destructor
~GuiImage() override; ~GuiImage() override;
void draw(Renderer *r) override;
void setTexture(GuiTextureData *tex);
private:
GuiTextureData *texture = nullptr;
bool freeTextureData = false;
}; };

View File

@ -15,64 +15,65 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/ ****************************************************************************/
#include "GuiSound.h" #include "GuiSound.h"
#include "../utils/logger.h"
GuiSound::GuiSound(void *buffer, uint32_t filesize, bool freeSrc) {
SDL_RWops *rw = SDL_RWFromMem(buffer, filesize);
music = Mix_LoadWAV_RW(rw, freeSrc);
}
GuiSound::GuiSound(const char *filepath) { GuiSound::GuiSound(const char *filepath) {
Load(filepath); Load(filepath);
} }
GuiSound::~GuiSound() { GuiSound::~GuiSound() {
if(music){ if (music) {
Mix_FreeChunk(music); Mix_FreeChunk(music);
music = nullptr;
} }
} }
bool GuiSound::Load(const char *filepath) { bool GuiSound::Load(const char *filepath) {
music = Mix_LoadWAV(filepath); music = Mix_LoadWAV(filepath);
DEBUG_FUNCTION_LINE("load %s %d", filepath, music);
return music != nullptr; return music != nullptr;
} }
void GuiSound::Play() { void GuiSound::Play() {
playedOn = Mix_PlayChannel(-1,music, loops); if (music) {
playedOn = Mix_PlayChannel(-1, music, loops);
}
} }
void GuiSound::Stop() { void GuiSound::Stop() const {
Pause(); Pause();
} }
void GuiSound::Pause() { void GuiSound::Pause() const {
if (playedOn != -1) {
Mix_HaltChannel(playedOn); Mix_HaltChannel(playedOn);
}
} }
void GuiSound::Resume() { void GuiSound::Resume() {
Play(); Play();
} }
bool GuiSound::IsPlaying() { bool GuiSound::IsPlaying() const {
if(playedOn == -1){ if (playedOn == -1) {
return false; return false;
} }
return Mix_Playing(playedOn); return Mix_Playing(playedOn);
} }
void GuiSound::SetVolume(uint32_t vol) { void GuiSound::SetVolume(uint32_t vol) const {
if(music != nullptr){ if (music) { Mix_VolumeChunk(music, vol); }
Mix_VolumeChunk(music, vol);
}
} }
void GuiSound::SetLoop(bool l) { void GuiSound::SetLoop(bool l) {
if(l){ // < 0 == infinitive loop
loops = -1; loops = l ? -1 : 1;
}else{
loops = 1;
}
} }
void GuiSound::Rewind() { void GuiSound::Rewind() const {
// TODO: how to rewind?
Stop(); Stop();
} }

View File

@ -22,10 +22,12 @@
//!Sound conversion and playback. A wrapper for other sound libraries - ASND, libmad, ltremor, etc //!Sound conversion and playback. A wrapper for other sound libraries - ASND, libmad, ltremor, etc
class GuiSound : public GuiElement { class GuiSound : public GuiElement {
public: public:
explicit GuiSound(const char *filepath);
//!Constructor //!Constructor
//!\param sound Pointer to the sound data //!\param sound Pointer to the sound data
//!\param filesize Length of sound data //!\param filesize Length of sound data
explicit GuiSound(const char *filepath); GuiSound(void *buffer, uint32_t filesize, bool freeSrc = false);
//!Destructor //!Destructor
~GuiSound() override; ~GuiSound() override;
@ -37,29 +39,29 @@ public:
void Play(); void Play();
//!Stop sound playback //!Stop sound playback
void Stop(); void Stop() const;
//!Pause sound playback //!Pause sound playback
void Pause(); void Pause() const;
//!Resume sound playback //!Resume sound playback
void Resume(); void Resume();
//!Checks if the sound is currently playing //!Checks if the sound is currently playing
//!\return true if sound is playing, false otherwise //!\return true if sound is playing, false otherwise
bool IsPlaying(); [[nodiscard]] bool IsPlaying() const;
//!Rewind the music //!Rewind the music
void Rewind(); void Rewind() const;
//!Set sound volume //!Set sound volume
//!\param v Sound volume (0-100) //!\param v Sound volume (0-100)
void SetVolume(uint32_t v); void SetVolume(uint32_t v) const;
//!\param l Loop (true to loop) //!\param l Loop (true to loop)
void SetLoop(bool l); void SetLoop(bool l);
Mix_Chunk *music; Mix_Chunk *music = nullptr;
int32_t loops = 0; int32_t loops = 0;
int32_t playedOn = -1; int32_t playedOn = -1;
}; };

View File

@ -26,16 +26,12 @@ GuiText::GuiText(const std::string& text, SDL_Color c, FC_Font* gFont) {
this->text = text; this->text = text;
this->color = c; this->color = c;
this->fc_font = gFont; this->fc_font = gFont;
updateSize();
this->doUpdateTexture = true; this->doUpdateTexture = true;
this->texture.setParent(this);
} }
GuiText::~GuiText(){ GuiText::~GuiText() {
if(fc_font){ delete textureData;
FC_FreeFont(fc_font);
fc_font = nullptr;
}
delete texture;
} }
void GuiText::draw(Renderer *renderer) { void GuiText::draw(Renderer *renderer) {
@ -45,9 +41,7 @@ void GuiText::draw(Renderer *renderer) {
updateTexture(renderer); updateTexture(renderer);
if(texture){ texture.draw(renderer);
texture->draw(renderer);
}
} }
void GuiText::process() { void GuiText::process() {
@ -57,7 +51,7 @@ void GuiText::process() {
void GuiText::setMaxWidth(float width) { void GuiText::setMaxWidth(float width) {
this->maxWidth = width; this->maxWidth = width;
// Rebuild the texture cache. // Rebuild the texture cache on next draw
doUpdateTexture = true; doUpdateTexture = true;
} }
@ -69,20 +63,23 @@ void GuiText::updateSize() {
} }
void GuiText::updateTexture(Renderer *renderer) { void GuiText::updateTexture(Renderer *renderer) {
if(!texture || doUpdateTexture) { if(doUpdateTexture) {
updateSize(); updateSize();
int tex_width = tex_width = width == 0 ? 1 : (int) width;
int tex_height = tex_height = height == 0 ? 1 : (int)height;
SDL_Texture *temp = SDL_CreateTexture(renderer->getRenderer(), renderer->getPixelFormat(), SDL_TEXTUREACCESS_TARGET, (int) width, (int) height); SDL_Texture *temp = SDL_CreateTexture(renderer->getRenderer(), renderer->getPixelFormat(), SDL_TEXTUREACCESS_TARGET, tex_width, tex_height);
if (temp) { if (temp) {
delete texture; texture.setTexture(nullptr);
texture = new GuiTexture(temp); delete textureData;
texture->setParent(this); textureData = new GuiTextureData(temp);
texture->setBlendMode(SDL_BLENDMODE_BLEND); textureData->setBlendMode(SDL_BLENDMODE_BLEND);
texture.setTexture(textureData);
FC_DrawColumnToTexture(fc_font, temp, 0, 0, maxWidth, text.c_str()); FC_DrawColumnToTexture(fc_font, temp, 0, 0, maxWidth, text.c_str());
doUpdateTexture = false;
} else { } else {
DEBUG_FUNCTION_LINE("Failed to create texture"); DEBUG_FUNCTION_LINE("Failed to create texture");
} }
doUpdateTexture = false;
} }
} }

View File

@ -17,8 +17,9 @@
#pragma once #pragma once
#include "GuiElement.h" #include "GuiElement.h"
#include "GuiTexture.h" #include "GuiTextureData.h"
#include "../system/video/SDL_FontCache.h" #include "../system/video/SDL_FontCache.h"
#include "GuiImage.h"
#include <mutex> #include <mutex>
#include <SDL2/SDL_ttf.h> #include <SDL2/SDL_ttf.h>
@ -39,7 +40,9 @@ public:
void setMaxWidth(float width); void setMaxWidth(float width);
protected: protected:
GuiTexture* texture = nullptr; GuiImage texture;
GuiTextureData* textureData = nullptr;
std::string text; std::string text;
SDL_Color color; SDL_Color color;
FC_Font *fc_font = nullptr; FC_Font *fc_font = nullptr;

View File

@ -1,93 +0,0 @@
#include <SDL2/SDL_image.h>
#include "GuiTexture.h"
#include "../system/SDLSystem.h"
#include "../utils/logger.h"
GuiTexture::GuiTexture(const std::string& path) {
imgSurface = IMG_Load( path.c_str() );
if(!imgSurface){
return;
}
this->width = imgSurface->w;
this->height = imgSurface->h;
}
GuiTexture::GuiTexture(SDL_Texture *texture) {
if (this->texture) {
SDL_DestroyTexture(this->texture);
this->texture = NULL;
}
this->texture = texture;
int w, h;
SDL_QueryTexture(texture, nullptr, nullptr, &w, &h);
this->setSize(w, h);
}
GuiTexture::GuiTexture(SDL_Surface *pSurface) {
if(!pSurface){
return;
}
imgSurface = pSurface;
this->width = imgSurface->w;
this->height = imgSurface->h;
}
/**
* Destructor for the GuiImage class.
*/
GuiTexture::~GuiTexture() {
if (this->imgSurface) {
SDL_FreeSurface(this->imgSurface);
this->imgSurface = nullptr;
}
if (this->texture) {
SDL_DestroyTexture(this->texture);
this->texture = nullptr;
}
}
void GuiTexture::draw(Renderer *renderer) {
if (!this->isVisible()) {
DEBUG_FUNCTION_LINE("not visible!");
return;
}
if (texture == NULL && imgSurface) {
SDL_Surface *optimizedSurface = SDL_ConvertSurfaceFormat(imgSurface, renderer->getPixelFormat(), 0);
if (optimizedSurface != NULL) {
SDL_FreeSurface(imgSurface);
imgSurface = optimizedSurface;
DEBUG_FUNCTION_LINE("Optimized surface");
}
texture = SDL_CreateTextureFromSurface(renderer->getRenderer(), imgSurface);
}
if (!texture) {
DEBUG_FUNCTION_LINE("no texture!");
return;
}
float currScaleX = getScaleX();
float currScaleY = getScaleY();
SDL_Rect rect;
rect.x = getLeft();
rect.y = getTop();
rect.w = currScaleX * getWidth();
rect.h = currScaleY * getHeight();
if (getAngle() == 0) {
SDL_RenderCopy(renderer->getRenderer(), texture, nullptr, &rect);
} else {
SDL_RenderCopyEx(renderer->getRenderer(), texture, nullptr, &rect, getAngle(), nullptr, SDL_FLIP_NONE);
}
}
int GuiTexture::setBlendMode(SDL_BlendMode) {
if(texture){
return SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
}
return SDL_BLENDMODE_INVALID;
}

View File

@ -1,22 +0,0 @@
#pragma once
#include <SDL2/SDL_render.h>
#include "GuiElement.h"
class GuiTexture : public GuiElement {
public:
explicit GuiTexture(const std::string &path);
explicit GuiTexture(SDL_Texture * texture);
explicit GuiTexture(SDL_Surface *pSurface);
//!Destructor
~GuiTexture() override;
//!Constantly called to draw the image
void draw(Renderer *pVideo) override;
int setBlendMode(SDL_BlendMode blendMode);
protected:
SDL_Surface *imgSurface = nullptr;
SDL_Texture *texture = nullptr;
};

View File

@ -0,0 +1,87 @@
#include <SDL2/SDL_image.h>
#include "GuiTextureData.h"
#include "../system/SDLSystem.h"
#include "../utils/logger.h"
GuiTextureData::GuiTextureData(const std::string& path) {
SDL_Surface *surface = IMG_Load_RW(SDL_RWFromFile(path.c_str(), "rb"), 1);
loadSurface(surface);
}
GuiTextureData::GuiTextureData(void *buffer, const uint32_t filesize, bool freesrc) {
SDL_RWops *rw = SDL_RWFromMem(buffer, filesize);
SDL_Surface *surface = IMG_Load_RW(rw, freesrc);
loadSurface(surface);
}
GuiTextureData::GuiTextureData(SDL_Texture *texture) {
if (this->texture) {
SDL_DestroyTexture(this->texture);
this->texture = nullptr;
}
this->texture = texture;
int w, h;
SDL_QueryTexture(this->texture, nullptr, nullptr, &w, &h);
this->width = w;
this->height = h;
}
void GuiTextureData::loadSurface(SDL_Surface *pSurface) {
if(!pSurface){
return;
}
cleanUp();
imgSurface = pSurface;
this->width = imgSurface->w;
this->height = imgSurface->h;
}
void GuiTextureData::cleanUp() {
if (imgSurface) {
SDL_FreeSurface(imgSurface);
imgSurface = nullptr;
}
if (texture) {
SDL_DestroyTexture(texture);
texture = nullptr;
}
}
/**
* Destructor for the GuiImage class.
*/
GuiTextureData::~GuiTextureData() {
cleanUp();
}
void GuiTextureData::draw(Renderer *renderer, const SDL_Rect& dest, float angle) {
if (texture == nullptr && imgSurface) {
SDL_Surface *optimizedSurface = SDL_ConvertSurfaceFormat(imgSurface, renderer->getPixelFormat(), 0);
if (optimizedSurface != nullptr) {
SDL_FreeSurface(imgSurface);
imgSurface = optimizedSurface;
}
texture = SDL_CreateTextureFromSurface(renderer->getRenderer(), imgSurface);
}
if (!texture) {
DEBUG_FUNCTION_LINE("no texture!");
return;
}
if (angle == 0) {
SDL_RenderCopy(renderer->getRenderer(), texture, nullptr, &dest);
} else {
SDL_RenderCopyEx(renderer->getRenderer(), texture, nullptr, &dest, angle, nullptr, SDL_FLIP_NONE);
}
}
int GuiTextureData::setBlendMode(SDL_BlendMode) {
if(texture){ return SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); }
return SDL_BLENDMODE_INVALID;
}

40
src/gui/GuiTextureData.h Normal file
View File

@ -0,0 +1,40 @@
#pragma once
#include <SDL2/SDL_render.h>
#include "GuiElement.h"
class GuiTextureData {
public:
GuiTextureData(void *buffer, uint32_t filesize, bool freesrc = false);
explicit GuiTextureData(SDL_Texture *texture);
explicit GuiTextureData(const std::string &path);
//!Destructor
~GuiTextureData();
void draw(Renderer *pVideo, const SDL_Rect &rect, float angle);
int setBlendMode(SDL_BlendMode blendMode);
[[nodiscard]] int32_t getWidth() const {
return width;
}
[[nodiscard]] int32_t getHeight() const {
return height;
}
protected:
void loadSurface(SDL_Surface *pSurface);
SDL_Surface *imgSurface = nullptr;
void cleanUp();
SDL_Texture *texture = nullptr;
int32_t width = 0;
int32_t height = 0;
};

View File

@ -14,10 +14,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/ ****************************************************************************/
#include <iostream>
#include "GuiElement.h"
#include "GuiController.h" #include "GuiController.h"
#include "GuiTrigger.h"
/** /**
* Constructor for the GuiTrigger class. * Constructor for the GuiTrigger class.
@ -33,8 +30,7 @@ GuiTrigger::GuiTrigger(uint32_t ch, uint32_t btn, bool clickEverywhere, bool hol
/** /**
* Destructor for the GuiTrigger class. * Destructor for the GuiTrigger class.
*/ */
GuiTrigger::~GuiTrigger() { GuiTrigger::~GuiTrigger() = default;
}
/** /**
* Sets a simple trigger. Requires: * Sets a simple trigger. Requires:
@ -93,6 +89,7 @@ int32_t GuiTrigger::clicked(const GuiController *controller) const {
int32_t bResult = CLICKED_NONE; int32_t bResult = CLICKED_NONE;
if (controller->data.touched && controller->data.validPointer && (btns & TOUCHED) && !controller->lastData.touched) { if (controller->data.touched && controller->data.validPointer && (btns & TOUCHED) && !controller->lastData.touched) {
bResult = CLICKED_TOUCH; bResult = CLICKED_TOUCH;
} }

View File

@ -20,7 +20,7 @@
class GuiController; class GuiController;
//!Menu input trigger management. Determine if action is neccessary based on input data by comparing controller input data to a specific trigger element. //!Menu input trigger management. Determine if action is necessary based on input data by comparing controller input data to a specific trigger element.
class GuiTrigger { class GuiTrigger {
public: public:
enum eClicked { enum eClicked {
@ -96,15 +96,15 @@ public:
bSelectionClickEverywhere = b; bSelectionClickEverywhere = b;
} }
bool isClickEverywhere() const { [[nodiscard]] bool isClickEverywhere() const {
return bClickEverywhere; return bClickEverywhere;
} }
bool isHoldEverywhere() const { [[nodiscard]] bool isHoldEverywhere() const {
return bHoldEverywhere; return bHoldEverywhere;
} }
bool isSelectionClickEverywhere() const { [[nodiscard]] bool isSelectionClickEverywhere() const {
return bSelectionClickEverywhere; return bSelectionClickEverywhere;
} }

View File

@ -7,15 +7,19 @@ public:
} }
void before() override{
SDLController::before();
data.validPointer = true;
}
virtual bool update(SDL_Event *e, int32_t screenWidth, int32_t screenHeight) override { virtual bool update(SDL_Event *e, int32_t screenWidth, int32_t screenHeight) override {
if (e->type == SDL_MOUSEMOTION) { if (e->type == SDL_MOUSEMOTION) {
data.y = e->motion.y; data.y = e->motion.y;
data.x = e->motion.x; data.x = e->motion.x;
data.validPointer = true;
} else if (e->type == SDL_MOUSEBUTTONDOWN && e->button.button == SDL_BUTTON_LEFT) { } else if (e->type == SDL_MOUSEBUTTONDOWN && e->button.button == SDL_BUTTON_LEFT) {
data.buttons_h |= GuiTrigger::TOUCHED; data.touched = true;
} else if (e->type == SDL_MOUSEBUTTONUP && e->button.button == SDL_BUTTON_LEFT) { } else if (e->type == SDL_MOUSEBUTTONUP && e->button.button == SDL_BUTTON_LEFT) {
data.buttons_h &= ~GuiTrigger::TOUCHED; data.touched = false;
}else{ }else{
DEBUG_FUNCTION_LINE("Unknown event"); DEBUG_FUNCTION_LINE("Unknown event");
return false; return false;

View File

@ -26,16 +26,14 @@ public:
} }
bool update(SDL_Event *e, int32_t screenWidth, int32_t screenHeight) override { bool update(SDL_Event *e, int32_t screenWidth, int32_t screenHeight) override {
if (e->type == SDL_FINGERMOTION) { if (e->type == SDL_FINGERMOTION || e->type == SDL_FINGERUP || e->type == SDL_FINGERDOWN) {
data.y = e->tfinger.y * screenHeight; data.y = e->tfinger.y * screenHeight;
data.x = e->tfinger.x * screenWidth;; data.x = e->tfinger.x * screenWidth;
data.validPointer = true; if (e->type == SDL_FINGERUP) {
} else if (e->type == SDL_FINGERUP) { data.touched = false;
data.validPointer = false;
data.buttons_h &= ~GuiTrigger::TOUCHED;
} else if (e->type == SDL_FINGERDOWN) { } else if (e->type == SDL_FINGERDOWN) {
data.validPointer = true; data.touched = true;
data.buttons_h |= GuiTrigger::TOUCHED; }
} else if (e->type == SDL_JOYBUTTONDOWN) { } else if (e->type == SDL_JOYBUTTONDOWN) {
data.buttons_h |= vpad_button_map[e->jbutton.button]; data.buttons_h |= vpad_button_map[e->jbutton.button];
} else if (e->type == SDL_JOYBUTTONUP) { } else if (e->type == SDL_JOYBUTTONUP) {
@ -46,5 +44,10 @@ public:
} }
return true; return true;
} }
void after() override {
data.validPointer = data.touched;
SDLController::after();
}
}; };

View File

@ -1,23 +1,16 @@
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include "system/SDLSystem.h" #include "system/SDLSystem.h"
#include "gui/GuiFrame.h" #include "gui/GuiFrame.h"
#include "gui/GuiImage.h"
#include "gui/GuiButton.h" #include "gui/GuiButton.h"
#include "gui/GuiController.h" #include "gui/GuiController.h"
#include "menu/MainWindow.h" #include "menu/MainWindow.h"
#include "utils/logger.h"
#include "input/SDLController.h" #include "input/SDLController.h"
#include "input/SDLControllerMouse.h" #include "input/SDLControllerMouse.h"
#include "input/SDLControllerWiiUGamepad.h"
#include "input/SDLControllerXboxOne.h"
#include "input/SDLControllerWiiUProContoller.h"
#include "input/SDLControllerJoystick.h"
#include "input/ControllerManager.h" #include "input/ControllerManager.h"
#include <cstdio> #include <cstdio>
#include <fcntl.h> #include <fcntl.h>
#include <map>
#if defined _WIN32 #if defined _WIN32
#include <windows.h> #include <windows.h>

View File

@ -1,57 +1,91 @@
#include "MainWindow.h" #include "MainWindow.h"
#include "../resources/Resources.h"
MainWindow::~MainWindow() { MainWindow::~MainWindow() {
delete label;; delete label;
delete touchTrigger;; delete touchTrigger;
delete sound;; delete buttonTrigger;
delete image;; delete sound;
delete image2;; delete image;
delete image3;; delete image2;
delete image4;; delete image3;
delete image5;; delete image4;
delete image;; delete image5;
delete label;; delete image;
delete button;; delete label;
delete bgMusic;; delete button;
delete bgMusic;
} }
MainWindow::MainWindow(int32_t w, int32_t h, Renderer* renderer) : GuiFrame(w, h) { MainWindow::MainWindow(int32_t w, int32_t h, Renderer* renderer) : GuiFrame(w, h) {
#if defined _WIN32 #if defined _WIN32
auto picture_path = "test.png"; Resources::LoadFiles(".");
#endif
auto picture_path = "button.png";
auto font_path = "FreeSans.ttf"; auto font_path = "FreeSans.ttf";
auto bgMusic_path = "bgMusic.ogg"; auto bgMusic_path = "bgMusic.ogg";
auto music_click = "button_click.mp3"; auto music_click = "button_click.mp3";
#else
auto picture_path = "fs:/vol/external01/test.png";
auto font_path = "fs:/vol/external01/FreeSans.ttf";
auto bgMusic_path = "fs:/vol/external01/bgMusic.ogg";
auto music_click = "fs:/vol/external01/button_click.mp3";
#endif
TTF_Init(); TTF_Init();
TTF_Font *font; TTF_Font *font;
font = TTF_OpenFont(font_path, 28); SDL_RWops *rw = SDL_RWFromMem((void *) Resources::GetFile(font_path), Resources::GetFileSize(font_path));
DEBUG_FUNCTION_LINE("load font %08X %d", Resources::GetFile(font_path), Resources::GetFileSize(font_path));
font = TTF_OpenFontRW(rw, 0, 28);
if(!font){
DEBUG_FUNCTION_LINE("Failed to load the font");
return;
}
FC_Font* fc_font = FC_CreateFont(); FC_Font* fc_font = FC_CreateFont();
if(!fc_font){ if(!fc_font){
DEBUG_FUNCTION_LINE("Failed to create font"); DEBUG_FUNCTION_LINE("Failed to create font");
} }
FC_LoadFontFromTTF(fc_font, renderer->getRenderer(), font, {255, 255, 255, 255}); auto res = FC_LoadFontFromTTF(fc_font, renderer->getRenderer(), font, {255, 255, 255, 255});
DEBUG_FUNCTION_LINE("FontCache init %d", res);
label = new GuiText("This is a test.This is a test. This is a test.This is a test.This is a test.This is a test.", {255, 255, 0, 255}, fc_font); label = new GuiText("This is a test.", {255, 255, 0, 255}, fc_font);
bgMusic = new GuiSound(bgMusic_path);
bgMusic = Resources::GetSound(bgMusic_path);
if(!bgMusic){
DEBUG_FUNCTION_LINE("Failed to load %s", bgMusic_path);
return;
}
bgMusic->SetLoop(true); bgMusic->SetLoop(true);
bgMusic->Play(); bgMusic->Play();
image = new GuiImage(picture_path); image = new GuiImage(Resources::GetTexture(picture_path));
image2 = new GuiImage(picture_path); image2 = new GuiImage(Resources::GetTexture(picture_path));
image3 = new GuiImage(picture_path); image3 = new GuiImage(Resources::GetTexture(picture_path));
image4 = new GuiImage(picture_path); image4 = new GuiImage(Resources::GetTexture(picture_path));
image5 = new GuiImage(picture_path); image5 = new GuiImage(Resources::GetTexture(picture_path));
if(!image){
DEBUG_FUNCTION_LINE("Failed to add image");
return;
}
if(!image2){
DEBUG_FUNCTION_LINE("Failed to add image");
return;
}
if(!image3){
DEBUG_FUNCTION_LINE("Failed to add image");
return;
}
if(!image4){
DEBUG_FUNCTION_LINE("Failed to add image");
return;
}
if(!image5){
DEBUG_FUNCTION_LINE("Failed to add image");
return;
}
DEBUG_FUNCTION_LINE("%d", image5->getWidth());
button = new GuiButton(image5->getWidth(), image5->getHeight()); button = new GuiButton(image5->getWidth(), image5->getHeight());
this->setAlignment(ALIGN_TOP_LEFT); this->setAlignment(ALIGN_TOP_LEFT);
@ -69,11 +103,12 @@ MainWindow::MainWindow(int32_t w, int32_t h, Renderer* renderer) : GuiFrame(w, h
button->setAlignment(ALIGN_CENTERED); button->setAlignment(ALIGN_CENTERED);
button->setImage(image5); button->setImage(image5);
sound = new GuiSound(music_click); sound = Resources::GetSound(music_click);
touchTrigger = new GuiTrigger(GuiTrigger::CHANNEL_1, GuiTrigger::TOUCHED); touchTrigger = new GuiTrigger(GuiTrigger::CHANNEL_1, GuiTrigger::TOUCHED);
touchTrigger = new GuiTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::TOUCHED); buttonTrigger = new GuiTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_A, true);
button->setTrigger(touchTrigger); button->setTrigger(touchTrigger);
button->setTrigger(buttonTrigger);
button->setEffectGrow(); button->setEffectGrow();
label->setAlignment(ALIGN_CENTERED); label->setAlignment(ALIGN_CENTERED);
button->setLabel(label); button->setLabel(label);
@ -86,8 +121,11 @@ MainWindow::MainWindow(int32_t w, int32_t h, Renderer* renderer) : GuiFrame(w, h
void MainWindow::process() { void MainWindow::process() {
GuiFrame::process(); GuiFrame::process();
if(!button){
return;
}
// Rotate the button for fun. // Rotate the button for fun.
auto res = button->getAngle() + 1; auto res = button->getAngle() + 0.1f;
if(res > 360){ if(res > 360){
res = 0; res = 0;
} }

View File

@ -4,6 +4,7 @@
#include "../gui/GuiFrame.h" #include "../gui/GuiFrame.h"
#include "../gui/GuiButton.h" #include "../gui/GuiButton.h"
#include "../utils/logger.h" #include "../utils/logger.h"
#include "../gui/GuiImage.h"
class MainWindow : public GuiFrame, public sigslot::has_slots<> { class MainWindow : public GuiFrame, public sigslot::has_slots<> {
public: public:
@ -16,6 +17,7 @@ public:
private: private:
GuiText *label = nullptr; GuiText *label = nullptr;
GuiTrigger *touchTrigger = nullptr; GuiTrigger *touchTrigger = nullptr;
GuiTrigger *buttonTrigger = nullptr;
GuiSound *sound = nullptr; GuiSound *sound = nullptr;
GuiImage *image = nullptr; GuiImage *image = nullptr;
GuiImage *image2 = nullptr; GuiImage *image2 = nullptr;

177
src/resources/Resources.cpp Normal file
View File

@ -0,0 +1,177 @@
#include <malloc.h>
#include <cstring>
#include <string>
#include "Resources.h"
#include "../fs/FSUtils.h"
#include "../gui/GuiSound.h"
#include "../gui/GuiTextureData.h"
#include <chrono>
#include "filelist.h"
#include "../utils/logger.h"
Resources *Resources::instance = nullptr;
void Resources::Clear() {
for (int32_t i = 0; RecourceList[i].filename != nullptr; ++i) {
if (RecourceList[i].CustomFile) {
free(RecourceList[i].CustomFile);
RecourceList[i].CustomFile = nullptr;
}
if (RecourceList[i].CustomFileSize != 0) {
RecourceList[i].CustomFileSize = 0;
}
}
delete instance;
instance = nullptr;
}
bool Resources::LoadFiles(const char *path) {
if (!path) {
return false;
}
bool result = false;
Clear();
for (int32_t i = 0; RecourceList[i].filename != nullptr; ++i) {
std::string fullpath(path);
fullpath += "/";
fullpath += RecourceList[i].filename;
DEBUG_FUNCTION_LINE("%s", fullpath.c_str());
uint8_t *buffer = nullptr;
uint32_t filesize = 0;
auto res = FSUtils::LoadFileToMem(fullpath.c_str(), &buffer, &filesize);
if (filesize > 0) {
RecourceList[i].CustomFile = buffer;
RecourceList[i].CustomFileSize = (uint32_t) filesize;
}
result |= (buffer != 0);
}
return result;
}
const uint8_t *Resources::GetFile(const char *filename) {
for (int32_t i = 0; RecourceList[i].filename != nullptr; ++i) {
if (strcasecmp(filename, RecourceList[i].filename) == 0) {
return (RecourceList[i].CustomFile ? RecourceList[i].CustomFile : RecourceList[i].DefaultFile);
}
}
return nullptr;
}
uint32_t Resources::GetFileSize(const char *filename) {
for (int32_t i = 0; RecourceList[i].filename != nullptr; ++i) {
if (strcasecmp(filename, RecourceList[i].filename) == 0) {
return (RecourceList[i].CustomFile ? RecourceList[i].CustomFileSize : RecourceList[i].DefaultFileSize);
}
}
return 0;
}
GuiTextureData *Resources::GetTexture(const char *filename) {
if (!instance) {
instance = new Resources;
}
auto itr = instance->textureDataMap.find(std::string(filename));
if (itr != instance->textureDataMap.end()) {
itr->second.first++;
return itr->second.second;
}
for (int32_t i = 0; RecourceList[i].filename != nullptr; ++i) {
if (strcasecmp(filename, RecourceList[i].filename) == 0) {
const uint8_t *buff = RecourceList[i].CustomFile ? RecourceList[i].CustomFile : RecourceList[i].DefaultFile;
const uint32_t size = RecourceList[i].CustomFile ? RecourceList[i].CustomFileSize : RecourceList[i].DefaultFileSize;
if (buff == nullptr) {
return nullptr;
}
auto *image = new GuiTextureData((void *) buff, size, false);
instance->textureDataMap[std::string(filename)].first = 1;
instance->textureDataMap[std::string(filename)].second = image;
return image;
}
}
return nullptr;
}
bool Resources::RemoveTexture(GuiTextureData *image) {
std::map<std::string, std::pair<uint32_t, GuiTextureData *> >::iterator itr;
for (itr = instance->textureDataMap.begin(); itr != instance->textureDataMap.end(); itr++) {
if (itr->second.second == image) {
itr->second.first--;
if (itr->second.first == 0) {
delete itr->second.second;
// AsyncExecutor::pushForDelete(itr->second.second);
instance->textureDataMap.erase(itr);
}
return true;
}
}
return false;
}
GuiSound *Resources::GetSound(const char *filename) {
if (!instance) {
instance = new Resources;
}
auto itr = instance->soundDataMap.find(std::string(filename));
if (itr != instance->soundDataMap.end()) {
itr->second.first++;
return itr->second.second;
}
for (int32_t i = 0; RecourceList[i].filename != nullptr; ++i) {
if (strcasecmp(filename, RecourceList[i].filename) == 0) {
const uint8_t *buff = RecourceList[i].CustomFile ? RecourceList[i].CustomFile : RecourceList[i].DefaultFile;
const uint32_t size = RecourceList[i].CustomFile ? RecourceList[i].CustomFileSize : RecourceList[i].DefaultFileSize;
if (buff == nullptr) {
return nullptr;
}
auto *sound = new GuiSound((void *) buff, size);
instance->soundDataMap[std::string(filename)].first = 1;
instance->soundDataMap[std::string(filename)].second = sound;
return sound;
}
}
return nullptr;
}
void Resources::RemoveSound(GuiSound *sound) {
std::map<std::string, std::pair<uint32_t, GuiSound *> >::iterator itr;
for (itr = instance->soundDataMap.begin(); itr != instance->soundDataMap.end(); itr++) {
if (itr->second.second == sound) {
itr->second.first--;
if (itr->second.first == 0) {
// AsyncExecutor::pushForDelete(itr->second.second);
delete itr->second.second;
instance->soundDataMap.erase(itr);
}
break;
}
}
}

48
src/resources/Resources.h Normal file
View File

@ -0,0 +1,48 @@
#pragma once
#include <map>
#include <string>
#include <cstdint>
//! forward declaration
class GuiTextureData;
class GuiSound;
typedef struct RecourceFile
{
const char *filename;
const unsigned char *DefaultFile;
const unsigned int &DefaultFileSize;
unsigned char *CustomFile;
unsigned int CustomFileSize;
} RecourceFile;
class Resources {
public:
static void Clear();
static bool LoadFiles(const char *path);
static const uint8_t *GetFile(const char *filename);
static uint32_t GetFileSize(const char *filename);
static GuiTextureData *GetTexture(const char *filename);
static bool RemoveTexture(GuiTextureData *image);
static GuiSound *GetSound(const char *filename);
static void RemoveSound(GuiSound *sound);
private:
static Resources *instance;
Resources() {}
~Resources() {}
std::map<std::string, std::pair<uint32_t, GuiTextureData *> > textureDataMap;
std::map<std::string, std::pair<uint32_t, GuiSound *> > soundDataMap;
};

40
src/resources/filelist.h Normal file
View File

@ -0,0 +1,40 @@
/****************************************************************************
* Resource files.
* This file is generated automatically.
* Includes 4 files.
*
* NOTE:
* Any manual modification of this file will be overwriten by the generation.
****************************************************************************/
#ifndef _FILELIST_H_
#define _FILELIST_H_
#include "Resources.h"
#ifdef __WIIU__
#include "bgMusic_ogg.h"
#include "button_png.h"
#include "button_click_mp3.h"
#include "FreeSans_ttf.h"
static RecourceFile RecourceList[] =
{
{"bgMusic.ogg", bgMusic_ogg, bgMusic_ogg_size, NULL, 0},
{"button.png", button_png, button_png_size, NULL, 0},
{"button_click.mp3", button_click_mp3, button_click_mp3_size, NULL, 0},
{"FreeSans.ttf", FreeSans_ttf, FreeSans_ttf_size, NULL, 0},
{NULL, NULL, 0, NULL, 0}
};
#else
static RecourceFile RecourceList[] =
{
{"bgMusic.ogg", NULL, 0, NULL, 0},
{"button.png", NULL, 0, NULL, 0},
{"button_click.mp3", nullptr, 0, NULL, 0},
{"FreeSans.ttf", NULL, 0, NULL, 0},
{NULL, NULL, 0, NULL, 0}
};
#endif
#endif

View File

@ -451,9 +451,9 @@ struct FC_Font
FC_Image** glyph_cache; FC_Image** glyph_cache;
char* loading_string; char* loading_string;
};
std::recursive_mutex mutex; std::recursive_mutex* mutex = nullptr;
};
// Private // Private
static FC_GlyphData* FC_PackGlyphData(FC_Font* font, Uint32 codepoint, Uint16 width, Uint16 maxWidth, Uint16 maxHeight); static FC_GlyphData* FC_PackGlyphData(FC_Font* font, Uint32 codepoint, Uint16 width, Uint16 maxWidth, Uint16 maxHeight);
@ -845,12 +845,7 @@ void FC_SetTabWidth(unsigned int width_in_spaces)
fc_tab_width = width_in_spaces; fc_tab_width = width_in_spaces;
} }
// Constructors // Constructors
static void FC_Init(FC_Font* font) static void FC_Init(FC_Font* font)
{ {
if(font == NULL) if(font == NULL)
@ -895,6 +890,7 @@ static void FC_Init(FC_Font* font)
font->glyph_cache_size = 3; font->glyph_cache_size = 3;
font->glyph_cache_count = 0; font->glyph_cache_count = 0;
font->mutex = new std::recursive_mutex();
font->glyph_cache = (FC_Image**)malloc(font->glyph_cache_size * sizeof(FC_Image*)); font->glyph_cache = (FC_Image**)malloc(font->glyph_cache_size * sizeof(FC_Image*));
@ -1181,7 +1177,7 @@ Uint8 FC_LoadFontFromTTF(FC_Font* font, SDL_Renderer* renderer, TTF_Font* ttf, S
#endif #endif
FC_ClearFont(font); FC_ClearFont(font);
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
// Might as well check render target support here // Might as well check render target support here
#ifdef FC_USE_SDL_GPU #ifdef FC_USE_SDL_GPU
@ -1435,6 +1431,9 @@ void FC_ClearFont(FC_Font* font)
} }
free(font->glyph_cache); free(font->glyph_cache);
font->glyph_cache = NULL; font->glyph_cache = NULL;
delete font->mutex;
font->mutex = nullptr;
// Reset font // Reset font
FC_Init(font); FC_Init(font);
@ -1770,7 +1769,7 @@ FC_Rect FC_Draw(FC_Font* font, FC_Target* dest, float x, float y, const char* fo
if(formatted_text == NULL || font == NULL) if(formatted_text == NULL || font == NULL)
return FC_MakeRect(x, y, 0, 0); return FC_MakeRect(x, y, 0, 0);
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text); FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
set_color_for_all_caches(font, font->default_color); set_color_for_all_caches(font, font->default_color);
@ -2062,7 +2061,7 @@ FC_Rect FC_DrawBox(FC_Font* font, FC_Target* dest, FC_Rect box, const char* form
if(formatted_text == NULL || font == NULL) if(formatted_text == NULL || font == NULL)
return FC_MakeRect(box.x, box.y, 0, 0); return FC_MakeRect(box.x, box.y, 0, 0);
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text); FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
@ -2096,7 +2095,7 @@ FC_Rect FC_DrawBoxAlign(FC_Font* font, FC_Target* dest, FC_Rect box, FC_AlignEnu
if(formatted_text == NULL || font == NULL) if(formatted_text == NULL || font == NULL)
return FC_MakeRect(box.x, box.y, 0, 0); return FC_MakeRect(box.x, box.y, 0, 0);
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text); FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
@ -2129,7 +2128,7 @@ FC_Rect FC_DrawBoxScale(FC_Font* font, FC_Target* dest, FC_Rect box, FC_Scale sc
if(formatted_text == NULL || font == NULL) if(formatted_text == NULL || font == NULL)
return FC_MakeRect(box.x, box.y, 0, 0); return FC_MakeRect(box.x, box.y, 0, 0);
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text); FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
@ -2162,7 +2161,7 @@ FC_Rect FC_DrawBoxColor(FC_Font* font, FC_Target* dest, FC_Rect box, SDL_Color c
if(formatted_text == NULL || font == NULL) if(formatted_text == NULL || font == NULL)
return FC_MakeRect(box.x, box.y, 0, 0); return FC_MakeRect(box.x, box.y, 0, 0);
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text); FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
@ -2195,7 +2194,7 @@ FC_Rect FC_DrawBoxEffect(FC_Font* font, FC_Target* dest, FC_Rect box, FC_Effect
if(formatted_text == NULL || font == NULL) if(formatted_text == NULL || font == NULL)
return FC_MakeRect(box.x, box.y, 0, 0); return FC_MakeRect(box.x, box.y, 0, 0);
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text); FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
@ -2230,7 +2229,7 @@ FC_Rect FC_DrawColumn(FC_Font* font, FC_Target* dest, float x, float y, Uint16 w
if(formatted_text == NULL || font == NULL) if(formatted_text == NULL || font == NULL)
return FC_MakeRect(x, y, 0, 0); return FC_MakeRect(x, y, 0, 0);
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text); FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
@ -2245,7 +2244,7 @@ FC_Rect FC_DrawColumn(FC_Font* font, FC_Target* dest, float x, float y, Uint16 w
FC_Rect FC_DrawColumnToTexture(FC_Font* font, SDL_Texture* target, float x, float y, Uint16 width, const char* text) FC_Rect FC_DrawColumnToTexture(FC_Font* font, SDL_Texture* target, float x, float y, Uint16 width, const char* text)
{ {
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
// Draw the text onto it // Draw the text onto it
SDL_SetRenderTarget(font->renderer, target); SDL_SetRenderTarget(font->renderer, target);
@ -2265,7 +2264,7 @@ FC_Rect FC_DrawColumnAlign(FC_Font* font, FC_Target* dest, float x, float y, Uin
if(formatted_text == NULL || font == NULL) if(formatted_text == NULL || font == NULL)
return FC_MakeRect(x, y, 0, 0); return FC_MakeRect(x, y, 0, 0);
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text); FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
@ -2298,7 +2297,7 @@ FC_Rect FC_DrawColumnScale(FC_Font* font, FC_Target* dest, float x, float y, Uin
if(formatted_text == NULL || font == NULL) if(formatted_text == NULL || font == NULL)
return FC_MakeRect(x, y, 0, 0); return FC_MakeRect(x, y, 0, 0);
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text); FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
@ -2321,7 +2320,7 @@ FC_Rect FC_DrawColumnColor(FC_Font* font, FC_Target* dest, float x, float y, Uin
if(formatted_text == NULL || font == NULL) if(formatted_text == NULL || font == NULL)
return FC_MakeRect(x, y, 0, 0); return FC_MakeRect(x, y, 0, 0);
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text); FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
@ -2344,7 +2343,7 @@ FC_Rect FC_DrawColumnEffect(FC_Font* font, FC_Target* dest, float x, float y, Ui
if(formatted_text == NULL || font == NULL) if(formatted_text == NULL || font == NULL)
return FC_MakeRect(x, y, 0, 0); return FC_MakeRect(x, y, 0, 0);
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text); FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
@ -2442,7 +2441,7 @@ FC_Rect FC_DrawScale(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale
if(formatted_text == NULL || font == NULL) if(formatted_text == NULL || font == NULL)
return FC_MakeRect(x, y, 0, 0); return FC_MakeRect(x, y, 0, 0);
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text); FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
@ -2460,7 +2459,7 @@ FC_Rect FC_DrawAlign(FC_Font* font, FC_Target* dest, float x, float y, FC_AlignE
if(formatted_text == NULL || font == NULL) if(formatted_text == NULL || font == NULL)
return FC_MakeRect(x, y, 0, 0); return FC_MakeRect(x, y, 0, 0);
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text); FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
@ -2493,7 +2492,7 @@ FC_Rect FC_DrawColor(FC_Font* font, FC_Target* dest, float x, float y, SDL_Color
if(formatted_text == NULL || font == NULL) if(formatted_text == NULL || font == NULL)
return FC_MakeRect(x, y, 0, 0); return FC_MakeRect(x, y, 0, 0);
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text); FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
@ -2512,7 +2511,7 @@ FC_Rect FC_DrawEffect(FC_Font* font, FC_Target* dest, float x, float y, FC_Effec
if(formatted_text == NULL || font == NULL) if(formatted_text == NULL || font == NULL)
return FC_MakeRect(x, y, 0, 0); return FC_MakeRect(x, y, 0, 0);
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text); FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
@ -2567,7 +2566,7 @@ Uint16 FC_GetHeight(FC_Font* font, const char* formatted_text, ...)
if(formatted_text == NULL || font == NULL) if(formatted_text == NULL || font == NULL)
return 0; return 0;
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text); FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
@ -2593,7 +2592,7 @@ Uint16 FC_GetWidth(FC_Font* font, const char* formatted_text, ...)
if(formatted_text == NULL || font == NULL) if(formatted_text == NULL || font == NULL)
return 0; return 0;
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text); FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
@ -2633,7 +2632,7 @@ FC_Rect FC_GetCharacterOffset(FC_Font* font, Uint16 position_index, int column_w
if(formatted_text == NULL || column_width == 0 || position_index == 0 || font == NULL) if(formatted_text == NULL || column_width == 0 || position_index == 0 || font == NULL)
return result; return result;
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text); FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
@ -2692,7 +2691,7 @@ Uint16 FC_GetColumnHeight(FC_Font* font, Uint16 width, const char* formatted_tex
if(formatted_text == NULL || width == 0) if(formatted_text == NULL || width == 0)
return font->height; return font->height;
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text); FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
@ -2744,7 +2743,7 @@ int FC_GetAscent(FC_Font* font, const char* formatted_text, ...)
if(formatted_text == NULL) if(formatted_text == NULL)
return font->ascent; return font->ascent;
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text); FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
@ -2780,7 +2779,7 @@ int FC_GetDescent(FC_Font* font, const char* formatted_text, ...)
if(formatted_text == NULL) if(formatted_text == NULL)
return font->descent; return font->descent;
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text); FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
@ -2899,7 +2898,7 @@ Uint16 FC_GetPositionFromOffset(FC_Font* font, float x, float y, int column_widt
if(formatted_text == NULL || column_width == 0 || font == NULL) if(formatted_text == NULL || column_width == 0 || font == NULL)
return 0; return 0;
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text); FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
@ -2947,7 +2946,7 @@ int FC_GetWrappedText(FC_Font* font, char* result, int max_result_size, Uint16 w
if(formatted_text == NULL || width == 0) if(formatted_text == NULL || width == 0)
return 0; return 0;
std::scoped_lock lock(mutex); std::scoped_lock lock(*font->mutex);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text); FC_EXTRACT_VARARGS(fc_buffer, formatted_text);

1166
src/utils/dirent.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,7 @@
#endif #endif
#include <string.h> #include <string.h>
#include <stdio.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {