all repos — mgba @ d724d914c89304c339d738d924bed5a929d8a891

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
 21static void _drawBackground(struct GUIBackground* background) {
 22	struct GBAGUIBackground* gbaBackground = (struct GBAGUIBackground*) background;
 23	if (gbaBackground->p->drawFrame) {
 24		gbaBackground->p->drawFrame(gbaBackground->p, true);
 25	}
 26}
 27
 28void GBAGUIInit(struct GBAGUIRunner* runner, const char* port) {
 29	GUIInit(&runner->params);
 30	GBAContextInit(&runner->context, port);
 31	runner->background.d.draw = _drawBackground;
 32	runner->background.p = runner;
 33	if (runner->setup) {
 34		runner->setup(runner);
 35	}
 36}
 37
 38void GBAGUIDeinit(struct GBAGUIRunner* runner) {
 39	if (runner->teardown) {
 40		runner->teardown(runner);
 41	}
 42	GBAContextDeinit(&runner->context);
 43}
 44
 45void GBAGUIRunloop(struct GBAGUIRunner* runner) {
 46	struct GUIMenu pauseMenu = {
 47		.title = "Game Paused",
 48		.index = 0,
 49		.background = &runner->background.d
 50	};
 51	GUIMenuItemListInit(&pauseMenu.items, 0);
 52	*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Unpause", .data = (void*) RUNNER_CONTINUE };
 53#if !(defined(__POWERPC__) || defined(__PPC__))
 54	// PPC doesn't have working savestates yet
 55	*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Save state", .data = (void*) RUNNER_SAVE_STATE };
 56	*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Load state", .data = (void*) RUNNER_LOAD_STATE };
 57#endif
 58	*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Exit game", .data = (void*) RUNNER_EXIT };
 59
 60	while (true) {
 61		char path[256];
 62		if (!GUISelectFile(&runner->params, path, sizeof(path), GBAIsROM)) {
 63			if (runner->params.guiFinish) {
 64				runner->params.guiFinish();
 65			}
 66			GUIMenuItemListDeinit(&pauseMenu.items);
 67			return;
 68		}
 69
 70		if (runner->params.guiPrepare) {
 71			runner->params.guiPrepare();
 72		}
 73		// TODO: Message box API
 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, "Loading...");
 76		runner->params.drawEnd();
 77		runner->params.drawStart();
 78		GUIFontPrint(runner->params.font, runner->params.width / 2, (GUIFontHeight(runner->params.font) + runner->params.height) / 2, GUI_TEXT_CENTER, 0xFFFFFFFF, "Loading...");
 79		runner->params.drawEnd();
 80
 81		if (!GBAContextLoadROM(&runner->context, path, true)) {
 82			int i;
 83			for (i = 0; i < 300; ++i) {
 84				runner->params.drawStart();
 85				GUIFontPrint(runner->params.font, runner->params.width / 2, (GUIFontHeight(runner->params.font) + runner->params.height) / 2, GUI_TEXT_CENTER, 0xFFFFFFFF, "Load failed!");
 86				runner->params.drawEnd();
 87			}
 88		}
 89		if (runner->params.guiFinish) {
 90			runner->params.guiFinish();
 91		}
 92		GBAContextStart(&runner->context);
 93		if (runner->gameLoaded) {
 94			runner->gameLoaded(runner);
 95		}
 96		bool running = true;
 97		while (running) {
 98			while (true) {
 99				int guiKeys = runner->params.pollInput();
100				if (guiKeys & (1 << GUI_INPUT_CANCEL)) {
101					break;
102				}
103				uint16_t keys = runner->pollGameInput(runner);
104				if (runner->prepareForFrame) {
105					runner->prepareForFrame(runner);
106				}
107				GBAContextFrame(&runner->context, keys);
108				if (runner->drawFrame) {
109					runner->params.drawStart();
110					runner->drawFrame(runner, false);
111					runner->params.drawEnd();
112				}
113			}
114
115			GUIInvalidateKeys(&runner->params);
116			int keys = -1; // Huge hack to avoid an extra variable!
117			struct GUIMenuItem item;
118			enum GUIMenuExitReason reason = GUIShowMenu(&runner->params, &pauseMenu, &item);
119			if (reason == GUI_MENU_EXIT_ACCEPT) {
120				struct VFile* vf;
121				switch ((int) item.data) {
122				case RUNNER_EXIT:
123					running = false;
124					keys = 0;
125					break;
126				case RUNNER_SAVE_STATE:
127					vf = GBAGetState(runner->context.gba, 0, 1, true);
128					if (vf) {
129						GBASaveStateNamed(runner->context.gba, vf, true);
130						vf->close(vf);
131					}
132					break;
133				case RUNNER_LOAD_STATE:
134					vf = GBAGetState(runner->context.gba, 0, 1, false);
135					if (vf) {
136						GBALoadStateNamed(runner->context.gba, vf);
137						vf->close(vf);
138					}
139					break;
140				case RUNNER_CONTINUE:
141					break;
142				}
143			}
144			while (keys) {
145				GUIPollInput(&runner->params, 0, &keys);
146			}
147			if (runner->params.guiFinish) {
148				runner->params.guiFinish();
149			}
150		}
151		GBAContextStop(&runner->context);
152		if (runner->gameUnloaded) {
153			runner->gameUnloaded(runner);
154		}
155		GBAContextUnloadROM(&runner->context);
156	}
157	GUIMenuItemListDeinit(&pauseMenu.items);
158}