Wii: Add file selector from PSP2 port

This commit is contained in:
Jeffrey Pfau 2015-08-06 15:29:46 -07:00
parent 8dd6a82201
commit 94e329a58c
10 changed files with 369 additions and 17 deletions

View File

@ -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 @@ elseif(UNIX)
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()

BIN
res/font.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

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

BIN
src/platform/wii/font.tpl Normal file

Binary file not shown.

View File

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

View File

@ -16,6 +16,9 @@
#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
@ -27,6 +30,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;
static struct GBAVideoSoftwareRenderer renderer;
@ -46,6 +53,8 @@ static struct GBAStereoSample audioBuffer[3][SAMPLES] __attribute__((__aligned__
static volatile size_t audioBufferSize = 0;
static volatile int currentAudioBuffer = 0;
static struct GUIFont* font;
int main() {
VIDEO_Init();
PAD_Init();
@ -108,8 +117,6 @@ int main() {
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 @@ int main() {
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,10 +163,23 @@ int main() {
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
int available = blip_samples_avail(gba.audio.left);
@ -224,6 +246,9 @@ int main() {
rom->close(rom);
save->close(save);
free(renderer.outputBuffer);
GUIFontDestroy(font);
return 0;
}
@ -243,10 +268,10 @@ static void GBAWiiFrame(void) {
}
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 @@ static void GBAWiiFrame(void) {
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 @@ bool GBAWiiLoadGame(const char* path) {
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 @@ static void _audioDMA(void) {
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;
}

35
src/util/gui.h Normal file
View File

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

121
src/util/gui/file-select.c Normal file
View File

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

View File

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

25
src/util/gui/font.h Normal file
View File

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