src/main.c (view raw)
1#include "debugger.h"
2#include "gba-thread.h"
3#include "gba.h"
4#include "renderers/video-software.h"
5
6#include <sdl.h>
7#include <OpenGL/gl.h>
8
9#include <fcntl.h>
10#include <errno.h>
11#include <signal.h>
12#include <sys/time.h>
13#include <unistd.h>
14
15struct GLSoftwareRenderer {
16 struct GBAVideoSoftwareRenderer d;
17
18 GLuint tex;
19};
20
21static int _GBASDLInit(struct GLSoftwareRenderer* renderer);
22static void _GBASDLDeinit(struct GLSoftwareRenderer* renderer);
23static void _GBASDLRunloop(struct GBAThread* context, struct GLSoftwareRenderer* renderer);
24static void _GBASDLHandleKeypress(struct GBAThread* context, const struct SDL_KeyboardEvent* event);
25
26static const GLint _glVertices[] = {
27 0, 0,
28 256, 0,
29 256, 256,
30 0, 256
31};
32
33static const GLint _glTexCoords[] = {
34 0, 0,
35 1, 0,
36 1, 1,
37 0, 1
38};
39
40int main(int argc, char** argv) {
41 (void)(argc);
42 (void)(argv);
43 int fd = open("test.rom", O_RDONLY);
44
45 sigset_t signals;
46 sigaddset(&signals, SIGINT);
47 sigaddset(&signals, SIGTRAP);
48 pthread_sigmask(SIG_BLOCK, &signals, 0);
49
50 struct GBAThread context;
51 struct GLSoftwareRenderer renderer;
52 GBAVideoSoftwareRendererCreate(&renderer.d);
53
54 if (!_GBASDLInit(&renderer)) {
55 return 1;
56 }
57
58 context.fd = fd;
59 context.renderer = &renderer.d.d;
60 GBAThreadStart(&context);
61
62 _GBASDLRunloop(&context, &renderer);
63
64 GBAThreadJoin(&context);
65 close(fd);
66
67 _GBASDLDeinit(&renderer);
68
69 return 0;
70}
71
72static int _GBASDLInit(struct GLSoftwareRenderer* renderer) {
73 if (SDL_Init(SDL_INIT_VIDEO) < 0) {
74 return 0;
75 }
76
77 SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
78 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
79 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
80 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
81 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
82 SDL_SetVideoMode(240, 160, 16, SDL_OPENGL);
83
84 renderer->d.outputBuffer = malloc(256 * 256 * 2);
85 renderer->d.outputBufferStride = 256;
86 glGenTextures(1, &renderer->tex);
87 glBindTexture(GL_TEXTURE_2D, renderer->tex);
88 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
89 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
90 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
91 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
92 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
93
94 glViewport(0, 0, 240, 160);
95
96 return 1;
97}
98
99static void _GBASDLRunloop(struct GBAThread* context, struct GLSoftwareRenderer* renderer) {
100 SDL_Event event;
101
102 int err;
103 glEnable(GL_TEXTURE_2D);
104 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
105 glEnableClientState(GL_VERTEX_ARRAY);
106 glVertexPointer(2, GL_INT, 0, _glVertices);
107 glTexCoordPointer(2, GL_INT, 0, _glTexCoords);
108 glMatrixMode (GL_PROJECTION);
109 glLoadIdentity();
110 glOrtho(0, 240, 160, 0, 0, 1);
111 while (context->started) {
112 pthread_mutex_lock(&renderer->d.mutex);
113 if (renderer->d.d.framesPending) {
114 renderer->d.d.framesPending = 0;
115 pthread_mutex_unlock(&renderer->d.mutex);
116 glBindTexture(GL_TEXTURE_2D, renderer->tex);
117 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, renderer->d.outputBuffer);
118 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
119
120 SDL_GL_SwapBuffers();
121 pthread_mutex_lock(&renderer->d.mutex);
122 pthread_cond_broadcast(&renderer->d.downCond);
123 pthread_mutex_unlock(&renderer->d.mutex);
124 } else {
125 while (!renderer->d.d.framesPending) {
126 struct timeval tv;
127 struct timespec ts;
128 gettimeofday(&tv, 0);
129 ts.tv_sec = tv.tv_sec;
130 ts.tv_nsec = tv.tv_usec * 1000 + 800000;
131 int err = pthread_cond_timedwait(&renderer->d.upCond, &renderer->d.mutex, &ts);
132 if (err == ETIMEDOUT) {
133 break;
134 }
135 }
136 pthread_mutex_unlock(&renderer->d.mutex);
137 }
138 while (SDL_PollEvent(&event)) {
139 switch (event.type) {
140 case SDL_QUIT:
141 // FIXME: this isn't thread-safe
142 context->debugger->state = DEBUGGER_EXITING;
143 break;
144 case SDL_KEYDOWN:
145 case SDL_KEYUP:
146 _GBASDLHandleKeypress(context, &event.key);
147 break;
148 }
149 }
150 }
151}
152
153static void _GBASDLDeinit(struct GLSoftwareRenderer* renderer) {
154 free(renderer->d.outputBuffer);
155
156 SDL_Quit();
157}
158
159static void _GBASDLHandleKeypress(struct GBAThread* context, const struct SDL_KeyboardEvent* event) {
160 enum GBAKey key = 0;
161 switch (event->keysym.sym) {
162 case SDLK_z:
163 key = GBA_KEY_A;
164 break;
165 case SDLK_x:
166 key = GBA_KEY_B;
167 break;
168 case SDLK_a:
169 key = GBA_KEY_L;
170 break;
171 case SDLK_s:
172 key = GBA_KEY_R;
173 break;
174 case SDLK_RETURN:
175 key = GBA_KEY_START;
176 break;
177 case SDLK_BACKSPACE:
178 key = GBA_KEY_SELECT;
179 break;
180 case SDLK_UP:
181 key = GBA_KEY_UP;
182 break;
183 case SDLK_DOWN:
184 key = GBA_KEY_DOWN;
185 break;
186 case SDLK_LEFT:
187 key = GBA_KEY_LEFT;
188 break;
189 case SDLK_RIGHT:
190 key = GBA_KEY_RIGHT;
191 break;
192 case SDLK_TAB:
193 context->renderer->turbo = !context->renderer->turbo;
194 return;
195 default:
196 return;
197 }
198
199 if (event->type == SDL_KEYDOWN) {
200 context->activeKeys |= 1 << key;
201 } else {
202 context->activeKeys &= ~(1 << key);
203 }
204}