>>WIP Early<< SDL2 GFX

This commit is contained in:
J-D-K 2021-06-02 17:05:57 -04:00
parent a02b3e82c3
commit e34a3f36c7
22 changed files with 673 additions and 1492 deletions

View File

@ -38,7 +38,7 @@ INCLUDES := inc
EXEFS_SRC := exefs_src
APP_TITLE := JKSV
APP_AUTHOR := JK
APP_VERSION := 05.27.2021
APP_VERSION := 06.02.2021
ROMFS := romfs
ICON := romfs/icon.jpg
@ -47,7 +47,7 @@ ICON := romfs/icon.jpg
#---------------------------------------------------------------------------------
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
override CFLAGS += -g -Wall -O2 -ffunction-sections -ffast-math \
override CFLAGS += `sdl2-config --cflags` -g -Wall -O2 -ffunction-sections -ffast-math \
$(ARCH) $(DEFINES)
override CFLAGS += $(INCLUDE) -D__SWITCH__ `freetype-config --cflags` `curl-config --cflags`
@ -57,7 +57,7 @@ CXXFLAGS:= $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LIBS := `freetype-config --libs` `curl-config --libs` -lpng -ljpeg -lz -lminizip -ljson-c -lnx
LIBS := `sdl2-config --libs` `freetype-config --libs` `curl-config --libs` -lsdl2_image -lwebp -lpng -ljpeg -lz -lminizip -ljson-c -lnx
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing

View File

@ -89,7 +89,17 @@ JKSV on Switch started as a small project/port to test some things and get famil
## Building:
1. Requires [devkitPro](https://devkitpro.org/) and [libnx](https://github.com/switchbrew/libnx)
2. Requires switch-[freetype, libpng, zlib, libjpeg-turbo, curl, and libjson-c]
2. Requires switch-
* freetype
* libpng
* zlib
* libjpeg-turbo
* curl
* libjson-c
* sdl2
* sdl2_image
* libwebp
## Credits and Thanks:
* [shared-font](https://github.com/switchbrew/switch-portlibs-examples) example by yellows8

View File

@ -12,8 +12,8 @@
#define curUser users[data::selUser]
#define curData users[data::selUser].titles[data::selData]
#define BLD_MON 05
#define BLD_DAY 27
#define BLD_MON 06
#define BLD_DAY 02
#define BLD_YEAR 2021
namespace data
@ -76,7 +76,7 @@ namespace data
uint32_t getLaunchCount() const { return launchCount; }
private:
tex *icon;
SDL_Texture *icon;
uint8_t saveDataType;
std::string title, titleSafe, author;
uint64_t id, saveID;
@ -91,13 +91,13 @@ namespace data
public:
user() = default;
user(const AccountUid& _id, const std::string& _backupName);
user(const AccountUid& _id, const std::string& _backupName, tex *img);
user(const AccountUid& _id, const std::string& _backupName, SDL_Texture *img);
//Sets ID
void setUID(const AccountUid& _id);
//Assigns icon
void assignIcon(tex *_icn) { userIcon = _icn; }
void assignIcon(SDL_Texture *_icn) { userIcon = _icn; }
//Returns user ID
AccountUid getUID() const { return userID; }
@ -111,16 +111,16 @@ namespace data
std::vector<titledata> titles;
void loadPlayTimes();
void drawIcon(int x, int y) { texDraw(userIcon, frameBuffer, x, y); }
void drawIconHalf(int x, int y) { texDrawSkip(userIcon, frameBuffer, x, y); }
void delIcon() { texDestroy(userIcon); }
void drawIcon(int x, int y) { gfx::texDraw(userIcon, x, y); }
void drawIconHalf(int x, int y) { gfx::texDrawStretch(userIcon, x, y, 128, 128); }
void delIcon() { SDL_DestroyTexture(userIcon); }
private:
AccountUid userID;
u128 uID128;
std::string username, userSafe;
//User icon
tex* userIcon;
SDL_Texture *userIcon;
};
//Adds title to blacklist
@ -130,7 +130,7 @@ namespace data
//User vector
extern std::vector<user> users;
extern std::unordered_map<uint64_t, tex *> icons;
extern std::unordered_map<uint64_t, SDL_Texture *> icons;
//Options and info
//Restores config to default

229
inc/gfx.h
View File

@ -1,200 +1,59 @@
#ifndef GFX_H
#define GFX_H
#include <stdint.h>
#include <stdbool.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <SDL.h>
#ifdef __cplusplus
extern "C"
namespace gfx
{
#endif
extern SDL_Renderer *render;
//Structs
typedef struct
{
uint8_t r, g, b, a;
} clr;
void init();
void exit();
void clear(const SDL_Color *c);
void present();
typedef struct
{
FT_Library lib;
FT_Face face[6];
FT_Error libRet, faceRet;
//Loads to buffer for speed for TTF
uint8_t *fntData;
bool external;
} font;
SDL_Texture *loadJPEGMem(const void *jpegData, size_t jpegSize);
SDL_Texture *loadImageFile(const char *file);
typedef struct
{
size_t size;
unsigned width, height;
uint32_t *data;
} tex;
void drawTextf(int fontSize, int x, int y, const SDL_Color *c, const char *fmt, ...);
void drawTextfWrap(int fontSize, int x, int y, int maxWidth, const SDL_Color* c, const char *fmt, ...);
size_t getTextWidth(const char *str, int fontSize);
typedef struct
{
size_t size;
unsigned width, height;
uint8_t *dat;
} alphaMask;
//Shortcuts for drawing
inline void texDraw(SDL_Texture *tex, int x, int y)
{
int tW = 0, tH = 0;
if(SDL_QueryTexture(tex, NULL, NULL, &tW, &tH) == 0)
{
SDL_Rect src = {0, 0, tW, tH};
SDL_Rect pos = {x, y, tW, tH};
SDL_RenderCopy(render, tex, &src, &pos);
}
}
//Inits needed graphics stuff
bool graphicsInit(int windowWidth, int windowHeight);
inline void texDrawStretch(SDL_Texture *tex, int x, int y, int w, int h)
{
int tW = 0, tH = 0;
if(SDL_QueryTexture(tex, NULL, NULL, &tW, &tH) == 0)
{
SDL_Rect src = {0, 0, tW, tH};
SDL_Rect pos = {x, y, w, h};
SDL_RenderCopy(render, tex, &src, &pos);
}
}
//Exits needed services
bool graphicsExit();
inline void drawLine(const SDL_Color *c, int x1, int y1, int x2, int y2)
{
SDL_SetRenderDrawColor(render, c->r, c->g, c->b, c->a);
SDL_RenderDrawLine(render, x1, y1, x2, y2);
}
void gfxBeginFrame();
void gfxEndFrame();
//Creates color from uint32_t
inline clr clrCreateU32(uint32_t color)
{
clr ret;
ret.a = color >> 24 & 0xFF;
ret.b = color >> 16 & 0xFF;
ret.g = color >> 8 & 0xFF;
ret.r = color & 0xFF;
return ret;
inline void drawRect(const SDL_Color *c, int x, int y, int w, int h)
{
SDL_SetRenderDrawColor(render, c->r, c->g, c->b, c->a);
SDL_Rect rect = {x, y, w, h};
SDL_RenderFillRect(render, &rect);
}
}
//Sets clr to [r], [g], [b], [a]
inline clr clrCreateRGBA(uint8_t _r, uint8_t _g, uint8_t _b, uint8_t _a)
{
clr ret;
ret.r = _r;
ret.g = _g;
ret.b = _b;
ret.a = _a;
return ret;
}
//Inverts color
inline void clrInvert(clr *c)
{
c->r = (0xFF - c->r);
c->g = (0xFF - c->g);
c->b = (0xFF - c->b);
}
//Returns uint32_t color
inline uint32_t clrGetColor(const clr c)
{
return (c.a << 24 | c.b << 16 | c.g << 8 | c.r);
}
//Draws text using f
void drawText(const char *str, tex *target, const font *f, int x, int y, int sz, clr c);
void drawTextf(tex *target, const font *f, int x, int y, int sz, clr c, const char *fmt, ...);
//Draws text wrapping lines
void drawTextWrap(const char *str, tex *target, const font *f, int x, int y, int sz, clr c, int maxWidth);
void drawTextfWrap(tex *target, const font *f, int x, int y, int sz, clr c, int maxWidth, const char *fmt, ...);
//Returns text width
size_t textGetWidth(const char *str, const font *f, int sz);
//Draws rectangle at x, y with w, h
void drawRect(tex *target, int x, int y, int w, int h, const clr c);
//Draws rect with alpha.
void drawRectAlpha(tex *target, int x, int y, int w, int h, const clr c);
/*
TEX BEGIN
*/
//Inits empty tex
tex *texCreate(int w, int h);
//Loads PNG from path
tex *texLoadPNGFile(const char *path);
//Loads JPEG from path
tex *texLoadJPEGFile(const char *path);
//Loads jpeg from memory
tex *texLoadJPEGMem(const uint8_t *jpegData, size_t jpegSize);
//Loads image from RGBA - Not meant for large images
tex *texLoadRGBA(const char *path);
//Frees memory used by t
void texDestroy(tex *t);
//Clears tex completely with c
void texClearColor(tex *in, const clr c);
//Draws t at x, y
void texDraw(const tex *t, tex *target, int x, int y);
//Draws without alpha blending, faster
void texDrawNoAlpha(const tex *t, tex *target, int x, int y);
//Draws skipping every other pixel + row
void texDrawSkip(const tex *t, tex *target, int x, int y);
//Same as above, no alpha
void texDrawSkipNoAlpha(const tex *t, tex *target, int x, int y);
//Draw t inverted at x, y
void texDrawInvert(const tex *t, tex *target, int x, int y);
//Replaces old with newColor
void texSwapColors(tex *t, const clr old, const clr newColor);
//Scales tex * scale and writes to out. Can only multiply for now
void texScaleToTex(const tex *in, tex *out, int scale);
//Creates and copies data from another image returns tex
tex *texCreateFromPart(const tex *src, int x, int y, int w, int h);
void texApplyAlphaMask(tex *target, const alphaMask *a);
/*
TEX END
*/
alphaMask *alphaMaskLoad(unsigned w, unsigned h, const char *file);
void alphaMaskDestroy(alphaMask *a);
//Loads and returns font with Switch shared font loaded
font *fontLoadSharedFonts();
//Loads and returns TTF font.
font *fontLoadTTF(const char *path);
//Frees font
void fontDestroy(font *f);
//returns framebuffer tex pointer
extern tex *frameBuffer;
/*Switch extended button codes:
e0e0 = A
e0e1 = B
e0e2 = X
e0e3 = Y
e0e4 = L
e0e5 = R
e0e6 = ZL
e0e7 = ZR
e0e8 = SL
e0e9 = SR
e0ea = dpad
e0eb = dpad up
e0ec = dpad down
e0ed = dpad left
e0ee = dpad right
e0ef = +
e0f0 = -
^^Replace second e with a for different button set. C0 to C9 = analog stick
*/
#ifdef __cplusplus
}
#endif
#endif // GFX_H

View File

@ -27,7 +27,7 @@ namespace ui
int getSelected() { return selected; }
//Draws the menu at x and y. rectWidth is the width of the rectangle drawn under the selected
void draw(const clr& textClr);
void draw(const SDL_Color *textClr);
//Clears and resets menu
void reset();

View File

@ -24,7 +24,6 @@ namespace ui
private:
uint64_t max, prog;
float width;
tex *bg;
};
//General use
@ -32,8 +31,7 @@ namespace ui
bool confirm(bool hold, const char *fmt, ...);
bool confirmTransfer(const std::string& f, const std::string& t);
bool confirmDelete(const std::string& p);
void drawTextbox(tex *target, int x, int y, int w, int h);
void drawTextboxInvert(tex *target, int x, int y, int w, int h);
void drawTextbox(int x, int y, int w, int h);
//Popup from freebird
void showPopup(unsigned frames, const char *fmt, ...);

View File

@ -60,20 +60,15 @@ namespace ui
txtCont = text that contrasts clearClr
txtDiag = text color for dialogs
*/
extern clr clearClr, txtCont, txtDiag, rectLt, rectSh, tboxClr, sideRect;
extern SDL_Color clearClr, txtCont, txtDiag, rectLt, rectSh, tboxClr, sideRect;
//Textbox graphics
extern tex *cornerTopLeft, *cornerTopRight, *cornerBottomLeft, *cornerBottomRight;
extern SDL_Texture *cornerTopLeft, *cornerTopRight, *cornerBottomLeft, *cornerBottomRight;
//Covers left and right of progress bar to fake being not a rectangle.
extern tex *progCovLeft, *progCovRight, *diaBox;
extern SDL_Texture *progCovLeft, *progCovRight, *diaBox;
//Side bar from Freebird. RIP. NEVERMIND
extern tex *sideBar;
extern alphaMask *iconMask;
//Shared font
extern font *shared;
//Side bar from Freebird. RIP.
extern SDL_Texture *sideBar;
//Sets colors and loads font for icon creation
void initTheme();

