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