Major rewrite: less repetition (#101)
* first step of rewriting: at least it compiles™ * fix tabs/spaces * fix dabort on load * fix preview crash * sorting isnt done outside of loading * step one of making remake_file useless * camera/qr code cleanup * fix dabort when folder is empty, and bring back preview optimization * fix button for switching modes and show mode when folder is empty * fix scanning qrs * no more splash discrimination * add debug helpers * fix theme installing turns out that wasnt such a good idea * fix battery icon * mistake * themeplaza compatibility * make use of load_data * don't drink and copy-paste, kids * fix user-agent * remove useless * cleanup includes * not even used * add splash buttons * upgrade buttons drawing * fix controls while preview is up * improve positions
This commit is contained in:
2
Makefile
2
Makefile
@@ -55,7 +55,7 @@ CFLAGS := -g -Wall -Wextra -O2 -mword-relocations \
|
|||||||
|
|
||||||
revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-9]*-g/-/')
|
revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-9]*-g/-/')
|
||||||
|
|
||||||
CFLAGS += $(INCLUDE) -DARM11 -D_3DS -D_GNU_SOURCE -DVERSION="\"$(revision)\""
|
CFLAGS += $(INCLUDE) -DARM11 -D_3DS -D_GNU_SOURCE -DVERSION="\"$(revision)\"" -DUSER_AGENT="\"$(APP_TITLE)/$(revision)\""
|
||||||
|
|
||||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
||||||
|
|
||||||
|
|||||||
@@ -29,11 +29,10 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
bool qr_mode;
|
|
||||||
|
|
||||||
void init_qr(void);
|
void init_qr(void);
|
||||||
void exit_qr(void);
|
void exit_qr(void);
|
||||||
void take_picture(void);
|
void take_picture(void);
|
||||||
Result http_get(char *url, char *path);
|
bool scan_qr(EntryMode current_mode);
|
||||||
|
Result http_get(char *url, const char *path);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -33,25 +33,26 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define THEMES_PATH "/Themes/"
|
#define ENTRIES_PER_SCREEN 4
|
||||||
#define SPLASHES_PATH "/Splashes/"
|
|
||||||
|
|
||||||
#define SINGLE_INSTALL 0
|
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
|
||||||
#define SHUFFLE_INSTALL 1
|
#define POS() DEBUG("%s (line %d)...\n", __func__, __LINE__)
|
||||||
#define BGM_INSTALL 2
|
|
||||||
#define UNINSTALL 3
|
|
||||||
#define DOWNLOADING 3
|
|
||||||
|
|
||||||
#define ERROR 0
|
#define DEBUGPOS(...) \
|
||||||
#define WARNING 1
|
POS(); \
|
||||||
static const int THEMES_PER_SCREEN = 4;
|
DEBUG(__VA_ARGS__)
|
||||||
|
|
||||||
bool homebrew;
|
typedef enum {
|
||||||
bool splash_mode;
|
MODE_THEMES = 0,
|
||||||
int shuffle_theme_count;
|
MODE_SPLASHES,
|
||||||
|
|
||||||
|
MODE_AMOUNT,
|
||||||
|
} EntryMode;
|
||||||
|
|
||||||
|
extern const char * main_paths[MODE_AMOUNT];
|
||||||
|
|
||||||
enum TextureID {
|
enum TextureID {
|
||||||
TEXTURE_FONT_RESERVED = 0, //used by pp2d for the font
|
TEXTURE_FONT_RESERVED = 0, // used by pp2d for the font
|
||||||
TEXTURE_ARROW,
|
TEXTURE_ARROW,
|
||||||
TEXTURE_SHUFFLE,
|
TEXTURE_SHUFFLE,
|
||||||
TEXTURE_BATTERY_1,
|
TEXTURE_BATTERY_1,
|
||||||
@@ -62,6 +63,10 @@ enum TextureID {
|
|||||||
TEXTURE_BATTERY_CHARGE,
|
TEXTURE_BATTERY_CHARGE,
|
||||||
TEXTURE_QR,
|
TEXTURE_QR,
|
||||||
TEXTURE_PREVIEW,
|
TEXTURE_PREVIEW,
|
||||||
|
|
||||||
|
TEXTURE_ICON, // always the last
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void exit_function(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -27,18 +27,49 @@
|
|||||||
#ifndef DRAW_H
|
#ifndef DRAW_H
|
||||||
#define DRAW_H
|
#define DRAW_H
|
||||||
|
|
||||||
#include "themes.h"
|
#include "common.h"
|
||||||
#include "splashes.h"
|
#include "loading.h"
|
||||||
#include "camera.h"
|
|
||||||
|
typedef enum {
|
||||||
|
INSTALL_SPLASH,
|
||||||
|
INSTALL_SPLASH_DELETE,
|
||||||
|
|
||||||
|
INSTALL_SINGLE,
|
||||||
|
INSTALL_SHUFFLE,
|
||||||
|
INSTALL_BGM,
|
||||||
|
|
||||||
|
INSTALL_DOWNLOAD,
|
||||||
|
} InstallType;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ERROR_LEVEL_ERROR,
|
||||||
|
ERROR_LEVEL_WARNING,
|
||||||
|
} ErrorLevel;
|
||||||
|
|
||||||
|
#define BUTTONS_START_Y 140
|
||||||
|
#define BUTTONS_STEP 25
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BUTTONS_Y_PREVIEW = BUTTONS_START_Y+5,
|
||||||
|
|
||||||
|
BUTTONS_Y_LINE_1 = BUTTONS_START_Y + BUTTONS_STEP*1,
|
||||||
|
BUTTONS_Y_LINE_2 = BUTTONS_START_Y + BUTTONS_STEP*2,
|
||||||
|
BUTTONS_Y_LINE_3 = BUTTONS_START_Y + BUTTONS_STEP*3,
|
||||||
|
|
||||||
|
BUTTONS_X_LEFT = 20,
|
||||||
|
BUTTONS_X_RIGHT = 200,
|
||||||
|
} ButtonPos;
|
||||||
|
|
||||||
void init_screens(void);
|
void init_screens(void);
|
||||||
void exit_screens(void);
|
void exit_screens(void);
|
||||||
|
|
||||||
void draw_themext_error(void);
|
void draw_themext_error(void);
|
||||||
void draw_base_interface(void);
|
void throw_error(char* error, ErrorLevel level);
|
||||||
void draw_theme_install(int install_type);
|
|
||||||
void draw_theme_interface(Theme_s * themes_list, int theme_count, int selected_theme, bool preview_mode, int shuffle_theme_count);
|
void draw_preview(int preview_offset);
|
||||||
void draw_splash_install(int install_type);
|
|
||||||
void draw_splash_interface(Splash_s *splashes_list, int splash_count, int selected_splash, bool preview_mode);
|
void draw_install(InstallType type);
|
||||||
void throw_error(char* error, int error_type);
|
|
||||||
|
void draw_interface(Entry_List_s* list, EntryMode current_mode);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -36,7 +36,7 @@ FS_Archive ArchiveThemeExt;
|
|||||||
Result open_archives(void);
|
Result open_archives(void);
|
||||||
Result close_archives(void);
|
Result close_archives(void);
|
||||||
|
|
||||||
u64 file_to_buf(FS_Path path, FS_Archive archive, char** buf);
|
u32 file_to_buf(FS_Path path, FS_Archive archive, char** buf);
|
||||||
u32 zip_file_to_buf(char *file_name, u16 *zip_path, char **buf);
|
u32 zip_file_to_buf(char *file_name, u16 *zip_path, char **buf);
|
||||||
|
|
||||||
Result buf_to_file(u32 size, char *path, FS_Archive archive, char *buf);
|
Result buf_to_file(u32 size, char *path, FS_Archive archive, char *buf);
|
||||||
|
|||||||
60
include/loading.h
Normal file
60
include/loading.h
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Anemone3DS
|
||||||
|
* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth")
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||||
|
* * Requiring preservation of specified reasonable legal notices or
|
||||||
|
* author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
* * Prohibiting misrepresentation of the origin of that material,
|
||||||
|
* or requiring that modified versions of such material be marked in
|
||||||
|
* reasonable ways as different from the original version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LOADING_H
|
||||||
|
#define LOADING_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u16 name[0x41];
|
||||||
|
u16 desc[0x81];
|
||||||
|
u16 author[0x41];
|
||||||
|
|
||||||
|
u32 placeholder_color;
|
||||||
|
ssize_t icon_id;
|
||||||
|
|
||||||
|
u16 path[0x106];
|
||||||
|
bool is_zip;
|
||||||
|
|
||||||
|
bool in_shuffle;
|
||||||
|
} Entry_s;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Entry_s * entries;
|
||||||
|
int entries_count;
|
||||||
|
|
||||||
|
int scroll;
|
||||||
|
int selected_entry;
|
||||||
|
|
||||||
|
int shuffle_count;
|
||||||
|
} Entry_List_s;
|
||||||
|
|
||||||
|
Result load_entries(const char * loading_path, Entry_List_s * list);
|
||||||
|
bool load_preview(Entry_List_s list, int * preview_offset);
|
||||||
|
u32 load_data(char * filename, Entry_s entry, char ** buf);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -28,26 +28,9 @@
|
|||||||
#define SPLASHES_H
|
#define SPLASHES_H
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "loading.h"
|
||||||
|
|
||||||
typedef struct {
|
void splash_delete(void);
|
||||||
u16 name[0x41];
|
void splash_install(Entry_s splash);
|
||||||
u16 desc[0x81];
|
|
||||||
u16 author[0x41];
|
|
||||||
|
|
||||||
u32 placeholder_color;
|
|
||||||
ssize_t icon_id;
|
|
||||||
|
|
||||||
u16 path[0x106];
|
|
||||||
bool is_zip;
|
|
||||||
} Splash_s;
|
|
||||||
|
|
||||||
Splash_s *splashes_list;
|
|
||||||
int splash_count;
|
|
||||||
|
|
||||||
Result get_splashes(Splash_s** splashes_list, int *splash_count);
|
|
||||||
int splashcmp(const void* a, const void* b);
|
|
||||||
void splash_install(Splash_s splash_to_install);
|
|
||||||
void splash_delete();
|
|
||||||
void load_splash_preview(Splash_s *splash);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -28,33 +28,12 @@
|
|||||||
#define THEMES_H
|
#define THEMES_H
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "loading.h"
|
||||||
|
|
||||||
typedef struct {
|
void delete_theme(Entry_s theme);
|
||||||
u16 name[0x41];
|
Result theme_install(Entry_s theme);
|
||||||
u16 desc[0x81];
|
|
||||||
u16 author[0x41];
|
|
||||||
|
|
||||||
u32 placeholder_color;
|
Result shuffle_install(Entry_s* themes_list, int themes_count);
|
||||||
ssize_t icon_id;
|
Result bgm_install(Entry_s bgm_to_install);
|
||||||
|
|
||||||
bool has_preview;
|
|
||||||
int preview_offset;
|
|
||||||
|
|
||||||
u16 path[0x106];
|
|
||||||
bool is_zip;
|
|
||||||
|
|
||||||
bool in_shuffle;
|
|
||||||
} Theme_s;
|
|
||||||
|
|
||||||
Theme_s * themes_list;
|
|
||||||
int theme_count;
|
|
||||||
|
|
||||||
void load_theme_preview(Theme_s *theme);
|
|
||||||
Result get_themes(Theme_s **themes_list, int *theme_count);
|
|
||||||
int themecmp(const void* a, const void* b);
|
|
||||||
void del_theme(u16 *path);
|
|
||||||
Result single_install(Theme_s theme);
|
|
||||||
Result shuffle_install(Theme_s *themes_list, int theme_count);
|
|
||||||
Result bgm_install(Theme_s bgm_to_install);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -27,14 +27,16 @@
|
|||||||
#include "camera.h"
|
#include "camera.h"
|
||||||
|
|
||||||
#include "quirc/quirc.h"
|
#include "quirc/quirc.h"
|
||||||
#include "draw.h"
|
|
||||||
#include "fs.h"
|
|
||||||
#include "themes.h"
|
|
||||||
#include "pp2d/pp2d/pp2d.h"
|
#include "pp2d/pp2d/pp2d.h"
|
||||||
|
|
||||||
u32 transfer_size;
|
#include "draw.h"
|
||||||
Handle event;
|
#include "fs.h"
|
||||||
struct quirc* context;
|
#include "loading.h"
|
||||||
|
|
||||||
|
static u32 transfer_size;
|
||||||
|
static Handle event;
|
||||||
|
static struct quirc* context;
|
||||||
|
static u16 * camera_buf = NULL;
|
||||||
|
|
||||||
void init_qr(void)
|
void init_qr(void)
|
||||||
{
|
{
|
||||||
@@ -69,10 +71,14 @@ void exit_qr(void)
|
|||||||
CAMU_Activate(SELECT_NONE);
|
CAMU_Activate(SELECT_NONE);
|
||||||
camExit();
|
camExit();
|
||||||
quirc_destroy(context);
|
quirc_destroy(context);
|
||||||
|
free(camera_buf);
|
||||||
|
camera_buf = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void scan_qr(u16 *buf)
|
bool scan_qr(EntryMode current_mode)
|
||||||
{
|
{
|
||||||
|
if(camera_buf == NULL) return false;
|
||||||
|
|
||||||
int w;
|
int w;
|
||||||
int h;
|
int h;
|
||||||
|
|
||||||
@@ -82,7 +88,7 @@ void scan_qr(u16 *buf)
|
|||||||
{
|
{
|
||||||
for (ssize_t y = 0; y < h; y++)
|
for (ssize_t y = 0; y < h; y++)
|
||||||
{
|
{
|
||||||
u16 px = buf[y * 400 + x];
|
u16 px = camera_buf[y * 400 + x];
|
||||||
image[y * w + x] = (u8)(((((px >> 11) & 0x1F) << 3) + (((px >> 5) & 0x3F) << 2) + ((px & 0x1F) << 3)) / 3);
|
image[y * w + x] = (u8)(((((px >> 11) & 0x1F) << 3) + (((px >> 5) & 0x3F) << 2) + ((px & 0x1F) << 3)) / 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,59 +102,49 @@ void scan_qr(u16 *buf)
|
|||||||
quirc_extract(context, 0, &code);
|
quirc_extract(context, 0, &code);
|
||||||
if (!quirc_decode(&code, &data))
|
if (!quirc_decode(&code, &data))
|
||||||
{
|
{
|
||||||
qr_mode = false;
|
http_get((char*)data.payload, main_paths[current_mode]);
|
||||||
|
exit_qr();
|
||||||
http_get((char*)data.payload, splash_mode ? "/Splashes/" : "/Themes/");
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void take_picture(void)
|
void take_picture(void)
|
||||||
{
|
{
|
||||||
u16 *buf = malloc(sizeof(u16) * 400 * 240 * 4);
|
pp2d_begin_draw(GFX_TOP, GFX_LEFT);
|
||||||
if (buf == NULL) return;
|
free(camera_buf);
|
||||||
CAMU_SetReceiving(&event, buf, PORT_CAM1, 240 * 400 * 2, transfer_size);
|
|
||||||
|
camera_buf = malloc(sizeof(u16) * 400 * 240 * 4);
|
||||||
|
if (camera_buf == NULL) return;
|
||||||
|
|
||||||
|
CAMU_SetReceiving(&event, camera_buf, PORT_CAM1, 240 * 400 * 2, transfer_size);
|
||||||
svcWaitSynchronization(event, U64_MAX);
|
svcWaitSynchronization(event, U64_MAX);
|
||||||
svcCloseHandle(event);
|
svcCloseHandle(event);
|
||||||
pp2d_begin_draw(GFX_TOP, GFX_LEFT);
|
|
||||||
u32 *rgba8_buf = malloc(240 * 400 * sizeof(u32));
|
u32 *rgba8_buf = malloc(240 * 400 * sizeof(u32));
|
||||||
if (rgba8_buf == NULL) return;
|
if (rgba8_buf == NULL) return;
|
||||||
for (int i = 0; i < 240 * 400; i++)
|
for (int i = 0; i < 240 * 400; i++)
|
||||||
{
|
{
|
||||||
rgba8_buf[i] = RGB565_TO_ABGR8(buf[i]);
|
rgba8_buf[i] = RGB565_TO_ABGR8(camera_buf[i]);
|
||||||
}
|
}
|
||||||
|
pp2d_free_texture(TEXTURE_QR);
|
||||||
pp2d_load_texture_memory(TEXTURE_QR, rgba8_buf, 400, 240);
|
pp2d_load_texture_memory(TEXTURE_QR, rgba8_buf, 400, 240);
|
||||||
|
free(rgba8_buf);
|
||||||
|
|
||||||
pp2d_draw_texture(TEXTURE_QR, 0, 0);
|
pp2d_draw_texture(TEXTURE_QR, 0, 0);
|
||||||
pp2d_draw_rectangle(0, 216, 400, 24, RGBA8(55, 122, 168, 255));
|
pp2d_draw_rectangle(0, 216, 400, 24, RGBA8(55, 122, 168, 255));
|
||||||
pp2d_draw_text_center(GFX_TOP, 220, 0.5, 0.5, RGBA8(255, 255, 255, 255), "Press \uE005 To Quit");
|
pp2d_draw_text_center(GFX_TOP, 220, 0.5, 0.5, RGBA8(255, 255, 255, 255), "Press \uE005 To Quit");
|
||||||
pp2d_draw_rectangle(0, 0, 400, 24, RGBA8(55, 122, 168, 255));
|
pp2d_draw_rectangle(0, 0, 400, 24, RGBA8(55, 122, 168, 255));
|
||||||
pp2d_draw_text_center(GFX_TOP, 4, 0.5, 0.5, RGBA8(255, 255, 255, 255), "Press \uE004 To Scan");
|
pp2d_draw_text_center(GFX_TOP, 4, 0.5, 0.5, RGBA8(255, 255, 255, 255), "Press \uE004 To Scan");
|
||||||
pp2d_end_draw();
|
|
||||||
free(rgba8_buf);
|
|
||||||
pp2d_free_texture(TEXTURE_QR);
|
|
||||||
hidScanInput();
|
|
||||||
u32 kDown = hidKeysDown();
|
|
||||||
if (kDown & KEY_L)
|
|
||||||
{
|
|
||||||
CAMU_StopCapture(PORT_BOTH);
|
|
||||||
CAMU_Activate(SELECT_NONE);
|
|
||||||
scan_qr(buf);
|
|
||||||
CAMU_Activate(SELECT_OUT1_OUT2);
|
|
||||||
CAMU_StartCapture(PORT_BOTH);
|
|
||||||
}
|
|
||||||
if (kDown & KEY_R)
|
|
||||||
{
|
|
||||||
exit_qr();
|
|
||||||
qr_mode = false;
|
|
||||||
}
|
|
||||||
free(buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Putting this in camera because I'm too lazy to make a network.c
|
Putting this in camera because I'm too lazy to make a network.c
|
||||||
This'll probably get refactored later
|
This'll probably get refactored later
|
||||||
*/
|
*/
|
||||||
Result http_get(char *url, char *path)
|
Result http_get(char *url, const char *path)
|
||||||
{
|
{
|
||||||
Result ret;
|
Result ret;
|
||||||
httpcContext context;
|
httpcContext context;
|
||||||
@@ -164,9 +160,10 @@ Result http_get(char *url, char *path)
|
|||||||
ret = httpcOpenContext(&context, HTTPC_METHOD_GET, url, 1);
|
ret = httpcOpenContext(&context, HTTPC_METHOD_GET, url, 1);
|
||||||
ret = httpcSetSSLOpt(&context, SSLCOPT_DisableVerify); // should let us do https
|
ret = httpcSetSSLOpt(&context, SSLCOPT_DisableVerify); // should let us do https
|
||||||
ret = httpcSetKeepAlive(&context, HTTPC_KEEPALIVE_ENABLED);
|
ret = httpcSetKeepAlive(&context, HTTPC_KEEPALIVE_ENABLED);
|
||||||
ret = httpcAddRequestHeaderField(&context, "User-Agent", "Anemone3DS/1.1.0");
|
ret = httpcAddRequestHeaderField(&context, "User-Agent", USER_AGENT);
|
||||||
ret = httpcAddRequestHeaderField(&context, "Connection", "Keep-Alive");
|
ret = httpcAddRequestHeaderField(&context, "Connection", "Keep-Alive");
|
||||||
draw_theme_install(DOWNLOADING);
|
draw_install(INSTALL_DOWNLOAD);
|
||||||
|
|
||||||
ret = httpcBeginRequest(&context);
|
ret = httpcBeginRequest(&context);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
{
|
{
|
||||||
@@ -234,9 +231,7 @@ Result http_get(char *url, char *path)
|
|||||||
free(content_disposition);
|
free(content_disposition);
|
||||||
free(new_url);
|
free(new_url);
|
||||||
free(buf);
|
free(buf);
|
||||||
char error[29] = {0};
|
throw_error("Target is not valid!", ERROR_LEVEL_WARNING);
|
||||||
sprintf(error, "Target is not a valid %s", splash_mode ? "splash" : "theme");
|
|
||||||
throw_error(error, WARNING);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < strlen(filename); i++)
|
for (size_t i = 0; i < strlen(filename); i++)
|
||||||
@@ -283,14 +278,13 @@ Result http_get(char *url, char *path)
|
|||||||
char path_to_file[0x106] = {0};
|
char path_to_file[0x106] = {0};
|
||||||
strcpy(path_to_file, path);
|
strcpy(path_to_file, path);
|
||||||
strcat(path_to_file, filename);
|
strcat(path_to_file, filename);
|
||||||
|
char * extension = strrchr(path_to_file, '.');
|
||||||
|
if (extension == NULL || strcmp(extension, ".zip"))
|
||||||
|
strcat(path_to_file, ".zip");
|
||||||
|
|
||||||
remake_file(path_to_file, ArchiveSD, size);
|
remake_file(path_to_file, ArchiveSD, size);
|
||||||
buf_to_file(size, path_to_file, ArchiveSD, (char*)buf);
|
buf_to_file(size, path_to_file, ArchiveSD, (char*)buf);
|
||||||
|
|
||||||
if (splash_mode) get_splashes(&splashes_list, &splash_count);
|
|
||||||
else get_themes(&themes_list, &theme_count);
|
|
||||||
|
|
||||||
exit_qr();
|
|
||||||
|
|
||||||
free(content_disposition);
|
free(content_disposition);
|
||||||
free(new_url);
|
free(new_url);
|
||||||
free(buf);
|
free(buf);
|
||||||
|
|||||||
387
source/draw.c
387
source/draw.c
@@ -25,14 +25,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "common.h"
|
#include "unicode.h"
|
||||||
|
|
||||||
#include "pp2d/pp2d/pp2d.h"
|
#include "pp2d/pp2d/pp2d.h"
|
||||||
#include "quirc/quirc.h"
|
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
|
||||||
enum Colors {
|
enum Colors {
|
||||||
COLOR_BACKGROUND = ABGR8(255, 32, 28, 35), //silver-y black
|
COLOR_BACKGROUND = ABGR8(255, 32, 28, 35), //silver-y black
|
||||||
COLOR_ACCENT = RGBA8(55, 122, 168, 255),
|
COLOR_ACCENT = RGBA8(55, 122, 168, 255),
|
||||||
@@ -65,11 +63,7 @@ void exit_screens(void)
|
|||||||
pp2d_exit();
|
pp2d_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int theme_vertical_scroll = 0;
|
static void draw_base_interface(void)
|
||||||
static int splash_vertical_scroll = 0;
|
|
||||||
|
|
||||||
|
|
||||||
void draw_base_interface(void)
|
|
||||||
{
|
{
|
||||||
pp2d_begin_draw(GFX_TOP, GFX_LEFT);
|
pp2d_begin_draw(GFX_TOP, GFX_LEFT);
|
||||||
pp2d_draw_rectangle(0, 0, 400, 23, COLOR_ACCENT);
|
pp2d_draw_rectangle(0, 0, 400, 23, COLOR_ACCENT);
|
||||||
@@ -78,29 +72,32 @@ void draw_base_interface(void)
|
|||||||
struct tm tm = *localtime(&t);
|
struct tm tm = *localtime(&t);
|
||||||
|
|
||||||
pp2d_draw_textf(7, 2, 0.6, 0.6, COLOR_WHITE, "%.2i", tm.tm_hour);
|
pp2d_draw_textf(7, 2, 0.6, 0.6, COLOR_WHITE, "%.2i", tm.tm_hour);
|
||||||
pp2d_draw_text(28, 2, 0.6, 0.6, COLOR_WHITE, (tm.tm_sec % 2 == 1) ? ":" : " ");
|
pp2d_draw_text(28, 1, 0.6, 0.6, COLOR_WHITE, (tm.tm_sec % 2 == 1) ? ":" : " ");
|
||||||
pp2d_draw_textf(34, 2, 0.6, 0.6, COLOR_WHITE, "%.2i", tm.tm_min);
|
pp2d_draw_textf(34, 2, 0.6, 0.6, COLOR_WHITE, "%.2i", tm.tm_min);
|
||||||
|
|
||||||
u8 battery_charging;
|
u8 battery_charging = 0;
|
||||||
PTMU_GetBatteryChargeState(&battery_charging);
|
PTMU_GetBatteryChargeState(&battery_charging);
|
||||||
u8 battery_status;
|
u8 battery_status = 0;
|
||||||
PTMU_GetBatteryLevel(&battery_status);
|
PTMU_GetBatteryLevel(&battery_status);
|
||||||
pp2d_draw_texture(2 + battery_status, 357, 2);
|
pp2d_draw_texture(TEXTURE_BATTERY_1 + battery_status - 1, 357, 2);
|
||||||
|
|
||||||
if (battery_charging)
|
if(battery_charging)
|
||||||
pp2d_draw_texture(TEXTURE_BATTERY_CHARGE, 357, 2);
|
pp2d_draw_texture(TEXTURE_BATTERY_CHARGE, 357, 2);
|
||||||
|
|
||||||
pp2d_draw_on(GFX_BOTTOM, GFX_LEFT);
|
pp2d_draw_on(GFX_BOTTOM, GFX_LEFT);
|
||||||
pp2d_draw_rectangle(0, 0, 320, 24, COLOR_ACCENT);
|
pp2d_draw_rectangle(0, 0, 320, 24, COLOR_ACCENT);
|
||||||
pp2d_draw_rectangle(0, 216, 320, 24, COLOR_ACCENT);
|
pp2d_draw_rectangle(0, 216, 320, 24, COLOR_ACCENT);
|
||||||
pp2d_draw_text(7, 219, 0.6, 0.6, COLOR_WHITE, VERSION);
|
pp2d_draw_text(7, 219, 0.6, 0.6, COLOR_WHITE, VERSION);
|
||||||
|
|
||||||
pp2d_draw_on(GFX_TOP, GFX_LEFT);
|
pp2d_draw_on(GFX_TOP, GFX_LEFT);
|
||||||
}
|
}
|
||||||
void throw_error(char* error, int error_type) {
|
|
||||||
|
|
||||||
switch (error_type) {
|
void throw_error(char* error, ErrorLevel level)
|
||||||
case ERROR:
|
{
|
||||||
while (aptMainLoop())
|
switch(level)
|
||||||
|
{
|
||||||
|
case ERROR_LEVEL_ERROR:
|
||||||
|
while(aptMainLoop())
|
||||||
{
|
{
|
||||||
hidScanInput();
|
hidScanInput();
|
||||||
u32 kDown = hidKeysDown();
|
u32 kDown = hidKeysDown();
|
||||||
@@ -108,254 +105,190 @@ void throw_error(char* error, int error_type) {
|
|||||||
pp2d_draw_text_center(GFX_TOP, 120, 0.6, 0.6, COLOR_RED, error);
|
pp2d_draw_text_center(GFX_TOP, 120, 0.6, 0.6, COLOR_RED, error);
|
||||||
pp2d_draw_wtext_center(GFX_TOP, 150, 0.6, 0.6, COLOR_WHITE, L"Press \uE000 to shut down.");
|
pp2d_draw_wtext_center(GFX_TOP, 150, 0.6, 0.6, COLOR_WHITE, L"Press \uE000 to shut down.");
|
||||||
pp2d_end_draw();
|
pp2d_end_draw();
|
||||||
if (kDown & KEY_A) {
|
if(kDown & KEY_A) exit_function();
|
||||||
if (homebrew)
|
}
|
||||||
APT_HardwareResetAsync();
|
break;
|
||||||
else {
|
case ERROR_LEVEL_WARNING:
|
||||||
srvPublishToSubscriber(0x202, 0);
|
while(aptMainLoop())
|
||||||
}
|
{
|
||||||
}
|
hidScanInput();
|
||||||
|
u32 kDown = hidKeysDown();
|
||||||
|
draw_base_interface();
|
||||||
|
pp2d_draw_text_center(GFX_TOP, 120, 0.6, 0.6, COLOR_YELLOW, error);
|
||||||
|
pp2d_draw_wtext_center(GFX_TOP, 150, 0.6, 0.6, COLOR_WHITE, L"Press \uE000 to continue.");
|
||||||
|
pp2d_end_draw();
|
||||||
|
if(kDown & KEY_A) break;
|
||||||
}
|
}
|
||||||
case WARNING:
|
|
||||||
while (aptMainLoop())
|
|
||||||
{
|
|
||||||
hidScanInput();
|
|
||||||
u32 kDown = hidKeysDown();
|
|
||||||
draw_base_interface();
|
|
||||||
pp2d_draw_text_center(GFX_TOP, 120, 0.6, 0.6, COLOR_YELLOW, error);
|
|
||||||
pp2d_draw_wtext_center(GFX_TOP, 150, 0.6, 0.6, COLOR_WHITE, L"Press \uE000 to continue.");
|
|
||||||
pp2d_end_draw();
|
|
||||||
if (kDown & KEY_A) break;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pp2d_end_draw();
|
|
||||||
}
|
}
|
||||||
void draw_theme_install(int install_type)
|
|
||||||
|
void draw_preview(int preview_offset)
|
||||||
|
{
|
||||||
|
pp2d_begin_draw(GFX_TOP, GFX_LEFT);
|
||||||
|
pp2d_draw_texture_part(TEXTURE_PREVIEW, 0, 0, preview_offset, 0, 400, 240);
|
||||||
|
pp2d_draw_on(GFX_BOTTOM, GFX_LEFT);
|
||||||
|
pp2d_draw_texture_part(TEXTURE_PREVIEW, 0, 0, 40 + preview_offset, 240, 320, 240);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_install(InstallType type)
|
||||||
{
|
{
|
||||||
draw_base_interface();
|
draw_base_interface();
|
||||||
switch(install_type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case 0:
|
case INSTALL_SINGLE:
|
||||||
pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Installing a single theme...");
|
pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Installing a single theme...");
|
||||||
break;
|
break;
|
||||||
case 1:
|
case INSTALL_SHUFFLE:
|
||||||
pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Installing a shuffle theme...");
|
pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Installing a shuffle theme...");
|
||||||
break;
|
break;
|
||||||
case 2:
|
case INSTALL_BGM:
|
||||||
pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Installing BGM...");
|
pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Installing BGM...");
|
||||||
break;
|
break;
|
||||||
case 3:
|
case INSTALL_DOWNLOAD:
|
||||||
pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Downloading...");
|
pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Downloading...");
|
||||||
break;
|
break;
|
||||||
|
case INSTALL_SPLASH:
|
||||||
|
pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Installing a splash...");
|
||||||
|
break;
|
||||||
|
case INSTALL_SPLASH_DELETE:
|
||||||
|
pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Uninstalling a splash...");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pp2d_end_draw();
|
pp2d_end_draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_theme_interface(Theme_s * themes_list, int theme_count, int selected_theme, bool preview_mode, int shuffle_theme_count)
|
void draw_interface(Entry_List_s* list, EntryMode current_mode)
|
||||||
{
|
|
||||||
|
|
||||||
if (themes_list == NULL)
|
|
||||||
{
|
|
||||||
draw_base_interface();
|
|
||||||
pp2d_draw_text_center(GFX_TOP, 80, 0.7, 0.7, COLOR_YELLOW, "No themes found!");
|
|
||||||
pp2d_draw_text_center(GFX_TOP, 110, 0.7, 0.7, COLOR_YELLOW, "Press \uE005 to download from QR");
|
|
||||||
pp2d_draw_text_center(GFX_TOP, 140, 0.7, 0.7, COLOR_YELLOW, "Or \uE045 to quit");
|
|
||||||
pp2d_end_draw();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Theme_s current_theme = themes_list[selected_theme];
|
|
||||||
|
|
||||||
if (preview_mode)
|
|
||||||
{
|
|
||||||
if (current_theme.has_preview)
|
|
||||||
{
|
|
||||||
pp2d_begin_draw(GFX_TOP, GFX_LEFT);
|
|
||||||
pp2d_draw_texture_part(TEXTURE_PREVIEW, 0, 0, current_theme.preview_offset, 0, 400, 240);
|
|
||||||
pp2d_draw_on(GFX_BOTTOM, GFX_LEFT);
|
|
||||||
pp2d_draw_texture_part(TEXTURE_PREVIEW, 0, 0, 40+current_theme.preview_offset, 240, 320, 240);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
draw_base_interface();
|
|
||||||
pp2d_draw_text_center(GFX_TOP, 4, 0.5, 0.5, COLOR_WHITE, "Theme mode");
|
|
||||||
wchar_t title[0x41] = {0};
|
|
||||||
utf16_to_utf32((u32*)title, current_theme.name, 0x40);
|
|
||||||
pp2d_draw_wtext_wrap(20, 30, 0.7, 0.7, COLOR_WHITE, 380, title);
|
|
||||||
wchar_t author[0x41] = {0};
|
|
||||||
utf16_to_utf32((u32*)author, current_theme.author, 0x40);
|
|
||||||
pp2d_draw_text(20, 50, 0.5, 0.5, COLOR_WHITE, "By: ");
|
|
||||||
pp2d_draw_wtext_wrap(44, 50, 0.5, 0.5, COLOR_WHITE, 380, author);
|
|
||||||
wchar_t description[0x81] = {0};
|
|
||||||
utf16_to_utf32((u32*)description, current_theme.desc, 0x80);
|
|
||||||
pp2d_draw_wtext_wrap(20, 65, 0.5, 0.5, COLOR_WHITE, 363, description);
|
|
||||||
|
|
||||||
pp2d_draw_wtext(20, 150, 0.6, 0.6, COLOR_WHITE, L"\uE046 Install Shuffle Theme");
|
|
||||||
pp2d_draw_wtext(200, 150, 0.6, 0.6, COLOR_WHITE, L"\uE004 Switch to Splashes");
|
|
||||||
pp2d_draw_wtext(20, 180, 0.6, 0.6, COLOR_WHITE, L"\uE000 Install Theme");
|
|
||||||
pp2d_draw_wtext(200, 180, 0.6, 0.6, COLOR_WHITE, L"\uE001 Queue Shuffle");
|
|
||||||
pp2d_draw_wtext(20, 210, 0.6, 0.6, COLOR_WHITE, L"\uE002 Install BGM");
|
|
||||||
pp2d_draw_wtext(200, 210, 0.6, 0.6, COLOR_WHITE, L"\uE003 Preview Theme");
|
|
||||||
pp2d_draw_wtext(130, 120, 0.6, 0.6, COLOR_WHITE, L"\uE005 Scan QRCode");
|
|
||||||
pp2d_draw_on(GFX_BOTTOM, GFX_LEFT);
|
|
||||||
|
|
||||||
pp2d_draw_textf(7, 3, 0.6, 0.6, COLOR_WHITE, "Selected: %i/10", shuffle_theme_count);
|
|
||||||
|
|
||||||
// Scroll the menu up or down if the selected theme is out of its bounds
|
|
||||||
//----------------------------------------------------------------
|
|
||||||
for (int i = 0; i < theme_count; i++) {
|
|
||||||
if (theme_count <= THEMES_PER_SCREEN)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (theme_vertical_scroll > selected_theme)
|
|
||||||
theme_vertical_scroll--;
|
|
||||||
|
|
||||||
if ((i < selected_theme) && \
|
|
||||||
((selected_theme - theme_vertical_scroll) >= THEMES_PER_SCREEN) && \
|
|
||||||
(theme_vertical_scroll != ( - THEMES_PER_SCREEN)))
|
|
||||||
theme_vertical_scroll++;
|
|
||||||
}
|
|
||||||
//----------------------------------------------------------------
|
|
||||||
|
|
||||||
// Show arrows if there are themes out of bounds
|
|
||||||
//----------------------------------------------------------------
|
|
||||||
if (theme_vertical_scroll > 0)
|
|
||||||
pp2d_draw_texture(TEXTURE_ARROW, 155, 6);
|
|
||||||
if (theme_vertical_scroll + THEMES_PER_SCREEN < theme_count)
|
|
||||||
pp2d_draw_texture_flip(TEXTURE_ARROW, 155, 224, VERTICAL);
|
|
||||||
|
|
||||||
for (int i = theme_vertical_scroll; i < (THEMES_PER_SCREEN + theme_vertical_scroll); i++)
|
|
||||||
{
|
|
||||||
if (i >= theme_count)
|
|
||||||
break;
|
|
||||||
|
|
||||||
current_theme = themes_list[i];
|
|
||||||
wchar_t name[0x80] = {0};
|
|
||||||
utf16_to_utf32((u32*)name, current_theme.name, 0x80);
|
|
||||||
|
|
||||||
int vertical_offset = 48 * (i-theme_vertical_scroll);
|
|
||||||
u32 font_color = COLOR_WHITE;
|
|
||||||
|
|
||||||
if (i == selected_theme)
|
|
||||||
{
|
|
||||||
font_color = COLOR_BLACK;
|
|
||||||
pp2d_draw_rectangle(0, 24 + vertical_offset, 320, 48, COLOR_CURSOR);
|
|
||||||
}
|
|
||||||
pp2d_draw_wtext(54, 40 + vertical_offset, 0.55, 0.55, font_color, name);
|
|
||||||
if (!current_theme.placeholder_color)
|
|
||||||
pp2d_draw_texture(current_theme.icon_id, 0, 24 + vertical_offset);
|
|
||||||
else
|
|
||||||
pp2d_draw_rectangle(0, 24 + vertical_offset, 48, 48, current_theme.placeholder_color);
|
|
||||||
|
|
||||||
if (current_theme.in_shuffle)
|
|
||||||
pp2d_draw_texture_blend(TEXTURE_SHUFFLE, 280, 32 + vertical_offset, font_color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pp2d_end_draw();
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_splash_install(int install_type)
|
|
||||||
{
|
{
|
||||||
draw_base_interface();
|
draw_base_interface();
|
||||||
switch (install_type)
|
|
||||||
|
const char* mode_string[] = {
|
||||||
|
"Theme mode",
|
||||||
|
"Splashes mode",
|
||||||
|
};
|
||||||
|
|
||||||
|
pp2d_draw_text_center(GFX_TOP, 4, 0.5, 0.5, COLOR_WHITE, mode_string[current_mode]);
|
||||||
|
|
||||||
|
if(list->entries == NULL)
|
||||||
{
|
{
|
||||||
case SINGLE_INSTALL:
|
const char* mode_found_string[] = {
|
||||||
pp2d_draw_text_center(GFX_TOP, 110, 0.7, 0.7, COLOR_WHITE, "Installing a splash...");
|
"No themes found",
|
||||||
|
"No splashes found",
|
||||||
|
};
|
||||||
|
pp2d_draw_text_center(GFX_TOP, 80, 0.7, 0.7, COLOR_YELLOW, mode_found_string[current_mode]);
|
||||||
|
pp2d_draw_text_center(GFX_TOP, 110, 0.7, 0.7, COLOR_YELLOW, "Press \uE005 to download from QR");
|
||||||
|
const char* mode_switch_string[] = {
|
||||||
|
"Or \uE004 to switch to splashes",
|
||||||
|
"Or \uE004 to switch to themes",
|
||||||
|
};
|
||||||
|
pp2d_draw_text_center(GFX_TOP, 140, 0.7, 0.7, COLOR_YELLOW, mode_switch_string[current_mode]);
|
||||||
|
pp2d_draw_text_center(GFX_TOP, 170, 0.7, 0.7, COLOR_YELLOW, "Or \uE045 to quit");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int selected_entry = list->selected_entry;
|
||||||
|
Entry_s current_entry = list->entries[selected_entry];
|
||||||
|
|
||||||
|
wchar_t title[0x41] = {0};
|
||||||
|
utf16_to_utf32((u32*)title, current_entry.name, 0x40);
|
||||||
|
pp2d_draw_wtext_wrap(20, 30, 0.7, 0.7, COLOR_WHITE, 380, title);
|
||||||
|
|
||||||
|
wchar_t author[0x41] = {0};
|
||||||
|
utf16_to_utf32((u32*)author, current_entry.author, 0x40);
|
||||||
|
pp2d_draw_text(20, 50, 0.5, 0.5, COLOR_WHITE, "By: ");
|
||||||
|
pp2d_draw_wtext_wrap(44, 50, 0.5, 0.5, COLOR_WHITE, 380, author);
|
||||||
|
|
||||||
|
wchar_t description[0x81] = {0};
|
||||||
|
utf16_to_utf32((u32*)description, current_entry.desc, 0x80);
|
||||||
|
pp2d_draw_wtext_wrap(20, 65, 0.5, 0.5, COLOR_WHITE, 363, description);
|
||||||
|
|
||||||
|
|
||||||
|
switch(current_mode)
|
||||||
|
{
|
||||||
|
case MODE_THEMES:
|
||||||
|
pp2d_draw_text_center(GFX_TOP, BUTTONS_Y_PREVIEW, 0.6, 0.6, COLOR_WHITE, "\uE003 Preview Theme");
|
||||||
|
pp2d_draw_wtext(BUTTONS_X_LEFT, BUTTONS_Y_LINE_1, 0.6, 0.6, COLOR_WHITE, L"\uE004 Switch to Splashes");
|
||||||
|
pp2d_draw_wtext(BUTTONS_X_RIGHT, BUTTONS_Y_LINE_1, 0.6, 0.6, COLOR_WHITE, L"\uE005 Scan QRCode");
|
||||||
|
|
||||||
|
pp2d_draw_wtext(BUTTONS_X_LEFT, BUTTONS_Y_LINE_2, 0.6, 0.6, COLOR_WHITE, L"\uE000 Install Theme");
|
||||||
|
pp2d_draw_wtext(BUTTONS_X_RIGHT, BUTTONS_Y_LINE_2, 0.6, 0.6, COLOR_WHITE, L"\uE001 Queue Shuffle");
|
||||||
|
|
||||||
|
pp2d_draw_wtext(BUTTONS_X_LEFT, BUTTONS_Y_LINE_3, 0.6, 0.6, COLOR_WHITE, L"\uE002 Install BGM");
|
||||||
|
pp2d_draw_wtext(BUTTONS_X_RIGHT, BUTTONS_Y_LINE_3, 0.6, 0.6, COLOR_WHITE, L"\uE046 Install Shuffle Themes");
|
||||||
break;
|
break;
|
||||||
case UNINSTALL:
|
case MODE_SPLASHES:
|
||||||
pp2d_draw_text_center(GFX_TOP, 110, 0.7, 0.7, COLOR_WHITE, "Uninstalling a splash...");
|
pp2d_draw_text_center(GFX_TOP, BUTTONS_Y_PREVIEW, 0.6, 0.6, COLOR_WHITE, "\uE003 Preview Splash");
|
||||||
|
pp2d_draw_wtext(BUTTONS_X_LEFT, BUTTONS_Y_LINE_1, 0.6, 0.6, COLOR_WHITE, L"\uE004 Switch to Themes");
|
||||||
|
pp2d_draw_wtext(BUTTONS_X_RIGHT, BUTTONS_Y_LINE_1, 0.6, 0.6, COLOR_WHITE, L"\uE005 Scan QRCode");
|
||||||
|
|
||||||
|
pp2d_draw_wtext(BUTTONS_X_LEFT, BUTTONS_Y_LINE_2, 0.6, 0.6, COLOR_WHITE, L"\uE000 Install Splash");
|
||||||
|
pp2d_draw_wtext(BUTTONS_X_RIGHT, BUTTONS_Y_LINE_2, 0.6, 0.6, COLOR_WHITE, L"\uE001 Delete installed Splash");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pp2d_end_draw();
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_splash_interface(Splash_s *splashes_list, int splash_count, int selected_splash, bool preview_mode)
|
|
||||||
{
|
pp2d_draw_on(GFX_BOTTOM, GFX_LEFT);
|
||||||
if (splashes_list == NULL)
|
|
||||||
|
switch(current_mode)
|
||||||
{
|
{
|
||||||
draw_base_interface();
|
case MODE_THEMES:
|
||||||
pp2d_draw_text_center(GFX_TOP, 80, 0.7, 0.7, COLOR_YELLOW, "No splashes found!");
|
pp2d_draw_textf(7, 3, 0.6, 0.6, list->shuffle_count <= 10 ? COLOR_WHITE : COLOR_RED, "Selected: %i/10", list->shuffle_count);
|
||||||
pp2d_draw_text_center(GFX_TOP, 110, 0.7, 0.7, COLOR_YELLOW, "Press \uE005 to download from QR");
|
break;
|
||||||
pp2d_draw_text_center(GFX_TOP, 140, 0.7, 0.7, COLOR_YELLOW, "Or \uE045 to quit");
|
default:
|
||||||
pp2d_end_draw();
|
break;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
Splash_s current_splash = splashes_list[selected_splash];
|
|
||||||
if (preview_mode)
|
// Scroll the menu up or down if the selected theme is out of its bounds
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
for(int i = 0; i < list->entries_count; i++) {
|
||||||
|
if(list->entries_count <= ENTRIES_PER_SCREEN) break;
|
||||||
|
|
||||||
|
if(list->scroll > list->selected_entry)
|
||||||
|
list->scroll--;
|
||||||
|
|
||||||
|
if((i < list->selected_entry) && \
|
||||||
|
((list->selected_entry - list->scroll) >= ENTRIES_PER_SCREEN) && \
|
||||||
|
(list->scroll != (i - ENTRIES_PER_SCREEN)))
|
||||||
|
list->scroll++;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
// Show arrows if there are themes out of bounds
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
if(list->scroll > 0)
|
||||||
|
pp2d_draw_texture(TEXTURE_ARROW, 155, 6);
|
||||||
|
if(list->scroll + ENTRIES_PER_SCREEN < list->entries_count)
|
||||||
|
pp2d_draw_texture_flip(TEXTURE_ARROW, 155, 224, VERTICAL);
|
||||||
|
|
||||||
|
for(int i = list->scroll; i < (ENTRIES_PER_SCREEN + list->scroll); i++)
|
||||||
{
|
{
|
||||||
pp2d_begin_draw(GFX_TOP, GFX_LEFT);
|
if(i >= list->entries_count) break;
|
||||||
pp2d_draw_texture_part(TEXTURE_PREVIEW, 0, 0, 0, 0, 400, 240);
|
|
||||||
pp2d_draw_on(GFX_BOTTOM, GFX_LEFT);
|
|
||||||
pp2d_draw_texture_part(TEXTURE_PREVIEW, 0, 0, 40, 240, 320, 240);
|
|
||||||
} else {
|
|
||||||
draw_base_interface();
|
|
||||||
pp2d_draw_text_center(GFX_TOP, 4, 0.5, 0.5, COLOR_WHITE, "Splash mode");
|
|
||||||
wchar_t title[0x40] = {0};
|
|
||||||
utf16_to_utf32((u32*)title, current_splash.name, 0x40);
|
|
||||||
pp2d_draw_wtext_wrap(20, 30, 0.7, 0.7, COLOR_WHITE, 380, title);
|
|
||||||
wchar_t author[0x40] = {0};
|
|
||||||
utf16_to_utf32((u32*)author, current_splash.author, 0x40);
|
|
||||||
pp2d_draw_text(20, 50, 0.5, 0.5, COLOR_WHITE, "By: ");
|
|
||||||
pp2d_draw_wtext_wrap(44, 50, 0.5, 0.5, COLOR_WHITE, 380, author);
|
|
||||||
wchar_t description[0xa6] = {0};
|
|
||||||
utf16_to_utf32((u32*)description, current_splash.desc, 0xb0);
|
|
||||||
pp2d_draw_wtext_wrap(20, 65, 0.5, 0.5, COLOR_WHITE, 363, description);
|
|
||||||
|
|
||||||
pp2d_draw_wtext_center(GFX_TOP, 180, 0.7, 0.7, COLOR_WHITE, L"\uE000 Install Splash \uE004 Switch to Themes");
|
current_entry = list->entries[i];
|
||||||
pp2d_draw_wtext_center(GFX_TOP, 210, 0.7, 0.7, COLOR_WHITE, L"\uE002 Delete current Splash");
|
|
||||||
pp2d_draw_wtext_center(GFX_TOP, 150, 0.7, 0.7, COLOR_WHITE, L"\uE003 Preview Splash \uE005 Scan QRCode");
|
|
||||||
pp2d_draw_wtext(130, 120, 0.6, 0.6, COLOR_WHITE, L"");
|
|
||||||
|
|
||||||
pp2d_draw_on(GFX_BOTTOM, GFX_LEFT);
|
wchar_t name[0x41] = {0};
|
||||||
for (int i = 0; i < splash_count; i++) {
|
utf16_to_utf32((u32*)name, current_entry.name, 0x40);
|
||||||
if (splash_count <= THEMES_PER_SCREEN)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (splash_vertical_scroll > selected_splash)
|
int vertical_offset = 48 * (i - list->scroll);
|
||||||
splash_vertical_scroll--;
|
u32 font_color = COLOR_WHITE;
|
||||||
|
|
||||||
if ((i < selected_splash) && \
|
if(i == list->selected_entry)
|
||||||
((selected_splash - splash_vertical_scroll) >= THEMES_PER_SCREEN) && \
|
|
||||||
(splash_vertical_scroll != ( - THEMES_PER_SCREEN)))
|
|
||||||
splash_vertical_scroll++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (splash_vertical_scroll > 0)
|
|
||||||
pp2d_draw_texture(TEXTURE_ARROW, 155, 6);
|
|
||||||
if (splash_vertical_scroll + THEMES_PER_SCREEN < splash_count)
|
|
||||||
pp2d_draw_texture_flip(TEXTURE_ARROW, 155, 224, VERTICAL);
|
|
||||||
|
|
||||||
for (int i = splash_vertical_scroll; i < (THEMES_PER_SCREEN + splash_vertical_scroll); i++)
|
|
||||||
{
|
{
|
||||||
if (i >= splash_count)
|
font_color = COLOR_BLACK;
|
||||||
break;
|
pp2d_draw_rectangle(0, 24 + vertical_offset, 320, 48, COLOR_CURSOR);
|
||||||
|
|
||||||
current_splash = splashes_list[i];
|
|
||||||
wchar_t name[0x106] = {0};
|
|
||||||
utf16_to_utf32((u32*)name, current_splash.name, 0x106);
|
|
||||||
|
|
||||||
int vertical_offset = 48 * (i-splash_vertical_scroll);
|
|
||||||
u32 font_color = COLOR_WHITE;
|
|
||||||
|
|
||||||
if (i == selected_splash)
|
|
||||||
{
|
|
||||||
font_color = COLOR_BLACK;
|
|
||||||
pp2d_draw_rectangle(0, 24 + vertical_offset, 320, 48, COLOR_CURSOR);
|
|
||||||
}
|
|
||||||
pp2d_draw_wtext(54, 40 + vertical_offset, 0.55, 0.55, font_color, name);
|
|
||||||
|
|
||||||
if (!current_splash.placeholder_color)
|
|
||||||
pp2d_draw_texture(current_splash.icon_id, 0, 24 + vertical_offset);
|
|
||||||
else
|
|
||||||
pp2d_draw_rectangle(0, 24 + vertical_offset, 48, 48, current_splash.placeholder_color);
|
|
||||||
}
|
}
|
||||||
|
pp2d_draw_wtext(54, 40 + vertical_offset, 0.55, 0.55, font_color, name);
|
||||||
|
if(!current_entry.placeholder_color)
|
||||||
|
pp2d_draw_texture(current_entry.icon_id, 0, 24 + vertical_offset);
|
||||||
|
else
|
||||||
|
pp2d_draw_rectangle(0, 24 + vertical_offset, 48, 48, current_entry.placeholder_color);
|
||||||
|
|
||||||
|
if(current_entry.in_shuffle)
|
||||||
|
pp2d_draw_texture_blend(TEXTURE_SHUFFLE, 280, 32 + vertical_offset, font_color);
|
||||||
}
|
}
|
||||||
pp2d_end_draw();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ Result close_archives(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 file_to_buf(FS_Path path, FS_Archive archive, char** buf)
|
u32 file_to_buf(FS_Path path, FS_Archive archive, char** buf)
|
||||||
{
|
{
|
||||||
Handle file;
|
Handle file;
|
||||||
Result res = 0;
|
Result res = 0;
|
||||||
@@ -114,7 +114,7 @@ u64 file_to_buf(FS_Path path, FS_Archive archive, char** buf)
|
|||||||
*buf = calloc(1, size);
|
*buf = calloc(1, size);
|
||||||
FSFILE_Read(file, NULL, 0, *buf, size);
|
FSFILE_Read(file, NULL, 0, *buf, size);
|
||||||
FSFILE_Close(file);
|
FSFILE_Close(file);
|
||||||
return size;
|
return (u32)size;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 zip_file_to_buf(char *file_name, u16 *zip_path, char **buf)
|
u32 zip_file_to_buf(char *file_name, u16 *zip_path, char **buf)
|
||||||
|
|||||||
197
source/loading.c
Normal file
197
source/loading.c
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Anemone3DS
|
||||||
|
* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth")
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||||
|
* * Requiring preservation of specified reasonable legal notices or
|
||||||
|
* author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
* * Prohibiting misrepresentation of the origin of that material,
|
||||||
|
* or requiring that modified versions of such material be marked in
|
||||||
|
* reasonable ways as different from the original version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "loading.h"
|
||||||
|
#include "pp2d/pp2d/pp2d.h"
|
||||||
|
#include "fs.h"
|
||||||
|
#include "unicode.h"
|
||||||
|
|
||||||
|
u32 load_data(char * filename, Entry_s entry, char ** buf)
|
||||||
|
{
|
||||||
|
if(entry.is_zip)
|
||||||
|
{
|
||||||
|
return zip_file_to_buf(filename+1, entry.path, buf); //the first character will always be '/' because of the other case
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u16 path[0x106] = {0};
|
||||||
|
strucat(path, entry.path);
|
||||||
|
struacat(path, filename);
|
||||||
|
|
||||||
|
return file_to_buf(fsMakePath(PATH_UTF16, path), ArchiveSD, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_smdh(Entry_s * entry, const ssize_t textureID, const u16 * fallback_name)
|
||||||
|
{
|
||||||
|
pp2d_free_texture(textureID);
|
||||||
|
|
||||||
|
char *info_buffer = NULL;
|
||||||
|
u64 size = load_data("/info.smdh", *entry, &info_buffer);
|
||||||
|
|
||||||
|
if(!size)
|
||||||
|
{
|
||||||
|
free(info_buffer);
|
||||||
|
memcpy(entry->name, fallback_name, 0x80);
|
||||||
|
utf8_to_utf16(entry->desc, (u8*)"No description", 0x100);
|
||||||
|
utf8_to_utf16(entry->author, (u8*)"Unknown author", 0x80);
|
||||||
|
entry->placeholder_color = RGBA8(rand() % 255, rand() % 255, rand() % 255, 255);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(entry->name, info_buffer + 0x08, 0x80);
|
||||||
|
memcpy(entry->desc, info_buffer + 0x88, 0x100);
|
||||||
|
memcpy(entry->author, info_buffer + 0x188, 0x80);
|
||||||
|
|
||||||
|
u16 *icon_data = malloc(0x1200);
|
||||||
|
memcpy(icon_data, info_buffer + 0x24C0, 0x1200);
|
||||||
|
free(info_buffer);
|
||||||
|
|
||||||
|
const u32 width = 48, height = 48;
|
||||||
|
u32 *image = malloc(width*height*sizeof(u32));
|
||||||
|
|
||||||
|
for(u32 x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
for(u32 y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
unsigned int dest_pixel = (x + y*width);
|
||||||
|
unsigned int source_pixel = (((y >> 3) * (width >> 3) + (x >> 3)) << 6) + ((x & 1) | ((y & 1) << 1) | ((x & 2) << 1) | ((y & 2) << 2) | ((x & 4) << 2) | ((y & 4) << 3));
|
||||||
|
|
||||||
|
image[dest_pixel] = RGB565_TO_ABGR8(icon_data[source_pixel]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(icon_data);
|
||||||
|
pp2d_load_texture_memory(textureID, (u8*)image, (u32)width, (u32)height);
|
||||||
|
free(image);
|
||||||
|
|
||||||
|
entry->icon_id = textureID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int compare_entries(const void * a, const void * b)
|
||||||
|
{
|
||||||
|
Entry_s *entry_a = (Entry_s *)a;
|
||||||
|
Entry_s *entry_b = (Entry_s *)b;
|
||||||
|
|
||||||
|
return memcmp(entry_a->name, entry_b->name, 0x40*sizeof(u16));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sort_list(Entry_List_s * list)
|
||||||
|
{
|
||||||
|
qsort(list->entries, list->entries_count, sizeof(Entry_s), compare_entries); //alphabet sort
|
||||||
|
}
|
||||||
|
|
||||||
|
Result load_entries(const char * loading_path, Entry_List_s * list)
|
||||||
|
{
|
||||||
|
Handle dir_handle;
|
||||||
|
Result res = FSUSER_OpenDirectory(&dir_handle, ArchiveSD, fsMakePath(PATH_ASCII, loading_path));
|
||||||
|
if(R_FAILED(res))
|
||||||
|
return res;
|
||||||
|
|
||||||
|
u32 entries_read = 1;
|
||||||
|
|
||||||
|
while(entries_read)
|
||||||
|
{
|
||||||
|
FS_DirectoryEntry dir_entry = {0};
|
||||||
|
res = FSDIR_Read(dir_handle, &entries_read, 1, &dir_entry);
|
||||||
|
if(R_FAILED(res) || entries_read == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(!(dir_entry.attributes & FS_ATTRIBUTE_DIRECTORY) && strcmp(dir_entry.shortExt, "ZIP"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
list->entries_count++;
|
||||||
|
list->entries = realloc(list->entries, list->entries_count * sizeof(Entry_s));
|
||||||
|
if(list->entries == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
Entry_s * current_entry = &(list->entries[list->entries_count-1]);
|
||||||
|
memset(current_entry, 0, sizeof(Entry_s));
|
||||||
|
|
||||||
|
struacat(current_entry->path, loading_path);
|
||||||
|
strucat(current_entry->path, dir_entry.name);
|
||||||
|
|
||||||
|
current_entry->is_zip = !strcmp(dir_entry.shortExt, "ZIP");
|
||||||
|
|
||||||
|
ssize_t iconID = TEXTURE_ICON + list->entries_count;
|
||||||
|
parse_smdh(current_entry, iconID, dir_entry.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
FSDIR_Close(dir_handle);
|
||||||
|
|
||||||
|
sort_list(list);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u16 previous_path[0x106] = {0};
|
||||||
|
|
||||||
|
bool load_preview(Entry_List_s list, int * preview_offset)
|
||||||
|
{
|
||||||
|
if(list.entries == NULL) return false;
|
||||||
|
|
||||||
|
Entry_s entry = list.entries[list.selected_entry];
|
||||||
|
|
||||||
|
if(!memcmp(&previous_path, &entry.path, 0x106*sizeof(u16))) return true;
|
||||||
|
else memcpy(&previous_path, &entry.path, 0x106*sizeof(u16));
|
||||||
|
|
||||||
|
// free the previously loaded preview. wont do anything if there wasnt one
|
||||||
|
pp2d_free_texture(TEXTURE_PREVIEW);
|
||||||
|
|
||||||
|
char *preview_buffer = NULL;
|
||||||
|
u64 size = load_data("/preview.png", entry, &preview_buffer);
|
||||||
|
|
||||||
|
if(!size)
|
||||||
|
{
|
||||||
|
free(preview_buffer);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ret = false;
|
||||||
|
u8 * image = NULL;
|
||||||
|
unsigned int width = 0, height = 0;
|
||||||
|
|
||||||
|
if((lodepng_decode32(&image, &width, &height, (u8*)preview_buffer, size)) == 0) // no error
|
||||||
|
{
|
||||||
|
for(u32 i = 0; i < width; i++)
|
||||||
|
{
|
||||||
|
for(u32 j = 0; j < height; j++)
|
||||||
|
{
|
||||||
|
u32* pixel = (u32*)(image + (i + j*width) * 4);
|
||||||
|
*pixel = __builtin_bswap32(*pixel); //swap from RGBA to ABGR, needed for pp2d
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pp2d_load_texture_memory(TEXTURE_PREVIEW, image, (u32)width, (u32)height);
|
||||||
|
*preview_offset = (width-400)/2;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(image);
|
||||||
|
free(preview_buffer);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
430
source/main.c
430
source/main.c
@@ -25,79 +25,89 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
|
#include "loading.h"
|
||||||
#include "themes.h"
|
#include "themes.h"
|
||||||
#include "splashes.h"
|
#include "splashes.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "common.h"
|
|
||||||
#include "camera.h"
|
#include "camera.h"
|
||||||
|
#include "pp2d/pp2d/pp2d.h"
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
static bool homebrew = false;
|
||||||
int __stacksize__ = 64 * 1024;
|
int __stacksize__ = 64 * 1024;
|
||||||
Result archive_result;
|
Result archive_result;
|
||||||
|
|
||||||
int init_services(void)
|
const char * main_paths[MODE_AMOUNT] = {
|
||||||
|
"/Themes/",
|
||||||
|
"/Splashes/",
|
||||||
|
};
|
||||||
|
|
||||||
|
void init_services(void)
|
||||||
{
|
{
|
||||||
|
consoleDebugInit(debugDevice_SVC);
|
||||||
cfguInit();
|
cfguInit();
|
||||||
ptmuInit();
|
ptmuInit();
|
||||||
acInit();
|
acInit();
|
||||||
httpcInit(0);
|
httpcInit(0);
|
||||||
archive_result = open_archives();
|
archive_result = open_archives();
|
||||||
homebrew = true;
|
if(envIsHomebrew())
|
||||||
if (!envIsHomebrew())
|
|
||||||
{
|
{
|
||||||
homebrew = false;
|
|
||||||
} else {
|
|
||||||
s64 out;
|
s64 out;
|
||||||
svcGetSystemInfo(&out, 0x10000, 0);
|
svcGetSystemInfo(&out, 0x10000, 0);
|
||||||
if (out)
|
homebrew = !out;
|
||||||
{
|
|
||||||
homebrew = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return homebrew;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int exit_services(void)
|
void exit_services(void)
|
||||||
{
|
{
|
||||||
close_archives();
|
close_archives();
|
||||||
cfguExit();
|
cfguExit();
|
||||||
ptmuExit();
|
ptmuExit();
|
||||||
httpcExit();
|
httpcExit();
|
||||||
acExit();
|
acExit();
|
||||||
return 0;
|
}
|
||||||
|
|
||||||
|
void exit_function(void)
|
||||||
|
{
|
||||||
|
if(homebrew)
|
||||||
|
{
|
||||||
|
APT_HardwareResetAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
srvPublishToSubscriber(0x202, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit_screens();
|
||||||
|
exit_services();
|
||||||
|
}
|
||||||
|
|
||||||
|
void change_selected(Entry_List_s * list, int change_value)
|
||||||
|
{
|
||||||
|
list->selected_entry += change_value;
|
||||||
|
if(change_value < 0 && list->selected_entry < 0)
|
||||||
|
list->selected_entry = list->entries_count - 1;
|
||||||
|
else
|
||||||
|
list->selected_entry %= list->entries_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
srand(time(NULL));
|
srand(time(NULL));
|
||||||
bool homebrew = init_services();
|
init_services();
|
||||||
init_screens();
|
init_screens();
|
||||||
|
|
||||||
themes_list = NULL;
|
Entry_List_s lists[MODE_AMOUNT] = {0};
|
||||||
theme_count = 0;
|
|
||||||
Result res = get_themes(&themes_list, &theme_count);
|
for(int i = 0; i < MODE_AMOUNT; i++)
|
||||||
if (R_FAILED(res))
|
load_entries(main_paths[i], &lists[i]);
|
||||||
{
|
|
||||||
//don't need to worry about possible textures (icons, previews), that's freed by pp2d itself
|
EntryMode current_mode = MODE_THEMES;
|
||||||
free(themes_list);
|
|
||||||
themes_list = NULL;
|
|
||||||
}
|
|
||||||
splash_count = 0;
|
|
||||||
splashes_list = NULL;
|
|
||||||
res = get_splashes(&splashes_list, &splash_count);
|
|
||||||
if (R_FAILED(res))
|
|
||||||
{
|
|
||||||
//don't need to worry about possible textures (icons, previews), that's freed by pp2d itself
|
|
||||||
free(splashes_list);
|
|
||||||
splashes_list = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
splash_mode = false;
|
|
||||||
int selected_splash = 0;
|
|
||||||
int selected_theme = 0;
|
|
||||||
int previously_selected = 0;
|
|
||||||
shuffle_theme_count = 0;
|
|
||||||
bool preview_mode = false;
|
bool preview_mode = false;
|
||||||
|
int preview_offset = 0;
|
||||||
|
|
||||||
|
bool qr_mode = false;
|
||||||
|
|
||||||
while(aptMainLoop())
|
while(aptMainLoop())
|
||||||
{
|
{
|
||||||
@@ -105,274 +115,188 @@ int main(void)
|
|||||||
u32 kDown = hidKeysDown();
|
u32 kDown = hidKeysDown();
|
||||||
u32 kHeld = hidKeysHeld();
|
u32 kHeld = hidKeysHeld();
|
||||||
|
|
||||||
if (qr_mode)
|
Entry_List_s * current_list = &lists[current_mode];
|
||||||
{
|
|
||||||
take_picture();
|
|
||||||
} else if (!splash_mode)
|
|
||||||
{
|
|
||||||
draw_theme_interface(themes_list, theme_count, selected_theme, preview_mode, shuffle_theme_count);
|
|
||||||
} else {
|
|
||||||
draw_splash_interface(splashes_list, splash_count, selected_splash, preview_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kDown & KEY_START)
|
if(qr_mode) take_picture();
|
||||||
{
|
else if(preview_mode) draw_preview(preview_offset);
|
||||||
if (homebrew)
|
else draw_interface(current_list, current_mode);
|
||||||
APT_HardwareResetAsync();
|
pp2d_end_draw();
|
||||||
else {
|
|
||||||
srvPublishToSubscriber(0x202, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (kDown & KEY_L)
|
|
||||||
{
|
|
||||||
splash_mode = !splash_mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (R_FAILED(archive_result) && !splash_mode)
|
if(kDown & KEY_START) break;
|
||||||
|
|
||||||
|
if(R_FAILED(archive_result) && current_mode == MODE_THEMES)
|
||||||
{
|
{
|
||||||
throw_error("Theme extdata does not exist\nSet a default theme from the home menu", ERROR);
|
throw_error("Theme extdata does not exist!\nSet a default theme from the home menu.", ERROR_LEVEL_ERROR);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kDown & KEY_R)
|
if(!preview_mode && !qr_mode && kDown & KEY_L) //toggle between splashes and themes
|
||||||
{
|
{
|
||||||
if (preview_mode) {
|
current_mode++;
|
||||||
continue;
|
current_mode %= MODE_AMOUNT;
|
||||||
} else {
|
continue;
|
||||||
u32 out;
|
|
||||||
ACU_GetWifiStatus(&out);
|
|
||||||
if (out)
|
|
||||||
{
|
|
||||||
qr_mode = !qr_mode;
|
|
||||||
if (qr_mode) init_qr();
|
|
||||||
else exit_qr();
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
throw_error("Please connect to Wi-Fi before scanning QR", WARNING);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else if(!preview_mode && kDown & KEY_R) //toggle QR mode
|
||||||
if (qr_mode) continue;
|
|
||||||
|
|
||||||
if (themes_list == NULL && !splash_mode)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (splashes_list == NULL && splash_mode)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Theme_s * current_theme = &themes_list[selected_theme];
|
|
||||||
Splash_s *current_splash = &splashes_list[selected_splash];
|
|
||||||
|
|
||||||
if (kDown & KEY_Y)
|
|
||||||
{
|
{
|
||||||
if (!preview_mode)
|
u32 out;
|
||||||
|
ACU_GetWifiStatus(&out);
|
||||||
|
if(out)
|
||||||
{
|
{
|
||||||
if (!splash_mode)
|
qr_mode = !qr_mode;
|
||||||
{
|
if(qr_mode)
|
||||||
if (!current_theme->has_preview)
|
init_qr();
|
||||||
load_theme_preview(current_theme);
|
else
|
||||||
|
exit_qr();
|
||||||
preview_mode = current_theme->has_preview;
|
|
||||||
} else {
|
|
||||||
load_splash_preview(current_splash);
|
|
||||||
preview_mode = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
throw_error("Please connect to Wi-Fi before scanning QR", ERROR_LEVEL_WARNING);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if(!qr_mode && kDown & KEY_Y) //toggle preview mode
|
||||||
|
{
|
||||||
|
if(!preview_mode)
|
||||||
|
{
|
||||||
|
preview_mode = load_preview(*current_list, &preview_offset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
preview_mode = false;
|
preview_mode = false;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if(qr_mode && kDown & KEY_L) //scan a QR code while in QR mode
|
||||||
|
{
|
||||||
|
CAMU_StopCapture(PORT_BOTH);
|
||||||
|
CAMU_Activate(SELECT_NONE);
|
||||||
|
qr_mode = !scan_qr(current_mode);
|
||||||
|
CAMU_Activate(SELECT_OUT1_OUT2);
|
||||||
|
CAMU_StartCapture(PORT_BOTH);
|
||||||
|
|
||||||
|
if(!qr_mode)
|
||||||
|
{
|
||||||
|
free(current_list->entries);
|
||||||
|
memset(current_list, 0, sizeof(Entry_List_s));
|
||||||
|
load_entries(main_paths[current_mode], current_list);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//don't allow anything while the preview is up
|
if(qr_mode || preview_mode || current_list->entries == NULL)
|
||||||
if (preview_mode)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
int selected_entry = current_list->selected_entry;
|
||||||
|
Entry_s * current_entry = ¤t_list->entries[selected_entry];
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
else if (kDown & KEY_X)
|
if(kDown & KEY_X)
|
||||||
{
|
{
|
||||||
if (splash_mode) {
|
switch(current_mode)
|
||||||
draw_splash_install(UNINSTALL);
|
{
|
||||||
splash_delete();
|
case MODE_THEMES:
|
||||||
} else {
|
draw_install(INSTALL_BGM);
|
||||||
draw_theme_install(BGM_INSTALL);
|
bgm_install(*current_entry);
|
||||||
bgm_install(*current_theme);
|
break;
|
||||||
|
case MODE_SPLASHES:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (kDown & KEY_A)
|
else if(kDown & KEY_A)
|
||||||
{
|
{
|
||||||
if (splash_mode)
|
switch(current_mode)
|
||||||
{
|
{
|
||||||
draw_splash_install(SINGLE_INSTALL);
|
case MODE_THEMES:
|
||||||
splash_install(*current_splash);
|
draw_install(INSTALL_SINGLE);
|
||||||
svcSleepThread(5e8);
|
theme_install(*current_entry);
|
||||||
} else {
|
break;
|
||||||
draw_theme_install(SINGLE_INSTALL);
|
case MODE_SPLASHES:
|
||||||
single_install(*current_theme);
|
draw_install(INSTALL_SPLASH);
|
||||||
|
splash_install(*current_entry);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(kDown & KEY_B)
|
||||||
|
{
|
||||||
|
switch(current_mode)
|
||||||
|
{
|
||||||
|
case MODE_THEMES:
|
||||||
|
if(current_entry->in_shuffle) current_list->shuffle_count--;
|
||||||
|
else current_list->shuffle_count++;
|
||||||
|
current_entry->in_shuffle = !current_entry->in_shuffle;
|
||||||
|
break;
|
||||||
|
case MODE_SPLASHES:
|
||||||
|
draw_install(INSTALL_SPLASH_DELETE);
|
||||||
|
splash_delete();
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
//these are here just so I don't forget how to implement them - HM
|
|
||||||
//if (current_theme->in_shuffle) {
|
|
||||||
// shuffle_theme_count--;
|
|
||||||
// current_theme->in_shuffle = false;
|
|
||||||
//}
|
|
||||||
//del_theme(current_theme->path);
|
|
||||||
//get_themes(&themes_list, &theme_count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (kDown & KEY_B)
|
else if(kDown & KEY_SELECT)
|
||||||
{
|
{
|
||||||
if (splash_mode)
|
switch(current_mode)
|
||||||
{
|
{
|
||||||
|
case MODE_THEMES:
|
||||||
} else {
|
if(current_list->shuffle_count > 0)
|
||||||
if (shuffle_theme_count < 10)
|
{
|
||||||
{
|
draw_install(INSTALL_SHUFFLE);
|
||||||
if (current_theme->in_shuffle) shuffle_theme_count--;
|
shuffle_install(current_list->entries, current_list->entries_count);
|
||||||
else shuffle_theme_count++;
|
current_list->shuffle_count = 0;
|
||||||
current_theme->in_shuffle = !(current_theme->in_shuffle);
|
|
||||||
} else {
|
|
||||||
if (current_theme->in_shuffle) {
|
|
||||||
shuffle_theme_count--;
|
|
||||||
current_theme->in_shuffle = false;
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
}
|
{
|
||||||
}
|
throw_error("You dont have any Shuffle selected.", ERROR_LEVEL_WARNING);
|
||||||
|
}
|
||||||
else if (kDown & KEY_SELECT)
|
break;
|
||||||
{
|
default:
|
||||||
if (splash_mode)
|
break;
|
||||||
{
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (shuffle_theme_count > 0)
|
|
||||||
{
|
|
||||||
draw_theme_install(SHUFFLE_INSTALL);
|
|
||||||
shuffle_install(themes_list, theme_count);
|
|
||||||
shuffle_theme_count = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw_error("You dont have any Shuffle selected.", WARNING);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Movement in the UI
|
// Movement in the UI
|
||||||
else if (kDown & KEY_DOWN)
|
else if(kDown & KEY_UP)
|
||||||
{
|
{
|
||||||
if (splash_mode)
|
change_selected(current_list, -1);
|
||||||
{
|
|
||||||
selected_splash++;
|
|
||||||
if (selected_splash >= splash_count)
|
|
||||||
selected_splash = 0;
|
|
||||||
} else {
|
|
||||||
selected_theme++;
|
|
||||||
if (selected_theme >= theme_count)
|
|
||||||
selected_theme = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (kDown & KEY_UP)
|
else if(kDown & KEY_DOWN)
|
||||||
{
|
{
|
||||||
if (splash_mode)
|
change_selected(current_list, 1);
|
||||||
{
|
|
||||||
selected_splash--;
|
|
||||||
if (selected_splash < 0)
|
|
||||||
selected_splash = splash_count - 1;
|
|
||||||
} else {
|
|
||||||
selected_theme--;
|
|
||||||
if (selected_theme < 0)
|
|
||||||
selected_theme = theme_count - 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Quick moving
|
// Quick moving
|
||||||
else if (kDown & KEY_LEFT)
|
else if(kDown & KEY_LEFT)
|
||||||
{
|
{
|
||||||
if (splash_mode)
|
change_selected(current_list, -ENTRIES_PER_SCREEN);
|
||||||
{
|
|
||||||
selected_splash -= 4;
|
|
||||||
if (selected_splash < 0) selected_splash = 0;
|
|
||||||
} else {
|
|
||||||
selected_theme -= 4;
|
|
||||||
if (selected_theme < 0) selected_theme = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (kDown & KEY_RIGHT)
|
else if(kDown & KEY_RIGHT)
|
||||||
{
|
{
|
||||||
if (splash_mode)
|
change_selected(current_list, ENTRIES_PER_SCREEN);
|
||||||
{
|
|
||||||
selected_splash += 4;
|
|
||||||
if (selected_splash >= splash_count) selected_splash = splash_count-1;
|
|
||||||
} else {
|
|
||||||
selected_theme += 4;
|
|
||||||
if (selected_theme >= theme_count) selected_theme = theme_count-1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fast scroll using circle pad
|
// Fast scroll using circle pad
|
||||||
else if (kHeld & KEY_CPAD_UP)
|
else if(kHeld & KEY_CPAD_UP)
|
||||||
{
|
{
|
||||||
svcSleepThread(100000000);
|
change_selected(current_list, -1);
|
||||||
|
|
||||||
if (splash_mode)
|
|
||||||
{
|
|
||||||
selected_splash--;
|
|
||||||
if (selected_splash < 0)
|
|
||||||
selected_splash = splash_count - 1;
|
|
||||||
} else {
|
|
||||||
selected_theme--;
|
|
||||||
if (selected_theme < 0)
|
|
||||||
selected_theme = theme_count - 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (kHeld & KEY_CPAD_DOWN)
|
else if(kHeld & KEY_CPAD_DOWN)
|
||||||
{
|
{
|
||||||
svcSleepThread(100000000);
|
change_selected(current_list, 1);
|
||||||
|
|
||||||
if (splash_mode)
|
|
||||||
{
|
|
||||||
selected_splash++;
|
|
||||||
if (selected_splash >= splash_count)
|
|
||||||
selected_splash = 0;
|
|
||||||
} else {
|
|
||||||
selected_theme++;
|
|
||||||
if (selected_theme >= theme_count)
|
|
||||||
selected_theme = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (kDown & KEY_CPAD_LEFT)
|
else if(kDown & KEY_CPAD_LEFT)
|
||||||
{
|
{
|
||||||
svcSleepThread(100000000);
|
change_selected(current_list, -ENTRIES_PER_SCREEN);
|
||||||
|
|
||||||
if (splash_mode)
|
|
||||||
{
|
|
||||||
selected_splash -= 4;
|
|
||||||
if (selected_splash < 0) selected_splash = 0;
|
|
||||||
} else {
|
|
||||||
selected_theme -= 4;
|
|
||||||
if (selected_theme < 0) selected_theme = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (kDown & KEY_CPAD_RIGHT)
|
else if(kDown & KEY_CPAD_RIGHT)
|
||||||
{
|
{
|
||||||
svcSleepThread(100000000);
|
change_selected(current_list, ENTRIES_PER_SCREEN);
|
||||||
|
|
||||||
if (splash_mode)
|
|
||||||
{
|
|
||||||
selected_splash += 4;
|
|
||||||
if (selected_splash >= splash_count) selected_splash = splash_count-1;
|
|
||||||
} else {
|
|
||||||
selected_theme += 4;
|
|
||||||
if (selected_theme >= theme_count) selected_theme = theme_count-1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!splash_mode && selected_theme != previously_selected)
|
|
||||||
{
|
|
||||||
current_theme->has_preview = false;
|
|
||||||
previously_selected = selected_theme;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exit_screens();
|
|
||||||
exit_services();
|
exit_function();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,254 +26,34 @@
|
|||||||
#include "splashes.h"
|
#include "splashes.h"
|
||||||
#include "unicode.h"
|
#include "unicode.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "themes.h"
|
|
||||||
#include "pp2d/pp2d/pp2d.h"
|
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
|
|
||||||
void load_splash_preview(Splash_s *splash)
|
void splash_delete(void)
|
||||||
{
|
|
||||||
//free the previously loaded preview. wont do anything if there wasnt one
|
|
||||||
pp2d_free_texture(TEXTURE_PREVIEW);
|
|
||||||
|
|
||||||
char *preview_buffer = NULL;
|
|
||||||
u64 size = 0;
|
|
||||||
if (!(splash->is_zip))
|
|
||||||
{
|
|
||||||
u16 path_to_preview[0x106] = {0};
|
|
||||||
strucat(path_to_preview, splash->path);
|
|
||||||
struacat(path_to_preview, "/preview.png");
|
|
||||||
size = file_to_buf(fsMakePath(PATH_UTF16, path_to_preview), ArchiveSD, &preview_buffer);
|
|
||||||
} else {
|
|
||||||
size = zip_file_to_buf("preview.png", splash->path, &preview_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!size)
|
|
||||||
{
|
|
||||||
free(preview_buffer);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 * image = NULL;
|
|
||||||
unsigned int width = 0, height = 0;
|
|
||||||
|
|
||||||
if ((lodepng_decode32(&image, &width, &height, (u8*)preview_buffer, size)) == 0) // no error
|
|
||||||
{
|
|
||||||
for (u32 i = 0; i < width; i++)
|
|
||||||
{
|
|
||||||
for (u32 j = 0; j < height; j++)
|
|
||||||
{
|
|
||||||
u32 p = (i + j*width) * 4;
|
|
||||||
|
|
||||||
u8 r = *(u8*)(image + p);
|
|
||||||
u8 g = *(u8*)(image + p + 1);
|
|
||||||
u8 b = *(u8*)(image + p + 2);
|
|
||||||
u8 a = *(u8*)(image + p + 3);
|
|
||||||
|
|
||||||
*(image + p) = a;
|
|
||||||
*(image + p + 1) = b;
|
|
||||||
*(image + p + 2) = g;
|
|
||||||
*(image + p + 3) = r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pp2d_load_texture_memory(TEXTURE_PREVIEW, image, (u32)width, (u32)height);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(image);
|
|
||||||
free(preview_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void parse_smdh(Splash_s *splash, ssize_t textureID, u16 *splash_name)
|
|
||||||
{
|
|
||||||
char *info_buffer = NULL;
|
|
||||||
u64 size = 0;
|
|
||||||
if (!(splash->is_zip))
|
|
||||||
{
|
|
||||||
u16 path_to_smdh[0x106] = {0};
|
|
||||||
strucat(path_to_smdh, splash->path);
|
|
||||||
struacat(path_to_smdh, "/info.smdh");
|
|
||||||
|
|
||||||
size = file_to_buf(fsMakePath(PATH_UTF16, path_to_smdh), ArchiveSD, &info_buffer);
|
|
||||||
} else {
|
|
||||||
size = zip_file_to_buf("info.smdh", splash->path, &info_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!size)
|
|
||||||
{
|
|
||||||
free(info_buffer);
|
|
||||||
memset(splash->name, 0, 0x80);
|
|
||||||
memset(splash->desc, 0, 0x100);
|
|
||||||
memset(splash->author, 0, 0x80);
|
|
||||||
memcpy(splash->name, splash_name, 0x80);
|
|
||||||
utf8_to_utf16(splash->desc, (u8*)"No description", 0x100);
|
|
||||||
utf8_to_utf16(splash->author, (u8*)"Unknown author", 0x80);
|
|
||||||
splash->placeholder_color = RGBA8(rand() % 255, rand() % 255, rand() % 255, 255);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(splash->name, info_buffer + 0x08, 0x80);
|
|
||||||
memcpy(splash->desc, info_buffer + 0x88, 0x100);
|
|
||||||
memcpy(splash->author, info_buffer + 0x188, 0x80);
|
|
||||||
|
|
||||||
u16 *icon_data = malloc(0x1200);
|
|
||||||
memcpy(icon_data, info_buffer + 0x24C0, 0x1200);
|
|
||||||
|
|
||||||
const u32 width = 48, height = 48;
|
|
||||||
u32 *image = malloc(width*height*sizeof(u32));
|
|
||||||
|
|
||||||
for (u32 x = 0; x < width; x++)
|
|
||||||
{
|
|
||||||
for (u32 y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
unsigned int dest_pixel = (x + y*width);
|
|
||||||
unsigned int source_pixel = (((y >> 3) * (width >> 3) + (x >> 3)) << 6) + ((x & 1) | ((y & 1) << 1) | ((x & 2) << 1) | ((y & 2) << 2) | ((x & 4) << 2) | ((y & 4) << 3));
|
|
||||||
|
|
||||||
u8 r = ((icon_data[source_pixel] >> 11) & 0b11111) << 3;
|
|
||||||
u8 g = ((icon_data[source_pixel] >> 5) & 0b111111) << 2;
|
|
||||||
u8 b = (icon_data[source_pixel] & 0b11111) << 3;
|
|
||||||
u8 a = 0xFF;
|
|
||||||
|
|
||||||
image[dest_pixel] = (r << 24) | (g << 16) | (b << 8) | a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pp2d_load_texture_memory(textureID, (u8*)image, (u32)width, (u32)height);
|
|
||||||
splash->icon_id = textureID;
|
|
||||||
|
|
||||||
free(image);
|
|
||||||
free(icon_data);
|
|
||||||
free(info_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result get_splashes(Splash_s** splashes_list, int *splash_count)
|
|
||||||
{
|
|
||||||
Result res = 0;
|
|
||||||
Handle dir_handle;
|
|
||||||
|
|
||||||
if (R_FAILED(res = FSUSER_OpenDirectory(&dir_handle, ArchiveSD, fsMakePath(PATH_ASCII, SPLASHES_PATH))))
|
|
||||||
return res;
|
|
||||||
|
|
||||||
if (*splashes_list != NULL)
|
|
||||||
{
|
|
||||||
free(*splashes_list);
|
|
||||||
*splashes_list = NULL;
|
|
||||||
*splash_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 entries_read = 1;
|
|
||||||
while (entries_read)
|
|
||||||
{
|
|
||||||
FS_DirectoryEntry entry = {0};
|
|
||||||
if (R_FAILED(res = FSDIR_Read(dir_handle, &entries_read, 1, &entry)) || entries_read == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!(entry.attributes & FS_ATTRIBUTE_DIRECTORY) && strcmp(entry.shortExt, "ZIP"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
*splash_count += entries_read;
|
|
||||||
*splashes_list= realloc(*splashes_list, (*splash_count) * sizeof(Splash_s));
|
|
||||||
if (splashes_list == NULL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
Splash_s *current_splash = &(*splashes_list)[*splash_count-1];
|
|
||||||
memset(current_splash, 0, sizeof(Splash_s));
|
|
||||||
|
|
||||||
u16 splash_path[0x106]= {0};
|
|
||||||
struacat(splash_path, SPLASHES_PATH);
|
|
||||||
strucat(splash_path, entry.name);
|
|
||||||
|
|
||||||
char pathchar[0x106] = {0};
|
|
||||||
utf16_to_utf8((u8*) pathchar, splash_path, 0x106);
|
|
||||||
|
|
||||||
memcpy(current_splash->path, splash_path, 0x106 * sizeof(u16));
|
|
||||||
current_splash->is_zip = !strcmp(entry.shortExt, "ZIP");
|
|
||||||
|
|
||||||
ssize_t iconID = TEXTURE_PREVIEW + theme_count + *splash_count;
|
|
||||||
parse_smdh(current_splash, iconID, entry.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
FSDIR_Close(dir_handle);
|
|
||||||
|
|
||||||
qsort(*splashes_list, (long)*splash_count, sizeof(Splash_s), splashcmp);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
int splashcmp(const void* a, const void* b) //essentially a memcmp alias, so that it can be used properly with qsort
|
|
||||||
{
|
|
||||||
Splash_s *splash_a = (Splash_s *)a;
|
|
||||||
Splash_s *splash_b = (Splash_s *)b;
|
|
||||||
|
|
||||||
return memcmp(splash_a, splash_b, 0x40*sizeof(u16));
|
|
||||||
}
|
|
||||||
|
|
||||||
void splash_delete()
|
|
||||||
{
|
{
|
||||||
remove("/luma/splash.bin");
|
remove("/luma/splash.bin");
|
||||||
remove("/luma/splashbottom.bin");
|
remove("/luma/splashbottom.bin");
|
||||||
}
|
}
|
||||||
|
|
||||||
void splash_install(Splash_s splash_to_install)
|
void splash_install(Entry_s splash)
|
||||||
{
|
{
|
||||||
char *screen_buf = NULL;
|
char *screen_buf = NULL;
|
||||||
u32 size = 0;
|
|
||||||
if (splash_to_install.is_zip)
|
|
||||||
{
|
|
||||||
size = zip_file_to_buf("splash.bin", splash_to_install.path, &screen_buf);
|
|
||||||
if (size)
|
|
||||||
{
|
|
||||||
remake_file("/luma/splash.bin", ArchiveSD, sizeof(screen_buf));
|
|
||||||
buf_to_file(size, "/luma/splash.bin", ArchiveSD, screen_buf);
|
|
||||||
free(screen_buf);
|
|
||||||
screen_buf = NULL;
|
|
||||||
size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size = zip_file_to_buf("splashbottom.bin", splash_to_install.path, &screen_buf);
|
u32 size = load_data("/splash.bin", splash, &screen_buf);
|
||||||
if (size)
|
remake_file("/luma/splash.bin", ArchiveSD, size);
|
||||||
{
|
buf_to_file(size, "/luma/splash.bin", ArchiveSD, screen_buf);
|
||||||
remake_file("/luma/splashbottom.bin", ArchiveSD, sizeof(screen_buf));
|
|
||||||
buf_to_file(size, "/luma/splashbottom.bin", ArchiveSD, screen_buf);
|
|
||||||
free(screen_buf);
|
|
||||||
screen_buf = NULL;
|
|
||||||
size = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
u16 path[0x106] = {0};
|
|
||||||
memcpy(path, splash_to_install.path, 0x106 * sizeof(u16));
|
|
||||||
struacat(path, "/splash.bin");
|
|
||||||
size = file_to_buf(fsMakePath(PATH_UTF16, path), ArchiveSD, &screen_buf);
|
|
||||||
if (size)
|
|
||||||
{
|
|
||||||
remake_file("/luma/splash.bin", ArchiveSD, sizeof(screen_buf));
|
|
||||||
buf_to_file(size, "/luma/splash.bin", ArchiveSD, screen_buf);
|
|
||||||
free(screen_buf);
|
|
||||||
screen_buf = NULL;
|
|
||||||
size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(path, splash_to_install.path, 0x106 * sizeof(u16));
|
size = load_data("/splashbottom.bin", splash, &screen_buf);
|
||||||
struacat(path, "/splashbottom.bin");
|
remake_file("/luma/splashbottom.bin", ArchiveSD, size);
|
||||||
size = file_to_buf(fsMakePath(PATH_UTF16, path), ArchiveSD, &screen_buf);
|
buf_to_file(size, "/luma/splashbottom.bin", ArchiveSD, screen_buf);
|
||||||
if (size)
|
|
||||||
{
|
|
||||||
remake_file("/luma/splashbottom.bin", ArchiveSD, sizeof(screen_buf));
|
|
||||||
buf_to_file(size, "/luma/splashbottom.bin", ArchiveSD, screen_buf);
|
|
||||||
free(screen_buf);
|
|
||||||
screen_buf = NULL;
|
|
||||||
size = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char *config_buf;
|
char *config_buf;
|
||||||
size = file_to_buf(fsMakePath(PATH_ASCII, "/luma/config.bin"), ArchiveSD, &config_buf);
|
size = file_to_buf(fsMakePath(PATH_ASCII, "/luma/config.bin"), ArchiveSD, &config_buf);
|
||||||
if (size)
|
if(size)
|
||||||
{
|
{
|
||||||
if (config_buf[0xC] == 0)
|
if(config_buf[0xC] == 0)
|
||||||
{
|
{
|
||||||
free(config_buf);
|
free(config_buf);
|
||||||
throw_error("WARNING: Splashes are disabled in Luma Config", WARNING);
|
throw_error("WARNING: Splashes are disabled in Luma Config", ERROR_LEVEL_WARNING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
363
source/themes.c
363
source/themes.c
@@ -27,209 +27,25 @@
|
|||||||
#include "themes.h"
|
#include "themes.h"
|
||||||
#include "unicode.h"
|
#include "unicode.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include <time.h>
|
#include "draw.h"
|
||||||
|
|
||||||
#include "pp2d/pp2d/pp2d.h"
|
#define BGM_MAX_SIZE 3371008
|
||||||
#include "pp2d/pp2d/lodepng.h"
|
|
||||||
|
|
||||||
void load_theme_preview(Theme_s *theme)
|
void delete_theme(Entry_s theme)
|
||||||
{
|
|
||||||
//free the previously loaded preview. wont do anything if there wasnt one
|
|
||||||
pp2d_free_texture(TEXTURE_PREVIEW);
|
|
||||||
|
|
||||||
char *preview_buffer = NULL;
|
|
||||||
u64 size = 0;
|
|
||||||
if (!(theme->is_zip))
|
|
||||||
{
|
|
||||||
u16 path_to_preview[0x106] = {0};
|
|
||||||
strucat(path_to_preview, theme->path);
|
|
||||||
struacat(path_to_preview, "/preview.png");
|
|
||||||
size = file_to_buf(fsMakePath(PATH_UTF16, path_to_preview), ArchiveSD, &preview_buffer);
|
|
||||||
} else {
|
|
||||||
size = zip_file_to_buf("preview.png", theme->path, &preview_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!size)
|
|
||||||
{
|
|
||||||
free(preview_buffer);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 * image = NULL;
|
|
||||||
unsigned int width = 0, height = 0;
|
|
||||||
|
|
||||||
int result = lodepng_decode32(&image, &width, &height, (u8*)preview_buffer, size);
|
|
||||||
if (result == 0) // no error
|
|
||||||
{
|
|
||||||
for (u32 i = 0; i < width; i++)
|
|
||||||
{
|
|
||||||
for (u32 j = 0; j < height; j++)
|
|
||||||
{
|
|
||||||
u32 p = (i + j*width) * 4;
|
|
||||||
|
|
||||||
u8 r = *(u8*)(image + p);
|
|
||||||
u8 g = *(u8*)(image + p + 1);
|
|
||||||
u8 b = *(u8*)(image + p + 2);
|
|
||||||
u8 a = *(u8*)(image + p + 3);
|
|
||||||
|
|
||||||
*(image + p) = a;
|
|
||||||
*(image + p + 1) = b;
|
|
||||||
*(image + p + 2) = g;
|
|
||||||
*(image + p + 3) = r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
theme->has_preview = true;
|
|
||||||
pp2d_load_texture_memory(TEXTURE_PREVIEW, image, (u32)width, (u32)height);
|
|
||||||
theme->preview_offset = (width-400)/2;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(image);
|
|
||||||
free(preview_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void parse_smdh(Theme_s *theme, ssize_t textureID, u16 *dir_name)
|
|
||||||
{
|
|
||||||
char *info_buffer = NULL;
|
|
||||||
u64 size = 0;
|
|
||||||
if (!(theme->is_zip))
|
|
||||||
{
|
|
||||||
u16 path_to_smdh[0x106] = {0};
|
|
||||||
strucat(path_to_smdh, theme->path);
|
|
||||||
struacat(path_to_smdh, "/info.smdh");
|
|
||||||
|
|
||||||
size = file_to_buf(fsMakePath(PATH_UTF16, path_to_smdh), ArchiveSD, &info_buffer);
|
|
||||||
} else {
|
|
||||||
size = zip_file_to_buf("info.smdh", theme->path, &info_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!size)
|
|
||||||
{
|
|
||||||
free(info_buffer);
|
|
||||||
memset(theme->name, 0, 0x80);
|
|
||||||
memset(theme->desc, 0, 0x100);
|
|
||||||
memset(theme->author, 0, 0x80);
|
|
||||||
memcpy(theme->name, dir_name, 0x80);
|
|
||||||
utf8_to_utf16(theme->desc, (u8*)"No description", 0x100);
|
|
||||||
utf8_to_utf16(theme->author, (u8*)"Unknown author", 0x80);
|
|
||||||
theme->placeholder_color = RGBA8(rand() % 255, rand() % 255, rand() % 255, 255);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(theme->name, info_buffer + 0x08, 0x80);
|
|
||||||
memcpy(theme->desc, info_buffer + 0x88, 0x100);
|
|
||||||
memcpy(theme->author, info_buffer + 0x188, 0x80);
|
|
||||||
|
|
||||||
u16 *icon_data = malloc(0x1200);
|
|
||||||
memcpy(icon_data, info_buffer + 0x24C0, 0x1200);
|
|
||||||
|
|
||||||
const u32 width = 48, height = 48;
|
|
||||||
u32 *image = malloc(width*height*sizeof(u32));
|
|
||||||
|
|
||||||
for (u32 x = 0; x < width; x++)
|
|
||||||
{
|
|
||||||
for (u32 y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
unsigned int dest_pixel = (x + y*width);
|
|
||||||
unsigned int source_pixel = (((y >> 3) * (width >> 3) + (x >> 3)) << 6) + ((x & 1) | ((y & 1) << 1) | ((x & 2) << 1) | ((y & 2) << 2) | ((x & 4) << 2) | ((y & 4) << 3));
|
|
||||||
|
|
||||||
u8 r = ((icon_data[source_pixel] >> 11) & 0b11111) << 3;
|
|
||||||
u8 g = ((icon_data[source_pixel] >> 5) & 0b111111) << 2;
|
|
||||||
u8 b = (icon_data[source_pixel] & 0b11111) << 3;
|
|
||||||
u8 a = 0xFF;
|
|
||||||
|
|
||||||
image[dest_pixel] = (r << 24) | (g << 16) | (b << 8) | a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pp2d_load_texture_memory(textureID, (u8*)image, (u32)width, (u32)height);
|
|
||||||
theme->icon_id = textureID;
|
|
||||||
|
|
||||||
free(image);
|
|
||||||
free(icon_data);
|
|
||||||
free(info_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result get_themes(Theme_s **themes_list, int *theme_count)
|
|
||||||
{
|
|
||||||
shuffle_theme_count = 0;
|
|
||||||
Result res = 0;
|
|
||||||
Handle dir_handle;
|
|
||||||
res = FSUSER_OpenDirectory(&dir_handle, ArchiveSD, fsMakePath(PATH_ASCII, THEMES_PATH));
|
|
||||||
if (R_FAILED(res))
|
|
||||||
return res;
|
|
||||||
|
|
||||||
if (*themes_list != NULL) //used for QR reading and also for theme deletion
|
|
||||||
{
|
|
||||||
free(*themes_list);
|
|
||||||
*themes_list = NULL;
|
|
||||||
*theme_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 entries_read = 1;
|
|
||||||
|
|
||||||
while (entries_read)
|
|
||||||
{
|
|
||||||
FS_DirectoryEntry entry = {0};
|
|
||||||
res = FSDIR_Read(dir_handle, &entries_read, 1, &entry);
|
|
||||||
if (R_FAILED(res) || entries_read == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!(entry.attributes & FS_ATTRIBUTE_DIRECTORY) && strcmp(entry.shortExt, "ZIP"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
*theme_count += entries_read;
|
|
||||||
*themes_list = realloc(*themes_list, (*theme_count) * sizeof(Theme_s));
|
|
||||||
if (*themes_list == NULL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
Theme_s* current_theme = &(*themes_list)[*theme_count-1];
|
|
||||||
memset(current_theme, 0, sizeof(Theme_s));
|
|
||||||
|
|
||||||
u16 theme_path[0x106] = {0};
|
|
||||||
struacat(theme_path, THEMES_PATH);
|
|
||||||
strucat(theme_path, entry.name);
|
|
||||||
|
|
||||||
char pathchar[0x106] = {0};
|
|
||||||
utf16_to_utf8((u8*)pathchar, theme_path, 0x106);
|
|
||||||
|
|
||||||
memcpy(current_theme->path, theme_path, 0x106 * sizeof(u16));
|
|
||||||
current_theme->is_zip = !strcmp(entry.shortExt, "ZIP");
|
|
||||||
|
|
||||||
ssize_t iconID = TEXTURE_PREVIEW + *theme_count;
|
|
||||||
parse_smdh(current_theme, iconID, entry.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
FSDIR_Close(dir_handle);
|
|
||||||
|
|
||||||
qsort(*themes_list, (long)*theme_count, sizeof(Theme_s), themecmp); //alphabet sort
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
int themecmp(const void* a, const void* b) //essentially a memcmp alias, so that it can be used properly with qsort
|
|
||||||
{
|
|
||||||
Theme_s *theme_a = (Theme_s *)a;
|
|
||||||
Theme_s *theme_b = (Theme_s *)b;
|
|
||||||
|
|
||||||
return memcmp(theme_a, theme_b, 0x40*sizeof(u16));
|
|
||||||
}
|
|
||||||
|
|
||||||
void del_theme(u16 *path)
|
|
||||||
{
|
{
|
||||||
Handle dir_handle;
|
Handle dir_handle;
|
||||||
Result res = FSUSER_OpenDirectory(&dir_handle, ArchiveSD, fsMakePath(PATH_UTF16, path));
|
Result res = FSUSER_OpenDirectory(&dir_handle, ArchiveSD, fsMakePath(PATH_UTF16, theme.path));
|
||||||
if (R_SUCCEEDED(res))
|
if(R_SUCCEEDED(res))
|
||||||
{
|
{
|
||||||
FSDIR_Close(dir_handle);
|
FSDIR_Close(dir_handle);
|
||||||
FSUSER_DeleteDirectoryRecursively(ArchiveSD, fsMakePath(PATH_UTF16, path));
|
FSUSER_DeleteDirectoryRecursively(ArchiveSD, fsMakePath(PATH_UTF16, theme.path));
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
FSUSER_DeleteFile(ArchiveSD, fsMakePath(PATH_UTF16, path));
|
FSUSER_DeleteFile(ArchiveSD, fsMakePath(PATH_UTF16, theme.path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result bgm_install(Theme_s bgm_to_install)
|
Result bgm_install(Entry_s bgm_to_install)
|
||||||
{
|
{
|
||||||
char *savedata_buf;
|
char *savedata_buf;
|
||||||
char *thememanage_buf;
|
char *thememanage_buf;
|
||||||
@@ -245,31 +61,23 @@ Result bgm_install(Theme_s bgm_to_install)
|
|||||||
Result result = buf_to_file(savedata_size, "/SaveData.dat", ArchiveHomeExt, savedata_buf);
|
Result result = buf_to_file(savedata_size, "/SaveData.dat", ArchiveHomeExt, savedata_buf);
|
||||||
free(savedata_buf);
|
free(savedata_buf);
|
||||||
|
|
||||||
if (!R_SUCCEEDED(result)) return result;
|
if(R_FAILED(result)) return result;
|
||||||
|
|
||||||
if (bgm_to_install.is_zip) // Same as above but this time with bgm
|
music_size = load_data("/bgm.bcstm", bgm_to_install, &music);
|
||||||
{
|
|
||||||
music_size = zip_file_to_buf("bgm.bcstm", bgm_to_install.path, &music);
|
|
||||||
} else {
|
|
||||||
u16 path[0x106] = {0};
|
|
||||||
memcpy(path, bgm_to_install.path, 0x106 * sizeof(u16));
|
|
||||||
struacat(path, "/bgm.bcstm");
|
|
||||||
music_size = file_to_buf(fsMakePath(PATH_UTF16, path), ArchiveSD, &music);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (music_size == 0)
|
if(music_size == 0)
|
||||||
{
|
{
|
||||||
music = calloc(1, 3371008);
|
music = calloc(1, BGM_MAX_SIZE);
|
||||||
} else if (music_size > 3371008) {
|
} else if(music_size > BGM_MAX_SIZE) {
|
||||||
free(music);
|
free(music);
|
||||||
puts("musicrip");
|
puts("musicrip");
|
||||||
return MAKERESULT(RL_PERMANENT, RS_CANCELED, RM_APPLICATION, RD_TOO_LARGE);
|
return MAKERESULT(RL_PERMANENT, RS_CANCELED, RM_APPLICATION, RD_TOO_LARGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = buf_to_file(music_size == 0 ? 3371008 : music_size, "/BgmCache.bin", ArchiveThemeExt, music);
|
result = buf_to_file(music_size == 0 ? BGM_MAX_SIZE : music_size, "/BgmCache.bin", ArchiveThemeExt, music);
|
||||||
free(music);
|
free(music);
|
||||||
|
|
||||||
if (!R_SUCCEEDED(result)) return result;
|
if(R_FAILED(result)) return result;
|
||||||
|
|
||||||
file_to_buf(fsMakePath(PATH_ASCII, "/ThemeManage.bin"), ArchiveThemeExt, &thememanage_buf);
|
file_to_buf(fsMakePath(PATH_ASCII, "/ThemeManage.bin"), ArchiveThemeExt, &thememanage_buf);
|
||||||
thememanage_buf[0x00] = 1;
|
thememanage_buf[0x00] = 1;
|
||||||
@@ -296,23 +104,24 @@ Result bgm_install(Theme_s bgm_to_install)
|
|||||||
result = buf_to_file(0x800, "/ThemeManage.bin", ArchiveThemeExt, thememanage_buf);
|
result = buf_to_file(0x800, "/ThemeManage.bin", ArchiveThemeExt, thememanage_buf);
|
||||||
free(thememanage_buf);
|
free(thememanage_buf);
|
||||||
|
|
||||||
if (!R_SUCCEEDED(result)) return result;
|
if(R_FAILED(result)) return result;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Install a single theme
|
// Install a single theme
|
||||||
Result single_install(Theme_s theme_to_install)
|
Result theme_install(Entry_s theme)
|
||||||
{
|
{
|
||||||
char *body;
|
char *body = NULL;
|
||||||
char *music;
|
char *music = NULL;
|
||||||
char *savedata_buf;
|
char *savedata_buf = NULL;
|
||||||
char *thememanage_buf;
|
char *thememanage_buf = NULL;
|
||||||
u32 body_size;
|
u32 body_size = 0;
|
||||||
u32 music_size;
|
u32 music_size = 0;
|
||||||
u32 savedata_size;
|
u32 savedata_size = 0;
|
||||||
|
|
||||||
savedata_size = file_to_buf(fsMakePath(PATH_ASCII, "/SaveData.dat"), ArchiveHomeExt, &savedata_buf);
|
savedata_size = file_to_buf(fsMakePath(PATH_ASCII, "/SaveData.dat"), ArchiveHomeExt, &savedata_buf);
|
||||||
|
DEBUGPOS("savedata: %p, %lx\n", savedata_buf, savedata_size);
|
||||||
savedata_buf[0x141b] = 0;
|
savedata_buf[0x141b] = 0;
|
||||||
memset(&savedata_buf[0x13b8], 0, 8);
|
memset(&savedata_buf[0x13b8], 0, 8);
|
||||||
savedata_buf[0x13bd] = 3;
|
savedata_buf[0x13bd] = 3;
|
||||||
@@ -320,56 +129,38 @@ Result single_install(Theme_s theme_to_install)
|
|||||||
Result result = buf_to_file(savedata_size, "/SaveData.dat", ArchiveHomeExt, savedata_buf);
|
Result result = buf_to_file(savedata_size, "/SaveData.dat", ArchiveHomeExt, savedata_buf);
|
||||||
free(savedata_buf);
|
free(savedata_buf);
|
||||||
|
|
||||||
if (!R_SUCCEEDED(result)) return result;
|
if(R_FAILED(result)) return result;
|
||||||
|
|
||||||
// Open body cache file. Test if theme is zipped
|
// Open body cache file.
|
||||||
if (theme_to_install.is_zip)
|
body_size = load_data("/body_LZ.bin", theme, &body);
|
||||||
{
|
|
||||||
body_size = zip_file_to_buf("body_LZ.bin", theme_to_install.path, &body);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
u16 path[0x106] = {0};
|
|
||||||
memcpy(path, theme_to_install.path, 0x106 * sizeof(u16));
|
|
||||||
struacat(path, "/body_lz.bin");
|
|
||||||
body_size = file_to_buf(fsMakePath(PATH_UTF16, path), ArchiveSD, &body);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (body_size == 0)
|
if(body_size == 0)
|
||||||
{
|
{
|
||||||
free(body);
|
free(body);
|
||||||
puts("bodyrip");
|
DEBUGPOS("bodyrip");
|
||||||
return MAKERESULT(RL_PERMANENT, RS_CANCELED, RM_APPLICATION, RD_NOT_FOUND);
|
return MAKERESULT(RL_PERMANENT, RS_CANCELED, RM_APPLICATION, RD_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = buf_to_file(body_size, "/BodyCache.bin", ArchiveThemeExt, body); // Write body data to file
|
result = buf_to_file(body_size, "/BodyCache.bin", ArchiveThemeExt, body); // Write body data to file
|
||||||
free(body);
|
free(body);
|
||||||
|
|
||||||
if (!R_SUCCEEDED(result)) return result;
|
if(R_FAILED(result)) return result;
|
||||||
|
|
||||||
if (theme_to_install.is_zip) // Same as above but this time with bgm
|
music_size = load_data("/bgm.bcstm", theme, &music);
|
||||||
{
|
|
||||||
music_size = zip_file_to_buf("bgm.bcstm", theme_to_install.path, &music);
|
|
||||||
} else {
|
|
||||||
u16 path[0x106] = {0};
|
|
||||||
memcpy(path, theme_to_install.path, 0x106 * sizeof(u16));
|
|
||||||
struacat(path, "/bgm.bcstm");
|
|
||||||
music_size = file_to_buf(fsMakePath(PATH_UTF16, path), ArchiveSD, &music);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (music_size == 0)
|
if(music_size == 0)
|
||||||
{
|
{
|
||||||
music = calloc(1, 3371008);
|
music = calloc(1, BGM_MAX_SIZE);
|
||||||
} else if (music_size > 3371008) {
|
} else if(music_size > BGM_MAX_SIZE) {
|
||||||
free(music);
|
free(music);
|
||||||
puts("musicrip");
|
DEBUGPOS("musicrip");
|
||||||
return MAKERESULT(RL_PERMANENT, RS_CANCELED, RM_APPLICATION, RD_TOO_LARGE);
|
return MAKERESULT(RL_PERMANENT, RS_CANCELED, RM_APPLICATION, RD_TOO_LARGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = buf_to_file(music_size == 0 ? 3371008 : music_size, "/BgmCache.bin", ArchiveThemeExt, music);
|
result = buf_to_file(music_size == 0 ? BGM_MAX_SIZE : music_size, "/BgmCache.bin", ArchiveThemeExt, music);
|
||||||
free(music);
|
free(music);
|
||||||
|
|
||||||
if (!R_SUCCEEDED(result)) return result;
|
if(R_FAILED(result)) return result;
|
||||||
|
|
||||||
file_to_buf(fsMakePath(PATH_ASCII, "/ThemeManage.bin"), ArchiveThemeExt, &thememanage_buf);
|
file_to_buf(fsMakePath(PATH_ASCII, "/ThemeManage.bin"), ArchiveThemeExt, &thememanage_buf);
|
||||||
thememanage_buf[0x00] = 1;
|
thememanage_buf[0x00] = 1;
|
||||||
@@ -398,18 +189,18 @@ Result single_install(Theme_s theme_to_install)
|
|||||||
result = buf_to_file(0x800, "/ThemeManage.bin", ArchiveThemeExt, thememanage_buf);
|
result = buf_to_file(0x800, "/ThemeManage.bin", ArchiveThemeExt, thememanage_buf);
|
||||||
free(thememanage_buf);
|
free(thememanage_buf);
|
||||||
|
|
||||||
if (!R_SUCCEEDED(result)) return result;
|
if(R_FAILED(result)) return result;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result shuffle_install(Theme_s *themes_list, int theme_count)
|
Result shuffle_install(Entry_s* themes_list, int themes_count)
|
||||||
{
|
{
|
||||||
u8 count = 0;
|
u8 count = 0;
|
||||||
Theme_s *shuffle_themes[10] = {0};
|
Entry_s *shuffle_themes[10] = {0};
|
||||||
u32 body_sizes[10] = {0};
|
u32 body_sizes[10] = {0};
|
||||||
u32 bgm_sizes[10] = {0};
|
u32 bgm_sizes[10] = {0};
|
||||||
for (int i = 0; i < theme_count; i++)
|
for (int i = 0; i < themes_count; i++)
|
||||||
{
|
{
|
||||||
if (count > 10) return MAKERESULT(RL_USAGE, RS_INVALIDARG, RM_COMMON, RD_INVALID_SELECTION);
|
if (count > 10) return MAKERESULT(RL_USAGE, RS_INVALIDARG, RM_COMMON, RD_INVALID_SELECTION);
|
||||||
if (themes_list[i].in_shuffle)
|
if (themes_list[i].in_shuffle)
|
||||||
@@ -435,10 +226,10 @@ Result shuffle_install(Theme_s *themes_list, int theme_count)
|
|||||||
savedata_buf[0x13bd] = 3;
|
savedata_buf[0x13bd] = 3;
|
||||||
savedata_buf[0x13b8] = 0xff;
|
savedata_buf[0x13b8] = 0xff;
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
for(int i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
memset(&savedata_buf[0x13c0 + 0x8 * i], 0, 8); // clear any existing theme structure. 8 is the length of the theme structure, so 8 * i is the pos of the current one
|
memset(&savedata_buf[0x13c0 + 0x8 * i], 0, 8); // clear any existing theme structure. 8 is the length of the theme structure, so 8 * i is the pos of the current one
|
||||||
if (count > i) // if we are still installing themes...
|
if(count > i) // if we are still installing themes...
|
||||||
{
|
{
|
||||||
savedata_buf[0x13c0 + (8 * i)] = i; // index
|
savedata_buf[0x13c0 + (8 * i)] = i; // index
|
||||||
savedata_buf[0x13c0 + (8 * i) + 5] = 3; // persistence (?)
|
savedata_buf[0x13c0 + (8 * i) + 5] = 3; // persistence (?)
|
||||||
@@ -448,61 +239,39 @@ Result shuffle_install(Theme_s *themes_list, int theme_count)
|
|||||||
Result result = buf_to_file(size, "/SaveData.dat", ArchiveHomeExt, savedata_buf);
|
Result result = buf_to_file(size, "/SaveData.dat", ArchiveHomeExt, savedata_buf);
|
||||||
free(savedata_buf);
|
free(savedata_buf);
|
||||||
|
|
||||||
if (!R_SUCCEEDED(result)) return result;
|
if(R_FAILED(result)) return result;
|
||||||
|
|
||||||
remake_file("/BodyCache_rd.bin", ArchiveThemeExt, 0x150000 * 10); // Enough space for 10 theme files
|
remake_file("/BodyCache_rd.bin", ArchiveThemeExt, 0x150000 * 10); // Enough space for 10 theme files
|
||||||
Handle body_cache_handle;
|
Handle body_cache_handle;
|
||||||
FSUSER_OpenFile(&body_cache_handle, ArchiveThemeExt, fsMakePath(PATH_ASCII, "/BodyCache_rd.bin"), FS_OPEN_WRITE, 0);
|
FSUSER_OpenFile(&body_cache_handle, ArchiveThemeExt, fsMakePath(PATH_ASCII, "/BodyCache_rd.bin"), FS_OPEN_WRITE, 0);
|
||||||
for (int i = 0; i < 10; i++)
|
for(int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
if (count > i)
|
Entry_s * current_theme = shuffle_themes[i];
|
||||||
{
|
char * body_buf = NULL;
|
||||||
if (shuffle_themes[i]->is_zip)
|
u32 body_size = load_data("/body_LZ.bin", *current_theme, &body_buf);
|
||||||
{
|
|
||||||
char *body_buf;
|
body_sizes[i] = body_size;
|
||||||
u32 body_size = zip_file_to_buf("body_LZ.bin", shuffle_themes[i]->path, &body_buf);
|
FSFILE_Write(body_cache_handle, NULL, 0x150000 * i, body_buf, body_size, FS_WRITE_FLUSH);
|
||||||
body_sizes[i] = body_size;
|
free(body_buf);
|
||||||
FSFILE_Write(body_cache_handle, NULL, 0x150000 * i, body_buf, body_size, FS_WRITE_FLUSH);
|
|
||||||
free(body_buf);
|
|
||||||
} else {
|
|
||||||
u16 path[0x106] = {0};
|
|
||||||
strucat(path, shuffle_themes[i]->path);
|
|
||||||
struacat(path, "/body_LZ.bin");
|
|
||||||
char *body_buf;
|
|
||||||
u32 body_size = file_to_buf(fsMakePath(PATH_UTF16, path), ArchiveSD, &body_buf);
|
|
||||||
body_sizes[i] = body_size;
|
|
||||||
FSFILE_Write(body_cache_handle, NULL, 0x150000 * i, body_buf, body_size, FS_WRITE_FLUSH);
|
|
||||||
free(body_buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FSFILE_Close(body_cache_handle);
|
FSFILE_Close(body_cache_handle);
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
for(int i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
char bgm_cache_path[17] = {0};
|
char bgm_cache_path[17] = {0};
|
||||||
sprintf(bgm_cache_path, "/BgmCache_%.2i.bin", i);
|
sprintf(bgm_cache_path, "/BgmCache_%.2i.bin", i);
|
||||||
remake_file(bgm_cache_path, ArchiveThemeExt, 3371008);
|
remake_file(bgm_cache_path, ArchiveThemeExt, BGM_MAX_SIZE);
|
||||||
if (count > i)
|
if(count > i)
|
||||||
{
|
{
|
||||||
char *music_buf;
|
Entry_s * current_theme = shuffle_themes[i];
|
||||||
u32 music_size;
|
char *music_buf = NULL;
|
||||||
|
u32 music_size = music_size = load_data("/bgm.bcstm", *current_theme, &music_buf);
|
||||||
|
|
||||||
if (shuffle_themes[i]->is_zip)
|
if(!music_size)
|
||||||
{
|
{
|
||||||
music_size = zip_file_to_buf("bgm.bcstm", shuffle_themes[i]->path, &music_buf);
|
char *empty = calloc(1, BGM_MAX_SIZE);
|
||||||
} else {
|
buf_to_file(BGM_MAX_SIZE, bgm_cache_path, ArchiveThemeExt, empty);
|
||||||
u16 path[0x106] = {0};
|
|
||||||
strucat(path, shuffle_themes[i]->path);
|
|
||||||
struacat(path, "/bgm.bcstm");
|
|
||||||
music_size = file_to_buf(fsMakePath(PATH_UTF16, path), ArchiveSD, &music_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!music_size)
|
|
||||||
{
|
|
||||||
char *empty = calloc(1, 3371008);
|
|
||||||
buf_to_file(3371008, bgm_cache_path, ArchiveThemeExt, empty);
|
|
||||||
bgm_sizes[i] = 0;
|
bgm_sizes[i] = 0;
|
||||||
free(empty);
|
free(empty);
|
||||||
continue;
|
continue;
|
||||||
@@ -511,8 +280,8 @@ Result shuffle_install(Theme_s *themes_list, int theme_count)
|
|||||||
buf_to_file(music_size, bgm_cache_path, ArchiveThemeExt, music_buf);
|
buf_to_file(music_size, bgm_cache_path, ArchiveThemeExt, music_buf);
|
||||||
free(music_buf);
|
free(music_buf);
|
||||||
} else {
|
} else {
|
||||||
char *empty = calloc(1, 3371008);
|
char *empty = calloc(1, BGM_MAX_SIZE);
|
||||||
buf_to_file(3371008, bgm_cache_path, ArchiveThemeExt, empty);
|
buf_to_file(BGM_MAX_SIZE, bgm_cache_path, ArchiveThemeExt, empty);
|
||||||
bgm_sizes[i] = 0;
|
bgm_sizes[i] = 0;
|
||||||
free(empty);
|
free(empty);
|
||||||
}
|
}
|
||||||
@@ -538,7 +307,7 @@ Result shuffle_install(Theme_s *themes_list, int theme_count)
|
|||||||
*bodysizeloc = (u32) 0;
|
*bodysizeloc = (u32) 0;
|
||||||
*bgmsizeloc = (u32) 0;
|
*bgmsizeloc = (u32) 0;
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
for(int i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
bodysizeloc = (u32*) (&thememanage_buf[0x338 + (4 * i)]); // body size info for shuffle themes starts at 0x338 and is 4 bytes for each theme
|
bodysizeloc = (u32*) (&thememanage_buf[0x338 + (4 * i)]); // body size info for shuffle themes starts at 0x338 and is 4 bytes for each theme
|
||||||
bgmsizeloc = (u32*) (&thememanage_buf[0x360 + (4 * i)]); // same thing for bgm but starting at 0x360
|
bgmsizeloc = (u32*) (&thememanage_buf[0x360 + (4 * i)]); // same thing for bgm but starting at 0x360
|
||||||
@@ -549,7 +318,7 @@ Result shuffle_install(Theme_s *themes_list, int theme_count)
|
|||||||
result = buf_to_file(0x800, "/ThemeManage.bin", ArchiveThemeExt, thememanage_buf);
|
result = buf_to_file(0x800, "/ThemeManage.bin", ArchiveThemeExt, thememanage_buf);
|
||||||
free(thememanage_buf);
|
free(thememanage_buf);
|
||||||
|
|
||||||
if (!R_SUCCEEDED(result)) return result;
|
if(R_FAILED(result)) return result;
|
||||||
|
|
||||||
return MAKERESULT(RL_SUCCESS, RS_SUCCESS, RM_COMMON, RD_SUCCESS);
|
return MAKERESULT(RL_SUCCESS, RS_SUCCESS, RM_COMMON, RD_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user