src/platform/sdl/gl-sdl.c (view raw)
1/* Copyright (c) 2013-2015 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "main.h"
7
8#include "gl-common.h"
9
10#include "gba/supervisor/thread.h"
11#ifdef M_CORE_GB
12#include "gb/gb.h"
13#endif
14#include "platform/opengl/gl.h"
15
16#define GB_GBA_CENTER ((VIDEO_HORIZONTAL_PIXELS - GB_VIDEO_HORIZONTAL_PIXELS + VIDEO_HORIZONTAL_PIXELS * (VIDEO_VERTICAL_PIXELS - GB_VIDEO_VERTICAL_PIXELS)) / 2)
17
18static void _doViewport(int w, int h, struct VideoBackend* v) {
19 v->resized(v, w, h);
20 v->clear(v);
21 v->swap(v);
22 v->clear(v);
23}
24
25#ifdef M_CORE_GBA
26static bool mSDLGLInitGBA(struct mSDLRenderer* renderer);
27static void mSDLGLRunloopGBA(struct mSDLRenderer* renderer, void* user);
28static void mSDLGLDeinitGBA(struct mSDLRenderer* renderer);
29#endif
30#ifdef M_CORE_GB
31static bool mSDLGLInitGB(struct mSDLRenderer* renderer);
32static void mSDLGLRunloopGB(struct mSDLRenderer* renderer, void* user);
33static void mSDLGLDeinitGB(struct mSDLRenderer* renderer);
34#endif
35
36#ifdef M_CORE_GBA
37void mSDLGLCreate(struct mSDLRenderer* renderer) {
38 renderer->init = mSDLGLInitGBA;
39 renderer->deinit = mSDLGLDeinitGBA;
40 renderer->runloop = mSDLGLRunloopGBA;
41}
42
43bool mSDLGLInitGBA(struct mSDLRenderer* renderer) {
44 mSDLGLCommonInit(renderer);
45
46 renderer->d.outputBuffer = malloc(VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL);
47 renderer->d.outputBufferStride = VIDEO_HORIZONTAL_PIXELS;
48
49 GBAGLContextCreate(&renderer->gl);
50 renderer->gl.d.user = renderer;
51 renderer->gl.d.lockAspectRatio = renderer->lockAspectRatio;
52 renderer->gl.d.filter = renderer->filter;
53 renderer->gl.d.swap = mSDLGLCommonSwap;
54 renderer->gl.d.init(&renderer->gl.d, 0);
55
56 _doViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl.d);
57 return true;
58}
59
60void mSDLGLRunloopGBA(struct mSDLRenderer* renderer, void* user) {
61 struct GBAThread* context = user;
62 SDL_Event event;
63 struct VideoBackend* v = &renderer->gl.d;
64
65 while (context->state < THREAD_EXITING) {
66 while (SDL_PollEvent(&event)) {
67 GBASDLHandleEvent(context, &renderer->player, &event);
68#if SDL_VERSION_ATLEAST(2, 0, 0)
69 // Event handling can change the size of the screen
70 if (renderer->player.windowUpdated) {
71 SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight);
72 _doViewport(renderer->viewportWidth, renderer->viewportHeight, v);
73 renderer->player.windowUpdated = 0;
74 }
75#endif
76 }
77
78 if (GBASyncWaitFrameStart(&context->sync)) {
79 v->postFrame(v, renderer->d.outputBuffer);
80 }
81 GBASyncWaitFrameEnd(&context->sync);
82 v->drawFrame(v);
83 v->swap(v);
84 }
85}
86
87void mSDLGLDeinitGBA(struct mSDLRenderer* renderer) {
88 if (renderer->gl.d.deinit) {
89 renderer->gl.d.deinit(&renderer->gl.d);
90 }
91 free(renderer->d.outputBuffer);
92#if SDL_VERSION_ATLEAST(2, 0, 0)
93 SDL_GL_DeleteContext(renderer->glCtx);
94#endif
95}
96#endif
97
98#ifdef M_CORE_GB
99void mSDLGLCreateGB(struct mSDLRenderer* renderer) {
100 renderer->init = mSDLGLInitGB;
101 renderer->deinit = mSDLGLDeinitGB;
102 renderer->runloop = mSDLGLRunloopGB;
103}
104
105bool mSDLGLInitGB(struct mSDLRenderer* renderer) {
106 mSDLGLCommonInit(renderer);
107
108 // TODO: Pass texture size along
109 color_t* buf = malloc(VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL);
110 memset(buf, 0, VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL);
111 renderer->gb.outputBuffer = buf + GB_GBA_CENTER;
112 renderer->gb.outputBufferStride = VIDEO_HORIZONTAL_PIXELS;
113
114 GBAGLContextCreate(&renderer->gl);
115 renderer->gl.d.user = renderer;
116 renderer->gl.d.lockAspectRatio = renderer->lockAspectRatio;
117 renderer->gl.d.filter = renderer->filter;
118 renderer->gl.d.swap = mSDLGLCommonSwap;
119 renderer->gl.d.init(&renderer->gl.d, 0);
120
121 _doViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl.d);
122 return true;
123}
124
125void mSDLGLRunloopGB(struct mSDLRenderer* renderer, void* user) {
126 struct GB* gb = user;
127 SDL_Event event;
128 struct VideoBackend* v = &renderer->gl.d;
129 int activeKeys = 0;
130 gb->keySource = &activeKeys;
131
132 while (true) {
133 int64_t frameCounter = gb->video.frameCounter;
134 while (gb->video.frameCounter == frameCounter) {
135 LR35902Tick(gb->cpu);
136 }
137 while (SDL_PollEvent(&event)) {
138 // TODO: Refactor out
139 if (event.type == SDL_KEYUP || event.type == SDL_KEYDOWN) {
140 int key;
141#if !defined(BUILD_PANDORA) && SDL_VERSION_ATLEAST(2, 0, 0)
142 key = GBAInputMapKey(renderer->player.bindings, SDL_BINDING_KEY, event.key.keysym.scancode);
143#else
144 key = GBAInputMapKey(renderer->player.bindings, SDL_BINDING_KEY, event.key.keysym.sym);
145#endif
146 if (key != GBA_KEY_NONE) {
147 if (event.type == SDL_KEYDOWN) {
148 activeKeys |= 1 << key;
149 } else {
150 activeKeys &= ~(1 << key);
151 }
152 }
153 }
154 if (event.type == SDL_QUIT) {
155 return;
156 }
157
158#if SDL_VERSION_ATLEAST(2, 0, 0)
159 // Event handling can change the size of the screen
160 if (renderer->player.windowUpdated) {
161 SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight);
162 _doViewport(renderer->viewportWidth, renderer->viewportHeight, v);
163 renderer->player.windowUpdated = 0;
164 }
165#endif
166 }
167
168 v->postFrame(v, renderer->gb.outputBuffer - GB_GBA_CENTER);
169 v->drawFrame(v);
170 v->swap(v);
171 }
172}
173
174void mSDLGLDeinitGB(struct mSDLRenderer* renderer) {
175 if (renderer->gl.d.deinit) {
176 renderer->gl.d.deinit(&renderer->gl.d);
177 }
178 free(renderer->gb.outputBuffer - GB_GBA_CENTER);
179#if SDL_VERSION_ATLEAST(2, 0, 0)
180 SDL_GL_DeleteContext(renderer->glCtx);
181#endif
182}
183#endif