PSP2: Add GUI framework and use for file chooser
Jeffrey Pfau jeffrey@endrift.com
Tue, 28 Jul 2015 00:59:28 -0700
12 files changed,
342 insertions(+),
10 deletions(-)
jump to
M
CMakeLists.txt
→
CMakeLists.txt
@@ -27,6 +27,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)@@ -355,6 +356,7 @@ ${GBA_SV_SRC}
${DEBUGGER_SRC} ${RENDERER_SRC} ${SIO_SRC} + ${GUI_SRC} ${UTIL_SRC} ${VFS_SRC} ${OS_SRC}
M
src/platform/psp2/CMakeLists.txt
→
src/platform/psp2/CMakeLists.txt
@@ -1,8 +1,10 @@
file(GLOB PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/psp2/*.c) -set(PLATFORM_LIBRARY -lvita2d -lSceCtrl_stub -lSceRtc_stub -lSceGxm_stub -lSceDisplay_stub -lSceAudio_stub -lm_stub) +execute_process(COMMAND ${DEVKITARM}/bin/arm-none-eabi-objcopy -I binary -O elf32-littlearm -B arm font.png ${CMAKE_BINARY_DIR}/font.o WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/res) -add_executable(${BINARY_NAME}.elf ${PLATFORM_SRC}) +set(PLATFORM_LIBRARY -lvita2d -lSceCtrl_stub -lSceRtc_stub -lSceGxm_stub -lSceDisplay_stub -lSceAudio_stub -lpng -lz -lm_stub) + +add_executable(${BINARY_NAME}.elf ${PLATFORM_SRC} ${CMAKE_BINARY_DIR}/font.o) target_link_libraries(${BINARY_NAME}.elf ${BINARY_NAME} ${PLATFORM_LIBRARY}) set_target_properties(${BINARY_NAME}.elf PROPERTIES OUTPUT_NAME ${BINARY_NAME}.elf) add_custom_command(TARGET ${BINARY_NAME}.elf POST_BUILD COMMAND ${FIXUP} -q -S ${BINARY_NAME}.elf ${BINARY_NAME}.velf MAIN_DEPENDENCY ${BINARY_NAME}.elf)
A
src/platform/psp2/gui-font.c
@@ -0,0 +1,60 @@
+/* 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 <vita2d.h> + +#define GLYPH_HEIGHT 11 +#define GLYPH_WIDTH 14 +#define FONT_TRACKING 10 +#define CELL_HEIGHT 16 +#define CELL_WIDTH 16 + +extern const uint8_t _binary_font_png_start[]; + +struct GUIFont { + vita2d_texture* tex; +}; + +struct GUIFont* GUIFontCreate(void) { + struct GUIFont* font = malloc(sizeof(struct GUIFont)); + if (!font) { + return 0; + } + font->tex = vita2d_load_PNG_buffer(_binary_font_png_start); + return font; +} + +void GUIFontDestroy(struct GUIFont* font) { + vita2d_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; + } + vita2d_draw_texture_tint_part(font->tex, x, y - GLYPH_HEIGHT, + (c & 15) * CELL_WIDTH + ((CELL_WIDTH - GLYPH_WIDTH) >> 1), + (c >> 4) * CELL_HEIGHT + ((CELL_HEIGHT - GLYPH_HEIGHT) >> 1), + GLYPH_WIDTH, GLYPH_HEIGHT, color); + x += FONT_TRACKING; + } +}
M
src/platform/psp2/main.c
→
src/platform/psp2/main.c
@@ -5,18 +5,82 @@ * 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 "psp2-context.h" +#include "util/gui.h" +#include "util/gui/font.h" +#include "util/gui/file-select.h" + +#include <psp2/ctrl.h> #include <psp2/kernel/processmgr.h> #include <psp2/moduleinfo.h> +#include <vita2d.h> + PSP2_MODULE_INFO(0, 0, "mGBA"); +static void _drawStart(void) { + vita2d_start_drawing(); + vita2d_clear_screen(); +} + +static void _drawEnd(void) { + vita2d_end_drawing(); + vita2d_swap_buffers(); +} + +static int _pollInput(void) { + SceCtrlData pad; + sceCtrlPeekBufferPositive(0, &pad, 1); + int input = 0; + if (pad.buttons & PSP2_CTRL_TRIANGLE) { + input |= 1 << GUI_INPUT_CANCEL; + } + if (pad.buttons & PSP2_CTRL_CIRCLE) { + input |= 1 << GUI_INPUT_BACK; + } + if (pad.buttons & PSP2_CTRL_CROSS) { + input |= 1 << GUI_INPUT_SELECT; + } + + if (pad.buttons & PSP2_CTRL_UP) { + input |= 1 << GUI_INPUT_UP; + } + if (pad.buttons & PSP2_CTRL_DOWN) { + input |= 1 << GUI_INPUT_DOWN; + } + if (pad.buttons & PSP2_CTRL_LEFT) { + input |= 1 << GUI_INPUT_LEFT; + } + if (pad.buttons & PSP2_CTRL_RIGHT) { + input |= 1 << GUI_INPUT_RIGHT; + } + return input; +} + int main() { printf("%s initializing", projectName); + + vita2d_init(); + struct GUIFont* font = GUIFontCreate(); GBAPSP2Setup(); - GBAPSP2LoadROM("cache0:/VitaDefilerClient/Documents/GBA/rom.gba"); - GBAPSP2Runloop(); - GBAPSP2UnloadROM(); + struct GUIParams params = { + PSP2_HORIZONTAL_PIXELS, PSP2_VERTICAL_PIXELS, + font, _drawStart, _drawEnd, _pollInput + }; + + while (true) { + char path[256]; + if (!selectFile(¶ms, "cache0:", path, sizeof(path), "gba")) { + break; + } + GBAPSP2LoadROM(path); + GBAPSP2Runloop(); + GBAPSP2UnloadROM(); + } + GBAPSP2Teardown(); + + GUIFontDestroy(font); + vita2d_fini(); sceKernelExitProcess(0); return 0;
A
src/platform/psp2/psp2-common.h
@@ -0,0 +1,14 @@
+/* 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 PSP2_COMMON_H +#define PSP2_COMMON_H + +#include "util/common.h" + +#define PSP2_HORIZONTAL_PIXELS 960 +#define PSP2_VERTICAL_PIXELS 544 + +#endif
M
src/platform/psp2/psp2-context.c
→
src/platform/psp2/psp2-context.c
@@ -39,8 +39,6 @@ static Thread audioThread;
static bool fullscreen = false; -#define PSP2_HORIZONTAL_PIXELS 960 -#define PSP2_VERTICAL_PIXELS 544 #define PSP2_INPUT 0x50535032 #define PSP2_SAMPLES 64 #define PSP2_AUDIO_BUFFER_SIZE (PSP2_SAMPLES * 19)@@ -100,7 +98,6 @@ GBAInputBindAxis(&inputMap, PSP2_INPUT, 0, &desc);
desc = (struct GBAAxis) { GBA_KEY_RIGHT, GBA_KEY_LEFT, 192, 64 }; GBAInputBindAxis(&inputMap, PSP2_INPUT, 1, &desc); - vita2d_init(); tex = vita2d_create_empty_texture_format(256, 256, SCE_GXM_TEXTURE_FORMAT_X8U8U8U8_1BGR); renderer.outputBuffer = vita2d_texture_get_datap(tex);@@ -251,7 +248,6 @@ void GBAPSP2Teardown(void) {
GBAInputMapDeinit(&inputMap); vita2d_free_texture(tex); - vita2d_fini(); } void GBAPSP2Draw(void) {
M
src/platform/psp2/psp2-context.h
→
src/platform/psp2/psp2-context.h
@@ -6,7 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef PSP2_CONTEXT_H #define PSP2_CONTEXT_H -#include "util/common.h" +#include "psp2-common.h" void GBAPSP2Setup(void); void GBAPSP2Teardown(void);
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(¤tFiles, 0); + _refreshDirectory(currentPath, ¤tFiles); + + 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(¤tFiles) - 1) { + ++fileIndex; + } + if (newInput & (1 << GUI_INPUT_CANCEL)) { + _cleanFiles(¤tFiles); + FileListDeinit(¤tFiles); + return false; + } + if (newInput & (1 << GUI_INPUT_SELECT)) { + snprintf(currentPath, sizeof(currentPath), "%s%c%s", currentPath, '/', *FileListGetPointer(¤tFiles, fileIndex)); + if (!_refreshDirectory(currentPath, ¤tFiles)) { + strncpy(outPath, currentPath, outLen); + return true; + } + fileIndex = 0; + } + if (newInput & (1 << GUI_INPUT_BACK)) { + if (strncmp(currentPath, basePath, sizeof(currentPath)) == 0) { + _cleanFiles(¤tFiles); + FileListDeinit(¤tFiles); + return false; + } + _upDirectory(currentPath); + _refreshDirectory(currentPath, ¤tFiles); + 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(¤tFiles); ++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(¤tFiles, 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