1 #include "stratagus.h"
2 #include "video.h"
3 #ifdef USE_OPENGL
4 const char* vertex_shader = "#version 130\n\
5 \n\
6 uniform sampler2D u_texture;\n\
7 \n\
8 void main()\n\
9 {\n\
10     gl_TexCoord[0] = gl_MultiTexCoord0;\n\
11 	gl_Position = ftransform();\n\
12 }";
13 
14 const char* fragment_shaders[MAX_SHADERS] = {
15 	// Nearest-neighbour
16 	"#version 130\n\
17 	\n\
18 	uniform sampler2D u_texture;\n\
19 	uniform float u_width;\n\
20 	uniform float u_height;\n\
21 	uniform float u_widthrel;\n\
22 	uniform float u_heightrel;\n\
23 	void main()\n\
24 	{\n\
25 		vec4 myColor = texture2D(u_texture, gl_TexCoord[0].xy * vec2(u_widthrel, -u_heightrel));\n\
26 		gl_FragColor = myColor;\n\
27 	}",
28 	// Scale2x
29 	"#version 110\n\
30 	\n\
31 	uniform sampler2D u_texture;\n\
32 	uniform float u_width;\n\
33 	uniform float u_height;\n\
34 	uniform float u_widthrel;\n\
35 	uniform float u_heightrel;\n\
36 	\n\
37 	void main() {\n\
38 		// o = offset, the width of a pixel\n\
39         vec2 texCoord = gl_TexCoord[0].xy * vec2(u_widthrel, -u_heightrel);\n\
40         vec2 textureDimensions = vec2(u_width, u_height);\n\
41 		vec2 o = 1.0 / textureDimensions;\n\
42 		// texel arrangement\n\
43 		// A B C\n\
44 		// D E F\n\
45 		// G H I\n\
46 		vec4 A = texture2D(u_texture, texCoord + vec2( -o.x,  o.y));\n\
47 		vec4 B = texture2D(u_texture, texCoord + vec2(    0,  o.y));\n\
48 		vec4 C = texture2D(u_texture, texCoord + vec2(  o.x,  o.y));\n\
49 		vec4 D = texture2D(u_texture, texCoord + vec2( -o.x,    0));\n\
50 		vec4 E = texture2D(u_texture, texCoord + vec2(    0,    0));\n\
51 		vec4 F = texture2D(u_texture, texCoord + vec2(  o.x,    0));\n\
52 		vec4 G = texture2D(u_texture, texCoord + vec2( -o.x, -o.y));\n\
53 		vec4 H = texture2D(u_texture, texCoord + vec2(    0, -o.y));\n\
54 		vec4 I = texture2D(u_texture, texCoord + vec2(  o.x, -o.y));\n\
55 		vec2 p = texCoord * textureDimensions;\n\
56 		// p = the position within a pixel [0...1]\n\
57 		p = p - floor(p);\n\
58 		if (p.x > .5) {\n\
59 			if (p.y > .5) {\n\
60 				// Top Right\n\
61 				gl_FragColor = B == F && B != D && F != H ? F : E;\n\
62 			} else {\n\
63 				// Bottom Right\n\
64 				gl_FragColor = H == F && D != H && B != F ? F : E;\n\
65 			}\n\
66 		} else {\n\
67 			if (p.y > .5) {\n\
68 				// Top Left\n\
69 				gl_FragColor = D == B && B != F && D != H ? D : E;\n\
70 			} else {\n\
71 				// Bottom Left\n\
72 				gl_FragColor = D == H && D != B && H != F ? D : E;\n\
73 			}\n\
74 		}\n\
75 	}",
76 	// HQX
77 	"#version 130\n\
78 	\n\
79 	uniform sampler2D u_texture;\n\
80 	uniform float u_width;\n\
81 	uniform float u_height;\n\
82 	uniform float u_widthrel;\n\
83 	uniform float u_heightrel;\n\
84 	\n\
85 	const float mx = 0.325;      // start smoothing wt.\n\
86 	const float k = -0.250;      // wt. decrease factor\n\
87 	const float max_w = 0.25;    // max filter weigth\n\
88 	const float min_w =-0.05;    // min filter weigth\n\
89 	const float lum_add = 0.25;  // effects smoothing \n\
90 	\n\
91 	void main()\n\
92 	{\n\
93 	   vec2 v_texCoord = gl_TexCoord[0].xy * vec2(u_widthrel, -u_heightrel);\n\
94 	\n\
95 	   // hq2x\n\
96 	   float x = 0.5 * (1.0 / u_width);\n\
97 	   float y = 0.5 * (1.0 / u_height);\n\
98 	   vec2 dg1 = vec2( x, y);\n\
99 	   vec2 dg2 = vec2(-x, y);\n\
100 	   vec2 dx = vec2(x, 0.0);\n\
101 	   vec2 dy = vec2(0.0, y);\n\
102 	\n\
103 	   vec4 TexCoord[5];\n\
104 	   TexCoord[0] = vec4(v_texCoord, 0.0, 0.0);\n\
105 	   TexCoord[1].xy = TexCoord[0].xy - dg1;\n\
106 	   TexCoord[1].zw = TexCoord[0].xy - dy;\n\
107 	   TexCoord[2].xy = TexCoord[0].xy - dg2;\n\
108 	   TexCoord[2].zw = TexCoord[0].xy + dx;\n\
109 	   TexCoord[3].xy = TexCoord[0].xy + dg1;\n\
110 	   TexCoord[3].zw = TexCoord[0].xy + dy;\n\
111 	   TexCoord[4].xy = TexCoord[0].xy + dg2;\n\
112 	   TexCoord[4].zw = TexCoord[0].xy - dx;\n\
113 	\n\
114 	   vec3 c00 = texture2D(u_texture, TexCoord[1].xy).xyz; \n\
115 	   vec3 c10 = texture2D(u_texture, TexCoord[1].zw).xyz; \n\
116 	   vec3 c20 = texture2D(u_texture, TexCoord[2].xy).xyz; \n\
117 	   vec3 c01 = texture2D(u_texture, TexCoord[4].zw).xyz; \n\
118 	   vec3 c11 = texture2D(u_texture, TexCoord[0].xy).xyz; \n\
119 	   vec3 c21 = texture2D(u_texture, TexCoord[2].zw).xyz; \n\
120 	   vec3 c02 = texture2D(u_texture, TexCoord[4].xy).xyz; \n\
121 	   vec3 c12 = texture2D(u_texture, TexCoord[3].zw).xyz; \n\
122 	   vec3 c22 = texture2D(u_texture, TexCoord[3].xy).xyz; \n\
123 	   vec3 dt = vec3(1.0, 1.0, 1.0);\n\
124 	\n\
125 	   float md1 = dot(abs(c00 - c22), dt);\n\
126 	   float md2 = dot(abs(c02 - c20), dt);\n\
127 	\n\
128 	   float w1 = dot(abs(c22 - c11), dt) * md2;\n\
129 	   float w2 = dot(abs(c02 - c11), dt) * md1;\n\
130 	   float w3 = dot(abs(c00 - c11), dt) * md2;\n\
131 	   float w4 = dot(abs(c20 - c11), dt) * md1;\n\
132 	\n\
133 	   float t1 = w1 + w3;\n\
134 	   float t2 = w2 + w4;\n\
135 	   float ww = max(t1, t2) + 0.0001;\n\
136 	\n\
137 	   c11 = (w1 * c00 + w2 * c20 + w3 * c22 + w4 * c02 + ww * c11) / (t1 + t2 + ww);\n\
138 	\n\
139 	   float lc1 = k / (0.12 * dot(c10 + c12 + c11, dt) + lum_add);\n\
140 	   float lc2 = k / (0.12 * dot(c01 + c21 + c11, dt) + lum_add);\n\
141 	\n\
142 	   w1 = clamp(lc1 * dot(abs(c11 - c10), dt) + mx, min_w, max_w);\n\
143 	   w2 = clamp(lc2 * dot(abs(c11 - c21), dt) + mx, min_w, max_w);\n\
144 	   w3 = clamp(lc1 * dot(abs(c11 - c12), dt) + mx, min_w, max_w);\n\
145 	   w4 = clamp(lc2 * dot(abs(c11 - c01), dt) + mx, min_w, max_w);\n\
146 	   \n\
147 	   gl_FragColor = vec4(w1 * c10 + w2 * c21 + w3 * c12 + w4 * c01 + (1.0 - w1 - w2 - w3 - w4) * c11, 1);\n\
148 	}",
149 	// 2xSAL
150 	"#version 130\n\
151 	\n\
152 	uniform sampler2D u_texture;\n\
153 	uniform float u_width;\n\
154 	uniform float u_height;\n\
155 	uniform float u_widthrel;\n\
156 	uniform float u_heightrel;\n\
157 	\n\
158 	void main()\n\
159 	{\n\
160 	   vec2 texCoord = gl_TexCoord[0].xy * vec2(u_widthrel, -u_heightrel);\n\
161 	   vec2 UL, UR, DL, DR;\n\
162 	   float dx = pow(u_width, -1.0) * 0.25;\n\
163 	   float dy = pow(u_height, -1.0) * 0.25;\n\
164 	   vec3 dt = vec3(1.0, 1.0, 1.0);\n\
165 	   UL = texCoord + vec2(-dx, -dy);\n\
166 	   UR = texCoord + vec2(dx, -dy);\n\
167 	   DL = texCoord + vec2(-dx, dy);\n\
168 	   DR = texCoord + vec2(dx, dy);\n\
169 	   vec3 c00 = texture2D(u_texture, UL).xyz;\n\
170 	   vec3 c20 = texture2D(u_texture, UR).xyz;\n\
171 	   vec3 c02 = texture2D(u_texture, DL).xyz;\n\
172 	   vec3 c22 = texture2D(u_texture, DR).xyz;\n\
173 	   float m1=dot(abs(c00-c22),dt)+0.001;\n\
174 	   float m2=dot(abs(c02-c20),dt)+0.001;\n\
175 	   gl_FragColor = vec4((m1*(c02+c20)+m2*(c22+c00))/(2.0*(m1+m2)),1.0); \n\
176 	}",
177 	// SuperEagle
178 	"#version 130\n\
179 	\n\
180 	uniform sampler2D u_texture;\n\
181 	uniform float u_width;\n\
182 	uniform float u_height;\n\
183 	uniform float u_widthrel;\n\
184 	uniform float u_heightrel;\n\
185 	\n\
186 	int GET_RESULT(float A, float B, float C, float D)\n\
187 	{\n\
188 		int x = 0; int y = 0; int r = 0;\n\
189 		if (A == C) x+=1; else if (B == C) y+=1;\n\
190 		if (A == D) x+=1; else if (B == D) y+=1;\n\
191 		if (x <= 1) r+=1; \n\
192 		if (y <= 1) r-=1;\n\
193 		return r;\n\
194 	} \n\
195 	\n\
196 	const vec3 dtt = vec3(65536.0,255.0,1.0);\n\
197 	\n\
198 	float reduce(vec3 color)\n\
199 	{ \n\
200 		return dot(color, dtt);\n\
201 	}\n\
202 	\n\
203 	void main()\n\
204 	{\n\
205 	   // get texel size   	\n\
206 		vec2 ps = vec2(0.999/u_width, 0.999/u_height);\n\
207 	\n\
208 		vec2 v_texCoord = gl_TexCoord[0].xy * vec2(u_widthrel, -u_heightrel);\n\
209 	\n\
210 		// calculating offsets, coordinates\n\
211 		vec2 dx = vec2( ps.x, 0.0); \n\
212 		vec2 dy = vec2( 0.0, ps.y);\n\
213 		vec2 g1 = vec2( ps.x,ps.y);\n\
214 		vec2 g2 = vec2(-ps.x,ps.y);	\n\
215 		\n\
216 		vec2 pixcoord  = v_texCoord/ps;	//VAR.CT\n\
217 		vec2 fp        = fract(pixcoord);\n\
218 		vec2 pC4       = v_texCoord-fp*ps;\n\
219 		vec2 pC8       = pC4+g1;		//VAR.CT\n\
220 	\n\
221 		// Reading the texels\n\
222 		vec3 C0 = texture2D(u_texture,pC4-g1).xyz; \n\
223 		vec3 C1 = texture2D(u_texture,pC4-dy).xyz;\n\
224 		vec3 C2 = texture2D(u_texture,pC4-g2).xyz;\n\
225 		vec3 D3 = texture2D(u_texture,pC4-g2+dx).xyz;\n\
226 		vec3 C3 = texture2D(u_texture,pC4-dx).xyz;\n\
227 		vec3 C4 = texture2D(u_texture,pC4   ).xyz;\n\
228 		vec3 C5 = texture2D(u_texture,pC4+dx).xyz;\n\
229 		vec3 D4 = texture2D(u_texture,pC8-g2).xyz;\n\
230 		vec3 C6 = texture2D(u_texture,pC4+g2).xyz;\n\
231 		vec3 C7 = texture2D(u_texture,pC4+dy).xyz;\n\
232 		vec3 C8 = texture2D(u_texture,pC4+g1).xyz;\n\
233 		vec3 D5 = texture2D(u_texture,pC8+dx).xyz;\n\
234 		vec3 D0 = texture2D(u_texture,pC4+g2+dy).xyz;\n\
235 		vec3 D1 = texture2D(u_texture,pC8+g2).xyz;\n\
236 		vec3 D2 = texture2D(u_texture,pC8+dy).xyz;\n\
237 		vec3 D6 = texture2D(u_texture,pC8+g1).xyz;\n\
238 	\n\
239 		vec3 p00,p10,p01,p11;\n\
240 	\n\
241 		// reducing vec3 to float	\n\
242 		float c0 = reduce(C0);float c1 = reduce(C1);\n\
243 		float c2 = reduce(C2);float c3 = reduce(C3);\n\
244 		float c4 = reduce(C4);float c5 = reduce(C5);\n\
245 		float c6 = reduce(C6);float c7 = reduce(C7);\n\
246 		float c8 = reduce(C8);float d0 = reduce(D0);\n\
247 		float d1 = reduce(D1);float d2 = reduce(D2);\n\
248 		float d3 = reduce(D3);float d4 = reduce(D4);\n\
249 		float d5 = reduce(D5);float d6 = reduce(D6);\n\
250 	\n\
251 		/*              SuperEagle code               */\n\
252 		/*  Copied from the Dosbox source code        */\n\
253 		/*  Copyright (C) 2002-2007  The DOSBox Team  */\n\
254 		/*  License: GNU-GPL                          */\n\
255 		/*  Adapted by guest(r) on 16.4.2007          */       \n\
256 		if (c4 != c8) {\n\
257 			if (c7 == c5) {\n\
258 				p01 = p10 = C7;\n\
259 				if ((c6 == c7) || (c5 == c2)) {\n\
260 						p00 = 0.25*(3.0*C7+C4);\n\
261 				} else {\n\
262 						p00 = 0.5*(C4+C5);\n\
263 				}\n\
264 	\n\
265 				if ((c5 == d4) || (c7 == d1)) {\n\
266 						p11 = 0.25*(3.0*C7+C8);\n\
267 				} else {\n\
268 						p11 = 0.5*(C7+C8);\n\
269 				}\n\
270 			} else {\n\
271 				p11 = 0.125*(6.0*C8+C7+C5);\n\
272 				p00 = 0.125*(6.0*C4+C7+C5);\n\
273 	\n\
274 				p10 = 0.125*(6.0*C7+C4+C8);\n\
275 				p01 = 0.125*(6.0*C5+C4+C8);\n\
276 			}\n\
277 		} else {\n\
278 			if (c7 != c5) {\n\
279 				p11 = p00 = C4;\n\
280 	\n\
281 				if ((c1 == c4) || (c8 == d5)) {\n\
282 						p01 = 0.25*(3.0*C4+C5);\n\
283 				} else {\n\
284 						p01 = 0.5*(C4+C5);\n\
285 				}\n\
286 	\n\
287 				if ((c8 == d2) || (c3 == c4)) {\n\
288 						p10 = 0.25*(3.0*C4+C7);\n\
289 				} else {\n\
290 						p10 = 0.5*(C7+C8);\n\
291 				}\n\
292 			} else {\n\
293 				int r = 0;\n\
294 				r += GET_RESULT(c5,c4,c6,d1);\n\
295 				r += GET_RESULT(c5,c4,c3,c1);\n\
296 				r += GET_RESULT(c5,c4,d2,d5);\n\
297 				r += GET_RESULT(c5,c4,c2,d4);\n\
298 	\n\
299 				if (r > 0) {\n\
300 						p01 = p10 = C7;\n\
301 						p00 = p11 = 0.5*(C4+C5);\n\
302 				} else if (r < 0) {\n\
303 						p11 = p00 = C4;\n\
304 						p01 = p10 = 0.5*(C4+C5);\n\
305 				} else {\n\
306 						p11 = p00 = C4;\n\
307 						p01 = p10 = C7;\n\
308 				}\n\
309 			}\n\
310 		}\n\
311 	\n\
312 		// Distributing the four products	\n\
313 		if (fp.x < 0.50)\n\
314 			{ if (fp.y < 0.50) p10 = p00;}\n\
315 		else\n\
316 			{ if (fp.y < 0.50) p10 = p01; else p10 = p11;}\n\
317 	\n\
318 		gl_FragColor = vec4(p10, 1);\n\
319 	}"
320 };
321 
322 #ifndef __APPLE__
323 PFNGLCREATESHADERPROC glCreateShader;
324 PFNGLSHADERSOURCEPROC glShaderSource;
325 PFNGLCOMPILESHADERPROC glCompileShader;
326 PFNGLCREATEPROGRAMPROC glCreateProgram;
327 PFNGLATTACHSHADERPROC glAttachShader;
328 PFNGLLINKPROGRAMPROC glLinkProgram;
329 PFNGLUSEPROGRAMPROC glUseProgram;
330 PFNGLISPROGRAMPROC glIsProgram;
331 PFNGLDELETEPROGRAMPROC glDeleteProgram;
332 PFNGLDELETESHADERPROC glDeleteShader;
333 PFNGLGETSHADERIVPROC glGetShaderiv;
334 PFNGLGETPROGRAMIVPROC glGetProgramiv;
335 PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
336 PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
337 PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
338 PFNGLACTIVETEXTUREPROC glActiveTextureProc;
339 PFNGLUNIFORM1FPROC glUniform1f;
340 PFNGLUNIFORM1IPROC glUniform1i;
341 PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffers;
342 PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebuffer;
343 PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture;
344 PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffers;
345 PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbuffer;
346 PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorage;
347 PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbuffer;
348 PFNGLDRAWBUFFERSPROC glDrawBuffers;
349 PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatus;
350 #else
351 #define glGenFramebuffers glGenFramebuffersEXT
352 #define glBindFramebuffer glBindFramebufferEXT
353 #define glCheckFramebufferStatus glCheckFramebufferStatusEXT
354 #define glActiveTextureProc glActiveTexture
355 #define glFramebufferTexture glFramebufferTexture2DEXT
356 #endif
357 
358 GLuint fullscreenShader;
359 GLuint fullscreenFramebuffer = 0;
360 GLuint fullscreenTexture;
361 
printShaderInfoLog(GLuint obj,const char * prefix)362 void printShaderInfoLog(GLuint obj, const char* prefix)
363 {
364 	int infologLength = 0;
365 	int charsWritten = 0;
366 	char *infoLog;
367 
368 	glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &infologLength);
369 
370 	if (infologLength > 0)
371 	{
372 		infoLog = (char *)malloc(infologLength);
373 		glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
374 		fprintf(stdout, "%s: %s\n", prefix, infoLog);
375 		free(infoLog);
376 	}
377 }
printProgramInfoLog(GLuint obj,const char * prefix)378 void printProgramInfoLog(GLuint obj, const char* prefix)
379 {
380 	int infologLength = 0;
381 	int charsWritten = 0;
382 	char *infoLog;
383 
384 	glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &infologLength);
385 
386 	if (infologLength > 0)
387 	{
388 		infoLog = (char *)malloc(infologLength);
389 		glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
390 		fprintf(stdout, "%s: %s\n", prefix, infoLog);
391 		free(infoLog);
392 	}
393 }
394 
395 //Wyrmgus start
396 //unsigned ShaderIndex = 0;
397 unsigned ShaderIndex = -1 % MAX_SHADERS;
398 //Wyrmgus end
399 
LoadShaders()400 extern bool LoadShaders() {
401 	GLuint vs, fs;
402 	GLint params;
403 	fs = glCreateShader(GL_FRAGMENT_SHADER);
404 	if (fs == 0) {
405 		return false;
406 	}
407 	glShaderSource(fs, 1, (const char**)&(fragment_shaders[ShaderIndex]), nullptr);
408 	glCompileShader(fs);
409 	glGetShaderiv(fs, GL_COMPILE_STATUS, &params);
410 	if (params == GL_FALSE) {
411 		glDeleteShader(fs);
412 		return false;
413 	}
414 	//printShaderInfoLog(fs, "Fragment Shader");
415 	ShaderIndex = (ShaderIndex + 1) % MAX_SHADERS;
416 	vs = glCreateShader(GL_VERTEX_SHADER);
417 	if (fs == 0) {
418 		glDeleteShader(fs);
419 		return false;
420 	}
421 	glShaderSource(vs, 1, (const char**)&vertex_shader, nullptr);
422 	glCompileShader(vs);
423 	glGetShaderiv(fs, GL_COMPILE_STATUS, &params);
424 	if (params == GL_FALSE) {
425 		glDeleteShader(fs);
426 		glDeleteShader(vs);
427 		return false;
428 	}
429 	//printShaderInfoLog(vs, "Vertex Shader");
430 	if (glIsProgram(fullscreenShader)) {
431 		glDeleteProgram(fullscreenShader);
432 	}
433 	fullscreenShader = glCreateProgram();
434 	if (fullscreenShader == 0) {
435 		glDeleteShader(fs);
436 		glDeleteShader(vs);
437 		return false;
438 	}
439 	glAttachShader(fullscreenShader, vs);
440 	glAttachShader(fullscreenShader, fs);
441 	glLinkProgram(fullscreenShader);
442 	glGetProgramiv(fullscreenShader, GL_LINK_STATUS, &params);
443 	if (params == GL_FALSE) {
444 		glDeleteShader(fs);
445 		glDeleteShader(vs);
446 		glDeleteProgram(fullscreenShader);
447 		return false;
448 	}
449 	glDeleteShader(fs);
450 	glDeleteShader(vs);
451 	//printProgramInfoLog(fullscreenShader, "Shader Program");
452 	return true;
453 }
454 
LoadShaderExtensions()455 extern bool LoadShaderExtensions() {
456 #ifndef __APPLE__
457 	glCreateShader = (PFNGLCREATESHADERPROC)(uintptr_t)SDL_GL_GetProcAddress("glCreateShader");
458 	glShaderSource = (PFNGLSHADERSOURCEPROC)(uintptr_t)SDL_GL_GetProcAddress("glShaderSource");
459 	glCompileShader = (PFNGLCOMPILESHADERPROC)(uintptr_t)SDL_GL_GetProcAddress("glCompileShader");
460 	glCreateProgram = (PFNGLCREATEPROGRAMPROC)(uintptr_t)SDL_GL_GetProcAddress("glCreateProgram");
461 	glAttachShader = (PFNGLATTACHSHADERPROC)(uintptr_t)SDL_GL_GetProcAddress("glAttachShader");
462 	glLinkProgram = (PFNGLLINKPROGRAMPROC)(uintptr_t)SDL_GL_GetProcAddress("glLinkProgram");
463 	glUseProgram = (PFNGLUSEPROGRAMPROC)(uintptr_t)SDL_GL_GetProcAddress("glUseProgram");
464 	glGetShaderiv = (PFNGLGETSHADERIVPROC)(uintptr_t)SDL_GL_GetProcAddress("glGetShaderiv");
465 	glGetProgramiv = (PFNGLGETPROGRAMIVPROC)(uintptr_t)SDL_GL_GetProcAddress("glGetProgramiv");
466 	glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)(uintptr_t)SDL_GL_GetProcAddress("glGetShaderInfoLog");
467 	glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)(uintptr_t)SDL_GL_GetProcAddress("glGetProgramInfoLog");
468 	glIsProgram = (PFNGLISPROGRAMPROC)(uintptr_t)SDL_GL_GetProcAddress("glIsProgram");
469 	glDeleteProgram = (PFNGLDELETEPROGRAMPROC)(uintptr_t)SDL_GL_GetProcAddress("glDeleteProgram");
470 	glDeleteShader = (PFNGLDELETESHADERPROC)(uintptr_t)SDL_GL_GetProcAddress("glDeleteShader");
471 
472 	glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)(uintptr_t)SDL_GL_GetProcAddress("glGetUniformLocation");
473 	glActiveTextureProc = (PFNGLACTIVETEXTUREPROC)(uintptr_t)SDL_GL_GetProcAddress("glActiveTexture");
474 	glUniform1f = (PFNGLUNIFORM1FPROC)(uintptr_t)SDL_GL_GetProcAddress("glUniform1f");
475 	glUniform1i = (PFNGLUNIFORM1IPROC)(uintptr_t)SDL_GL_GetProcAddress("glUniform1i");
476 
477 	glGenFramebuffers = (PFNGLGENFRAMEBUFFERSEXTPROC)(uintptr_t)SDL_GL_GetProcAddress("glGenFramebuffers");
478 	glBindFramebuffer = (PFNGLBINDFRAMEBUFFEREXTPROC)(uintptr_t)SDL_GL_GetProcAddress("glBindFramebuffer");
479 	glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)(uintptr_t)SDL_GL_GetProcAddress("glFramebufferTexture2D");
480 	glGenRenderbuffers = (PFNGLGENRENDERBUFFERSEXTPROC)(uintptr_t)SDL_GL_GetProcAddress("glGenRenderbuffers");
481 	glBindRenderbuffer = (PFNGLBINDRENDERBUFFEREXTPROC)(uintptr_t)SDL_GL_GetProcAddress("glBindRenderbuffer");
482 	glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEEXTPROC)(uintptr_t)SDL_GL_GetProcAddress("glRenderbufferStorage");
483 	glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)(uintptr_t)SDL_GL_GetProcAddress("glFramebufferRenderbuffer");
484 	glDrawBuffers = (PFNGLDRAWBUFFERSPROC)(uintptr_t)SDL_GL_GetProcAddress("glDrawBuffers");
485 	glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)(uintptr_t)SDL_GL_GetProcAddress("glCheckFramebufferStatus");
486 #endif
487 	if (glCreateShader && glGenFramebuffers && glGetUniformLocation && glActiveTextureProc) {
488 		return LoadShaders();
489 	} else {
490 		return false;
491 	}
492 }
493 
SetupFramebuffer()494 extern void SetupFramebuffer() {
495 	glGenTextures(1, &fullscreenTexture); // generate a texture to render to off-screen
496 	glBindTexture(GL_TEXTURE_2D, fullscreenTexture); // bind it, so all texture functions go to it
497 	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Video.ViewportWidth, Video.ViewportHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); // give an empty image to opengl
498 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // make sure we use nearest filtering
499 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
500 	glGenFramebuffers(1, &fullscreenFramebuffer); // generate a framebuffer to render to
501 	glBindFramebuffer(GL_FRAMEBUFFER_EXT, fullscreenFramebuffer); // bind it
502 	glFramebufferTexture(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, fullscreenTexture, 0); // set our texture as the "screen" of the framebuffer
503 	GLenum DrawBuffers[1] = { GL_COLOR_ATTACHMENT0_EXT };
504 	glDrawBuffers(1, DrawBuffers);
505 	if (glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) {
506 		fprintf(stderr, "FATAL: Error Creating Framebuffer! Try running without OpenGL.");
507 		exit(-1);
508 	}
509 	glBindFramebuffer(GL_FRAMEBUFFER_EXT, fullscreenFramebuffer);
510 }
511 
RenderFramebufferToScreen()512 extern void RenderFramebufferToScreen() {
513 	// switch the rendering target back to the real display
514 	glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
515 	// setup our shader program
516 	glUseProgram(fullscreenShader);
517 	GLint textureloc = glGetUniformLocation(fullscreenShader, "u_texture");
518 	GLint widthloc = glGetUniformLocation(fullscreenShader, "u_width");
519 	GLint heightloc = glGetUniformLocation(fullscreenShader, "u_height");
520 	GLint widthrelloc = glGetUniformLocation(fullscreenShader, "u_widthrel");
521 	GLint heightrelloc = glGetUniformLocation(fullscreenShader, "u_heightrel");
522 	glUniform1f(widthloc, Video.ViewportWidth);
523 	glUniform1f(heightloc, Video.ViewportHeight);
524 	glUniform1f(widthrelloc, (float)Video.Width / (float)Video.ViewportWidth);
525 	glUniform1f(heightrelloc, (float)Video.Height / (float)Video.ViewportHeight);
526 	glUniform1i(textureloc, 0);
527 	glActiveTextureProc(GL_TEXTURE0);
528 	// render the framebuffer texture to a fullscreen quad on the real display
529 	glBindTexture(GL_TEXTURE_2D, fullscreenTexture);
530 	glBegin(GL_QUADS);
531 	glTexCoord2f(0, 0);
532 	glVertex2i(0, 0);
533 	glTexCoord2f(1, 0);
534 	glVertex2i(Video.ViewportWidth, 0);
535 	glTexCoord2f(1, 1);
536 	glVertex2i(Video.ViewportWidth, Video.ViewportHeight);
537 	glTexCoord2f(0, 1);
538 	glVertex2i(0, Video.ViewportHeight);
539 	glEnd();
540 	SDL_GL_SwapBuffers();
541 	glUseProgram(0); // Disable shaders again, and render to framebuffer again
542 	glBindFramebuffer(GL_FRAMEBUFFER_EXT, fullscreenFramebuffer);
543 }
544 #endif
545