Begin to show my final form

This commit is contained in:
J-D-K
2018-07-01 11:44:49 -04:00
parent 0a85828a4b
commit eb14630a9e
14 changed files with 503 additions and 83 deletions

View File

@@ -38,7 +38,7 @@ INCLUDES := inc
EXEFS_SRC := exefs_src
APP_TITLE := JKSV
APP_AUTHOR := JK_
APP_VERSION := 06/29/2018
APP_VERSION := 07/01/2018
ROMFS := romfs
#---------------------------------------------------------------------------------
@@ -56,7 +56,7 @@ CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LIBS := `freetype-config --libs` -lpng
LIBS := `freetype-config --libs` -lpng -ljpeg
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing

View File

@@ -7,7 +7,7 @@ JKSV for Switch. Mostly to get used to libnx. Reuses a lot of code of JKSM for 3
# Building:
1. Requires [devkitPro](https://devkitpro.org/) devkitA64
2. Requires switch-freetype
3. libpng
3. libpng and libjpeg-turbo
# Credits and Thanks:
* [shared-font](https://github.com/switchbrew/switch-portlibs-examples) example by yellows8

View File

@@ -6,12 +6,32 @@
#include <vector>
#include <string>
#include "gfx.h"
namespace data
{
extern bool sysSave, forceMountable;
//Loads user + title info
void loadDataInfo();
void exit();
//Class to help not load the same icons over and over
class icn
{
public:
void load(const uint64_t& _id, const uint8_t *jpegData, const size_t& jpegSize);
void setIcon(const uint64_t& _id, const gfx::tex& _set);
void draw(unsigned x, unsigned y);
void drawHalf(unsigned x, unsigned y);
uint64_t getTitleID();
void deleteData();
private:
uint64_t titleID;
gfx::tex iconTex;
};
//Class to store title info
class titledata
@@ -30,6 +50,9 @@ namespace data
//Returns ID
uint64_t getID();
//Game icon
icn icon;
FsSaveDataType getType();
private:
@@ -59,6 +82,8 @@ namespace data
//Vector for storing save data info for user
std::vector<titledata> titles;
gfx::tex icn;
private:
u128 userID;
std::string username, userSafe;

View File

@@ -7,7 +7,7 @@ namespace gfx
{
//Inits graphics and shared font. Code for shared font is from switch-portlibs examples
bool init();
bool fini();
bool exit();
//Changes gfx mode to linear double
void switchMode();
@@ -42,11 +42,21 @@ namespace gfx
Others will have issues.
*/
void loadFromFile(const std::string& path);
//Icons
void loadJpegMem(const uint8_t *txData, const uint32_t& jpegSz);
//Frees memory used by data
~tex();
void deleteData();
uint16_t getWidth();
uint16_t getHeight();
const uint32_t *getDataPointer();
void draw(uint32_t x, uint32_t y);
void drawNoBlend(uint32_t x, uint32_t y);
//For lazy-scaling icons
//Skips every-other pixel and row, so 1/2 scale
void drawNoBlendSkip(unsigned x, unsigned y);
//These only repeat pixels.
void drawRepeatHori(uint32_t x, uint32_t y, uint32_t w);
void drawRepeatHoriNoBlend(uint32_t x, uint32_t y, uint32_t w);

View File

@@ -44,6 +44,7 @@ namespace ui
bool confirm(const std::string& q);
bool confirmTransfer(const std::string& f, const std::string& t);
bool confirmDelete(const std::string& p);
void debShowTex(gfx::tex tx);
void drawTextbox(unsigned x, unsigned y, unsigned w, unsigned h);
}

View File

@@ -22,6 +22,7 @@ namespace ui
//Loads in the A, B, X, Y button graphics
void init();
void exit();
//Prepares menus for use
void userMenuInit();

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 B

View File

@@ -38,15 +38,27 @@ static int getUserIndex(const u128& id)
return -1;
}
//Default icon if one isn't found. For system saves
gfx::tex defIcn;
namespace data
{
titledata curData;
user curUser;
std::vector<icn> icons;
std::vector<user> users;
bool sysSave = false, forceMountable = true;
void loadDataInfo()
{
//Load default icon
defIcn.loadFromFile("romfs:/img/icn/icnDefault.png");
//Create icon for it
icn defIcnIcon;
defIcnIcon.setIcon((uint64_t)0, defIcn);
icons.push_back(defIcnIcon);
for(unsigned i = 0; i < users.size(); i++)
users[i].titles.clear();
@@ -102,6 +114,60 @@ namespace data
for(unsigned i = 0; i < users.size(); i++)
std::sort(users[i].titles.begin(), users[i].titles.end(), sortTitles);
curUser = users[0];
}
void exit()
{
for(unsigned i = 0; i < users.size(); i++)
users[i].icn.deleteData();
for(unsigned i = 1; i < icons.size(); i++)
icons[i].deleteData();
}
void icn::load(const uint64_t& _id, const uint8_t *jpegData, const size_t& jpegSize)
{
titleID = _id;
iconTex.loadJpegMem(jpegData, jpegSize);
}
void icn::setIcon(const uint64_t& _id, const gfx::tex& _set)
{
titleID = _id;
iconTex = _set;
}
void icn::draw(unsigned x, unsigned y)
{
iconTex.drawNoBlend(x, y);
}
void icn::drawHalf(unsigned x, unsigned y)
{
iconTex.drawNoBlendSkip(x, y);
}
uint64_t icn::getTitleID()
{
return titleID;
}
void icn::deleteData()
{
iconTex.deleteData();
}
int findIcnIndex(const uint64_t& titleID)
{
for(unsigned i = 0; i < icons.size(); i++)
{
if(icons[i].getTitleID() == titleID)
return i;
}
return -1;
}
bool titledata::init(const FsSaveDataInfo& inf)
@@ -142,6 +208,20 @@ namespace data
{
title.assign(ent->name);
titleSafe = util::safeString(ent->name);
int iconIndex = findIcnIndex(id);
if(iconIndex == -1)
{
uint32_t icnSize = outSz - sizeof(dat->nacp);
icn newIcon;
newIcon.load(id, dat->icon, icnSize);
icons.push_back(newIcon);
icon = icons[findIcnIndex(id)];
}
else
icon = icons[iconIndex];
delete dat;
}
else
@@ -150,6 +230,7 @@ namespace data
sprintf(tmp, "%016lX", (u64)id);
title.assign(tmp);
titleSafe = util::safeString(tmp);
icon = icons[0];
}
return true;
@@ -208,6 +289,15 @@ namespace data
username = "Unknown";
userSafe = util::safeString(username);
size_t sz = 0;
accountProfileGetImageSize(&prof, &sz);
uint8_t *profJpeg = new uint8_t[sz];
accountProfileLoadImage(&prof, profJpeg, sz, &sz);
icn.loadJpegMem(profJpeg, sz);
delete[] profJpeg;
accountProfileClose(&prof);
return true;
@@ -237,6 +327,7 @@ namespace data
{
username = "Unknown";
userSafe = "Unknown";
icn = defIcn;
}
return true;

View File

@@ -4,6 +4,9 @@
#include <cstdio>
#include <switch.h>
#include <png.h>
#include <jpeglib.h>
#include <malloc.h>
#include <ft2build.h>
#include FT_FREETYPE_H
@@ -62,7 +65,7 @@ namespace gfx
return true;
}
bool fini()
bool exit()
{
if(faceret == 0)
FT_Done_Face(face);
@@ -306,10 +309,77 @@ namespace gfx
}
}
tex::~tex()
void tex::loadJpegMem(const uint8_t *txData, const uint32_t& jpegSz)
{
struct jpeg_decompress_struct jpegInfo;
struct jpeg_error_mgr error;
jpegInfo.err = jpeg_std_error(&error);
jpeg_create_decompress(&jpegInfo);
jpeg_mem_src(&jpegInfo, txData, jpegSz);
jpeg_read_header(&jpegInfo, true);
//make sure we have RGB
if(jpegInfo.jpeg_color_space == JCS_YCbCr)
jpegInfo.out_color_space = JCS_RGB;
width = jpegInfo.image_width;
height = jpegInfo.image_height;
data = new uint32_t[width * height];
jpeg_start_decompress(&jpegInfo);
JSAMPARRAY row = (JSAMPARRAY)new JSAMPARRAY[sizeof(JSAMPROW)];
row[0] = (JSAMPROW)new JSAMPROW[(sizeof(JSAMPLE) * width) * 3];
uint8_t *ptr;
for(unsigned y = 0, i = 0; y < height; y++)
{
jpeg_read_scanlines(&jpegInfo, row, 1);
unsigned x;
for(x = 0, ptr = row[0]; x < width; x++, ptr += 3, i++)
{
uint8_t r, g, b;
r = ptr[0];
g = ptr[1];
b = ptr[2];
data[i] = 0xFF << 24 | b << 16 | g << 8 | r;
}
}
jpeg_finish_decompress(&jpegInfo);
jpeg_destroy_decompress(&jpegInfo);
delete row[0];
delete[] row;
}
void tex::deleteData()
{
if(data != NULL)
{
delete[] data;
data = NULL;
}
}
uint16_t tex::getWidth()
{
return width;
}
uint16_t tex::getHeight()
{
return height;
}
const uint32_t *tex::getDataPointer()
{
return data;
}
void tex::draw(uint32_t x, uint32_t y)
@@ -347,6 +417,23 @@ namespace gfx
}
}
void tex::drawNoBlendSkip(unsigned x, unsigned y)
{
if(data != NULL)
{
unsigned tY, tX, i = 0;
uint32_t *fb = (uint32_t *)gfxGetFramebuffer(NULL, NULL);
for(tY = y; tY < y + (height / 2); tY++, i += width)
{
for(tX = x; tX < x + (width / 2); tX++, i += 2)
{
fb[tY * frameBufWidth + tX] = data[i];
}
}
}
}
void tex::drawRepeatHori(uint32_t x, uint32_t y, uint32_t w)
{
if(data != NULL)

View File

@@ -33,14 +33,11 @@ extern "C"
}
}
extern int mstate;
int main(int argc, const char *argv[])
{
gfx::init();
data::loadDataInfo();
ui::init();
ui::userMenuInit();
data::loadDataInfo();
bool run = true;
while(appletMainLoop() && run)
@@ -57,12 +54,9 @@ int main(int argc, const char *argv[])
data::sysSave = true;
data::forceMountable = false;
data::loadDataInfo();
ui::userMenuInit();
//Just to be sure
fsdevUnmountDevice("sv");
mstate = 0;
}
}
else if(down & KEY_PLUS)
@@ -72,5 +66,7 @@ int main(int argc, const char *argv[])
gfx::handleBuffs();
}
gfx::fini();
gfx::exit();
ui::exit();
data::exit();
}

