src/platform/opengl/gl.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 "gl.h"
7
8#include <mgba-util/math.h>
9
10static const GLint _glTexCoords[] = {
11 0, 0,
12 1, 0,
13 1, 1,
14 0, 1
15};
16
17static void mGLContextInit(struct VideoBackend* v, WHandle handle) {
18 UNUSED(handle);
19 struct mGLContext* context = (struct mGLContext*) v;
20 v->width = 1;
21 v->height = 1;
22 glGenTextures(2, context->tex);
23 glBindTexture(GL_TEXTURE_2D, context->tex[0]);
24 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
25#ifndef _WIN32
26 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
27 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
28#endif
29 glBindTexture(GL_TEXTURE_2D, context->tex[1]);
30 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
31#ifndef _WIN32
32 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
33 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
34#endif
35 context->activeTex = 0;
36}
37
38static void mGLContextSetDimensions(struct VideoBackend* v, unsigned width, unsigned height) {
39 struct mGLContext* context = (struct mGLContext*) v;
40 if (width == v->width && height == v->height) {
41 return;
42 }
43 v->width = width;
44 v->height = height;
45
46 glBindTexture(GL_TEXTURE_2D, context->tex[0]);
47#ifdef COLOR_16_BIT
48#ifdef COLOR_5_6_5
49 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
50#else
51 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0);
52#endif
53#elif defined(__BIG_ENDIAN__)
54 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, 0);
55#else
56 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
57#endif
58
59 glBindTexture(GL_TEXTURE_2D, context->tex[1]);
60#ifdef COLOR_16_BIT
61#ifdef COLOR_5_6_5
62 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
63#else
64 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0);
65#endif
66#elif defined(__BIG_ENDIAN__)
67 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, 0);
68#else
69 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
70#endif
71
72 context->vertices[0] = 0;
73 context->vertices[1] = 0;
74 context->vertices[2] = toPow2(width);
75 context->vertices[3] = 0;
76 context->vertices[4] = toPow2(width);
77 context->vertices[5] = toPow2(height);
78 context->vertices[6] = 0;
79 context->vertices[7] = toPow2(height);
80}
81
82static void mGLContextDeinit(struct VideoBackend* v) {
83 struct mGLContext* context = (struct mGLContext*) v;
84 glDeleteTextures(2, context->tex);
85}
86
87static void mGLContextResized(struct VideoBackend* v, unsigned w, unsigned h) {
88 unsigned drawW = w;
89 unsigned drawH = h;
90 if (v->lockAspectRatio) {
91 if (w * v->height > h * v->width) {
92 drawW = h * v->width / v->height;
93 } else if (w * v->height < h * v->width) {
94 drawH = w * v->height / v->width;
95 }
96 }
97 if (v->lockIntegerScaling) {
98 if (drawW >= v->width) {
99 drawW -= drawW % v->width;
100 }
101 if (drawH >= v->height) {
102 drawH -= drawH % v->height;
103 }
104 }
105 glMatrixMode(GL_MODELVIEW);
106 glLoadIdentity();
107 glClearColor(0, 0, 0, 0);
108 glClear(GL_COLOR_BUFFER_BIT);
109 glViewport((w - drawW) / 2, (h - drawH) / 2, drawW, drawH);
110}
111
112static void mGLContextClear(struct VideoBackend* v) {
113 UNUSED(v);
114 glClearColor(0, 0, 0, 0);
115 glClear(GL_COLOR_BUFFER_BIT);
116}
117
118void mGLContextDrawFrame(struct VideoBackend* v) {
119 struct mGLContext* context = (struct mGLContext*) v;
120 glEnable(GL_TEXTURE_2D);
121 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
122 glEnableClientState(GL_VERTEX_ARRAY);
123 glVertexPointer(2, GL_INT, 0, context->vertices);
124 glTexCoordPointer(2, GL_INT, 0, _glTexCoords);
125 glMatrixMode(GL_PROJECTION);
126 glLoadIdentity();
127 glOrtho(0, v->width, v->height, 0, 0, 1);
128 glMatrixMode(GL_MODELVIEW);
129 glLoadIdentity();
130 if (v->interframeBlending) {
131 glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA);
132 glBlendColor(1, 1, 1, 0.5);
133 glBindTexture(GL_TEXTURE_2D, context->tex[context->activeTex ^ 1]);
134 if (v->filter) {
135 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
136 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
137 } else {
138 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
139 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
140 }
141 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
142 glEnable(GL_BLEND);
143 }
144 glBindTexture(GL_TEXTURE_2D, context->tex[context->activeTex]);
145 if (v->filter) {
146 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
147 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
148 } else {
149 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
150 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
151 }
152 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
153 glDisable(GL_BLEND);
154}
155
156void mGLContextPostFrame(struct VideoBackend* v, const void* frame) {
157 struct mGLContext* context = (struct mGLContext*) v;
158 context->activeTex ^= 1;
159 glBindTexture(GL_TEXTURE_2D, context->tex[context->activeTex]);
160#ifdef COLOR_16_BIT
161#ifdef COLOR_5_6_5
162 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, v->width, v->height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame);
163#else
164 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, v->width, v->height, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame);
165#endif
166#elif defined(__BIG_ENDIAN__)
167 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, v->width, v->height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, frame);
168#else
169 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, v->width, v->height, GL_RGBA, GL_UNSIGNED_BYTE, frame);
170#endif
171}
172
173void mGLContextCreate(struct mGLContext* context) {
174 context->d.init = mGLContextInit;
175 context->d.deinit = mGLContextDeinit;
176 context->d.setDimensions = mGLContextSetDimensions;
177 context->d.resized = mGLContextResized;
178 context->d.swap = 0;
179 context->d.clear = mGLContextClear;
180 context->d.postFrame = mGLContextPostFrame;
181 context->d.drawFrame = mGLContextDrawFrame;
182 context->d.setMessage = 0;
183 context->d.clearMessage = 0;
184}