From 619539b7dc891a19b40fd56c6682779d63d53d2f Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Mon, 17 Aug 2015 02:02:26 -0700 Subject: [PATCH 01/19] 3DS: Fix video sync --- src/platform/3ds/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platform/3ds/main.c b/src/platform/3ds/main.c index 06597460c..f93983d4d 100644 --- a/src/platform/3ds/main.c +++ b/src/platform/3ds/main.c @@ -77,8 +77,8 @@ int main() { } } gfxFlushBuffers(); - gfxSwapBuffersGpu(); - gspWaitForVBlank(); + gfxSwapBuffers(); + gspWaitForVBlank1(); hidScanInput(); activeKeys = hidKeysHeld() & 0x3FF; if (hidKeysDown() & KEY_X) { From 7fa535380165fdb517433a65f1adec435a941950 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sat, 22 Aug 2015 17:10:03 -0700 Subject: [PATCH 02/19] 3DS: Disable -Wformat --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 009b4f3f8..b551dbdbd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -168,6 +168,7 @@ elseif(UNIX) file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/posix/*.c) source_group("POSIX-specific code" FILES ${OS_SRC}) elseif(3DS) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format") add_definitions(-DCOLOR_16_BIT -DCOLOR_5_6_5) list(APPEND OS_LIB ctru) file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/3ds/3ds-*.c) From 2c7926ef66d3c4a8703abd60f619109a15f56f23 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sat, 22 Aug 2015 17:21:35 -0700 Subject: [PATCH 03/19] 3DS: Adapt VFileOpen for 3DS --- src/platform/3ds/3ds-vfs.h | 2 ++ src/platform/3ds/main.c | 7 ++++--- src/util/vfs.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/platform/3ds/3ds-vfs.h b/src/platform/3ds/3ds-vfs.h index 52a146a78..5a386f154 100644 --- a/src/platform/3ds/3ds-vfs.h +++ b/src/platform/3ds/3ds-vfs.h @@ -12,6 +12,8 @@ #include <3ds.h> +extern FS_archive sdmcArchive; + struct VFile* VFileOpen3DS(FS_archive* archive, const char* path, int flags); #endif diff --git a/src/platform/3ds/main.c b/src/platform/3ds/main.c index f93983d4d..9d6305978 100644 --- a/src/platform/3ds/main.c +++ b/src/platform/3ds/main.c @@ -13,6 +13,8 @@ #include <3ds.h> +FS_archive sdmcArchive; + static void GBA3DSLog(struct GBAThread* thread, enum GBALogLevel level, const char* format, va_list args); static Handle logFile; @@ -22,10 +24,9 @@ int main() { hidInit(0); gfxInit(GSP_RGB565_OES, GSP_RGB565_OES, false); fsInit(); - - FS_archive sdmcArchive = (FS_archive) { + sdmcArchive = (FS_archive) { ARCH_SDMC, - (FS_path) { PATH_EMPTY, 1, (u8*)"" }, + (FS_path) { PATH_EMPTY, 1, (const u8*)"" }, 0, 0 }; FSUSER_OpenArchive(0, &sdmcArchive); diff --git a/src/util/vfs.c b/src/util/vfs.c index 696cc3dc8..ac282ec23 100644 --- a/src/util/vfs.c +++ b/src/util/vfs.c @@ -5,6 +5,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "vfs.h" +#ifdef _3DS +#include "platform/3ds/3ds-vfs.h" +#endif + struct VFile* VFileOpen(const char* path, int flags) { #ifdef USE_VFS_FILE const char* chflags; @@ -30,6 +34,34 @@ struct VFile* VFileOpen(const char* path, int flags) { break; } return VFileFOpen(path, chflags); +#elif defined(_3DS) + int ctrFlags = FS_OPEN_READ; + switch (flags & O_ACCMODE) { + case O_WRONLY: + ctrFlags = FS_OPEN_WRITE; + break; + case O_RDWR: + ctrFlags = FS_OPEN_READ | FS_OPEN_WRITE; + break; + case O_RDONLY: + ctrFlags = FS_OPEN_READ; + break; + } + + if (flags & O_CREAT) { + ctrFlags |= FS_OPEN_CREATE; + } + struct VFile* vf = VFileOpen3DS(&sdmcArchive, path, ctrFlags); + if (!vf) { + return 0; + } + if (flags & O_TRUNC) { + vf->truncate(vf, 0); + } + if (flags & O_APPEND) { + vf->seek(vf, vf->size(vf), SEEK_SET); + } + return vf; #else return VFileOpenFD(path, flags); #endif From ca42faae3c397fb480966637ba99bdda85e7a644 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sat, 22 Aug 2015 17:22:25 -0700 Subject: [PATCH 04/19] 3DS: Use GBAContext --- src/platform/3ds/main.c | 91 ++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 55 deletions(-) diff --git a/src/platform/3ds/main.c b/src/platform/3ds/main.c index 9d6305978..5f1449f56 100644 --- a/src/platform/3ds/main.c +++ b/src/platform/3ds/main.c @@ -3,10 +3,10 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "gba/gba.h" -#include "gba/video.h" #include "gba/renderers/video-software.h" +#include "gba/supervisor/context.h" +#include "gba/video.h" #include "util/memory.h" #include "3ds-vfs.h" @@ -19,6 +19,7 @@ static void GBA3DSLog(struct GBAThread* thread, enum GBALogLevel level, const ch static Handle logFile; int main() { + struct GBAContext context; srvInit(); aptInit(); hidInit(0); @@ -32,71 +33,51 @@ int main() { FSUSER_OpenArchive(0, &sdmcArchive); FSUSER_OpenFile(0, &logFile, sdmcArchive, FS_makePath(PATH_CHAR, "/mgba.log"), FS_OPEN_WRITE | FS_OPEN_CREATE, FS_ATTRIBUTE_NONE); + GBAContextInit(&context, 0); + struct GBAOptions opts = { + .useBios = true, + .logLevel = 0, + .idleOptimization = IDLE_LOOP_REMOVE + }; + GBAConfigLoadDefaults(&context.config, &opts); + context.gba->logHandler = GBA3DSLog; + struct GBAVideoSoftwareRenderer renderer; GBAVideoSoftwareRendererCreate(&renderer); - size_t stride = VIDEO_HORIZONTAL_PIXELS * BYTES_PER_PIXEL; color_t* videoBuffer = anonymousMemoryMap(stride * VIDEO_VERTICAL_PIXELS); - struct GBA* gba = anonymousMemoryMap(sizeof(struct GBA)); - struct ARMCore* cpu = anonymousMemoryMap(sizeof(struct ARMCore)); - int activeKeys = 0; - renderer.outputBuffer = videoBuffer; renderer.outputBufferStride = VIDEO_HORIZONTAL_PIXELS; + GBAVideoAssociateRenderer(&context.gba->video, &renderer.d); - struct VFile* rom = VFileOpen3DS(&sdmcArchive, "/rom.gba", FS_OPEN_READ); - struct VFile* save = VFileOpen3DS(&sdmcArchive, "/rom.sav", FS_OPEN_READ | FS_OPEN_WRITE); + GBAContextLoadROM(&context, "/rom.gba", true); + GBAContextStart(&context); - GBACreate(gba); - ARMSetComponents(cpu, &gba->d, 0, 0); - ARMInit(cpu); - - gba->keySource = &activeKeys; - gba->sync = 0; - - GBAVideoAssociateRenderer(&gba->video, &renderer.d); - - GBALoadROM(gba, rom, save, 0); - - gba->logHandler = GBA3DSLog; - - ARMReset(cpu); - - int frameCounter = 0; while (aptMainLoop()) { - ARMRunLoop(cpu); - - if (frameCounter != gba->video.frameCounter) { - u16 width, height; - u16* screen = (u16*) gfxGetFramebuffer(GFX_BOTTOM, GFX_BOTTOM, &height, &width); - u32 startX = (width - VIDEO_HORIZONTAL_PIXELS) / 2; - u32 startY = (height + VIDEO_VERTICAL_PIXELS) / 2 - 1; - u32 x, y; - for (y = 0; y < VIDEO_VERTICAL_PIXELS; ++y) { - for (x = 0; x < VIDEO_HORIZONTAL_PIXELS; ++x) { - screen[startY - y + (startX + x) * height] = videoBuffer[y * VIDEO_HORIZONTAL_PIXELS + x]; - } - } - gfxFlushBuffers(); - gfxSwapBuffers(); - gspWaitForVBlank1(); - hidScanInput(); - activeKeys = hidKeysHeld() & 0x3FF; - if (hidKeysDown() & KEY_X) { - break; - } - frameCounter = gba->video.frameCounter; + hidScanInput(); + int activeKeys = hidKeysHeld() & 0x3FF; + if (hidKeysDown() & KEY_X) { + break; } + GBAContextFrame(&context, activeKeys); + + u16 width, height; + u16* screen = (u16*) gfxGetFramebuffer(GFX_BOTTOM, GFX_BOTTOM, &height, &width); + u32 startX = (width - VIDEO_HORIZONTAL_PIXELS) / 2; + u32 startY = (height + VIDEO_VERTICAL_PIXELS) / 2 - 1; + u32 x, y; + for (y = 0; y < VIDEO_VERTICAL_PIXELS; ++y) { + for (x = 0; x < VIDEO_HORIZONTAL_PIXELS; ++x) { + screen[startY - y + (startX + x) * height] = videoBuffer[y * VIDEO_HORIZONTAL_PIXELS + x]; + } + } + gfxFlushBuffers(); + gfxSwapBuffers(); + gspWaitForVBlank1(); } - ARMDeinit(cpu); - GBADestroy(gba); - - rom->close(rom); - save->close(save); - - mappedMemoryFree(gba, 0); - mappedMemoryFree(cpu, 0); + GBAContextStop(&context); + GBAContextDeinit(&context); mappedMemoryFree(videoBuffer, 0); From 836d73bc93d1bf9b6877476ce476682af96f6102 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sun, 23 Aug 2015 09:20:56 -0700 Subject: [PATCH 05/19] 3DS: Start using sf2dlib --- CMakeLists.txt | 2 +- src/platform/3ds/main.c | 116 ++++++++++++++++++++++++++++++++++------ 2 files changed, 100 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b25173236..093f5f178 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,7 +171,7 @@ elseif(UNIX) elseif(3DS) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format") add_definitions(-DCOLOR_16_BIT -DCOLOR_5_6_5) - list(APPEND OS_LIB ctru) + list(APPEND OS_LIB sf2d ctru) file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/3ds/3ds-*.c) source_group("3DS-specific code" FILES ${OS_SRC}) endif() diff --git a/src/platform/3ds/main.c b/src/platform/3ds/main.c index 5f1449f56..d2d7c88f2 100644 --- a/src/platform/3ds/main.c +++ b/src/platform/3ds/main.c @@ -12,19 +12,32 @@ #include "3ds-vfs.h" #include <3ds.h> +#include FS_archive sdmcArchive; static void GBA3DSLog(struct GBAThread* thread, enum GBALogLevel level, const char* format, va_list args); static Handle logFile; +static void _drawStart(void) { + sf2d_start_frame(GFX_BOTTOM, GFX_LEFT); +} +static void _drawEnd(void) { + sf2d_end_frame(); + sf2d_swapbuffers(); +} + int main() { struct GBAContext context; srvInit(); aptInit(); hidInit(0); - gfxInit(GSP_RGB565_OES, GSP_RGB565_OES, false); fsInit(); + + sf2d_init(); + sf2d_set_clear_color(0); + sf2d_texture* tex = sf2d_create_texture(256, 256, TEXFMT_RGB565, SF2D_PLACE_RAM); + sdmcArchive = (FS_archive) { ARCH_SDMC, (FS_path) { PATH_EMPTY, 1, (const u8*)"" }, @@ -44,10 +57,8 @@ int main() { struct GBAVideoSoftwareRenderer renderer; GBAVideoSoftwareRendererCreate(&renderer); - size_t stride = VIDEO_HORIZONTAL_PIXELS * BYTES_PER_PIXEL; - color_t* videoBuffer = anonymousMemoryMap(stride * VIDEO_VERTICAL_PIXELS); - renderer.outputBuffer = videoBuffer; - renderer.outputBufferStride = VIDEO_HORIZONTAL_PIXELS; + renderer.outputBuffer = anonymousMemoryMap(256 * VIDEO_VERTICAL_PIXELS * 2); + renderer.outputBufferStride = 256; GBAVideoAssociateRenderer(&context.gba->video, &renderer.d); GBAContextLoadROM(&context, "/rom.gba", true); @@ -60,29 +71,100 @@ int main() { break; } GBAContextFrame(&context, activeKeys); + uint32_t* texdest = (uint32_t*) tex->data; + uint32_t* texsrc = (uint32_t*) renderer.outputBuffer; + int x, y; + for (y = 0; y < VIDEO_VERTICAL_PIXELS; y += 8) { + for (x = 0; x < 16; ++x) { + texdest[ 0 + x * 64 + y * 128] = texsrc[0 + x * 8 + (y + 0) * 128]; + texdest[ 2 + x * 64 + y * 128] = texsrc[1 + x * 8 + (y + 0) * 128]; + texdest[ 8 + x * 64 + y * 128] = texsrc[2 + x * 8 + (y + 0) * 128]; + texdest[10 + x * 64 + y * 128] = texsrc[3 + x * 8 + (y + 0) * 128]; + texdest[32 + x * 64 + y * 128] = texsrc[4 + x * 8 + (y + 0) * 128]; + texdest[34 + x * 64 + y * 128] = texsrc[5 + x * 8 + (y + 0) * 128]; + texdest[40 + x * 64 + y * 128] = texsrc[6 + x * 8 + (y + 0) * 128]; + texdest[42 + x * 64 + y * 128] = texsrc[7 + x * 8 + (y + 0) * 128]; - u16 width, height; - u16* screen = (u16*) gfxGetFramebuffer(GFX_BOTTOM, GFX_BOTTOM, &height, &width); - u32 startX = (width - VIDEO_HORIZONTAL_PIXELS) / 2; - u32 startY = (height + VIDEO_VERTICAL_PIXELS) / 2 - 1; - u32 x, y; - for (y = 0; y < VIDEO_VERTICAL_PIXELS; ++y) { - for (x = 0; x < VIDEO_HORIZONTAL_PIXELS; ++x) { - screen[startY - y + (startX + x) * height] = videoBuffer[y * VIDEO_HORIZONTAL_PIXELS + x]; + texdest[ 1 + x * 64 + y * 128] = texsrc[0 + x * 8 + (y + 1) * 128]; + texdest[ 3 + x * 64 + y * 128] = texsrc[1 + x * 8 + (y + 1) * 128]; + texdest[ 9 + x * 64 + y * 128] = texsrc[2 + x * 8 + (y + 1) * 128]; + texdest[11 + x * 64 + y * 128] = texsrc[3 + x * 8 + (y + 1) * 128]; + texdest[33 + x * 64 + y * 128] = texsrc[4 + x * 8 + (y + 1) * 128]; + texdest[35 + x * 64 + y * 128] = texsrc[5 + x * 8 + (y + 1) * 128]; + texdest[41 + x * 64 + y * 128] = texsrc[6 + x * 8 + (y + 1) * 128]; + texdest[43 + x * 64 + y * 128] = texsrc[7 + x * 8 + (y + 1) * 128]; + + texdest[ 4 + x * 64 + y * 128] = texsrc[0 + x * 8 + (y + 2) * 128]; + texdest[ 6 + x * 64 + y * 128] = texsrc[1 + x * 8 + (y + 2) * 128]; + texdest[12 + x * 64 + y * 128] = texsrc[2 + x * 8 + (y + 2) * 128]; + texdest[14 + x * 64 + y * 128] = texsrc[3 + x * 8 + (y + 2) * 128]; + texdest[36 + x * 64 + y * 128] = texsrc[4 + x * 8 + (y + 2) * 128]; + texdest[38 + x * 64 + y * 128] = texsrc[5 + x * 8 + (y + 2) * 128]; + texdest[44 + x * 64 + y * 128] = texsrc[6 + x * 8 + (y + 2) * 128]; + texdest[46 + x * 64 + y * 128] = texsrc[7 + x * 8 + (y + 2) * 128]; + + texdest[ 5 + x * 64 + y * 128] = texsrc[0 + x * 8 + (y + 3) * 128]; + texdest[ 7 + x * 64 + y * 128] = texsrc[1 + x * 8 + (y + 3) * 128]; + texdest[13 + x * 64 + y * 128] = texsrc[2 + x * 8 + (y + 3) * 128]; + texdest[15 + x * 64 + y * 128] = texsrc[3 + x * 8 + (y + 3) * 128]; + texdest[37 + x * 64 + y * 128] = texsrc[4 + x * 8 + (y + 3) * 128]; + texdest[39 + x * 64 + y * 128] = texsrc[5 + x * 8 + (y + 3) * 128]; + texdest[45 + x * 64 + y * 128] = texsrc[6 + x * 8 + (y + 3) * 128]; + texdest[47 + x * 64 + y * 128] = texsrc[7 + x * 8 + (y + 3) * 128]; + + texdest[16 + x * 64 + y * 128] = texsrc[0 + x * 8 + (y + 4) * 128]; + texdest[18 + x * 64 + y * 128] = texsrc[1 + x * 8 + (y + 4) * 128]; + texdest[24 + x * 64 + y * 128] = texsrc[2 + x * 8 + (y + 4) * 128]; + texdest[26 + x * 64 + y * 128] = texsrc[3 + x * 8 + (y + 4) * 128]; + texdest[48 + x * 64 + y * 128] = texsrc[4 + x * 8 + (y + 4) * 128]; + texdest[50 + x * 64 + y * 128] = texsrc[5 + x * 8 + (y + 4) * 128]; + texdest[56 + x * 64 + y * 128] = texsrc[6 + x * 8 + (y + 4) * 128]; + texdest[58 + x * 64 + y * 128] = texsrc[7 + x * 8 + (y + 4) * 128]; + + texdest[17 + x * 64 + y * 128] = texsrc[0 + x * 8 + (y + 5) * 128]; + texdest[19 + x * 64 + y * 128] = texsrc[1 + x * 8 + (y + 5) * 128]; + texdest[25 + x * 64 + y * 128] = texsrc[2 + x * 8 + (y + 5) * 128]; + texdest[27 + x * 64 + y * 128] = texsrc[3 + x * 8 + (y + 5) * 128]; + texdest[49 + x * 64 + y * 128] = texsrc[4 + x * 8 + (y + 5) * 128]; + texdest[51 + x * 64 + y * 128] = texsrc[5 + x * 8 + (y + 5) * 128]; + texdest[57 + x * 64 + y * 128] = texsrc[6 + x * 8 + (y + 5) * 128]; + texdest[59 + x * 64 + y * 128] = texsrc[7 + x * 8 + (y + 5) * 128]; + + texdest[20 + x * 64 + y * 128] = texsrc[0 + x * 8 + (y + 6) * 128]; + texdest[22 + x * 64 + y * 128] = texsrc[1 + x * 8 + (y + 6) * 128]; + texdest[28 + x * 64 + y * 128] = texsrc[2 + x * 8 + (y + 6) * 128]; + texdest[30 + x * 64 + y * 128] = texsrc[3 + x * 8 + (y + 6) * 128]; + texdest[52 + x * 64 + y * 128] = texsrc[4 + x * 8 + (y + 6) * 128]; + texdest[54 + x * 64 + y * 128] = texsrc[5 + x * 8 + (y + 6) * 128]; + texdest[60 + x * 64 + y * 128] = texsrc[6 + x * 8 + (y + 6) * 128]; + texdest[62 + x * 64 + y * 128] = texsrc[7 + x * 8 + (y + 6) * 128]; + + texdest[21 + x * 64 + y * 128] = texsrc[0 + x * 8 + (y + 7) * 128]; + texdest[23 + x * 64 + y * 128] = texsrc[1 + x * 8 + (y + 7) * 128]; + texdest[29 + x * 64 + y * 128] = texsrc[2 + x * 8 + (y + 7) * 128]; + texdest[31 + x * 64 + y * 128] = texsrc[3 + x * 8 + (y + 7) * 128]; + texdest[53 + x * 64 + y * 128] = texsrc[4 + x * 8 + (y + 7) * 128]; + texdest[55 + x * 64 + y * 128] = texsrc[5 + x * 8 + (y + 7) * 128]; + texdest[61 + x * 64 + y * 128] = texsrc[6 + x * 8 + (y + 7) * 128]; + texdest[63 + x * 64 + y * 128] = texsrc[7 + x * 8 + (y + 7) * 128]; } } - gfxFlushBuffers(); - gfxSwapBuffers(); - gspWaitForVBlank1(); + _drawStart(); + sf2d_draw_texture_scale(tex, 40, 300, 1, -1); + _drawEnd(); } GBAContextStop(&context); GBAContextDeinit(&context); - mappedMemoryFree(videoBuffer, 0); +cleanup: + mappedMemoryFree(renderer.outputBuffer, 0); FSFILE_Close(logFile); + sf2d_free_texture(tex); + sf2d_fini(); + fsExit(); gfxExit(); hidExit(); From a9bc0a9c15d5401efd5fce807a6d9e6d17806cf3 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sun, 23 Aug 2015 17:15:52 -0700 Subject: [PATCH 06/19] All: Correct path to GUI_SRC --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 093f5f178..ca89e4ce0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,8 +28,8 @@ file(GLOB GBA_SRC ${CMAKE_SOURCE_DIR}/src/gba/*.c) file(GLOB GBA_CHEATS_SRC ${CMAKE_SOURCE_DIR}/src/gba/cheats/*.c) file(GLOB GBA_RR_SRC ${CMAKE_SOURCE_DIR}/src/gba/rr/*.c) file(GLOB GBA_SV_SRC ${CMAKE_SOURCE_DIR}/src/gba/supervisor/*.c) -file(GLOB GUI_SRC ${CMAKE_SOURCE_DIR}/src/gui/*.c) file(GLOB UTIL_SRC ${CMAKE_SOURCE_DIR}/src/util/*.[cSs]) +file(GLOB GUI_SRC ${CMAKE_SOURCE_DIR}/src/util/gui/*.c) file(GLOB RENDERER_SRC ${CMAKE_SOURCE_DIR}/src/gba/renderers/*.c) file(GLOB SIO_SRC ${CMAKE_SOURCE_DIR}/src/gba/sio/lockstep.c) file(GLOB THIRD_PARTY_SRC ${CMAKE_SOURCE_DIR}/src/third-party/inih/*.c) From 56dd9c4158d156fbf8d5280bcb35fb261a42942c Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sun, 23 Aug 2015 17:17:43 -0700 Subject: [PATCH 07/19] 3DS: Add raw2c --- src/platform/3ds/CMakeToolchain.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/platform/3ds/CMakeToolchain.txt b/src/platform/3ds/CMakeToolchain.txt index 0cdb7f7e3..d7067d01e 100644 --- a/src/platform/3ds/CMakeToolchain.txt +++ b/src/platform/3ds/CMakeToolchain.txt @@ -34,6 +34,7 @@ set(CMAKE_MODULE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "module link flags") set(CMAKE_SHARED_LINKER_FLAGS ${link_flags} CACHE INTERNAL "shared link flags") set(3DSXTOOL ${toolchain_bin_dir}/3dsxtool) +set(RAW2C ${toolchain_bin_dir}/raw2c) set(3DS ON) add_definitions(-D_3DS -DARM11) From 1b78b2133827584224f210d3ae7027e9289cfc04 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sun, 23 Aug 2015 17:18:28 -0700 Subject: [PATCH 08/19] 3DS: Add GUIFont --- CMakeLists.txt | 7 ++- src/platform/3ds/3ds-vfs.c | 98 ++++++++++++++++++++++++++++++++++++ src/platform/3ds/font.raw | Bin 0 -> 65536 bytes src/platform/3ds/gui-font.c | 65 ++++++++++++++++++++++++ src/platform/3ds/main.c | 50 +++++++++++++++++- 5 files changed, 217 insertions(+), 3 deletions(-) create mode 100644 src/platform/3ds/font.raw create mode 100644 src/platform/3ds/gui-font.c diff --git a/CMakeLists.txt b/CMakeLists.txt index ca89e4ce0..482a8ce09 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -169,10 +169,13 @@ elseif(UNIX) file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/posix/*.c) source_group("POSIX-specific code" FILES ${OS_SRC}) elseif(3DS) + set(M_LIBRARY m) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format") add_definitions(-DCOLOR_16_BIT -DCOLOR_5_6_5) + execute_process(COMMAND ${RAW2C} ${CMAKE_SOURCE_DIR}/src/platform/3ds/font.raw) + include_directories(${CMAKE_BINARY_DIR}) list(APPEND OS_LIB sf2d ctru) - file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/3ds/3ds-*.c) + file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/3ds/*.c ${CMAKE_BINARY_DIR}/font.c) source_group("3DS-specific code" FILES ${OS_SRC}) endif() @@ -443,7 +446,7 @@ if(BUILD_QT) endif() if(3DS) - add_executable(${BINARY_NAME}.elf ${CMAKE_SOURCE_DIR}/src/platform/3ds/main.c) + add_executable(${BINARY_NAME}.elf ${GUI_SRC}) target_link_libraries(${BINARY_NAME}.elf ${BINARY_NAME} m ${OS_LIB}) add_custom_command(TARGET ${BINARY_NAME}.elf POST_BUILD COMMAND ${3DSXTOOL} ${BINARY_NAME}.elf ${BINARY_NAME}.3dsx) endif() diff --git a/src/platform/3ds/3ds-vfs.c b/src/platform/3ds/3ds-vfs.c index 38e7cc55a..d2fc0e545 100644 --- a/src/platform/3ds/3ds-vfs.c +++ b/src/platform/3ds/3ds-vfs.c @@ -6,6 +6,7 @@ #include "3ds-vfs.h" #include "util/memory.h" +#include "util/string.h" struct VFile3DS { struct VFile d; @@ -14,6 +15,20 @@ struct VFile3DS { u64 offset; }; +struct VDirEntry3DS { + struct VDirEntry d; + FS_dirent ent; + char* utf8Name; +}; + +struct VDir3DS { + struct VDir d; + + char* path; + Handle handle; + struct VDirEntry3DS vde; +}; + static bool _vf3dClose(struct VFile* vf); static off_t _vf3dSeek(struct VFile* vf, off_t offset, int whence); static ssize_t _vf3dRead(struct VFile* vf, void* buffer, size_t size); @@ -24,6 +39,13 @@ static void _vf3dTruncate(struct VFile* vf, size_t size); static ssize_t _vf3dSize(struct VFile* vf); static bool _vf3dSync(struct VFile* vf, const void* buffer, size_t size); +static bool _vd3dClose(struct VDir* vd); +static void _vd3dRewind(struct VDir* vd); +static struct VDirEntry* _vd3dListNext(struct VDir* vd); +static struct VFile* _vd3dOpenFile(struct VDir* vd, const char* path, int mode); + +static const char* _vd3deName(struct VDirEntry* vde); + struct VFile* VFileOpen3DS(FS_archive* archive, const char* path, int flags) { struct VFile3DS* vf3d = malloc(sizeof(struct VFile3DS)); if (!vf3d) { @@ -141,3 +163,79 @@ static bool _vf3dSync(struct VFile* vf, const void* buffer, size_t size) { FSFILE_Flush(vf3d->handle); return true; } + +struct VDir* VDirOpen(const char* path) { + struct VDir3DS* vd3d = malloc(sizeof(struct VDir3DS)); + if (!vd3d) { + return 0; + } + + FS_path newPath = FS_makePath(PATH_CHAR, path); + Result res = FSUSER_OpenDirectory(0, &vd3d->handle, sdmcArchive, newPath); + if (res & 0xFFFC03FF) { + free(vd3d); + return 0; + } + + vd3d->path = strdup(path); + + vd3d->d.close = _vd3dClose; + vd3d->d.rewind = _vd3dRewind; + vd3d->d.listNext = _vd3dListNext; //// Crashes here for no good reason + vd3d->d.openFile = _vd3dOpenFile; + + vd3d->vde.d.name = _vd3deName; + + return &vd3d->d; +} + +static bool _vd3dClose(struct VDir* vd) { + struct VDir3DS* vd3d = (struct VDir3DS*) vd; + FSDIR_Close(vd3d->handle); + free(vd3d->path); + if (vd3d->vde.utf8Name) { + free(vd3d->vde.utf8Name); + } + free(vd3d); + return true; +} + +static void _vd3dRewind(struct VDir* vd) { + struct VDir3DS* vd3d = (struct VDir3DS*) vd; + FSDIR_Close(vd3d->handle); + FS_path newPath = FS_makePath(PATH_CHAR, vd3d->path); + FSUSER_OpenDirectory(0, &vd3d->handle, sdmcArchive, newPath); +} + +static struct VDirEntry* _vd3dListNext(struct VDir* vd) { + struct VDir3DS* vd3d = (struct VDir3DS*) vd; + u32 n = 0; + Result res = FSDIR_Read(vd3d->handle, &n, 1, &vd3d->vde.ent); + if (res & 0xFFFC03FF || !n) { + return 0; + } + return &vd3d->vde.d; +} + +static struct VFile* _vd3dOpenFile(struct VDir* vd, const char* path, int mode) { + struct VDir3DS* vd3d = (struct VDir3DS*) vd; + if (!path) { + return 0; + } + const char* dir = vd3d->path; + char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2)); + sprintf(combined, "%s/%s", dir, path); + + struct VFile* file = VFileOpen(combined, mode); + free(combined); + return file; +} + +static const char* _vd3deName(struct VDirEntry* vde) { + struct VDirEntry3DS* vd3de = (struct VDirEntry3DS*) vde; + if (vd3de->utf8Name) { + free(vd3de->utf8Name); + } + vd3de->utf8Name = utf16to8(vd3de->ent.name, sizeof(vd3de->ent.name) / 2); + return vd3de->utf8Name; +} diff --git a/src/platform/3ds/font.raw b/src/platform/3ds/font.raw new file mode 100644 index 0000000000000000000000000000000000000000..aa7abf5a4126107bd10db4505f722a44e691976b GIT binary patch literal 65536 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 LECrSVpH<+0tX?pb literal 0 HcmV?d00001 diff --git a/src/platform/3ds/gui-font.c b/src/platform/3ds/gui-font.c new file mode 100644 index 000000000..5df92ed9e --- /dev/null +++ b/src/platform/3ds/gui-font.c @@ -0,0 +1,65 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "util/gui/font.h" +#include "util/gui/font-metrics.h" +#include "util/png-io.h" +#include "util/vfs.h" +#include "font.h" + +#include + +#define CELL_HEIGHT 16 +#define CELL_WIDTH 16 +#define GLYPH_HEIGHT 12 + +struct GUIFont { + sf2d_texture* tex; +}; + +struct GUIFont* GUIFontCreate(void) { + struct GUIFont* guiFont = malloc(sizeof(struct GUIFont)); + if (!guiFont) { + return 0; + } + guiFont->tex = sf2d_create_texture(256, 128, TEXFMT_RGB5A1, SF2D_PLACE_RAM); + memcpy(guiFont->tex->data, font, font_size); + guiFont->tex->tiled = 1; + return guiFont; +} + +void GUIFontDestroy(struct GUIFont* font) { + sf2d_free_texture(font->tex); + free(font); +} + +int GUIFontHeight(const struct GUIFont* font) { + UNUSED(font); + return GLYPH_HEIGHT; +} + +void GUIFontPrintf(const struct GUIFont* font, int x, int y, enum GUITextAlignment align, uint32_t color, const char* text, ...) { + UNUSED(align); // TODO + char buffer[256]; + va_list args; + va_start(args, text); + int len = vsnprintf(buffer, sizeof(buffer), text, args); + va_end(args); + int i; + for (i = 0; i < len; ++i) { + char c = buffer[i]; + if (c > 0x7F) { + c = 0; + } + struct GUIFontGlyphMetric metric = defaultFontMetrics[c]; + sf2d_draw_texture_part_blend(font->tex, x, y - GLYPH_HEIGHT + metric.padding.top, + (c & 15) * CELL_WIDTH + metric.padding.left, + (c >> 4) * CELL_HEIGHT + metric.padding.top, + CELL_WIDTH - (metric.padding.left + metric.padding.right), + CELL_HEIGHT - (metric.padding.top + metric.padding.bottom), + color); + x += metric.width; + } +} diff --git a/src/platform/3ds/main.c b/src/platform/3ds/main.c index d2d7c88f2..1a212d982 100644 --- a/src/platform/3ds/main.c +++ b/src/platform/3ds/main.c @@ -7,6 +7,9 @@ #include "gba/renderers/video-software.h" #include "gba/supervisor/context.h" #include "gba/video.h" +#include "util/gui.h" +#include "util/gui/file-select.h" +#include "util/gui/font.h" #include "util/memory.h" #include "3ds-vfs.h" @@ -27,6 +30,34 @@ static void _drawEnd(void) { sf2d_swapbuffers(); } +static int _pollInput(void) { + hidScanInput(); + int keys = 0; + int activeKeys = hidKeysHeld(); + if (activeKeys & KEY_X) { + keys |= 1 << GUI_INPUT_CANCEL; + } + if (activeKeys & KEY_B) { + keys |= 1 << GUI_INPUT_BACK; + } + if (activeKeys & KEY_A) { + keys |= 1 << GUI_INPUT_SELECT; + } + if (activeKeys & KEY_LEFT) { + keys |= 1 << GUI_INPUT_LEFT; + } + if (activeKeys & KEY_RIGHT) { + keys |= 1 << GUI_INPUT_RIGHT; + } + if (activeKeys & KEY_UP) { + keys |= 1 << GUI_INPUT_UP; + } + if (activeKeys & KEY_DOWN) { + keys |= 1 << GUI_INPUT_DOWN; + } + return keys; +} + int main() { struct GBAContext context; srvInit(); @@ -46,6 +77,8 @@ int main() { FSUSER_OpenArchive(0, &sdmcArchive); FSUSER_OpenFile(0, &logFile, sdmcArchive, FS_makePath(PATH_CHAR, "/mgba.log"), FS_OPEN_WRITE | FS_OPEN_CREATE, FS_ATTRIBUTE_NONE); + struct GUIFont* font = GUIFontCreate(); + GBAContextInit(&context, 0); struct GBAOptions opts = { .useBios = true, @@ -54,6 +87,7 @@ int main() { }; GBAConfigLoadDefaults(&context.config, &opts); context.gba->logHandler = GBA3DSLog; + context.gba->logLevel = 0; struct GBAVideoSoftwareRenderer renderer; GBAVideoSoftwareRendererCreate(&renderer); @@ -61,7 +95,21 @@ int main() { renderer.outputBufferStride = 256; GBAVideoAssociateRenderer(&context.gba->video, &renderer.d); - GBAContextLoadROM(&context, "/rom.gba", true); + if (!font) { + goto cleanup; + } + + struct GUIParams params = { + 320, 240, + font, _drawStart, _drawEnd, _pollInput + }; + _drawStart(); + GUIFontPrintf(font, 20, 20, GUI_TEXT_LEFT, 0xFFFFFFFF, "Loading..."); + _drawEnd(); + char path[256] = "/rom.gba"; + if (!selectFile(¶ms, "/", path, sizeof(path), "gba") || !GBAContextLoadROM(&context, path, true)) { + goto cleanup; + } GBAContextStart(&context); while (aptMainLoop()) { From 49e66da5c222fd957caf5026f8648ddd3d595f5d Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sun, 23 Aug 2015 19:31:13 -0700 Subject: [PATCH 09/19] 3DS: Fix GUIFontPrintf on hardware --- src/platform/3ds/gui-font.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/platform/3ds/gui-font.c b/src/platform/3ds/gui-font.c index 5df92ed9e..bd241cb92 100644 --- a/src/platform/3ds/gui-font.c +++ b/src/platform/3ds/gui-font.c @@ -54,12 +54,14 @@ void GUIFontPrintf(const struct GUIFont* font, int x, int y, enum GUITextAlignme c = 0; } struct GUIFontGlyphMetric metric = defaultFontMetrics[c]; - sf2d_draw_texture_part_blend(font->tex, x, y - GLYPH_HEIGHT + metric.padding.top, - (c & 15) * CELL_WIDTH + metric.padding.left, - (c >> 4) * CELL_HEIGHT + metric.padding.top, - CELL_WIDTH - (metric.padding.left + metric.padding.right), - CELL_HEIGHT - (metric.padding.top + metric.padding.bottom), - color); + sf2d_draw_texture_part_blend(font->tex, + x - metric.padding.left, + y - GLYPH_HEIGHT, + (c & 15) * CELL_WIDTH, + (c >> 4) * CELL_HEIGHT, + CELL_WIDTH, + CELL_HEIGHT, + color); x += metric.width; } } From d8f77aa62e51c7893e04d2353f84c968bd052bce Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sun, 23 Aug 2015 20:00:23 -0700 Subject: [PATCH 10/19] 3DS: Fix font outline --- src/platform/3ds/font.raw | Bin 65536 -> 65536 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/platform/3ds/font.raw b/src/platform/3ds/font.raw index aa7abf5a4126107bd10db4505f722a44e691976b..05b1436df325f5a4cbc2703202ed694b5fa3d149 100644 GIT binary patch literal 65536 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 j`hCx`t-~S zg8PV!jI4d01ozYP@@eG8&bS#ZPRE_`zB_-InP)J{jNKvkFnD77G;(8S+>92d<1TP{ z($GAfIz?w3>W&z9E%Q8+?|bRkYTK{%3NCYx4y&DU-`i7f<{3OtT@n9}^MBUAR1w0g z9}}`atGPA1UwQwxIQ4#Y6~FiF&ve+M*((IydE45DW$$O!E0yZ=j{ThJuk8Q2s_vJ& zpu5{+5O+pj>BxuZZ_a<_?*4S5{n&@Q&g+bE-D90Ht~3dMUbmDufZz6|9bqMm67V2k;#O`cjm7uJXKLu z3};rsJMig|I~>p)sFl(`j0xtJD$?xI3ldW zQM~#?-J?j(dsWZnK8yM@`uE(Vv+kNTv)}fURWtV|*U5gL*VR0@2WK)WLbh|h_Sk;1 zm^hXE+~w@M`y>3G)!k}O^323a#C_O8)qIF{mt!QiD%2!;jQKT|=kGf({x)%HJ+>Lf z{p>q)=Q`ECzW;@st57%U<@_8M5o`Ch0$VqEoD@|xAALMG8i`<;8chlO`Wf&Pi| z{JnzY3EN`MOrNKlxo1!R{v2`lc^cVKf$sN-Pt2>krDM##MW1w6^~tv5%t$MooXb-& zR@0fEkBl}(g_Tjgr;04}%{Z`%{Jou+bmyH{H9KY9vv8-ZD(FSG)(!>j z%R1QCBX2ROezIqMGOG5On>vok__QMDzGr-*a~1WIQS+X&Q7`ItRhRF&0(la9*)jQe z3b=_~mgjy39TaC6y+eJ|2eYWUhfOSZF~9HS?>p?heGT7!ohlDK&H z%X2-C+fPQ`{QmO2sQ#@wir0PgTI2evHEPRNwmz(2!EnZ%J<2q%{!|hA=rn&@-Te2G zBKQ!Ut>^voOlM?sqFiL;jUg;>~a|&~#MU~i*X)N)~C@^~7zuCAB)9}q2 zHNYBqMc%kml(3u=Q>KgDIlZ}aGK7}<)jr!}zRoz!F(acbi(WxDU(|Jtk>A+A`>g2X znpHjZ@0X{j>edSmT_3%VyjmfU>q%#4WbM&}NmvCepLQtO7yZB_pJ{JYD)~EmYsP33 zxvlRQ{mjZ$)EB*-!z4cI+vh1l$o=W;y*A%D|JcK%nY!yq*lH^=JQj=e z)6j#A9NXVd0!x9Vz*1l-uoPGdECrSVOM#`pQeY{t6j%x@1(pI!fu+DwU@5Q^SPCo!mI6zG zrNB~PDXVd0!x9Vz*1l-uoPGdECrSVOM#`pQeY{t6j%x@1(pI!fu+DwU@5Q^ MSPCo!KC8h00EbAi2LJ#7 literal 65536 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 LECrSVpH<+0tX?pb From 81dffd6a12996deda2d26fb40caca26ab459d970 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sun, 23 Aug 2015 20:28:33 -0700 Subject: [PATCH 11/19] 3DS: Cleanup --- src/platform/3ds/3ds-vfs.c | 15 ++++++++++----- src/platform/3ds/main.c | 2 +- src/util/gui/file-select.c | 6 +++--- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/platform/3ds/3ds-vfs.c b/src/platform/3ds/3ds-vfs.c index d2fc0e545..9875f681b 100644 --- a/src/platform/3ds/3ds-vfs.c +++ b/src/platform/3ds/3ds-vfs.c @@ -185,6 +185,7 @@ struct VDir* VDirOpen(const char* path) { vd3d->d.openFile = _vd3dOpenFile; vd3d->vde.d.name = _vd3deName; + vd3d->vde.utf8Name = 0; return &vd3d->d; } @@ -210,8 +211,13 @@ static void _vd3dRewind(struct VDir* vd) { static struct VDirEntry* _vd3dListNext(struct VDir* vd) { struct VDir3DS* vd3d = (struct VDir3DS*) vd; u32 n = 0; - Result res = FSDIR_Read(vd3d->handle, &n, 1, &vd3d->vde.ent); - if (res & 0xFFFC03FF || !n) { + memset(&vd3d->vde.ent, 0, sizeof(vd3d->vde.ent)); + if (vd3d->vde.utf8Name) { + free(vd3d->vde.utf8Name); + vd3d->vde.utf8Name = 0; + }; + FSDIR_Read(vd3d->handle, &n, 1, &vd3d->vde.ent); + if (!n) { return 0; } return &vd3d->vde.d; @@ -233,9 +239,8 @@ static struct VFile* _vd3dOpenFile(struct VDir* vd, const char* path, int mode) static const char* _vd3deName(struct VDirEntry* vde) { struct VDirEntry3DS* vd3de = (struct VDirEntry3DS*) vde; - if (vd3de->utf8Name) { - free(vd3de->utf8Name); + if (!vd3de->utf8Name) { + vd3de->utf8Name = utf16to8(vd3de->ent.name, sizeof(vd3de->ent.name) / 2); } - vd3de->utf8Name = utf16to8(vd3de->ent.name, sizeof(vd3de->ent.name) / 2); return vd3de->utf8Name; } diff --git a/src/platform/3ds/main.c b/src/platform/3ds/main.c index 1a212d982..e02cbaed9 100644 --- a/src/platform/3ds/main.c +++ b/src/platform/3ds/main.c @@ -104,7 +104,7 @@ int main() { font, _drawStart, _drawEnd, _pollInput }; _drawStart(); - GUIFontPrintf(font, 20, 20, GUI_TEXT_LEFT, 0xFFFFFFFF, "Loading..."); + GUIFontPrintf(font, 0, GUIFontHeight(font), GUI_TEXT_LEFT, 0xFFFFFFFF, "Loading..."); _drawEnd(); char path[256] = "/rom.gba"; if (!selectFile(¶ms, "/", path, sizeof(path), "gba") || !GBAContextLoadROM(&context, path, true)) { diff --git a/src/util/gui/file-select.c b/src/util/gui/file-select.c index 05a0fbb67..e88eee5a7 100644 --- a/src/util/gui/file-select.c +++ b/src/util/gui/file-select.c @@ -12,7 +12,7 @@ DECLARE_VECTOR(FileList, char*); DEFINE_VECTOR(FileList, char*); -void _cleanFiles(struct FileList* currentFiles) { +static void _cleanFiles(struct FileList* currentFiles) { size_t size = FileListSize(currentFiles); size_t i; for (i = 0; i < size; ++i) { @@ -21,7 +21,7 @@ void _cleanFiles(struct FileList* currentFiles) { FileListClear(currentFiles); } -void _upDirectory(char* currentPath) { +static void _upDirectory(char* currentPath) { char* end = strrchr(currentPath, '/'); if (!end) { return; @@ -33,7 +33,7 @@ void _upDirectory(char* currentPath) { // TODO: What if there was a trailing slash? } -bool _refreshDirectory(const char* currentPath, struct FileList* currentFiles) { +static bool _refreshDirectory(const char* currentPath, struct FileList* currentFiles) { _cleanFiles(currentFiles); struct VDir* dir = VDirOpen(currentPath); From 85298a0a54ed4ebdee218af29a7220ddf1697cb4 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sun, 23 Aug 2015 23:51:57 -0700 Subject: [PATCH 12/19] 3DS: use GX_SetDisplayTransfer to tile pixels --- src/platform/3ds/main.c | 84 +++-------------------------------------- 1 file changed, 5 insertions(+), 79 deletions(-) diff --git a/src/platform/3ds/main.c b/src/platform/3ds/main.c index e02cbaed9..9eff4ac47 100644 --- a/src/platform/3ds/main.c +++ b/src/platform/3ds/main.c @@ -68,6 +68,7 @@ int main() { sf2d_init(); sf2d_set_clear_color(0); sf2d_texture* tex = sf2d_create_texture(256, 256, TEXFMT_RGB565, SF2D_PLACE_RAM); + memset(tex->data, 0, 256 * 256 * 2); sdmcArchive = (FS_archive) { ARCH_SDMC, @@ -119,86 +120,11 @@ int main() { break; } GBAContextFrame(&context, activeKeys); - uint32_t* texdest = (uint32_t*) tex->data; - uint32_t* texsrc = (uint32_t*) renderer.outputBuffer; - int x, y; - for (y = 0; y < VIDEO_VERTICAL_PIXELS; y += 8) { - for (x = 0; x < 16; ++x) { - texdest[ 0 + x * 64 + y * 128] = texsrc[0 + x * 8 + (y + 0) * 128]; - texdest[ 2 + x * 64 + y * 128] = texsrc[1 + x * 8 + (y + 0) * 128]; - texdest[ 8 + x * 64 + y * 128] = texsrc[2 + x * 8 + (y + 0) * 128]; - texdest[10 + x * 64 + y * 128] = texsrc[3 + x * 8 + (y + 0) * 128]; - texdest[32 + x * 64 + y * 128] = texsrc[4 + x * 8 + (y + 0) * 128]; - texdest[34 + x * 64 + y * 128] = texsrc[5 + x * 8 + (y + 0) * 128]; - texdest[40 + x * 64 + y * 128] = texsrc[6 + x * 8 + (y + 0) * 128]; - texdest[42 + x * 64 + y * 128] = texsrc[7 + x * 8 + (y + 0) * 128]; - - texdest[ 1 + x * 64 + y * 128] = texsrc[0 + x * 8 + (y + 1) * 128]; - texdest[ 3 + x * 64 + y * 128] = texsrc[1 + x * 8 + (y + 1) * 128]; - texdest[ 9 + x * 64 + y * 128] = texsrc[2 + x * 8 + (y + 1) * 128]; - texdest[11 + x * 64 + y * 128] = texsrc[3 + x * 8 + (y + 1) * 128]; - texdest[33 + x * 64 + y * 128] = texsrc[4 + x * 8 + (y + 1) * 128]; - texdest[35 + x * 64 + y * 128] = texsrc[5 + x * 8 + (y + 1) * 128]; - texdest[41 + x * 64 + y * 128] = texsrc[6 + x * 8 + (y + 1) * 128]; - texdest[43 + x * 64 + y * 128] = texsrc[7 + x * 8 + (y + 1) * 128]; - - texdest[ 4 + x * 64 + y * 128] = texsrc[0 + x * 8 + (y + 2) * 128]; - texdest[ 6 + x * 64 + y * 128] = texsrc[1 + x * 8 + (y + 2) * 128]; - texdest[12 + x * 64 + y * 128] = texsrc[2 + x * 8 + (y + 2) * 128]; - texdest[14 + x * 64 + y * 128] = texsrc[3 + x * 8 + (y + 2) * 128]; - texdest[36 + x * 64 + y * 128] = texsrc[4 + x * 8 + (y + 2) * 128]; - texdest[38 + x * 64 + y * 128] = texsrc[5 + x * 8 + (y + 2) * 128]; - texdest[44 + x * 64 + y * 128] = texsrc[6 + x * 8 + (y + 2) * 128]; - texdest[46 + x * 64 + y * 128] = texsrc[7 + x * 8 + (y + 2) * 128]; - - texdest[ 5 + x * 64 + y * 128] = texsrc[0 + x * 8 + (y + 3) * 128]; - texdest[ 7 + x * 64 + y * 128] = texsrc[1 + x * 8 + (y + 3) * 128]; - texdest[13 + x * 64 + y * 128] = texsrc[2 + x * 8 + (y + 3) * 128]; - texdest[15 + x * 64 + y * 128] = texsrc[3 + x * 8 + (y + 3) * 128]; - texdest[37 + x * 64 + y * 128] = texsrc[4 + x * 8 + (y + 3) * 128]; - texdest[39 + x * 64 + y * 128] = texsrc[5 + x * 8 + (y + 3) * 128]; - texdest[45 + x * 64 + y * 128] = texsrc[6 + x * 8 + (y + 3) * 128]; - texdest[47 + x * 64 + y * 128] = texsrc[7 + x * 8 + (y + 3) * 128]; - - texdest[16 + x * 64 + y * 128] = texsrc[0 + x * 8 + (y + 4) * 128]; - texdest[18 + x * 64 + y * 128] = texsrc[1 + x * 8 + (y + 4) * 128]; - texdest[24 + x * 64 + y * 128] = texsrc[2 + x * 8 + (y + 4) * 128]; - texdest[26 + x * 64 + y * 128] = texsrc[3 + x * 8 + (y + 4) * 128]; - texdest[48 + x * 64 + y * 128] = texsrc[4 + x * 8 + (y + 4) * 128]; - texdest[50 + x * 64 + y * 128] = texsrc[5 + x * 8 + (y + 4) * 128]; - texdest[56 + x * 64 + y * 128] = texsrc[6 + x * 8 + (y + 4) * 128]; - texdest[58 + x * 64 + y * 128] = texsrc[7 + x * 8 + (y + 4) * 128]; - - texdest[17 + x * 64 + y * 128] = texsrc[0 + x * 8 + (y + 5) * 128]; - texdest[19 + x * 64 + y * 128] = texsrc[1 + x * 8 + (y + 5) * 128]; - texdest[25 + x * 64 + y * 128] = texsrc[2 + x * 8 + (y + 5) * 128]; - texdest[27 + x * 64 + y * 128] = texsrc[3 + x * 8 + (y + 5) * 128]; - texdest[49 + x * 64 + y * 128] = texsrc[4 + x * 8 + (y + 5) * 128]; - texdest[51 + x * 64 + y * 128] = texsrc[5 + x * 8 + (y + 5) * 128]; - texdest[57 + x * 64 + y * 128] = texsrc[6 + x * 8 + (y + 5) * 128]; - texdest[59 + x * 64 + y * 128] = texsrc[7 + x * 8 + (y + 5) * 128]; - - texdest[20 + x * 64 + y * 128] = texsrc[0 + x * 8 + (y + 6) * 128]; - texdest[22 + x * 64 + y * 128] = texsrc[1 + x * 8 + (y + 6) * 128]; - texdest[28 + x * 64 + y * 128] = texsrc[2 + x * 8 + (y + 6) * 128]; - texdest[30 + x * 64 + y * 128] = texsrc[3 + x * 8 + (y + 6) * 128]; - texdest[52 + x * 64 + y * 128] = texsrc[4 + x * 8 + (y + 6) * 128]; - texdest[54 + x * 64 + y * 128] = texsrc[5 + x * 8 + (y + 6) * 128]; - texdest[60 + x * 64 + y * 128] = texsrc[6 + x * 8 + (y + 6) * 128]; - texdest[62 + x * 64 + y * 128] = texsrc[7 + x * 8 + (y + 6) * 128]; - - texdest[21 + x * 64 + y * 128] = texsrc[0 + x * 8 + (y + 7) * 128]; - texdest[23 + x * 64 + y * 128] = texsrc[1 + x * 8 + (y + 7) * 128]; - texdest[29 + x * 64 + y * 128] = texsrc[2 + x * 8 + (y + 7) * 128]; - texdest[31 + x * 64 + y * 128] = texsrc[3 + x * 8 + (y + 7) * 128]; - texdest[53 + x * 64 + y * 128] = texsrc[4 + x * 8 + (y + 7) * 128]; - texdest[55 + x * 64 + y * 128] = texsrc[5 + x * 8 + (y + 7) * 128]; - texdest[61 + x * 64 + y * 128] = texsrc[6 + x * 8 + (y + 7) * 128]; - texdest[63 + x * 64 + y * 128] = texsrc[7 + x * 8 + (y + 7) * 128]; - } - } + GSPGPU_FlushDataCache(0, renderer.outputBuffer, 256 * VIDEO_VERTICAL_PIXELS * 2); + GX_SetDisplayTransfer(0, renderer.outputBuffer, GX_BUFFER_DIM(256, VIDEO_VERTICAL_PIXELS), tex->data, GX_BUFFER_DIM(256, VIDEO_VERTICAL_PIXELS), 0x000002202); + gspWaitForPPF(); _drawStart(); - sf2d_draw_texture_scale(tex, 40, 300, 1, -1); + sf2d_draw_texture_scale(tex, 40, 296, 1, -1); _drawEnd(); } From fb82257d03d8ad01b2353513f11981308ee47126 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Mon, 24 Aug 2015 19:18:32 -0700 Subject: [PATCH 13/19] 3DS: Use newlib fs functions unless told otherwise --- CMakeLists.txt | 6 ++++++ src/platform/3ds/3ds-vfs.c | 2 ++ src/platform/3ds/main.c | 2 ++ src/util/vfs.c | 2 +- 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 482a8ce09..9b23d8327 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -176,6 +176,12 @@ elseif(3DS) include_directories(${CMAKE_BINARY_DIR}) list(APPEND OS_LIB sf2d ctru) file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/3ds/*.c ${CMAKE_BINARY_DIR}/font.c) + if(USE_VFS_3DS) + add_definitions(-DUSE_VFS_3DS) + else() + add_definitions(-DUSE_VFS_FILE) + list(APPEND VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-file.c ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-dirent.c) + endif() source_group("3DS-specific code" FILES ${OS_SRC}) endif() diff --git a/src/platform/3ds/3ds-vfs.c b/src/platform/3ds/3ds-vfs.c index 9875f681b..0538b846a 100644 --- a/src/platform/3ds/3ds-vfs.c +++ b/src/platform/3ds/3ds-vfs.c @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "3ds-vfs.h" +#ifdef USE_VFS_3DS #include "util/memory.h" #include "util/string.h" @@ -244,3 +245,4 @@ static const char* _vd3deName(struct VDirEntry* vde) { } return vd3de->utf8Name; } +#endif diff --git a/src/platform/3ds/main.c b/src/platform/3ds/main.c index 9eff4ac47..994bff8af 100644 --- a/src/platform/3ds/main.c +++ b/src/platform/3ds/main.c @@ -64,6 +64,7 @@ int main() { aptInit(); hidInit(0); fsInit(); + sdmcInit(); sf2d_init(); sf2d_set_clear_color(0); @@ -139,6 +140,7 @@ cleanup: sf2d_free_texture(tex); sf2d_fini(); + sdmcExit(); fsExit(); gfxExit(); hidExit(); diff --git a/src/util/vfs.c b/src/util/vfs.c index ac282ec23..0ceea78e9 100644 --- a/src/util/vfs.c +++ b/src/util/vfs.c @@ -34,7 +34,7 @@ struct VFile* VFileOpen(const char* path, int flags) { break; } return VFileFOpen(path, chflags); -#elif defined(_3DS) +#elif defined(USE_VFS_3DS) int ctrFlags = FS_OPEN_READ; switch (flags & O_ACCMODE) { case O_WRONLY: From 762ddb096d103d2e8947c453dc0a1375764e83f2 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Mon, 24 Aug 2015 19:35:44 -0700 Subject: [PATCH 14/19] GUI: Handle paths starting with / properly --- src/util/gui/file-select.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/util/gui/file-select.c b/src/util/gui/file-select.c index e88eee5a7..8e40372e0 100644 --- a/src/util/gui/file-select.c +++ b/src/util/gui/file-select.c @@ -26,6 +26,10 @@ static void _upDirectory(char* currentPath) { if (!end) { return; } + if (end == currentPath) { + end[1] = '\0'; + return; + } end[0] = '\0'; if (end[1]) { return; @@ -85,7 +89,12 @@ bool selectFile(const struct GUIParams* params, const char* basePath, char* outP return false; } if (newInput & (1 << GUI_INPUT_SELECT)) { - snprintf(currentPath, sizeof(currentPath), "%s%c%s", currentPath, '/', *FileListGetPointer(¤tFiles, fileIndex)); + size_t len = strlen(currentPath); + const char* sep = PATH_SEP; + if (currentPath[len - 1] == *sep) { + sep = ""; + } + snprintf(currentPath, sizeof(currentPath), "%s%s%s", currentPath, sep, *FileListGetPointer(¤tFiles, fileIndex)); if (!_refreshDirectory(currentPath, ¤tFiles)) { strncpy(outPath, currentPath, outLen); return true; From 2236b27600f499406e3de3eec9079e28042f05e6 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Mon, 24 Aug 2015 19:53:00 -0700 Subject: [PATCH 15/19] 3DS: Return to menu on exit --- src/platform/3ds/main.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/src/platform/3ds/main.c b/src/platform/3ds/main.c index 994bff8af..73599817b 100644 --- a/src/platform/3ds/main.c +++ b/src/platform/3ds/main.c @@ -105,31 +105,35 @@ int main() { 320, 240, font, _drawStart, _drawEnd, _pollInput }; - _drawStart(); - GUIFontPrintf(font, 0, GUIFontHeight(font), GUI_TEXT_LEFT, 0xFFFFFFFF, "Loading..."); - _drawEnd(); - char path[256] = "/rom.gba"; - if (!selectFile(¶ms, "/", path, sizeof(path), "gba") || !GBAContextLoadROM(&context, path, true)) { - goto cleanup; - } - GBAContextStart(&context); while (aptMainLoop()) { - hidScanInput(); - int activeKeys = hidKeysHeld() & 0x3FF; - if (hidKeysDown() & KEY_X) { + char path[256]; + if (!selectFile(¶ms, "/", path, sizeof(path), "gba")) { break; } - GBAContextFrame(&context, activeKeys); - GSPGPU_FlushDataCache(0, renderer.outputBuffer, 256 * VIDEO_VERTICAL_PIXELS * 2); - GX_SetDisplayTransfer(0, renderer.outputBuffer, GX_BUFFER_DIM(256, VIDEO_VERTICAL_PIXELS), tex->data, GX_BUFFER_DIM(256, VIDEO_VERTICAL_PIXELS), 0x000002202); - gspWaitForPPF(); _drawStart(); - sf2d_draw_texture_scale(tex, 40, 296, 1, -1); + GUIFontPrintf(font, 130, (GUIFontHeight(font) + 240) / 2, GUI_TEXT_LEFT, 0xFFFFFFFF, "Loading..."); _drawEnd(); + if (!GBAContextLoadROM(&context, path, true)) { + continue; + } + GBAContextStart(&context); + while (aptMainLoop()) { + hidScanInput(); + int activeKeys = hidKeysHeld() & 0x3FF; + if (hidKeysDown() & KEY_X) { + break; + } + GBAContextFrame(&context, activeKeys); + GX_SetDisplayTransfer(0, renderer.outputBuffer, GX_BUFFER_DIM(256, VIDEO_VERTICAL_PIXELS), tex->data, GX_BUFFER_DIM(256, VIDEO_VERTICAL_PIXELS), 0x000002202); + GSPGPU_FlushDataCache(0, tex->data, 256 * VIDEO_VERTICAL_PIXELS * 2); + gspWaitForPPF(); + _drawStart(); + sf2d_draw_texture_scale(tex, 40, 296, 1, -1); + _drawEnd(); + } + GBAContextStop(&context); } - - GBAContextStop(&context); GBAContextDeinit(&context); cleanup: From 5ee5d9f78b3a94010b6e2e43fda014061d907d25 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Mon, 24 Aug 2015 21:43:08 -0700 Subject: [PATCH 16/19] GBA: GBALoadROM can fail --- src/gba/gba.c | 5 +++-- src/gba/gba.h | 2 +- src/gba/supervisor/context.c | 7 +++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/gba/gba.c b/src/gba/gba.c index f10ec8c6c..241291d55 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -388,7 +388,7 @@ void GBADetachDebugger(struct GBA* gba) { gba->cpu->components[GBA_COMPONENT_DEBUGGER] = 0; } -void GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char* fname) { +bool GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char* fname) { GBAUnloadROM(gba); gba->romVf = vf; gba->pristineRomSize = vf->size(vf); @@ -399,7 +399,7 @@ void GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char gba->pristineRom = vf->map(vf, gba->pristineRomSize, MAP_READ); if (!gba->pristineRom) { GBALog(gba, GBA_LOG_WARN, "Couldn't map ROM"); - return; + return false; } gba->yankedRomSize = 0; gba->memory.rom = gba->pristineRom; @@ -409,6 +409,7 @@ void GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize); GBASavedataInit(&gba->memory.savedata, sav); GBAHardwareInit(&gba->memory.hw, &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1]); + return true; // TODO: error check } diff --git a/src/gba/gba.h b/src/gba/gba.h index e472a14ac..f4f89e5dd 100644 --- a/src/gba/gba.h +++ b/src/gba/gba.h @@ -166,7 +166,7 @@ void GBASetBreakpoint(struct GBA* gba, struct ARMComponent* component, uint32_t uint32_t* opcode); void GBAClearBreakpoint(struct GBA* gba, uint32_t address, enum ExecutionMode mode, uint32_t opcode); -void GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char* fname); +bool GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char* fname); void GBAYankROM(struct GBA* gba); void GBAUnloadROM(struct GBA* gba); void GBALoadBIOS(struct GBA* gba, struct VFile* vf); diff --git a/src/gba/supervisor/context.c b/src/gba/supervisor/context.c index 6a42be653..9351f643e 100644 --- a/src/gba/supervisor/context.c +++ b/src/gba/supervisor/context.c @@ -114,13 +114,16 @@ bool GBAContextLoadBIOSFromVFile(struct GBAContext* context, struct VFile* bios) bool GBAContextStart(struct GBAContext* context) { struct GBAOptions opts = {}; - GBAConfigMap(&context->config, &opts); if (context->renderer) { GBAVideoAssociateRenderer(&context->gba->video, context->renderer); } - GBALoadROM(context->gba, context->rom, context->save, 0); + if (!GBALoadROM(context->gba, context->rom, context->save, 0)) { + return false; + } + + GBAConfigMap(&context->config, &opts); if (opts.useBios && context->bios) { GBALoadBIOS(context->gba, context->bios); } From 86c7b478e207ce5c9d05c14141d4abfb47048898 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Mon, 24 Aug 2015 21:43:25 -0700 Subject: [PATCH 17/19] 3DS: Skip run if the GBA context fails to start --- src/platform/3ds/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/platform/3ds/main.c b/src/platform/3ds/main.c index 73599817b..ae74fa026 100644 --- a/src/platform/3ds/main.c +++ b/src/platform/3ds/main.c @@ -117,7 +117,9 @@ int main() { if (!GBAContextLoadROM(&context, path, true)) { continue; } - GBAContextStart(&context); + if (!GBAContextStart(&context)) { + continue; + } while (aptMainLoop()) { hidScanInput(); int activeKeys = hidKeysHeld() & 0x3FF; From 0cc32d98fb2dee03f519fa59c059c55a2d9fbb5a Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Mon, 24 Aug 2015 22:11:12 -0700 Subject: [PATCH 18/19] GUI: Add key repeat --- src/util/gui.h | 2 ++ src/util/gui/file-select.c | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/util/gui.h b/src/util/gui.h index d8b2bb058..f2d267655 100644 --- a/src/util/gui.h +++ b/src/util/gui.h @@ -20,6 +20,8 @@ enum GUIInput { GUI_INPUT_DOWN, GUI_INPUT_LEFT, GUI_INPUT_RIGHT, + + GUI_INPUT_MAX }; struct GUIParams { diff --git a/src/util/gui/file-select.c b/src/util/gui/file-select.c index 8e40372e0..0f25d6db5 100644 --- a/src/util/gui/file-select.c +++ b/src/util/gui/file-select.c @@ -58,7 +58,6 @@ static bool _refreshDirectory(const char* currentPath, struct FileList* currentF bool selectFile(const struct GUIParams* params, const char* basePath, char* outPath, size_t outLen, const char* suffix) { char currentPath[256]; strncpy(currentPath, basePath, sizeof(currentPath)); - int oldInput = -1; size_t fileIndex = 0; size_t start = 0; @@ -66,10 +65,21 @@ bool selectFile(const struct GUIParams* params, const char* basePath, char* outP FileListInit(¤tFiles, 0); _refreshDirectory(currentPath, ¤tFiles); + int inputHistory[GUI_INPUT_MAX] = { 0 }; + while (true) { int input = params->pollInput(); - int newInput = input & (oldInput ^ input); - oldInput = input; + int newInput = 0; + for (int i = 0; i < GUI_INPUT_MAX; ++i) { + if (input & (1 << i)) { + ++inputHistory[i]; + } else { + inputHistory[i] = -1; + } + if (!inputHistory[i] || (inputHistory[i] >= 30 && !(inputHistory[i] % 6))) { + newInput |= (1 << i); + } + } if (newInput & (1 << GUI_INPUT_UP) && fileIndex > 0) { --fileIndex; From 6f9eb5343e6d6459df3d080fa7fbab91fa9e042a Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Mon, 24 Aug 2015 22:21:21 -0700 Subject: [PATCH 19/19] GUI: Fix some font metrics --- src/util/gui/font-metrics.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/gui/font-metrics.c b/src/util/gui/font-metrics.c index 24fd2d169..332339109 100644 --- a/src/util/gui/font-metrics.c +++ b/src/util/gui/font-metrics.c @@ -49,7 +49,7 @@ struct GUIFontGlyphMetric defaultFontMetrics[128] = { { 6, 11, { 2, 5, 3, 5 }}, // 0x28 "(" { 6, 11, { 2, 5, 3, 5 }}, // 0x29 ")" { 8, 7, { 2, 4, 5, 4 }}, // 0x2A "*" - { 10, 9, { 3, 0, 4, 0 }}, // 0x2B "+" + { 10, 9, { 3, 3, 4, 3 }}, // 0x2B "+" { 4, 5, { 9, 6, 2, 6 }}, // 0x2C "," { 6, 3, { 6, 4, 7, 4 }}, // 0x2D "-" { 4, 4, { 9, 6, 3, 6 }}, // 0x2E "." @@ -115,7 +115,7 @@ struct GUIFontGlyphMetric defaultFontMetrics[128] = { { 7, 13, { 2, 5, 1, 4 }}, // 0x6A "j" { 8, 11, { 2, 4, 3, 4 }}, // 0x6B "k" { 5, 11, { 2, 5, 3, 6 }}, // 0x6C "l" - { 10, 7, { 6, 2, 3, 2 }}, // 0x6D "m" + { 10, 7, { 6, 3, 3, 3 }}, // 0x6D "m" { 8, 7, { 6, 4, 3, 4 }}, // 0x6E "n" { 8, 7, { 6, 4, 3, 4 }}, // 0x6F "o" { 8, 9, { 6, 4, 1, 4 }}, // 0x70 "p"