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