all repos — mgba @ 94e329a58cf3cef6bc6d3ce39944f4847e3a44a0

mGBA Game Boy Advance Emulator

Wii: Add file selector from PSP2 port
Jeffrey Pfau jeffrey@endrift.com
Thu, 06 Aug 2015 15:29:46 -0700
commit

94e329a58cf3cef6bc6d3ce39944f4847e3a44a0

parent

8dd6a822010619310836f65f42cd67ae756aae7b

M CMakeLists.txtCMakeLists.txt

@@ -28,6 +28,7 @@ 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 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)

@@ -163,9 +164,10 @@ list(APPEND VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-fd.c ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-dirent.c)

file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/posix/*.c) source_group("POSIX-specific code" FILES ${OS_SRC}) elseif(WII) - list(APPEND VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-file.c) + list(APPEND VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-file.c ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-dirent.c) add_definitions(-DCOLOR_16_BIT -DCOLOR_5_6_5 -DUSE_VFS_FILE) - file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/wii/wii-*.c) + include_directories(${CMAKE_BINARY_DIR}) + file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/wii/*.c) list(APPEND OS_LIB fat ogc) source_group("Wii-specific code" FILES ${OS_SRC}) endif()

@@ -192,7 +194,8 @@ endif()

if(WII) add_definitions(-U__STRICT_ANSI__) - add_executable(${BINARY_NAME}.elf ${CMAKE_SOURCE_DIR}/src/platform/wii/main.c) + execute_process(COMMAND ${RAW2C} ${CMAKE_SOURCE_DIR}/src/platform/wii/font.tpl OUTPUT_QUIET ERROR_QUIET) + add_executable(${BINARY_NAME}.elf ${GUI_SRC} ${CMAKE_BINARY_DIR}/font.c) target_link_libraries(${BINARY_NAME}.elf ${BINARY_NAME} ${OS_LIB}) add_custom_command(TARGET ${BINARY_NAME}.elf POST_BUILD COMMAND ${ELF2DOL} ${BINARY_NAME}.elf ${BINARY_NAME}.dol) endif()
M src/platform/wii/CMakeToolchain.txtsrc/platform/wii/CMakeToolchain.txt

@@ -34,6 +34,8 @@ 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(ELF2DOL ${toolchain_bin_dir}/elf2dol) +set(GXTEXCONV ${toolchain_bin_dir}/gxtexconv) +set(RAW2C ${toolchain_bin_dir}/raw2c) set(WII ON) add_definitions(-DGEKKO)
A src/platform/wii/gui-font.c

@@ -0,0 +1,87 @@

+/* 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 "font.h" + +#include <ogc/tpl.h> + +#define GLYPH_HEIGHT 11 +#define GLYPH_WIDTH 14 +#define FONT_TRACKING 10 +#define CELL_HEIGHT 16 +#define CELL_WIDTH 16 + +struct GUIFont { + TPLFile tdf; +}; + +struct GUIFont* GUIFontCreate(void) { + struct GUIFont* guiFont = malloc(sizeof(struct GUIFont)); + if (!guiFont) { + return 0; + } + + // libogc's TPL code modifies and frees this itself... + void* fontTpl = memalign(32, font_size); + if (!fontTpl) { + free(guiFont); + return 0; + } + memcpy(fontTpl, font, font_size); + TPL_OpenTPLFromMemory(&guiFont->tdf, fontTpl, font_size); + return guiFont; +} + +void GUIFontDestroy(struct GUIFont* font) { + TPL_CloseTPLFile(&font->tdf); + 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; + GXTexObj tex; + // Grumble grumble, libogc is bad about const-correctness + struct GUIFont* ncfont = font; + TPL_GetTexture(&ncfont->tdf, 0, &tex); + GX_LoadTexObj(&tex, GX_TEXMAP0); + + GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_NOOP); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); + + for (i = 0; i < len; ++i) { + char c = buffer[i]; + if (c > 0x7F) { + c = 0; + } + s16 tx = (c & 15) * CELL_WIDTH + ((CELL_WIDTH - GLYPH_WIDTH) >> 1); + s16 ty = (c >> 4) * CELL_HEIGHT + ((CELL_HEIGHT - GLYPH_HEIGHT) >> 1) - 1; + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + GX_Position2s16(x, y - GLYPH_HEIGHT); + GX_TexCoord2f32(tx / 256.f, ty / 128.f); + + GX_Position2s16(x + GLYPH_WIDTH, y - GLYPH_HEIGHT); + GX_TexCoord2f32((tx + CELL_WIDTH) / 256.f, ty / 128.f); + + GX_Position2s16(x + GLYPH_WIDTH, y); + GX_TexCoord2f32((tx + CELL_WIDTH) / 256.f, (ty + CELL_HEIGHT) / 128.f); + + GX_Position2s16(x, y); + GX_TexCoord2f32(tx / 256.f, (ty + CELL_HEIGHT) / 128.f); + GX_End(); + x += FONT_TRACKING; + } +}
M src/platform/wii/main.csrc/platform/wii/main.c

@@ -16,6 +16,9 @@ #include "gba/renderers/video-software.h"

#include "gba/serialize.h" #include "gba/supervisor/overrides.h" #include "gba/video.h" +#include "util/gui.h" +#include "util/gui/file-select.h" +#include "util/gui/font.h" #include "util/vfs.h" #define SAMPLES 1024

@@ -26,6 +29,10 @@ static bool GBAWiiLoadGame(const char* path);

static void _postVideoFrame(struct GBAAVStream*, struct GBAVideoRenderer* renderer); static void _audioDMA(void); + +static void _drawStart(void); +static void _drawEnd(void); +static int _pollInput(void); static struct GBA gba; static struct ARMCore cpu;

@@ -45,6 +52,8 @@

static struct GBAStereoSample audioBuffer[3][SAMPLES] __attribute__((__aligned__(32))); static volatile size_t audioBufferSize = 0; static volatile int currentAudioBuffer = 0; + +static struct GUIFont* font; int main() { VIDEO_Init();

@@ -108,8 +117,6 @@ GX_InvVtxCache();

GX_InvalidateTexAll(); Mtx44 proj; - guOrtho(proj, 0, VIDEO_VERTICAL_PIXELS, 0, VIDEO_HORIZONTAL_PIXELS, 0, 300); - GX_LoadProjectionMtx(proj, GX_ORTHOGRAPHIC); guVector cam = { 0.0f, 0.0f, 0.0f }; guVector up = { 0.0f, 1.0f, 0.0f };

@@ -125,6 +132,8 @@ texmem = memalign(32, 256 * 256 * BYTES_PER_PIXEL);

memset(texmem, 0, 256 * 256 * BYTES_PER_PIXEL); GX_InitTexObj(&tex, texmem, 256, 256, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE); + font = GUIFontCreate(); + fatInitDefault(); logfile = fopen("/mgba.log", "w");

@@ -154,9 +163,22 @@ blip_set_rates(gba.audio.left, GBA_ARM7TDMI_FREQUENCY, 48000);

blip_set_rates(gba.audio.right, GBA_ARM7TDMI_FREQUENCY, 48000); #endif - if (!GBAWiiLoadGame("/rom.gba")) { + char path[256]; + guOrtho(proj, 0, 240, 0, 400, 0, 300); + GX_LoadProjectionMtx(proj, GX_ORTHOGRAPHIC); + + struct GUIParams params = { + 400, 240, + font, _drawStart, _drawEnd, _pollInput + }; + if (!selectFile(&params, "sd:", path, sizeof(path), "gba") || !GBAWiiLoadGame(path)) { + free(renderer.outputBuffer); + GUIFontDestroy(font); return 1; } + + guOrtho(proj, 0, VIDEO_VERTICAL_PIXELS, 0, VIDEO_HORIZONTAL_PIXELS, 0, 300); + GX_LoadProjectionMtx(proj, GX_ORTHOGRAPHIC); while (true) { #if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF

@@ -224,6 +246,9 @@

rom->close(rom); save->close(save); + free(renderer.outputBuffer); + GUIFontDestroy(font); + return 0; }

@@ -243,10 +268,10 @@ }

} DCFlushRange(texdest, 256 * 256 * BYTES_PER_PIXEL); - GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE); - GX_SetColorUpdate(GX_TRUE); + _drawStart(); - GX_SetViewport(0, 0, mode->fbWidth, mode->efbHeight, 0, 1); + GX_SetBlendMode(GX_BM_NONE, GX_BL_ONE, GX_BL_ZERO, GX_LO_SET); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_S16, 0); GX_InvalidateTexAll(); GX_LoadTexObj(&tex, GX_TEXMAP0);

@@ -264,16 +289,14 @@ GX_Position2s16(0, 0);

GX_TexCoord2s16(0, 0); GX_End(); - GX_DrawDone(); - - whichFb = !whichFb; - - GX_CopyDisp(framebuffer[whichFb], GX_TRUE); - VIDEO_SetNextFramebuffer(framebuffer[whichFb]); - VIDEO_Flush(); + _drawEnd(); } bool GBAWiiLoadGame(const char* path) { + _drawStart(); + GUIFontPrintf(font, 0, 30, GUI_TEXT_CENTER, 0xFFFFFFFF, "Loading..."); + _drawEnd(); + rom = VFileOpen(path, O_RDONLY); if (!rom) {

@@ -283,7 +306,7 @@ if (!GBAIsROM(rom)) {

return false; } - save = VFileOpen("test.sav", O_RDWR | O_CREAT); + save = VDirOptionalOpenFile(0, path, 0, ".sav", O_RDWR | O_CREAT); GBALoadROM(&gba, rom, save, path);

@@ -321,3 +344,46 @@ AUDIO_InitDMA((u32) audioBuffer[currentAudioBuffer], audioBufferSize * sizeof(struct GBAStereoSample));

currentAudioBuffer = (currentAudioBuffer + 1) % 3; audioBufferSize = 0; } + +static void _drawStart(void) { + GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE); + GX_SetColorUpdate(GX_TRUE); + + GX_SetViewport(0, 0, mode->fbWidth, mode->efbHeight, 0, 1); +} + +static void _drawEnd(void) { + GX_DrawDone(); + + whichFb = !whichFb; + + GX_CopyDisp(framebuffer[whichFb], GX_TRUE); + VIDEO_SetNextFramebuffer(framebuffer[whichFb]); + VIDEO_Flush(); +} + +static int _pollInput(void) { + PAD_ScanPads(); + u16 padkeys = PAD_ButtonsHeld(0); + int keys = 0; + gba.keySource = &keys; + if (padkeys & PAD_BUTTON_A) { + keys |= 1 << GUI_INPUT_SELECT; + } + if (padkeys & PAD_BUTTON_B) { + keys |= 1 << GUI_INPUT_BACK; + } + if (padkeys & PAD_BUTTON_LEFT) { + keys |= 1 << GUI_INPUT_LEFT; + } + if (padkeys & PAD_BUTTON_RIGHT) { + keys |= 1 << GUI_INPUT_RIGHT; + } + if (padkeys & PAD_BUTTON_UP) { + keys |= 1 << GUI_INPUT_UP; + } + if (padkeys & PAD_BUTTON_DOWN) { + keys |= 1 << GUI_INPUT_DOWN; + } + return keys; +}
A src/util/gui.h

@@ -0,0 +1,35 @@

+/* 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/. */ +#ifndef GUI_H +#define GUI_H + +#include "util/common.h" + +struct GUIFont; + +enum GUIInput { + GUI_INPUT_NONE = -1, + GUI_INPUT_SELECT = 0, + GUI_INPUT_BACK, + GUI_INPUT_CANCEL, + + GUI_INPUT_UP, + GUI_INPUT_DOWN, + GUI_INPUT_LEFT, + GUI_INPUT_RIGHT, +}; + +struct GUIParams { + int width; + int height; + const struct GUIFont* font; + + void (*drawStart)(void); + void (*drawEnd)(void); + int (*pollInput)(void); +}; + +#endif
A src/util/gui/file-select.c

