Merge lp:~timfelgentreff/stratagus/shaders into lp:stratagus
- shaders
- Merge into trunk
Proposed by
timfelgentreff
Status: | Merged |
---|---|
Merged at revision: | 9033 |
Proposed branch: | lp:~timfelgentreff/stratagus/shaders |
Merge into: | lp:stratagus |
Diff against target: |
687 lines (+557/-4) 6 files modified
CMakeLists.txt (+10/-1) src/include/shaders.h (+11/-0) src/include/video.h (+1/-0) src/stratagus/stratagus.cpp (+7/-1) src/video/sdl.cpp (+26/-2) src/video/shaders.cpp (+502/-0) |
To merge this branch: | bzr merge lp:~timfelgentreff/stratagus/shaders |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Stratagus | Pending | ||
Review via email: mp+274693@code.launchpad.net |
Commit message
Description of the change
Adds shaders that are used with OpenGL to scale the entire screen. For now, the 'ctrl+alt+/' (backslash) key is globally bound to cycle through available shaders so you can try it.
To post a comment you must log in.
- 9032. By timfelgentreff
-
add scale2x (aka advmame2x) as scaling shader
- 9033. By timfelgentreff
-
add cmdline switches for shaders, add ctrl+alt+/ as hard cycle keybinding, remove debug prints
Revision history for this message
timfelgentreff (timfelgentreff) wrote : | # |
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2015-04-12 09:55:12 +0000 |
3 | +++ CMakeLists.txt 2015-10-19 16:16:43 +0000 |
4 | @@ -348,6 +348,7 @@ |
5 | src/video/movie.cpp |
6 | src/video/png.cpp |
7 | src/video/sdl.cpp |
8 | + src/video/shaders.cpp |
9 | src/video/sprite.cpp |
10 | src/video/video.cpp |
11 | ) |
12 | @@ -554,6 +555,7 @@ |
13 | src/include/script.h |
14 | src/include/script_sound.h |
15 | src/include/settings.h |
16 | + src/include/shaders.h |
17 | src/include/sound.h |
18 | src/include/sound_server.h |
19 | src/include/spells.h |
20 | @@ -932,7 +934,14 @@ |
21 | |
22 | if(ENABLE_MULTIBUILD) |
23 | if(WIN32 AND MSVC) |
24 | - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") |
25 | + if(MSVC_VERSION GREATER 1800) # if > VC13 |
26 | + message("The project must be compiled with VS2013 or older. VS2015 has deprecated many functions that we still use.") |
27 | + set(CMAKE_GENERATOR_TOOLSET "v120" CACHE STRING "Platform Toolset" FORCE) |
28 | + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO /NODEFAULTLIB:MSVCRT") |
29 | + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO /NODEFAULTLIB:MSVCRT") |
30 | + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO /NODEFAULTLIB:MSVCRT") |
31 | + endif() |
32 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") |
33 | message(STATUS "Added parallel build arguments to CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}") |
34 | endif() |
35 | endif() |
36 | |
37 | === added file 'src/include/shaders.h' |
38 | --- src/include/shaders.h 1970-01-01 00:00:00 +0000 |
39 | +++ src/include/shaders.h 2015-10-19 16:16:43 +0000 |
40 | @@ -0,0 +1,11 @@ |
41 | +#ifndef __SHADERS_H__ |
42 | +#define __SHADERS_H__ |
43 | +#ifdef USE_OPENGL |
44 | +#define MAX_SHADERS 5 |
45 | +extern unsigned ShaderIndex; |
46 | +extern void LoadShaders(); |
47 | +extern bool LoadShaderExtensions(); |
48 | +extern void SetupFramebuffer(); |
49 | +extern void RenderFramebufferToScreen(); |
50 | +#endif |
51 | +#endif |
52 | |
53 | === modified file 'src/include/video.h' |
54 | --- src/include/video.h 2015-03-11 19:07:07 +0000 |
55 | +++ src/include/video.h 2015-10-19 16:16:43 +0000 |
56 | @@ -41,6 +41,7 @@ |
57 | |
58 | #ifdef USE_OPENGL |
59 | #include "SDL_opengl.h" |
60 | +#include "shaders.h" |
61 | #endif |
62 | |
63 | #include "guichan.h" |
64 | |
65 | === modified file 'src/stratagus/stratagus.cpp' |
66 | --- src/stratagus/stratagus.cpp 2015-04-12 09:54:50 +0000 |
67 | +++ src/stratagus/stratagus.cpp 2015-10-19 16:16:43 +0000 |
68 | @@ -477,6 +477,9 @@ |
69 | "\t-v mode\t\tVideo mode resolution in format <xres>x<yres>\n" |
70 | "\t-W\t\tWindowed video mode\n" |
71 | #if defined(USE_OPENGL) || defined(USE_GLES) |
72 | + "\t-x\t\tControls fullscreen scaling if your graphics card supports shaders.\n"\ |
73 | + "\t \t\tPass 1 for nearest-neigubour, 2 for EPX/AdvMame, 3 for HQx, 4 for SAL, 5 for SuperEagle\n"\ |
74 | + "\t \t\tYou can also use Ctrl+Alt+/ to cycle between these scaling algorithms at runtime.\n" |
75 | "\t-Z\t\tUse OpenGL to scale the screen to the viewport (retro-style). Implies -O.\n" |
76 | #endif |
77 | "map is relative to StratagusLibPath=datapath, use ./map for relative to cwd\n", |
78 | @@ -529,7 +532,7 @@ |
79 | void ParseCommandLine(int argc, char **argv, Parameters ¶meters) |
80 | { |
81 | for (;;) { |
82 | - switch (getopt(argc, argv, "ac:d:D:eE:FhiI:lN:oOP:ps:S:u:v:WZ?")) { |
83 | + switch (getopt(argc, argv, "ac:d:D:eE:FhiI:lN:oOP:ps:S:u:v:Wx:Z?")) { |
84 | case 'a': |
85 | EnableAssert = true; |
86 | continue; |
87 | @@ -629,6 +632,9 @@ |
88 | Video.FullScreen = 0; |
89 | continue; |
90 | #if defined(USE_OPENGL) || defined(USE_GLES) |
91 | + case 'x': |
92 | + ShaderIndex = atoi(optarg) % MAX_SHADERS; |
93 | + continue; |
94 | case 'Z': |
95 | ForceUseOpenGL = 1; |
96 | UseOpenGL = 1; |
97 | |
98 | === modified file 'src/video/sdl.cpp' |
99 | --- src/video/sdl.cpp 2015-03-05 17:12:52 +0000 |
100 | +++ src/video/sdl.cpp 2015-10-19 16:16:43 +0000 |
101 | @@ -70,6 +70,7 @@ |
102 | |
103 | #ifdef USE_OPENGL |
104 | #include "SDL_opengl.h" |
105 | +#include "shaders.h" |
106 | #endif |
107 | |
108 | #ifdef USE_BEOS |
109 | @@ -122,6 +123,7 @@ |
110 | GLint GLMaxTextureSizeOverride; /// User-specified limit for ::GLMaxTextureSize |
111 | bool GLTextureCompressionSupported; /// Is OpenGL texture compression supported |
112 | bool UseGLTextureCompression; /// Use OpenGL texture compression |
113 | +bool GLShaderPipelineSupported; |
114 | #endif |
115 | |
116 | static std::map<int, std::string> Key2Str; |
117 | @@ -256,8 +258,11 @@ |
118 | } else { |
119 | GLTextureCompressionSupported = false; |
120 | } |
121 | + |
122 | + GLShaderPipelineSupported = LoadShaderExtensions(); |
123 | #else |
124 | GLTextureCompressionSupported = false; |
125 | + GLShaderPipelineSupported = false; |
126 | #endif |
127 | } |
128 | |
129 | @@ -281,7 +286,11 @@ |
130 | #endif |
131 | |
132 | #ifdef USE_OPENGL |
133 | - glOrtho(0, Video.Width, Video.Height, 0, -1, 1); |
134 | + if (!GLShaderPipelineSupported) { |
135 | + glOrtho(0, Video.Width, Video.Height, 0, -1, 1); |
136 | + } else { |
137 | + glOrtho(0, Video.ViewportWidth, Video.ViewportHeight, 0, -1, 1); |
138 | + } |
139 | #endif |
140 | |
141 | glMatrixMode(GL_MODELVIEW); |
142 | @@ -299,6 +308,10 @@ |
143 | |
144 | #ifdef USE_OPENGL |
145 | glClearDepth(1.0f); |
146 | + |
147 | + if (GLShaderPipelineSupported) { |
148 | + SetupFramebuffer(); |
149 | + } |
150 | #endif |
151 | |
152 | glShadeModel(GL_FLAT); |
153 | @@ -879,6 +892,13 @@ |
154 | break; |
155 | |
156 | case SDL_KEYDOWN: |
157 | + if (GLShaderPipelineSupported |
158 | + && event.key.keysym.sym == SDLK_SLASH |
159 | + && event.key.keysym.mod & KMOD_ALT |
160 | + && event.key.keysym.mod & KMOD_CTRL) { |
161 | + LoadShaders(); |
162 | + break; |
163 | + } |
164 | InputKeyButtonPress(callbacks, SDL_GetTicks(), |
165 | event.key.keysym.sym, event.key.keysym.unicode); |
166 | break; |
167 | @@ -999,7 +1019,11 @@ |
168 | eglSwapBuffers(eglDisplay, eglSurface); |
169 | #endif |
170 | #if defined(USE_OPENGL) || defined(USE_GLES_NATIVE) |
171 | - SDL_GL_SwapBuffers(); |
172 | + if (GLShaderPipelineSupported) { |
173 | + RenderFramebufferToScreen(); |
174 | + } else { |
175 | + SDL_GL_SwapBuffers(); |
176 | + } |
177 | #endif |
178 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
179 | } else |
180 | |
181 | === added file 'src/video/shaders.cpp' |
182 | --- src/video/shaders.cpp 1970-01-01 00:00:00 +0000 |
183 | +++ src/video/shaders.cpp 2015-10-19 16:16:43 +0000 |
184 | @@ -0,0 +1,502 @@ |
185 | +#include "stratagus.h" |
186 | +#include "video.h" |
187 | +#ifdef USE_OPENGL |
188 | +const char* vertex_shader = "#version 130\n\ |
189 | +\n\ |
190 | +uniform sampler2D u_texture;\n\ |
191 | +\n\ |
192 | +void main()\n\ |
193 | +{\n\ |
194 | + gl_TexCoord[0] = gl_MultiTexCoord0;\n\ |
195 | + gl_Position = ftransform();\n\ |
196 | +}"; |
197 | + |
198 | +const char* fragment_shaders[MAX_SHADERS] = { |
199 | + // Nearest-neighbour |
200 | + "#version 130\n\ |
201 | + \n\ |
202 | + uniform sampler2D u_texture;\n\ |
203 | + uniform float u_width;\n\ |
204 | + uniform float u_height;\n\ |
205 | + uniform float u_widthrel;\n\ |
206 | + uniform float u_heightrel;\n\ |
207 | + void main()\n\ |
208 | + {\n\ |
209 | + vec4 myColor = texture2D(u_texture, gl_TexCoord[0].xy * vec2(u_widthrel, -u_heightrel));\n\ |
210 | + gl_FragColor = myColor;\n\ |
211 | + }", |
212 | + // Scale2x |
213 | + "#version 110\n\ |
214 | + \n\ |
215 | + uniform sampler2D u_texture;\n\ |
216 | + uniform float u_width;\n\ |
217 | + uniform float u_height;\n\ |
218 | + uniform float u_widthrel;\n\ |
219 | + uniform float u_heightrel;\n\ |
220 | + \n\ |
221 | + void main() {\n\ |
222 | + // o = offset, the width of a pixel\n\ |
223 | + vec2 texCoord = gl_TexCoord[0].xy * vec2(u_widthrel, -u_heightrel);\n\ |
224 | + vec2 textureDimensions = vec2(u_width, u_height);\n\ |
225 | + vec2 o = 1.0 / textureDimensions;\n\ |
226 | + // texel arrangement\n\ |
227 | + // A B C\n\ |
228 | + // D E F\n\ |
229 | + // G H I\n\ |
230 | + vec4 A = texture2D(u_texture, texCoord + vec2( -o.x, o.y));\n\ |
231 | + vec4 B = texture2D(u_texture, texCoord + vec2( 0, o.y));\n\ |
232 | + vec4 C = texture2D(u_texture, texCoord + vec2( o.x, o.y));\n\ |
233 | + vec4 D = texture2D(u_texture, texCoord + vec2( -o.x, 0));\n\ |
234 | + vec4 E = texture2D(u_texture, texCoord + vec2( 0, 0));\n\ |
235 | + vec4 F = texture2D(u_texture, texCoord + vec2( o.x, 0));\n\ |
236 | + vec4 G = texture2D(u_texture, texCoord + vec2( -o.x, -o.y));\n\ |
237 | + vec4 H = texture2D(u_texture, texCoord + vec2( 0, -o.y));\n\ |
238 | + vec4 I = texture2D(u_texture, texCoord + vec2( o.x, -o.y));\n\ |
239 | + vec2 p = texCoord * textureDimensions;\n\ |
240 | + // p = the position within a pixel [0...1]\n\ |
241 | + p = p - floor(p);\n\ |
242 | + if (p.x > .5) {\n\ |
243 | + if (p.y > .5) {\n\ |
244 | + // Top Right\n\ |
245 | + gl_FragColor = B == F && B != D && F != H ? F : E;\n\ |
246 | + } else {\n\ |
247 | + // Bottom Right\n\ |
248 | + gl_FragColor = H == F && D != H && B != F ? F : E;\n\ |
249 | + }\n\ |
250 | + } else {\n\ |
251 | + if (p.y > .5) {\n\ |
252 | + // Top Left\n\ |
253 | + gl_FragColor = D == B && B != F && D != H ? D : E;\n\ |
254 | + } else {\n\ |
255 | + // Bottom Left\n\ |
256 | + gl_FragColor = D == H && D != B && H != F ? D : E;\n\ |
257 | + }\n\ |
258 | + }\n\ |
259 | + }", |
260 | + // HQX |
261 | + "#version 130\n\ |
262 | + \n\ |
263 | + uniform sampler2D u_texture;\n\ |
264 | + uniform float u_width;\n\ |
265 | + uniform float u_height;\n\ |
266 | + uniform float u_widthrel;\n\ |
267 | + uniform float u_heightrel;\n\ |
268 | + \n\ |
269 | + const float mx = 0.325; // start smoothing wt.\n\ |
270 | + const float k = -0.250; // wt. decrease factor\n\ |
271 | + const float max_w = 0.25; // max filter weigth\n\ |
272 | + const float min_w =-0.05; // min filter weigth\n\ |
273 | + const float lum_add = 0.25; // effects smoothing \n\ |
274 | + \n\ |
275 | + void main()\n\ |
276 | + {\n\ |
277 | + vec2 v_texCoord = gl_TexCoord[0].xy * vec2(u_widthrel, -u_heightrel);\n\ |
278 | + \n\ |
279 | + // hq2x\n\ |
280 | + float x = 0.5 * (1.0 / u_width);\n\ |
281 | + float y = 0.5 * (1.0 / u_height);\n\ |
282 | + vec2 dg1 = vec2( x, y);\n\ |
283 | + vec2 dg2 = vec2(-x, y);\n\ |
284 | + vec2 dx = vec2(x, 0.0);\n\ |
285 | + vec2 dy = vec2(0.0, y);\n\ |
286 | + \n\ |
287 | + vec4 TexCoord[5];\n\ |
288 | + TexCoord[0] = vec4(v_texCoord, 0.0, 0.0);\n\ |
289 | + TexCoord[1].xy = TexCoord[0].xy - dg1;\n\ |
290 | + TexCoord[1].zw = TexCoord[0].xy - dy;\n\ |
291 | + TexCoord[2].xy = TexCoord[0].xy - dg2;\n\ |
292 | + TexCoord[2].zw = TexCoord[0].xy + dx;\n\ |
293 | + TexCoord[3].xy = TexCoord[0].xy + dg1;\n\ |
294 | + TexCoord[3].zw = TexCoord[0].xy + dy;\n\ |
295 | + TexCoord[4].xy = TexCoord[0].xy + dg2;\n\ |
296 | + TexCoord[4].zw = TexCoord[0].xy - dx;\n\ |
297 | + \n\ |
298 | + vec3 c00 = texture2D(u_texture, TexCoord[1].xy).xyz; \n\ |
299 | + vec3 c10 = texture2D(u_texture, TexCoord[1].zw).xyz; \n\ |
300 | + vec3 c20 = texture2D(u_texture, TexCoord[2].xy).xyz; \n\ |
301 | + vec3 c01 = texture2D(u_texture, TexCoord[4].zw).xyz; \n\ |
302 | + vec3 c11 = texture2D(u_texture, TexCoord[0].xy).xyz; \n\ |
303 | + vec3 c21 = texture2D(u_texture, TexCoord[2].zw).xyz; \n\ |
304 | + vec3 c02 = texture2D(u_texture, TexCoord[4].xy).xyz; \n\ |
305 | + vec3 c12 = texture2D(u_texture, TexCoord[3].zw).xyz; \n\ |
306 | + vec3 c22 = texture2D(u_texture, TexCoord[3].xy).xyz; \n\ |
307 | + vec3 dt = vec3(1.0, 1.0, 1.0);\n\ |
308 | + \n\ |
309 | + float md1 = dot(abs(c00 - c22), dt);\n\ |
310 | + float md2 = dot(abs(c02 - c20), dt);\n\ |
311 | + \n\ |
312 | + float w1 = dot(abs(c22 - c11), dt) * md2;\n\ |
313 | + float w2 = dot(abs(c02 - c11), dt) * md1;\n\ |
314 | + float w3 = dot(abs(c00 - c11), dt) * md2;\n\ |
315 | + float w4 = dot(abs(c20 - c11), dt) * md1;\n\ |
316 | + \n\ |
317 | + float t1 = w1 + w3;\n\ |
318 | + float t2 = w2 + w4;\n\ |
319 | + float ww = max(t1, t2) + 0.0001;\n\ |
320 | + \n\ |
321 | + c11 = (w1 * c00 + w2 * c20 + w3 * c22 + w4 * c02 + ww * c11) / (t1 + t2 + ww);\n\ |
322 | + \n\ |
323 | + float lc1 = k / (0.12 * dot(c10 + c12 + c11, dt) + lum_add);\n\ |
324 | + float lc2 = k / (0.12 * dot(c01 + c21 + c11, dt) + lum_add);\n\ |
325 | + \n\ |
326 | + w1 = clamp(lc1 * dot(abs(c11 - c10), dt) + mx, min_w, max_w);\n\ |
327 | + w2 = clamp(lc2 * dot(abs(c11 - c21), dt) + mx, min_w, max_w);\n\ |
328 | + w3 = clamp(lc1 * dot(abs(c11 - c12), dt) + mx, min_w, max_w);\n\ |
329 | + w4 = clamp(lc2 * dot(abs(c11 - c01), dt) + mx, min_w, max_w);\n\ |
330 | + \n\ |
331 | + gl_FragColor = vec4(w1 * c10 + w2 * c21 + w3 * c12 + w4 * c01 + (1.0 - w1 - w2 - w3 - w4) * c11, 1);\n\ |
332 | + }", |
333 | + // 2xSAL |
334 | + "#version 130\n\ |
335 | + \n\ |
336 | + uniform sampler2D u_texture;\n\ |
337 | + uniform float u_width;\n\ |
338 | + uniform float u_height;\n\ |
339 | + uniform float u_widthrel;\n\ |
340 | + uniform float u_heightrel;\n\ |
341 | + \n\ |
342 | + void main()\n\ |
343 | + {\n\ |
344 | + vec2 texCoord = gl_TexCoord[0].xy * vec2(u_widthrel, -u_heightrel);\n\ |
345 | + vec2 UL, UR, DL, DR;\n\ |
346 | + float dx = pow(u_width, -1.0) * 0.25;\n\ |
347 | + float dy = pow(u_height, -1.0) * 0.25;\n\ |
348 | + vec3 dt = vec3(1.0, 1.0, 1.0);\n\ |
349 | + UL = texCoord + vec2(-dx, -dy);\n\ |
350 | + UR = texCoord + vec2(dx, -dy);\n\ |
351 | + DL = texCoord + vec2(-dx, dy);\n\ |
352 | + DR = texCoord + vec2(dx, dy);\n\ |
353 | + vec3 c00 = texture2D(u_texture, UL).xyz;\n\ |
354 | + vec3 c20 = texture2D(u_texture, UR).xyz;\n\ |
355 | + vec3 c02 = texture2D(u_texture, DL).xyz;\n\ |
356 | + vec3 c22 = texture2D(u_texture, DR).xyz;\n\ |
357 | + float m1=dot(abs(c00-c22),dt)+0.001;\n\ |
358 | + float m2=dot(abs(c02-c20),dt)+0.001;\n\ |
359 | + gl_FragColor = vec4((m1*(c02+c20)+m2*(c22+c00))/(2.0*(m1+m2)),1.0); \n\ |
360 | + }", |
361 | + // SuperEagle |
362 | + "#version 130\n\ |
363 | + \n\ |
364 | + uniform sampler2D u_texture;\n\ |
365 | + uniform float u_width;\n\ |
366 | + uniform float u_height;\n\ |
367 | + uniform float u_widthrel;\n\ |
368 | + uniform float u_heightrel;\n\ |
369 | + \n\ |
370 | + int GET_RESULT(float A, float B, float C, float D)\n\ |
371 | + {\n\ |
372 | + int x = 0; int y = 0; int r = 0;\n\ |
373 | + if (A == C) x+=1; else if (B == C) y+=1;\n\ |
374 | + if (A == D) x+=1; else if (B == D) y+=1;\n\ |
375 | + if (x <= 1) r+=1; \n\ |
376 | + if (y <= 1) r-=1;\n\ |
377 | + return r;\n\ |
378 | + } \n\ |
379 | + \n\ |
380 | + const vec3 dtt = vec3(65536.0,255.0,1.0);\n\ |
381 | + \n\ |
382 | + float reduce(vec3 color)\n\ |
383 | + { \n\ |
384 | + return dot(color, dtt);\n\ |
385 | + }\n\ |
386 | + \n\ |
387 | + void main()\n\ |
388 | + {\n\ |
389 | + // get texel size \n\ |
390 | + vec2 ps = vec2(0.999/u_width, 0.999/u_height);\n\ |
391 | + \n\ |
392 | + vec2 v_texCoord = gl_TexCoord[0].xy * vec2(u_widthrel, -u_heightrel);\n\ |
393 | + \n\ |
394 | + // calculating offsets, coordinates\n\ |
395 | + vec2 dx = vec2( ps.x, 0.0); \n\ |
396 | + vec2 dy = vec2( 0.0, ps.y);\n\ |
397 | + vec2 g1 = vec2( ps.x,ps.y);\n\ |
398 | + vec2 g2 = vec2(-ps.x,ps.y); \n\ |
399 | + \n\ |
400 | + vec2 pixcoord = v_texCoord/ps; //VAR.CT\n\ |
401 | + vec2 fp = fract(pixcoord);\n\ |
402 | + vec2 pC4 = v_texCoord-fp*ps;\n\ |
403 | + vec2 pC8 = pC4+g1; //VAR.CT\n\ |
404 | + \n\ |
405 | + // Reading the texels\n\ |
406 | + vec3 C0 = texture2D(u_texture,pC4-g1).xyz; \n\ |
407 | + vec3 C1 = texture2D(u_texture,pC4-dy).xyz;\n\ |
408 | + vec3 C2 = texture2D(u_texture,pC4-g2).xyz;\n\ |
409 | + vec3 D3 = texture2D(u_texture,pC4-g2+dx).xyz;\n\ |
410 | + vec3 C3 = texture2D(u_texture,pC4-dx).xyz;\n\ |
411 | + vec3 C4 = texture2D(u_texture,pC4 ).xyz;\n\ |
412 | + vec3 C5 = texture2D(u_texture,pC4+dx).xyz;\n\ |
413 | + vec3 D4 = texture2D(u_texture,pC8-g2).xyz;\n\ |
414 | + vec3 C6 = texture2D(u_texture,pC4+g2).xyz;\n\ |
415 | + vec3 C7 = texture2D(u_texture,pC4+dy).xyz;\n\ |
416 | + vec3 C8 = texture2D(u_texture,pC4+g1).xyz;\n\ |
417 | + vec3 D5 = texture2D(u_texture,pC8+dx).xyz;\n\ |
418 | + vec3 D0 = texture2D(u_texture,pC4+g2+dy).xyz;\n\ |
419 | + vec3 D1 = texture2D(u_texture,pC8+g2).xyz;\n\ |
420 | + vec3 D2 = texture2D(u_texture,pC8+dy).xyz;\n\ |
421 | + vec3 D6 = texture2D(u_texture,pC8+g1).xyz;\n\ |
422 | + \n\ |
423 | + vec3 p00,p10,p01,p11;\n\ |
424 | + \n\ |
425 | + // reducing vec3 to float \n\ |
426 | + float c0 = reduce(C0);float c1 = reduce(C1);\n\ |
427 | + float c2 = reduce(C2);float c3 = reduce(C3);\n\ |
428 | + float c4 = reduce(C4);float c5 = reduce(C5);\n\ |
429 | + float c6 = reduce(C6);float c7 = reduce(C7);\n\ |
430 | + float c8 = reduce(C8);float d0 = reduce(D0);\n\ |
431 | + float d1 = reduce(D1);float d2 = reduce(D2);\n\ |
432 | + float d3 = reduce(D3);float d4 = reduce(D4);\n\ |
433 | + float d5 = reduce(D5);float d6 = reduce(D6);\n\ |
434 | + \n\ |
435 | + /* SuperEagle code */\n\ |
436 | + /* Copied from the Dosbox source code */\n\ |
437 | + /* Copyright (C) 2002-2007 The DOSBox Team */\n\ |
438 | + /* License: GNU-GPL */\n\ |
439 | + /* Adapted by guest(r) on 16.4.2007 */ \n\ |
440 | + if (c4 != c8) {\n\ |
441 | + if (c7 == c5) {\n\ |
442 | + p01 = p10 = C7;\n\ |
443 | + if ((c6 == c7) || (c5 == c2)) {\n\ |
444 | + p00 = 0.25*(3.0*C7+C4);\n\ |
445 | + } else {\n\ |
446 | + p00 = 0.5*(C4+C5);\n\ |
447 | + }\n\ |
448 | + \n\ |
449 | + if ((c5 == d4) || (c7 == d1)) {\n\ |
450 | + p11 = 0.25*(3.0*C7+C8);\n\ |
451 | + } else {\n\ |
452 | + p11 = 0.5*(C7+C8);\n\ |
453 | + }\n\ |
454 | + } else {\n\ |
455 | + p11 = 0.125*(6.0*C8+C7+C5);\n\ |
456 | + p00 = 0.125*(6.0*C4+C7+C5);\n\ |
457 | + \n\ |
458 | + p10 = 0.125*(6.0*C7+C4+C8);\n\ |
459 | + p01 = 0.125*(6.0*C5+C4+C8);\n\ |
460 | + }\n\ |
461 | + } else {\n\ |
462 | + if (c7 != c5) {\n\ |
463 | + p11 = p00 = C4;\n\ |
464 | + \n\ |
465 | + if ((c1 == c4) || (c8 == d5)) {\n\ |
466 | + p01 = 0.25*(3.0*C4+C5);\n\ |
467 | + } else {\n\ |
468 | + p01 = 0.5*(C4+C5);\n\ |
469 | + }\n\ |
470 | + \n\ |
471 | + if ((c8 == d2) || (c3 == c4)) {\n\ |
472 | + p10 = 0.25*(3.0*C4+C7);\n\ |
473 | + } else {\n\ |
474 | + p10 = 0.5*(C7+C8);\n\ |
475 | + }\n\ |
476 | + } else {\n\ |
477 | + int r = 0;\n\ |
478 | + r += GET_RESULT(c5,c4,c6,d1);\n\ |
479 | + r += GET_RESULT(c5,c4,c3,c1);\n\ |
480 | + r += GET_RESULT(c5,c4,d2,d5);\n\ |
481 | + r += GET_RESULT(c5,c4,c2,d4);\n\ |
482 | + \n\ |
483 | + if (r > 0) {\n\ |
484 | + p01 = p10 = C7;\n\ |
485 | + p00 = p11 = 0.5*(C4+C5);\n\ |
486 | + } else if (r < 0) {\n\ |
487 | + p11 = p00 = C4;\n\ |
488 | + p01 = p10 = 0.5*(C4+C5);\n\ |
489 | + } else {\n\ |
490 | + p11 = p00 = C4;\n\ |
491 | + p01 = p10 = C7;\n\ |
492 | + }\n\ |
493 | + }\n\ |
494 | + }\n\ |
495 | + \n\ |
496 | + // Distributing the four products \n\ |
497 | + if (fp.x < 0.50)\n\ |
498 | + { if (fp.y < 0.50) p10 = p00;}\n\ |
499 | + else\n\ |
500 | + { if (fp.y < 0.50) p10 = p01; else p10 = p11;}\n\ |
501 | + \n\ |
502 | + gl_FragColor = vec4(p10, 1);\n\ |
503 | + }" |
504 | +}; |
505 | + |
506 | + |
507 | +PFNGLCREATESHADERPROC glCreateShader; |
508 | +PFNGLSHADERSOURCEPROC glShaderSource; |
509 | +PFNGLCOMPILESHADERPROC glCompileShader; |
510 | +PFNGLCREATEPROGRAMPROC glCreateProgram; |
511 | +PFNGLATTACHSHADERPROC glAttachShader; |
512 | +PFNGLLINKPROGRAMPROC glLinkProgram; |
513 | +PFNGLUSEPROGRAMPROC glUseProgram; |
514 | +PFNGLISPROGRAMPROC glIsProgram; |
515 | +PFNGLDELETEPROGRAMPROC glDeleteProgram; |
516 | +PFNGLDELETESHADERPROC glDeleteShader; |
517 | +PFNGLGETSHADERIVPROC glGetShaderiv; |
518 | +PFNGLGETPROGRAMIVPROC glGetProgramiv; |
519 | +PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; |
520 | +PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; |
521 | +PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; |
522 | +PFNGLACTIVETEXTUREPROC glActiveTexture; |
523 | +PFNGLUNIFORM1FPROC glUniform1f; |
524 | +PFNGLUNIFORM1IPROC glUniform1i; |
525 | + |
526 | +GLuint fullscreenShader; |
527 | +GLuint fullscreenFramebuffer = 0; |
528 | +GLuint fullscreenTexture; |
529 | +PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffers; |
530 | +PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebuffer; |
531 | +PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture; |
532 | +PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffers; |
533 | +PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbuffer; |
534 | +PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorage; |
535 | +PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbuffer; |
536 | +PFNGLDRAWBUFFERSPROC glDrawBuffers; |
537 | +PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatus; |
538 | + |
539 | +void printShaderInfoLog(GLuint obj, const char* prefix) |
540 | +{ |
541 | + int infologLength = 0; |
542 | + int charsWritten = 0; |
543 | + char *infoLog; |
544 | + |
545 | + glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &infologLength); |
546 | + |
547 | + if (infologLength > 0) |
548 | + { |
549 | + infoLog = (char *)malloc(infologLength); |
550 | + glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog); |
551 | + fprintf(stdout, "%s: %s\n", prefix, infoLog); |
552 | + free(infoLog); |
553 | + } |
554 | +} |
555 | +void printProgramInfoLog(GLuint obj, const char* prefix) |
556 | +{ |
557 | + int infologLength = 0; |
558 | + int charsWritten = 0; |
559 | + char *infoLog; |
560 | + |
561 | + glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &infologLength); |
562 | + |
563 | + if (infologLength > 0) |
564 | + { |
565 | + infoLog = (char *)malloc(infologLength); |
566 | + glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog); |
567 | + fprintf(stdout, "%s: %s\n", prefix, infoLog); |
568 | + free(infoLog); |
569 | + } |
570 | +} |
571 | + |
572 | +extern unsigned ShaderIndex = 0; |
573 | + |
574 | +extern void LoadShaders() { |
575 | + GLuint vs, fs; |
576 | + fs = glCreateShader(GL_FRAGMENT_SHADER); |
577 | + glShaderSource(fs, 1, (const char**)&(fragment_shaders[ShaderIndex]), NULL); |
578 | + glCompileShader(fs); |
579 | + //printShaderInfoLog(fs, "Fragment Shader"); |
580 | + ShaderIndex = (ShaderIndex + 1) % MAX_SHADERS; |
581 | + vs = glCreateShader(GL_VERTEX_SHADER); |
582 | + glShaderSource(vs, 1, (const char**)&vertex_shader, NULL); |
583 | + glCompileShader(vs); |
584 | + //printShaderInfoLog(vs, "Vertex Shader"); |
585 | + if (glIsProgram(fullscreenShader)) { |
586 | + glDeleteProgram(fullscreenShader); |
587 | + } |
588 | + fullscreenShader = glCreateProgram(); |
589 | + glAttachShader(fullscreenShader, vs); |
590 | + glAttachShader(fullscreenShader, fs); |
591 | + glLinkProgram(fullscreenShader); |
592 | + glDeleteShader(fs); |
593 | + glDeleteShader(vs); |
594 | + //printProgramInfoLog(fullscreenShader, "Shader Program"); |
595 | +} |
596 | + |
597 | +extern bool LoadShaderExtensions() { |
598 | + glCreateShader = (PFNGLCREATESHADERPROC)(uintptr_t)SDL_GL_GetProcAddress("glCreateShader"); |
599 | + glShaderSource = (PFNGLSHADERSOURCEPROC)(uintptr_t)SDL_GL_GetProcAddress("glShaderSource"); |
600 | + glCompileShader = (PFNGLCOMPILESHADERPROC)(uintptr_t)SDL_GL_GetProcAddress("glCompileShader"); |
601 | + glCreateProgram = (PFNGLCREATEPROGRAMPROC)(uintptr_t)SDL_GL_GetProcAddress("glCreateProgram"); |
602 | + glAttachShader = (PFNGLATTACHSHADERPROC)(uintptr_t)SDL_GL_GetProcAddress("glAttachShader"); |
603 | + glLinkProgram = (PFNGLLINKPROGRAMPROC)(uintptr_t)SDL_GL_GetProcAddress("glLinkProgram"); |
604 | + glUseProgram = (PFNGLUSEPROGRAMPROC)(uintptr_t)SDL_GL_GetProcAddress("glUseProgram"); |
605 | + glGetShaderiv = (PFNGLGETSHADERIVPROC)(uintptr_t)SDL_GL_GetProcAddress("glGetShaderiv"); |
606 | + glGetProgramiv = (PFNGLGETPROGRAMIVPROC)(uintptr_t)SDL_GL_GetProcAddress("glGetProgramiv"); |
607 | + glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)(uintptr_t)SDL_GL_GetProcAddress("glGetShaderInfoLog"); |
608 | + glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)(uintptr_t)SDL_GL_GetProcAddress("glGetProgramInfoLog"); |
609 | + glIsProgram = (PFNGLISPROGRAMPROC)(uintptr_t)SDL_GL_GetProcAddress("glIsProgram"); |
610 | + glDeleteProgram = (PFNGLDELETEPROGRAMPROC)(uintptr_t)SDL_GL_GetProcAddress("glDeleteProgram"); |
611 | + glDeleteShader = (PFNGLDELETESHADERPROC)(uintptr_t)SDL_GL_GetProcAddress("glDeleteShader"); |
612 | + |
613 | + glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)(uintptr_t)SDL_GL_GetProcAddress("glGetUniformLocation"); |
614 | + glActiveTexture = (PFNGLACTIVETEXTUREPROC)(uintptr_t)SDL_GL_GetProcAddress("glActiveTexture"); |
615 | + glUniform1f = (PFNGLUNIFORM1FPROC)(uintptr_t)SDL_GL_GetProcAddress("glUniform1f"); |
616 | + glUniform1i = (PFNGLUNIFORM1IPROC)(uintptr_t)SDL_GL_GetProcAddress("glUniform1i"); |
617 | + |
618 | + glGenFramebuffers = (PFNGLGENFRAMEBUFFERSEXTPROC)(uintptr_t)SDL_GL_GetProcAddress("glGenFramebuffers"); |
619 | + glBindFramebuffer = (PFNGLBINDFRAMEBUFFEREXTPROC)(uintptr_t)SDL_GL_GetProcAddress("glBindFramebuffer"); |
620 | + glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)(uintptr_t)SDL_GL_GetProcAddress("glFramebufferTexture2D"); |
621 | + glGenRenderbuffers = (PFNGLGENRENDERBUFFERSEXTPROC)(uintptr_t)SDL_GL_GetProcAddress("glGenRenderbuffers"); |
622 | + glBindRenderbuffer = (PFNGLBINDRENDERBUFFEREXTPROC)(uintptr_t)SDL_GL_GetProcAddress("glBindRenderbuffer"); |
623 | + glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEEXTPROC)(uintptr_t)SDL_GL_GetProcAddress("glRenderbufferStorage"); |
624 | + glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)(uintptr_t)SDL_GL_GetProcAddress("glFramebufferRenderbuffer"); |
625 | + glDrawBuffers = (PFNGLDRAWBUFFERSPROC)(uintptr_t)SDL_GL_GetProcAddress("glDrawBuffers"); |
626 | + glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)(uintptr_t)SDL_GL_GetProcAddress("glCheckFramebufferStatus"); |
627 | + |
628 | + if (glCreateShader && glGenFramebuffers && glGetUniformLocation && glActiveTexture) { |
629 | + LoadShaders(); |
630 | + return true; |
631 | + } else { |
632 | + return false; |
633 | + } |
634 | +} |
635 | + |
636 | +extern void SetupFramebuffer() { |
637 | + glGenTextures(1, &fullscreenTexture); // generate a texture to render to off-screen |
638 | + glBindTexture(GL_TEXTURE_2D, fullscreenTexture); // bind it, so all texture functions go to it |
639 | + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Video.ViewportWidth, Video.ViewportHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); // give an empty image to opengl |
640 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // make sure we use nearest filtering |
641 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
642 | + glGenFramebuffers(1, &fullscreenFramebuffer); // generate a framebuffer to render to |
643 | + glBindFramebuffer(GL_FRAMEBUFFER_EXT, fullscreenFramebuffer); // bind it |
644 | + glFramebufferTexture(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, fullscreenTexture, 0); // set our texture as the "screen" of the framebuffer |
645 | + GLenum DrawBuffers[1] = { GL_COLOR_ATTACHMENT0_EXT }; |
646 | + glDrawBuffers(1, DrawBuffers); |
647 | + if (glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) { |
648 | + fprintf(stderr, "FATAL: Error Creating Framebuffer! Try running without OpenGL."); |
649 | + exit(-1); |
650 | + } |
651 | + glBindFramebuffer(GL_FRAMEBUFFER_EXT, fullscreenFramebuffer); |
652 | +} |
653 | + |
654 | +extern void RenderFramebufferToScreen() { |
655 | + // switch the rendering target back to the real display |
656 | + glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); |
657 | + // setup our shader program |
658 | + glUseProgram(fullscreenShader); |
659 | + GLint textureloc = glGetUniformLocation(fullscreenShader, "u_texture"); |
660 | + GLint widthloc = glGetUniformLocation(fullscreenShader, "u_width"); |
661 | + GLint heightloc = glGetUniformLocation(fullscreenShader, "u_height"); |
662 | + GLint widthrelloc = glGetUniformLocation(fullscreenShader, "u_widthrel"); |
663 | + GLint heightrelloc = glGetUniformLocation(fullscreenShader, "u_heightrel"); |
664 | + glUniform1f(widthloc, Video.ViewportWidth); |
665 | + glUniform1f(heightloc, Video.ViewportHeight); |
666 | + glUniform1f(widthrelloc, (float)Video.Width / (float)Video.ViewportWidth); |
667 | + glUniform1f(heightrelloc, (float)Video.Height / (float)Video.ViewportHeight); |
668 | + glUniform1i(textureloc, 0); |
669 | + glActiveTexture(GL_TEXTURE0); |
670 | + // render the framebuffer texture to a fullscreen quad on the real display |
671 | + glBindTexture(GL_TEXTURE_2D, fullscreenTexture); |
672 | + glBegin(GL_QUADS); |
673 | + glTexCoord2f(0, 0); |
674 | + glVertex2i(0, 0); |
675 | + glTexCoord2f(1, 0); |
676 | + glVertex2i(Video.ViewportWidth, 0); |
677 | + glTexCoord2f(1, 1); |
678 | + glVertex2i(Video.ViewportWidth, Video.ViewportHeight); |
679 | + glTexCoord2f(0, 1); |
680 | + glVertex2i(0, Video.ViewportHeight); |
681 | + glEnd(); |
682 | + SDL_GL_SwapBuffers(); |
683 | + glUseProgram(0); // Disable shaders again, and render to framebuffer again |
684 | + glBindFramebuffer(GL_FRAMEBUFFER_EXT, fullscreenFramebuffer); |
685 | +} |
686 | +#endif |
687 | \ No newline at end of file |
Ok, I've made a few cleanups, there is now a global key-combo to cycle through shaders (ctrl+alt+/) and the shaders can also be selected from the cmdline. If anyone has time to test this, that would be great. Otherwise, I'll just merge this in a couple of days