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