14 Commits

Author SHA1 Message Date
LiquidFenrir
8022ed1682 add bgm preview to the themeplaza browser
and prevent some errors
2018-05-10 13:53:51 +02:00
5520ec2b2f Move load_audio into loading.c for consistency 2018-05-10 07:40:28 -04:00
f2aa7420df Add support for zip BGM preview 2018-05-10 06:49:03 -04:00
05b56b1aa1 Add BGM Preview Functionality
Some code adapted from Themely. Thanks to ErmanSayin
2018-05-09 22:26:39 -04:00
LiquidFenrir
cac2450fde fix copy-paste error 2018-05-09 00:22:34 +02:00
Alex Taber
1c24d08eef restore shuffle install speed back to roughly 30 seconds (#156) 2018-05-08 18:17:14 -04:00
Alex Taber
24b12023ca always 0-pad stuff (#155) 2018-05-08 16:39:22 -04:00
FrozenChen
9ccc705046 Make uncompressed logo smaller because of home menu bug (#150)
Closes #146
2018-04-15 21:17:31 -04:00
95d8808a73 Copyright Update
* Replaced contributors section in README with CONTRIBUTORS.md
* Updated copyright notice to include all contributors
* Updated SMDH
2018-04-10 16:09:10 -04:00
LiquidFenrir
6c2f09147f Themeplaza caching (#147)
* change fs to use a FS_Path argument for remake_file and buf_to_file

* more debug information when downloading

* browser caching v1: poc, works and is fast but not ideal

* add preview to cache

* this wasnt meant to be added now
2018-04-10 15:12:37 -04:00
LiquidFenrir
7b1d6f9860 implement L and R as extra menus instead of extra keys for X (#148)
L is now the sorting menu
R is unused
2018-04-09 19:28:37 -04:00
LiquidFenrir
6f7c2489d5 Different sorting modes (#143) (#145) 2018-04-04 22:04:45 +02:00
LiquidFenrir
38e70df17b Forgot to update the bottom screen when there's no entry (fix #144) 2018-04-04 11:40:38 +02:00
Helloman892
ad6117404f updated readme to fit: dkP updates, buildtools updates, library changes, lexigraphical errors 2018-04-03 23:48:47 +01:00
27 changed files with 655 additions and 193 deletions

18
CONTRIBUTORS.md Normal file
View File

@@ -0,0 +1,18 @@
# Main Contributors
* Alex Taber ([@astronautlevel2](https://github.com/astronautlevel2))
* [@LiquidFenrir](https://github.com/LiquidFenrir)
* Dawid Eckert ([@daedreth](https://github.com/daedreth))
* Dylan G. ([@helloman892](https://github.com/helloman892))
* Nils P. ([@ZetaDesigns](https://github.com/ZetaDesigns))
* Matt Kenny ([@mattkenster](https://github.com/mattkenster))
# Minor Contributors
* Nic ([@Wizzrobes](https://github.com/Wizzrobes))
* [@saibotu](https://github.com/saibotu)
* Jeremy Postelnek ([@TurtleP](https://github.com/TurtleP))
* [@FrozenChen](https://github.com/FrozenChen)
* Luís Marques ([@luigoalma](https://github.com/luigoalma))
* [@uyuiyu](https://github.com/uyuiyu)
* Guillaume Gérard ([@GreatWizard](https://github.com/GreatWizard))
* Joel ([@joel16](https://github.com/joel16))
* [@thedax](https://github.com/thedax)

View File

@@ -12,7 +12,7 @@ include $(DEVKITARM)/3ds_rules
# Your values.
APP_TITLE := Anemone3DS
APP_DESCRIPTION := A complete theming tool for the 3DS
APP_AUTHOR := astronautlevel and daedreth
APP_AUTHOR := Anemone3DS Team
TARGET := $(subst $e ,_,$(notdir $(APP_TITLE)))
@@ -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/-/')
CFLAGS += $(INCLUDE) -DARM11 -D_3DS -D_GNU_SOURCE -DVERSION="\"$(revision)\"" -DUSER_AGENT="\"$(APP_TITLE)/$(revision)\""
CFLAGS += $(INCLUDE) -DARM11 -D_3DS -D_GNU_SOURCE -DVERSION="\"$(revision)\"" -DUSER_AGENT="\"$(APP_TITLE)/$(revision)\"" -DAPP_TITLE="\"$(APP_TITLE)\""
ifneq ($(strip $(CITRA_MODE)),)
CFLAGS += -DCITRA_MODE
endif
@@ -65,7 +65,7 @@ CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LIBS := -larchive -ljansson -lcitro3d -lctrud -lm -lz
LIBS := -lvorbisidec -logg -larchive -ljansson -lcitro3d -lctrud -lm -lz
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing

View File

@@ -4,31 +4,34 @@ A Theme and Splashscreen Manager for the Nintendo 3DS, written in C.\
To-do list here: https://trello.com/b/F1YSa1VK
# Dependencies
* zlib, jansson, and libarchive, which can be retrieved from the [3ds_portlibs](https://github.com/devkitPro/3ds_portlibs).
* devkitPro, which can be installed following the instructions [here](https://devkitpro.org/wiki/Getting_Started).
* zlib, jansson, and libarchive, which can be retrieved from [devkitPro pacman](https://devkitpro.org/viewtopic.php?f=13&t=8702).
* A recent build of [makerom](https://github.com/profi200/Project_CTR) and the latest release of [bannertool](https://github.com/Steveice10/bannertool). These must be added to your PATH.
A 64-bit Windows binary of makerom is available [here](https://hm892.s-ul.eu/U0Irkqih).
* ~~[pp2d](https://github.com/BernardoGiordano/pp2d), which is included in the repo if you do a git clone --recursive.~~
Due to circumstances surrounding the privacy settings on the pp2d repo, the source files are now included directly within the repo.
* Git needs to be on your PATH (this is usually only manual under Windows).
* [makerom](https://github.com/profi200/Project_CTR) and [bannertool](https://github.com/Steveice10/buildtools), which can be retrieved from [SteveIce10's](https://github.com/Steveice10) buildtools repo. These must be added to your PATH.
* ~~[pp2d](https://github.com/BernardoGiordano/pp2d), which is included in the repo if you do a git clone --recursive.~~ Due to circumstances surrounding the privacy settings on the pp2d repo, the source files are now included directly within the repo.
* Git needs to be on your PATH, if building in a non-*nix environment.
# Building
First of all, make sure devkitPRO is properly installed and added to the PATH.
After that, open the directory you want to clone the repo into, and type: `git clone https://github.com/astronautlevel2/Anemone3DS/ --recursive`.
Instructions for installing zlib, jansson and libarchive can be found on the [3ds_portlibs repo](https://github.com/devkitPro/3ds_portlibs) (its easy, just run `make` and `make install-zlib`). After also adding [makerom](https://github.com/profi200/Project_CTR) and [bannertool](https://github.com/Steveice10/buildtools) to your PATH, just enter your directory and run `make`. All built files will be in `/out/`.
First of all, make sure devkitPro is properly installed and added to your PATH.
After that, open the directory you want to clone the repo into, and execute
`git clone https://github.com/astronautlevel2/Anemone3DS` (or any other cloning method).
To install zlib, jansson and libarchive, begin by following the instructions found above ([here](https://devkitpro.org/viewtopic.php?f=13&t=8702)) on the devkitPro forums, and then install the dkP packages `3ds-zlib`, `3ds-jansson` and `3ds-libarchive`.
After also adding [makerom](https://github.com/profi200/Project_CTR) and [bannertool](https://github.com/Steveice10/buildtools) to your PATH, just enter your directory and run `make`. All built files will be in `/out/`.
# License
This project is licensed under the GNU GPLv3. See LICENSE.md for details. Additional terms 7b and 7c apply to this project.
# Credits
The following people contributed to Anemone3DS in some way. Without these people, Anemone3DS wouldn't exist, or wouldn't be as good as it is:
* [Daedreth](https://github.com/daedreth), who wrote the initial implementation of theme installation code and SMDH parsing.
* [LiquidFenrir](https://github.com/LiquidFenrir), who refactored a lot of my messy code and has been essential in development.
* [Kenn (mattkenster)](https://github.com/mattkenster), for designing the GUI, a number of sprites used in the application, and drawing the banner and icon.
The following people contributed to Anemone3DS in some way. Without these people, Anemone3DS wouldn't exist, or wouldn't be as good as it is: [CONTRIBUTORS.md](CONTRIBUTORS.md)
Special thanks go to these people who, while not directly contributing, helped immensely:
Special thanks go to these people who, whilst not directly contributing, helped immensely:
* [Rinnegatamante](https://github.com/Rinnegatamante), whose code served as reference on theme installation.
* [SteveIce10](https://github.com/SteveIce10), whose QR code in FBI was essential.
* [BernardoGiordano](https://github.com/BernardoGiordano) for making pp2d, and being super responsive to feature requests and just general help.
* [yellows8](https://github.com/yellows8) for his home menu extdump tool, which was invaluable in debugging.
* the folks on #dev of Nintendo Homebrew, who helped with unicode shenanigans (especially [Stary2001](https://github.com/Stary2001), [Fenrir](https://github.com/FenrirWolf), and DanielKO).
* the maintainers for all used libraries, including ctrulib, zlib, citro3d, pp2d, quirc and minizip.
* the maintainers for all used libraries, including but not limited to ctrulib, zlib, citro3d, pp2d, and quirc.
* all the people who helped keep me going and motivated me to work. This includes, but is definitely not limited to:
+ The members of the [Nintendo Homebrew Discord](https://discord.gg/C29hYvh)

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Anemone3DS
* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth")
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
*
* 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

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Anemone3DS
* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth")
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
*
* 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

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Anemone3DS
* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth")
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
*
* 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
@@ -62,6 +62,7 @@ enum TextureID {
TEXTURE_SHUFFLE,
TEXTURE_INSTALLED,
TEXTURE_PREVIEW_ICON,
TEXTURE_SORT,
TEXTURE_DOWNLOAD,
TEXTURE_BROWSE,
TEXTURE_LIST,

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Anemone3DS
* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth")
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
*
* 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
@@ -51,6 +51,7 @@ typedef enum {
INSTALL_LOADING_REMOTE_THEMES,
INSTALL_LOADING_REMOTE_SPLASHES,
INSTALL_LOADING_REMOTE_PREVIEW,
INSTALL_LOADING_REMOTE_BGM,
INSTALL_NONE,
} InstallType;

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Anemone3DS
* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth")
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
*
* 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
@@ -40,7 +40,7 @@ u32 file_to_buf(FS_Path path, FS_Archive archive, char** buf);
u32 zip_memory_to_buf(char *file_name, void * zip_memory, size_t zip_size, 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);
void remake_file(char *path, FS_Archive archive, u32 size);
Result buf_to_file(u32 size, FS_Path path, FS_Archive archive, char *buf);
void remake_file(FS_Path path, FS_Archive archive, u32 size);
#endif

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Anemone3DS
* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth")
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
*
* 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
@@ -98,27 +98,51 @@ Instructions_s install_instructions = {
}
};
Instructions_s extra_instructions = {
.info_line = L"Release \uE002 to cancel or hold \uE006 and release \uE002 to do stuff",
.info_line_color = COLOR_WHITE,
.instructions = {
{
L"\uE079 Jump in the list",
L"\uE07A Reload broken icons"
},
{
L"\uE07B Browse ThemePlaza",
NULL
},
{
NULL,
NULL
},
{
L"Exit",
NULL
Instructions_s extra_instructions[3] = {
{
.info_line = L"Release \uE002 to cancel or hold \uE006 and release \uE002 to sort",
.info_line_color = COLOR_WHITE,
.instructions = {
{
L"\uE079 Sort by name",
L"\uE07A Sort by author"
},
{
L"\uE07B Sort by filename",
NULL
},
{
NULL,
NULL
},
{
L"Exit",
NULL
}
}
}
},
{
.info_line = L"Release \uE002 to cancel or hold \uE006 and release \uE002 to do stuff",
.info_line_color = COLOR_WHITE,
.instructions = {
{
L"\uE079 Jump in the list",
L"\uE07A Reload broken icons"
},
{
L"\uE07B Browse ThemePlaza",
NULL,
},
{
L"\uE004 Sorting menu",
NULL
},
{
L"Exit",
NULL
}
}
},
};
#endif

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Anemone3DS
* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth")
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
*
* 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
@@ -28,6 +28,7 @@
#define LOADING_H
#include "common.h"
#include "music.h"
#include <jansson.h>
enum ICON_IDS_OFFSET {
@@ -38,6 +39,14 @@ enum ICON_IDS_OFFSET {
ICONS_OFFSET_AMOUNT,
};
typedef enum {
SORT_NONE,
SORT_NAME,
SORT_AUTHOR,
SORT_PATH,
} SortMode;
typedef struct {
u8 _padding1[4 + 2 + 2];
@@ -88,6 +97,8 @@ typedef struct {
int entries_loaded;
int entry_size;
SortMode current_sort;
json_int_t tp_current_page;
json_int_t tp_page_count;
char * tp_search;
@@ -98,9 +109,14 @@ typedef struct {
volatile bool run_thread;
} Thread_Arg_s;
void sort_by_name(Entry_List_s * list);
void sort_by_author(Entry_List_s * list);
void sort_by_filename(Entry_List_s * list);
void delete_entry(Entry_s * entry, bool is_file);
Result load_entries(const char * loading_path, Entry_List_s * list);
bool load_preview(Entry_List_s list, int * preview_offset);
Result load_audio(Entry_s, audio_s *);
void load_icons_first(Entry_List_s * current_list, bool silent);
void handle_scrolling(Entry_List_s * list);
void load_icons_thread(void * void_arg);

52
include/music.h Normal file
View File

@@ -0,0 +1,52 @@
/*
* This file is part of Anemone3DS
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
*
* 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 MUSIC_H
#define MUSIC_H
#include "common.h"
#include "fs.h"
#include "unicode.h"
#include <tremor/ivorbisfile.h>
#include <tremor/ivorbiscodec.h>
#define BUF_TO_READ 40960 // How much data should be buffered at a time
typedef struct {
OggVorbis_File vf;
ndspWaveBuf wave_buf[2];
float mix[12];
u8 buf_pos;
long data_read;
volatile bool stop;
char *filebuf;
u32 filesize;
} audio_s;
void play_audio(audio_s *);
#endif

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Anemone3DS
* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth")
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
*
* 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
@@ -41,15 +41,13 @@
#define THEMEPLAZA_JSON_ERROR_MESSAGE_NOT_FOUND "No items found"
#define THEMEPLAZA_ENTRY_FORMAT THEMEPLAZA_BASE_API_URL "/query?item_id=%" JSON_INTEGER_FORMAT
#define THEMEPLAZA_JSON_ENTRY_NAME "title"
#define THEMEPLAZA_JSON_ENTRY_DESC "description"
#define THEMEPLAZA_JSON_ENTRY_AUTH "author"
#define THEMEPLAZA_DOWNLOAD_FORMAT THEMEPLAZA_BASE_URL "/download/%" JSON_INTEGER_FORMAT
#define THEMEPLAZA_PREVIEW_FORMAT THEMEPLAZA_DOWNLOAD_FORMAT "/preview"
#define THEMEPLAZA_BGM_FORMAT THEMEPLAZA_DOWNLOAD_FORMAT "/bgm"
#define THEMEPLAZA_ICON_FORMAT THEMEPLAZA_DOWNLOAD_FORMAT "/preview/icon"
#define THEMEPLAZA_SMDH_FORMAT THEMEPLAZA_DOWNLOAD_FORMAT "/smdh"
#define CACHE_PATH_FORMAT "/3ds/" APP_TITLE "/cache/%" JSON_INTEGER_FORMAT
bool themeplaza_browser(EntryMode mode);
u32 http_get(const char *url, char ** filename, char ** buf);

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Anemone3DS
* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth")
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
*
* 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

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Anemone3DS
* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth")
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
*
* 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

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Anemone3DS
* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth")
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
*
* 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

Binary file not shown.

BIN
romfs/sort.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 B

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Anemone3DS
* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth")
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
*
* 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
@@ -255,8 +255,8 @@ void update_qr(qr_data *data)
if (extension == NULL || strcmp(extension, ".zip"))
strcat(path_to_file, ".zip");
remake_file(path_to_file, ArchiveSD, zip_size);
buf_to_file(zip_size, path_to_file, ArchiveSD, zip_buf);
remake_file(fsMakePath(PATH_ASCII, path_to_file), ArchiveSD, zip_size);
buf_to_file(zip_size, fsMakePath(PATH_ASCII, path_to_file), ArchiveSD, zip_buf);
data->success = true;
}
else

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Anemone3DS
* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth")
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
*
* 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
@@ -43,8 +43,9 @@ void init_screens(void)
pp2d_load_texture_png(TEXTURE_ARROW_SIDE, "romfs:/arrow_side.png");
pp2d_load_texture_png(TEXTURE_SHUFFLE, "romfs:/shuffle.png");
pp2d_load_texture_png(TEXTURE_INSTALLED, "romfs:/installed.png");
pp2d_load_texture_png(TEXTURE_DOWNLOAD, "romfs:/download.png");
pp2d_load_texture_png(TEXTURE_PREVIEW_ICON, "romfs:/preview.png");
pp2d_load_texture_png(TEXTURE_SORT, "romfs:/sort.png");
pp2d_load_texture_png(TEXTURE_DOWNLOAD, "romfs:/download.png");
pp2d_load_texture_png(TEXTURE_BROWSE, "romfs:/browse.png");
pp2d_load_texture_png(TEXTURE_LIST, "romfs:/list.png");
pp2d_load_texture_png(TEXTURE_EXIT, "romfs:/exit.png");
@@ -203,6 +204,9 @@ void draw_install(InstallType type)
case INSTALL_LOADING_REMOTE_PREVIEW:
pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Downloading preview, please wait...");
break;
case INSTALL_LOADING_REMOTE_BGM:
pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Downloading BGM, please wait...");
break;
case INSTALL_SINGLE:
pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Installing a single theme...");
break;
@@ -408,10 +412,12 @@ void draw_interface(Entry_List_s* list, Instructions_s instructions)
pp2d_draw_on(GFX_BOTTOM, GFX_LEFT);
pp2d_draw_texture_blend(TEXTURE_EXIT, 320-120, 0, COLOR_WHITE);
pp2d_draw_texture_blend(TEXTURE_DOWNLOAD, 320-96, 0, COLOR_WHITE);
for(int i = 0; i < MODE_AMOUNT; i++)
pp2d_draw_textf(320-(24*(i+1))+2.5, -3, 1, 1, COLOR_WHITE, "%c", mode_string[i][0]);
pp2d_draw_texture_blend(TEXTURE_SORT, 320-144, 0, COLOR_WHITE);
pp2d_draw_texture_blend(TEXTURE_DOWNLOAD, 320-120, 0, COLOR_WHITE);
pp2d_draw_texture_blend(TEXTURE_BROWSE, 320-96, 0, COLOR_WHITE);
pp2d_draw_texture_blend(TEXTURE_EXIT, 320-72, 0, COLOR_WHITE);
pp2d_draw_texture_blend(TEXTURE_PREVIEW_ICON, 320-48, 0, COLOR_WHITE);
pp2d_draw_textf(320-24+2.5, -3, 1, 1, COLOR_WHITE, "%c", mode_string[!list->mode][0]);
return;
}
@@ -433,6 +439,7 @@ void draw_interface(Entry_List_s* list, Instructions_s instructions)
break;
}
pp2d_draw_texture_blend(TEXTURE_SORT, 320-144, 0, COLOR_WHITE);
pp2d_draw_texture_blend(TEXTURE_DOWNLOAD, 320-120, 0, COLOR_WHITE);
pp2d_draw_texture_blend(TEXTURE_BROWSE, 320-96, 0, COLOR_WHITE);
pp2d_draw_texture_blend(TEXTURE_EXIT, 320-72, 0, COLOR_WHITE);

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Anemone3DS
* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth")
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
*
* 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
@@ -68,6 +68,9 @@ Result open_archives(void)
FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_ASCII, "/Themes"), FS_ATTRIBUTE_DIRECTORY);
FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_ASCII, "/Splashes"), FS_ATTRIBUTE_DIRECTORY);
FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_ASCII, "/3ds"), FS_ATTRIBUTE_DIRECTORY);
FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_ASCII, "/3ds/" APP_TITLE), FS_ATTRIBUTE_DIRECTORY);
FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_ASCII, "/3ds/" APP_TITLE "/cache"), FS_ATTRIBUTE_DIRECTORY);
u32 homeMenuPath[3] = {MEDIATYPE_SD, archive2, 0};
home.type = PATH_BINARY;
@@ -178,23 +181,23 @@ u32 zip_file_to_buf(char *file_name, u16 *zip_path, char **buf)
return zip_to_buf(a, file_name, buf);
}
Result buf_to_file(u32 size, char *path, FS_Archive archive, char *buf)
Result buf_to_file(u32 size, FS_Path path, FS_Archive archive, char *buf)
{
Handle handle;
Result res = 0;
if (R_FAILED(res = FSUSER_OpenFile(&handle, archive, fsMakePath(PATH_ASCII, path), FS_OPEN_WRITE, 0))) return res;
if (R_FAILED(res = FSUSER_OpenFile(&handle, archive, path, FS_OPEN_WRITE, 0))) return res;
if (R_FAILED(res = FSFILE_Write(handle, NULL, 0, buf, size, FS_WRITE_FLUSH))) return res;
if (R_FAILED(res = FSFILE_Close(handle))) return res;
return 0;
}
void remake_file(char *path, FS_Archive archive, u32 size)
void remake_file(FS_Path path, FS_Archive archive, u32 size)
{
Handle handle;
if (R_SUCCEEDED(FSUSER_OpenFile(&handle, archive, fsMakePath(PATH_ASCII, path), FS_OPEN_READ, 0)))
if (R_SUCCEEDED(FSUSER_OpenFile(&handle, archive, path, FS_OPEN_READ, 0)))
{
FSFILE_Close(handle);
FSUSER_DeleteFile(archive, fsMakePath(PATH_ASCII, path));
FSUSER_DeleteFile(archive, path);
}
FSUSER_CreateFile(archive, fsMakePath(PATH_ASCII, path), 0, size);
FSUSER_CreateFile(archive, path, 0, size);
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Anemone3DS
* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth")
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
*
* 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
@@ -28,6 +28,7 @@
#include "pp2d/pp2d/pp2d.h"
#include "fs.h"
#include "unicode.h"
#include "music.h"
#include "draw.h"
void delete_entry(Entry_s * entry, bool is_file)
@@ -104,20 +105,51 @@ static void load_smdh_icon(Entry_s entry, const ssize_t textureID)
free(image);
}
static int compare_entries(const void * a, const void * b)
typedef int (*sort_comparator)(const void *, const void *);
static int compare_entries_by_name(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)
static int compare_entries_by_author(const void * a, const void * b)
{
if(list->entries != NULL)
Entry_s *entry_a = (Entry_s *)a;
Entry_s *entry_b = (Entry_s *)b;
return memcmp(entry_a->author, entry_b->author, 0x40*sizeof(u16));
}
static int compare_entries_by_filename(const void * a, const void * b)
{
Entry_s *entry_a = (Entry_s *)a;
Entry_s *entry_b = (Entry_s *)b;
return memcmp(entry_a->path, entry_b->path, 0x106*sizeof(u16));
}
static void sort_list(Entry_List_s * list, sort_comparator compare_entries)
{
if(list->entries != NULL && list->entries != NULL)
qsort(list->entries, list->entries_count, sizeof(Entry_s), compare_entries); //alphabet sort
}
void sort_by_name(Entry_List_s * list)
{
sort_list(list, compare_entries_by_name);
list->current_sort = SORT_NAME;
}
void sort_by_author(Entry_List_s * list)
{
sort_list(list, compare_entries_by_author);
list->current_sort = SORT_AUTHOR;
}
void sort_by_filename(Entry_List_s * list)
{
sort_list(list, compare_entries_by_filename);
list->current_sort = SORT_PATH;
}
Result load_entries(const char * loading_path, Entry_List_s * list)
{
Handle dir_handle;
@@ -165,8 +197,6 @@ Result load_entries(const char * loading_path, Entry_List_s * list)
FSDIR_Close(dir_handle);
sort_list(list);
return res;
}
@@ -429,3 +459,44 @@ bool load_preview(Entry_List_s list, int * preview_offset)
return ret;
}
// Initialize the audio struct
Result load_audio(Entry_s entry, audio_s *audio)
{
audio->filesize = load_data("/bgm.ogg", entry, &audio->filebuf);
audio->mix[0] = audio->mix[1] = 1.0f; // Determines volume for the 12 (?) different outputs. See http://smealum.github.io/ctrulib/channel_8h.html#a30eb26f1972cc3ec28370263796c0444
ndspChnSetInterp(0, NDSP_INTERP_LINEAR);
ndspChnSetRate(0, 44100);
ndspChnSetFormat(0, NDSP_FORMAT_STEREO_PCM16); // Tremor outputs ogg files in 16 bit PCM stereo
ndspChnSetMix(0, audio->mix); // See mix comment above
FILE *file = fmemopen(audio->filebuf, audio->filesize, "rb");
if(file != NULL)
{
int e = ov_open(file, &audio->vf, NULL, 0);
if (e < 0)
{
char error[50];
sprintf(error, "Vorbis: %d\n", e);
DEBUG(error);
return MAKERESULT(RL_FATAL, RS_INVALIDARG, RM_APPLICATION, RD_NO_DATA);
}
vorbis_info *vi = ov_info(&audio->vf, -1);
ndspChnSetRate(0, vi->rate);// Set sample rate to what's read from the ogg file
audio->wave_buf[0].nsamples = audio->wave_buf[1].nsamples = vi->rate / 4; // 4 bytes per sample, samples = rate (bytes) / 4
audio->wave_buf[0].status = audio->wave_buf[1].status = NDSP_WBUF_DONE; // Used in play to stop from writing to current buffer
audio->wave_buf[0].data_vaddr = linearAlloc(BUF_TO_READ); // Most vorbis packets should only be 4 KB at most (?) Possibly dangerous assumption
audio->wave_buf[1].data_vaddr = linearAlloc(BUF_TO_READ);
DEBUG("Success!");
return MAKERESULT(RL_SUCCESS, RS_SUCCESS, RM_APPLICATION, RD_SUCCESS);
} else {
free(audio->filebuf);
free(audio);
DEBUG("File not found!\n");
return MAKERESULT(RL_FATAL, RS_NOTFOUND, RM_APPLICATION, RD_NOT_FOUND);
}
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Anemone3DS
* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth")
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
*
* 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
@@ -30,12 +30,14 @@
#include "splashes.h"
#include "draw.h"
#include "camera.h"
#include "music.h"
#include "remote.h"
#include "instructions.h"
#include "pp2d/pp2d/pp2d.h"
#include <time.h>
bool quit = false;
audio_s * audio;
static bool homebrew = false;
static bool installed_themes = false;
@@ -75,6 +77,7 @@ static void init_services(void)
cfguInit();
ptmuInit();
acInit();
ndspInit();
APT_GetAppCpuTimeLimit(&old_time_limit);
APT_SetAppCpuTimeLimit(30);
httpcInit(0);
@@ -95,6 +98,7 @@ static void exit_services(void)
if (old_time_limit != UINT32_MAX) APT_SetAppCpuTimeLimit(old_time_limit);
httpcExit();
acExit();
ndspExit();
}
static void stop_install_check(void)
@@ -187,6 +191,8 @@ static void load_lists(Entry_List_s * lists)
if(current_list->entries_count > current_list->entries_loaded*ICONS_OFFSET_AMOUNT)
iconLoadingThread_arg.run_thread = true;
sort_by_name(current_list);
DEBUG("total: %i\n", current_list->entries_count);
current_list->texture_id_offset = texture_id_offset;
@@ -345,10 +351,25 @@ int main(void)
if(install_mode)
instructions = install_instructions;
if(extra_mode)
instructions = extra_instructions;
{
int index = 1;
bool key_l = (kDown | kHeld) & KEY_L;
bool key_r = (kDown | kHeld) & KEY_R;
if(key_l ^ key_r)
{
if(key_l)
index = 0;
// else if(key_r) // uncomment when we use the right menu. we don't for now
// index = 2;
}
instructions = extra_instructions[index];
}
if(qr_mode) take_picture();
else if(preview_mode) draw_preview(TEXTURE_PREVIEW, preview_offset);
else if(preview_mode)
{
draw_preview(TEXTURE_PREVIEW, preview_offset);
}
else {
if(!iconLoadingThread_arg.run_thread)
{
@@ -412,14 +433,28 @@ int main(void)
{
toggle_preview:
if(!preview_mode)
{
preview_mode = load_preview(*current_list, &preview_offset);
if(current_mode == MODE_THEMES)
{
audio = calloc(1, sizeof(audio_s));
load_audio(current_list->entries[current_list->selected_entry], audio);
play_audio(audio);
}
}
else
{
preview_mode = false;
if(current_mode == MODE_THEMES && audio)
audio->stop = true;
}
continue;
}
else if(preview_mode && kDown & (KEY_B | KEY_TOUCH))
{
preview_mode = false;
if(current_mode == MODE_THEMES && audio)
audio->stop = true;
continue;
}
}
@@ -525,28 +560,50 @@ int main(void)
extra_mode = false;
if(!extra_mode)
{
if((kDown | kHeld) & KEY_DLEFT)
bool key_l = (kDown | kHeld) & KEY_L;
bool key_r = (kDown | kHeld) & KEY_R;
if(!(key_l ^ key_r))
{
browse_themeplaza:
if(themeplaza_browser(current_mode))
if((kDown | kHeld) & KEY_DLEFT)
{
current_mode = MODE_THEMES;
load_lists(lists);
browse_themeplaza:
if(themeplaza_browser(current_mode))
{
current_mode = MODE_THEMES;
load_lists(lists);
}
}
else if((kDown | kHeld) & KEY_DUP)
{
jump:
jump_menu(current_list);
}
else if((kDown | kHeld) & KEY_DDOWN)
{
load_icons_first(current_list, false);
}
}
else if((kDown | kHeld) & KEY_DUP)
else if(key_l)
{
jump:
jump_menu(current_list);
}
else if((kDown | kHeld) & KEY_DRIGHT)
{
}
else if((kDown | kHeld) & KEY_DDOWN)
{
load_icons_first(current_list, false);
if((kDown | kHeld) & KEY_DLEFT)
{
sort_path:
sort_by_filename(current_list);
load_icons_first(current_list, false);
}
else if(((kDown | kHeld)) & KEY_DUP)
{
sort_name:
sort_by_name(current_list);
load_icons_first(current_list, false);
}
else if(((kDown | kHeld)) & KEY_DDOWN)
{
sort_author:
sort_by_author(current_list);
load_icons_first(current_list, false);
}
}
}
continue;
@@ -665,6 +722,23 @@ int main(void)
{
change_selected(current_list, -current_list->entries_per_screen_v);
}
else if(BETWEEN(320-144, x, 320-120))
{
switch(current_list->current_sort)
{
case SORT_NAME:
goto sort_author;
break;
case SORT_AUTHOR:
goto sort_path;
break;
case SORT_PATH:
goto sort_name;
break;
default:
break;
}
}
else if(BETWEEN(320-120, x, 320-96))
{
goto enable_qr;

79
source/music.c Normal file
View File

@@ -0,0 +1,79 @@
/*
* This file is part of Anemone3DS
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
*
* 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 "music.h"
#include "loading.h"
// Play a given audio struct
Result update_audio(audio_s *audio)
{
long size = audio->wave_buf[audio->buf_pos].nsamples * 4 - audio->data_read;
char size_info[50] = {0};
sprintf(size_info, "Audio Size: %ld\n", size);
DEBUG(size_info);
if (audio->wave_buf[audio->buf_pos].status == NDSP_WBUF_DONE) // only run if the current selected buffer has already finished playing
{
size_t read = ov_read(&audio->vf, (char*)audio->wave_buf[audio->buf_pos].data_vaddr + audio->data_read, size, NULL); // read 1 vorbis packet into wave buffer
if (read <= 0) // EoF or error
{
ov_clear(&audio->vf);
if (read == 0) // EoF
{
ov_open(fmemopen(audio->filebuf, audio->filesize, "rb"), &audio->vf, NULL, 0); // Reopen file. Don't need to reinit channel stuff since it's all the same as before
} else // Error :(
{
char error[100] = {0};
sprintf(error, "Vorbis play error: %d\n", read);
DEBUG(error);
ndspChnReset(0);
return MAKERESULT(RL_FATAL, RS_INVALIDARG, RM_APPLICATION, RD_NO_DATA);
}
} else
{
audio->data_read += read;
if (read == size) {
audio->data_read = 0;
ndspChnWaveBufAdd(0, &audio->wave_buf[audio->buf_pos]); // Add buffer to ndsp
audio->buf_pos = 1 - audio->buf_pos; // switch to other buffer to load and prepare it while the current one is playing
}
}
}
return MAKERESULT(RL_SUCCESS, RS_SUCCESS, RM_APPLICATION, RD_SUCCESS);
}
void thread_audio(void* data) {
audio_s *audio = (audio_s*)data;
while(!audio->stop) {
update_audio(audio);
}
free(audio->filebuf);
free(audio);
}
void play_audio(audio_s *audio) {
threadCreate(thread_audio, audio, 0x1000, 0x3F, 1, true);
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Anemone3DS
* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth")
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
*
* 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
@@ -28,6 +28,8 @@
#include "loading.h"
#include "draw.h"
#include "fs.h"
#include "unicode.h"
#include "music.h"
#include "pp2d/pp2d/pp2d.h"
static Instructions_s browser_instructions[MODE_AMOUNT] = {
@@ -85,7 +87,7 @@ static Instructions_s extra_instructions = {
},
{
L"\uE07B Toggle splash/theme",
NULL
L"\uE07C Reload without cache"
},
{
NULL,
@@ -98,60 +100,71 @@ static Instructions_s extra_instructions = {
}
};
static void load_remote_entry(Entry_s * entry)
static void load_remote_smdh(Entry_s * entry, size_t textureID, bool ignore_cache)
{
char * entry_json = NULL;
char * api_url = NULL;
asprintf(&api_url, THEMEPLAZA_ENTRY_FORMAT, entry->tp_download_id);
u32 json_len = http_get(api_url, NULL, &entry_json);
free(api_url);
bool not_cached = true;
char * smdh_buf = NULL;
u32 smdh_size = load_data("/info.smdh", *entry, &smdh_buf);
Icon_s * smdh = (Icon_s *)smdh_buf;
if(json_len)
not_cached = !smdh_size || ignore_cache; // if the size is 0, the file wasn't there
if(not_cached)
{
json_error_t error;
json_t *root = json_loadb(entry_json, json_len, 0, &error);
if(root)
{
const char *key;
json_t *value;
json_object_foreach(root, key, value)
{
if(json_is_string(value))
{
if(!strcmp(key, THEMEPLAZA_JSON_ENTRY_NAME))
{
utf8_to_utf16(entry->name, (u8*)json_string_value(value), 0x40);
}
else if(!strcmp(key, THEMEPLAZA_JSON_ENTRY_DESC))
utf8_to_utf16(entry->desc, (u8*)json_string_value(value), 0x80);
else if(!strcmp(key, THEMEPLAZA_JSON_ENTRY_AUTH))
utf8_to_utf16(entry->author, (u8*)json_string_value(value), 0x40);
}
}
}
else
DEBUG("json error on line %d: %s\n", error.line, error.text);
json_decref(root);
free(smdh_buf);
smdh_buf = NULL;
char * api_url = NULL;
asprintf(&api_url, THEMEPLAZA_SMDH_FORMAT, entry->tp_download_id);
smdh_size = http_get(api_url, NULL, &smdh_buf);
free(api_url);
smdh = (Icon_s *)smdh_buf;
}
free(entry_json);
}
static void load_remote_icon(size_t textureID, json_int_t id)
{
char * icon_data = NULL;
char * icon_url = NULL;
asprintf(&icon_url, THEMEPLAZA_ICON_FORMAT, id);
u32 icon_size = http_get(icon_url, NULL, &icon_data);
free(icon_url);
if(!smdh_size)
{
free(smdh_buf);
utf8_to_utf16(entry->name, (u8*)"No 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, smdh->name, 0x40*sizeof(u16));
memcpy(entry->desc, smdh->desc, 0x80*sizeof(u16));
memcpy(entry->author, smdh->author, 0x40*sizeof(u16));
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(smdh->big_icon[source_pixel]);
}
}
pp2d_free_texture(textureID);
pp2d_load_texture_png_memory(textureID, icon_data, icon_size);
free(icon_data);
pp2d_load_texture_memory(textureID, (u8*)image, (u32)width, (u32)height);
free(image);
if(not_cached)
{
FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_UTF16, entry->path), FS_ATTRIBUTE_DIRECTORY);
u16 path[0x107] = {0};
strucat(path, entry->path);
struacat(path, "/info.smdh");
remake_file(fsMakePath(PATH_UTF16, path), ArchiveSD, smdh_size);
buf_to_file(smdh_size, fsMakePath(PATH_UTF16, path), ArchiveSD, smdh_buf);
}
free(smdh_buf);
}
static void load_remote_entries(Entry_List_s * list, json_t *ids_array)
static void load_remote_entries(Entry_List_s * list, json_t *ids_array, bool ignore_cache)
{
list->entries_count = json_array_size(ids_array);
free(list->entries);
@@ -167,15 +180,19 @@ static void load_remote_entries(Entry_List_s * list, json_t *ids_array)
size_t offset = i;
Entry_s * current_entry = &list->entries[offset];
current_entry->tp_download_id = json_integer_value(id);
load_remote_entry(current_entry);
size_t textureID = list->texture_id_offset + i;
load_remote_icon(textureID, current_entry->tp_download_id);
char * entry_path = NULL;
asprintf(&entry_path, CACHE_PATH_FORMAT, current_entry->tp_download_id);
utf8_to_utf16(current_entry->path, (u8*)entry_path, 0x106);
free(entry_path);
load_remote_smdh(current_entry, textureID, ignore_cache);
list->icons_ids[offset] = textureID;
}
}
static void load_remote_list(Entry_List_s * list, json_int_t page, EntryMode mode)
static void load_remote_list(Entry_List_s * list, json_int_t page, EntryMode mode, bool ignore_cache)
{
if(page > list->tp_page_count)
page = 1;
@@ -215,7 +232,7 @@ static void load_remote_list(Entry_List_s * list, json_int_t page, EntryMode mod
if(json_is_integer(value) && !strcmp(key, THEMEPLAZA_JSON_PAGE_COUNT))
list->tp_page_count = json_integer_value(value);
else if(json_is_array(value) && !strcmp(key, THEMEPLAZA_JSON_PAGE_IDS))
load_remote_entries(list, value);
load_remote_entries(list, value, ignore_cache);
else if(json_is_string(value) && !strcmp(key, THEMEPLAZA_JSON_ERROR_MESSAGE) && !strcmp(json_string_value(value), THEMEPLAZA_JSON_ERROR_MESSAGE_NOT_FOUND))
throw_error("No results for this search.", ERROR_LEVEL_WARNING);
}
@@ -231,22 +248,31 @@ static void load_remote_list(Entry_List_s * list, json_int_t page, EntryMode mod
free(page_json);
}
static char previous_preview_url[0x100] = {0};
static bool load_remote_preview(Entry_List_s list, int * preview_offset)
static u16 previous_path_preview[0x106] = {0};
static bool load_remote_preview(Entry_s * entry, int * preview_offset)
{
Entry_s entry = list.entries[list.selected_entry];
bool not_cached = true;
char * preview_url = NULL;
asprintf(&preview_url, THEMEPLAZA_PREVIEW_FORMAT, entry.tp_download_id);
if(!strncmp(previous_preview_url, preview_url, 0x100))
{
free(preview_url);
return true;
}
if(!memcmp(&previous_path_preview, entry->path, 0x106*sizeof(u16))) return true;
draw_install(INSTALL_LOADING_REMOTE_PREVIEW);
char * preview_png = NULL;
u32 preview_size = http_get(preview_url, NULL, &preview_png);
u32 preview_size = load_data("/preview.png", *entry, &preview_png);
not_cached = !preview_size;
if(not_cached)
{
free(preview_png);
preview_png = NULL;
char * preview_url = NULL;
asprintf(&preview_url, THEMEPLAZA_PREVIEW_FORMAT, entry->tp_download_id);
draw_install(INSTALL_LOADING_REMOTE_PREVIEW);
preview_size = http_get(preview_url, NULL, &preview_png);
free(preview_url);
}
if(!preview_size)
{
@@ -270,7 +296,7 @@ static bool load_remote_preview(Entry_List_s list, int * preview_offset)
}
// mark the new preview as loaded for optimisation
strncpy(previous_preview_url, preview_url, 0x100);
memcpy(&previous_path_preview, entry->path, 0x106*sizeof(u16));
// free the previously loaded preview. wont do anything if there wasnt one
pp2d_free_texture(TEXTURE_REMOTE_PREVIEW);
@@ -285,12 +311,53 @@ static bool load_remote_preview(Entry_List_s list, int * preview_offset)
}
free(image);
free(preview_url);
if(not_cached)
{
u16 path[0x107] = {0};
strucat(path, entry->path);
struacat(path, "/preview.png");
remake_file(fsMakePath(PATH_UTF16, path), ArchiveSD, preview_size);
buf_to_file(preview_size, fsMakePath(PATH_UTF16, path), ArchiveSD, preview_png);
}
free(preview_png);
return ret;
}
static u16 previous_path_bgm[0x106] = {0};
static void load_remote_bgm(Entry_s * entry)
{
if(!memcmp(&previous_path_bgm, entry->path, 0x106*sizeof(u16))) return;
char * bgm_ogg = NULL;
u32 bgm_size = load_data("/bgm.ogg", *entry, &bgm_ogg);
if(!bgm_size)
{
free(bgm_ogg);
bgm_ogg = NULL;
char * bgm_url = NULL;
asprintf(&bgm_url, THEMEPLAZA_BGM_FORMAT, entry->tp_download_id);
draw_install(INSTALL_LOADING_REMOTE_BGM);
bgm_size = http_get(bgm_url, NULL, &bgm_ogg);
free(bgm_url);
u16 path[0x107] = {0};
strucat(path, entry->path);
struacat(path, "/bgm.ogg");
remake_file(fsMakePath(PATH_UTF16, path), ArchiveSD, bgm_size);
buf_to_file(bgm_size, fsMakePath(PATH_UTF16, path), ArchiveSD, bgm_ogg);
memcpy(&previous_path_bgm, entry->path, 0x106*sizeof(u16));
}
free(bgm_ogg);
}
static void download_remote_entry(Entry_s * entry, EntryMode mode)
{
char * download_url = NULL;
@@ -311,8 +378,8 @@ static void download_remote_entry(Entry_s * entry, EntryMode mode)
strcat(path_to_file, ".zip");
DEBUG("Saving to sd: %s\n", path_to_file);
remake_file(path_to_file, ArchiveSD, zip_size);
buf_to_file(zip_size, path_to_file, ArchiveSD, zip_buf);
remake_file(fsMakePath(PATH_ASCII, path_to_file), ArchiveSD, zip_size);
buf_to_file(zip_size, fsMakePath(PATH_ASCII, path_to_file), ArchiveSD, zip_buf);
free(zip_buf);
}
@@ -361,7 +428,7 @@ static void jump_menu(Entry_List_s * list)
{
json_int_t newpage = (json_int_t)atoi(numbuf);
if(newpage != list->tp_current_page)
load_remote_list(list, newpage, list->mode);
load_remote_list(list, newpage, list->mode, false);
}
}
@@ -389,7 +456,7 @@ static void search_menu(Entry_List_s * list)
search[i] = '+';
}
list->tp_search = search;
load_remote_list(list, 1, list->mode);
load_remote_list(list, 1, list->mode, false);
}
else
{
@@ -425,11 +492,12 @@ bool themeplaza_browser(EntryMode mode)
bool preview_mode = false;
int preview_offset = 0;
audio_s * audio = NULL;
Entry_List_s list = {0};
Entry_List_s * current_list = &list;
current_list->tp_search = strdup("");
load_remote_list(current_list, 1, mode);
load_remote_list(current_list, 1, mode, false);
bool extra_mode = false;
@@ -461,6 +529,8 @@ bool themeplaza_browser(EntryMode mode)
exit:
quit = true;
downloaded = false;
if(audio)
audio->stop = true;
break;
}
@@ -479,7 +549,7 @@ bool themeplaza_browser(EntryMode mode)
free(current_list->tp_search);
current_list->tp_search = strdup("");
load_remote_list(current_list, 1, mode);
load_remote_list(current_list, 1, mode, false);
}
else if((kDown | kHeld) & KEY_DUP)
{
@@ -487,7 +557,7 @@ bool themeplaza_browser(EntryMode mode)
}
else if((kDown | kHeld) & KEY_DRIGHT)
{
load_remote_list(current_list, current_list->tp_current_page, mode, true);
}
else if((kDown | kHeld) & KEY_DDOWN)
{
@@ -504,14 +574,31 @@ bool themeplaza_browser(EntryMode mode)
{
toggle_preview:
if(!preview_mode)
preview_mode = load_remote_preview(*current_list, &preview_offset);
{
preview_mode = load_remote_preview(current_entry, &preview_offset);
if(mode == MODE_THEMES)
{
load_remote_bgm(current_entry);
audio = calloc(1, sizeof(audio_s));
load_audio(*current_entry, audio);
play_audio(audio);
}
}
else
{
preview_mode = false;
if(mode == MODE_THEMES && audio)
audio->stop = true;
}
}
else if(kDown & KEY_B)
{
if(preview_mode)
{
preview_mode = false;
if(mode == MODE_THEMES && audio)
audio->stop = true;
}
else
break;
}
@@ -530,11 +617,11 @@ bool themeplaza_browser(EntryMode mode)
}
else if(kDown & KEY_L)
{
load_remote_list(current_list, current_list->tp_current_page-1, mode);
load_remote_list(current_list, current_list->tp_current_page-1, mode, false);
}
else if(kDown & KEY_R)
{
load_remote_list(current_list, current_list->tp_current_page+1, mode);
load_remote_list(current_list, current_list->tp_current_page+1, mode, false);
}
// Movement in the UI
@@ -595,6 +682,8 @@ bool themeplaza_browser(EntryMode mode)
if(preview_mode)
{
preview_mode = false;
if(mode == MODE_THEMES && audio)
audio->stop = true;
continue;
}
else if(y < 24)
@@ -628,11 +717,11 @@ bool themeplaza_browser(EntryMode mode)
{
if(BETWEEN(0, x, border))
{
load_remote_list(current_list, current_list->tp_current_page-1, mode);
load_remote_list(current_list, current_list->tp_current_page-1, mode, false);
}
else if(BETWEEN(320-border, x, 320))
{
load_remote_list(current_list, current_list->tp_current_page+1, mode);
load_remote_list(current_list, current_list->tp_current_page+1, mode, false);
}
}
}
@@ -722,7 +811,7 @@ u32 http_get(const char *url, char ** filename, char ** buf)
{
httpcCloseContext(&context);
if (new_url != NULL) free(new_url);
DEBUG("status_code\n");
DEBUG("status_code, %lu\n", status_code);
return 0;
}
@@ -820,5 +909,6 @@ u32 http_get(const char *url, char ** filename, char ** buf)
httpcCloseContext(&context);
free(new_url);
DEBUG("size: %lu\n", size);
return size;
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Anemone3DS
* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth")
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
*
* 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
@@ -41,15 +41,15 @@ void splash_install(Entry_s splash)
u32 size = load_data("/splash.bin", splash, &screen_buf);
if(size != 0)
{
remake_file("/luma/splash.bin", ArchiveSD, size);
buf_to_file(size, "/luma/splash.bin", ArchiveSD, screen_buf);
remake_file(fsMakePath(PATH_ASCII, "/luma/splash.bin"), ArchiveSD, size);
buf_to_file(size, fsMakePath(PATH_ASCII, "/luma/splash.bin"), ArchiveSD, screen_buf);
}
u32 bottom_size = load_data("/splashbottom.bin", splash, &screen_buf);
if(bottom_size != 0)
{
remake_file("/luma/splashbottom.bin", ArchiveSD, bottom_size);
buf_to_file(bottom_size, "/luma/splashbottom.bin", ArchiveSD, screen_buf);
remake_file(fsMakePath(PATH_ASCII, "/luma/splashbottom.bin"), ArchiveSD, bottom_size);
buf_to_file(bottom_size, fsMakePath(PATH_ASCII, "/luma/splashbottom.bin"), ArchiveSD, screen_buf);
}
if(size == 0 && bottom_size == 0)

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Anemone3DS
* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth")
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
*
* 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
@@ -56,12 +56,14 @@ static Result install_theme_internal(Entry_List_s themes, int installmode)
return MAKERESULT(RL_USAGE, RS_INVALIDARG, RM_COMMON, RD_INVALID_SELECTION);
}
char * padded = NULL;
int shuffle_count = 0;
Handle body_cache_handle;
if(installmode & THEME_INSTALL_BODY)
{
remake_file("/BodyCache_rd.bin", ArchiveThemeExt, BODY_CACHE_SIZE * MAX_SHUFFLE_THEMES);
remake_file(fsMakePath(PATH_ASCII, "/BodyCache_rd.bin"), ArchiveThemeExt, BODY_CACHE_SIZE * MAX_SHUFFLE_THEMES);
FSUSER_OpenFile(&body_cache_handle, ArchiveThemeExt, fsMakePath(PATH_ASCII, "/BodyCache_rd.bin"), FS_OPEN_WRITE, 0);
}
@@ -83,8 +85,15 @@ static Result install_theme_internal(Entry_List_s themes, int installmode)
}
shuffle_body_sizes[shuffle_count] = body_size;
FSFILE_Write(body_cache_handle, NULL, BODY_CACHE_SIZE * shuffle_count, body, body_size, FS_WRITE_FLUSH);
padded = calloc(BODY_CACHE_SIZE, sizeof(char));
memcpy(padded, body, body_size);
free(body);
FSFILE_Write(body_cache_handle, NULL, BODY_CACHE_SIZE * shuffle_count, padded, BODY_CACHE_SIZE, FS_WRITE_FLUSH);
free(padded);
padded = NULL;
}
if(installmode & THEME_INSTALL_BGM)
@@ -101,9 +110,20 @@ static Result install_theme_internal(Entry_List_s themes, int installmode)
}
shuffle_music_sizes[shuffle_count] = music_size;
remake_file(bgm_cache_path, ArchiveThemeExt, BGM_MAX_SIZE);
buf_to_file(music_size, bgm_cache_path, ArchiveThemeExt, music);
remake_file(fsMakePath(PATH_ASCII, bgm_cache_path), ArchiveThemeExt, BGM_MAX_SIZE);
Handle bgm_cache_handle;
FSUSER_OpenFile(&bgm_cache_handle, ArchiveThemeExt, fsMakePath(PATH_ASCII, bgm_cache_path), FS_OPEN_WRITE, 0);
padded = calloc(BGM_MAX_SIZE, sizeof(char));
memcpy(padded, music, music_size);
free(music);
FSFILE_Write(bgm_cache_handle, NULL, 0, padded, BGM_MAX_SIZE, FS_WRITE_FLUSH);
FSFILE_Close(bgm_cache_handle);
free(padded);
padded = NULL;
}
shuffle_count++;
@@ -112,12 +132,15 @@ static Result install_theme_internal(Entry_List_s themes, int installmode)
if(installmode & THEME_INSTALL_BGM)
{
char * blank = calloc(BGM_MAX_SIZE, sizeof(char));
for(int i = shuffle_count; i < MAX_SHUFFLE_THEMES; i++)
{
char bgm_cache_path[26] = {0};
sprintf(bgm_cache_path, "/BgmCache_%.2i.bin", i);
remake_file(bgm_cache_path, ArchiveThemeExt, BGM_MAX_SIZE);
remake_file(fsMakePath(PATH_ASCII, bgm_cache_path), ArchiveThemeExt, BGM_MAX_SIZE);
buf_to_file(BGM_MAX_SIZE, fsMakePath(PATH_ASCII, bgm_cache_path), ArchiveThemeExt, blank);
}
free(blank);
}
if(installmode & THEME_INSTALL_BODY)
@@ -140,7 +163,7 @@ static Result install_theme_internal(Entry_List_s themes, int installmode)
return MAKERESULT(RL_PERMANENT, RS_CANCELED, RM_APPLICATION, RD_NOT_FOUND);
}
res = buf_to_file(body_size, "/BodyCache.bin", ArchiveThemeExt, body); // Write body data to file
res = buf_to_file(body_size, fsMakePath(PATH_ASCII, "/BodyCache.bin"), ArchiveThemeExt, body); // Write body data to file
free(body);
if(R_FAILED(res)) return res;
@@ -156,7 +179,7 @@ static Result install_theme_internal(Entry_List_s themes, int installmode)
return MAKERESULT(RL_PERMANENT, RS_CANCELED, RM_APPLICATION, RD_TOO_LARGE);
}
res = buf_to_file(music_size, "/BgmCache.bin", ArchiveThemeExt, music);
res = buf_to_file(music_size, fsMakePath(PATH_ASCII, "/BgmCache.bin"), ArchiveThemeExt, music);
free(music);
if(R_FAILED(res)) return res;
@@ -195,7 +218,7 @@ static Result install_theme_internal(Entry_List_s themes, int installmode)
theme_manage->dlc_theme_content_index = 0xFF;
theme_manage->use_theme_cache = 0x0200;
res = buf_to_file(0x800, "/ThemeManage.bin", ArchiveThemeExt, thememanage_buf);
res = buf_to_file(0x800, fsMakePath(PATH_ASCII, "/ThemeManage.bin"), ArchiveThemeExt, thememanage_buf);
free(thememanage_buf);
if(R_FAILED(res)) return res;
//----------------------------------------
@@ -220,7 +243,7 @@ static Result install_theme_internal(Entry_List_s themes, int installmode)
}
}
res = buf_to_file(savedata_size, "/SaveData.dat", ArchiveHomeExt, savedata_buf);
res = buf_to_file(savedata_size, fsMakePath(PATH_ASCII, "/SaveData.dat"), ArchiveHomeExt, savedata_buf);
free(savedata_buf);
if(R_FAILED(res)) return res;
//----------------------------------------

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Anemone3DS
* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth")
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
*
* 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
@@ -48,7 +48,9 @@ void printu(u16 *input)
ssize_t buf_len = in_len + 1; // Plus 1 for proper null termination
wchar_t *buf = calloc(buf_len, sizeof(wchar_t));
utf16_to_utf32((u32*)buf, input, buf_len);
printf("%ls\n", buf);
char cbuf[0x106];
sprintf(cbuf, "%ls\n", buf);
DEBUG(cbuf);
free(buf);
}