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}