src/platform/sdl/main.c (view raw)
1#include "main.h"
2
3#ifdef USE_CLI_DEBUGGER
4#include "debugger/cli-debugger.h"
5#endif
6
7#ifdef USE_GDB_STUB
8#include "debugger/gdb-stub.h"
9#endif
10
11#include "gba-thread.h"
12#include "gba.h"
13#include "gba-config.h"
14#include "platform/commandline.h"
15#include "util/configuration.h"
16
17#include <SDL.h>
18
19#include <errno.h>
20#include <signal.h>
21#include <sys/time.h>
22
23#define PORT "sdl"
24
25static bool _GBASDLInit(struct SDLSoftwareRenderer* renderer);
26static void _GBASDLDeinit(struct SDLSoftwareRenderer* renderer);
27static void _GBASDLStart(struct GBAThread* context);
28static void _GBASDLClean(struct GBAThread* context);
29
30int main(int argc, char** argv) {
31 struct SDLSoftwareRenderer renderer;
32 GBAVideoSoftwareRendererCreate(&renderer.d);
33
34 struct GBAInputMap inputMap;
35 GBAInputMapInit(&inputMap);
36
37 struct GBAConfig config;
38 GBAConfigInit(&config, PORT);
39 GBAConfigLoad(&config);
40
41 struct GBAOptions opts = {
42 .audioBuffers = 512,
43 .videoSync = false,
44 .audioSync = true,
45 };
46 GBAConfigLoadDefaults(&config, &opts);
47
48 struct GBAArguments args = {};
49 struct GraphicsOpts graphicsOpts = {};
50
51 struct SubParser subparser;
52
53 GBAConfigMap(&config, &opts);
54
55 initParserForGraphics(&subparser, &graphicsOpts);
56 if (!parseArguments(&args, &config, argc, argv, &subparser)) {
57 usage(argv[0], subparser.usage);
58 freeArguments(&args);
59 GBAConfigFreeOpts(&opts);
60 GBAConfigDeinit(&config);
61 return 1;
62 }
63
64 renderer.viewportWidth = opts.width;
65 renderer.viewportHeight = opts.height;
66#if SDL_VERSION_ATLEAST(2, 0, 0)
67 renderer.events.fullscreen = opts.fullscreen;
68 renderer.events.windowUpdated = 0;
69#endif
70 renderer.ratio = graphicsOpts.multiplier;
71
72 if (!_GBASDLInit(&renderer)) {
73 freeArguments(&args);
74 GBAConfigFreeOpts(&opts);
75 GBAConfigDeinit(&config);
76 return 1;
77 }
78
79 struct GBAThread context = {
80 .renderer = &renderer.d.d,
81 .startCallback = _GBASDLStart,
82 .cleanCallback = _GBASDLClean,
83 .userData = &renderer
84 };
85
86 context.debugger = createDebugger(&args);
87
88 GBAMapOptionsToContext(&opts, &context);
89 GBAMapArgumentsToContext(&args, &context);
90
91 renderer.audio.samples = context.audioBuffers;
92 GBASDLInitAudio(&renderer.audio);
93
94 renderer.events.bindings = &inputMap;
95 GBASDLInitindings(&inputMap);
96 GBASDLInitEvents(&renderer.events);
97 GBASDLEventsLoadConfig(&renderer.events, &config.configTable); // TODO: Don't use this directly
98
99 GBAThreadStart(&context);
100
101 GBASDLRunloop(&context, &renderer);
102
103 GBAThreadJoin(&context);
104 freeArguments(&args);
105 GBAConfigFreeOpts(&opts);
106 GBAConfigDeinit(&config);
107 free(context.debugger);
108 GBAInputMapDeinit(&inputMap);
109
110 _GBASDLDeinit(&renderer);
111
112 return 0;
113}
114
115static bool _GBASDLInit(struct SDLSoftwareRenderer* renderer) {
116 if (SDL_Init(SDL_INIT_VIDEO) < 0) {
117 return false;
118 }
119
120 return GBASDLInit(renderer);
121}
122
123static void _GBASDLDeinit(struct SDLSoftwareRenderer* renderer) {
124 free(renderer->d.outputBuffer);
125
126 GBASDLDeinitEvents(&renderer->events);
127 GBASDLDeinitAudio(&renderer->audio);
128#if SDL_VERSION_ATLEAST(2, 0, 0)
129 SDL_DestroyWindow(renderer->window);
130#endif
131
132 GBASDLDeinit(renderer);
133
134 SDL_Quit();
135
136}
137
138static void _GBASDLStart(struct GBAThread* threadContext) {
139 struct SDLSoftwareRenderer* renderer = threadContext->userData;
140 renderer->audio.audio = &threadContext->gba->audio;
141 renderer->audio.thread = threadContext;
142}
143
144static void _GBASDLClean(struct GBAThread* threadContext) {
145 struct SDLSoftwareRenderer* renderer = threadContext->userData;
146 renderer->audio.audio = 0;
147}