all repos — mgba @ 754725e1244bbf6c4aa8d54c0e4f7c0370f921ad

mGBA Game Boy Advance Emulator

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}