mirror of https://github.com/mgba-emu/mgba.git
GUI: Support single-shot runs
This commit is contained in:
parent
2725d6ed2f
commit
396d097db4
|
@ -129,7 +129,7 @@ void GBAGUIDeinit(struct GBAGUIRunner* runner) {
|
||||||
GBAContextDeinit(&runner->context);
|
GBAContextDeinit(&runner->context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBAGUIRunloop(struct GBAGUIRunner* runner) {
|
void GBAGUIRun(struct GBAGUIRunner* runner, const char* path) {
|
||||||
struct GBAGUIBackground drawState = {
|
struct GBAGUIBackground drawState = {
|
||||||
.d = {
|
.d = {
|
||||||
.draw = _drawState
|
.draw = _drawState
|
||||||
|
@ -185,177 +185,170 @@ void GBAGUIRunloop(struct GBAGUIRunner* runner) {
|
||||||
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Reset game", .data = (void*) RUNNER_RESET };
|
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Reset game", .data = (void*) RUNNER_RESET };
|
||||||
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Exit game", .data = (void*) RUNNER_EXIT };
|
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Exit game", .data = (void*) RUNNER_EXIT };
|
||||||
|
|
||||||
while (true) {
|
// TODO: Message box API
|
||||||
char path[256];
|
runner->params.drawStart();
|
||||||
if (!GUISelectFile(&runner->params, path, sizeof(path), 0)) {
|
if (runner->params.guiPrepare) {
|
||||||
break;
|
runner->params.guiPrepare();
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Message box API
|
|
||||||
runner->params.drawStart();
|
|
||||||
if (runner->params.guiPrepare) {
|
|
||||||
runner->params.guiPrepare();
|
|
||||||
}
|
|
||||||
GUIFontPrint(runner->params.font, runner->params.width / 2, (GUIFontHeight(runner->params.font) + runner->params.height) / 2, GUI_TEXT_CENTER, 0xFFFFFFFF, "Loading...");
|
|
||||||
if (runner->params.guiFinish) {
|
|
||||||
runner->params.guiFinish();
|
|
||||||
}
|
|
||||||
runner->params.drawEnd();
|
|
||||||
|
|
||||||
if (!GBAContextLoadROM(&runner->context, path, true)) {
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < 300; ++i) {
|
|
||||||
runner->params.drawStart();
|
|
||||||
if (runner->params.guiPrepare) {
|
|
||||||
runner->params.guiPrepare();
|
|
||||||
}
|
|
||||||
GUIFontPrint(runner->params.font, runner->params.width / 2, (GUIFontHeight(runner->params.font) + runner->params.height) / 2, GUI_TEXT_CENTER, 0xFFFFFFFF, "Load failed!");
|
|
||||||
if (runner->params.guiFinish) {
|
|
||||||
runner->params.guiFinish();
|
|
||||||
}
|
|
||||||
runner->params.drawEnd();
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
bool running = GBAContextStart(&runner->context);
|
|
||||||
if (runner->gameLoaded) {
|
|
||||||
runner->gameLoaded(runner);
|
|
||||||
}
|
|
||||||
while (running) {
|
|
||||||
CircleBufferClear(&runner->fpsBuffer);
|
|
||||||
runner->totalDelta = 0;
|
|
||||||
runner->fps = 0;
|
|
||||||
struct timeval tv;
|
|
||||||
gettimeofday(&tv, 0);
|
|
||||||
runner->lastFpsCheck = 1000000LL * tv.tv_sec + tv.tv_usec;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
uint32_t guiKeys;
|
|
||||||
GUIPollInput(&runner->params, &guiKeys, 0);
|
|
||||||
if (guiKeys & (1 << GUI_INPUT_CANCEL)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (guiKeys & (1 << GBA_GUI_INPUT_INCREASE_BRIGHTNESS)) {
|
|
||||||
if (runner->luminanceSource.luxLevel < 10) {
|
|
||||||
++runner->luminanceSource.luxLevel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (guiKeys & (1 << GBA_GUI_INPUT_DECREASE_BRIGHTNESS)) {
|
|
||||||
if (runner->luminanceSource.luxLevel > 0) {
|
|
||||||
--runner->luminanceSource.luxLevel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (guiKeys & (1 << GBA_GUI_INPUT_SCREEN_MODE) && runner->incrementScreenMode) {
|
|
||||||
runner->incrementScreenMode(runner);
|
|
||||||
}
|
|
||||||
uint16_t keys = runner->pollGameInput(runner);
|
|
||||||
if (runner->prepareForFrame) {
|
|
||||||
runner->prepareForFrame(runner);
|
|
||||||
}
|
|
||||||
GBAContextFrame(&runner->context, keys);
|
|
||||||
if (runner->drawFrame) {
|
|
||||||
int drawFps = false;
|
|
||||||
GBAConfigGetIntValue(&runner->context.config, "fpsCounter", &drawFps);
|
|
||||||
|
|
||||||
runner->params.drawStart();
|
|
||||||
runner->drawFrame(runner, false);
|
|
||||||
if (drawFps) {
|
|
||||||
if (runner->params.guiPrepare) {
|
|
||||||
runner->params.guiPrepare();
|
|
||||||
}
|
|
||||||
GUIFontPrintf(runner->params.font, 0, GUIFontHeight(runner->params.font), GUI_TEXT_LEFT, 0x7FFFFFFF, "%.2f fps", runner->fps);
|
|
||||||
if (runner->params.guiFinish) {
|
|
||||||
runner->params.guiFinish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
runner->params.drawEnd();
|
|
||||||
|
|
||||||
if (runner->context.gba->video.frameCounter % FPS_GRANULARITY == 0) {
|
|
||||||
if (drawFps) {
|
|
||||||
struct timeval tv;
|
|
||||||
gettimeofday(&tv, 0);
|
|
||||||
uint64_t t = 1000000LL * tv.tv_sec + tv.tv_usec;
|
|
||||||
uint64_t delta = t - runner->lastFpsCheck;
|
|
||||||
runner->lastFpsCheck = t;
|
|
||||||
if (delta > 0x7FFFFFFFLL) {
|
|
||||||
CircleBufferClear(&runner->fpsBuffer);
|
|
||||||
runner->fps = 0;
|
|
||||||
}
|
|
||||||
if (CircleBufferSize(&runner->fpsBuffer) == CircleBufferCapacity(&runner->fpsBuffer)) {
|
|
||||||
int32_t last;
|
|
||||||
CircleBufferRead32(&runner->fpsBuffer, &last);
|
|
||||||
runner->totalDelta -= last;
|
|
||||||
}
|
|
||||||
CircleBufferWrite32(&runner->fpsBuffer, delta);
|
|
||||||
runner->totalDelta += delta;
|
|
||||||
runner->fps = (CircleBufferSize(&runner->fpsBuffer) * FPS_GRANULARITY * 1000000.0f) / (runner->totalDelta * sizeof(uint32_t));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (runner->paused) {
|
|
||||||
runner->paused(runner);
|
|
||||||
}
|
|
||||||
GUIInvalidateKeys(&runner->params);
|
|
||||||
uint32_t keys = 0xFFFFFFFF; // Huge hack to avoid an extra variable!
|
|
||||||
struct GUIMenuItem* item;
|
|
||||||
enum GUIMenuExitReason reason = GUIShowMenu(&runner->params, &pauseMenu, &item);
|
|
||||||
if (reason == GUI_MENU_EXIT_ACCEPT) {
|
|
||||||
struct VFile* vf;
|
|
||||||
switch (((int) item->data) & RUNNER_COMMAND_MASK) {
|
|
||||||
case RUNNER_EXIT:
|
|
||||||
running = false;
|
|
||||||
keys = 0;
|
|
||||||
break;
|
|
||||||
case RUNNER_RESET:
|
|
||||||
GBAContextReset(&runner->context);
|
|
||||||
break;
|
|
||||||
case RUNNER_SAVE_STATE:
|
|
||||||
vf = GBAGetState(runner->context.gba, 0, ((int) item->data) >> 16, true);
|
|
||||||
if (vf) {
|
|
||||||
GBASaveStateNamed(runner->context.gba, vf, SAVESTATE_SCREENSHOT);
|
|
||||||
vf->close(vf);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case RUNNER_LOAD_STATE:
|
|
||||||
vf = GBAGetState(runner->context.gba, 0, ((int) item->data) >> 16, false);
|
|
||||||
if (vf) {
|
|
||||||
GBALoadStateNamed(runner->context.gba, vf, SAVESTATE_SCREENSHOT);
|
|
||||||
vf->close(vf);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case RUNNER_SCREENSHOT:
|
|
||||||
GBATakeScreenshot(runner->context.gba, 0);
|
|
||||||
break;
|
|
||||||
case RUNNER_CONFIG:
|
|
||||||
GBAGUIShowConfig(runner, runner->configExtra, runner->nConfigExtra);
|
|
||||||
GBAConfigGetIntValue(&runner->context.config, "frameskip", &runner->context.gba->video.frameskip);
|
|
||||||
break;
|
|
||||||
case RUNNER_CONTINUE:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int frames = 0;
|
|
||||||
GUIPollInput(&runner->params, 0, &keys);
|
|
||||||
while (keys && frames < 30) {
|
|
||||||
++frames;
|
|
||||||
runner->params.drawStart();
|
|
||||||
runner->drawFrame(runner, true);
|
|
||||||
runner->params.drawEnd();
|
|
||||||
GUIPollInput(&runner->params, 0, &keys);
|
|
||||||
}
|
|
||||||
if (runner->unpaused) {
|
|
||||||
runner->unpaused(runner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GBAContextStop(&runner->context);
|
|
||||||
if (runner->gameUnloaded) {
|
|
||||||
runner->gameUnloaded(runner);
|
|
||||||
}
|
|
||||||
GBAContextUnloadROM(&runner->context);
|
|
||||||
drawState.screenshotId = 0;
|
|
||||||
}
|
}
|
||||||
|
GUIFontPrint(runner->params.font, runner->params.width / 2, (GUIFontHeight(runner->params.font) + runner->params.height) / 2, GUI_TEXT_CENTER, 0xFFFFFFFF, "Loading...");
|
||||||
|
if (runner->params.guiFinish) {
|
||||||
|
runner->params.guiFinish();
|
||||||
|
}
|
||||||
|
runner->params.drawEnd();
|
||||||
|
|
||||||
|
if (!GBAContextLoadROM(&runner->context, path, true)) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 300; ++i) {
|
||||||
|
runner->params.drawStart();
|
||||||
|
if (runner->params.guiPrepare) {
|
||||||
|
runner->params.guiPrepare();
|
||||||
|
}
|
||||||
|
GUIFontPrint(runner->params.font, runner->params.width / 2, (GUIFontHeight(runner->params.font) + runner->params.height) / 2, GUI_TEXT_CENTER, 0xFFFFFFFF, "Load failed!");
|
||||||
|
if (runner->params.guiFinish) {
|
||||||
|
runner->params.guiFinish();
|
||||||
|
}
|
||||||
|
runner->params.drawEnd();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool running = GBAContextStart(&runner->context);
|
||||||
|
if (runner->gameLoaded) {
|
||||||
|
runner->gameLoaded(runner);
|
||||||
|
}
|
||||||
|
while (running) {
|
||||||
|
CircleBufferClear(&runner->fpsBuffer);
|
||||||
|
runner->totalDelta = 0;
|
||||||
|
runner->fps = 0;
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, 0);
|
||||||
|
runner->lastFpsCheck = 1000000LL * tv.tv_sec + tv.tv_usec;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
uint32_t guiKeys;
|
||||||
|
GUIPollInput(&runner->params, &guiKeys, 0);
|
||||||
|
if (guiKeys & (1 << GUI_INPUT_CANCEL)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (guiKeys & (1 << GBA_GUI_INPUT_INCREASE_BRIGHTNESS)) {
|
||||||
|
if (runner->luminanceSource.luxLevel < 10) {
|
||||||
|
++runner->luminanceSource.luxLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (guiKeys & (1 << GBA_GUI_INPUT_DECREASE_BRIGHTNESS)) {
|
||||||
|
if (runner->luminanceSource.luxLevel > 0) {
|
||||||
|
--runner->luminanceSource.luxLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (guiKeys & (1 << GBA_GUI_INPUT_SCREEN_MODE) && runner->incrementScreenMode) {
|
||||||
|
runner->incrementScreenMode(runner);
|
||||||
|
}
|
||||||
|
uint16_t keys = runner->pollGameInput(runner);
|
||||||
|
if (runner->prepareForFrame) {
|
||||||
|
runner->prepareForFrame(runner);
|
||||||
|
}
|
||||||
|
GBAContextFrame(&runner->context, keys);
|
||||||
|
if (runner->drawFrame) {
|
||||||
|
int drawFps = false;
|
||||||
|
GBAConfigGetIntValue(&runner->context.config, "fpsCounter", &drawFps);
|
||||||
|
|
||||||
|
runner->params.drawStart();
|
||||||
|
runner->drawFrame(runner, false);
|
||||||
|
if (drawFps) {
|
||||||
|
if (runner->params.guiPrepare) {
|
||||||
|
runner->params.guiPrepare();
|
||||||
|
}
|
||||||
|
GUIFontPrintf(runner->params.font, 0, GUIFontHeight(runner->params.font), GUI_TEXT_LEFT, 0x7FFFFFFF, "%.2f fps", runner->fps);
|
||||||
|
if (runner->params.guiFinish) {
|
||||||
|
runner->params.guiFinish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
runner->params.drawEnd();
|
||||||
|
|
||||||
|
if (runner->context.gba->video.frameCounter % FPS_GRANULARITY == 0) {
|
||||||
|
if (drawFps) {
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, 0);
|
||||||
|
uint64_t t = 1000000LL * tv.tv_sec + tv.tv_usec;
|
||||||
|
uint64_t delta = t - runner->lastFpsCheck;
|
||||||
|
runner->lastFpsCheck = t;
|
||||||
|
if (delta > 0x7FFFFFFFLL) {
|
||||||
|
CircleBufferClear(&runner->fpsBuffer);
|
||||||
|
runner->fps = 0;
|
||||||
|
}
|
||||||
|
if (CircleBufferSize(&runner->fpsBuffer) == CircleBufferCapacity(&runner->fpsBuffer)) {
|
||||||
|
int32_t last;
|
||||||
|
CircleBufferRead32(&runner->fpsBuffer, &last);
|
||||||
|
runner->totalDelta -= last;
|
||||||
|
}
|
||||||
|
CircleBufferWrite32(&runner->fpsBuffer, delta);
|
||||||
|
runner->totalDelta += delta;
|
||||||
|
runner->fps = (CircleBufferSize(&runner->fpsBuffer) * FPS_GRANULARITY * 1000000.0f) / (runner->totalDelta * sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runner->paused) {
|
||||||
|
runner->paused(runner);
|
||||||
|
}
|
||||||
|
GUIInvalidateKeys(&runner->params);
|
||||||
|
uint32_t keys = 0xFFFFFFFF; // Huge hack to avoid an extra variable!
|
||||||
|
struct GUIMenuItem* item;
|
||||||
|
enum GUIMenuExitReason reason = GUIShowMenu(&runner->params, &pauseMenu, &item);
|
||||||
|
if (reason == GUI_MENU_EXIT_ACCEPT) {
|
||||||
|
struct VFile* vf;
|
||||||
|
switch (((int) item->data) & RUNNER_COMMAND_MASK) {
|
||||||
|
case RUNNER_EXIT:
|
||||||
|
running = false;
|
||||||
|
keys = 0;
|
||||||
|
break;
|
||||||
|
case RUNNER_RESET:
|
||||||
|
GBAContextReset(&runner->context);
|
||||||
|
break;
|
||||||
|
case RUNNER_SAVE_STATE:
|
||||||
|
vf = GBAGetState(runner->context.gba, 0, ((int) item->data) >> 16, true);
|
||||||
|
if (vf) {
|
||||||
|
GBASaveStateNamed(runner->context.gba, vf, SAVESTATE_SCREENSHOT);
|
||||||
|
vf->close(vf);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RUNNER_LOAD_STATE:
|
||||||
|
vf = GBAGetState(runner->context.gba, 0, ((int) item->data) >> 16, false);
|
||||||
|
if (vf) {
|
||||||
|
GBALoadStateNamed(runner->context.gba, vf, SAVESTATE_SCREENSHOT);
|
||||||
|
vf->close(vf);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RUNNER_SCREENSHOT:
|
||||||
|
GBATakeScreenshot(runner->context.gba, 0);
|
||||||
|
break;
|
||||||
|
case RUNNER_CONFIG:
|
||||||
|
GBAGUIShowConfig(runner, runner->configExtra, runner->nConfigExtra);
|
||||||
|
GBAConfigGetIntValue(&runner->context.config, "frameskip", &runner->context.gba->video.frameskip);
|
||||||
|
break;
|
||||||
|
case RUNNER_CONTINUE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int frames = 0;
|
||||||
|
GUIPollInput(&runner->params, 0, &keys);
|
||||||
|
while (keys && frames < 30) {
|
||||||
|
++frames;
|
||||||
|
runner->params.drawStart();
|
||||||
|
runner->drawFrame(runner, true);
|
||||||
|
runner->params.drawEnd();
|
||||||
|
GUIPollInput(&runner->params, 0, &keys);
|
||||||
|
}
|
||||||
|
if (runner->unpaused) {
|
||||||
|
runner->unpaused(runner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GBAContextStop(&runner->context);
|
||||||
|
if (runner->gameUnloaded) {
|
||||||
|
runner->gameUnloaded(runner);
|
||||||
|
}
|
||||||
|
GBAContextUnloadROM(&runner->context);
|
||||||
|
drawState.screenshotId = 0;
|
||||||
if (drawState.screenshot) {
|
if (drawState.screenshot) {
|
||||||
mappedMemoryFree(drawState.screenshot, VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4);
|
mappedMemoryFree(drawState.screenshot, VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4);
|
||||||
}
|
}
|
||||||
|
@ -363,3 +356,13 @@ void GBAGUIRunloop(struct GBAGUIRunner* runner) {
|
||||||
GUIMenuItemListDeinit(&stateSaveMenu.items);
|
GUIMenuItemListDeinit(&stateSaveMenu.items);
|
||||||
GUIMenuItemListDeinit(&stateLoadMenu.items);
|
GUIMenuItemListDeinit(&stateLoadMenu.items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GBAGUIRunloop(struct GBAGUIRunner* runner) {
|
||||||
|
while (true) {
|
||||||
|
char path[PATH_MAX];
|
||||||
|
if (!GUISelectFile(&runner->params, path, sizeof(path), GBAIsROM)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
GBAGUIRun(runner, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -59,6 +59,7 @@ struct GBAGUIRunner {
|
||||||
|
|
||||||
void GBAGUIInit(struct GBAGUIRunner*, const char* port);
|
void GBAGUIInit(struct GBAGUIRunner*, const char* port);
|
||||||
void GBAGUIDeinit(struct GBAGUIRunner*);
|
void GBAGUIDeinit(struct GBAGUIRunner*);
|
||||||
|
void GBAGUIRun(struct GBAGUIRunner*, const char* path);
|
||||||
void GBAGUIRunloop(struct GBAGUIRunner*);
|
void GBAGUIRunloop(struct GBAGUIRunner*);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue