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 GBAConfig config;
35 GBAConfigInit(&config, PORT);
36 GBAConfigLoad(&config);
37
38 struct GBAOptions opts = {
39 .audioBuffers = 512,
40 .videoSync = false,
41 .audioSync = true,
42 };
43 GBAConfigLoadDefaults(&config, &opts);
44
45 struct GBAArguments args = {};
46 struct GraphicsOpts graphicsOpts = {};
47
48 struct SubParser subparser;
49
50 GBAConfigMap(&config, &opts);
51
52 initParserForGraphics(&subparser, &graphicsOpts);
53 if (!parseArguments(&args, &config, argc, argv, &subparser)) {
54 usage(argv[0], subparser.usage);
55 freeArguments(&args);
56 GBAConfigFreeOpts(&opts);
57 GBAConfigDeinit(&config);
58 return 1;
59 }
60
61 renderer.viewportWidth = opts.width;
62 renderer.viewportHeight = opts.height;
63#if SDL_VERSION_ATLEAST(2, 0, 0)
64 renderer.events.fullscreen = opts.fullscreen;
65 renderer.events.windowUpdated = 0;
66#endif
67 renderer.ratio = graphicsOpts.multiplier;
68
69 if (!_GBASDLInit(&renderer)) {
70 freeArguments(&args);
71 GBAConfigFreeOpts(&opts);
72 GBAConfigDeinit(&config);
73 return 1;
74 }
75
76 struct GBAThread context = {
77 .renderer = &renderer.d.d,
78 .startCallback = _GBASDLStart,
79 .cleanCallback = _GBASDLClean,
80 .userData = &renderer
81 };
82
83 context.debugger = createDebugger(&args);
84
85 GBAMapOptionsToContext(&opts, &context);
86 GBAMapArgumentsToContext(&args, &context);
87
88 renderer.audio.samples = context.audioBuffers;
89 GBASDLInitAudio(&renderer.audio);
90
91 renderer.events.bindings = &context.inputMap;
92 GBASDLInitEvents(&renderer.events);
93 GBASDLEventsLoadConfig(&renderer.events, &config.configTable); // TODO: Don't use this directly
94
95 GBAThreadStart(&context);
96
97 GBASDLRunloop(&context, &renderer);
98
99 GBAThreadJoin(&context);
100 freeArguments(&args);
101 GBAConfigFreeOpts(&opts);
102 GBAConfigDeinit(&config);
103 free(context.debugger);
104
105 _GBASDLDeinit(&renderer);
106
107 return 0;
108}
109
110static bool _GBASDLInit(struct SDLSoftwareRenderer* renderer) {
111 if (SDL_Init(SDL_INIT_VIDEO) < 0) {
112 return false;
113 }
114
115 return GBASDLInit(renderer);
116}
117
118static void _GBASDLDeinit(struct SDLSoftwareRenderer* renderer) {
119 free(renderer->d.outputBuffer);
120
121 GBASDLDeinitEvents(&renderer->events);
122 GBASDLDeinitAudio(&renderer->audio);
123#if SDL_VERSION_ATLEAST(2, 0, 0)
124 SDL_DestroyWindow(renderer->window);
125#endif
126
127 GBASDLDeinit(renderer);
128
129 SDL_Quit();
130
131}
132
133static void _GBASDLStart(struct GBAThread* threadContext) {
134 struct SDLSoftwareRenderer* renderer = threadContext->userData;
135 renderer->audio.audio = &threadContext->gba->audio;
136 renderer->audio.thread = threadContext;
137}
138
139static void _GBASDLClean(struct GBAThread* threadContext) {
140 struct SDLSoftwareRenderer* renderer = threadContext->userData;
141 renderer->audio.audio = 0;
142}