1 #include "build.h"
2
3 #if USE_OPENGL
4
5 #include "glbuild.h"
6 #include "baselayer.h"
7 #include <stdlib.h>
8 #include <string.h>
9 #include <stdio.h>
10
11 struct glbuild_funcs glfunc;
12
getproc_(const char * func,int * err,int fatal)13 static inline void * getproc_(const char *func, int *err, int fatal)
14 {
15 void *proc = getglprocaddress(func, 1);
16 if (!proc && fatal) {
17 buildprintf("glbuild_loadfunctions: failed to find %s\n", func);
18 *err = 1;
19 }
20 return proc;
21 }
22 #define INIT_PROC(s) glfunc.s = getproc_(#s, &err, 1)
23 #define INIT_PROC_SOFT(s) glfunc.s = getproc_(#s, &err, 0)
24
glbuild_loadfunctions(void)25 int glbuild_loadfunctions(void)
26 {
27 int err=0;
28
29 INIT_PROC(glClearColor);
30 INIT_PROC(glClear);
31 INIT_PROC(glColorMask);
32 INIT_PROC(glBlendFunc);
33 INIT_PROC(glCullFace);
34 INIT_PROC(glFrontFace);
35 INIT_PROC(glPolygonOffset);
36 #if (USE_OPENGL != USE_GLES2)
37 INIT_PROC(glPolygonMode);
38 #endif
39 INIT_PROC(glEnable);
40 INIT_PROC(glDisable);
41 INIT_PROC(glGetFloatv);
42 INIT_PROC(glGetIntegerv);
43 INIT_PROC(glGetString);
44 #if (USE_OPENGL == USE_GL3)
45 INIT_PROC(glGetStringi);
46 #endif
47 INIT_PROC(glGetError);
48 INIT_PROC(glHint);
49 INIT_PROC(glPixelStorei);
50 INIT_PROC(glViewport);
51 INIT_PROC(glScissor);
52
53 // Depth
54 INIT_PROC(glDepthFunc);
55 INIT_PROC(glDepthMask);
56 #if (USE_OPENGL == USE_GLES2)
57 INIT_PROC(glDepthRangef);
58 #else
59 INIT_PROC(glDepthRange);
60 #endif
61
62 // Raster funcs
63 INIT_PROC(glReadPixels);
64
65 // Texture mapping
66 INIT_PROC(glTexEnvf);
67 INIT_PROC(glGenTextures);
68 INIT_PROC(glDeleteTextures);
69 INIT_PROC(glBindTexture);
70 INIT_PROC(glTexImage2D);
71 INIT_PROC(glTexSubImage2D);
72 INIT_PROC(glTexParameterf);
73 INIT_PROC(glTexParameteri);
74 INIT_PROC_SOFT(glCompressedTexImage2D);
75
76 // Buffer objects
77 INIT_PROC(glBindBuffer);
78 INIT_PROC(glBufferData);
79 INIT_PROC(glBufferSubData);
80 INIT_PROC(glDeleteBuffers);
81 INIT_PROC(glGenBuffers);
82 INIT_PROC(glDrawElements);
83 INIT_PROC(glEnableVertexAttribArray);
84 INIT_PROC(glDisableVertexAttribArray);
85 INIT_PROC(glVertexAttribPointer);
86 #if (USE_OPENGL == USE_GL3)
87 INIT_PROC(glBindVertexArray);
88 INIT_PROC(glDeleteVertexArrays);
89 INIT_PROC(glGenVertexArrays);
90 #endif
91
92 // Shaders
93 INIT_PROC(glActiveTexture);
94 INIT_PROC(glAttachShader);
95 INIT_PROC(glCompileShader);
96 INIT_PROC(glCreateProgram);
97 INIT_PROC(glCreateShader);
98 INIT_PROC(glDeleteProgram);
99 INIT_PROC(glDeleteShader);
100 INIT_PROC(glDetachShader);
101 INIT_PROC(glGetAttribLocation);
102 INIT_PROC(glGetProgramiv);
103 INIT_PROC(glGetProgramInfoLog);
104 INIT_PROC(glGetShaderiv);
105 INIT_PROC(glGetShaderInfoLog);
106 INIT_PROC(glGetUniformLocation);
107 INIT_PROC(glLinkProgram);
108 INIT_PROC(glShaderSource);
109 INIT_PROC(glUseProgram);
110 INIT_PROC(glUniform1i);
111 INIT_PROC(glUniform1f);
112 INIT_PROC(glUniform2f);
113 INIT_PROC(glUniform3f);
114 INIT_PROC(glUniform4f);
115 INIT_PROC(glUniformMatrix4fv);
116
117 #if (USE_OPENGL == USE_GLES2)
118 INIT_PROC_SOFT(glDebugMessageCallbackKHR);
119 #else
120 INIT_PROC_SOFT(glDebugMessageCallback);
121 #endif
122
123 if (err) glbuild_unloadfunctions();
124 return err;
125 }
126
glbuild_unloadfunctions(void)127 void glbuild_unloadfunctions(void)
128 {
129 memset(&glfunc, 0, sizeof(glfunc));
130 }
131
glbuild_check_errors(const char * file,int line)132 void glbuild_check_errors(const char *file, int line)
133 {
134 GLenum err;
135 const char *str;
136
137 while ((err = glfunc.glGetError()) != GL_NO_ERROR) {
138 switch (err) {
139 case GL_INVALID_ENUM: str = "GL_INVALID_ENUM"; break;
140 case GL_INVALID_VALUE: str = "GL_INVALID_VALUE"; break;
141 case GL_INVALID_OPERATION: str = "GL_INVALID_OPERATION"; break;
142 case GL_INVALID_FRAMEBUFFER_OPERATION: str = "GL_INVALID_FRAMEBUFFER_OPERATION"; break;
143 case GL_OUT_OF_MEMORY: str = "GL_OUT_OF_MEMORY"; break;
144 #ifdef GL_STACK_UNDERFLOW
145 case GL_STACK_UNDERFLOW: str = "GL_STACK_UNDERFLOW"; break;
146 #endif
147 #ifdef GL_STACK_OVERFLOW
148 case GL_STACK_OVERFLOW: str = "GL_STACK_OVERFLOW"; break;
149 #endif
150 default: str = "(unknown)"; break;
151 }
152 debugprintf("GL error [%s:%d]: (%d) %s\n", file, line, err, str);
153 }
154 }
155
glbuild_cook_source(const GLchar * source,const char * spec)156 static GLchar *glbuild_cook_source(const GLchar *source, const char *spec)
157 {
158 GLchar *cooked, *pos, *match, *end;
159 const char *marker = "#glbuild(";
160 const int markerlen = 9;
161 int keep;
162
163 cooked = strdup(source);
164 if (!cooked) {
165 debugprintf("glbuild_cook_source: couldn't duplicate source\n");
166 return NULL;
167 }
168 pos = cooked;
169 do {
170 match = strstr(pos, marker);
171 if (!match) break;
172
173 end = strchr(match, ')');
174 if (!end) break;
175
176 if (!strncmp(match + markerlen, spec, end-match-markerlen)) {
177 // Marker matches the spec. Overwrite it with spaces to uncomment the line.
178 for (; match <= end; match++) *match = ' ';
179 } else {
180 // Overwrite the line with spaces.
181 for (; *match && *match != '\n' && *match != '\r'; match++) *match = ' ';
182 }
183 pos = end;
184 } while(pos);
185
186 return cooked;
187 }
188
glbuild_compile_shader(GLuint type,const GLchar * source)189 GLuint glbuild_compile_shader(GLuint type, const GLchar *source)
190 {
191 GLuint shader;
192 GLint status;
193 GLchar *cookedsource;
194
195 shader = glfunc.glCreateShader(type);
196 if (!shader) {
197 return 0;
198 }
199
200 #if (USE_OPENGL == USE_GLES2)
201 cookedsource = glbuild_cook_source(source, "ES2");
202 #elif (USE_OPENGL == USE_GL3)
203 cookedsource = glbuild_cook_source(source, "3");
204 #else
205 cookedsource = glbuild_cook_source(source, "2");
206 #endif
207 if (!cookedsource) {
208 glfunc.glDeleteShader(shader);
209 return 0;
210 }
211
212 glfunc.glShaderSource(shader, 1, (const GLchar**)&cookedsource, NULL);
213 glfunc.glCompileShader(shader);
214 free(cookedsource);
215
216 glfunc.glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
217 if (status == GL_FALSE) {
218 GLint loglen = 0;
219 GLchar *logtext = NULL;
220
221 glfunc.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &loglen);
222
223 logtext = (GLchar *)malloc(loglen);
224 glfunc.glGetShaderInfoLog(shader, loglen, &loglen, logtext);
225 buildprintf("GL shader compile error: %s\n", logtext);
226 free(logtext);
227
228 glfunc.glDeleteShader(shader);
229 return 0;
230 }
231
232 return shader;
233 }
234
glbuild_link_program(int shadercount,GLuint * shaders)235 GLuint glbuild_link_program(int shadercount, GLuint *shaders)
236 {
237 GLuint program;
238 GLint status;
239 int i;
240
241 program = glfunc.glCreateProgram();
242 if (!program) {
243 return 0;
244 }
245
246 for (i = 0; i < shadercount; i++) {
247 glfunc.glAttachShader(program, shaders[i]);
248 }
249
250 glfunc.glLinkProgram(program);
251
252 glfunc.glGetProgramiv(program, GL_LINK_STATUS, &status);
253 if (status == GL_FALSE) {
254 GLint loglen = 0;
255 GLchar *logtext = NULL;
256
257 glfunc.glGetProgramiv(program, GL_INFO_LOG_LENGTH, &loglen);
258
259 logtext = (GLchar *)malloc(loglen);
260 glfunc.glGetProgramInfoLog(program, loglen, &loglen, logtext);
261 buildprintf("glbuild_link_program: link error: %s\n", logtext);
262 free(logtext);
263
264 glfunc.glDeleteProgram(program);
265 return 0;
266 }
267
268 for (i = 0; i < shadercount; i++) {
269 glfunc.glDetachShader(program, shaders[i]);
270 }
271
272 return program;
273 }
274
glbuild_prepare_8bit_shader(glbuild8bit * state,int resx,int resy,int stride)275 int glbuild_prepare_8bit_shader(glbuild8bit *state, int resx, int resy, int stride)
276 {
277 GLuint shaders[2] = {0,0}, prog = 0;
278 GLint status = 0;
279
280 extern const char default_glbuild_fs_glsl[];
281 extern const char default_glbuild_vs_glsl[];
282
283 float tx = (float)resx / (float)stride, ty = 1.0;
284 int tsizx = stride, tsizy = resy;
285
286 if (!glinfo.texnpot) {
287 for (tsizx = 1; tsizx < stride; tsizx <<= 1) { }
288 for (tsizy = 1; tsizy < resy; tsizy <<= 1) { }
289 tx = (float)resx / (float)tsizx;
290 ty = (float)resy / (float)tsizy;
291 }
292
293 // Buffer contents: indexes and texcoord/vertex elements.
294 GLushort indexes[6] = { 0, 1, 2, 0, 2, 3 };
295 GLfloat elements[4][4] = {
296 // tx, ty, vx, vy
297 { 0.0, ty, -1.0, -1.0 },
298 { tx, ty, 1.0, -1.0 },
299 { tx, 0.0, 1.0, 1.0 },
300 { 0.0, 0.0, -1.0, 1.0 },
301 };
302
303 GLint clamp = glinfo.clamptoedge ? GL_CLAMP_TO_EDGE : GL_CLAMP;
304 GLenum intfmt, extfmt;
305
306 // Initialise texture objects for the palette and framebuffer.
307 // The textures will be uploaded on the first rendered frame.
308 glfunc.glGenTextures(1, &state->paltex);
309 glfunc.glActiveTexture(GL_TEXTURE1);
310 glfunc.glBindTexture(GL_TEXTURE_2D, state->paltex);
311 glfunc.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); // Allocates memory.
312 glfunc.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
313 glfunc.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
314 glfunc.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clamp);
315 glfunc.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clamp);
316
317 #if (USE_OPENGL == USE_GLES2)
318 intfmt = GL_LUMINANCE;
319 extfmt = GL_LUMINANCE;
320 #else
321 intfmt = GL_RGB;
322 extfmt = GL_RED;
323 #endif
324
325 glfunc.glGenTextures(1, &state->frametex);
326 glfunc.glActiveTexture(GL_TEXTURE0);
327 glfunc.glBindTexture(GL_TEXTURE_2D, state->frametex);
328 glfunc.glTexImage2D(GL_TEXTURE_2D, 0, intfmt, tsizx, tsizy, 0, extfmt, GL_UNSIGNED_BYTE, NULL); // Allocates memory.
329 glfunc.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
330 glfunc.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
331 glfunc.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clamp);
332 glfunc.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clamp);
333
334 glfunc.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
335
336 // Prepare the vertex and fragment shaders.
337 shaders[0] = glbuild_compile_shader(GL_VERTEX_SHADER, default_glbuild_vs_glsl);
338 shaders[1] = glbuild_compile_shader(GL_FRAGMENT_SHADER, default_glbuild_fs_glsl);
339 if (!shaders[0] || !shaders[1]) {
340 if (shaders[0]) glfunc.glDeleteShader(shaders[0]);
341 if (shaders[1]) glfunc.glDeleteShader(shaders[1]);
342 return -1;
343 }
344
345 // Prepare the shader program.
346 prog = glbuild_link_program(2, shaders);
347 if (!prog) {
348 glfunc.glDeleteShader(shaders[0]);
349 glfunc.glDeleteShader(shaders[1]);
350 return -1;
351 }
352
353 // Shaders were detached in glbuild_link_program.
354 glfunc.glDeleteShader(shaders[0]);
355 glfunc.glDeleteShader(shaders[1]);
356
357 // Connect the textures to the program.
358 glfunc.glUseProgram(prog);
359 glfunc.glUniform1i(glfunc.glGetUniformLocation(prog, "u_palette"), 1);
360 glfunc.glUniform1i(glfunc.glGetUniformLocation(prog, "u_frame"), 0);
361
362 state->program = prog;
363 state->attrib_vertex = glfunc.glGetAttribLocation(prog, "a_vertex");
364 state->attrib_texcoord = glfunc.glGetAttribLocation(prog, "a_texcoord");
365
366 #if (USE_OPENGL == USE_GL3)
367 glfunc.glGenVertexArrays(1, &state->vao);
368 glfunc.glBindVertexArray(state->vao);
369 #endif
370
371 // Prepare buffer objects for the vertex/texcoords and indexes.
372 glfunc.glGenBuffers(1, &state->buffer_indexes);
373 glfunc.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, state->buffer_indexes);
374 glfunc.glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexes), indexes, GL_STATIC_DRAW);
375
376 glfunc.glGenBuffers(1, &state->buffer_elements);
377 glfunc.glBindBuffer(GL_ARRAY_BUFFER, state->buffer_elements);
378 glfunc.glBufferData(GL_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
379
380 glfunc.glEnableVertexAttribArray(state->attrib_texcoord);
381 glfunc.glVertexAttribPointer(state->attrib_texcoord, 2, GL_FLOAT, GL_FALSE,
382 sizeof(GLfloat)*4, (const GLvoid *)0);
383
384 glfunc.glEnableVertexAttribArray(state->attrib_vertex);
385 glfunc.glVertexAttribPointer(state->attrib_vertex, 2, GL_FLOAT, GL_FALSE,
386 sizeof(GLfloat)*4, (const GLvoid *)(sizeof(GLfloat)*2));
387
388 #if (USE_OPENGL == USE_GL3)
389 glfunc.glBindVertexArray(0);
390 #endif
391
392 // Set some persistent GL state.
393 glfunc.glClearColor(0.0, 0.0, 0.0, 0.0);
394 glfunc.glDisable(GL_DEPTH_TEST);
395
396 return 0;
397 }
398
glbuild_delete_8bit_shader(glbuild8bit * state)399 void glbuild_delete_8bit_shader(glbuild8bit *state)
400 {
401 if (state->program) {
402 #if (USE_OPENGL != USE_GL3)
403 glfunc.glDisableVertexAttribArray(state->attrib_vertex);
404 glfunc.glDisableVertexAttribArray(state->attrib_texcoord);
405 #endif
406 glfunc.glUseProgram(0); // Disable shaders, go back to fixed-function.
407 glfunc.glDeleteProgram(state->program);
408 state->program = 0;
409 }
410 if (state->paltex) {
411 glfunc.glDeleteTextures(1, &state->paltex);
412 state->paltex = 0;
413 }
414 if (state->frametex) {
415 glfunc.glDeleteTextures(1, &state->frametex);
416 state->frametex = 0;
417 }
418 #if (USE_OPENGL == USE_GL3)
419 if (state->vao) {
420 glfunc.glBindVertexArray(0);
421 glfunc.glDeleteVertexArrays(1, &state->vao);
422 state->vao = 0;
423 }
424 #endif
425 if (state->buffer_indexes) {
426 glfunc.glDeleteBuffers(1, &state->buffer_indexes);
427 state->buffer_indexes = 0;
428 }
429 if (state->buffer_elements) {
430 glfunc.glDeleteBuffers(1, &state->buffer_elements);
431 state->buffer_elements = 0;
432 }
433 }
434
glbuild_update_8bit_palette(glbuild8bit * state,const GLvoid * pal)435 void glbuild_update_8bit_palette(glbuild8bit *state, const GLvoid *pal)
436 {
437 glfunc.glActiveTexture(GL_TEXTURE1);
438 glfunc.glBindTexture(GL_TEXTURE_2D, state->paltex);
439 glfunc.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pal);
440 }
441
glbuild_update_8bit_frame(glbuild8bit * state,const GLvoid * frame,int resx,int resy,int stride)442 void glbuild_update_8bit_frame(glbuild8bit *state, const GLvoid *frame, int resx, int resy, int stride)
443 {
444 #if (USE_OPENGL == USE_GLES2)
445 GLenum extfmt = GL_LUMINANCE;
446 #else
447 GLenum extfmt = GL_RED;
448 #endif
449
450 glfunc.glActiveTexture(GL_TEXTURE0);
451 glfunc.glBindTexture(GL_TEXTURE_2D, state->frametex);
452 glfunc.glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, stride, resy, extfmt, GL_UNSIGNED_BYTE, frame);
453 }
454
glbuild_draw_8bit_frame(glbuild8bit * state)455 void glbuild_draw_8bit_frame(glbuild8bit *state)
456 {
457 #if (USE_OPENGL == USE_GLES2)
458 glfunc.glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
459 #endif
460 #if (USE_OPENGL == USE_GL3)
461 glfunc.glBindVertexArray(state->vao);
462 #endif
463 glfunc.glDrawElements(GL_TRIANGLE_FAN, 6, GL_UNSIGNED_SHORT, 0);
464 }
465
466 #endif //USE_OPENGL
467