all repos — mgba @ e6429cc8a255fc9ee63cb0463b6fae8015b8038f

mGBA Game Boy Advance Emulator

src/gba/gui/gui-runner.c (view raw)

  1/* Copyright (c) 2013-2015 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include "gui-runner.h"
  7
  8#include "gba/serialize.h"
  9#include "util/gui/file-select.h"
 10#include "util/gui/font.h"
 11#include "util/gui/menu.h"
 12#include "util/vfs.h"
 13
 14enum {
 15	RUNNER_CONTINUE,
 16	RUNNER_EXIT,
 17	RUNNER_SAVE_STATE,
 18	RUNNER_LOAD_STATE,
 19};
 20
 21void GBAGUIInit(struct GBAGUIRunner* runner, const char* port) {
 22	GUIInit(&runner->params);
 23	GBAContextInit(&runner->context, port);
 24	if (runner->setup) {
 25		runner->setup(runner);
 26	}
 27}
 28
 29void GBAGUIDeinit(struct GBAGUIRunner* runner) {
 30	if (runner->teardown) {
 31		runner->teardown(runner);
 32	}
 33	GBAContextDeinit(&runner->context);
 34}
 35
 36void GBAGUIRunloop(struct GBAGUIRunner* runner) {
 37	struct GUIMenu pauseMenu = {
 38		.title = "Game Paused",
 39		.index = 0,
 40	};
 41	GUIMenuItemListInit(&pauseMenu.items, 0);
 42	*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Unpause", .data = (void*) RUNNER_CONTINUE };
 43#if !(defined(__POWERPC__) || defined(__PPC__))
 44	// PPC doesn't have working savestates yet
 45	*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Save state", .data = (void*) RUNNER_SAVE_STATE };
 46	*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Load state", .data = (void*) RUNNER_LOAD_STATE };
 47#endif
 48	*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Exit game", .data = (void*) RUNNER_EXIT };
 49
 50	while (true) {
 51		if (runner->params.guiPrepare) {
 52			runner->params.guiPrepare();
 53		}
 54		char path[256];
 55		if (!GUISelectFile(&runner->params, path, sizeof(path), GBAIsROM)) {
 56			if (runner->params.guiFinish) {
 57				runner->params.guiFinish();
 58			}
 59			GUIMenuItemListDeinit(&pauseMenu.items);
 60			return;
 61		}
 62
 63		// TODO: Message box API
 64		runner->params.drawStart();
 65		GUIFontPrint(runner->params.font, runner->params.width / 2, (GUIFontHeight(runner->params.font) + runner->params.height) / 2, GUI_TEXT_CENTER, 0xFFFFFFFF, "Loading...");
 66		runner->params.drawEnd();
 67		runner->params.drawStart();
 68		GUIFontPrint(runner->params.font, runner->params.width / 2, (GUIFontHeight(runner->params.font) + runner->params.height) / 2, GUI_TEXT_CENTER, 0xFFFFFFFF, "Loading...");
 69		runner->params.drawEnd();
 70
 71		if (!GBAContextLoadROM(&runner->context, path, true)) {
 72			int i;
 73			for (i = 0; i < 300; ++i) {
 74				runner->params.drawStart();
 75				GUIFontPrint(runner->params.font, runner->params.width / 2, (GUIFontHeight(runner->params.font) + runner->params.height) / 2, GUI_TEXT_CENTER, 0xFFFFFFFF, "Load failed!");
 76				runner->params.drawEnd();
 77			}
 78		}
 79		if (runner->params.guiFinish) {
 80			runner->params.guiFinish();
 81		}
 82		GBAContextStart(&runner->context);
 83		if (runner->gameLoaded) {
 84			runner->gameLoaded(runner);
 85		}
 86		bool running = true;
 87		while (running) {
 88			while (true) {
 89				int guiKeys = runner->params.pollInput();
 90				if (guiKeys & (1 << GUI_INPUT_CANCEL)) {
 91					break;
 92				}
 93				uint16_t keys = runner->pollGameInput(runner);
 94				if (runner->prepareForFrame) {
 95					runner->prepareForFrame(runner);
 96				}
 97				GBAContextFrame(&runner->context, keys);
 98				if (runner->drawFrame) {
 99					runner->drawFrame(runner, false);
100				}
101			}
102
103			if (runner->params.guiPrepare) {
104				runner->params.guiPrepare();
105			}
106			GUIInvalidateKeys(&runner->params);
107			int keys = -1; // Huge hack to avoid an extra variable!
108			struct GUIMenuItem item;
109			enum GUIMenuExitReason reason = GUIShowMenu(&runner->params, &pauseMenu, &item);
110			if (reason == GUI_MENU_EXIT_ACCEPT) {
111				struct VFile* vf;
112				switch ((int) item.data) {
113				case RUNNER_EXIT:
114					running = false;
115					keys = 0;
116					break;
117				case RUNNER_SAVE_STATE:
118					vf = GBAGetState(runner->context.gba, 0, 1, true);
119					if (vf) {
120						GBASaveStateNamed(runner->context.gba, vf, true);
121						vf->close(vf);
122					}
123					break;
124				case RUNNER_LOAD_STATE:
125					vf = GBAGetState(runner->context.gba, 0, 1, false);
126					if (vf) {
127						GBALoadStateNamed(runner->context.gba, vf);
128						vf->close(vf);
129					}
130					break;
131				case RUNNER_CONTINUE:
132					break;
133				}
134			}
135			while (keys) {
136				GUIPollInput(&runner->params, 0, &keys);
137			}
138			if (runner->params.guiFinish) {
139				runner->params.guiFinish();
140			}
141		}
142		GBAContextStop(&runner->context);
143		if (runner->gameUnloaded) {
144			runner->gameUnloaded(runner);
145		}
146		GBAContextUnloadROM(&runner->context);
147	}
148	GUIMenuItemListDeinit(&pauseMenu.items);
149}