From ebd2a9d6ae16e842c442c4cdfc55c586c2bbc427 Mon Sep 17 00:00:00 2001 From: LiquidFenrir Date: Thu, 31 Aug 2017 13:55:00 +0200 Subject: [PATCH] Several improvements (#9) * fix icon filename * update pp2d to fix preview problem * several improvements: - rely on a single header for simple/common headers - cleaned up main by putting the interface drawing function in its own file - load previews from .zip themes (may cause some loading times when launching - only need 1 shuffle image thanks to pp2d's blending abilities * not needed anymore * fix preview color and position * forgot * add proper icon loading thanks steveice10 for bannertool which this was pretty much taken from * only add proper themes to the list * add slightly more space between the icon and the name * not monospace, the little movement every blink is annoying * fix typo --- include/common.h | 47 +++++ include/draw.h | 37 ++++ include/fs.h | 5 +- include/themes.h | 33 ++-- include/unicode.h | 2 +- meta/{logo.png => icon.png} | Bin romfs/{shuffle_white.png => shuffle.png} | Bin romfs/shuffle_black.png | Bin 443 -> 0 bytes source/draw.c | 219 +++++++++++++++++++++++ source/fs.c | 27 +-- source/main.c | 197 +++++++------------- source/pp2d | 2 +- source/themes.c | 195 ++++++++++++++------ source/unicode.c | 5 - 14 files changed, 537 insertions(+), 232 deletions(-) create mode 100644 include/common.h create mode 100644 include/draw.h rename meta/{logo.png => icon.png} (100%) rename romfs/{shuffle_white.png => shuffle.png} (100%) delete mode 100644 romfs/shuffle_black.png create mode 100644 source/draw.c diff --git a/include/common.h b/include/common.h new file mode 100644 index 0000000..c7682a5 --- /dev/null +++ b/include/common.h @@ -0,0 +1,47 @@ +/* +* 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 . +* +* 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 COMMON_H +#define COMMON_H + +#include <3ds.h> + +#include +#include +#include + +#define THEMES_PATH "/Themes/" + +static const int THEMES_PER_SCREEN = 4; + +enum TextureID { + TEXTURE_FONT_RESERVED = 0, //used by pp2d for the font + TEXTURE_ARROW, + TEXTURE_SHUFFLE, + MAX_TEXTURE, +}; + +#endif \ No newline at end of file diff --git a/include/draw.h b/include/draw.h new file mode 100644 index 0000000..696b3e6 --- /dev/null +++ b/include/draw.h @@ -0,0 +1,37 @@ +/* +* 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 . +* +* 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 DRAW_H +#define DRAW_H + +#include "themes.h" + +void init_screens(void); +void exit_screens(void); + +void draw_interface(Theme_s * themes_list, int theme_count, int selected_theme, bool preview_mode); + +#endif \ No newline at end of file diff --git a/include/fs.h b/include/fs.h index d3fd713..c1dfc60 100644 --- a/include/fs.h +++ b/include/fs.h @@ -27,7 +27,7 @@ #ifndef FS_H #define FS_H -#include <3ds.h> +#include "common.h" FS_Archive ArchiveSD; FS_Archive ArchiveHomeExt; @@ -35,9 +35,10 @@ FS_Archive ArchiveThemeExt; Result open_archives(void); Result close_archives(void); -int get_number_entries(char*); + u64 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 buf_to_file(u32 size, char *path, FS_Archive archive, char *buf); void remake_file(char *path, FS_Archive archive, u32 size); diff --git a/include/themes.h b/include/themes.h index 99a8a89..1fb41b8 100644 --- a/include/themes.h +++ b/include/themes.h @@ -27,26 +27,27 @@ #ifndef THEMES_H #define THEMES_H -#include <3ds.h> - -#define TEX_COUNT 3 +#include "common.h" typedef struct { - u16 name[0x40]; - u16 desc[0x80]; - u16 author[0x40]; - char icon_data[0x1200]; + u16 name[0x80]; + u16 desc[0x100]; + u16 author[0x80]; + + bool has_icon; + ssize_t icon_id; + + bool has_preview; + ssize_t preview_id; + u16 path[262]; bool is_zip; - bool selected; - ssize_t preview_id; - bool has_preview; - char preview_path[0x106]; -} theme; + + bool in_shuffle; +} Theme_s; -void parse_smdh(theme *entry, u16 *path); -int scan_themes(theme **themes, int num_themes); -Result single_install(theme); -Result shuffle_install(theme **themes_list, int num_themes); +Result get_themes(Theme_s **themes_list, int *theme_count); +Result single_install(Theme_s theme); +Result shuffle_install(Theme_s *themes_list, int theme_count); #endif \ No newline at end of file diff --git a/include/unicode.h b/include/unicode.h index 34d7e0d..56971e4 100644 --- a/include/unicode.h +++ b/include/unicode.h @@ -27,7 +27,7 @@ #ifndef UNICODE_H #define UNICODE_H -#include <3ds.h> +#include "common.h" ssize_t strulen(u16*, ssize_t); void struacat(u16 *input, const char *addition); diff --git a/meta/logo.png b/meta/icon.png similarity index 100% rename from meta/logo.png rename to meta/icon.png diff --git a/romfs/shuffle_white.png b/romfs/shuffle.png similarity index 100% rename from romfs/shuffle_white.png rename to romfs/shuffle.png diff --git a/romfs/shuffle_black.png b/romfs/shuffle_black.png deleted file mode 100644 index 45ce30c11c5f76dde9472d11f76c98ecb8e576b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 443 zcmV;s0Yv_ZP)YzO3zeNn%Hana`vXTpl%C8%T@ zwgU1u%;C;2G-1==H;nBBYX-mJ;t&BNiD-z1OD7J zXcXrOK1lc. +* +* 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 "draw.h" + +#include "pp2d/pp2d/pp2d.h" + +#include + +enum Colors { + COLOR_BACKGROUND = ABGR8(255, 32, 28, 35), //silver-y black + COLOR_ACCENT = RGBA8(55, 122, 168, 255), + COLOR_WHITE = RGBA8(255, 255, 255, 255), + COLOR_CURSOR = RGBA8(200, 200, 200, 255), + COLOR_BLACK = RGBA8(0, 0, 0, 255), +}; + +void init_screens(void) +{ + pp2d_init(); + + pp2d_set_screen_color(GFX_TOP, COLOR_BACKGROUND); + pp2d_set_screen_color(GFX_BOTTOM, COLOR_BACKGROUND); + + pp2d_load_texture_png(TEXTURE_ARROW, "romfs:/arrow.png"); + pp2d_load_texture_png(TEXTURE_SHUFFLE, "romfs:/shuffle.png"); +} + +void exit_screens(void) +{ + pp2d_exit(); +} + +static Result MCUHWC_GetBatteryLevel(u8 *out) // Code taken from daedreth's fork of lpp-3ds +{ + #define TRY(expr) if(R_FAILED(res = (expr))) { svcCloseHandle(mcuhwcHandle); return res; } + Result res; + Handle mcuhwcHandle; + TRY(srvGetServiceHandle(&mcuhwcHandle, "mcu::HWC")); + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x50000; + TRY(svcSendSyncRequest(mcuhwcHandle)); + *out = (u8) cmdbuf[2]; + svcCloseHandle(mcuhwcHandle); + return cmdbuf[1]; + #undef TRY +} + +static int vertical_scroll = 0; + +// static const int FRAMES_FOR_TEXT_SCROLL = 40; +// static int frames_count = 0; +// static int horizontal_scroll = 0; +// static int previous_selected = 0; +// static int horizontal_scroll_change = 1; + +void draw_interface(Theme_s * themes_list, int theme_count, int selected_theme, bool preview_mode) +{ + pp2d_begin_draw(GFX_TOP); + + if (themes_list == NULL) + { + pp2d_draw_text_center(GFX_TOP, 100, 1, 1, COLOR_WHITE, "FAILURE"); + pp2d_end_draw(); + return; + } + + Theme_s current_theme = themes_list[selected_theme]; + + if (preview_mode) + { + if (current_theme.has_preview) + { + pp2d_draw_texture_part(current_theme.preview_id, 0, 0, 6, 0, 400, 240); + } + } + else + { + pp2d_draw_rectangle(0, 0, 400, 23, COLOR_ACCENT); + pp2d_draw_text_center(GFX_TOP, 4, 0.5, 0.5, COLOR_WHITE, "Theme mode"); + wchar_t title[0x80] = {0}; + utf16_to_utf32((u32*)title, current_theme.name, 0x80); + pp2d_draw_wtext(20, 30, 0.7, 0.7, COLOR_WHITE, title); + + time_t t = time(NULL); + struct tm tm = *localtime(&t); + + 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_textf(34, 2, 0.6, 0.6, COLOR_WHITE, "%.2i", tm.tm_min); + + u8 battery_val = 0; + MCUHWC_GetBatteryLevel(&battery_val); + pp2d_draw_textf(350, 2, 0.6, 0.6, COLOR_WHITE, "%i%%", battery_val); + + if (current_theme.has_preview) + { + //skip the weird 6 pixels to the left + pp2d_texture_select_part(current_theme.preview_id, 220, 35, 6, 0, 400, 480); + pp2d_texture_scale(0.4, 0.4); + pp2d_texture_draw(); + } + } + + pp2d_draw_on(GFX_BOTTOM); + + if (preview_mode) + { + if (current_theme.has_preview) + { + pp2d_draw_texture_part(current_theme.preview_id, 0, 0, 46, 240, 320, 240); + } + } + else + { + /* + // Scroll the theme name if it's too large + //---------------------------------------------------------------- + if (previous_selected != selected_theme) { + previous_selected = selected_theme; + frames_count = 0; + horizontal_scroll = 0; + horizontal_scroll_change = 1; + } + + frames_count = (frames_count+1) % FRAMES_FOR_TEXT_SCROLL; + + if (frames_count == 0 && (config.entries[selectedEntry].name.size() > MENU_WIDTH)) + horizontal_scroll += horizontal_scroll_change; + + if (horizontal_scroll == (config.entries[selected_theme].name.size() - MENU_WIDTH)) + horizontal_scroll_change = -1; + + if (horizontal_scroll == 0) + horizontal_scroll_change = 1; + //---------------------------------------------------------------- + */ + + // 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 (vertical_scroll > selected_theme) + vertical_scroll--; + + if ((i < selected_theme) && \ + ((selected_theme - vertical_scroll) >= THEMES_PER_SCREEN) && \ + (vertical_scroll != ( - THEMES_PER_SCREEN))) + vertical_scroll++; + } + //---------------------------------------------------------------- + + // Show arrows if there are themes out of bounds + //---------------------------------------------------------------- + pp2d_draw_rectangle(0, 0, 320, 24, COLOR_ACCENT); + pp2d_draw_rectangle(0, 216, 320, 24, COLOR_ACCENT); + if (vertical_scroll > 0) + { + pp2d_draw_texture(TEXTURE_ARROW, 155, 6); + } + if (theme_count - vertical_scroll > THEMES_PER_SCREEN) + { + pp2d_draw_texture_flip(TEXTURE_ARROW, 155, 224, VERTICAL); + } + //---------------------------------------------------------------- + + for (int i = vertical_scroll; i < (THEMES_PER_SCREEN + 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-vertical_scroll); + u32 front_color = COLOR_WHITE; + + if (i == selected_theme) + { + front_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, front_color, name); + if (current_theme.has_icon) + pp2d_draw_texture(current_theme.icon_id, 0, 24 + vertical_offset); + + if (current_theme.in_shuffle) + pp2d_draw_texture_blend(TEXTURE_SHUFFLE, 280, 32 + vertical_offset, front_color); + } + } + + pp2d_end_draw(); +} diff --git a/source/fs.c b/source/fs.c index d0eb121..ffaa8b1 100644 --- a/source/fs.c +++ b/source/fs.c @@ -24,12 +24,9 @@ * reasonable ways as different from the original version. */ -#include <3ds.h> -#include -#include - #include "fs.h" #include "unicode.h" + #include "minizip/unzip.h" Result open_archives(void) @@ -80,6 +77,7 @@ Result open_archives(void) theme.data = themePath; retValue = FSUSER_OpenArchive(&ArchiveThemeExt, ARCHIVE_EXTDATA, theme); if(R_FAILED(retValue)) return retValue; + romfsInit(); return 0; } @@ -98,27 +96,6 @@ Result close_archives(void) return 0; } -int get_number_entries(char *path) -{ - int count = 0; - Handle dir_handle; - Result res = FSUSER_OpenDirectory(&dir_handle, ArchiveSD, fsMakePath(PATH_ASCII, path)); - if (R_FAILED(res)) return -1; - - bool done = false; - while (!done) - { - FS_DirectoryEntry *entry = malloc(sizeof(FS_DirectoryEntry)); - u32 entries_read = 0; - FSDIR_Read(dir_handle, &entries_read, 1, entry); - free(entry); - if (entries_read) count++; - else if (!entries_read) break; - } - FSDIR_Close(dir_handle); - return count; -} - u64 file_to_buf(FS_Path path, FS_Archive archive, char** buf) { Handle file; diff --git a/source/main.c b/source/main.c index a2940fa..195e71f 100644 --- a/source/main.c +++ b/source/main.c @@ -24,183 +24,116 @@ * reasonable ways as different from the original version. */ -#include -#include -#include <3ds.h> -#include -#include - -#include "pp2d/pp2d/pp2d.h" #include "fs.h" #include "themes.h" -#include "unicode.h" - -#define TEXTURE_ARROW 1 -#define TEXTURE_SHUFFLE_BLACK 2 -#define TEXTURE_SHUFFLE_WHITE 3 -#define MAX_THEMES 4 +#include "draw.h" int init_services(void) { cfguInit(); - srvInit(); - hidInit(); - fsInit(); - ptmSysmInit(); open_archives(); - pp2d_init(); - pp2d_set_screen_color(GFX_TOP, ABGR8(255, 32, 28, 35)); - pp2d_set_screen_color(GFX_BOTTOM, ABGR8(255, 32, 28, 35)); - pp2d_load_texture_png(TEXTURE_ARROW, "romfs:/arrow.png"); - pp2d_load_texture_png(TEXTURE_SHUFFLE_BLACK, "romfs:/shuffle_black.png"); - pp2d_load_texture_png(TEXTURE_SHUFFLE_WHITE, "romfs:/shuffle_white.png"); return 0; } -int de_init_services(void) +int exit_services(void) { - gfxExit(); - cfguExit(); - srvExit(); - hidExit(); - fsExit(); - ptmSysmExit(); close_archives(); + cfguExit(); return 0; } -void format_time(char *time_string) -{ - time_t t = time(NULL); - struct tm tm = *localtime(&t); - sprintf(time_string, "%s%.2i:%.2i", time_string, tm.tm_hour, tm.tm_min); -} - -Result MCUHWC_GetBatteryLevel(u8 *out) // Code taken from daedreth's fork of lpp-3ds -{ - #define TRY(expr) if(R_FAILED(res = (expr))) { svcCloseHandle(mcuhwcHandle); return res; } - Result res; - Handle mcuhwcHandle; - TRY(srvGetServiceHandle(&mcuhwcHandle, "mcu::HWC")); - u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = 0x50000; - TRY(svcSendSyncRequest(mcuhwcHandle)); - *out = (u8) cmdbuf[2]; - svcCloseHandle(mcuhwcHandle); - return cmdbuf[1]; - #undef TRY -} - int main(void) { init_services(); - - int theme_count = get_number_entries("/Themes"); - theme **themes_list = calloc(theme_count, sizeof(theme)); - scan_themes(themes_list, theme_count); - - u32 color_accent = RGBA8(55, 122, 168, 255); - u32 color_white = RGBA8(255, 255, 255, 255); - u32 cursor_color = RGBA8(200, 200, 200, 255); - u32 color_black = RGBA8(0, 0, 0, 255); - - int cursor_pos = 1; - int top_pos = 0; + init_screens(); + + int theme_count = 0; + Theme_s * themes_list = NULL; + Result res = get_themes(&themes_list, &theme_count); + + int selected_theme = 0; + bool preview_mode = false; while(aptMainLoop()) { - theme *current_theme = themes_list[cursor_pos + top_pos - 1]; hidScanInput(); u32 kDown = hidKeysDown(); - - pp2d_begin_draw(GFX_TOP); - pp2d_draw_rectangle(0, 0, 400, 23, color_accent); - pp2d_draw_text_center(GFX_TOP, 4, 0.5, 0.5, color_white, "Theme mode"); - - wchar_t title[0x40] = {0}; - utf16_to_utf32((u32*)title, current_theme->name, 0x40); - pp2d_draw_wtext(20, 30, 0.7, 0.7, color_white, title); - - if (current_theme->has_preview) - { - pp2d_draw_texture_scale(current_theme->preview_id, 220, 35, 0.4, 0.4); - } - char time_string[6] = {0}; - format_time(time_string); - pp2d_draw_text(7, 2, 0.6, 0.6, color_white, time_string); - - u8 battery_val; - MCUHWC_GetBatteryLevel(&battery_val); - pp2d_draw_textf(350, 2, 0.6, 0.6, color_white, "%i%%", battery_val); - - pp2d_draw_on(GFX_BOTTOM); - pp2d_draw_rectangle(0, 0, 320, 24, color_accent); - pp2d_draw_rectangle(0, 216, 320, 24, color_accent); - pp2d_draw_rectangle(0, 24 + (48 * (cursor_pos-1)), 320, 48, cursor_color); + draw_interface(themes_list, theme_count, selected_theme, preview_mode); - if (top_pos > 0) + if (kDown & KEY_START) + break; //quit + + if (themes_list == NULL) + continue; + + Theme_s * current_theme = &themes_list[selected_theme]; + + if (kDown & KEY_Y) { - pp2d_draw_texture(TEXTURE_ARROW, 155, 6); - } - - if (top_pos + MAX_THEMES < theme_count) - { - pp2d_draw_texture_flip(TEXTURE_ARROW, 155, 224, VERTICAL); - } - - for (int i = 0; i < MAX_THEMES; i++) - { - if (i + top_pos == theme_count) break; - wchar_t name[0x40] = {0}; - utf16_to_utf32((u32*)name, themes_list[i+top_pos]->name, 0x40); - if (cursor_pos-1 == i) pp2d_draw_wtext(50, 40 + (48 * i), 0.55, 0.55, color_black, name); - else pp2d_draw_wtext(50, 40 + (48 * i), 0.55, 0.55, color_white, name); - if (themes_list[i+top_pos]->selected) + if (!preview_mode) { - if (cursor_pos-1 == i) pp2d_draw_texture(TEXTURE_SHUFFLE_BLACK, 280, 32 + (48 * i)); - else pp2d_draw_texture(TEXTURE_SHUFFLE_WHITE, 280, 32 + (48 * i)); + if (current_theme->has_preview) + preview_mode = true; } + else + preview_mode = false; } - if (kDown & KEY_A) + //don't allow anything while the preview is up + if (preview_mode) + continue; + + // Actions + else if (kDown & KEY_X) + { + // install_bgm(current_theme); + } + else if (kDown & KEY_A) { single_install(*current_theme); } - - if (kDown & KEY_B) + else if (kDown & KEY_B) { - current_theme->selected = !(current_theme->selected); + current_theme->in_shuffle = !(current_theme->in_shuffle); } - - if (kDown & KEY_SELECT) + else if (kDown & KEY_SELECT) { shuffle_install(themes_list, theme_count); } - if (kDown & KEY_DOWN) + // Movement in the UI + else if (kDown & KEY_DOWN) { - if (cursor_pos < MAX_THEMES && cursor_pos < theme_count) cursor_pos++; - else if (cursor_pos + top_pos < theme_count) top_pos++; + selected_theme++; + if (selected_theme >= theme_count) + selected_theme = theme_count-1; } - - if (kDown & KEY_UP) + else if (kDown & KEY_UP) { - if (cursor_pos > 1) cursor_pos--; - else if (top_pos > 0) top_pos--; + selected_theme--; + if (selected_theme < 0) + selected_theme = 0; } - - if (kDown & KEY_START) + // Quick moving + else if (kDown & KEY_LEFT) { - // close_archives(); - // PTMSYSM_ShutdownAsync(0); - // ptmSysmExit(); - break; + selected_theme = 0; + } + else if (kDown & KEY_RIGHT) + { + selected_theme = theme_count-1; } - - pp2d_end_draw(); } - - de_init_services(); + + free(themes_list); + + exit_screens(); + exit_services(); + + ptmSysmInit(); + PTMSYSM_ShutdownAsync(0); + ptmSysmExit(); + return 0; } diff --git a/source/pp2d b/source/pp2d index 8da5af2..cb235fa 160000 --- a/source/pp2d +++ b/source/pp2d @@ -1 +1 @@ -Subproject commit 8da5af2efbf2705b64c2f79ce2ba0e61c7ce5f57 +Subproject commit cb235fa83b87c63f7f943cd497b2a877b5d506be diff --git a/source/themes.c b/source/themes.c index 0639680..03a23ea 100644 --- a/source/themes.c +++ b/source/themes.c @@ -24,25 +24,23 @@ * reasonable ways as different from the original version. */ -#include <3ds.h> -#include -#include -#include - #include "themes.h" #include "unicode.h" #include "fs.h" -#include "pp2d/pp2d/pp2d.h" -void parse_smdh(theme *entry, u16 *path) +#include "pp2d/pp2d/pp2d.h" +#include "pp2d/pp2d/lodepng.h" + +static void parse_smdh(Theme_s *theme, u16 *path, ssize_t textureID) { - char *info_buffer; + char *info_buffer = NULL; u64 size = 0; - if (!(entry->is_zip)) + if (!(theme->is_zip)) { u16 path_to_smdh[0x106] = {0}; strucat(path_to_smdh, 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", path, &info_buffer); @@ -50,52 +48,147 @@ void parse_smdh(theme *entry, u16 *path) if (!size) { + free(info_buffer); return; } - memcpy(entry->name, info_buffer + 0x08, 0x80); - memcpy(entry->desc, info_buffer + 0x88, 0x100); - memcpy(entry->author, info_buffer + 0x188, 0x80); - memcpy(entry->icon_data, info_buffer + 0x2040, 0x1200); + 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; + } + } + + theme->has_icon = true; + pp2d_load_texture_memory(textureID, (u8*)image, (u32)width, (u32)height); + theme->icon_id = textureID; + + free(image); + free(icon_data); free(info_buffer); } -int scan_themes(theme **themes, int num_themes) +static void load_preview(Theme_s *theme, u16 *path, ssize_t textureID) { - Handle dir_handle; - FSUSER_OpenDirectory(&dir_handle, ArchiveSD, fsMakePath(PATH_ASCII, "/Themes")); - for (int i = 0; i < num_themes; i++) + char *preview_buffer = NULL; + u64 size = 0; + if (!(theme->is_zip)) { - FS_DirectoryEntry *entry = malloc(sizeof(FS_DirectoryEntry)); - FSDIR_Read(dir_handle, NULL, 1, entry); - theme *theme_info = malloc(sizeof(theme)); - u16 theme_path[0x106] = {0}; - struacat(theme_path, "/Themes/"); - strucat(theme_path, entry->name); - if (!strcmp(entry->shortExt, "ZIP")) - { - theme_info->is_zip = true; - theme_info->has_preview = false; - } else { - theme_info->is_zip = false; - char u8_path[0x106] = {0}; - utf16_to_utf8((u8*)u8_path, theme_path, 0x106); - strcat(u8_path, "/Preview.png"); - strcpy(theme_info->preview_path, u8_path); - pp2d_load_texture_png(TEX_COUNT + 1 + i, u8_path); - theme_info->preview_id = TEX_COUNT + 1 + i; - theme_info->has_preview = true; - } - parse_smdh(theme_info, theme_path); - memcpy(theme_info->path, theme_path, 0x106 * sizeof(u16)); - themes[i] = theme_info; - free(entry); + u16 path_to_preview[0x106] = {0}; + strucat(path_to_preview, 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", path, &preview_buffer); } - return 0; + + 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(textureID, image, (u32)width, (u32)height); + theme->preview_id = textureID; + } + + free(image); + free(preview_buffer); +} + +Result get_themes(Theme_s **themes_list, int *theme_count) +{ + Result res = 0; + Handle dir_handle; + res = FSUSER_OpenDirectory(&dir_handle, ArchiveSD, fsMakePath(PATH_ASCII, THEMES_PATH)); + if (R_FAILED(res)) + return res; + + 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 textureID = MAX_TEXTURE + (*theme_count * 2); + parse_smdh(current_theme, theme_path, textureID); + load_preview(current_theme, theme_path, textureID+1); + } + + FSDIR_Close(dir_handle); + + return res; } // Install a single theme -Result single_install(theme theme_to_install) +Result single_install(Theme_s theme_to_install) { char *body; char *music; @@ -120,7 +213,9 @@ Result single_install(theme theme_to_install) if (theme_to_install.is_zip) { body_size = zip_file_to_buf("body_LZ.bin", theme_to_install.path, &body); - } else { + } + else + { u16 path[0x106] = {0}; memcpy(path, theme_to_install.path, 0x106 * sizeof(u16)); struacat(path, "/body_lz.bin"); @@ -198,18 +293,18 @@ Result single_install(theme theme_to_install) return 0; } -Result shuffle_install(theme **themes_list, int num_themes) +Result shuffle_install(Theme_s *themes_list, int theme_count) { u8 count = 0; - theme *shuffle_themes[10] = {0}; + Theme_s *shuffle_themes[10] = {0}; u32 body_sizes[10] = {0}; u32 bgm_sizes[10] = {0}; - for (int i = 0; i < num_themes; i++) + for (int i = 0; i < theme_count; i++) { if (count > 9) return MAKERESULT(RL_USAGE, RS_INVALIDARG, RM_COMMON, RD_INVALID_SELECTION); - if (themes_list[i]->selected) + if (themes_list[i].in_shuffle) { - shuffle_themes[count++] = themes_list[i]; + shuffle_themes[count++] = &themes_list[i]; } } for (int i = 0; i < count; i++) @@ -274,7 +369,7 @@ Result shuffle_install(theme **themes_list, int num_themes) for (int i = 0; i < 10; i++) { char bgm_cache_path[17] = {0}; - sprintf(bgm_cache_path, "/BgmCache_0%i.bin", i); + sprintf(bgm_cache_path, "/BgmCache_%.2i.bin", i); remake_file(bgm_cache_path, ArchiveThemeExt, 3371008); if (count > i) { diff --git a/source/unicode.c b/source/unicode.c index b8f83c1..2e7798e 100644 --- a/source/unicode.c +++ b/source/unicode.c @@ -24,11 +24,6 @@ * reasonable ways as different from the original version. */ -#include -#include <3ds.h> -#include -#include - #include "unicode.h" ssize_t strulen(u16 *input, ssize_t max_len)