all repos — mgba @ 1b78b2133827584224f210d3ae7027e9289cfc04

mGBA Game Boy Advance Emulator

3DS: Add GUIFont
Jeffrey Pfau jeffrey@endrift.com
Sun, 23 Aug 2015 17:18:28 -0700
commit

1b78b2133827584224f210d3ae7027e9289cfc04

parent

56dd9c4158d156fbf8d5280bcb35fb261a42942c

M CMakeLists.txtCMakeLists.txt

@@ -169,10 +169,13 @@ 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(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 @@ add_subdirectory(${CMAKE_SOURCE_DIR}/src/platform/qt ${CMAKE_BINARY_DIR}/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()
M src/platform/3ds/3ds-vfs.csrc/platform/3ds/3ds-vfs.c

@@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "3ds-vfs.h" #include "util/memory.h" +#include "util/string.h" struct VFile3DS { struct VFile d;

@@ -14,6 +15,20 @@ Handle handle;

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);

@@ -23,6 +38,13 @@ static void _vf3dUnmap(struct VFile* vf, void* memory, size_t size);

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));

@@ -141,3 +163,79 @@ }

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; +}
A 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 <sf2d.h> + +#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; + } +}
M src/platform/3ds/main.csrc/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 @@ sf2d_end_frame();

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 @@ };

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 @@ .idleOptimization = IDLE_LOOP_REMOVE

}; GBAConfigLoadDefaults(&context.config, &opts); context.gba->logHandler = GBA3DSLog; + context.gba->logLevel = 0; struct GBAVideoSoftwareRenderer renderer; GBAVideoSoftwareRendererCreate(&renderer);

@@ -61,7 +95,21 @@ renderer.outputBuffer = anonymousMemoryMap(256 * VIDEO_VERTICAL_PIXELS * 2);

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(&params, "/", path, sizeof(path), "gba") || !GBAContextLoadROM(&context, path, true)) { + goto cleanup; + } GBAContextStart(&context); while (aptMainLoop()) {