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 glBindTexture(GL_TEXTURE_2D, renderer->tex);
110 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, renderer->d.outputBuffer);
111 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
112
113 pthread_mutex_lock(&renderer->d.mutex);
114 if (renderer->d.d.framesPending) {
115 --renderer->d.d.framesPending;
116 pthread_mutex_unlock(&renderer->d.mutex);
117 SDL_GL_SwapBuffers();
118 pthread_mutex_lock(&renderer->d.mutex);
119 }
120 pthread_cond_broadcast(&renderer->d.cond);
121 pthread_mutex_unlock(&renderer->d.mutex);
122 while (SDL_PollEvent(&event)) {
123 switch (event.type) {
124 case SDL_QUIT:
125 // FIXME: this isn't thread-safe
126 context->debugger->state = DEBUGGER_EXITING;
127 break;
128 case SDL_KEYDOWN:
129 case SDL_KEYUP:
130 _GBASDLHandleKeypress(context, &event.key);
131 break;
132 }
133 }
134 }
135}
136
137static void _GBASDLDeinit(struct GLSoftwareRenderer* renderer) {
138 free(renderer->d.outputBuffer);
139
140 SDL_Quit();
141}
142
143static void _GBASDLHandleKeypress(struct GBAThread* context, const struct SDL_KeyboardEvent* event) {
144 enum GBAKey key = 0;
145 switch (event->keysym.sym) {
146 case SDLK_z:
147 key = GBA_KEY_A;
148 break;
149 case SDLK_x:
150 key = GBA_KEY_B;
151 break;
152 case SDLK_a:
153 key = GBA_KEY_L;
154 break;
155 case SDLK_s:
156 key = GBA_KEY_R;
157 break;
158 case SDLK_RETURN:
159 key = GBA_KEY_START;
160 break;
161 case SDLK_BACKSPACE:
162 key = GBA_KEY_SELECT;
163 break;
164 case SDLK_UP:
165 key = GBA_KEY_UP;
166 break;
167 case SDLK_DOWN:
168 key = GBA_KEY_DOWN;
169 break;
170 case SDLK_LEFT:
171 key = GBA_KEY_LEFT;
172 break;
173 case SDLK_RIGHT:
174 key = GBA_KEY_RIGHT;
175 break;
176 case SDLK_TAB:
177 context->renderer->turbo = !context->renderer->turbo;
178 return;
179 default:
180 return;
181 }
182
183 if (event->type == SDL_KEYDOWN) {
184 context->activeKeys |= 1 << key;
185 } else {
186 context->activeKeys &= ~(1 << key);
187 }
188}