View File

@ -41,7 +41,7 @@ namespace util
void replaceButtonsInString(std::string& rep);
//Creates a basic generic icon for stuff without one
tex *createIconGeneric(const char *txt);
SDL_Texture *createIconGeneric(const char *txt, int fontSize);
inline u128 accountUIDToU128(AccountUid uid)
{

View File

@ -12,7 +12,7 @@
#include "util.h"
//Color for favorite hearts
const clr heartColor = clrCreateRGBA(0xFF, 0x44, 0x44, 0xFF);
const SDL_Color heartColor = {0xFF, 0x44, 0x44, 0xFF};
//FsSaveDataSpaceId_All doesn't work for SD
static const unsigned saveOrder [] =
@ -39,7 +39,7 @@ static bool sysBCATPushed = false, cachePushed = false, tempPushed = false;
static std::vector<uint64_t> blacklist;
static std::vector<uint64_t> favorites;
static std::unordered_map<uint64_t, std::string> pathDefs;
std::unordered_map<uint64_t, tex *> data::icons;
std::unordered_map<uint64_t, SDL_Texture *> data::icons;
//Sorts titles by sortType
static struct
@ -113,28 +113,14 @@ static bool isDefined(const uint64_t& id)
return false;
}
static tex *createDeviceIcon()
static SDL_Texture *createDeviceIcon()
{
tex *ret = texCreate(256, 256);
texClearColor(ret, ui::rectLt);
unsigned x = 128 - (textGetWidth("\ue121", ui::shared, 188) / 2);
drawText("\ue121", ret, ui::shared, x, 34, 188, ui::txtCont);
texApplyAlphaMask(ret, ui::iconMask);
return ret;
}
static inline tex *createFavIcon(const tex *_icn)
{
tex *ret = texCreate(256, 256);
memcpy(ret->data, _icn->data, 256 * 256 * sizeof(uint32_t));
drawText("", ret, ui::shared, 16, 16, 48, clrCreateU32(0xFF4444FF));
return ret;
return util::createIconGeneric("\ue121", 192);
}
static inline void loadCreateIcon(const uint64_t& _id, size_t _sz, const NsApplicationControlData *_d)
{
data::icons[_id] = texLoadJPEGMem(_d->icon, _sz);
texApplyAlphaMask(data::icons[_id], ui::iconMask);
data::icons[_id] = gfx::loadJPEGMem(_d->icon, _sz);
}
static void loadCreateSystemIcon(const uint64_t& _id)
@ -142,8 +128,7 @@ static void loadCreateSystemIcon(const uint64_t& _id)
char tmp[16];
sprintf(tmp, "%08X", (uint32_t)_id);
data::icons[_id] = util::createIconGeneric(tmp);
texApplyAlphaMask(data::icons[_id], ui::iconMask);
data::icons[_id] = util::createIconGeneric(tmp, 32);
}
static inline std::string getIDStr(const uint64_t& _id)
@ -322,7 +307,7 @@ void data::exit()
for(auto& icn : icons)
{
if(icn.second)
texDestroy(icn.second);
SDL_DestroyTexture(icn.second);
}
saveFav();
@ -403,22 +388,22 @@ void data::titledata::assignIcon()
void data::titledata::drawIcon(bool full, unsigned x, unsigned y)
{
if(full)
texDraw(icon, frameBuffer, x, y);
gfx::texDraw(icon, x, y);
else
texDrawSkip(icon, frameBuffer, x, y);
gfx::texDrawStretch(icon, x, y, 128, 128);
}
void data::titledata::drawIconFav(bool full, unsigned x, unsigned y)
{
if(full)
{
texDraw(icon, frameBuffer, x, y);
drawText("", frameBuffer, ui::shared, x + 16, y + 16, 48, heartColor);
gfx::texDraw(icon, x, y);
gfx::drawTextf(48, x + 16, y + 16, &heartColor, "");
}
else
{
texDrawSkip(icon, frameBuffer, x, y);
drawText("", frameBuffer, ui::shared, x + 8, y + 8, 24, heartColor);
gfx::texDrawStretch(icon, x, y, 128, 128);
gfx::drawTextf(24, x + 8, y + 8, &heartColor, "");
}
}
@ -445,7 +430,7 @@ data::user::user(const AccountUid& _id, const std::string& _backupName)
accountProfileGetImageSize(&prof, &jpgSize);
uint8_t *jpegData = new uint8_t[jpgSize];
accountProfileLoadImage(&prof, jpegData, jpgSize, &jpgSize);
userIcon = texLoadJPEGMem(jpegData, jpgSize);
userIcon = gfx::loadJPEGMem(jpegData, jpgSize);
delete[] jpegData;
accountProfileClose(&prof);
@ -454,13 +439,12 @@ data::user::user(const AccountUid& _id, const std::string& _backupName)
{
username = _backupName.empty() ? getIDStr((uint64_t)uID128) : _backupName;
userSafe = _backupName.empty() ? getIDStr((uint64_t)uID128) : _backupName;
userIcon = util::createIconGeneric(_backupName.c_str());
userIcon = util::createIconGeneric(_backupName.c_str(), 32);
}
texApplyAlphaMask(userIcon, ui::iconMask);
titles.reserve(32);
}
data::user::user(const AccountUid& _id, const std::string& _backupName, tex *img) : user(_id, _backupName)
data::user::user(const AccountUid& _id, const std::string& _backupName, SDL_Texture *img) : user(_id, _backupName)
{
delIcon();
userIcon = img;
@ -667,6 +651,8 @@ void data::loadDefs()
}
}
static const SDL_Color green = {0x00, 0xDD, 0x00, 0xFF};
void data::dispStats()
{
//Easiest/laziest way to do this
@ -678,5 +664,5 @@ void data::dispStats()
stats += "Safe Title: " + data::curData.getTitleSafe() + "\n";
stats += "Icon count: " + std::to_string(icons.size()) + "\n";
stats += "Sort Type: " + std::to_string(data::sortType) + "\n";
drawText(stats.c_str(), frameBuffer, ui::shared, 2, 2, 16, clrCreateU32(0xFF00DD00));
gfx::drawTextf(16, 8, 8, &green, stats.c_str());
}

View File

@ -22,7 +22,7 @@ static std::string wd;
static std::vector<std::string> pathFilter;
static FSFILE *log;
static FSFILE *debLog;
static FsFileSystem sv;
@ -379,9 +379,8 @@ void fs::copyFile(const std::string& from, const std::string& to)
while(!send->fin)
{
prog.update(progress);
gfxBeginFrame();
prog.draw(from, ui::copyHead);
gfxEndFrame();
gfx::present();
}
threadClose(&cpyThread);
copyArgsDestroy(send);
@ -458,9 +457,8 @@ void fs::copyFileCommit(const std::string& from, const std::string& to, const st
while(!send->fin)
{
prog.update(offset);
gfxBeginFrame();
prog.draw(from, ui::copyHead);
gfxEndFrame();
gfx::present();
}
threadClose(&cpyThread);
copyArgsDestroy(send);
@ -527,9 +525,8 @@ void copyFileToZip(const std::string& from, zipFile *z)
while(!send->fin)
{
prog.update(progress);
gfxBeginFrame();
prog.draw(from, ui::copyHead);
gfxEndFrame();
gfx::present();
}
threadClose(&cpyThread);
copyArgsDestroy(send);
@ -587,10 +584,8 @@ void fs::copyZipToDir(unzFile *unz, const std::string& to, const std::string& de
done += readIn;
fwriteCommit(path, buff, readIn, dev);
prog.update(done);
gfxBeginFrame();
prog.draw(filename, ui::copyHead);
gfxEndFrame();
gfx::present();
}
}
else
@ -600,10 +595,8 @@ void fs::copyZipToDir(unzFile *unz, const std::string& to, const std::string& de
done += readIn;
fwriteCommit(path, buff, readIn, dev);
prog.update(done);
gfxBeginFrame();
prog.draw(filename, ui::copyHead);
gfxEndFrame();
gfx::present();
}
}
unzCloseCurrentFile(*unz);
@ -836,7 +829,7 @@ void fs::logOpen()
{
std::string logPath = wd + "log.txt";
remove(logPath.c_str());
log = fsfopen(logPath.c_str(), FsOpenMode_Write);
debLog = fsfopen(logPath.c_str(), FsOpenMode_Write);
}
void fs::logWrite(const char *fmt, ...)
@ -846,11 +839,11 @@ void fs::logWrite(const char *fmt, ...)
va_start(args, fmt);
vsprintf(tmp, fmt, args);
va_end(args);
fsfwrite(tmp, 1, strlen(tmp), log);
fsfwrite(tmp, 1, strlen(tmp), debLog);
}
void fs::logClose()
{
fsfclose(log);
fsfclose(debLog);
}

957
src/gfx.c
View File

