diff --git a/.gitignore b/.gitignore index 2354a8b..a27b0d2 100644 --- a/.gitignore +++ b/.gitignore @@ -57,6 +57,7 @@ dkms.conf # Build files build/ +out/ # Sublime stuff .clang_complete diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..73aca7f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "source/pp2d"] + path = source/pp2d + url = git@github.com:BernardoGiordano/pp2d.git diff --git a/Makefile b/Makefile index bf82d03..e25b948 100644 --- a/Makefile +++ b/Makefile @@ -9,48 +9,58 @@ endif TOPDIR ?= $(CURDIR) include $(DEVKITARM)/3ds_rules -#--------------------------------------------------------------------------------- -# TARGET is the name of the output -# BUILD is the directory where object files & intermediate files will be placed -# SOURCES is a list of directories containing source code -# DATA is a list of directories containing data files -# INCLUDES is a list of directories containing header files -# -# NO_SMDH: if set to anything, no SMDH file is generated. -# ROMFS is the directory which contains the RomFS, relative to the Makefile (Optional) -# APP_TITLE is the name of the app stored in the SMDH file (Optional) -# APP_DESCRIPTION is the description of the app stored in the SMDH file (Optional) -# APP_AUTHOR is the author of the app stored in the SMDH file (Optional) -# ICON is the filename of the icon (.png), relative to the project folder. -# If not set, it attempts to use one of the following (in this order): -# - .png -# - icon.png -# - /default_icon.png -#--------------------------------------------------------------------------------- -TARGET := $(notdir $(CURDIR)) -BUILD := build -SOURCES := source source/minizip -DATA := data -INCLUDES := include -#ROMFS := romfs +# Your values. +APP_TITLE := Anemone3DS +APP_DESCRIPTION := A complete themeing tool for the 3DS +APP_AUTHOR := astronautlevel and daedreth + + +TARGET := $(subst $e ,_,$(notdir $(APP_TITLE))) +OUTDIR := out +BUILD := build +SOURCES := source source/pp2d/pp2d source/minizip +INCLUDES := include +ROMFS := romfs + + +# Path to the files +# If left blank, will try to use "icon.png", "$(TARGET).png", or the default ctrulib icon, in that order +ICON := + +BANNER_AUDIO := meta/audio.wav +BANNER_IMAGE := meta/banner.png + +RSF_PATH := meta/app.rsf + +# If left blank, makerom will use the default Homebrew logo +LOGO := + + +# If left blank, makerom will use default values (0xff3ff and CTR-P-CTAP, respectively) +# Be careful if UNIQUE_ID is the same as other apps: it will overwrite the previously installed one +UNIQUE_ID := 0xAFEN +PRODUCT_CODE := CTR-P-ANEM + +# Don't really need to change this +ICON_FLAGS := nosavebackups,visible #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft -CFLAGS := -g -Wall -Wextra -Wno-pointer-sign -mword-relocations \ - -ffunction-sections \ +CFLAGS := -g -Wall -Wextra -O2 -mword-relocations \ + -fomit-frame-pointer -ffunction-sections \ $(ARCH) -CFLAGS += $(INCLUDE) -DARM11 -D_3DS +CFLAGS += $(INCLUDE) -DARM11 -D_3DS -D_GNU_SOURCE CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 ASFLAGS := -g $(ARCH) LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) -LIBS := -lcitro3d -lctrud -lm -lz +LIBS := -lcitro3d -lctru -lm -lz #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing @@ -66,7 +76,7 @@ LIBDIRS := $(CTRULIB) $(DEVKITPRO)/portlibs/armv6k ifneq ($(BUILD),$(notdir $(CURDIR))) #--------------------------------------------------------------------------------- -export OUTPUT := $(CURDIR)/$(TARGET) +export OUTPUT := $(CURDIR)/$(OUTDIR)/$(TARGET) export TOPDIR := $(CURDIR) export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ @@ -119,7 +129,7 @@ else endif ifeq ($(strip $(NO_SMDH)),) - export _3DSXFLAGS += --smdh=$(CURDIR)/$(TARGET).smdh + export _3DSXFLAGS += --smdh=$(OUTPUT).smdh endif ifneq ($(ROMFS),) @@ -129,17 +139,76 @@ endif .PHONY: $(BUILD) clean all #--------------------------------------------------------------------------------- -all: $(BUILD) +3dsx: $(BUILD) $(OUTPUT).3dsx +cia : $(BUILD) $(OUTPUT).cia + +all: 3dsx cia + +#--------------------------------------------------------------------------------- $(BUILD): - @[ -d $@ ] || mkdir -p $@ + @mkdir -p $(OUTDIR) + @[ -d "$@" ] || mkdir -p "$@" @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile #--------------------------------------------------------------------------------- clean: @echo clean ... - @rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf + @rm -fr $(BUILD) $(OUTDIR) +#--------------------------------------------------------------------------------- +ifeq ($(strip $(NO_SMDH)),) +$(OUTPUT).3dsx : $(OUTPUT).elf $(OUTPUT).smdh +else +$(OUTPUT).3dsx : $(OUTPUT).elf +endif + +#--------------------------------------------------------------------------------- +MAKEROM ?= makerom + +MAKEROM_ARGS := -elf "$(OUTPUT).elf" -rsf "$(RSF_PATH)" -banner "$(BUILD)/banner.bnr" -icon "$(BUILD)/icon.icn" -DAPP_TITLE="$(APP_TITLE)" -DAPP_PRODUCT_CODE="$(PRODUCT_CODE)" -DAPP_UNIQUE_ID="$(UNIQUE_ID)" + +ifneq ($(strip $(ROMFS)),) + MAKEROM_ARGS += -romfs "$(BUILD)/romfs.bin" +endif +ifneq ($(strip $(LOGO)),) + MAKEROM_ARGS += -logo "$(LOGO)" +endif + +ifeq ($(strip $(ROMFS)),) +$(OUTPUT).cia: $(OUTPUT).elf $(BUILD)/banner.bnr $(BUILD)/icon.icn + $(MAKEROM) -f cia -o "$@" -target t -exefslogo $(MAKEROM_ARGS) +else +$(OUTPUT).cia: $(OUTPUT).elf $(BUILD)/romfs.bin $(BUILD)/banner.bnr $(BUILD)/icon.icn + $(MAKEROM) -f cia -o "$@" -target t -exefslogo $(MAKEROM_ARGS) +endif + + +BANNERTOOL ?= bannertool + +ifeq ($(suffix $(BANNER_IMAGE)),.cgfx) + BANNER_IMAGE_ARG := -ci +else + BANNER_IMAGE_ARG := -i +endif + +ifeq ($(suffix $(BANNER_AUDIO)),.cwav) + BANNER_AUDIO_ARG := -ca +else + BANNER_AUDIO_ARG := -a +endif + +$(BUILD)/banner.bnr : $(BANNER_IMAGE) $(BANNER_AUDIO) + $(BANNERTOOL) makebanner $(BANNER_IMAGE_ARG) "$(BANNER_IMAGE)" $(BANNER_AUDIO_ARG) "$(BANNER_AUDIO)" -o "$@" + +$(BUILD)/icon.icn : $(APP_ICON) + $(BANNERTOOL) makesmdh -s "$(APP_TITLE)" -l "$(APP_DESCRIPTION)" -p "$(APP_AUTHOR)" -i "$(APP_ICON)" -f "$(ICON_FLAGS)" -o "$@" + + +3DSTOOL ?= 3dstool + +$(BUILD)/romfs.bin : $(ROMFS) + $(3DSTOOL) -ctf romfs "$@" --romfs-dir "$(ROMFS)" #--------------------------------------------------------------------------------- else @@ -149,11 +218,6 @@ DEPENDS := $(OFILES:.o=.d) #--------------------------------------------------------------------------------- # main targets #--------------------------------------------------------------------------------- -ifeq ($(strip $(NO_SMDH)),) -$(OUTPUT).3dsx : $(OUTPUT).elf $(OUTPUT).smdh -else -$(OUTPUT).3dsx : $(OUTPUT).elf -endif $(OUTPUT).elf : $(OFILES) diff --git a/README.md b/README.md index ad5ac47..326c80b 100644 --- a/README.md +++ b/README.md @@ -8,17 +8,15 @@ This depends on zlib. Get it from portlibs. This project is licensed under the GNU GPLv3. See LICENSE.md for details. Additional terms 7b and 7c apply to this project. # Credits -Thanks to Rinnegatamante, whose code served as reference on theme installation. -Thanks to yellows8 for his home menu extdump tool, which was invaluable in debugging. - -Thanks to the folks on #dev of Nintendo Homebrew, who helped with unicode shenanigans (especially Stary2001, Fenrir, and DanielKO). - -Thanks to Kenn (mattkenster) for designing the GUI as well as the banner and icon. - -Thanks to the maintainers for all used libraries, including ctrulib, zlib, citro3d, pp2d and minizip. - -Thanks to 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 - * The members of the Secret Shack Service Discord - * The members of the ThemePlaza Discord \ No newline at end of file +Thanks to... + * Rinnegatamante, whose code served as reference on theme installation. + * 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, Fenrir, and DanielKO). + * Kenn (mattkenster) for designing the GUI as well as the banner and icon. + * the maintainers for all used libraries, including ctrulib, zlib, citro3d, pp2d and minizip. + * BernardoGiordano and LiquidFenrir for making pp2d and helping me out immensely with graphics + * 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 + * The members of the Secret Shack Service Discord + * The members of the ThemePlaza Discord \ No newline at end of file diff --git a/meta/app.rsf b/meta/app.rsf new file mode 100644 index 0000000..367e431 --- /dev/null +++ b/meta/app.rsf @@ -0,0 +1,189 @@ +BasicInfo: + Title : "Anemone3DS" + CompanyCode : "00" + ProductCode : "CTR-P-ANEM" + ContentType : Application + Logo : Nintendo # Nintendo / Licensed / Distributed / iQue / iQueForSystem + +TitleInfo: + UniqueId : 0xAFEN + Category : Application + +CardInfo: + MediaSize : 128MB # 128MB / 256MB / 512MB / 1GB / 2GB / 4GB + MediaType : Card1 # Card1 / Card2 + CardDevice : NorFlash # NorFlash(Pick this if you use savedata) / None + + +Option: + UseOnSD : true # true if App is to be installed to SD + FreeProductCode : true # Removes limitations on ProductCode + MediaFootPadding : false # If true CCI files are created with padding + EnableCrypt : false # Enables encryption for NCCH and CIA + EnableCompress : true # Compresses exefs code + +AccessControlInfo: + #UseExtSaveData : true + #ExtSaveDataId: 0xff3ff + #UseExtendedSaveDataAccessControl: true + #AccessibleSaveDataIds: [0x101, 0x202, 0x303, 0x404, 0x505, 0x606] + +SystemControlInfo: + SaveDataSize: 128KB + RemasterVersion: 7 + StackSize: 0x40000 + +# DO NOT EDIT BELOW HERE OR PROGRAMS WILL NOT LAUNCH (most likely) + +AccessControlInfo: + FileSystemAccess: + - Debug + - DirectSdmc + - DirectSdmcWrite + + IdealProcessor : 0 + AffinityMask : 1 + + Priority : 16 + + MaxCpu : 0x9E # Default + DisableDebug : false + EnableForceDebug : false + CanWriteSharedPage : false + CanUsePrivilegedPriority : false + CanUseNonAlphabetAndNumber : false + PermitMainFunctionArgument : false + CanShareDeviceMemory : false + RunnableOnSleep : false + SpecialMemoryArrange : false + CoreVersion : 2 + DescVersion : 2 + + ReleaseKernelMajor : "02" + ReleaseKernelMinor : "33" + MemoryType : Application + HandleTableSize: 512 + IORegisterMapping: + - 1ff50000-1ff57fff + - 1ff70000-1ff77fff + MemoryMapping: + - 1f000000-1f5fffff:r + SystemCallAccess: + ArbitrateAddress: 34 + Break: 60 + CancelTimer: 28 + ClearEvent: 25 + ClearTimer: 29 + CloseHandle: 35 + ConnectToPort: 45 + ControlMemory: 1 + CreateAddressArbiter: 33 + CreateEvent: 23 + CreateMemoryBlock: 30 + CreateMutex: 19 + CreateSemaphore: 21 + CreateThread: 8 + CreateTimer: 26 + DuplicateHandle: 39 + ExitProcess: 3 + ExitThread: 9 + GetCurrentProcessorNumber: 17 + GetHandleInfo: 41 + GetProcessId: 53 + GetProcessIdOfThread: 54 + GetProcessIdealProcessor: 6 + GetProcessInfo: 43 + GetResourceLimit: 56 + GetResourceLimitCurrentValues: 58 + GetResourceLimitLimitValues: 57 + GetSystemInfo: 42 + GetSystemTick: 40 + GetThreadContext: 59 + GetThreadId: 55 + GetThreadIdealProcessor: 15 + GetThreadInfo: 44 + GetThreadPriority: 11 + MapMemoryBlock: 31 + OutputDebugString: 61 + QueryMemory: 2 + ReleaseMutex: 20 + ReleaseSemaphore: 22 + SendSyncRequest1: 46 + SendSyncRequest2: 47 + SendSyncRequest3: 48 + SendSyncRequest4: 49 + SendSyncRequest: 50 + SetThreadPriority: 12 + SetTimer: 27 + SignalEvent: 24 + SleepThread: 10 + UnmapMemoryBlock: 32 + WaitSynchronization1: 36 + WaitSynchronizationN: 37 + InterruptNumbers: + ServiceAccessControl: + - APT:U + - $hioFIO + - $hostio0 + - $hostio1 + - ac:u + - boss:U + - cam:u + - cecd:u + - cfg:u + - dlp:FKCL + - dlp:SRVR + - dsp::DSP + - frd:u + - fs:USER + - gsp::Gpu + - hid:USER + - http:C + - mic:u + - ndm:u + - news:s + - nwm::UDS + - ptm:u + - pxi:dev + - soc:U + - gsp::Lcd + - y2r:u + - ldr:ro + - ir:USER + - ir:u + - csnd:SND + - am:u + - ns:s + +SystemControlInfo: + Dependency: + ac: 0x0004013000002402L + am: 0x0004013000001502L + boss: 0x0004013000003402L + camera: 0x0004013000001602L + cecd: 0x0004013000002602L + cfg: 0x0004013000001702L + codec: 0x0004013000001802L + csnd: 0x0004013000002702L + dlp: 0x0004013000002802L + dsp: 0x0004013000001a02L + friends: 0x0004013000003202L + gpio: 0x0004013000001b02L + gsp: 0x0004013000001c02L + hid: 0x0004013000001d02L + http: 0x0004013000002902L + i2c: 0x0004013000001e02L + ir: 0x0004013000003302L + mcu: 0x0004013000001f02L + mic: 0x0004013000002002L + ndm: 0x0004013000002b02L + news: 0x0004013000003502L + nim: 0x0004013000002c02L + nwm: 0x0004013000002d02L + pdn: 0x0004013000002102L + ps: 0x0004013000003102L + ptm: 0x0004013000002202L + ro: 0x0004013000003702L + socket: 0x0004013000002e02L + spi: 0x0004013000002302L + ssl: 0x0004013000002f02L diff --git a/meta/audio.wav b/meta/audio.wav new file mode 100644 index 0000000..5515161 Binary files /dev/null and b/meta/audio.wav differ diff --git a/meta/banner.png b/meta/banner.png new file mode 100644 index 0000000..965f85a Binary files /dev/null and b/meta/banner.png differ diff --git a/romfs/arrow.png b/romfs/arrow.png new file mode 100644 index 0000000..30f6e99 Binary files /dev/null and b/romfs/arrow.png differ diff --git a/source/fs.c b/source/fs.c index a5615db..d0eb121 100644 --- a/source/fs.c +++ b/source/fs.c @@ -80,6 +80,7 @@ Result open_archives(void) theme.data = themePath; retValue = FSUSER_OpenArchive(&ArchiveThemeExt, ARCHIVE_EXTDATA, theme); if(R_FAILED(retValue)) return retValue; + romfsInit(); return 0; } diff --git a/source/main.c b/source/main.c index f9126bb..fd5987f 100644 --- a/source/main.c +++ b/source/main.c @@ -28,20 +28,28 @@ #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 MAX_THEMES 4 + int init_services(void) { - gfxInitDefault(); 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"); return 0; } @@ -57,41 +65,124 @@ int de_init_services(void) return 0; } +void format_time(char *time_string) +{ + time_t t = time(NULL); + struct tm tm = *localtime(&t); + if (tm.tm_hour < 10) + { + char temp_string[3] = {0}; + sprintf(temp_string, "0%i", tm.tm_hour); + strcat(time_string, temp_string); + } else { + char temp_string[3] = {0}; + sprintf(temp_string, "%i", tm.tm_hour); + strcat(time_string, temp_string); + } + strcat(time_string, ":"); + if (tm.tm_min < 10) + { + char temp_string[3] = {0}; + sprintf(temp_string, "0%i", tm.tm_min); + strcat(time_string, temp_string); + } else { + char temp_string[3] = {0}; + sprintf(temp_string, "%i", tm.tm_min); + strcat(time_string, temp_string); + } +} + +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(); - consoleInit(GFX_TOP, NULL); int theme_count = get_number_entries("/Themes"); - printf("Theme count: %i\n", theme_count); 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; while(aptMainLoop()) { hidScanInput(); u32 kDown = hidKeysDown(); - if (kDown & KEY_A) + + pp2d_begin_draw(GFX_TOP); + pp2d_draw_rectangle(0, 0, 400, 23, color_accent); + + 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_textf(20, 50, 0.7, 0.7, color_white, "top_pos: %i", top_pos); + + 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); + + if (top_pos > 0) { - for (int i = 0; i < theme_count; i++) - { - printu(themes_list[i]->name); - printu(themes_list[i]->path); - } - } - if (kDown & KEY_B) + pp2d_draw_texture(TEXTURE_ARROW, 155, 6); + } + + if (top_pos + MAX_THEMES < theme_count) { - shuffle_install(themes_list, theme_count); - close_archives(); - PTMSYSM_ShutdownAsync(0); - ptmSysmExit(); + 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 (kDown & KEY_DOWN) + { + if (cursor_pos < MAX_THEMES && cursor_pos < theme_count) cursor_pos++; + else if (cursor_pos + top_pos < theme_count) top_pos++; + } + if (kDown & KEY_UP) + { + if (cursor_pos > 1) cursor_pos--; + else if (top_pos > 0) top_pos--; } if (kDown & KEY_START) { - close_archives(); - PTMSYSM_ShutdownAsync(0); - ptmSysmExit(); + // close_archives(); + // PTMSYSM_ShutdownAsync(0); + // ptmSysmExit(); + break; } + + pp2d_end_draw(); } de_init_services(); diff --git a/source/pp2d b/source/pp2d new file mode 160000 index 0000000..824abba --- /dev/null +++ b/source/pp2d @@ -0,0 +1 @@ +Subproject commit 824abba2eab5aca6553aa8a360227ada2d39f8e9