View File

@@ -186,6 +186,30 @@ namespace ui
return confirm(confMess);
}
void debShowTex(gfx::tex tx)
{
unsigned tbX = 256, tbY = 128;
unsigned tbW = 768, tbH = 464;
unsigned texX = tbX + ((tbW / 2) - (tx.getWidth() / 2));
unsigned texY = tbY + ((tbH / 2) - (tx.getHeight() / 2));
while(true)
{
hidScanInput();
uint64_t down = hidKeysDown(CONTROLLER_P1_AUTO);
if(down & KEY_A)
break;
ui::drawTextbox(tbX, tbY, tbW, tbH);
tx.drawNoBlend(texX, texY);
gfx::handleBuffs();
}
}
void drawTextbox(unsigned x, unsigned y, unsigned w, unsigned h)
{
//Top

View File

@@ -21,10 +21,10 @@ enum menuState
int mstate = USR_SEL;
//Button controlled menus
static ui::menu userMenu, titleMenu, folderMenu, devMenu, saveMenu, sdMenu, copyMenu;
static ui::menu folderMenu, devMenu, saveMenu, sdMenu, copyMenu;
//Bar at top
static gfx::tex buttonA, buttonB, buttonX, buttonY, titleBar;
static gfx::tex buttonA, buttonB, buttonX, buttonY;
//Shown if someone tries to write to system saves
static const std::string sysSaveMess = "No system saves until we get public NAND restore.";
@@ -53,8 +53,6 @@ namespace ui
switch(gthm)
{
case ColorSetId_Light:
titleBar.loadFromFile("romfs:/img/topbar_lght.png");
//Dark corners
cornerTopLeft.loadFromFile("romfs:/img/tbox/tboxCornerTopLeft_drk.png");
cornerTopRight.loadFromFile("romfs:/img/tbox/tboxCornerTopRight_drk.png");
@@ -77,8 +75,6 @@ namespace ui
default:
case ColorSetId_Dark:
titleBar.loadFromFile("romfs:/img/topbar_drk.png");
//Light corners
cornerTopLeft.loadFromFile("romfs:/img/tbox/tboxCornerTopLeft_lght.png");
cornerTopRight.loadFromFile("romfs:/img/tbox/tboxCornerTopRight_lght.png");
@@ -113,19 +109,22 @@ namespace ui
copyMenu.addOpt("Back");
}
void userMenuInit()
void exit()
{
userMenu.reset();
for(unsigned i = 0; i < data::users.size(); i++)
userMenu.addOpt(data::users[i].getUsername());
}
cornerTopLeft.deleteData();
cornerTopRight.deleteData();
cornerBottomLeft.deleteData();
cornerBottomRight.deleteData();
void titleMenuPrepare(data::user& usr)
{
titleMenu.reset();
horEdgeTop.deleteData();
horEdgeBot.deleteData();
vertEdgeLeft.deleteData();
vertEdgeRight.deleteData();
for(unsigned i = 0; i < usr.titles.size(); i++)
titleMenu.addOpt(usr.titles[i].getTitle());
buttonA.deleteData();
buttonB.deleteData();
buttonX.deleteData();
buttonY.deleteData();
}
void folderMenuPrepare(data::user& usr, data::titledata& dat)
@@ -143,19 +142,16 @@ namespace ui
void drawTitleBar(const std::string& txt)
{
titleBar.drawRepeatHoriNoBlend(0, 0, 1280);
gfx::drawText(txt, 16, 16, 64, mnuTxt);
}
void drawUI()
{
gfx::clearBufferColor(clearClr);
ui::drawTitleBar("JKSV - 06/29/2018");
ui::drawTitleBar("JKSV - 07/01/2018");
switch(mstate)
{
case USR_SEL:
case TTL_SEL:
case FLD_SEL:
gfx::drawRectangle(448, 64, 1, 592, rectLt);
gfx::drawRectangle(449, 64, 2, 592, rectSh);
@@ -164,6 +160,15 @@ namespace ui
gfx::drawRectangle(16, 657, 1248, 2, rectSh);
break;
case USR_SEL:
case TTL_SEL:
gfx::drawRectangle(16, 64, 1248, 1, rectLt);
gfx::drawRectangle(16, 65, 1248, 2, rectSh);
gfx::drawRectangle(16, 656, 1248, 1, rectLt);
gfx::drawRectangle(16, 657, 1248, 2, rectSh);
break;
case ADV_MDE:
gfx::drawRectangle(640, 64, 1, 592, rectLt);
gfx::drawRectangle(641, 64, 2, 592, rectSh);
@@ -177,8 +182,6 @@ namespace ui
{
case USR_SEL:
{
//Menu
userMenu.print(16, 88, mnuTxt, 424);
//Input guide
unsigned startX = 1010;
buttonA.draw(startX, 672);
@@ -190,9 +193,6 @@ namespace ui
case TTL_SEL:
{
//Menu
titleMenu.print(16, 88, mnuTxt, 424);
//Input guide
unsigned startX = 914;
buttonA.draw(startX, 672);
gfx::drawText("Select", startX += 38, 668, 32, mnuTxt);
@@ -205,8 +205,6 @@ namespace ui
case FLD_SEL:
{
//Menus
titleMenu.print(16, 88, mnuTxt, 424);
folderMenu.print(458, 88, mnuTxt, 806);
//Input guide
unsigned startX = 726;
@@ -234,13 +232,68 @@ namespace ui
void updateUserMenu(const uint64_t& down, const uint64_t& held)
{
userMenu.handleInput(down, held);
static int start = 0, selected = 0;
if(down & KEY_A)
static uint8_t clrShft = 0;
static bool clrAdd = true;
static unsigned selRectX = 64, selRectY = 74;
if(clrAdd)
{
data::curUser = data::users[userMenu.getSelected()];
titleMenuPrepare(data::curUser);
clrShft += 4;
if(clrShft > 63)
clrAdd = false;
}
else
{
clrShft--;
if(clrShft == 0)
clrAdd = true;
}
if(down & KEY_RIGHT)
{
if((unsigned)selected < data::users.size() - 1)
selected++;
if(selected >= (int)start + 32)
start += 8;
}
else if(down & KEY_LEFT)
{
if(selected > 0)
selected--;
if(selected < (int)start)
start -= 8;
}
else if(down & KEY_UP)
{
selected -= 8;
if(selected < 0)
selected = 0;
if(selected - start >= 32)
start -= 8;
}
else if(down & KEY_DOWN)
{
selected += 8;
if(selected > (int)data::users.size() - 1)
selected = data::users.size() - 1;
if(selected - start >= 32)
start += 8;
}
else if(down & KEY_A)
{
data::curUser = data::users[selected];
//Reset this
start = 0;
selected = 0;
selRectX = 64, selRectY = 74;
mstate = TTL_SEL;
}
else if(down & KEY_Y)
@@ -248,22 +301,126 @@ namespace ui
for(unsigned i = 0; i < data::users.size(); i++)
fs::dumpAllUserSaves(data::users[i]);
}
unsigned x = 70, y = 80;
unsigned endUser = start + 32;
if(start + 32 > (int)data::users.size())
endUser = data::users.size();
uint32_t rectClr = 0xFF << 24 | ((0xBB + clrShft) & 0xFF) << 16 | ((0x60 + clrShft)) << 8 | 0x00;
gfx::drawRectangle(selRectX, selRectY, 140, 140, rectClr);
for(unsigned i = start; i < endUser; y += 144)
{
unsigned endRow = i + 8;
for(unsigned tX = x; i < endRow; i++, tX += 144)
{
if(i == endUser)
break;
if((int)i == selected)
{
if(selRectX != tX - 6)
{
if(selRectX < tX - 6)
selRectX += 24;
else
selRectX -= 24;
}
if(selRectY != y - 6)
{
if(selRectY < y - 6)
selRectY += 24;
else
selRectX -= 24;
}
std::string username = data::users[selected].getUsername();
unsigned userWidth = gfx::getTextWidth(username, 32);
int userRectWidth = userWidth + 32, userRectX = (tX + 64) - (userRectWidth / 2);
if(userRectX < 16)
userRectX = 16;
if(userRectX + userRectWidth > 1264)
userRectX = 1264 - userRectWidth;
drawTextbox(userRectX, y - 50, userRectWidth, 38);
gfx::drawText(username, userRectX + 16, y - 50, 32, txtClr);
}
data::users[i].icn.drawNoBlendSkip(tX, y);
}
}
}
void updateTitleMenu(const uint64_t& down, const uint64_t& held)
{
titleMenu.handleInput(down, held);
//Static vars so they don't change on every loop
//Where to start in titles, selected title
static int start = 0, selected = 0;
if(down & KEY_A)
//Color shift for rect
static uint8_t clrShft = 0;
//Whether or not we're adding or subtracting from clrShft
static bool clrAdd = true;
//Selected rectangle X and Y.
static unsigned selRectX = 64, selRectY = 74;
if(clrAdd)
{
data::curData = data::curUser.titles[titleMenu.getSelected()];
clrShft += 4;
if(clrShft > 63)
clrAdd = false;
}
else
{
clrShft--;
if(clrShft == 0)
clrAdd = true;
}
if(down & KEY_RIGHT)
{
if(selected < (int)data::curUser.titles.size() - 1)
selected++;
if(selected >= (int)start + 32)
start += 8;
}
else if(down & KEY_LEFT)
{
if(selected > 0)
selected--;
if(selected < (int)start)
start -= 8;
}
else if(down & KEY_UP)
{
selected -= 8;
if(selected < 0)
selected = 0;
if(selected < start)
start -= 8;
}
else if(down & KEY_DOWN)
{
selected += 8;
if(selected > (int)data::curUser.titles.size() - 1)
selected = data::curUser.titles.size() - 1;
if(selected - start >= 32)
start += 8;
}
else if(down & KEY_A)
{
data::curData = data::curUser.titles[selected];
if(fs::mountSave(data::curUser, data::curData))
{
util::makeTitleDir(data::curUser, data::curData);
folderMenuPrepare(data::curUser, data::curData);
mstate = FLD_SEL;
}
}
@@ -272,40 +429,68 @@ namespace ui
fs::dumpAllUserSaves(data::curUser);
}
else if(down & KEY_B)
mstate = USR_SEL;
if(data::sysSave)
{
std::string drawType = "Type: ";
switch(data::curUser.titles[titleMenu.getSelected()].getType())
{
case FsSaveDataType_SystemSaveData:
drawType += "System Save";
break;
case FsSaveDataType_SaveData:
drawType += "Save Data";
break;
case FsSaveDataType_BcatDeliveryCacheStorage:
drawType += "Bcat Delivery Cache";
break;
case FsSaveDataType_DeviceSaveData:
drawType += "Device Save";
break;
case FsSaveDataType_TemporaryStorage:
drawType += "Temp Storage";
break;
case FsSaveDataType_CacheStorage:
drawType += "Cache Storage";
break;
}
gfx::drawText(drawType, 16, 668, 32, mnuTxt);
start = 0;
selected = 0;
selRectX = 64;
selRectY = 74;
mstate = USR_SEL;
return;
}
unsigned x = 70, y = 80;
unsigned endTitle = start + 32;
if(start + 32 > (int)data::curUser.titles.size())
endTitle = data::curUser.titles.size();
//draw Rect so it's always behind icons
uint32_t rectClr = 0xFF << 24 | ((0xBB + clrShft) & 0xFF) << 16 | ((0x60 + clrShft)) << 8 | 0x00;
gfx::drawRectangle(selRectX, selRectY, 140, 140, rectClr);
for(unsigned i = start; i < endTitle; y += 144)
{
unsigned endRow = i + 8;
for(unsigned tX = x; i < endRow; i++, tX += 144)
{
if(i == endTitle)
break;
if((int)i == selected)
{
//Most Switch icons seem to be 256x256, we're drawing them 128x128
if(selRectX != tX - 6)
{
if(selRectX < tX - 6)
selRectX += 24;
else
selRectX -= 24;
}
if(selRectY != y - 6)
{
if(selRectY < y - 6)
selRectY += 24;
else
selRectY -= 24;
}
std::string title = data::curUser.titles[selected].getTitle();
unsigned titleWidth = gfx::getTextWidth(title, 32);
int rectWidth = titleWidth + 32, rectX = (tX + 64) - (rectWidth / 2);
if(rectX < 16)
rectX = 16;
if(rectX + rectWidth > 1264)
rectX = 1264 - rectWidth;
drawTextbox(rectX, y - 50, rectWidth, 38);
gfx::drawText(title, rectX + 16, y - 50, 32, txtClr);
}
data::curUser.titles[i].icon.drawHalf(tX, y);
}
}
}
void updateFolderMenu(const uint64_t& down, const uint64_t& held)