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