@ -1,957 +0,0 @@
#include <switch.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <malloc.h>
#include <png.h>
#include <jpeglib.h>
#include <zlib.h>
#include <setjmp.h>
#include "gfx.h"
tex *frameBuffer;
static clr textClr;
static NWindow *window;
static Framebuffer fb;
static bool framestarted = false;
typedef struct
{
uint16_t w;
uint16_t h;
uint32_t sz;
} rgbaHead;
typedef struct
{
struct jpeg_error_mgr mgr;
jmp_buf jmpBuffer;
} jpegError;
#pragma GCC optimize ("Ofast")
static inline uint32_t blend(const clr px, const clr fb)
{
uint32_t ret;
switch(px.a)
{
case 0x00:
ret = clrGetColor(fb);
break;
case 0xFF:
ret = clrGetColor(px);
break;
default:
{
uint8_t subAl = 0xFF - px.a;
uint8_t fR = (px.r * px.a + fb.r * subAl) / 0xFF;
uint8_t fG = (px.g * px.a + fb.g * subAl) / 0xFF;
uint8_t fB = (px.b * px.a + fb.b * subAl) / 0xFF;
ret = (0xFF << 24 | fB << 16 | fG << 8 | fR);
}
break;
}
return ret;
}
static inline clr smooth(const clr px1, const clr px2)
{
clr ret;
ret.r = (px1.r + px2.r) / 2;
ret.g = (px1.g + px2.g) / 2;
ret.b = (px1.b + px2.b) / 2;
ret.a = (px1.a + px2.a) / 2;
return ret;
}
static inline uint32_t smooth_32t(const clr px1, const clr px2)
{
uint8_t fR = (px1.r + px2.r) / 2;
uint8_t fG = (px1.g + px2.g) / 2;
uint8_t fB = (px1.b + px2.b) / 2;
uint8_t fA = (px1.a + px2.a) / 2;
return (fA << 24 | fB << 16 | fG << 8 | fR);
}
static inline bool yCheck(const tex *target, int y)
{
return y < 0 || y >= target->height;
}
static inline bool xCheck(const tex *target, int x)
{
return x < 0 || x >= target->width;
}
bool graphicsInit(int windowWidth, int windowHeight)
{
window = nwindowGetDefault();
nwindowSetDimensions(window, windowWidth, windowHeight);
framebufferCreate(&fb, window, windowWidth, windowHeight, PIXEL_FORMAT_RGBA_8888, 2);
framebufferMakeLinear(&fb);
plInitialize(PlServiceType_System);
//Make a fake tex that points to framebuffer
frameBuffer = malloc(sizeof(tex));
frameBuffer->width = windowWidth;
frameBuffer->height = windowHeight;
frameBuffer->size = windowWidth * windowHeight;
return true;
}
bool graphicsExit()
{
free(frameBuffer);
plExit();
framebufferClose(&fb);
nwindowClose(window);
return true;
}
void gfxBeginFrame()
{
if(!framestarted)
{
frameBuffer->data = (uint32_t *)framebufferBegin(&fb, NULL);
framestarted = true;
}
}
void gfxEndFrame()
{
if(framestarted)
{
framebufferEnd(&fb);
framestarted = false;
}
}
static void drawGlyph(const FT_Bitmap *bmp, tex *target, int _x, int _y)
{
if(bmp->pixel_mode != FT_PIXEL_MODE_GRAY)
return;
clr txClr = textClr, tgtClr;
uint8_t *bmpPtr = bmp->buffer;
for(int y = _y; y < _y + bmp->rows; y++)
{
if(yCheck(target, y))
continue;
uint32_t *rowPtr = &target->data[y * target->width + _x];
for(int x = _x; x < _x + bmp->width; x++, bmpPtr++, rowPtr++)
{
if(xCheck(target, x))
continue;
if(*bmpPtr > 0)
{
txClr.a = *bmpPtr;
tgtClr = clrCreateU32(*rowPtr);
*rowPtr = blend(txClr, tgtClr);
}
}
}
}
static inline void resizeFont(const font *f, int sz)
{
if(f->external)
FT_Set_Char_Size(f->face[0], 0, sz * 64, 90, 90);
else
{
for(int i = 0; i < 6; i++)
FT_Set_Char_Size(f->face[i], 0, sz * 64, 90, 90);
}
}
static inline FT_GlyphSlot loadGlyph(const uint32_t c, const font *f, FT_Int32 flags)
{
if(f->external)
{
FT_Load_Glyph(f->face[0], FT_Get_Char_Index(f->face[0], c), flags);
return f->face[0]->glyph;
}
for(int i = 0; i < 6; i++)
{
FT_UInt cInd = 0;
if( (cInd = FT_Get_Char_Index(f->face[i], c)) != 0 && FT_Load_Glyph(f->face[i], cInd, flags) == 0)
return f->face[i]->glyph;
}
return NULL;
}
void drawText(const char *str, tex *target, const font *f, int x, int y, int sz, clr c)
{
int tmpX = x;
uint32_t tmpChr = 0;
ssize_t unitCnt = 0;
textClr = c;
resizeFont(f, sz);
size_t length = strlen(str);
for(unsigned i = 0; i < length; )
{
unitCnt = decode_utf8(&tmpChr, (const uint8_t *)&str[i]);
if(unitCnt <= 0)
break;
i += unitCnt;
switch(tmpChr)
{
case '\n':
tmpX = x;
y += sz + 8;
continue;
break;
case '#':
if(clrGetColor(textClr) == 0xFFEE9900)
textClr = c;
else
textClr = clrCreateU32(0xFFEE9900);
continue;
break;
case '*':
if(clrGetColor(textClr) == 0xFF0000FF)
textClr = c;
else
textClr = clrCreateU32(0xFF0000FF);
continue;
break;
case '<':
if(clrGetColor(textClr) == 0xFF00FCF8)
textClr = c;
else
textClr = clrCreateU32(0xFF00FCF8);
continue;
break;
case '>':
if(clrGetColor(textClr) == 0xFF00FF00)
textClr = c;
else
textClr = clrCreateU32(0xFF00FF00);
continue;
break;
}
FT_GlyphSlot slot = loadGlyph(tmpChr, f, FT_LOAD_RENDER);
if(slot != NULL)
{
int drawY = y + (sz - slot->bitmap_top);
drawGlyph(&slot->bitmap, target, tmpX + slot->bitmap_left, drawY);
tmpX += slot->advance.x >> 6;
}
}
}
void drawTextf(tex *target, const font *f, int x, int y, int sz, clr c, const char *fmt, ...)
{
char tmp[512];
va_list args;
va_start(args, fmt);
vsprintf(tmp, fmt, args);
va_end(args);
drawText(tmp, target, f, x, y, sz, c);
}
void drawTextWrap(const char *str, tex *target, const font *f, int x, int y, int sz, clr c, int maxWidth)
{
char wordBuf[128];
size_t nextbreak = 0;
size_t strLength = strlen(str);
int tmpX = x;
resizeFont(f, sz);
textClr = c;
for(unsigned i = 0; i < strLength; )
{
nextbreak = strcspn(&str[i], " /_-");
memset(wordBuf, 0, 128);
memcpy(wordBuf, &str[i], nextbreak + 1);
size_t width = textGetWidth(wordBuf, f, sz);
if(tmpX + width >= x + maxWidth)
{
tmpX = x;
y += sz + 8;
}
size_t wLength = strlen(wordBuf);
uint32_t tmpChr = 0;
for(unsigned j = 0; j < wLength; )
{
ssize_t unitCnt = decode_utf8(&tmpChr, (const uint8_t *)&wordBuf[j]);
if(unitCnt <= 0)
break;
j += unitCnt;
switch(tmpChr)
{
case '\n':
tmpX = x;
y += sz + 8;
continue;
break;
case '#':
if(clrGetColor(textClr) == 0xFFEE9900)
textClr = c;
else
textClr = clrCreateU32(0xFFEE9900);
continue;
break;
case '*':
if(clrGetColor(textClr) == 0xFF0000FF)
textClr = c;
else
textClr = clrCreateU32(0xFF0000FF);
continue;
break;
case '<':
if(clrGetColor(textClr) == 0xFF00FCF8)
textClr = c;
else
textClr = clrCreateU32(0xFF00FCF8);
continue;
break;
case '>':
if(clrGetColor(textClr) == 0xFF00FF00)
textClr = c;
else
textClr = clrCreateU32(0xFF00FF00);
continue;
break;
}
FT_GlyphSlot slot = loadGlyph(tmpChr, f, FT_LOAD_RENDER);
if(slot != NULL)
{
int drawY = y + (sz - slot->bitmap_top);
drawGlyph(&slot->bitmap, target, tmpX + slot->bitmap_left, drawY);
tmpX += slot->advance.x >> 6;
}
}
i += strlen(wordBuf);
}
}
void drawTextfWrap(tex *target, const font *f, int x, int y, int sz, clr c, int maxWidth, const char *fmt, ...)
{
char tmp[512];
va_list args;
va_start(args, fmt);
vsprintf(tmp, fmt, args);
va_end(args);
drawTextWrap(tmp, target, f, x, y, sz, c, maxWidth);
}
size_t textGetWidth(const char *str, const font *f, int sz)
{
size_t width = 0;
uint32_t untCnt = 0, tmpChr = 0;
FT_Error ret = 0;
resizeFont(f, sz);
size_t length = strlen(str);
for(unsigned i = 0; i < length; )
{
untCnt = decode_utf8(&tmpChr, (const uint8_t *)&str[i]);
i += untCnt;
//Ignore color changing chars
if(tmpChr == '\n' || tmpChr == '#' || tmpChr == '*' || tmpChr == '<' || tmpChr == '>')
continue;
if(untCnt <= 0)
break;
FT_GlyphSlot slot = loadGlyph(tmpChr, f, FT_LOAD_DEFAULT);
if(ret)
return 0;
width += slot->advance.x >> 6;
}
return width;
}
void drawRect(tex *target, int x, int y, int w, int h, const clr c)
{
uint32_t clr = clrGetColor(c);
for(int tY = y; tY < y + h; tY++)
{
if(yCheck(target, tY))
continue;
uint32_t *rowPtr = &target->data[tY * target->width + x];
for(int tX = x; tX < x + w; tX++, rowPtr++)
{
if(xCheck(target, tX))
continue;
*rowPtr = clr;
}
}
}
void drawRectAlpha(tex *target, int x, int y, int w, int h, const clr c)
{
for(int tY = y; tY < y + h; tY++)
{
if(yCheck(target, tY))
continue;
uint32_t *rowPtr = &target->data[tY * target->width + x];
for(int tX = x; tX < x + w; tX++, rowPtr++)
{
if(xCheck(target, tX))
continue;
*rowPtr = blend(c, clrCreateU32(*rowPtr));
}
}
}
tex *texCreate(int w, int h)
{
tex *ret = malloc(sizeof(tex));
ret->width = w;
ret->height = h;
ret->data = (uint32_t *)malloc(w * h * sizeof(uint32_t));
memset(ret->data, 0, w * h * sizeof(uint32_t));
ret->size = ret->width * ret->height;
return ret;
}
tex *texLoadPNGFile(const char *path)
{
FILE *pngIn = fopen(path, "rb");
if(pngIn != NULL)
{
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if(png == 0)
return NULL;
png_infop pngInfo = png_create_info_struct(png);
if(pngInfo == 0)
return NULL;
int jmp = setjmp(png_jmpbuf(png));
if(jmp)
return NULL;
png_init_io(png, pngIn);
png_read_info(png, pngInfo);
if(png_get_color_type(png, pngInfo) != PNG_COLOR_TYPE_RGBA)
{
png_destroy_read_struct(&png, &pngInfo, NULL);
return NULL;
}
tex *ret = malloc(sizeof(tex));
ret->width = png_get_image_width(png, pngInfo);
ret->height = png_get_image_height(png, pngInfo);
ret->data = (uint32_t *)malloc((ret->width * ret->height) * sizeof(uint32_t));
ret->size = ret->width * ret->height;
png_bytep *rows = malloc(sizeof(png_bytep) * ret->height);
for(int i = 0; i < ret->height; i++)
rows[i] = malloc(png_get_rowbytes(png, pngInfo));
png_read_image(png, rows);
uint32_t *dataPtr = &ret->data[0];
for(int y = 0; y < ret->height; y++)
{
uint32_t *rowPtr = (uint32_t *)rows[y];
for(int x = 0; x < ret->width; x++)
*dataPtr++ = *rowPtr++;
}
for(int i = 0; i < ret->height; i++)
free(rows[i]);
free(rows);
png_destroy_read_struct(&png, &pngInfo, NULL);
fclose(pngIn);
return ret;
}
return NULL;
}
static void jpegExit(j_common_ptr ptr)
{
jpegError *err = (jpegError *)ptr->err;
longjmp(err->jmpBuffer, 1);
}
tex *texLoadJPEGFile(const char *path)
{
FILE *jpegIn = fopen(path, "rb");
if(jpegIn)
{
struct jpeg_decompress_struct jpegInfo;
jpegError jpgError;
jpegInfo.err = jpeg_std_error(&jpgError.mgr);
jpgError.mgr.error_exit = jpegExit;
if(setjmp(jpgError.jmpBuffer))
{
jpeg_destroy_decompress(&jpegInfo);
fclose(jpegIn);
return NULL;
}
jpeg_create_decompress(&jpegInfo);
jpeg_stdio_src(&jpegInfo, jpegIn);
jpeg_read_header(&jpegInfo, true);
jpegInfo.out_color_space = JCS_RGB;
tex *ret = malloc(sizeof(tex));
ret->width = jpegInfo.image_width;
ret->height = jpegInfo.image_height;
ret->data = (uint32_t *)malloc((ret->width * ret->height) * sizeof(uint32_t));
ret->size = ret->width * ret->height;
jpeg_start_decompress(&jpegInfo);
JSAMPARRAY row = malloc(sizeof(JSAMPROW));
for(unsigned i = 0; i < ret->height; i++)
row[0] = malloc(sizeof(JSAMPLE) * ret->width * 3);
uint32_t *dataPtr = &ret->data[0];
for(int y = 0; y < ret->height; y++)
{
jpeg_read_scanlines(&jpegInfo, row, 1);
uint8_t *jpegPtr = row[0];
for(int x = 0; x < ret->width; x++, jpegPtr += 3)
*dataPtr++ = (0xFF << 24 | jpegPtr[2] << 16 | jpegPtr[1] << 8 | jpegPtr[0]);
}
jpeg_finish_decompress(&jpegInfo);
jpeg_destroy_decompress(&jpegInfo);
free(row[0]);
free(row);
fclose(jpegIn);
return ret;
}
return NULL;
}
tex *texLoadJPEGMem(const uint8_t *jpegData, size_t jpegSize)
{
struct jpeg_decompress_struct jpegInfo;
jpegError jpgError;
jpegInfo.err = jpeg_std_error(&jpgError.mgr);
jpgError.mgr.error_exit = jpegExit;
if(setjmp(jpgError.jmpBuffer))
{
jpeg_destroy_decompress(&jpegInfo);
return NULL;
}
jpeg_create_decompress(&jpegInfo);
jpeg_mem_src(&jpegInfo, jpegData, jpegSize);
jpeg_read_header(&jpegInfo, true);
jpegInfo.out_color_space = JCS_RGB;
tex *ret = malloc(sizeof(tex));
ret->width = jpegInfo.image_width;
ret->height = jpegInfo.image_height;
ret->data = (uint32_t *)malloc((ret->width * ret->height) * sizeof(uint32_t));
ret->size = ret->width * ret->height;
jpeg_start_decompress(&jpegInfo);
JSAMPARRAY row = malloc(sizeof(JSAMPROW));
for(unsigned i = 0; i < ret->height; i++)
row[0] = malloc(sizeof(JSAMPLE) * ret->width * 3);
uint32_t *dataPtr = &ret->data[0];
for(int y = 0; y < ret->height; y++)
{
jpeg_read_scanlines(&jpegInfo, row, 1);
uint8_t *jpegPtr = row[0];
for(int x = 0; x < ret->width; x++, jpegPtr += 3)
*dataPtr++ = (0xFF << 24 | jpegPtr[2] << 16 | jpegPtr[1] << 8 | jpegPtr[0]);
}
jpeg_finish_decompress(&jpegInfo);
jpeg_destroy_decompress(&jpegInfo);
free(row[0]);
free(row);
return ret;
}
tex *texLoadRGBA(const char *path)
{
tex *ret = malloc(sizeof(tex));
FILE *rgb = fopen(path, "rb");
fseek(rgb, 0, SEEK_END);
size_t dataSize = ftell(rgb) - sizeof(rgbaHead);
fseek(rgb, 0, SEEK_SET);
rgbaHead head;
fread(&head, sizeof(rgbaHead), 1, rgb);
ret->width = head.w;
ret->height = head.h;
ret->size = head.w * head.h;
ret->data = (uint32_t *)malloc((ret->width * ret->height) * sizeof(uint32_t));
unsigned char *inBuff = malloc(dataSize);
fread(inBuff, 1, dataSize, rgb);
uLongf destSz = ret->size * 4;
uncompress((unsigned char *)ret->data, &destSz, inBuff, dataSize);
free(inBuff);
return ret;
}
void texDestroy(tex *t)
{
if(t->data != NULL)
free(t->data);
if(t != NULL)
free(t);
}
void texClearColor(tex *in, const clr c)
{
uint32_t *dataPtr = &in->data[0];
uint32_t color = clrGetColor(c);
for(int i = 0; i < in->size; i++)
*dataPtr++ = color;
}
void texDraw(const tex *t, tex *target, int x, int y)
{
if(t != NULL)
{
uint32_t *dataPtr = &t->data[0];
for(int tY = y; tY < y + t->height; tY++)
{
if(yCheck(target, tY))
continue;
uint32_t *rowPtr = &target->data[tY * target->width + x];
for(int tX = x; tX < x + t->width; tX++, rowPtr++)
{
if(xCheck(target, tX))
continue;
clr dataClr = clrCreateU32(*dataPtr++);
clr fbClr = clrCreateU32(*rowPtr);
*rowPtr = blend(dataClr, fbClr);
}
}
}
}
void texDrawNoAlpha(const tex *t, tex *target, int x, int y)
{
if(t != NULL)
{
uint32_t *dataPtr = &t->data[0];
for(int tY = y; tY < y + t->height; tY++)
{
if(yCheck(target, tY))
continue;
uint32_t *rowPtr = &target->data[tY * target->width + x];
for(int tX = x; tX < x + t->width; tX++)
{
if(xCheck(target, tX))
continue;
*rowPtr++ = *dataPtr++;
}
}
}
}
void texDrawSkip(const tex *t, tex *target, int x, int y)
{
if(t != NULL)
{
uint32_t *dataPtr = &t->data[0];
for(int tY = y; tY < y + (t->height / 2); tY++, dataPtr += t->width)
{
if(yCheck(target, tY))
continue;
uint32_t *rowPtr = &target->data[tY * target->width + x];
for(int tX = x; tX < x + (t->width / 2); tX++, rowPtr++)
{
if(xCheck(target, tX))
continue;
clr px1 = clrCreateU32(*dataPtr++);
clr px2 = clrCreateU32(*dataPtr++);
clr fbPx = clrCreateU32(*rowPtr);
*rowPtr = blend(smooth(px1, px2), fbPx);
}
}
}
}
void texDrawSkipNoAlpha(const tex *t, tex *target, int x, int y)
{
if(t != NULL)
{
uint32_t *dataPtr = &t->data[0];
for(int tY = y; tY < y + (t->height / 2); tY++, dataPtr += t->width)
{
if(yCheck(target, tY))
continue;
uint32_t *rowPtr = &target->data[tY * target->width + x];
for(int tX = x; tX < x + (t->width / 2); tX++, rowPtr++)
{
if(xCheck(target, tX))
continue;
clr px1 = clrCreateU32(*dataPtr++);
clr px2 = clrCreateU32(*dataPtr++);
*rowPtr = smooth_32t(px1, px2);
}
}
}
}
void texDrawInvert(const tex *t, tex *target, int x, int y)
{
if(t != NULL)
{
uint32_t *dataPtr = &t->data[0];
for(int tY = y; tY < y + t->height; tY++)
{
if(yCheck(target, tY))
continue;
uint32_t *rowPtr = &target->data[tY * target->width + x];
for(int tX = x; tX < x + t->width; tX++, rowPtr++)
{
if(xCheck(target, tX))
continue;
clr dataClr = clrCreateU32(*dataPtr++);
clrInvert(&dataClr);
clr fbClr = clrCreateU32(*rowPtr);
*rowPtr = blend(dataClr, fbClr);
}
}
}
}
void texSwapColors(tex *t, const clr old, const clr newColor)
{
uint32_t oldClr = clrGetColor(old), newClr = clrGetColor(newColor);
uint32_t *dataPtr = &t->data[0];
for(unsigned i = 0; i < t->size; i++, dataPtr++)
{
if(*dataPtr == oldClr)
*dataPtr = newClr;
}
}
tex *texCreateFromPart(const tex *src, int x, int y, int w, int h)
{
tex *ret = texCreate(w, h);
uint32_t *retPtr = &ret->data[0];
for(int tY = y; tY < y + h; tY++)
{
uint32_t *srcPtr = &src->data[tY * src->width + x];
for(int tX = x; tX < x + w; tX++)
*retPtr++ = *srcPtr++;
}
return ret;
}
void texScaleToTex(const tex *in, tex *out, int scale)
{
for(int y = 0; y < in->height; y++)
{
for(int tY = y * scale; tY < (y * scale) + scale; tY++)
{
uint32_t *inPtr = &in->data[y * in->width];
for(int x = 0; x < in->width; x++, inPtr++)
{
for(int tX = x * scale; tX < (x * scale) + scale; tX++)
{
out->data[tY * (in->width * scale) + tX] = *inPtr;
}
}
}
}
}
void texApplyAlphaMask(tex *target, const alphaMask *a)
{
if(target->width != a->width || target->height != a->height)
return;
uint32_t *pix = &target->data[0];
for(unsigned i = 0; i < target->size; i++, pix++)
{
clr msk = clrCreateU32(*pix);
msk.a = a->dat[i];
*pix = clrGetColor(msk);
}
}
alphaMask *alphaMaskLoad(unsigned w, unsigned h, const char *file)
{
FILE *mskIn = fopen(file, "rb");
if(!mskIn)
return NULL;
fseek(mskIn, 0, SEEK_END);
size_t mskSize = ftell(mskIn);
fseek(mskIn, 0, SEEK_SET);
alphaMask *ret = malloc(sizeof(alphaMask));
ret->width = w;
ret->height = h;
ret->dat = malloc(w * h);
fread(ret->dat, 1, mskSize, mskIn);
fclose(mskIn);
return ret;
}
void alphaMaskDestroy(alphaMask *a)
{
free(a->dat);
free(a);
}
font *fontLoadSharedFonts()
{
font *ret = malloc(sizeof(font));
if((ret->libRet = FT_Init_FreeType(&ret->lib)))
{
free(ret);
return NULL;
}
for(int i = 0; i < 6; i++)
{
PlFontData plFont;
if(R_FAILED(plGetSharedFontByType(&plFont, i)))
{
free(ret);
return NULL;
}
if((ret->faceRet = FT_New_Memory_Face(ret->lib, plFont.address, plFont.size, 0, &ret->face[i])))
{
free(ret);
return NULL;
}
}
ret->external = false;
ret->fntData = NULL;
return ret;
}
font *fontLoadTTF(const char *path)
{
font *ret = malloc(sizeof(font));
if((ret->libRet = FT_Init_FreeType(&ret->lib)))
{
free(ret);
return NULL;
}
FILE *ttf = fopen(path, "rb");
fseek(ttf, 0, SEEK_END);
size_t ttfSize = ftell(ttf);
fseek(ttf, 0, SEEK_SET);
ret->fntData = malloc(ttfSize);
fread(ret->fntData, 1, ttfSize, ttf);
fclose(ttf);
if((ret->faceRet = FT_New_Memory_Face(ret->lib, ret->fntData, ttfSize, 0, &ret->face[0])))
{
free(ret->fntData);
free(ret);
return NULL;
}
ret->external = true;
return ret;
}
void fontDestroy(font *f)
{
if(f->external && f->faceRet == 0)
FT_Done_Face(f->face[0]);
else if(!f->external && f->faceRet == 0)
{
for(int i = 0; i < 6; i++)
FT_Done_Face(f->face[i]);
}
if(f->libRet == 0)
FT_Done_FreeType(f->lib);
if(f->fntData != NULL)
free(f->fntData);
free(f);
}

