mirror of https://github.com/mgba-emu/mgba.git
GBA Context: Add GBAGUIRunner for ports and use it in the Wii version
This commit is contained in:
parent
e9c64a87bc
commit
178612a471
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -148,7 +148,7 @@ int main() {
|
|||
|
||||
struct GUIParams params = {
|
||||
320, 240,
|
||||
font, "/", _drawStart, _drawEnd, _pollInput,
|
||||
font, "/", _drawStart, _drawEnd, _pollInput, 0, 0,
|
||||
|
||||
GUI_PARAMS_TRAIL
|
||||
};
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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
|
||||
};
|
||||
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 = {
|
||||
struct GBAGUIRunner runner = {
|
||||
.params = {
|
||||
352, 230,
|
||||
font, "/", _drawStart, _drawEnd, _pollInput,
|
||||
font, "/",
|
||||
_drawStart, _drawEnd, _pollInput,
|
||||
_guiPrepare, 0,
|
||||
|
||||
GUI_PARAMS_TRAIL
|
||||
},
|
||||
.setup = _setup,
|
||||
.teardown = 0,
|
||||
.gameLoaded = _gameLoaded,
|
||||
.gameUnloaded = _gameUnloaded,
|
||||
.prepareForFrame = _prepareForFrame,
|
||||
.drawFrame = _drawFrame,
|
||||
.pollGameInput = _pollGameInput
|
||||
};
|
||||
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue