src/platform/sdl/sw-main.c (view raw)
1#ifdef USE_CLI_DEBUGGER
2#include "debugger/cli-debugger.h"
3#endif
4
5#ifdef USE_GDB_STUB
6#include "debugger/gdb-stub.h"
7#endif
8
9#include "gba-thread.h"
10#include "gba.h"
11#include "renderers/video-software.h"
12#include "sdl-audio.h"
13#include "sdl-events.h"
14
15#include <SDL.h>
16
17#include <errno.h>
18#include <signal.h>
19#include <sys/time.h>
20
21struct SoftwareRenderer {
22 struct GBAVideoSoftwareRenderer d;
23 struct GBASDLAudio audio;
24 struct GBASDLEvents events;
25};
26
27static int _GBASDLInit(struct SoftwareRenderer* renderer);
28static void _GBASDLDeinit(struct SoftwareRenderer* renderer);
29static void _GBASDLRunloop(struct GBAThread* context, struct SoftwareRenderer* renderer);
30static void _GBASDLStart(struct GBAThread* context);
31static void _GBASDLClean(struct GBAThread* context);
32
33int main(int argc, char** argv) {
34 struct SoftwareRenderer renderer;
35 GBAVideoSoftwareRendererCreate(&renderer.d);
36
37 struct StartupOptions opts;
38 if (!parseCommandArgs(&opts, argc, argv, GRAPHICS_OPTIONS)) {
39 usage(argv[0], GRAPHICS_USAGE);
40 return 1;
41 }
42
43 if (!_GBASDLInit(&renderer)) {
44 return 1;
45 }
46
47 struct GBAThread context = {
48 .renderer = &renderer.d.d,
49 .startCallback = _GBASDLStart,
50 .cleanCallback = _GBASDLClean,
51 .sync.videoFrameWait = 0,
52 .sync.audioWait = 1,
53 .userData = &renderer
54 };
55
56 context.debugger = createDebugger(&opts);
57
58 GBAMapOptionsToContext(&opts, &context);
59
60 SDL_Surface* surface = SDL_GetVideoSurface();
61 SDL_LockSurface(surface);
62 renderer.d.outputBuffer = surface->pixels;
63#ifdef COLOR_16_BIT
64 renderer.d.outputBufferStride = surface->pitch / 2;
65#else
66 renderer.d.outputBufferStride = surface->pitch / 4;
67#endif
68
69 GBAThreadStart(&context);
70
71 _GBASDLRunloop(&context, &renderer);
72
73 SDL_UnlockSurface(surface);
74 GBAThreadJoin(&context);
75 close(opts.fd);
76 if (opts.biosFd >= 0) {
77 close(opts.biosFd);
78 }
79 free(context.debugger);
80
81 _GBASDLDeinit(&renderer);
82
83 return 0;
84}
85
86static int _GBASDLInit(struct SoftwareRenderer* renderer) {
87 if (SDL_Init(SDL_INIT_VIDEO) < 0) {
88 return 0;
89 }
90
91 GBASDLInitEvents(&renderer->events);
92 GBASDLInitAudio(&renderer->audio);
93
94#ifdef COLOR_16_BIT
95 SDL_SetVideoMode(240, 160, 16, SDL_DOUBLEBUF | SDL_HWSURFACE);
96#else
97 SDL_SetVideoMode(240, 160, 32, SDL_DOUBLEBUF | SDL_HWSURFACE);
98#endif
99
100 return 1;
101}
102
103static void _GBASDLRunloop(struct GBAThread* context, struct SoftwareRenderer* renderer) {
104 SDL_Event event;
105 SDL_Surface* surface = SDL_GetVideoSurface();
106
107 while (context->state < THREAD_EXITING) {
108 if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) {
109 SDL_UnlockSurface(surface);
110 SDL_Flip(surface);
111 SDL_LockSurface(surface);
112 }
113 GBASyncWaitFrameEnd(&context->sync);
114
115 while (SDL_PollEvent(&event)) {
116 GBASDLHandleEvent(context, &renderer->events, &event);
117 }
118 }
119}
120
121static void _GBASDLDeinit(struct SoftwareRenderer* renderer) {
122 GBASDLDeinitEvents(&renderer->events);
123 GBASDLDeinitAudio(&renderer->audio);
124 SDL_Quit();
125}
126
127static void _GBASDLStart(struct GBAThread* threadContext) {
128 struct SoftwareRenderer* renderer = threadContext->userData;
129 renderer->audio.audio = &threadContext->gba->audio;
130}
131
132static void _GBASDLClean(struct GBAThread* threadContext) {
133 struct SoftwareRenderer* renderer = threadContext->userData;
134 renderer->audio.audio = 0;
135}