367
src/gfx.cpp Normal file
View File

@ -0,0 +1,367 @@
#include <stdio.h>
#include <map>
#include <switch.h>
#include <SDL.h>
#include <SDL_image.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#define VA_SIZE 1024
#include "gfx.h"
static SDL_Window *wind;
SDL_Renderer *gfx::render;
static FT_Library lib;
static FT_Face face[6];
static int totalFonts = 0;
static bool loaded = false;
static const SDL_Color *textcol;
static SDL_Color red = {0xFF, 0x00, 0x00, 0xFF};
static SDL_Color green = {0x00, 0xFF, 0x00, 0xFF};
static SDL_Color blue = {0x00, 0x99, 0xEE, 0xFF};
static SDL_Color yellow = {0xF8, 0xFC, 0x00, 0xFF};
static const uint32_t redMask = 0xFF000000;
static const uint32_t greenMask = 0x00FF0000;
static const uint32_t blueMask = 0x0000FF00;
static const uint32_t alphaMask = 0x000000FF;
static inline bool compClr(const SDL_Color *c1, const SDL_Color *c2)
{
return (c1->r == c2->r) && (c1->b == c2->b) && (c1->g == c2->g) && (c1->a == c2->a);
}
//Cache glyph textures
typedef struct
{
uint16_t w, h;
int advX, top, left;
SDL_Texture *tex;
} glyphData;
//<Char, font size>, tex
std::map<std::pair<uint32_t, int>, glyphData> glyphCache;
static bool loadSystemFont()
{
PlFontData shared[6];
uint64_t langCode = 0;
if(R_FAILED(plInitialize(PlServiceType_System)))
return false;
if(FT_Init_FreeType(&lib))
return false;
if(R_FAILED(setGetLanguageCode(&langCode)))
return false;
if(R_FAILED(plGetSharedFont(langCode, shared, 6, &totalFonts)))
return false;
for(int i = 0; i < totalFonts; i++)
{
if(FT_New_Memory_Face(lib, (FT_Byte *)shared[i].address, shared[i].size, 0, &face[i]))
return false;
}
loaded = true;
return true;
}
static void freeSystemFont()
{
if(loaded)
{
for(int i = 0; i < totalFonts; i++)
FT_Done_Face(face[i]);
FT_Done_FreeType(lib);
}
plExit();
}
void gfx::init()
{
SDL_Init(SDL_INIT_VIDEO);
IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG);
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best");
SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1");
wind = SDL_CreateWindow("JKSV", 0, 0, 1280, 720, SDL_WINDOW_SHOWN);
render = SDL_CreateRenderer(wind, -1, SDL_RENDERER_ACCELERATED);
loadSystemFont();
}
void gfx::exit()
{
IMG_Quit();
SDL_Quit();
freeSystemFont();
for(auto c : glyphCache)
SDL_DestroyTexture(c.second.tex);
}
void gfx::clear(const SDL_Color *c)
{
SDL_SetRenderDrawColor(render, c->r, c->g, c->b, c->a);
SDL_RenderClear(render);
}
void gfx::present()
{
SDL_RenderPresent(render);
}
SDL_Texture *gfx::loadJPEGMem(const void *jpegData, size_t jpegsize)
{
SDL_Texture *ret = NULL;
SDL_RWops *jpeg = SDL_RWFromConstMem(jpegData, jpegsize);
SDL_Surface *tmpSurf = IMG_LoadJPG_RW(jpeg);
if(tmpSurf)
ret = SDL_CreateTextureFromSurface(render, tmpSurf);
SDL_FreeSurface(tmpSurf);
SDL_RWclose(jpeg);
return ret;
}
SDL_Texture *gfx::loadImageFile(const char *file)
{
SDL_Texture *ret = NULL;
SDL_Surface *tmpSurf = IMG_Load(file);
if(tmpSurf)
ret = SDL_CreateTextureFromSurface(render, tmpSurf);
SDL_FreeSurface(tmpSurf);
return ret;
}
static inline void resizeFont(int sz)
{
for(int i = 0; i < totalFonts; i++)
FT_Set_Char_Size(face[i], 0, sz * 64, 90, 90);
}
static inline FT_GlyphSlot loadGlyph(const uint32_t c, FT_Int32 flags)
{
for(int i = 0; i < totalFonts; i++)
{
FT_UInt cInd = 0;
if( (cInd = FT_Get_Char_Index(face[i], c)) != 0 && FT_Load_Glyph(face[i], cInd, flags) == 0)
return face[i]->glyph;
}
return NULL;
}
static glyphData *getGlyph(uint32_t chr, int size)
{
//If it's already been loaded and rendered, grab the texture
if(glyphCache.find(std::make_pair(chr, size)) != glyphCache.end())
return &glyphCache[std::make_pair(chr, size)];
//Load glyph with Freetype
FT_GlyphSlot glyph = loadGlyph(chr, FT_LOAD_RENDER);
FT_Bitmap bmp = glyph->bitmap;
if(bmp.pixel_mode != FT_PIXEL_MODE_GRAY)
return NULL;
//Convert to SDL_Surface -> Texture
SDL_Texture *tex;
size_t glyphSize = bmp.rows * bmp.width;
uint8_t *bmpPtr = bmp.buffer;
uint32_t basePixel = 0xFFFFFF00;
uint32_t *tmpBuff = (uint32_t *)malloc(sizeof(uint32_t) * glyphSize);
//Loop through and fill out buffer
for(size_t i = 0; i < glyphSize; i++)
tmpBuff[i] = basePixel | *bmpPtr++;
SDL_Surface *tmpSurf = SDL_CreateRGBSurfaceFrom(tmpBuff, bmp.width, bmp.rows, 32, 4 * bmp.width, redMask, greenMask, blueMask, alphaMask);
tex = SDL_CreateTextureFromSurface(gfx::render, tmpSurf);
SDL_FreeSurface(tmpSurf);
free(tmpBuff);
//Add it to cache map
glyphCache[std::make_pair(chr, size)] = {(uint16_t)bmp.width, (uint16_t)bmp.rows, (int)glyph->advance.x >> 6, glyph->bitmap_top, glyph->bitmap_left, tex};
return &glyphCache[std::make_pair(chr, size)];
}
//Takes care of special characters/color switching
static inline bool specialChar(const uint32_t *p, const int *fontSize, const SDL_Color *c, const int *baseX, int *modX, int *modY)
{
//set to false on default
bool ret = true;
switch(*p)
{
case '\n':
*modX = *baseX;
*modY += *fontSize + 8;
break;
case '#':
if(compClr(textcol, &blue))
textcol = c;
else
textcol = &blue;
break;
case '*':
if(compClr(textcol, &red))
textcol = c;
else
textcol = &red;
break;
case '<':
if(compClr(textcol, &yellow))
textcol = c;
else
textcol = &yellow;
break;
case '>':
if(compClr(textcol, &green))
textcol = c;
else
textcol = &green;
break;
default:
ret = false;//no special char
break;
}
return ret;
}
void gfx::drawTextf(int fontSize, int x, int y, const SDL_Color *c, const char *fmt, ...)
{
char tmp[VA_SIZE];
va_list args;
va_start(args, fmt);
vsprintf(tmp, fmt, args);
va_end(args);
int tmpX = x;
uint32_t point = 0;
ssize_t unitCnt = 0;
size_t textLength = strlen(tmp);
resizeFont(fontSize);
textcol = c;
for(unsigned i = 0; i < textLength; )
{
unitCnt = decode_utf8(&point, (const uint8_t *)&tmp[i]);
if(unitCnt <= 0)
break;
i += unitCnt;
if(specialChar(&point, &fontSize, c, &x, &tmpX, &y))
continue;
glyphData *g = getGlyph(point, fontSize);
if(g != NULL)
{
SDL_Rect src = {0, 0, g->w, g->h};
SDL_Rect dst = {tmpX + g->left, y + (fontSize - g->top), g->w, g->h};
SDL_SetTextureColorMod(g->tex, c->r, c->g, c->b);
SDL_RenderCopy(render, g->tex, &src, &dst);
tmpX += g->advX;
}
}
}
void gfx::drawTextfWrap(int fontSize, int x, int y, int maxWidth, const SDL_Color *c, const char *fmt, ...)
{
char tmp[VA_SIZE], wordBuff[128];
va_list args;
va_start(args, fmt);
vsprintf(tmp, fmt, args);
va_end(args);
resizeFont(fontSize);
size_t nextBreak = 0, strlength = strlen(tmp);
int tmpX = x;
textcol = c;
for(unsigned i = 0; i < strlength; )
{
nextBreak = strcspn(&tmp[i], " /_-");
memset(wordBuff, 0, 128);
memcpy(wordBuff, &tmp[i], nextBreak + 1);
size_t width = gfx::getTextWidth(wordBuff, fontSize);
if(tmpX + width >= x + maxWidth)
{
tmpX = x;
y += fontSize + 8;
}
size_t wordLength = strlen(wordBuff);
uint32_t point = 0;
for(unsigned j = 0; j < wordLength; )
{
ssize_t unitCnt = decode_utf8(&point, (const uint8_t *)&wordBuff[j]);
if(unitCnt <= 0)
break;
j += unitCnt;
if(specialChar(&point, &fontSize, c, &x, &tmpX, &y))
continue;
glyphData *g = getGlyph(point, fontSize);
if(g != NULL)
{
SDL_Rect src = {0, 0, g->w, g->h};
SDL_Rect dst = {tmpX + g->left, y + (fontSize - g->top), g->w, g->h};
SDL_SetTextureColorMod(g->tex, textcol->r, textcol->g, textcol->b);
SDL_RenderCopy(render, g->tex, &src, &dst);
tmpX += g->advX;
}
}
i += wordLength;
}
}
size_t gfx::getTextWidth(const char *str, int fontSize)
{
resizeFont(fontSize);
size_t width = 0, strlength = strlen(str);
uint32_t unitCnt = 0, point = 0;
for(unsigned i = 0; i < strlength; )
{
unitCnt = decode_utf8(&point, (const uint8_t *)&str[i]);
if(unitCnt <= 0)
break;
i += unitCnt;
//Ignore these
if(point == '\n')
continue;
glyphData *g = getGlyph(point, fontSize);
if(g != NULL)
width += g->advX;
}
return width;
}

