in_sdl: give names to gamepad buttons
[libpicofe.git] / gl.c
CommitLineData
b9801854 1#include <stdio.h>
2#include <stdlib.h>
64f9c546 3#include <string.h>
4#include <assert.h>
b9801854 5
6#include <EGL/egl.h>
7#include <GLES/gl.h>
d5d1b164 8#include "gl_loader.h"
0d645bc5 9#include "gl_platform.h"
b9801854 10#include "gl.h"
11
64f9c546 12static EGLDisplay edpy = EGL_NO_DISPLAY;
13static EGLSurface esfc = EGL_NO_SURFACE;
14static EGLContext ectxt = EGL_NO_CONTEXT;
b9801854 15
c7228611 16static GLuint texture_name;
17
6fd09356 18/* for external flips */
19void *gl_es_display;
20void *gl_es_surface;
21
c7228611 22static int tex_w, tex_h;
23static void *tex_mem;
8c5a34d4 24static int flip_old_w, flip_old_h;
c7228611 25
b9801854 26static int gl_have_error(const char *name)
27{
28 GLenum e = glGetError();
29 if (e != GL_NO_ERROR) {
30 fprintf(stderr, "GL error: %s %x\n", name, e);
31 return 1;
32 }
33 return 0;
34}
35
36static int gles_have_error(const char *name)
37{
38 EGLint e = eglGetError();
39 if (e != EGL_SUCCESS) {
40 fprintf(stderr, "%s %x\n", name, e);
41 return 1;
42 }
43 return 0;
44}
45
4388a645 46int gl_init(void *display, int *quirks)
47{
48 int retval = -1;
49 int ret;
50
51 ret = gl_platform_init(&display, quirks);
52 if (ret != 0) {
53 fprintf(stderr, "gl_platform_init failed with %d\n", ret);
54 return retval;
55 }
56
57 edpy = eglGetDisplay((EGLNativeDisplayType)display);
58 if (edpy == EGL_NO_DISPLAY) {
59 fprintf(stderr, "Failed to get EGL display\n");
60 goto out;
61 }
62
63 if (!eglInitialize(edpy, NULL, NULL)) {
64 fprintf(stderr, "Failed to initialize EGL\n");
65 goto out;
66 }
67 retval = 0;
68
69out:
70 if (retval && edpy != EGL_NO_DISPLAY)
71 gl_shutdown();
72 return retval;
73}
74
75int gl_create(void *window, int *quirks, int w, int h)
b9801854 76{
77 EGLConfig ecfg = NULL;
b9801854 78 EGLint num_config;
79 int retval = -1;
80 int ret;
64f9c546 81 EGLint config_attr[] =
b9801854 82 {
83 EGL_NONE
84 };
85
4388a645 86 ret = gl_platform_create(&window, quirks);
0d645bc5 87 if (ret != 0) {
88 fprintf(stderr, "gl_platform_init failed with %d\n", ret);
d5d1b164 89 return retval;
0d645bc5 90 }
91
8c5a34d4 92 flip_old_w = flip_old_h = 0;
93 for (tex_w = 1; tex_w < w; tex_w *= 2)
94 ;
95 for (tex_h = 1; tex_h < h; tex_h *= 2)
96 ;
c7228611 97 tex_mem = realloc(tex_mem, tex_w * tex_h * 2);
98 if (tex_mem == NULL) {
b9801854 99 fprintf(stderr, "OOM\n");
100 goto out;
101 }
64f9c546 102 memset(tex_mem, 0, tex_w * tex_h * 2);
b9801854 103
64f9c546 104 if (!eglChooseConfig(edpy, config_attr, &ecfg, 1, &num_config)) {
b9801854 105 fprintf(stderr, "Failed to choose config (%x)\n", eglGetError());
106 goto out;
107 }
108
109 if (ecfg == NULL || num_config == 0) {
110 fprintf(stderr, "No EGL configs available\n");
111 goto out;
112 }
113
114 esfc = eglCreateWindowSurface(edpy, ecfg,
115 (EGLNativeWindowType)window, NULL);
116 if (esfc == EGL_NO_SURFACE) {
117 fprintf(stderr, "Unable to create EGL surface (%x)\n",
118 eglGetError());
119 goto out;
120 }
121
122 ectxt = eglCreateContext(edpy, ecfg, EGL_NO_CONTEXT, NULL);
123 if (ectxt == EGL_NO_CONTEXT) {
124 fprintf(stderr, "Unable to create EGL context (%x)\n",
125 eglGetError());
64f9c546 126 // on mesa, some distros disable ES1.x but compat GL still works
127 ret = eglBindAPI(EGL_OPENGL_API);
128 if (!ret) {
129 fprintf(stderr, "eglBindAPI: %x\n", eglGetError());
130 goto out;
131 }
132 ectxt = eglCreateContext(edpy, ecfg, EGL_NO_CONTEXT, NULL);
133 if (ectxt == EGL_NO_CONTEXT) {
134 fprintf(stderr, "giving up on EGL context (%x)\n",
135 eglGetError());
136 goto out;
137 }
b9801854 138 }
139
64f9c546 140 ret = eglMakeCurrent(edpy, esfc, esfc, ectxt);
141 if (!ret) {
142 fprintf(stderr, "eglMakeCurrent: %x\n", eglGetError());
143 goto out;
144 }
0b3abad8 145
146 ret = *quirks & GL_QUIRK_VSYNC_ON ? 1 : 0;
147 eglSwapInterval(edpy, ret);
b9801854 148
64f9c546 149 // 1.x (fixed-function) only
b9801854 150 glEnable(GL_TEXTURE_2D);
64f9c546 151 glGetError();
b9801854 152
64f9c546 153 assert(!texture_name);
c7228611 154
b9801854 155 glGenTextures(1, &texture_name);
64f9c546 156 if (gl_have_error("glGenTextures"))
157 goto out;
b9801854 158
159 glBindTexture(GL_TEXTURE_2D, texture_name);
64f9c546 160 if (gl_have_error("glBindTexture"))
161 goto out;
b9801854 162
c7228611 163 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_w, tex_h, 0, GL_RGB,
164 GL_UNSIGNED_SHORT_5_6_5, tex_mem);
b9801854 165 if (gl_have_error("glTexImage2D"))
166 goto out;
167
168 // no mipmaps
5411ac21 169 ret = *quirks & GL_QUIRK_SCALING_NEAREST ? GL_NEAREST : GL_LINEAR;
170 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, ret);
171 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, ret);
b9801854 172
173 //glViewport(0, 0, 512, 512);
174 glLoadIdentity();
175 glFrontFace(GL_CW);
176 glEnable(GL_CULL_FACE);
177
178 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
179 glEnableClientState(GL_VERTEX_ARRAY);
180
181 if (gl_have_error("init"))
182 goto out;
183
6fd09356 184 gl_es_display = (void *)edpy;
185 gl_es_surface = (void *)esfc;
b9801854 186 retval = 0;
187out:
64f9c546 188 if (retval && edpy != EGL_NO_DISPLAY)
4388a645 189 gl_destroy();
b9801854 190 return retval;
191}
192
c668921a 193void gl_announce(void)
194{
195 printf("GL_RENDERER: %s\n", (char *)glGetString(GL_RENDERER));
64f9c546 196 printf("GL_VERSION: %s\n", (char *)glGetString(GL_VERSION));
c668921a 197}
198
64f9c546 199static const float default_vertices[] = {
b9801854 200 -1.0f, 1.0f, 0.0f, // 0 0 1
201 1.0f, 1.0f, 0.0f, // 1 ^
202 -1.0f, -1.0f, 0.0f, // 2 | 2 3
203 1.0f, -1.0f, 0.0f, // 3 +-->
204};
205
206static float texture[] = {
207 0.0f, 0.0f, // we flip this:
208 1.0f, 0.0f, // v^
209 0.0f, 1.0f, // | u
210 1.0f, 1.0f, // +-->
211};
212
64f9c546 213int gl_flip_v(const void *fb, int w, int h, const float *vertices)
b9801854 214{
64f9c546 215 gl_have_error("pre-flip unknown");
216
217 glBindTexture(GL_TEXTURE_2D, texture_name);
218 if (gl_have_error("glBindTexture"))
219 return -1;
220
e54719ef 221 if (fb != NULL) {
8c5a34d4 222 if (w != flip_old_w || h != flip_old_h) {
c7228611 223 float f_w = (float)w / tex_w;
224 float f_h = (float)h / tex_h;
e54719ef 225 texture[1*2 + 0] = f_w;
226 texture[2*2 + 1] = f_h;
227 texture[3*2 + 0] = f_w;
228 texture[3*2 + 1] = f_h;
8c5a34d4 229 flip_old_w = w;
230 flip_old_h = h;
e54719ef 231 }
232
233 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h,
234 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fb);
64f9c546 235 if (gl_have_error("glTexSubImage2D")) {
236 fprintf(stderr, " %dx%d t: %dx%d %p\n", w, h, tex_w, tex_h, fb);
e54719ef 237 return -1;
64f9c546 238 }
b9801854 239 }
240
64f9c546 241 glVertexPointer(3, GL_FLOAT, 0, vertices ? vertices : default_vertices);
b9801854 242 glTexCoordPointer(2, GL_FLOAT, 0, texture);
243 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
b9801854 244 if (gl_have_error("glDrawArrays"))
245 return -1;
246
247 eglSwapBuffers(edpy, esfc);
248 if (gles_have_error("eglSwapBuffers"))
249 return -1;
250
251 return 0;
252}
253
64f9c546 254int gl_flip(const void *fb, int w, int h)
255{
256 return gl_flip_v(fb, w, h, NULL);
257}
258
259// to be used once after exiting menu, etc
260void gl_clear(void)
261{
262 glClearColor(0, 0, 0, 0);
263 glClear(GL_COLOR_BUFFER_BIT);
264 eglSwapBuffers(edpy, esfc);
265 glClear(GL_COLOR_BUFFER_BIT);
266 eglSwapBuffers(edpy, esfc);
267 glClear(GL_COLOR_BUFFER_BIT);
268 gl_have_error("glClear");
269}
270
4388a645 271void gl_destroy(void)
b9801854 272{
d5d1b164 273 if (edpy == EGL_NO_DISPLAY)
274 return; // nothing to do
275
64f9c546 276 // sometimes there is an error... from somewhere?
277 //gl_have_error("finish");
278 glGetError();
279
280 if (texture_name)
281 {
282 glDeleteTextures(1, &texture_name);
283 gl_have_error("glDeleteTextures");
284 texture_name = 0;
285 }
286
b9801854 287 eglMakeCurrent(edpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
64f9c546 288 if (ectxt != EGL_NO_CONTEXT) {
289 eglDestroyContext(edpy, ectxt);
290 ectxt = EGL_NO_CONTEXT;
291 }
292 if (esfc != EGL_NO_SURFACE) {
293 eglDestroySurface(edpy, esfc);
294 esfc = EGL_NO_SURFACE;
295 }
4388a645 296
297 gl_es_surface = (void *)esfc;
298
299 if (tex_mem) free(tex_mem);
300 tex_mem = NULL;
301
302 gl_platform_destroy();
303}
304
305void gl_shutdown(void)
306{
64f9c546 307 if (edpy != EGL_NO_DISPLAY) {
308 eglTerminate(edpy);
309 edpy = EGL_NO_DISPLAY;
310 }
0d645bc5 311
6fd09356 312 gl_es_display = (void *)edpy;
c7228611 313
4388a645 314 gl_platform_shutdown();
b9801854 315}