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 "gba/supervisor/thread.h"
9
10#ifdef __APPLE__
11#include <OpenGL/gl.h>
12#else
13#include <GL/gl.h>
14#endif
15
16#ifdef BUILD_GL
17static const GLint _glVertices[] = {
18 0, 0,
19 256, 0,
20 256, 256,
21 0, 256
22};
23
24static const GLint _glTexCoords[] = {
25 0, 0,
26 1, 0,
27 1, 1,
28 0, 1
29};
30#endif
31
32static void _doViewport(int w, int h, struct SDLSoftwareRenderer* renderer) {
33 int drawW = w;
34 int drawH = h;
35 if (renderer->lockAspectRatio) {
36 if (w * 2 > h * 3) {
37 drawW = h * 3 / 2;
38 } else if (w * 2 < h * 3) {
39 drawH = w * 2 / 3;
40 }
41 }
42 glViewport((w - drawW) / 2, (h - drawH) / 2, drawW, drawH);
43 glClear(GL_COLOR_BUFFER_BIT);
44#if SDL_VERSION_ATLEAST(2, 0, 0)
45 SDL_GL_SwapWindow(renderer->window);
46#else
47 SDL_GL_SwapBuffers();
48#endif
49 glClear(GL_COLOR_BUFFER_BIT);
50}
51
52static bool GBASDLGLInit(struct SDLSoftwareRenderer* renderer);
53static void GBASDLGLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer);
54static void GBASDLGLDeinit(struct SDLSoftwareRenderer* renderer);
55
56void GBASDLGLCreate(struct SDLSoftwareRenderer* renderer) {
57 renderer->init = GBASDLGLInit;
58 renderer->deinit = GBASDLGLDeinit;
59 renderer->runloop = GBASDLGLRunloop;
60}
61
62bool GBASDLGLInit(struct SDLSoftwareRenderer* renderer) {
63#ifndef COLOR_16_BIT
64 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
65 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
66 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
67#else
68 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
69#ifdef COLOR_5_6_5
70 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
71#else
72 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
73#endif
74 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
75#endif
76
77#if SDL_VERSION_ATLEAST(2, 0, 0)
78 renderer->window = SDL_CreateWindow(projectName, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, renderer->viewportWidth, renderer->viewportHeight, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | (SDL_WINDOW_FULLSCREEN_DESKTOP * renderer->player.fullscreen));
79 SDL_GL_CreateContext(renderer->window);
80 SDL_GL_SetSwapInterval(1);
81 SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight);
82 renderer->player.window = renderer->window;
83#else
84 SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
85#ifdef COLOR_16_BIT
86 SDL_SetVideoMode(renderer->viewportWidth, renderer->viewportHeight, 16, SDL_OPENGL);
87#else
88 SDL_SetVideoMode(renderer->viewportWidth, renderer->viewportHeight, 32, SDL_OPENGL);
89#endif
90#endif
91
92 renderer->d.outputBuffer = malloc(VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL);
93 renderer->d.outputBufferStride = VIDEO_HORIZONTAL_PIXELS;
94 glGenTextures(1, &renderer->tex);
95 glBindTexture(GL_TEXTURE_2D, renderer->tex);
96 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
97 if (renderer->filter) {
98 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
99 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
100 } else {
101 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
102 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
103 }
104#ifndef _WIN32
105 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
106 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
107#endif
108
109#ifdef COLOR_16_BIT
110#ifdef COLOR_5_6_5
111 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
112#else
113 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0);
114#endif
115#else
116 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
117#endif
118
119 _doViewport(renderer->viewportWidth, renderer->viewportHeight, renderer);
120 return true;
121}
122
123void GBASDLGLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) {
124 SDL_Event event;
125
126 glEnable(GL_TEXTURE_2D);
127 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
128 glEnableClientState(GL_VERTEX_ARRAY);
129 glVertexPointer(2, GL_INT, 0, _glVertices);
130 glTexCoordPointer(2, GL_INT, 0, _glTexCoords);
131 glMatrixMode (GL_PROJECTION);
132 glLoadIdentity();
133 glOrtho(0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, 0, 1);
134 while (context->state < THREAD_EXITING) {
135 while (SDL_PollEvent(&event)) {
136 GBASDLHandleEvent(context, &renderer->player, &event);
137#if SDL_VERSION_ATLEAST(2, 0, 0)
138 // Event handling can change the size of the screen
139 if (renderer->player.windowUpdated) {
140 SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight);
141 _doViewport(renderer->viewportWidth, renderer->viewportHeight, renderer);
142 renderer->player.windowUpdated = 0;
143 }
144#endif
145 }
146
147 if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) {
148 glBindTexture(GL_TEXTURE_2D, renderer->tex);
149#ifdef COLOR_16_BIT
150#ifdef COLOR_5_6_5
151 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, renderer->d.outputBuffer);
152#else
153 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, renderer->d.outputBuffer);
154#endif
155#else
156 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, GL_RGBA, GL_UNSIGNED_BYTE, renderer->d.outputBuffer);
157#endif
158 if (context->sync.videoFrameWait) {
159 glFlush();
160 }
161 }
162 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
163 GBASyncWaitFrameEnd(&context->sync);
164#if SDL_VERSION_ATLEAST(2, 0, 0)
165 SDL_GL_SwapWindow(renderer->window);
166#else
167 SDL_GL_SwapBuffers();
168#endif
169 }
170}
171
172void GBASDLGLDeinit(struct SDLSoftwareRenderer* renderer) {
173 free(renderer->d.outputBuffer);
174}