@@ -0,0 +1,121 @@

+/* 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 "file-select.h" + +#include "util/gui/font.h" +#include "util/vector.h" +#include "util/vfs.h" + +DECLARE_VECTOR(FileList, char*); +DEFINE_VECTOR(FileList, char*); + +void _cleanFiles(struct FileList* currentFiles) { + size_t size = FileListSize(currentFiles); + size_t i; + for (i = 0; i < size; ++i) { + free(*FileListGetPointer(currentFiles, i)); + } + FileListClear(currentFiles); +} + +void _upDirectory(char* currentPath) { + char* end = strrchr(currentPath, '/'); + if (!end) { + return; + } + end[0] = '\0'; + if (end[1]) { + return; + } + // TODO: What if there was a trailing slash? +} + +bool _refreshDirectory(const char* currentPath, struct FileList* currentFiles) { + _cleanFiles(currentFiles); + + struct VDir* dir = VDirOpen(currentPath); + if (!dir) { + return false; + } + struct VDirEntry* de; + while ((de = dir->listNext(dir))) { + if (de->name(de)[0] == '.') { + continue; + } + *FileListAppend(currentFiles) = strdup(de->name(de)); + } + dir->close(dir); + return true; +} + +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; + + struct FileList currentFiles; + FileListInit(&currentFiles, 0); + _refreshDirectory(currentPath, &currentFiles); + + while (true) { + int input = params->pollInput(); + int newInput = input & (oldInput ^ input); + oldInput = input; + + if (newInput & (1 << GUI_INPUT_UP) && fileIndex > 0) { + --fileIndex; + } + if (newInput & (1 << GUI_INPUT_DOWN) && fileIndex < FileListSize(&currentFiles) - 1) { + ++fileIndex; + } + if (newInput & (1 << GUI_INPUT_CANCEL)) { + _cleanFiles(&currentFiles); + FileListDeinit(&currentFiles); + return false; + } + if (newInput & (1 << GUI_INPUT_SELECT)) { + snprintf(currentPath, sizeof(currentPath), "%s%c%s", currentPath, '/', *FileListGetPointer(&currentFiles, fileIndex)); + if (!_refreshDirectory(currentPath, &currentFiles)) { + strncpy(outPath, currentPath, outLen); + return true; + } + fileIndex = 0; + } + if (newInput & (1 << GUI_INPUT_BACK)) { + if (strncmp(currentPath, basePath, sizeof(currentPath)) == 0) { + _cleanFiles(&currentFiles); + FileListDeinit(&currentFiles); + return false; + } + _upDirectory(currentPath); + _refreshDirectory(currentPath, &currentFiles); + fileIndex = 0; + } + + params->drawStart(); + int y = GUIFontHeight(params->font); + GUIFontPrintf(params->font, 0, y, GUI_TEXT_LEFT, 0xFFFFFFFF, "Current directory: %s", currentPath); + y += 2 * GUIFontHeight(params->font); + size_t i; + for (i = 0; i < FileListSize(&currentFiles); ++i) { + int color = 0xE0A0A0A0; + char bullet = ' '; + if (i == fileIndex) { + color = 0xFFFFFFFF; + bullet = '>'; + } + GUIFontPrintf(params->font, 0, y, GUI_TEXT_LEFT, color, "%c %s", bullet, *FileListGetPointer(&currentFiles, i)); + y += GUIFontHeight(params->font); + if (y + GUIFontHeight(params->font) > params->height) { + break; + } + } + y += GUIFontHeight(params->font) * 2; + + params->drawEnd(); + } +}
A src/util/gui/file-select.h

@@ -0,0 +1,13 @@

+/* 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/. */ +#ifndef GUI_FILE_CHOOSER_H +#define GUI_FILE_CHOOSER_H + +#include "util/gui.h" + +bool selectFile(const struct GUIParams*, const char* basePath, char* outPath, size_t outLen, const char* suffix); + +#endif
A src/util/gui/font.h

@@ -0,0 +1,25 @@

+/* 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/. */ +#ifndef GUI_FONT_H +#define GUI_FONT_H + +#include "util/common.h" + +struct GUIFont; +struct GUIFont* GUIFontCreate(void); +void GUIFontDestroy(struct GUIFont*); + +enum GUITextAlignment { + GUI_TEXT_LEFT = 0, + GUI_TEXT_CENTER, + GUI_TEXT_RIGHT +}; + +int GUIFontHeight(const struct GUIFont*); + +void GUIFontPrintf(const struct GUIFont*, int x, int y, enum GUITextAlignment, uint32_t color, const char* text, ...); + +#endif