From 178612a47196bb255b3a3554f2abf99548db51c4 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sun, 30 Aug 2015 16:25:32 -0700 Subject: [PATCH] GBA Context: Add GBAGUIRunner for ports and use it in the Wii version --- src/gba/context/context.c | 28 ++- src/gba/context/context.h | 1 + src/gba/context/gui-runner.c | 82 +++++++ src/gba/context/gui-runner.h | 29 +++ src/platform/3ds/main.c | 2 +- src/platform/psp2/main.c | 2 +- src/platform/wii/main.c | 428 ++++++++++++++++++----------------- src/util/gui.h | 4 +- 8 files changed, 349 insertions(+), 227 deletions(-) create mode 100644 src/gba/context/gui-runner.c create mode 100644 src/gba/context/gui-runner.h diff --git a/src/gba/context/context.c b/src/gba/context/context.c index 921916169..2304a0f5a 100644 --- a/src/gba/context/context.c +++ b/src/gba/context/context.c @@ -42,18 +42,6 @@ bool GBAContextInit(struct GBAContext* context, const char* port) { } void GBAContextDeinit(struct GBAContext* context) { - if (context->bios) { - context->bios->close(context->bios); - context->bios = 0; - } - if (context->rom) { - context->rom->close(context->rom); - context->rom = 0; - } - if (context->save) { - context->save->close(context->save); - context->save = 0; - } ARMDeinit(context->cpu); GBADestroy(context->gba); mappedMemoryFree(context->gba, 0); @@ -79,6 +67,22 @@ bool GBAContextLoadROM(struct GBAContext* context, const char* path, bool autolo return true; } +void GBAContextUnloadROM(struct GBAContext* context) { + GBAUnloadROM(context->gba); + if (context->bios) { + context->bios->close(context->bios); + context->bios = 0; + } + if (context->rom) { + context->rom->close(context->rom); + context->rom = 0; + } + if (context->save) { + context->save->close(context->save); + context->save = 0; + } +} + bool GBAContextLoadROMFromVFile(struct GBAContext* context, struct VFile* rom, struct VFile* save) { context->rom = rom; if (!GBAIsROM(context->rom)) { diff --git a/src/gba/context/context.h b/src/gba/context/context.h index 6d597d9b3..811f80c47 100644 --- a/src/gba/context/context.h +++ b/src/gba/context/context.h @@ -31,6 +31,7 @@ bool GBAContextLoadROM(struct GBAContext* context, const char* path, bool autolo bool GBAContextLoadROMFromVFile(struct GBAContext* context, struct VFile* rom, struct VFile* save); bool GBAContextLoadBIOS(struct GBAContext* context, const char* path); bool GBAContextLoadBIOSFromVFile(struct GBAContext* context, struct VFile* bios); +void GBAContextUnloadROM(struct GBAContext* context); bool GBAContextStart(struct GBAContext* context); void GBAContextStop(struct GBAContext* context); diff --git a/src/gba/context/gui-runner.c b/src/gba/context/gui-runner.c new file mode 100644 index 000000000..a3d1c38a3 --- /dev/null +++ b/src/gba/context/gui-runner.c @@ -0,0 +1,82 @@ +/* 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 "gui-runner.h" + +#include "util/gui/file-select.h" +#include "util/gui/font.h" + +void GBAGUIInit(struct GBAGUIRunner* runner, const char* port) { + GUIInit(&runner->params); + GBAContextInit(&runner->context, port); + if (runner->setup) { + runner->setup(runner); + } +} + +void GBAGUIDeinit(struct GBAGUIRunner* runner) { + if (runner->teardown) { + runner->teardown(runner); + } + GBAContextDeinit(&runner->context); +} + +void GBAGUIRunloop(struct GBAGUIRunner* runner) { + while (true) { + if (runner->params.guiPrepare) { + runner->params.guiPrepare(); + } + char path[256]; + if (!GUISelectFile(&runner->params, path, sizeof(path), GBAIsROM)) { + if (runner->params.guiFinish) { + runner->params.guiFinish(); + } + return; + } + if (runner->params.guiFinish) { + runner->params.guiFinish(); + } + + // TODO: Message box API + runner->params.drawStart(); + GUIFontPrint(runner->params.font, runner->params.width / 2, (GUIFontHeight(runner->params.font) + runner->params.height) / 2, GUI_TEXT_CENTER, 0xFFFFFFFF, "Loading..."); + runner->params.drawEnd(); + runner->params.drawStart(); + GUIFontPrint(runner->params.font, runner->params.width / 2, (GUIFontHeight(runner->params.font) + runner->params.height) / 2, GUI_TEXT_CENTER, 0xFFFFFFFF, "Loading..."); + runner->params.drawEnd(); + + if (!GBAContextLoadROM(&runner->context, path, true)) { + int i; + for (i = 0; i < 300; ++i) { + runner->params.drawStart(); + GUIFontPrint(runner->params.font, runner->params.width / 2, (GUIFontHeight(runner->params.font) + runner->params.height) / 2, GUI_TEXT_CENTER, 0xFFFFFFFF, "Load failed!"); + runner->params.drawEnd(); + } + } + GBAContextStart(&runner->context); + if (runner->gameLoaded) { + runner->gameLoaded(runner); + } + while (true) { + int guiKeys = runner->params.pollInput(); + if (guiKeys & (1 << GUI_INPUT_CANCEL)) { + break; + } + uint16_t keys = runner->pollGameInput(runner); + if (runner->prepareForFrame) { + runner->prepareForFrame(runner); + } + GBAContextFrame(&runner->context, keys); + if (runner->drawFrame) { + runner->drawFrame(runner, false); + } + } + GBAContextStop(&runner->context); + if (runner->gameUnloaded) { + runner->gameUnloaded(runner); + } + GBAContextUnloadROM(&runner->context); + } +} diff --git a/src/gba/context/gui-runner.h b/src/gba/context/gui-runner.h new file mode 100644 index 000000000..b9b4916ef --- /dev/null +++ b/src/gba/context/gui-runner.h @@ -0,0 +1,29 @@ +/* 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_RUNNER_H +#define GUI_RUNNER_H + +#include "gba/context/context.h" +#include "util/gui.h" + +struct GBAGUIRunner { + struct GBAContext context; + struct GUIParams params; + + void (*setup)(struct GBAGUIRunner*); + void (*teardown)(struct GBAGUIRunner*); + void (*gameLoaded)(struct GBAGUIRunner*); + void (*gameUnloaded)(struct GBAGUIRunner*); + void (*prepareForFrame)(struct GBAGUIRunner*); + void (*drawFrame)(struct GBAGUIRunner*, bool faded); + uint16_t (*pollGameInput)(struct GBAGUIRunner*); +}; + +void GBAGUIInit(struct GBAGUIRunner*, const char* port); +void GBAGUIDeinit(struct GBAGUIRunner*); +void GBAGUIRunloop(struct GBAGUIRunner*); + +#endif diff --git a/src/platform/3ds/main.c b/src/platform/3ds/main.c index d10978457..d1093a96e 100644 --- a/src/platform/3ds/main.c +++ b/src/platform/3ds/main.c @@ -148,7 +148,7 @@ int main() { struct GUIParams params = { 320, 240, - font, "/", _drawStart, _drawEnd, _pollInput, + font, "/", _drawStart, _drawEnd, _pollInput, 0, 0, GUI_PARAMS_TRAIL }; diff --git a/src/platform/psp2/main.c b/src/platform/psp2/main.c index 91cffe8b3..b711391cb 100644 --- a/src/platform/psp2/main.c +++ b/src/platform/psp2/main.c @@ -66,7 +66,7 @@ int main() { GBAPSP2Setup(); struct GUIParams params = { PSP2_HORIZONTAL_PIXELS, PSP2_VERTICAL_PIXELS, - font, "cache0:", _drawStart, _drawEnd, _pollInput, + font, "cache0:", _drawStart, _drawEnd, _pollInput, 0, 0, GUI_PARAMS_TRAIL }; diff --git a/src/platform/wii/main.c b/src/platform/wii/main.c index f9c33fdc4..a90dfc4e0 100644 --- a/src/platform/wii/main.c +++ b/src/platform/wii/main.c @@ -14,6 +14,7 @@ #include "gba/renderers/video-software.h" #include "gba/context/context.h" +#include "gba/context/gui-runner.h" #include "util/gui.h" #include "util/gui/file-select.h" #include "util/gui/font.h" @@ -22,10 +23,7 @@ #define SAMPLES 1024 static void GBAWiiLog(struct GBAThread* thread, enum GBALogLevel level, const char* format, va_list args); -static void GBAWiiFrame(void); -static bool GBAWiiLoadGame(const char* path); -static void _postVideoFrame(struct GBAAVStream*, struct GBAVideoRenderer* renderer); static void _audioDMA(void); static void _setRumble(struct GBARumble* rumble, int enable); static void _sampleRotation(struct GBARotationSource* source); @@ -36,10 +34,16 @@ static int32_t _readGyroZ(struct GBARotationSource* source); static void _drawStart(void); static void _drawEnd(void); static int _pollInput(void); +static void _guiPrepare(void); + +static void _setup(struct GBAGUIRunner* runner); +static void _gameLoaded(struct GBAGUIRunner* runner); +static void _gameUnloaded(struct GBAGUIRunner* runner); +static void _prepareForFrame(struct GBAGUIRunner* runner); +static void _drawFrame(struct GBAGUIRunner* runner, bool faded); +static uint16_t _pollGameInput(struct GBAGUIRunner* runner); -static struct GBAContext context; static struct GBAVideoSoftwareRenderer renderer; -static struct GBAAVStream stream; static struct GBARumble rumble; static struct GBARotationSource rotation; static FILE* logfile; @@ -109,9 +113,11 @@ int main() { GX_ClearVtxDesc(); GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_S16, 0); GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_S16, 0); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); GX_SetNumChans(1); GX_SetNumTexGens(1); @@ -122,8 +128,6 @@ int main() { GX_InvVtxCache(); GX_InvalidateTexAll(); - Mtx44 proj; - guVector cam = { 0.0f, 0.0f, 0.0f }; guVector up = { 0.0f, 1.0f, 0.0f }; guVector look = { 0.0f, 0.0f, -1.0f }; @@ -144,10 +148,6 @@ int main() { logfile = fopen("/mgba.log", "w"); - stream.postAudioFrame = 0; - stream.postAudioBuffer = 0; - stream.postVideoFrame = _postVideoFrame; - rumble.setRumble = _setRumble; rotation.sample = _sampleRotation; @@ -155,212 +155,36 @@ int main() { rotation.readTiltY = _readTiltY; rotation.readGyroZ = _readGyroZ; - GBAContextInit(&context, 0); - struct GBAOptions opts = { - .useBios = true, - .logLevel = 0, - .idleOptimization = IDLE_LOOP_DETECT + struct GBAGUIRunner runner = { + .params = { + 352, 230, + font, "/", + _drawStart, _drawEnd, _pollInput, + _guiPrepare, 0, + + GUI_PARAMS_TRAIL + }, + .setup = _setup, + .teardown = 0, + .gameLoaded = _gameLoaded, + .gameUnloaded = _gameUnloaded, + .prepareForFrame = _prepareForFrame, + .drawFrame = _drawFrame, + .pollGameInput = _pollGameInput }; - GBAConfigLoadDefaults(&context.config, &opts); - context.gba->logHandler = GBAWiiLog; - context.gba->stream = &stream; - context.gba->rumble = &rumble; - context.gba->rotationSource = &rotation; - - GBAVideoSoftwareRendererCreate(&renderer); - renderer.outputBuffer = memalign(32, 256 * 256 * BYTES_PER_PIXEL); - renderer.outputBufferStride = 256; - context.renderer = &renderer.d; - - GBAAudioResizeBuffer(&context.gba->audio, SAMPLES); - -#if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF - blip_set_rates(context.gba->audio.left, GBA_ARM7TDMI_FREQUENCY, 48000); - blip_set_rates(context.gba->audio.right, GBA_ARM7TDMI_FREQUENCY, 48000); -#endif - - struct GUIParams params = { - 352, 230, - font, "/", _drawStart, _drawEnd, _pollInput, - - GUI_PARAMS_TRAIL - }; - GUIInit(¶ms); - - while (true) { - char path[256]; - guOrtho(proj, -20, 240, 0, 352, 0, 300); - GX_LoadProjectionMtx(proj, GX_ORTHOGRAPHIC); - GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); - - if (!GUISelectFile(¶ms, path, sizeof(path), GBAIsROM) || !GBAWiiLoadGame(path)) { - break; - } - WPAD_SetDataFormat(0, WPAD_FMT_BTNS_ACC); - GBAContextStart(&context); - if (context.gba->memory.hw.devices & HW_GYRO) { - int i; - for (i = 0; i < 6; ++i) { - u32 result = WPAD_SetMotionPlus(0, 1); - if (result == WPAD_ERR_NONE) { - break; - } - sleep(1); - } - } - - guOrtho(proj, -10, VIDEO_VERTICAL_PIXELS + 10, 0, VIDEO_HORIZONTAL_PIXELS, 0, 300); - GX_LoadProjectionMtx(proj, GX_ORTHOGRAPHIC); - GX_SetVtxDesc(GX_VA_CLR0, GX_NONE); - - while (true) { - #if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF - int available = blip_samples_avail(context.gba->audio.left); - if (available + audioBufferSize > SAMPLES) { - available = SAMPLES - audioBufferSize; - } - available &= ~((32 / sizeof(struct GBAStereoSample)) - 1); // Force align to 32 bytes - if (available > 0) { - blip_read_samples(context.gba->audio.left, &audioBuffer[currentAudioBuffer][audioBufferSize].left, available, true); - blip_read_samples(context.gba->audio.right, &audioBuffer[currentAudioBuffer][audioBufferSize].right, available, true); - audioBufferSize += available; - } - if (audioBufferSize == SAMPLES && !AUDIO_GetDMAEnableFlag()) { - _audioDMA(); - AUDIO_StartDMA(); - } - #endif - PAD_ScanPads(); - u16 padkeys = PAD_ButtonsHeld(0); - WPAD_ScanPads(); - u32 wiiPad = WPAD_ButtonsHeld(0); - u32 ext = 0; - uint16_t keys = 0; - WPAD_Probe(0, &ext); - - if ((padkeys & PAD_BUTTON_A) || (wiiPad & WPAD_BUTTON_2) || - ((ext == WPAD_EXP_CLASSIC) && (wiiPad & (WPAD_CLASSIC_BUTTON_A | WPAD_CLASSIC_BUTTON_Y)))) { - keys |= 1 << GBA_KEY_A; - } - if ((padkeys & PAD_BUTTON_B) || (wiiPad & WPAD_BUTTON_1) || - ((ext == WPAD_EXP_CLASSIC) && (wiiPad & (WPAD_CLASSIC_BUTTON_B | WPAD_CLASSIC_BUTTON_X)))) { - keys |= 1 << GBA_KEY_B; - } - if ((padkeys & PAD_TRIGGER_L) || (wiiPad & WPAD_BUTTON_B) || - ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_FULL_L))) { - keys |= 1 << GBA_KEY_L; - } - if ((padkeys & PAD_TRIGGER_R) || (wiiPad & WPAD_BUTTON_A) || - ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_FULL_R))) { - keys |= 1 << GBA_KEY_R; - } - if ((padkeys & PAD_BUTTON_START) || (wiiPad & WPAD_BUTTON_PLUS) || - ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_PLUS))) { - keys |= 1 << GBA_KEY_START; - } - if ((padkeys & (PAD_BUTTON_X | PAD_BUTTON_Y)) || (wiiPad & WPAD_BUTTON_MINUS) || - ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_MINUS))) { - keys |= 1 << GBA_KEY_SELECT; - } - if ((padkeys & PAD_BUTTON_LEFT) || (wiiPad & WPAD_BUTTON_UP) || - ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_LEFT))) { - keys |= 1 << GBA_KEY_LEFT; - } - if ((padkeys & PAD_BUTTON_RIGHT) || (wiiPad & WPAD_BUTTON_DOWN) || - ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_RIGHT))) { - keys |= 1 << GBA_KEY_RIGHT; - } - if ((padkeys & PAD_BUTTON_UP) || (wiiPad & WPAD_BUTTON_RIGHT) || - ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_UP))) { - keys |= 1 << GBA_KEY_UP; - } - if ((padkeys & PAD_BUTTON_DOWN) || (wiiPad & WPAD_BUTTON_LEFT) || - ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_DOWN))) { - keys |= 1 << GBA_KEY_DOWN; - } - int x = PAD_StickX(0); - int y = PAD_StickY(0); - if (x < -0x40) { - keys |= 1 << GBA_KEY_LEFT; - } - if (x > 0x40) { - keys |= 1 << GBA_KEY_RIGHT; - } - if (y < -0x40) { - keys |= 1 << GBA_KEY_DOWN; - } - if (y > 0x40) { - keys |= 1 << GBA_KEY_UP; - } - if ((padkeys & PAD_TRIGGER_Z) || (wiiPad & WPAD_BUTTON_HOME) || (wiiPad & WPAD_CLASSIC_BUTTON_HOME)) { - break; - } - GBAContextFrame(&context, keys); - } - AUDIO_StopDMA(); - GBAContextStop(&context); - } + GBAGUIInit(&runner, 0); + GBAGUIRunloop(&runner); + GBAGUIDeinit(&runner); fclose(logfile); free(fifo); - GBAContextDeinit(&context); - free(renderer.outputBuffer); GUIFontDestroy(font); return 0; } -static void GBAWiiFrame(void) { - size_t x, y; - uint64_t* texdest = (uint64_t*) texmem; - uint64_t* texsrc = (uint64_t*) renderer.outputBuffer; - for (y = 0; y < VIDEO_VERTICAL_PIXELS; y += 4) { - for (x = 0; x < VIDEO_HORIZONTAL_PIXELS >> 2; ++x) { - texdest[0 + x * 4 + y * 64] = texsrc[0 + x + y * 64]; - texdest[1 + x * 4 + y * 64] = texsrc[64 + x + y * 64]; - texdest[2 + x * 4 + y * 64] = texsrc[128 + x + y * 64]; - texdest[3 + x * 4 + y * 64] = texsrc[192 + x + y * 64]; - } - } - DCFlushRange(texdest, 256 * 256 * BYTES_PER_PIXEL); - - _drawStart(); - - 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); - - GX_Begin(GX_QUADS, GX_VTXFMT0, 4); - GX_Position2s16(0, 256); - GX_TexCoord2s16(0, 1); - - GX_Position2s16(256, 256); - GX_TexCoord2s16(1, 1); - - GX_Position2s16(256, 0); - GX_TexCoord2s16(1, 0); - - GX_Position2s16(0, 0); - GX_TexCoord2s16(0, 0); - GX_End(); - - _drawEnd(); -} - -bool GBAWiiLoadGame(const char* path) { - _drawStart(); - GUIFontPrintf(font, 176, 120, GUI_TEXT_CENTER, 0xFFFFFFFF, "Loading..."); - _drawEnd(); - _drawStart(); - GUIFontPrintf(font, 176, 120, GUI_TEXT_CENTER, 0xFFFFFFFF, "Loading..."); - _drawEnd(); - - return GBAContextLoadROM(&context, path, true); -} - void GBAWiiLog(struct GBAThread* thread, enum GBALogLevel level, const char* format, va_list args) { UNUSED(thread); UNUSED(level); @@ -372,12 +196,6 @@ void GBAWiiLog(struct GBAThread* thread, enum GBALogLevel level, const char* for fflush(logfile); } -static void _postVideoFrame(struct GBAAVStream* stream, struct GBAVideoRenderer* renderer) { - UNUSED(stream); - UNUSED(renderer); - GBAWiiFrame(); -} - static void _audioDMA(void) { if (!audioBufferSize) { return; @@ -461,6 +279,192 @@ static int _pollInput(void) { return keys; } +void _guiPrepare(void) { + Mtx44 proj; + guOrtho(proj, -20, 240, 0, 352, 0, 300); + GX_LoadProjectionMtx(proj, GX_ORTHOGRAPHIC); +} + +void _setup(struct GBAGUIRunner* runner) { + struct GBAOptions opts = { + .useBios = true, + .logLevel = 0, + .idleOptimization = IDLE_LOOP_DETECT + }; + GBAConfigLoadDefaults(&runner->context.config, &opts); + runner->context.gba->logHandler = GBAWiiLog; + runner->context.gba->rumble = &rumble; + runner->context.gba->rotationSource = &rotation; + + GBAVideoSoftwareRendererCreate(&renderer); + renderer.outputBuffer = memalign(32, 256 * 256 * BYTES_PER_PIXEL); + renderer.outputBufferStride = 256; + runner->context.renderer = &renderer.d; + + GBAAudioResizeBuffer(&runner->context.gba->audio, SAMPLES); + +#if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF + blip_set_rates(runner->context.gba->audio.left, GBA_ARM7TDMI_FREQUENCY, 48000); + blip_set_rates(runner->context.gba->audio.right, GBA_ARM7TDMI_FREQUENCY, 48000); +#endif +} + +void _gameUnloaded(struct GBAGUIRunner* runner) { + UNUSED(runner); + AUDIO_StopDMA(); +} + +void _gameLoaded(struct GBAGUIRunner* runner) { + WPAD_SetDataFormat(0, WPAD_FMT_BTNS_ACC); + if (runner->context.gba->memory.hw.devices & HW_GYRO) { + int i; + for (i = 0; i < 6; ++i) { + u32 result = WPAD_SetMotionPlus(0, 1); + if (result == WPAD_ERR_NONE) { + break; + } + sleep(1); + } + } + + Mtx44 proj; + guOrtho(proj, -10, VIDEO_VERTICAL_PIXELS + 10, 0, VIDEO_HORIZONTAL_PIXELS, 0, 300); + GX_LoadProjectionMtx(proj, GX_ORTHOGRAPHIC); +} + +void _prepareForFrame(struct GBAGUIRunner* runner) { +#if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF + int available = blip_samples_avail(runner->context.gba->audio.left); + if (available + audioBufferSize > SAMPLES) { + available = SAMPLES - audioBufferSize; + } + available &= ~((32 / sizeof(struct GBAStereoSample)) - 1); // Force align to 32 bytes + if (available > 0) { + blip_read_samples(runner->context.gba->audio.left, &audioBuffer[currentAudioBuffer][audioBufferSize].left, available, true); + blip_read_samples(runner->context.gba->audio.right, &audioBuffer[currentAudioBuffer][audioBufferSize].right, available, true); + audioBufferSize += available; + } + if (audioBufferSize == SAMPLES && !AUDIO_GetDMAEnableFlag()) { + _audioDMA(); + AUDIO_StartDMA(); + } +#endif +} + +void _drawFrame(struct GBAGUIRunner* runner, bool faded) { + uint32_t color = 0xFFFFFF3F; + if (!faded) { + color |= 0xC0; + } + size_t x, y; + uint64_t* texdest = (uint64_t*) texmem; + uint64_t* texsrc = (uint64_t*) renderer.outputBuffer; + for (y = 0; y < VIDEO_VERTICAL_PIXELS; y += 4) { + for (x = 0; x < VIDEO_HORIZONTAL_PIXELS >> 2; ++x) { + texdest[0 + x * 4 + y * 64] = texsrc[0 + x + y * 64]; + texdest[1 + x * 4 + y * 64] = texsrc[64 + x + y * 64]; + texdest[2 + x * 4 + y * 64] = texsrc[128 + x + y * 64]; + texdest[3 + x * 4 + y * 64] = texsrc[192 + x + y * 64]; + } + } + DCFlushRange(texdest, 256 * 256 * BYTES_PER_PIXEL); + + _drawStart(); + + 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_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); + GX_InvalidateTexAll(); + GX_LoadTexObj(&tex, GX_TEXMAP0); + + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + GX_Position2s16(0, 256); + GX_Color1u32(color); + GX_TexCoord2s16(0, 1); + + GX_Position2s16(256, 256); + GX_Color1u32(color); + GX_TexCoord2s16(1, 1); + + GX_Position2s16(256, 0); + GX_Color1u32(color); + GX_TexCoord2s16(1, 0); + + GX_Position2s16(0, 0); + GX_Color1u32(color); + GX_TexCoord2s16(0, 0); + GX_End(); + + _drawEnd(); +} + +uint16_t _pollGameInput(struct GBAGUIRunner* runner) { + UNUSED(runner); + PAD_ScanPads(); + u16 padkeys = PAD_ButtonsHeld(0); + WPAD_ScanPads(); + u32 wiiPad = WPAD_ButtonsHeld(0); + u32 ext = 0; + uint16_t keys = 0; + WPAD_Probe(0, &ext); + + if ((padkeys & PAD_BUTTON_A) || (wiiPad & WPAD_BUTTON_2) || + ((ext == WPAD_EXP_CLASSIC) && (wiiPad & (WPAD_CLASSIC_BUTTON_A | WPAD_CLASSIC_BUTTON_Y)))) { + keys |= 1 << GBA_KEY_A; + } + if ((padkeys & PAD_BUTTON_B) || (wiiPad & WPAD_BUTTON_1) || + ((ext == WPAD_EXP_CLASSIC) && (wiiPad & (WPAD_CLASSIC_BUTTON_B | WPAD_CLASSIC_BUTTON_X)))) { + keys |= 1 << GBA_KEY_B; + } + if ((padkeys & PAD_TRIGGER_L) || (wiiPad & WPAD_BUTTON_B) || + ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_FULL_L))) { + keys |= 1 << GBA_KEY_L; + } + if ((padkeys & PAD_TRIGGER_R) || (wiiPad & WPAD_BUTTON_A) || + ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_FULL_R))) { + keys |= 1 << GBA_KEY_R; + } + if ((padkeys & PAD_BUTTON_START) || (wiiPad & WPAD_BUTTON_PLUS) || + ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_PLUS))) { + keys |= 1 << GBA_KEY_START; + } + if ((padkeys & (PAD_BUTTON_X | PAD_BUTTON_Y)) || (wiiPad & WPAD_BUTTON_MINUS) || + ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_MINUS))) { + keys |= 1 << GBA_KEY_SELECT; + } + if ((padkeys & PAD_BUTTON_LEFT) || (wiiPad & WPAD_BUTTON_UP) || + ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_LEFT))) { + keys |= 1 << GBA_KEY_LEFT; + } + if ((padkeys & PAD_BUTTON_RIGHT) || (wiiPad & WPAD_BUTTON_DOWN) || + ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_RIGHT))) { + keys |= 1 << GBA_KEY_RIGHT; + } + if ((padkeys & PAD_BUTTON_UP) || (wiiPad & WPAD_BUTTON_RIGHT) || + ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_UP))) { + keys |= 1 << GBA_KEY_UP; + } + if ((padkeys & PAD_BUTTON_DOWN) || (wiiPad & WPAD_BUTTON_LEFT) || + ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_DOWN))) { + keys |= 1 << GBA_KEY_DOWN; + } + int x = PAD_StickX(0); + int y = PAD_StickY(0); + if (x < -0x40) { + keys |= 1 << GBA_KEY_LEFT; + } + if (x > 0x40) { + keys |= 1 << GBA_KEY_RIGHT; + } + if (y < -0x40) { + keys |= 1 << GBA_KEY_DOWN; + } + if (y > 0x40) { + keys |= 1 << GBA_KEY_UP; + } + return keys; +} + void _setRumble(struct GBARumble* rumble, int enable) { UNUSED(rumble); WPAD_Rumble(0, enable); diff --git a/src/util/gui.h b/src/util/gui.h index 72fea2a6d..047e44512 100644 --- a/src/util/gui.h +++ b/src/util/gui.h @@ -35,6 +35,8 @@ struct GUIParams { void (*drawStart)(void); void (*drawEnd)(void); int (*pollInput)(void); + void (*guiPrepare)(void); + void (*guiFinish)(void); // State int inputHistory[GUI_INPUT_MAX]; @@ -44,7 +46,7 @@ struct GUIParams { size_t fileIndex; }; -#define GUI_PARAMS_TRAIL {}, "" +#define GUI_PARAMS_TRAIL {}, "", 0 void GUIInit(struct GUIParams* params); void GUIPollInput(struct GUIParams* params, int* newInput, int* heldInput);