View File

@ -45,7 +45,7 @@ int main(int argc, const char *argv[])
{
romfsInit();
fs::init();
graphicsInit(1280, 720);
gfx::init();
ui::initTheme();
ui::showLoadScreen();
data::init();
@ -63,16 +63,15 @@ int main(int argc, const char *argv[])
else if(down & HidNpadButton_Plus)
break;
gfxBeginFrame();
ui::runApp(down, held);
if(debDataStats)
data::dispStats();
gfxEndFrame();
gfx::present();
}
ui::exit();
data::exit();
graphicsExit();
gfx::exit();
fs::exit();
}

View File

@ -26,29 +26,23 @@ ColorSetId ui::thmID;
std::string ui::folderMenuInfo;
//UI colors
clr ui::clearClr, ui::txtCont, ui::txtDiag, ui::rectLt, ui::rectSh, ui::tboxClr, divClr;
SDL_Color ui::clearClr, ui::txtCont, ui::txtDiag, ui::rectLt, ui::rectSh, ui::tboxClr, divClr;
//textbox pieces
//I was going to flip them when I draw them, but then laziness kicked in.
tex *ui::cornerTopLeft, *ui::cornerTopRight, *ui::cornerBottomLeft, *ui::cornerBottomRight;
SDL_Texture *ui::cornerTopLeft, *ui::cornerTopRight, *ui::cornerBottomLeft, *ui::cornerBottomRight;
//Progress bar covers + dialog box predrawn
tex *ui::progCovLeft, *ui::progCovRight, *ui::diaBox;
SDL_Texture *ui::progCovLeft, *ui::progCovRight, *ui::diaBox;
//Menu box pieces
tex *mnuTopLeft, *mnuTopRight, *mnuBotLeft, *mnuBotRight;
SDL_Texture *mnuTopLeft, *mnuTopRight, *mnuBotLeft, *mnuBotRight;
//Select box + top left icon
tex *ui::sideBar;
SDL_Texture *ui::sideBar;
alphaMask *ui::iconMask;
//Shared font
font *ui::shared;
//Don't waste time drawing top and bottom over and over
//guide graphics are to save cpu drawing that over and over with alpha
static tex *top, *bot, *usrGuide, *ttlGuide, *fldrGuide, *optGuide;
static SDL_Texture *icn;
static SDL_Color white = {0xFF, 0xFF, 0xFF, 0xFF};
//X position of help texts. Calculated to make editing quicker/easier
static unsigned userHelpX, titleHelpX, folderHelpX, optHelpX;
@ -234,87 +228,69 @@ static void loadTrans()
void ui::initTheme()
{
if(fs::fileExists(fs::getWorkDir() + "font.ttf"))
shared = fontLoadTTF(std::string(fs::getWorkDir() + "font.ttf").c_str());
else
shared = fontLoadSharedFonts();
iconMask = alphaMaskLoad(256, 256, "romfs:/img/icn/icon.msk");
setsysGetColorSetId(&thmID);
switch(thmID)
{
case ColorSetId_Light:
clearClr = clrCreateU32(0xFFEBEBEB);
txtCont = clrCreateU32(0xFF000000);
txtDiag = clrCreateU32(0xFFFFFFFF);
rectLt = clrCreateU32(0xFFDFDFDF);
rectSh = clrCreateU32(0xFFCACACA);
tboxClr = clrCreateU32(0xFF505050);
divClr = clrCreateU32(0xFF000000);
clearClr = {0xEB, 0xEB, 0xEB, 0xFF};
txtCont = {0x00, 0x00, 0x00, 0xFF};
txtDiag = {0xFF, 0xFF, 0xFF, 0xFF};
rectLt = {0xDF, 0xDF, 0xDF, 0xFF};
rectSh = {0xCA, 0xCA, 0xCA, 0xFF};
tboxClr = {0x50, 0x50, 0x50, 0xFF};
divClr = {0x00, 0x00, 0x00, 0xFF};
break;
default:
case ColorSetId_Dark:
//jic
thmID = ColorSetId_Dark;
clearClr = clrCreateU32(0xFF2D2D2D);
txtCont = clrCreateU32(0xFFFFFFFF);
txtDiag = clrCreateU32(0xFF000000);
rectLt = clrCreateU32(0xFF505050);
rectSh = clrCreateU32(0xFF202020);
tboxClr = clrCreateU32(0xFFEBEBEB);
divClr = clrCreateU32(0xFFFFFFFF);
clearClr = {0x2D, 0x2D, 0x2D, 0xFF};
txtCont = {0xFF, 0xFF, 0xFF, 0xFF};
txtDiag = {0x00, 0x00, 0x00, 0xFF};
rectLt = {0x50, 0x50, 0x50, 0xFF};
rectSh = {0x20, 0x20, 0x20, 0xFF};
tboxClr = {0xEB, 0xEB, 0xEB, 0xFF};
divClr = {0xFF, 0xFF, 0xFF, 0xFF};
break;
}
}
void ui::init()
{
tex *icn;
char verStr[16];
mnuTopLeft = texLoadPNGFile("romfs:/img/fb/menuTopLeft.png");
mnuTopRight = texLoadPNGFile("romfs:/img/fb/menuTopRight.png");
mnuBotLeft = texLoadPNGFile("romfs:/img/fb/menuBotLeft.png");
mnuBotRight = texLoadPNGFile("romfs:/img/fb/menuBotRight.png");
mnuTopLeft = gfx::loadImageFile("romfs:/img/fb/menuTopLeft.png");
mnuTopRight = gfx::loadImageFile("romfs:/img/fb/menuTopRight.png");
mnuBotLeft = gfx::loadImageFile("romfs:/img/fb/menuBotLeft.png");
mnuBotRight = gfx::loadImageFile("romfs:/img/fb/menuBotRight.png");
switch(ui::thmID)
{
case ColorSetId_Light:
//Dark corners
cornerTopLeft = texLoadPNGFile("romfs:/img/tboxDrk/tboxCornerTopLeft.png");
cornerTopRight = texLoadPNGFile("romfs:/img/tboxDrk/tboxCornerTopRight.png");
cornerBottomLeft = texLoadPNGFile("romfs:/img/tboxDrk/tboxCornerBotLeft.png");
cornerBottomRight = texLoadPNGFile("romfs:/img/tboxDrk/tboxCornerBotRight.png");
progCovLeft = texLoadPNGFile("romfs:/img/tboxDrk/progBarCoverLeftDrk.png");
progCovRight = texLoadPNGFile("romfs:/img/tboxDrk/progBarCoverRightDrk.png");
icn = texLoadPNGFile("romfs:/img/icn/icnDrk.png");
sideBar = texLoadPNGFile("romfs:/img/fb/lLight.png");
cornerTopLeft = gfx::loadImageFile("romfs:/img/tboxDrk/tboxCornerTopLeft.png");
cornerTopRight = gfx::loadImageFile("romfs:/img/tboxDrk/tboxCornerTopRight.png");
cornerBottomLeft = gfx::loadImageFile("romfs:/img/tboxDrk/tboxCornerBotLeft.png");
cornerBottomRight = gfx::loadImageFile("romfs:/img/tboxDrk/tboxCornerBotRight.png");
progCovLeft = gfx::loadImageFile("romfs:/img/tboxDrk/progBarCoverLeftDrk.png");
progCovRight = gfx::loadImageFile("romfs:/img/tboxDrk/progBarCoverRightDrk.png");
icn = gfx::loadImageFile("romfs:/img/icn/icnDrk.png");
sideBar = gfx::loadImageFile("romfs:/img/fb/lLight.png");
break;
default:
//Light corners
cornerTopLeft = texLoadPNGFile("romfs:/img/tboxLght/tboxCornerTopLeft.png");
cornerTopRight = texLoadPNGFile("romfs:/img/tboxLght/tboxCornerTopRight.png");
cornerBottomLeft = texLoadPNGFile("romfs:/img/tboxLght/tboxCornerBotLeft.png");
cornerBottomRight = texLoadPNGFile("romfs:/img/tboxLght/tboxCornerBotRight.png");
progCovLeft = texLoadPNGFile("romfs:/img/tboxLght/progBarCoverLeftLight.png");
progCovRight = texLoadPNGFile("romfs:/img/tboxLght/progBarCoverRightLight.png");
icn = texLoadPNGFile("romfs:/img/icn/icnLght.png");
sideBar = texLoadPNGFile("romfs:/img/fb/lDark.png");
cornerTopLeft = gfx::loadImageFile("romfs:/img/tboxLght/tboxCornerTopLeft.png");
cornerTopRight = gfx::loadImageFile("romfs:/img/tboxLght/tboxCornerTopRight.png");
cornerBottomLeft = gfx::loadImageFile("romfs:/img/tboxLght/tboxCornerBotLeft.png");
cornerBottomRight = gfx::loadImageFile("romfs:/img/tboxLght/tboxCornerBotRight.png");
progCovLeft = gfx::loadImageFile("romfs:/img/tboxLght/progBarCoverLeftLight.png");
progCovRight = gfx::loadImageFile("romfs:/img/tboxLght/progBarCoverRightLight.png");
icn = gfx::loadImageFile("romfs:/img/icn/icnLght.png");
sideBar = gfx::loadImageFile("romfs:/img/fb/lDark.png");
break;
}
top = texCreate(1280, 88);
bot = texCreate(1280, 72);
diaBox = texCreate(640, 420);
//Setup dialog box
drawTextbox(diaBox, 0, 0, 640, 420);
drawRect(diaBox, 0, 56, 640, 2, ui::thmID == ColorSetId_Light ? clrCreateU32(0xFF6D6D6D) : clrCreateU32(0xFFCCCCCC));
if(ui::textMode && data::skipUser)
{
ui::textTitlePrep(data::curUser);
@ -339,45 +315,11 @@ void ui::init()
util::replaceButtonsInString(ui::optMenuExp[4]);
util::replaceButtonsInString(ui::optMenuExp[5]);
//Setup top and bottom gfx
texClearColor(top, clearClr);
texDraw(icn, top, 66, 27);
drawText("JKSV", top, shared, 130, 38, 24, ui::txtCont);
drawRect(top, 30, 87, 1220, 1, ui::txtCont);
texClearColor(bot, clearClr);
drawRect(bot, 30, 0, 1220, 1, ui::txtCont);
sprintf(verStr, "v. %02d.%02d.%04d", BLD_MON, BLD_DAY, BLD_YEAR);
drawText(verStr, bot, shared, 8, author == "NULL" ? 56 : 38, 12, ui::txtCont);
if(author != "NULL")
drawText(std::string("Translation: " + author).c_str(), bot, ui::shared, 8, 56, 12, ui::txtCont);
//Not needed anymore
texDestroy(icn);
//Create graphics to hold guides
usrGuide = texCreate(textGetWidth(userHelp.c_str(), ui::shared, 18), 28);
ttlGuide = texCreate(textGetWidth(titleHelp.c_str(), ui::shared, 18), 28);
fldrGuide = texCreate(textGetWidth(folderHelp.c_str(), ui::shared, 18), 28);
optGuide = texCreate(textGetWidth(optHelp.c_str(), ui::shared, 18), 28);
//Clear with bg color
texClearColor(usrGuide, ui::clearClr);
texClearColor(ttlGuide, ui::clearClr);
texClearColor(fldrGuide, ui::clearClr);
texClearColor(optGuide, ui::clearClr);
//Draw text to them
drawText(userHelp.c_str(), usrGuide, ui::shared, 0, 3, 18, ui::txtCont);
drawText(titleHelp.c_str(), ttlGuide, ui::shared, 0, 3, 18, ui::txtCont);
drawText(folderHelp.c_str(), fldrGuide, ui::shared, 0, 3, 18, ui::txtCont);
drawText(optHelp.c_str(), optGuide, ui::shared, 0, 3, 18, ui::txtCont);
//Calculate x position of help text
userHelpX = 1220 - usrGuide->width;
titleHelpX = 1220 - ttlGuide->width;
folderHelpX = 1220 - fldrGuide->width;
optHelpX = 1220 - optGuide->width;
userHelpX = 1220 - gfx::getTextWidth(ui::userHelp.c_str(), 18);
titleHelpX = 1220 - gfx::getTextWidth(ui::titleHelp.c_str(), 18);
folderHelpX = 1220 - gfx::getTextWidth(ui::folderHelp.c_str(), 18);
optHelpX = 1220 - gfx::getTextWidth(ui::optHelp.c_str(), 18);
//setup pad
padConfigureInput(1, HidNpadStyleSet_NpadStandard);
@ -390,98 +332,93 @@ void ui::init()
void ui::exit()
{
texDestroy(cornerTopLeft);
texDestroy(cornerTopRight);
texDestroy(cornerBottomLeft);
texDestroy(cornerBottomRight);
texDestroy(progCovLeft);
texDestroy(progCovRight);
SDL_DestroyTexture(cornerTopLeft);
SDL_DestroyTexture(cornerTopRight);
SDL_DestroyTexture(cornerBottomLeft);
SDL_DestroyTexture(cornerBottomRight);
SDL_DestroyTexture(progCovLeft);
SDL_DestroyTexture(progCovRight);
texDestroy(mnuTopLeft);
texDestroy(mnuTopRight);
texDestroy(mnuBotLeft);
texDestroy(mnuBotRight);
SDL_DestroyTexture(mnuTopLeft);
SDL_DestroyTexture(mnuTopRight);
SDL_DestroyTexture(mnuBotLeft);
SDL_DestroyTexture(mnuBotRight);
texDestroy(usrGuide);
texDestroy(ttlGuide);
texDestroy(fldrGuide);
texDestroy(optGuide);
texDestroy(top);
texDestroy(bot);
texDestroy(diaBox);
alphaMaskDestroy(iconMask);
fontDestroy(shared);
SDL_DestroyTexture(icn);
}
void ui::showLoadScreen()
{
tex *icn = texLoadJPEGFile("romfs:/icon.jpg");
gfxBeginFrame();
texClearColor(frameBuffer, clrCreateU32(0xFF2D2D2D));
texDrawNoAlpha(icn, frameBuffer, 512, 232);
drawText("Loading...", frameBuffer, ui::shared, 1100, 673, 16, clrCreateU32(0xFFFFFFFF));
gfxEndFrame();
texDestroy(icn);
SDL_Texture *icon = gfx::loadImageFile("romfs:/icon.jpg");
SDL_SetRenderDrawColor(gfx::render, 0x2D, 0x2D, 0x2D, 0xFF);
SDL_RenderClear(gfx::render);
gfx::texDraw(icon, 512, 232);
gfx::drawTextf(16, 1100, 673, &white, "Loading...");
gfx::present();
SDL_DestroyTexture(icon);
}
void ui::drawUI()
{
texClearColor(frameBuffer, clearClr);
texDrawNoAlpha(top, frameBuffer, 0, 0);
texDrawNoAlpha(bot, frameBuffer, 0, 648);
gfx::clear(&ui::clearClr);
gfx::texDraw(icn, 66, 27);
gfx::drawTextf(24, 130, 38, &ui::txtCont, "JKSV");
gfx::drawLine(&divClr, 30, 88, 1250, 88);
gfx::drawLine(&divClr, 30, 648, 1250, 648);
//Version / translation author
gfx::drawTextf(12, 8, 700, &ui::txtCont, "v. %02d.%02d.%04d", BLD_MON, BLD_DAY, BLD_YEAR);
if(author != "NULL")
gfx::drawTextf(12, 8, 682, &ui::txtCont, "Translation: %s", author.c_str());
switch(mstate)
{
case USR_SEL:
texDrawNoAlpha(usrGuide, frameBuffer, userHelpX, 673);
gfx::drawTextf(18, userHelpX, 673, &ui::txtCont, userHelp.c_str());
ui::drawUserMenu();
break;
case TTL_SEL:
texDrawNoAlpha(ttlGuide, frameBuffer, titleHelpX, 673);
gfx::drawTextf(18, titleHelpX, 673, &ui::txtCont, titleHelp.c_str());
ui::drawTitleMenu();
break;
case FLD_SEL:
texDrawNoAlpha(sideBar, frameBuffer, 0, 88);
texDrawNoAlpha(fldrGuide, frameBuffer, folderHelpX, 673);
gfx::texDraw(sideBar, 0, 89);
gfx::drawTextf(18, folderHelpX, 673, &ui::txtCont, folderHelp.c_str());
ui::drawFolderMenu();
break;
case TXT_USR:
texDrawNoAlpha(sideBar, frameBuffer, 0, 88);
texDrawNoAlpha(usrGuide, frameBuffer, userHelpX, 673);
gfx::texDraw(sideBar, 0, 89);
gfx::drawTextf(18, userHelpX, 673, &ui::txtCont, userHelp.c_str());
ui::drawTextUserMenu();
break;
case TXT_TTL:
texDrawNoAlpha(sideBar, frameBuffer, 0, 88);
texDrawNoAlpha(ttlGuide, frameBuffer, titleHelpX, 673);
gfx::texDraw(sideBar, 0, 89);
gfx::drawTextf(18, titleHelpX, 673, &ui::txtCont, titleHelp.c_str());
ui::drawTextTitleMenu();
break;
case TXT_FLD:
texDrawNoAlpha(sideBar, frameBuffer, 0, 88);
texDrawNoAlpha(fldrGuide, frameBuffer, folderHelpX, 673);
gfx::texDraw(sideBar, 0, 89);
gfx::drawTextf(18, folderHelpX, 673, &ui::txtCont, folderHelp.c_str());
ui::drawTextFolderMenu();
break;
case EX_MNU:
texDrawNoAlpha(sideBar, frameBuffer, 0, 88);
gfx::texDraw(sideBar, 0, 89);
ui::drawExMenu();
break;
case OPT_MNU:
texDrawNoAlpha(sideBar, frameBuffer, 0, 88);
texDrawNoAlpha(optGuide, frameBuffer, optHelpX, 673);
gfx::texDraw(sideBar, 0, 89);
ui::drawOptMenu();
break;
case ADV_MDE:
drawRect(frameBuffer, 640, 88, 1, 559, ui::txtCont);
gfx::drawRect(&ui::txtCont, 640, 88, 1, 559);
drawAdvMode();
break;
}
@ -489,43 +426,30 @@ void ui::drawUI()
void ui::drawBoundBox(int x, int y, int w, int h, int clrSh)
{
clr rectClr = clrCreateRGBA(0x00, 0x88 + clrSh, 0xC5 + (clrSh / 2), 0xFF);
SDL_Color rectClr;
texSwapColors(mnuTopLeft, clrCreateRGBA(0x00, 0x88, 0xC5, 0xFF), rectClr);
texSwapColors(mnuTopRight, clrCreateRGBA(0x00, 0x88, 0xC5, 0xFF), rectClr);
texSwapColors(mnuBotLeft, clrCreateRGBA(0x00, 0x88, 0xC5, 0xFF), rectClr);
texSwapColors(mnuBotRight, clrCreateRGBA(0x00, 0x88, 0xC5, 0xFF), rectClr);
if(ui::thmID == ColorSetId_Light)
rectClr = {0xFD, 0xFD, 0xFD, 0xFF};
else
rectClr = {0x21, 0x22, 0x21, 0xFF};
switch(ui::thmID)
{
case ColorSetId_Light:
drawRect(frameBuffer, x + 4, y + 4, w - 8, h - 8, clrCreateU32(0xFFFDFDFD));
break;
gfx::drawRect(&rectClr, x + 4, y + 4, w - 8, h - 8);
default:
case ColorSetId_Dark:
drawRect(frameBuffer, x + 4, y + 4, w - 8, h - 8, clrCreateU32(0xFF212221));
break;
}
rectClr = {0x00, 0x88, 0xC5, 0xFF};
//top
texDraw(mnuTopLeft, frameBuffer, x, y);
drawRect(frameBuffer, x + 4, y, w - 8, 4, rectClr);
texDraw(mnuTopRight, frameBuffer, (x + w) - 4, y);
gfx::texDraw(mnuTopLeft, x, y);
gfx::drawRect(&rectClr, x + 4, y, w - 8, 4);
gfx::texDraw(mnuTopRight, (x + w) - 4, y);
//mid
drawRect(frameBuffer, x, y + 4, 4, h - 8, rectClr);
drawRect(frameBuffer, (x + w) - 4, y + 4, 4, h - 8, rectClr);
gfx::drawRect(&rectClr, x, y + 4, 4, h - 8);
gfx::drawRect(&rectClr, (x + w) - 4, y + 4, 4, h - 8);
//bottom
texDraw(mnuBotLeft, frameBuffer, x, (y + h) - 4);
drawRect(frameBuffer, x + 4, (y + h) - 4, w - 8, 4, rectClr);
texDraw(mnuBotRight, frameBuffer, (x + w) - 4, (y + h) - 4);
texSwapColors(mnuTopLeft, rectClr, clrCreateRGBA(0x00, 0x88, 0xC5, 0xFF));
texSwapColors(mnuTopRight, rectClr, clrCreateRGBA(0x00, 0x88, 0xC5, 0xFF));
texSwapColors(mnuBotLeft, rectClr, clrCreateRGBA(0x00, 0x88, 0xC5, 0xFF));
texSwapColors(mnuBotRight, rectClr, clrCreateRGBA(0x00, 0x88, 0xC5, 0xFF));
gfx::texDraw(mnuBotLeft, x, (y + h) - 4);
gfx::drawRect(&rectClr, x + 4, (y + h) - 4, w - 8, 4);
gfx::texDraw(mnuBotRight, (x + w) - 4, (y + h) - 4);
}
void ui::runApp(const uint64_t& down, const uint64_t& held)

View File

@ -371,11 +371,11 @@ void ui::advModePrep(const std::string& svDev, const FsSaveDataType& _type, bool
void ui::drawAdvMode()
{
saveMenu.draw(ui::txtCont);
sdMenu.draw(ui::txtCont);
saveMenu.draw(&ui::txtCont);
sdMenu.draw(&ui::txtCont);
drawTextWrap(savePath.c_str(), frameBuffer, ui::shared, 30, 654, 14, ui::txtCont, 600);
drawTextWrap(sdPath.c_str(), frameBuffer, ui::shared, 640, 654, 14, ui::txtCont, 600);
gfx::drawTextfWrap(14, 30, 654, 600, &ui::txtCont, savePath.c_str());
gfx::drawTextfWrap(14, 640, 654, 600, &ui::txtCont, sdPath.c_str());
//draw copy menu if it's supposed to be up
if(advMenuCtrl == 2)
@ -385,18 +385,18 @@ void ui::drawAdvMode()
case 0:
copyMenu.setParams(176, 278, 304);
copyMenu.editOpt(0, advMenuStr[0] + "sdmc");
ui::drawTextbox(frameBuffer, 168, 236, 320, 268);
drawText(dev.c_str(), frameBuffer, ui::shared, 176, 250, 18, ui::txtDiag);
ui::drawTextbox(168, 236, 320, 268);
gfx::drawTextf(18, 176, 250, &ui::txtDiag, dev.c_str());
break;
case 1:
copyMenu.setParams(816, 278, 304);
copyMenu.editOpt(0, advMenuStr[0] + dev);
ui::drawTextbox(frameBuffer, 808, 236, 320, 268);
drawText("SDMC", frameBuffer, ui::shared, 816, 250, 18, ui::txtDiag);
ui::drawTextbox(808, 236, 320, 268);
gfx::drawTextf(18, 816, 250, &ui::txtDiag, "SDMC");
break;
}
copyMenu.draw(ui::txtDiag);
copyMenu.draw(&ui::txtDiag);
}
}

View File

@ -177,8 +177,8 @@ void ui::deleteBackup(unsigned ind)
void ui::drawFolderMenu()
{
data::curData.drawIcon(true, 96, 98);
drawTextWrap(folderMenuInfo.c_str(), frameBuffer, ui::shared, 60, 370, 16, ui::txtCont, 360);
folderMenu.draw(ui::txtCont);
gfx::drawTextfWrap(16, 60, 370, 360, &ui::txtCont, folderMenuInfo.c_str());
folderMenu.draw(&ui::txtCont);
}
void ui::updateFolderMenu(const uint64_t& down, const uint64_t& held)

View File

@ -6,7 +6,10 @@
#include "ui.h"
#include "miscui.h"
static const clr menuColorLight = clrCreateU32(0xFFF05032), menuColorDark = clrCreateU32(0xFFC5FF00);
static const SDL_Color menuColorLight = {0x32, 0x50, 0xF0, 0xFF};
static const SDL_Color menuColorDark = {0x00, 0xFF, 0xC5, 0xFF};
#define HOLD_FC 10
void ui::menu::setParams(const unsigned& _x, const unsigned& _y, const unsigned& _rW)
{
@ -18,7 +21,7 @@ void ui::menu::setParams(const unsigned& _x, const unsigned& _y, const unsigned&
void ui::menu::addOpt(const std::string& add)
{
if(textGetWidth(add.c_str(), ui::shared, 18) < rW - 32 || rW == 0)
if(gfx::getTextWidth(add.c_str(), 18) < rW - 32 || rW == 0)
opt.push_back(add);
else
{
@ -30,7 +33,7 @@ void ui::menu::addOpt(const std::string& add)
tmp += add.substr(i, untCnt);
i += untCnt;
if(textGetWidth(tmp.c_str(), ui::shared, 18) >= rW - 32)
if(gfx::getTextWidth(tmp.c_str(), 18) >= rW - 32)
{
opt.push_back(tmp);
break;
@ -59,7 +62,7 @@ void ui::menu::handleInput(const uint64_t& down, const uint64_t& held)
fc = 0;
int size = opt.size() - 1;
if((down & HidNpadButton_Up) || ((held & HidNpadButton_Up) && fc == 10))
if((down & HidNpadButton_Up) || ((held & HidNpadButton_Up) && fc == HOLD_FC))
{
selected--;
if(selected < 0)
@ -72,7 +75,7 @@ void ui::menu::handleInput(const uint64_t& down, const uint64_t& held)
if((selected - 14) > start)
start = selected - 14;
}
else if((down & HidNpadButton_Down) || ((held & HidNpadButton_Down) && fc == 10))
else if((down & HidNpadButton_Down) || ((held & HidNpadButton_Down) && fc == HOLD_FC))
{
selected++;
if(selected > size)
@ -101,7 +104,7 @@ void ui::menu::handleInput(const uint64_t& down, const uint64_t& held)
}
}
void ui::menu::draw(const clr& textClr)
void ui::menu::draw(const SDL_Color *textClr)
{
if(opt.size() < 1)
return;
@ -129,11 +132,11 @@ void ui::menu::draw(const clr& textClr)
{
if(i == selected)
{
drawBoundBox(x, y + ((i - start) * 36), rW, 36, clrSh);
drawText(opt[i].c_str(), frameBuffer, shared, x + 8, (y + 8) + ((i - start) * 36), 18, ui::thmID == ColorSetId_Light ? menuColorLight : menuColorDark);
ui::drawBoundBox(x, y + ((i - start) * 36), rW, 36, clrSh);
gfx::drawTextf(18, x + 8, (y + 8) + ((i - start) * 36), ui::thmID == ColorSetId_Light ? &menuColorLight : &menuColorDark, opt[i].c_str());
}
else
drawText(opt[i].c_str(), frameBuffer, shared, x + 8, (y + 8) + ((i - start) * 36), 18, textClr);
gfx::drawTextf(18, x + 8, (y + 8) + ((i - start) * 36), textClr, opt[i].c_str());
}
}

View File

@ -12,6 +12,14 @@ static std::string popText;
static const char *okt = "OK \ue0e0";
static unsigned popY, popX, popWidth, popState, frameCount, frameHold;
static const SDL_Color divLight = {0x6D, 0x6D, 0x6D, 0xFF};
static const SDL_Color divDark = {0xCC, 0xCC, 0xCC, 0xFF};
static const SDL_Color shadow = {0x66, 0x66, 0x66, 0xFF};
static const SDL_Color fillBack = {0x66, 0x66, 0x66, 0xFF};
static const SDL_Color fillLight = {0x00, 0xFF, 0xC5, 0xFF};
static const SDL_Color fillDark = {0x32, 0x50, 0xF0, 0xFF};
enum popStates
{
popRise,
@ -36,33 +44,31 @@ void ui::progBar::update(const uint64_t& _prog)
void ui::progBar::draw(const std::string& text, const std::string& head)
{
size_t headWidth = textGetWidth(head.c_str(), ui::shared, 20);
size_t headWidth = gfx::getTextWidth(head.c_str(), 20);
unsigned headX = (1280 / 2) - (headWidth / 2);
texDraw(diaBox, frameBuffer, 320, 150);
drawRect(frameBuffer, 320, 206, 640, 2, ui::thmID == ColorSetId_Light ? clrCreateU32(0xFF6D6D6D) : clrCreateU32(0xFFCCCCCC));
drawRect(frameBuffer, 352, 530, 576, 12, clrCreateU32(0xFF666666));
drawRect(frameBuffer, 352, 530, (unsigned)width, 12, ui::thmID == ColorSetId_Light ? clrCreateU32(0xFFC5FF00) : clrCreateU32(0xFFF05032));
texDraw(ui::progCovLeft, frameBuffer, 352, 530);
texDraw(ui::progCovRight, frameBuffer, 920, 530);
ui::drawTextbox(320, 150, 640, 420);
gfx::drawLine(ui::thmID == ColorSetId_Light ? &divLight : &divDark, 320, 206, 959, 206);
gfx::drawRect(&fillBack, 352, 530, 576, 12);
gfx::drawRect(ui::thmID == ColorSetId_Light ? &fillLight : &fillDark, 352, 530, (int)width, 12);
gfx::texDraw(ui::progCovLeft, 352, 530);
gfx::texDraw(ui::progCovRight, 920, 530);
drawText(head.c_str(), frameBuffer, ui::shared, headX, 168, 20, ui::txtDiag);
drawTextWrap(text.c_str(), frameBuffer, ui::shared, 352, 230, 16, ui::txtDiag, 576);
gfx::drawTextf(20, headX, 160, &ui::txtDiag, head.c_str());
gfx::drawTextfWrap(16, 352, 230, 576, &ui::txtDiag, text.c_str());
}
void ui::showMessage(const char *head, const char *fmt, ...)
{
//fake focus
drawRectAlpha(frameBuffer, 0, 0, 1280, 720, clrCreateU32(0xAA0D0D0D));
char tmp[1024];
va_list args;
va_start(args, fmt);
vsprintf(tmp, fmt, args);
va_end(args);
unsigned headX = (640 / 2) - (textGetWidth(head, ui::shared, 20) / 2);
unsigned okX = (640 / 2) - (textGetWidth(okt, ui::shared, 20) / 2);
unsigned headX = (640 / 2) - (gfx::getTextWidth(head, 20) / 2);
unsigned okX = (640 / 2) - (gfx::getTextWidth(okt, 20) / 2);
while(true)
{
@ -71,20 +77,16 @@ void ui::showMessage(const char *head, const char *fmt, ...)
if(ui::padKeysDown())
break;
gfxBeginFrame();
texDraw(diaBox, frameBuffer, 320, 150);
drawText(head, frameBuffer, ui::shared, 320 + headX, 168, 20, ui::txtDiag);
drawTextWrap(tmp, frameBuffer, ui::shared, 352, 230, 16, ui::txtDiag, 576);
drawText(okt, frameBuffer, ui::shared, 320 + okX, 522, 20, ui::txtDiag);
gfxEndFrame();
ui::drawTextbox(320, 150, 640, 420);
gfx::drawTextf(20, 320 + headX, 168, &ui::txtDiag, head);
gfx::drawTextfWrap(16, 352, 230, 576, &ui::txtDiag, tmp);
gfx::drawTextf(20, 320 + okX, 522, &ui::txtDiag, okt);
gfx::present();
}
}
bool ui::confirm(bool hold, const char *fmt, ...)
{
//fake focus
drawRectAlpha(frameBuffer, 0, 0, 1280, 720, clrCreateU32(0xAA0D0D0D));
char tmp[1024];
va_list args;
va_start(args, fmt);
@ -94,11 +96,11 @@ bool ui::confirm(bool hold, const char *fmt, ...)
bool ret = false, heldDown = false;
unsigned loadFrame = 0, holdCount = 0;
uint8_t holdClrDiff = 0;
clr holdClr = ui::txtDiag;
SDL_Color holdClr = ui::txtDiag;
unsigned headX = (640 / 2) - (textGetWidth("Confirm", ui::shared, 20) / 2);
unsigned yesX = 160 - (textGetWidth(ui::yt.c_str(), ui::shared, 20) / 2);
unsigned noX = 160 - (textGetWidth(ui::nt.c_str(), ui::shared, 20) / 2);
unsigned headX = (640 / 2) - (gfx::getTextWidth("Confirm", 20) / 2);
unsigned yesX = 160 - (gfx::getTextWidth(ui::yt.c_str(), 20) / 2);
unsigned noX = 160 - (gfx::getTextWidth(ui::nt.c_str(), 20) / 2);
std::string yesText = yt;
@ -134,14 +136,14 @@ bool ui::confirm(bool hold, const char *fmt, ...)
yesText = ui::holdingText[2];
yesText += loadGlyphArray[loadFrame];
yesX = 160 - (textGetWidth(yesText.c_str(), ui::shared, 20) / 2);
yesX = 160 - (gfx::getTextWidth(yesText.c_str(), 20) / 2);
}
else if(hold && heldDown)
{
//Reset everything
heldDown= false;
holdCount = 0, loadFrame = 0, holdClrDiff = 0;
yesX = 160 - (textGetWidth(ui::yt.c_str(), ui::shared, 20) / 2);
yesX = 160 - (gfx::getTextWidth(ui::yt.c_str(), 20) / 2);
yesText = ui::yt;
holdClr = ui::txtDiag;
}
@ -159,18 +161,17 @@ bool ui::confirm(bool hold, const char *fmt, ...)
if(hold && heldDown)
{
if(ui::thmID == ColorSetId_Light)
holdClr = clrCreateRGBA(0xFF, 0xFF - holdClrDiff, 0xFF - holdClrDiff, 0xFF);
holdClr = {0xFF, 0xFF - holdClrDiff, 0xFF - holdClrDiff, 0xFF};
else
holdClr = clrCreateRGBA(0x25 + holdClrDiff, 0x00, 0x00, 0xFF);
holdClr = {0x25 + holdClrDiff, 0x00, 0x00, 0xFF};
}
gfxBeginFrame();
texDraw(diaBox, frameBuffer, 320, 150);
drawText(ui::confirmHead.c_str(), frameBuffer, ui::shared, 320 + headX, 168, 20, ui::txtDiag);
drawText(yesText.c_str(), frameBuffer, ui::shared, 320 + yesX, 522, 20, holdClr);
drawText(ui::nt.c_str(), frameBuffer, ui::shared, 640 + noX, 522, 20, ui::txtDiag);
drawTextWrap(tmp, frameBuffer, ui::shared, 352, 230, 16, ui::txtDiag, 576);
gfxEndFrame();
ui::drawTextbox(320, 150, 640, 420);
gfx::drawTextf(20, 320 + headX, 168, &ui::txtDiag, ui::confirmHead.c_str());
gfx::drawTextf(20, 320 + yesX, 522, &holdClr, yesText.c_str());
gfx::drawTextf(20, 640 + noX, 522, &ui::txtDiag, ui::nt.c_str());
gfx::drawTextfWrap(16, 352, 230, 576, &ui::txtDiag, tmp);
gfx::present();
}
return ret;
}
@ -185,24 +186,23 @@ bool ui::confirmDelete(const std::string& p)
return confirm(data::holdDel, ui::confDel.c_str(), p.c_str());
}
void ui::drawTextbox(tex *target, int x, int y, int w, int h)
void ui::drawTextbox(int x, int y, int w, int h)
{
//Top
texDraw(ui::cornerTopLeft, target, x, y);
drawRect(target, x + 32, y, w - 64, 32, ui::tboxClr);
texDraw(ui::cornerTopRight, target, (x + w) - 32, y);
gfx::texDraw(ui::cornerTopLeft, x, y);
gfx::drawRect(&ui::tboxClr, x + 32, y, w - 64, 32);
gfx::texDraw(ui::cornerTopRight, (x + w) - 32, y);
//middle
drawRect(target, x, y + 32, w, h - 64, tboxClr);
gfx::drawRect(&ui::tboxClr, x, y + 32, w, h - 64);
//bottom
texDraw(ui::cornerBottomLeft, target, x, (y + h) - 32);
drawRect(target, x + 32, (y + h) - 32, w - 64, 32, tboxClr);
texDraw(ui::cornerBottomRight, target, (x + w) - 32, (y + h) - 32);
gfx::texDraw(ui::cornerBottomLeft, x, (y + h) - 32);
gfx::drawRect(&ui::tboxClr, x + 32, (y + h) - 32, w - 64, 32);
gfx::texDraw(ui::cornerBottomRight, (x + w) - 32, (y + h) - 32);
}
void ui::drawTextboxInvert(tex *target, int x, int y, int w, int h)
/*void ui::drawTextboxInvert(tex *target, int x, int y, int w, int h)
{
clr temp = ui::tboxClr;
clrInvert(&temp);
@ -219,7 +219,7 @@ void ui::drawTextboxInvert(tex *target, int x, int y, int w, int h)
texDrawInvert(ui::cornerBottomLeft, target, x, (y + h) - 32);
drawRect(target, x + 32, (y + h) - 32, w - 64, 32, temp);
texDrawInvert(ui::cornerBottomRight, target, (x + w) - 32, (y + h) - 32);
}
}*/
void ui::showPopup(unsigned frames, const char *fmt, ...)
{
@ -231,7 +231,7 @@ void ui::showPopup(unsigned frames, const char *fmt, ...)
frameCount = 0;
frameHold = frames;
popWidth = textGetWidth(tmp, ui::shared, 24) + 32;
popWidth = gfx::getTextWidth(tmp, 24) + 32;
popX = 640 - (popWidth / 2);
popText = tmp;
@ -267,7 +267,7 @@ void ui::drawPopup(const uint64_t& down)
break;
}
drawTextbox(frameBuffer, popX, popY, popWidth, 64);
drawText(popText.c_str(), frameBuffer, ui::shared, popX + 16, popY + 20, 24, ui::txtDiag);
drawTextbox(popX, popY, popWidth, 64);
gfx::drawTextf(24, popX + 16, popY + 20, &ui::txtDiag, popText.c_str());
}

View File

@ -63,15 +63,15 @@ void ui::drawTitleMenu()
selRectX = tX - 6;
selRectY = y - 6;
unsigned titleWidth = textGetWidth(data::curData.getTitle().c_str(), ui::shared, 18);
unsigned titleWidth = gfx::getTextWidth(data::curData.getTitle().c_str(), 18);
int rectWidth = titleWidth + 32, rectX = (tX + 64) - (rectWidth / 2);
if(rectX < 16)
rectX = 16;
else if(rectX + rectWidth > 1264)
rectX = 1264 - rectWidth;
drawTextbox(frameBuffer, rectX, y - 50, rectWidth, 38);
drawText(data::curData.getTitle().c_str(), frameBuffer, ui::shared, rectX + 16, y - 40, 18, ui::txtDiag);
ui::drawTextbox(rectX, y - 50, rectWidth, 38);
gfx::drawTextf(18, rectX + 16, y - 40, &ui::txtDiag, data::curData.getTitle().c_str());
}
if(data::curUser.titles[i].getFav())
data::curUser.titles[i].drawIconFav(false, tX, y);

View File

@ -86,7 +86,7 @@ void ui::textUserMenuUpdate(const uint64_t& down, const uint64_t& held)
void ui::drawTextUserMenu()
{
userMenu.draw(ui::txtCont);
userMenu.draw(&ui::txtCont);
}
void ui::textTitleMenuUpdate(const uint64_t& down, const uint64_t& held)
@ -151,7 +151,7 @@ void ui::textTitleMenuUpdate(const uint64_t& down, const uint64_t& held)
void ui::drawTextTitleMenu()
{
titleMenu.draw(ui::txtCont);
titleMenu.draw(&ui::txtCont);
}
void ui::textFolderMenuUpdate(const uint64_t& down, const uint64_t& held)
@ -200,8 +200,8 @@ void ui::textFolderMenuUpdate(const uint64_t& down, const uint64_t& held)
void ui::drawTextFolderMenu()
{
titleMenu.draw(ui::txtCont);
folderMenu.draw(ui::txtCont);
titleMenu.draw(&ui::txtCont);
folderMenu.draw(&ui::txtCont);
}
void ui::exMenuPrep()
@ -346,7 +346,7 @@ void ui::updateExMenu(const uint64_t& down, const uint64_t& held)
void ui::drawExMenu()
{
exMenu.draw(ui::txtCont);
exMenu.draw(&ui::txtCont);
}
static inline void switchBool(bool& sw)
@ -462,7 +462,7 @@ void ui::updateOptMenu(const uint64_t& down, const uint64_t& held)
void ui::drawOptMenu()
{
optMenu.draw(ui::txtCont);
drawTextWrap(ui::optMenuExp[optMenu.getSelected()].c_str(), frameBuffer, ui::shared, 466, 98, 18, ui::txtCont, 730);
optMenu.draw(&ui::txtCont);
gfx::drawTextfWrap(18, 466, 98, 730, &ui::txtCont, ui::optMenuExp[optMenu.getSelected()].c_str());
}

View File

@ -49,15 +49,15 @@ void ui::drawUserMenu()
selRectX = tX - 6;
selRectY = y - 6;
unsigned userWidth = textGetWidth(data::curUser.getUsername().c_str(), ui::shared, 18);
unsigned userWidth = gfx::getTextWidth(data::curUser.getUsername().c_str(), 18);
int userRectWidth = userWidth + 32, userRectX = (tX + 64) - (userRectWidth / 2);
if(userRectX < 16)
userRectX = 16;
else if(userRectX + userRectWidth > 1264)
userRectX = 1264 - userRectWidth;
drawTextbox(frameBuffer, userRectX, y - 50, userRectWidth, 38);
drawText(data::curUser.getUsername().c_str(), frameBuffer, ui::shared, userRectX + 16, y - 40, 18, ui::txtDiag);
drawTextbox(userRectX, y - 50, userRectWidth, 38);
gfx::drawTextf(18, userRectX + 16, y - 40, &ui::txtDiag, data::curUser.getUsername().c_str());
}
data::users[i].drawIconHalf(tX, y);
}

View File

@ -314,12 +314,16 @@ void util::replaceButtonsInString(std::string& rep)
replaceStr(rep, "[-]", "\ue0f0");
}
tex *util::createIconGeneric(const char *txt)
SDL_Texture *util::createIconGeneric(const char *txt, int fontSize)
{
tex *ret = texCreate(256, 256);
texClearColor(ret, ui::rectLt);
unsigned int x = 128 - (textGetWidth(txt, ui::shared, 32) / 2);
drawText(txt, ret, ui::shared, x, 112, 32, ui::txtCont);
SDL_Texture *ret = SDL_CreateTexture(gfx::render, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET, 256, 256);
SDL_SetRenderTarget(gfx::render, ret);
SDL_SetRenderDrawColor(gfx::render, ui::rectLt.r, ui::rectLt.g, ui::rectLt.b, ui::rectLt.a);
SDL_RenderClear(gfx::render);
unsigned int x = 128 - (gfx::getTextWidth(txt, fontSize) / 2);
unsigned int y = 128 - (fontSize / 2);
gfx::drawTextf(fontSize, x, y, &ui::txtCont, txt);
SDL_SetRenderTarget(gfx::render, NULL);
return ret;
}