all repos — mgba @ 4fd170ac38a9c312f3dd1d0dd912d2c761f60fdb

mGBA Game Boy Advance Emulator

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}