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