1 /*
2 Copyright (C) 2006 yopyop
3 Copyright (C) 2006-2007 shash
4 Copyright (C) 2008-2016 DeSmuME team
5
6 This file is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 2 of the License, or
9 (at your option) any later version.
10
11 This file is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with the this software. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "OGLRender.h"
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <algorithm>
26
27 #include "common.h"
28 #include "debug.h"
29 #include "gfx3d.h"
30 #include "NDSSystem.h"
31 #include "texcache.h"
32
33 #ifdef ENABLE_SSE2
34 #include <emmintrin.h>
35 #endif
36
37 #ifdef ENABLE_SSSE3
38 #include <tmmintrin.h>
39 #endif
40
41 typedef struct
42 {
43 unsigned int major;
44 unsigned int minor;
45 unsigned int revision;
46 } OGLVersion;
47
48 static OGLVersion _OGLDriverVersion = {0, 0, 0};
49
50 // Lookup Tables
51 static CACHE_ALIGN GLfloat material_8bit_to_float[256] = {0};
52 CACHE_ALIGN const GLfloat divide5bitBy31_LUT[32] = {0.0, 0.03225806451613, 0.06451612903226, 0.09677419354839,
53 0.1290322580645, 0.1612903225806, 0.1935483870968, 0.2258064516129,
54 0.2580645161290, 0.2903225806452, 0.3225806451613, 0.3548387096774,
55 0.3870967741935, 0.4193548387097, 0.4516129032258, 0.4838709677419,
56 0.5161290322581, 0.5483870967742, 0.5806451612903, 0.6129032258065,
57 0.6451612903226, 0.6774193548387, 0.7096774193548, 0.7419354838710,
58 0.7741935483871, 0.8064516129032, 0.8387096774194, 0.8709677419355,
59 0.9032258064516, 0.9354838709677, 0.9677419354839, 1.0};
60
61 const GLfloat PostprocessVtxBuffer[16] = {-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f,
62 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};
63 const GLubyte PostprocessElementBuffer[6] = {0, 1, 2, 2, 3, 0};
64
65 const GLenum RenderDrawList[4] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_COLOR_ATTACHMENT2_EXT, GL_COLOR_ATTACHMENT3_EXT};
66
BEGINGL()67 bool BEGINGL()
68 {
69 if(oglrender_beginOpenGL)
70 return oglrender_beginOpenGL();
71 else return true;
72 }
73
ENDGL()74 void ENDGL()
75 {
76 if(oglrender_endOpenGL)
77 oglrender_endOpenGL();
78 }
79
80 // Function Pointers
81 bool (*oglrender_init)() = NULL;
82 bool (*oglrender_beginOpenGL)() = NULL;
83 void (*oglrender_endOpenGL)() = NULL;
84 bool (*oglrender_framebufferDidResizeCallback)(size_t w, size_t h) = NULL;
85 void (*OGLLoadEntryPoints_3_2_Func)() = NULL;
86 void (*OGLCreateRenderer_3_2_Func)(OpenGLRenderer **rendererPtr) = NULL;
87
OGLLoadEntryPoints_Legacy()88 static void OGLLoadEntryPoints_Legacy()
89 {
90 }
91
92 // Vertex Shader GLSL 1.00
93 static const char *vertexShader_100 = {"\
94 attribute vec4 inPosition; \n\
95 attribute vec2 inTexCoord0; \n\
96 attribute vec3 inColor; \n\
97 \n\
98 uniform float polyAlpha; \n\
99 uniform vec2 polyTexScale; \n\
100 \n\
101 varying vec4 vtxPosition; \n\
102 varying vec2 vtxTexCoord; \n\
103 varying vec4 vtxColor; \n\
104 \n\
105 void main() \n\
106 { \n\
107 mat2 texScaleMtx = mat2( vec2(polyTexScale.x, 0.0), \n\
108 vec2( 0.0, polyTexScale.y)); \n\
109 \n\
110 vtxPosition = inPosition; \n\
111 vtxTexCoord = texScaleMtx * inTexCoord0; \n\
112 vtxColor = vec4(inColor * 4.0, polyAlpha); \n\
113 \n\
114 gl_Position = vtxPosition; \n\
115 } \n\
116 "};
117
118 // Fragment Shader GLSL 1.00
119 static const char *fragmentShader_100 = {"\
120 varying vec4 vtxPosition; \n\
121 varying vec2 vtxTexCoord; \n\
122 varying vec4 vtxColor; \n\
123 \n\
124 uniform sampler2D texRenderObject; \n\
125 uniform sampler1D texToonTable; \n\
126 \n\
127 uniform int stateToonShadingMode; \n\
128 uniform bool stateEnableAlphaTest; \n\
129 uniform bool stateEnableAntialiasing;\n\
130 uniform bool stateEnableEdgeMarking;\n\
131 uniform bool stateUseWDepth; \n\
132 uniform float stateAlphaTestRef; \n\
133 \n\
134 uniform int polyMode; \n\
135 uniform bool polyEnableDepthWrite;\n\
136 uniform bool polySetNewDepthForTranslucent;\n\
137 uniform int polyID; \n\
138 \n\
139 uniform bool polyEnableTexture; \n\
140 uniform bool polyEnableFog;\n\
141 \n\
142 vec3 packVec3FromFloat(const float value)\n\
143 {\n\
144 float expandedValue = value * 16777215.0;\n\
145 vec3 packedValue = vec3( fract(expandedValue/256.0), fract(((expandedValue/256.0) - fract(expandedValue/256.0)) / 256.0), fract(((expandedValue/65536.0) - fract(expandedValue/65536.0)) / 256.0) );\n\
146 return packedValue;\n\
147 }\n\
148 \n\
149 void main() \n\
150 { \n\
151 vec4 mainTexColor = (polyEnableTexture) ? texture2D(texRenderObject, vtxTexCoord) : vec4(1.0, 1.0, 1.0, 1.0); \n\
152 vec4 newFragColor = mainTexColor * vtxColor; \n\
153 \n\
154 if(polyMode == 1) \n\
155 { \n\
156 newFragColor.rgb = (polyEnableTexture) ? mix(vtxColor.rgb, mainTexColor.rgb, mainTexColor.a) : vtxColor.rgb; \n\
157 newFragColor.a = vtxColor.a; \n\
158 } \n\
159 else if(polyMode == 2) \n\
160 { \n\
161 vec3 toonColor = vec3(texture1D(texToonTable, vtxColor.r).rgb); \n\
162 newFragColor.rgb = (stateToonShadingMode == 0) ? mainTexColor.rgb * toonColor.rgb : min((mainTexColor.rgb * vtxColor.r) + toonColor.rgb, 1.0); \n\
163 } \n\
164 else if(polyMode == 3) \n\
165 { \n\
166 if (polyID != 0) \n\
167 { \n\
168 newFragColor = vtxColor; \n\
169 } \n\
170 } \n\
171 \n\
172 if (newFragColor.a == 0.0 || (stateEnableAlphaTest && newFragColor.a < stateAlphaTestRef)) \n\
173 { \n\
174 discard; \n\
175 } \n\
176 \n\
177 float vertW = (vtxPosition.w == 0.0) ? 0.00000001 : vtxPosition.w; \n\
178 // hack: when using z-depth, drop some LSBs so that the overworld map in Dragon Quest IV shows up correctly\n\
179 float newFragDepth = (stateUseWDepth) ? vtxPosition.w/4096.0 : clamp( (floor((((vtxPosition.z/vertW) * 0.5 + 0.5) * 16777215.0) / 4.0) * 4.0) / 16777215.0, 0.0, 1.0); \n\
180 \n\
181 gl_FragData[0] = newFragColor;\n\
182 gl_FragData[1] = vec4( packVec3FromFloat(newFragDepth), float(polyEnableDepthWrite && (newFragColor.a > 0.999 || polySetNewDepthForTranslucent)));\n\
183 gl_FragData[2] = vec4(float(polyID)/63.0, 0.0, 0.0, float(newFragColor.a > 0.999));\n\
184 gl_FragData[3] = vec4( float(polyEnableFog), 0.0, 0.0, float(newFragColor.a > 0.999 || !polyEnableFog));\n\
185 gl_FragDepth = newFragDepth;\n\
186 } \n\
187 "};
188
189 // Vertex shader for applying edge marking, GLSL 1.00
190 static const char *EdgeMarkVtxShader_100 = {"\
191 attribute vec2 inPosition;\n\
192 attribute vec2 inTexCoord0;\n\
193 uniform vec2 framebufferSize;\n\
194 varying vec2 texCoord[5];\n\
195 \n\
196 void main()\n\
197 {\n\
198 vec2 texInvScale = vec2(1.0/framebufferSize.x, 1.0/framebufferSize.y);\n\
199 \n\
200 texCoord[0] = inTexCoord0; // Center\n\
201 texCoord[1] = inTexCoord0 + (vec2( 1.0, 0.0) * texInvScale); // Right\n\
202 texCoord[2] = inTexCoord0 + (vec2( 0.0, 1.0) * texInvScale); // Down\n\
203 texCoord[3] = inTexCoord0 + (vec2(-1.0, 0.0) * texInvScale); // Left\n\
204 texCoord[4] = inTexCoord0 + (vec2( 0.0,-1.0) * texInvScale); // Up\n\
205 \n\
206 gl_Position = vec4(inPosition, 0.0, 1.0);\n\
207 }\n\
208 "};
209
210 // Fragment shader for applying edge marking, GLSL 1.00
211 static const char *EdgeMarkFragShader_100 = {"\
212 varying vec2 texCoord[5];\n\
213 \n\
214 uniform sampler2D texInFragDepth;\n\
215 uniform sampler2D texInPolyID;\n\
216 uniform vec4 stateEdgeColor[8];\n\
217 \n\
218 float unpackFloatFromVec3(const vec3 value)\n\
219 {\n\
220 const vec3 unpackRatio = vec3(256.0, 65536.0, 16777216.0);\n\
221 return (dot(value, unpackRatio) / 16777215.0);\n\
222 }\n\
223 \n\
224 void main()\n\
225 {\n\
226 int polyID[5];\n\
227 polyID[0] = int((texture2D(texInPolyID, texCoord[0]).r * 63.0) + 0.5);\n\
228 polyID[1] = int((texture2D(texInPolyID, texCoord[1]).r * 63.0) + 0.5);\n\
229 polyID[2] = int((texture2D(texInPolyID, texCoord[2]).r * 63.0) + 0.5);\n\
230 polyID[3] = int((texture2D(texInPolyID, texCoord[3]).r * 63.0) + 0.5);\n\
231 polyID[4] = int((texture2D(texInPolyID, texCoord[4]).r * 63.0) + 0.5);\n\
232 \n\
233 float depth[5];\n\
234 depth[0] = unpackFloatFromVec3(texture2D(texInFragDepth, texCoord[0]).rgb);\n\
235 depth[1] = unpackFloatFromVec3(texture2D(texInFragDepth, texCoord[1]).rgb);\n\
236 depth[2] = unpackFloatFromVec3(texture2D(texInFragDepth, texCoord[2]).rgb);\n\
237 depth[3] = unpackFloatFromVec3(texture2D(texInFragDepth, texCoord[3]).rgb);\n\
238 depth[4] = unpackFloatFromVec3(texture2D(texInFragDepth, texCoord[4]).rgb);\n\
239 \n\
240 vec4 edgeColor = vec4(0.0, 0.0, 0.0, 0.0);\n\
241 \n\
242 for (int i = 1; i < 5; i++)\n\
243 {\n\
244 if (polyID[0] != polyID[i] && depth[0] >= depth[i])\n\
245 {\n\
246 edgeColor = stateEdgeColor[polyID[i]/8];\n\
247 break;\n\
248 }\n\
249 }\n\
250 \n\
251 gl_FragData[0] = edgeColor;\n\
252 }\n\
253 "};
254
255 // Vertex shader for applying fog, GLSL 1.00
256 static const char *FogVtxShader_100 = {"\
257 attribute vec2 inPosition;\n\
258 attribute vec2 inTexCoord0;\n\
259 varying vec2 texCoord;\n\
260 \n\
261 void main() \n\
262 { \n\
263 texCoord = inTexCoord0; \n\
264 gl_Position = vec4(inPosition, 0.0, 1.0);\n\
265 }\n\
266 "};
267
268 // Fragment shader for applying fog, GLSL 1.00
269 static const char *FogFragShader_100 = {"\
270 varying vec2 texCoord;\n\
271 \n\
272 uniform sampler2D texInFragColor;\n\
273 uniform sampler2D texInFragDepth;\n\
274 uniform sampler2D texInFogAttributes;\n\
275 uniform bool stateEnableFogAlphaOnly;\n\
276 uniform vec4 stateFogColor;\n\
277 uniform float stateFogDensity[32];\n\
278 uniform float stateFogOffset;\n\
279 uniform float stateFogStep;\n\
280 \n\
281 float unpackFloatFromVec3(const vec3 value)\n\
282 {\n\
283 const vec3 unpackRatio = vec3(256.0, 65536.0, 16777216.0);\n\
284 return (dot(value, unpackRatio) / 16777215.0);\n\
285 }\n\
286 \n\
287 void main()\n\
288 {\n\
289 vec4 inFragColor = texture2D(texInFragColor, texCoord);\n\
290 vec4 inFogAttributes = texture2D(texInFogAttributes, texCoord);\n\
291 bool polyEnableFog = bool(inFogAttributes.r);\n\
292 vec4 newFoggedColor = inFragColor;\n\
293 \n\
294 if (polyEnableFog)\n\
295 {\n\
296 float inFragDepth = unpackFloatFromVec3(texture2D(texInFragDepth, texCoord).rgb);\n\
297 float fogMixWeight = 0.0;\n\
298 \n\
299 if (inFragDepth <= min(stateFogOffset + stateFogStep, 1.0))\n\
300 {\n\
301 fogMixWeight = stateFogDensity[0];\n\
302 }\n\
303 else if (inFragDepth >= min(stateFogOffset + (stateFogStep*32.0), 1.0))\n\
304 {\n\
305 fogMixWeight = stateFogDensity[31];\n\
306 }\n\
307 else\n\
308 {\n\
309 for (int i = 1; i < 32; i++)\n\
310 {\n\
311 float currentFogStep = min(stateFogOffset + (stateFogStep * float(i+1)), 1.0);\n\
312 if (inFragDepth <= currentFogStep)\n\
313 {\n\
314 float previousFogStep = min(stateFogOffset + (stateFogStep * float(i)), 1.0);\n\
315 fogMixWeight = mix(stateFogDensity[i-1], stateFogDensity[i], (inFragDepth - previousFogStep) / (currentFogStep - previousFogStep));\n\
316 break;\n\
317 }\n\
318 }\n\
319 }\n\
320 \n\
321 newFoggedColor = mix(inFragColor, (stateEnableFogAlphaOnly) ? vec4(inFragColor.rgb, stateFogColor.a) : stateFogColor, fogMixWeight);\n\
322 }\n\
323 \n\
324 gl_FragData[0] = newFoggedColor;\n\
325 }\n\
326 "};
327
328 // Vertex shader for the final framebuffer, GLSL 1.00
329 static const char *FramebufferOutputVtxShader_100 = {"\
330 attribute vec2 inPosition;\n\
331 attribute vec2 inTexCoord0;\n\
332 varying vec2 texCoord;\n\
333 \n\
334 void main()\n\
335 {\n\
336 texCoord = inTexCoord0;\n\
337 gl_Position = vec4(inPosition, 0.0, 1.0);\n\
338 }\n\
339 "};
340
341 // Fragment shader for the final RGBA6665 formatted framebuffer, GLSL 1.00
342 static const char *FramebufferOutputRGBA6665FragShader_100 = {"\
343 varying vec2 texCoord;\n\
344 \n\
345 uniform sampler2D texInFragColor;\n\
346 \n\
347 void main()\n\
348 {\n\
349 // Note that we swap B and R since pixel readbacks are done in BGRA format for fastest\n\
350 // performance. The final color is still in RGBA format.\n\
351 vec4 colorRGBA6665 = texture2D(texInFragColor, texCoord).bgra;\n\
352 colorRGBA6665 = floor((colorRGBA6665 * 255.0) + 0.5);\n\
353 colorRGBA6665.rgb = floor(colorRGBA6665.rgb / 4.0);\n\
354 colorRGBA6665.a = floor(colorRGBA6665.a / 8.0);\n\
355 \n\
356 gl_FragData[0] = (colorRGBA6665 / 255.0);\n\
357 }\n\
358 "};
359
360 // Fragment shader for the final RGBA8888 formatted framebuffer, GLSL 1.00
361 static const char *FramebufferOutputRGBA8888FragShader_100 = {"\
362 varying vec2 texCoord;\n\
363 \n\
364 uniform sampler2D texInFragColor;\n\
365 \n\
366 void main()\n\
367 {\n\
368 gl_FragData[0] = texture2D(texInFragColor, texCoord).bgra;\n\
369 }\n\
370 "};
371
BGRA8888_32_To_RGBA6665_32(const u32 srcPix)372 FORCEINLINE u32 BGRA8888_32_To_RGBA6665_32(const u32 srcPix)
373 {
374 const u32 dstPix = (srcPix >> 2);
375
376 return (dstPix & 0x00003F00) << 16 | // R
377 (dstPix & 0x003F0000) | // G
378 (dstPix & 0x3F000000) >> 16 | // B
379 ((dstPix >> 1) & 0x0000001F); // A
380 }
381
BGRA8888_32Rev_To_RGBA6665_32Rev(const u32 srcPix)382 FORCEINLINE u32 BGRA8888_32Rev_To_RGBA6665_32Rev(const u32 srcPix)
383 {
384 const u32 dstPix = (srcPix >> 2);
385
386 return (dstPix & 0x003F0000) >> 16 | // R
387 (dstPix & 0x00003F00) | // G
388 (dstPix & 0x0000003F) << 16 | // B
389 ((dstPix >> 1) & 0x1F000000); // A
390 }
391
BGRA8888_32_To_RGBA6665_32(const FragmentColor src)392 FORCEINLINE FragmentColor BGRA8888_32_To_RGBA6665_32(const FragmentColor src)
393 {
394 FragmentColor dst = src;
395 dst.r = src.b >> 2;
396 dst.g = src.g >> 2;
397 dst.b = src.r >> 2;
398 dst.a = src.a >> 3;
399
400 return dst;
401 }
402
BGRA8888_32Rev_To_RGBA6665_32Rev(const FragmentColor src)403 FORCEINLINE FragmentColor BGRA8888_32Rev_To_RGBA6665_32Rev(const FragmentColor src)
404 {
405 FragmentColor dst = src;
406 dst.r = src.b >> 2;
407 dst.g = src.g >> 2;
408 dst.b = src.r >> 2;
409 dst.a = src.a >> 3;
410
411 return dst;
412 }
413
BGRA8888_32_To_RGBA5551_16(const FragmentColor src)414 FORCEINLINE u16 BGRA8888_32_To_RGBA5551_16(const FragmentColor src)
415 {
416 return R5G5B5TORGB15( (src.b >> 3),
417 (src.g >> 3),
418 (src.r >> 3)) |
419 ((src.a == 0) ? 0x0000 : 0x8000);
420 }
421
BGRA8888_32Rev_To_RGBA5551_16Rev(const FragmentColor src)422 FORCEINLINE u16 BGRA8888_32Rev_To_RGBA5551_16Rev(const FragmentColor src)
423 {
424 return R5G5B5TORGB15( (src.b >> 3),
425 (src.g >> 3),
426 (src.r >> 3)) |
427 ((src.a == 0) ? 0x0000 : 0x8000);
428 }
429
430 #ifdef ENABLE_SSSE3
431
BGRA8888_32Rev_To_RGBA6665_32Rev(const __m128i src)432 FORCEINLINE __m128i BGRA8888_32Rev_To_RGBA6665_32Rev(const __m128i src)
433 {
434 const __m128i rgb = _mm_srli_epi32(_mm_and_si128(src, _mm_set1_epi32(0x00FCFCFC)), 2);
435 const __m128i a = _mm_srli_epi32(_mm_and_si128(src, _mm_set1_epi32(0xF8000000)), 3);
436
437 return _mm_shuffle_epi8(_mm_or_si128(rgb, a), _mm_set_epi8(15, 12, 13, 14, 11, 8, 9, 10, 7, 4, 5, 6, 3, 0, 1, 2)); // Swizzle RGBA to BGRA
438 }
439
BGRA8888_32Rev_To_RGBA5551_16Rev(const __m128i src)440 FORCEINLINE __m128i BGRA8888_32Rev_To_RGBA5551_16Rev(const __m128i src)
441 {
442 __m128i b = _mm_and_si128(src, _mm_set1_epi32(0x000000F8)); // Read from R
443 b = _mm_slli_epi32(b, 7); // Shift to B
444
445 __m128i g = _mm_and_si128(src, _mm_set1_epi32(0x0000F800)); // Read from G
446 g = _mm_srli_epi32(g, 6); // Shift in G
447
448 __m128i r = _mm_and_si128(src, _mm_set1_epi32(0x00F80000)); // Read from B
449 r = _mm_srli_epi32(r, 19); // Shift to R
450
451 __m128i a = _mm_and_si128(src, _mm_set1_epi32(0xFF000000)); // Read from A
452 a = _mm_cmpeq_epi32(a, _mm_setzero_si128()); // Determine A
453 a = _mm_andnot_si128(a, _mm_set1_epi32(0x00008000)); // Mask to A
454
455 // All the colors are currently placed on 32 bit boundaries, so we need to swizzle them
456 // to the lower 64 bits of our vector before we store them back to memory.
457 // Note: Do not attempt to use packssdw here since packing with the 0x8000 bit set will
458 // result in values of 0x7FFF, which are incorrect values in this case.
459 return _mm_shuffle_epi8(_mm_or_si128(_mm_or_si128(_mm_or_si128(b, g), r), a), _mm_set_epi8(15, 14, 11, 10, 7, 6, 3, 2, 13, 12, 9, 8, 5, 4, 1, 0));
460 }
461
462 #endif
463
IsVersionSupported(unsigned int checkVersionMajor,unsigned int checkVersionMinor,unsigned int checkVersionRevision)464 bool IsVersionSupported(unsigned int checkVersionMajor, unsigned int checkVersionMinor, unsigned int checkVersionRevision)
465 {
466 bool result = false;
467
468 if ( (_OGLDriverVersion.major > checkVersionMajor) ||
469 (_OGLDriverVersion.major >= checkVersionMajor && _OGLDriverVersion.minor > checkVersionMinor) ||
470 (_OGLDriverVersion.major >= checkVersionMajor && _OGLDriverVersion.minor >= checkVersionMinor && _OGLDriverVersion.revision >= checkVersionRevision) )
471 {
472 result = true;
473 }
474
475 return result;
476 }
477
OGLGetDriverVersion(const char * oglVersionString,unsigned int * versionMajor,unsigned int * versionMinor,unsigned int * versionRevision)478 static void OGLGetDriverVersion(const char *oglVersionString,
479 unsigned int *versionMajor,
480 unsigned int *versionMinor,
481 unsigned int *versionRevision)
482 {
483 size_t versionStringLength = 0;
484
485 if (oglVersionString == NULL)
486 return;
487
488 // First, check for the dot in the revision string. There should be at
489 // least one present.
490 const char *versionStrEnd = strstr(oglVersionString, ".");
491 if (versionStrEnd == NULL)
492 return;
493
494 // Next, check for the space before the vendor-specific info (if present).
495 versionStrEnd = strstr(oglVersionString, " ");
496 if (versionStrEnd == NULL)
497 {
498 // If a space was not found, then the vendor-specific info is not present,
499 // and therefore the entire string must be the version number.
500 versionStringLength = strlen(oglVersionString);
501 }
502 else
503 {
504 // If a space was found, then the vendor-specific info is present,
505 // and therefore the version number is everything before the space.
506 versionStringLength = versionStrEnd - oglVersionString;
507 }
508
509 // Copy the version substring and parse it.
510 char *versionSubstring = (char *)malloc(versionStringLength * sizeof(char));
511 strncpy(versionSubstring, oglVersionString, versionStringLength);
512
513 unsigned int major = 0;
514 unsigned int minor = 0;
515 unsigned int revision = 0;
516
517 sscanf(versionSubstring, "%u.%u.%u", &major, &minor, &revision);
518
519 free(versionSubstring);
520 versionSubstring = NULL;
521
522 if (versionMajor != NULL)
523 *versionMajor = major;
524
525 if (versionMinor != NULL)
526 *versionMinor = minor;
527
528 if (versionRevision != NULL)
529 *versionRevision = revision;
530 }
531
texDeleteCallback(TexCacheItem * texItem,void * param1,void * param2)532 void texDeleteCallback(TexCacheItem *texItem, void *param1, void *param2)
533 {
534 OpenGLRenderer *oglRenderer = (OpenGLRenderer *)param1;
535 oglRenderer->DeleteTexture(texItem);
536 }
537
538 template<bool require_profile, bool enable_3_2>
OpenGLRendererCreate()539 static Render3D* OpenGLRendererCreate()
540 {
541 OpenGLRenderer *newRenderer = NULL;
542 Render3DError error = OGLERROR_NOERR;
543
544 if (oglrender_init == NULL)
545 return NULL;
546
547 if (!oglrender_init())
548 return NULL;
549
550 if (!BEGINGL())
551 {
552 INFO("OpenGL<%s,%s>: Could not initialize -- BEGINGL() failed.\n",require_profile?"force":"auto",enable_3_2?"3_2":"old");
553 return NULL;
554 }
555
556 // Get OpenGL info
557 const char *oglVersionString = (const char *)glGetString(GL_VERSION);
558 const char *oglVendorString = (const char *)glGetString(GL_VENDOR);
559 const char *oglRendererString = (const char *)glGetString(GL_RENDERER);
560
561 // Writing to gl_FragDepth causes the driver to fail miserably on systems equipped
562 // with a Intel G965 graphic card. Warn the user and fail gracefully.
563 // http://forums.desmume.org/viewtopic.php?id=9286
564 if(!strcmp(oglVendorString,"Intel") && strstr(oglRendererString,"965"))
565 {
566 INFO("OpenGL: Incompatible graphic card detected. Disabling OpenGL support.\n");
567
568 ENDGL();
569 return newRenderer;
570 }
571
572 // Check the driver's OpenGL version
573 OGLGetDriverVersion(oglVersionString, &_OGLDriverVersion.major, &_OGLDriverVersion.minor, &_OGLDriverVersion.revision);
574
575 if (!IsVersionSupported(OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MAJOR, OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MINOR, OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_REVISION))
576 {
577 INFO("OpenGL: Driver does not support OpenGL v%u.%u.%u or later. Disabling 3D renderer.\n[ Driver Info -\n Version: %s\n Vendor: %s\n Renderer: %s ]\n",
578 OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MAJOR, OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MINOR, OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_REVISION,
579 oglVersionString, oglVendorString, oglRendererString);
580
581 ENDGL();
582 return newRenderer;
583 }
584
585 // Create new OpenGL rendering object
586 if (enable_3_2)
587 {
588 if (OGLLoadEntryPoints_3_2_Func != NULL && OGLCreateRenderer_3_2_Func != NULL)
589 {
590 OGLLoadEntryPoints_3_2_Func();
591 OGLLoadEntryPoints_Legacy(); //zero 04-feb-2013 - this seems to be necessary as well
592 OGLCreateRenderer_3_2_Func(&newRenderer);
593 }
594 else
595 {
596 if(require_profile)
597 {
598 ENDGL();
599 return newRenderer;
600 }
601 }
602 }
603
604 // If the renderer doesn't initialize with OpenGL v3.2 or higher, fall back
605 // to one of the lower versions.
606 if (newRenderer == NULL)
607 {
608 OGLLoadEntryPoints_Legacy();
609
610 if (IsVersionSupported(2, 1, 0))
611 {
612 newRenderer = new OpenGLRenderer_2_1;
613 newRenderer->SetVersion(2, 1, 0);
614 }
615 else if (IsVersionSupported(2, 0, 0))
616 {
617 newRenderer = new OpenGLRenderer_2_0;
618 newRenderer->SetVersion(2, 0, 0);
619 }
620 else if (IsVersionSupported(1, 5, 0))
621 {
622 newRenderer = new OpenGLRenderer_1_5;
623 newRenderer->SetVersion(1, 5, 0);
624 }
625 else if (IsVersionSupported(1, 4, 0))
626 {
627 newRenderer = new OpenGLRenderer_1_4;
628 newRenderer->SetVersion(1, 4, 0);
629 }
630 else if (IsVersionSupported(1, 3, 0))
631 {
632 newRenderer = new OpenGLRenderer_1_3;
633 newRenderer->SetVersion(1, 3, 0);
634 }
635 else if (IsVersionSupported(1, 2, 0))
636 {
637 newRenderer = new OpenGLRenderer_1_2;
638 newRenderer->SetVersion(1, 2, 0);
639 }
640 }
641
642 if (newRenderer == NULL)
643 {
644 INFO("OpenGL: Renderer did not initialize. Disabling 3D renderer.\n[ Driver Info -\n Version: %s\n Vendor: %s\n Renderer: %s ]\n",
645 oglVersionString, oglVendorString, oglRendererString);
646
647 ENDGL();
648 return newRenderer;
649 }
650
651 // Initialize OpenGL extensions
652 error = newRenderer->InitExtensions();
653 if (error != OGLERROR_NOERR)
654 {
655 if ( IsVersionSupported(2, 0, 0) &&
656 (error == OGLERROR_SHADER_CREATE_ERROR ||
657 error == OGLERROR_VERTEX_SHADER_PROGRAM_LOAD_ERROR ||
658 error == OGLERROR_FRAGMENT_SHADER_PROGRAM_LOAD_ERROR) )
659 {
660 INFO("OpenGL: Shaders are not working, even though they should be. Disabling 3D renderer.\n");
661 delete newRenderer;
662 newRenderer = NULL;
663
664 ENDGL();
665 return newRenderer;
666 }
667 else if (IsVersionSupported(3, 0, 0) && error == OGLERROR_FBO_CREATE_ERROR && OGLLoadEntryPoints_3_2_Func != NULL)
668 {
669 INFO("OpenGL: FBOs are not working, even though they should be. Disabling 3D renderer.\n");
670 delete newRenderer;
671 newRenderer = NULL;
672
673 ENDGL();
674 return newRenderer;
675 }
676 }
677
678 ENDGL();
679
680 // Initialization finished -- reset the renderer
681 newRenderer->Reset();
682
683 unsigned int major = 0;
684 unsigned int minor = 0;
685 unsigned int revision = 0;
686 newRenderer->GetVersion(&major, &minor, &revision);
687
688 INFO("OpenGL: Renderer initialized successfully (v%u.%u.%u).\n[ Driver Info -\n Version: %s\n Vendor: %s\n Renderer: %s ]\n",
689 major, minor, revision, oglVersionString, oglVendorString, oglRendererString);
690
691 return newRenderer;
692 }
693
OpenGLRendererDestroy()694 static void OpenGLRendererDestroy()
695 {
696 if(!BEGINGL())
697 return;
698
699 if (CurrentRenderer != BaseRenderer)
700 {
701 OpenGLRenderer *oldRenderer = (OpenGLRenderer *)CurrentRenderer;
702 CurrentRenderer = BaseRenderer;
703 delete oldRenderer;
704 }
705
706 ENDGL();
707 }
708
709 //automatically select 3.2 or old profile depending on whether 3.2 is available
710 GPU3DInterface gpu3Dgl = {
711 "OpenGL",
712 OpenGLRendererCreate<false,true>,
713 OpenGLRendererDestroy
714 };
715
716 //forcibly use old profile
717 GPU3DInterface gpu3DglOld = {
718 "OpenGL Old",
719 OpenGLRendererCreate<true,false>,
720 OpenGLRendererDestroy
721 };
722
723 //forcibly use new profile
724 GPU3DInterface gpu3Dgl_3_2 = {
725 "OpenGL 3.2",
726 OpenGLRendererCreate<true,true>,
727 OpenGLRendererDestroy
728 };
729
OpenGLRenderer()730 OpenGLRenderer::OpenGLRenderer()
731 {
732 _renderID = RENDERID_OPENGL_AUTO;
733 _renderName = "OpenGL";
734 _internalRenderingFormat = NDSColorFormat_BGR888_Rev;
735
736 versionMajor = 0;
737 versionMinor = 0;
738 versionRevision = 0;
739
740 isVBOSupported = false;
741 isPBOSupported = false;
742 isFBOSupported = false;
743 isMultisampledFBOSupported = false;
744 isShaderSupported = false;
745 isVAOSupported = false;
746 willFlipFramebufferOnGPU = false;
747 willConvertFramebufferOnGPU = false;
748
749 // Init OpenGL rendering states
750 ref = new OGLRenderRef;
751 ref->fboRenderID = 0;
752 ref->fboMSIntermediateRenderID = 0;
753 ref->fboPostprocessID = 0;
754 ref->selectedRenderingFBO = 0;
755
756 currTexture = NULL;
757 _mappedFramebuffer = NULL;
758 _pixelReadNeedsFinish = false;
759 _currentPolyIndex = 0;
760 _shadowPolyID.reserve(POLYLIST_SIZE);
761 }
762
~OpenGLRenderer()763 OpenGLRenderer::~OpenGLRenderer()
764 {
765 free_aligned(_framebufferColor);
766
767 // Destroy OpenGL rendering states
768 delete ref;
769 ref = NULL;
770 }
771
IsExtensionPresent(const std::set<std::string> * oglExtensionSet,const std::string extensionName) const772 bool OpenGLRenderer::IsExtensionPresent(const std::set<std::string> *oglExtensionSet, const std::string extensionName) const
773 {
774 if (oglExtensionSet == NULL || oglExtensionSet->size() == 0)
775 return false;
776
777 return (oglExtensionSet->find(extensionName) != oglExtensionSet->end());
778 }
779
ValidateShaderCompile(GLuint theShader) const780 bool OpenGLRenderer::ValidateShaderCompile(GLuint theShader) const
781 {
782 bool isCompileValid = false;
783 GLint status = GL_FALSE;
784
785 glGetShaderiv(theShader, GL_COMPILE_STATUS, &status);
786 if(status == GL_TRUE)
787 {
788 isCompileValid = true;
789 }
790 else
791 {
792 GLint logSize;
793 GLchar *log = NULL;
794
795 glGetShaderiv(theShader, GL_INFO_LOG_LENGTH, &logSize);
796 log = new GLchar[logSize];
797 glGetShaderInfoLog(theShader, logSize, &logSize, log);
798
799 INFO("OpenGL: SEVERE - FAILED TO COMPILE SHADER : %s\n", log);
800 delete[] log;
801 }
802
803 return isCompileValid;
804 }
805
ValidateShaderProgramLink(GLuint theProgram) const806 bool OpenGLRenderer::ValidateShaderProgramLink(GLuint theProgram) const
807 {
808 bool isLinkValid = false;
809 GLint status = GL_FALSE;
810
811 glGetProgramiv(theProgram, GL_LINK_STATUS, &status);
812 if(status == GL_TRUE)
813 {
814 isLinkValid = true;
815 }
816 else
817 {
818 GLint logSize;
819 GLchar *log = NULL;
820
821 glGetProgramiv(theProgram, GL_INFO_LOG_LENGTH, &logSize);
822 log = new GLchar[logSize];
823 glGetProgramInfoLog(theProgram, logSize, &logSize, log);
824
825 INFO("OpenGL: SEVERE - FAILED TO LINK SHADER PROGRAM : %s\n", log);
826 delete[] log;
827 }
828
829 return isLinkValid;
830 }
831
GetVersion(unsigned int * major,unsigned int * minor,unsigned int * revision) const832 void OpenGLRenderer::GetVersion(unsigned int *major, unsigned int *minor, unsigned int *revision) const
833 {
834 *major = this->versionMajor;
835 *minor = this->versionMinor;
836 *revision = this->versionRevision;
837 }
838
SetVersion(unsigned int major,unsigned int minor,unsigned int revision)839 void OpenGLRenderer::SetVersion(unsigned int major, unsigned int minor, unsigned int revision)
840 {
841 this->versionMajor = major;
842 this->versionMinor = minor;
843 this->versionRevision = revision;
844 }
845
_FlushFramebufferConvertOnCPU(const FragmentColor * __restrict srcFramebuffer,FragmentColor * __restrict dstFramebuffer,u16 * __restrict dstRGBA5551)846 Render3DError OpenGLRenderer::_FlushFramebufferConvertOnCPU(const FragmentColor *__restrict srcFramebuffer, FragmentColor *__restrict dstFramebuffer, u16 *__restrict dstRGBA5551)
847 {
848 if ( ((dstFramebuffer == NULL) && (dstRGBA5551 == NULL)) || (srcFramebuffer == NULL) )
849 return RENDER3DERROR_NOERR;
850
851 // Convert from 32-bit BGRA8888 format to 32-bit RGBA6665 reversed format. OpenGL
852 // stores pixels using a flipped Y-coordinate, so this needs to be flipped back
853 // to the DS Y-coordinate.
854
855 size_t i = 0;
856 const size_t pixCount = this->_framebufferWidth;
857
858 #ifdef ENABLE_SSSE3
859 const size_t ssePixCount = pixCount - (pixCount % 4);
860 #endif
861
862 if (this->willFlipFramebufferOnGPU)
863 {
864 if (this->_outputFormat == NDSColorFormat_BGR666_Rev)
865 {
866 if ( (dstFramebuffer != NULL) && (dstRGBA5551 != NULL) )
867 {
868 #ifdef ENABLE_SSSE3
869 for (; i < ssePixCount; i += 4)
870 {
871 const __m128i srcColor = _mm_load_si128((__m128i *)(srcFramebuffer + i));
872 const __m128i color6665 = BGRA8888_32Rev_To_RGBA6665_32Rev(srcColor);
873 const __m128i color5551 = BGRA8888_32Rev_To_RGBA5551_16Rev(srcColor);
874 _mm_store_si128((__m128i *)(dstFramebuffer + i), color6665);
875 _mm_storel_epi64((__m128i *)(dstRGBA5551 + i), color5551);
876 }
877 #endif
878 for (; i < pixCount; i++)
879 {
880 #ifdef MSB_FIRST
881 dstFramebuffer[i] = BGRA8888_32_To_RGBA6665_32(srcFramebuffer[i]);
882 dstRGBA5551[i] = BGRA8888_32_To_RGBA5551_16(srcFramebuffer[i]);
883 #else
884 dstFramebuffer[i] = BGRA8888_32Rev_To_RGBA6665_32Rev(srcFramebuffer[i]);
885 dstRGBA5551[i] = BGRA8888_32Rev_To_RGBA5551_16Rev(srcFramebuffer[i]);
886 #endif
887 }
888 }
889 else if (dstFramebuffer != NULL)
890 {
891 #ifdef ENABLE_SSSE3
892 for (; i < ssePixCount; i += 4)
893 {
894 const __m128i srcColor = _mm_load_si128((__m128i *)(srcFramebuffer + i));
895 const __m128i color6665 = BGRA8888_32Rev_To_RGBA6665_32Rev(srcColor);
896 _mm_store_si128((__m128i *)(dstFramebuffer + i), color6665);
897 }
898 #endif
899 for (; i < pixCount; i++)
900 {
901 #ifdef MSB_FIRST
902 dstFramebuffer[i] = BGRA8888_32_To_RGBA6665_32(srcFramebuffer[i]);
903 #else
904 dstFramebuffer[i] = BGRA8888_32Rev_To_RGBA6665_32Rev(srcFramebuffer[i]);
905 #endif
906 }
907 }
908 else
909 {
910 #ifdef ENABLE_SSSE3
911 for (; i < ssePixCount; i += 4)
912 {
913 const __m128i srcColor = _mm_load_si128((__m128i *)(srcFramebuffer + i));
914 const __m128i color5551 = BGRA8888_32Rev_To_RGBA5551_16Rev(srcColor);
915 _mm_storel_epi64((__m128i *)(dstRGBA5551 + i), color5551);
916 }
917 #endif
918 for (; i < pixCount; i++)
919 {
920 #ifdef MSB_FIRST
921 dstRGBA5551[i] = BGRA8888_32_To_RGBA5551_16(srcFramebuffer[i]);
922 #else
923 dstRGBA5551[i] = BGRA8888_32Rev_To_RGBA5551_16Rev(srcFramebuffer[i]);
924 #endif
925 }
926 }
927 }
928 else if (this->_outputFormat == NDSColorFormat_BGR888_Rev)
929 {
930 if ( (dstFramebuffer != NULL) && (dstRGBA5551 != NULL) )
931 {
932 #ifdef ENABLE_SSSE3
933 for (; i < ssePixCount; i += 4)
934 {
935 const __m128i srcColor = _mm_load_si128((__m128i *)(srcFramebuffer + i));
936 const __m128i color5551 = BGRA8888_32Rev_To_RGBA5551_16Rev(srcColor);
937 _mm_store_si128((__m128i *)(dstFramebuffer + i), srcColor);
938 _mm_storel_epi64((__m128i *)(dstRGBA5551 + i), color5551);
939 }
940 #endif
941 for (; i < pixCount; i++)
942 {
943 dstFramebuffer[i] = srcFramebuffer[i];
944 #ifdef MSB_FIRST
945 dstRGBA5551[i] = BGRA8888_32_To_RGBA5551_16(srcFramebuffer[i]);
946 #else
947 dstRGBA5551[i] = BGRA8888_32Rev_To_RGBA5551_16Rev(srcFramebuffer[i]);
948 #endif
949 }
950 }
951 else if (dstFramebuffer != NULL)
952 {
953 memcpy(dstFramebuffer, srcFramebuffer, this->_framebufferWidth * this->_framebufferHeight * sizeof(FragmentColor));
954 }
955 else
956 {
957 #ifdef ENABLE_SSSE3
958 for (; i < ssePixCount; i += 4)
959 {
960 const __m128i srcColor = _mm_load_si128((__m128i *)(srcFramebuffer + i));
961 const __m128i color5551 = BGRA8888_32Rev_To_RGBA5551_16Rev(srcColor);
962 _mm_storel_epi64((__m128i *)(dstRGBA5551 + i), color5551);
963 }
964 #endif
965 for (; i < pixCount; i++)
966 {
967 #ifdef MSB_FIRST
968 dstRGBA5551[i] = BGRA8888_32_To_RGBA5551_16(srcFramebuffer[i]);
969 #else
970 dstRGBA5551[i] = BGRA8888_32Rev_To_RGBA5551_16Rev(srcFramebuffer[i]);
971 #endif
972 }
973 }
974 }
975 }
976 else // In the case where OpenGL couldn't flip the framebuffer on the GPU, we'll instead need to flip the framebuffer during conversion.
977 {
978 if (this->_outputFormat == NDSColorFormat_BGR666_Rev)
979 {
980 if ( (dstFramebuffer != NULL) && (dstRGBA5551 != NULL) )
981 {
982 for (size_t y = 0, ir = 0, iw = ((this->_framebufferHeight - 1) * this->_framebufferWidth); y < this->_framebufferHeight; y++, iw -= (this->_framebufferWidth * 2))
983 {
984 size_t x = 0;
985 #ifdef ENABLE_SSSE3
986 for (; x < ssePixCount; x += 4, ir += 4, iw += 4)
987 {
988 const __m128i srcColor = _mm_load_si128((__m128i *)(srcFramebuffer + ir));
989 const __m128i color6665 = BGRA8888_32Rev_To_RGBA6665_32Rev(srcColor);
990 const __m128i color5551 = BGRA8888_32Rev_To_RGBA5551_16Rev(srcColor);
991 _mm_store_si128((__m128i *)(dstFramebuffer + iw), color6665);
992 _mm_storel_epi64((__m128i *)(dstFramebuffer + iw), color5551);
993 }
994 #endif
995 for (; x < pixCount; x++, ir++, iw++)
996 {
997 #ifdef MSB_FIRST
998 dstFramebuffer[iw] = BGRA8888_32_To_RGBA6665_32(srcFramebuffer[ir]);
999 dstRGBA5551[iw] = BGRA8888_32_To_RGBA5551_16(srcFramebuffer[ir]);
1000 #else
1001 dstFramebuffer[iw] = BGRA8888_32Rev_To_RGBA6665_32Rev(srcFramebuffer[ir]);
1002 dstRGBA5551[iw] = BGRA8888_32Rev_To_RGBA5551_16Rev(srcFramebuffer[ir]);
1003 #endif
1004 }
1005 }
1006 }
1007 else if (dstFramebuffer != NULL)
1008 {
1009 for (size_t y = 0, ir = 0, iw = ((this->_framebufferHeight - 1) * this->_framebufferWidth); y < this->_framebufferHeight; y++, iw -= (this->_framebufferWidth * 2))
1010 {
1011 size_t x = 0;
1012 #ifdef ENABLE_SSSE3
1013 for (; x < ssePixCount; x += 4, ir += 4, iw += 4)
1014 {
1015 const __m128i srcColor = _mm_load_si128((__m128i *)(srcFramebuffer + ir));
1016 const __m128i color6665 = BGRA8888_32Rev_To_RGBA6665_32Rev(srcColor);
1017 _mm_store_si128((__m128i *)(dstFramebuffer + iw), color6665);
1018 }
1019 #endif
1020 for (; x < pixCount; x++, ir++, iw++)
1021 {
1022 #ifdef MSB_FIRST
1023 dstFramebuffer[iw] = BGRA8888_32_To_RGBA6665_32(srcFramebuffer[ir]);
1024 #else
1025 dstFramebuffer[iw] = BGRA8888_32Rev_To_RGBA6665_32Rev(srcFramebuffer[ir]);
1026 #endif
1027 }
1028 }
1029 }
1030 else
1031 {
1032 for (size_t y = 0, ir = 0, iw = ((this->_framebufferHeight - 1) * this->_framebufferWidth); y < this->_framebufferHeight; y++, iw -= (this->_framebufferWidth * 2))
1033 {
1034 size_t x = 0;
1035 #ifdef ENABLE_SSSE3
1036 for (; x < ssePixCount; x += 4, ir += 4, iw += 4)
1037 {
1038 const __m128i srcColor = _mm_load_si128((__m128i *)(srcFramebuffer + ir));
1039 const __m128i color5551 = BGRA8888_32Rev_To_RGBA5551_16Rev(srcColor);
1040 _mm_storel_epi64((__m128i *)(dstFramebuffer + iw), color5551);
1041 }
1042 #endif
1043 for (; x < pixCount; x++, ir++, iw++)
1044 {
1045 #ifdef MSB_FIRST
1046 dstRGBA5551[iw] = BGRA8888_32_To_RGBA5551_16(srcFramebuffer[ir]);
1047 #else
1048 dstRGBA5551[iw] = BGRA8888_32Rev_To_RGBA5551_16Rev(srcFramebuffer[ir]);
1049 #endif
1050 }
1051 }
1052 }
1053 }
1054 else if (this->_outputFormat == NDSColorFormat_BGR888_Rev)
1055 {
1056 if ( (dstFramebuffer != NULL) && (dstRGBA5551 != NULL) )
1057 {
1058 for (size_t y = 0, ir = 0, iw = ((this->_framebufferHeight - 1) * this->_framebufferWidth); y < this->_framebufferHeight; y++, iw -= (this->_framebufferWidth * 2))
1059 {
1060 size_t x = 0;
1061 #ifdef ENABLE_SSSE3
1062 for (; x < ssePixCount; x += 4, ir += 4, iw += 4)
1063 {
1064 const __m128i srcColor = _mm_load_si128((__m128i *)(srcFramebuffer + ir));
1065 const __m128i color5551 = BGRA8888_32Rev_To_RGBA5551_16Rev(srcColor);
1066 _mm_store_si128((__m128i *)(dstFramebuffer + iw), srcColor);
1067 _mm_storel_epi64((__m128i *)(dstFramebuffer + iw), color5551);
1068 }
1069 #endif
1070 for (; x < pixCount; x++, ir++, iw++)
1071 {
1072 dstFramebuffer[iw] = srcFramebuffer[ir];
1073 #ifdef MSB_FIRST
1074 dstRGBA5551[iw] = BGRA8888_32_To_RGBA5551_16(srcFramebuffer[ir]);
1075 #else
1076 dstRGBA5551[iw] = BGRA8888_32Rev_To_RGBA5551_16Rev(srcFramebuffer[ir]);
1077 #endif
1078 }
1079 }
1080 }
1081 else if (dstFramebuffer != NULL)
1082 {
1083 const size_t lineBytes = this->_framebufferWidth * sizeof(FragmentColor);
1084 const FragmentColor *__restrict srcPtr = srcFramebuffer;
1085 FragmentColor *__restrict dstPtr = dstFramebuffer + ((this->_framebufferHeight - 1) * this->_framebufferWidth);
1086
1087 for (size_t y = 0; y < this->_framebufferHeight; y++)
1088 {
1089 memcpy(dstPtr, srcPtr, lineBytes);
1090 srcPtr += this->_framebufferWidth;
1091 dstPtr -= this->_framebufferWidth;
1092 }
1093 }
1094 else
1095 {
1096 for (size_t y = 0, ir = 0, iw = ((this->_framebufferHeight - 1) * this->_framebufferWidth); y < this->_framebufferHeight; y++, iw -= (this->_framebufferWidth * 2))
1097 {
1098 size_t x = 0;
1099 #ifdef ENABLE_SSSE3
1100 for (; x < ssePixCount; x += 4, ir += 4, iw += 4)
1101 {
1102 const __m128i srcColor = _mm_load_si128((__m128i *)(srcFramebuffer + ir));
1103 const __m128i color5551 = BGRA8888_32Rev_To_RGBA5551_16Rev(srcColor);
1104 _mm_storel_epi64((__m128i *)(dstFramebuffer + iw), color5551);
1105 }
1106 #endif
1107 for (; x < pixCount; x++, ir++, iw++)
1108 {
1109 #ifdef MSB_FIRST
1110 dstRGBA5551[iw] = BGRA8888_32_To_RGBA5551_16(srcFramebuffer[ir]);
1111 #else
1112 dstRGBA5551[iw] = BGRA8888_32Rev_To_RGBA5551_16Rev(srcFramebuffer[ir]);
1113 #endif
1114 }
1115 }
1116 }
1117 }
1118 }
1119
1120 return RENDER3DERROR_NOERR;
1121 }
1122
FlushFramebuffer(const FragmentColor * __restrict srcFramebuffer,FragmentColor * __restrict dstFramebuffer,u16 * __restrict dstRGBA5551)1123 Render3DError OpenGLRenderer::FlushFramebuffer(const FragmentColor *__restrict srcFramebuffer, FragmentColor *__restrict dstFramebuffer, u16 *__restrict dstRGBA5551)
1124 {
1125 if (this->willConvertFramebufferOnGPU)
1126 {
1127 #ifdef ENABLE_SSE2
1128 return Render3D_SSE2::FlushFramebuffer(srcFramebuffer, NULL, dstRGBA5551);
1129 #else
1130 return Render3D::FlushFramebuffer(srcFramebuffer, NULL, dstRGBA5551);
1131 #endif
1132 }
1133
1134 return this->_FlushFramebufferConvertOnCPU(srcFramebuffer, dstFramebuffer, dstRGBA5551);
1135 }
1136
GetFramebuffer()1137 FragmentColor* OpenGLRenderer::GetFramebuffer()
1138 {
1139 return (this->willConvertFramebufferOnGPU) ? this->_mappedFramebuffer : GPU->GetEngineMain()->Get3DFramebufferRGBA6665();
1140 }
1141
~OpenGLRenderer_1_2()1142 OpenGLRenderer_1_2::~OpenGLRenderer_1_2()
1143 {
1144 glFinish();
1145
1146 _pixelReadNeedsFinish = false;
1147
1148 delete[] ref->color4fBuffer;
1149 ref->color4fBuffer = NULL;
1150
1151 delete[] ref->vertIndexBuffer;
1152 ref->vertIndexBuffer = NULL;
1153
1154 DestroyGeometryProgram();
1155 DestroyPostprocessingPrograms();
1156 DestroyVAOs();
1157 DestroyVBOs();
1158 DestroyPBOs();
1159 DestroyFBOs();
1160 DestroyMultisampledFBO();
1161
1162 // Kill the texture cache now before all of our texture IDs disappear.
1163 TexCache_Reset();
1164
1165 while(!ref->freeTextureIDs.empty())
1166 {
1167 GLuint temp = ref->freeTextureIDs.front();
1168 ref->freeTextureIDs.pop();
1169 glDeleteTextures(1, &temp);
1170 }
1171
1172 glFinish();
1173 }
1174
InitExtensions()1175 Render3DError OpenGLRenderer_1_2::InitExtensions()
1176 {
1177 Render3DError error = OGLERROR_NOERR;
1178
1179 // Get OpenGL extensions
1180 std::set<std::string> oglExtensionSet;
1181 this->GetExtensionSet(&oglExtensionSet);
1182
1183 // Initialize OpenGL
1184 this->InitTables();
1185
1186 this->isShaderSupported = this->IsExtensionPresent(&oglExtensionSet, "GL_ARB_shader_objects") &&
1187 this->IsExtensionPresent(&oglExtensionSet, "GL_ARB_vertex_shader") &&
1188 this->IsExtensionPresent(&oglExtensionSet, "GL_ARB_fragment_shader") &&
1189 this->IsExtensionPresent(&oglExtensionSet, "GL_ARB_vertex_program");
1190 if (this->isShaderSupported)
1191 {
1192 std::string vertexShaderProgram;
1193 std::string fragmentShaderProgram;
1194
1195 error = this->LoadGeometryShaders(vertexShaderProgram, fragmentShaderProgram);
1196 if (error == OGLERROR_NOERR)
1197 {
1198 error = this->InitGeometryProgram(vertexShaderProgram, fragmentShaderProgram);
1199 if (error == OGLERROR_NOERR)
1200 {
1201 std::string edgeMarkVtxShaderString = std::string(EdgeMarkVtxShader_100);
1202 std::string edgeMarkFragShaderString = std::string(EdgeMarkFragShader_100);
1203 std::string fogVtxShaderString = std::string(FogVtxShader_100);
1204 std::string fogFragShaderString = std::string(FogFragShader_100);
1205 std::string framebufferOutputVtxShaderString = std::string(FramebufferOutputVtxShader_100);
1206 std::string framebufferOutputRGBA6665FragShaderString = std::string(FramebufferOutputRGBA6665FragShader_100);
1207 std::string framebufferOutputRGBA8888FragShaderString = std::string(FramebufferOutputRGBA8888FragShader_100);
1208 error = this->InitPostprocessingPrograms(edgeMarkVtxShaderString,
1209 edgeMarkFragShaderString,
1210 fogVtxShaderString,
1211 fogFragShaderString,
1212 framebufferOutputVtxShaderString,
1213 framebufferOutputRGBA6665FragShaderString,
1214 framebufferOutputRGBA8888FragShaderString);
1215 if (error != OGLERROR_NOERR)
1216 {
1217 INFO("OpenGL: Edge mark and fog require OpenGL v2.0 or later. These features will be disabled.\n");
1218 }
1219 }
1220 else
1221 {
1222 this->isShaderSupported = false;
1223 }
1224 }
1225 else
1226 {
1227 this->isShaderSupported = false;
1228 }
1229 }
1230 else
1231 {
1232 INFO("OpenGL: Shaders are unsupported. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n");
1233 }
1234
1235 this->isVBOSupported = this->IsExtensionPresent(&oglExtensionSet, "GL_ARB_vertex_buffer_object");
1236 if (this->isVBOSupported)
1237 {
1238 this->CreateVBOs();
1239 }
1240
1241 this->isPBOSupported = this->isVBOSupported &&
1242 (this->IsExtensionPresent(&oglExtensionSet, "GL_ARB_pixel_buffer_object") ||
1243 this->IsExtensionPresent(&oglExtensionSet, "GL_EXT_pixel_buffer_object"));
1244 if (this->isPBOSupported)
1245 {
1246 this->CreatePBOs();
1247 }
1248
1249 this->isVAOSupported = this->isShaderSupported &&
1250 this->isVBOSupported &&
1251 (this->IsExtensionPresent(&oglExtensionSet, "GL_ARB_vertex_array_object") ||
1252 this->IsExtensionPresent(&oglExtensionSet, "GL_APPLE_vertex_array_object"));
1253 if (this->isVAOSupported)
1254 {
1255 this->CreateVAOs();
1256 }
1257
1258 // Don't use ARB versions since we're using the EXT versions for backwards compatibility.
1259 this->isFBOSupported = this->IsExtensionPresent(&oglExtensionSet, "GL_EXT_framebuffer_object") &&
1260 this->IsExtensionPresent(&oglExtensionSet, "GL_EXT_framebuffer_blit") &&
1261 this->IsExtensionPresent(&oglExtensionSet, "GL_EXT_packed_depth_stencil");
1262 if (this->isFBOSupported)
1263 {
1264 this->willFlipFramebufferOnGPU = true;
1265 this->willConvertFramebufferOnGPU = (this->isShaderSupported && this->isVAOSupported && this->isPBOSupported && this->isFBOSupported);
1266
1267 error = this->CreateFBOs();
1268 if (error != OGLERROR_NOERR)
1269 {
1270 this->isFBOSupported = false;
1271 }
1272 }
1273 else
1274 {
1275 INFO("OpenGL: FBOs are unsupported. Some emulation features will be disabled.\n");
1276 }
1277
1278 // Set these again after FBO creation just in case FBO creation fails.
1279 this->willFlipFramebufferOnGPU = this->isFBOSupported;
1280 this->willConvertFramebufferOnGPU = (this->isShaderSupported && this->isVAOSupported && this->isPBOSupported && this->isFBOSupported);
1281
1282 // Don't use ARB versions since we're using the EXT versions for backwards compatibility.
1283 this->isMultisampledFBOSupported = this->isFBOSupported &&
1284 this->IsExtensionPresent(&oglExtensionSet, "GL_EXT_framebuffer_multisample");
1285 if (this->isMultisampledFBOSupported)
1286 {
1287 error = this->CreateMultisampledFBO();
1288 if (error != OGLERROR_NOERR)
1289 {
1290 this->isMultisampledFBOSupported = false;
1291 }
1292 }
1293 else
1294 {
1295 INFO("OpenGL: Multisampled FBOs are unsupported. Multisample antialiasing will be disabled.\n");
1296 }
1297
1298 this->InitTextures();
1299 this->InitFinalRenderStates(&oglExtensionSet); // This must be done last
1300
1301 return OGLERROR_NOERR;
1302 }
1303
CreateVBOs()1304 Render3DError OpenGLRenderer_1_2::CreateVBOs()
1305 {
1306 OGLRenderRef &OGLRef = *this->ref;
1307
1308 glGenBuffersARB(1, &OGLRef.vboGeometryVtxID);
1309 glGenBuffersARB(1, &OGLRef.iboGeometryIndexID);
1310 glGenBuffersARB(1, &OGLRef.vboPostprocessVtxID);
1311 glGenBuffersARB(1, &OGLRef.iboPostprocessIndexID);
1312
1313 glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboGeometryVtxID);
1314 glBufferDataARB(GL_ARRAY_BUFFER_ARB, VERTLIST_SIZE * sizeof(VERT), NULL, GL_STREAM_DRAW_ARB);
1315 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, OGLRef.iboGeometryIndexID);
1316 glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, OGLRENDER_VERT_INDEX_BUFFER_COUNT * sizeof(GLushort), NULL, GL_STREAM_DRAW_ARB);
1317
1318 glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboPostprocessVtxID);
1319 glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(PostprocessVtxBuffer), PostprocessVtxBuffer, GL_STATIC_DRAW_ARB);
1320 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, OGLRef.iboPostprocessIndexID);
1321 glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, sizeof(PostprocessElementBuffer), PostprocessElementBuffer, GL_STATIC_DRAW_ARB);
1322
1323 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1324 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1325
1326 return OGLERROR_NOERR;
1327 }
1328
DestroyVBOs()1329 void OpenGLRenderer_1_2::DestroyVBOs()
1330 {
1331 if (!this->isVBOSupported)
1332 return;
1333
1334 OGLRenderRef &OGLRef = *this->ref;
1335
1336 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1337 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1338
1339 glDeleteBuffersARB(1, &OGLRef.vboGeometryVtxID);
1340 glDeleteBuffersARB(1, &OGLRef.iboGeometryIndexID);
1341 glDeleteBuffersARB(1, &OGLRef.vboPostprocessVtxID);
1342 glDeleteBuffersARB(1, &OGLRef.iboPostprocessIndexID);
1343
1344 this->isVBOSupported = false;
1345 }
1346
CreatePBOs()1347 Render3DError OpenGLRenderer_1_2::CreatePBOs()
1348 {
1349 OGLRenderRef &OGLRef = *this->ref;
1350
1351 glGenBuffersARB(1, &OGLRef.pboRenderDataID);
1352 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, OGLRef.pboRenderDataID);
1353 glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, this->_framebufferColorSizeBytes, NULL, GL_STREAM_READ_ARB);
1354
1355 return OGLERROR_NOERR;
1356 }
1357
DestroyPBOs()1358 void OpenGLRenderer_1_2::DestroyPBOs()
1359 {
1360 if (!this->isPBOSupported)
1361 {
1362 return;
1363 }
1364
1365 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
1366 glDeleteBuffersARB(1, &this->ref->pboRenderDataID);
1367
1368 this->isPBOSupported = false;
1369 }
1370
LoadGeometryShaders(std::string & outVertexShaderProgram,std::string & outFragmentShaderProgram)1371 Render3DError OpenGLRenderer_1_2::LoadGeometryShaders(std::string &outVertexShaderProgram, std::string &outFragmentShaderProgram)
1372 {
1373 outVertexShaderProgram.clear();
1374 outFragmentShaderProgram.clear();
1375
1376 outVertexShaderProgram += std::string(vertexShader_100);
1377 outFragmentShaderProgram += std::string(fragmentShader_100);
1378
1379 return OGLERROR_NOERR;
1380 }
1381
InitGeometryProgramBindings()1382 Render3DError OpenGLRenderer_1_2::InitGeometryProgramBindings()
1383 {
1384 OGLRenderRef &OGLRef = *this->ref;
1385
1386 glBindAttribLocation(OGLRef.programGeometryID, OGLVertexAttributeID_Position, "inPosition");
1387 glBindAttribLocation(OGLRef.programGeometryID, OGLVertexAttributeID_TexCoord0, "inTexCoord0");
1388 glBindAttribLocation(OGLRef.programGeometryID, OGLVertexAttributeID_Color, "inColor");
1389
1390 return OGLERROR_NOERR;
1391 }
1392
InitGeometryProgramShaderLocations()1393 Render3DError OpenGLRenderer_1_2::InitGeometryProgramShaderLocations()
1394 {
1395 OGLRenderRef &OGLRef = *this->ref;
1396
1397 glUseProgram(OGLRef.programGeometryID);
1398
1399 const GLint uniformTexRenderObject = glGetUniformLocation(OGLRef.programGeometryID, "texRenderObject");
1400 const GLint uniformTexToonTable = glGetUniformLocation(OGLRef.programGeometryID, "texToonTable");
1401 glUniform1i(uniformTexRenderObject, 0);
1402 glUniform1i(uniformTexToonTable, OGLTextureUnitID_ToonTable);
1403
1404 OGLRef.uniformStateToonShadingMode = glGetUniformLocation(OGLRef.programGeometryID, "stateToonShadingMode");
1405 OGLRef.uniformStateEnableAlphaTest = glGetUniformLocation(OGLRef.programGeometryID, "stateEnableAlphaTest");
1406 OGLRef.uniformStateEnableAntialiasing = glGetUniformLocation(OGLRef.programGeometryID, "stateEnableAntialiasing");
1407 OGLRef.uniformStateEnableEdgeMarking = glGetUniformLocation(OGLRef.programGeometryID, "stateEnableEdgeMarking");
1408 OGLRef.uniformStateUseWDepth = glGetUniformLocation(OGLRef.programGeometryID, "stateUseWDepth");
1409 OGLRef.uniformStateAlphaTestRef = glGetUniformLocation(OGLRef.programGeometryID, "stateAlphaTestRef");
1410
1411 OGLRef.uniformPolyTexScale = glGetUniformLocation(OGLRef.programGeometryID, "polyTexScale");
1412 OGLRef.uniformPolyMode = glGetUniformLocation(OGLRef.programGeometryID, "polyMode");
1413 OGLRef.uniformPolyEnableDepthWrite = glGetUniformLocation(OGLRef.programGeometryID, "polyEnableDepthWrite");
1414 OGLRef.uniformPolySetNewDepthForTranslucent = glGetUniformLocation(OGLRef.programGeometryID, "polySetNewDepthForTranslucent");
1415 OGLRef.uniformPolyAlpha = glGetUniformLocation(OGLRef.programGeometryID, "polyAlpha");
1416 OGLRef.uniformPolyID = glGetUniformLocation(OGLRef.programGeometryID, "polyID");
1417
1418 OGLRef.uniformPolyEnableTexture = glGetUniformLocation(OGLRef.programGeometryID, "polyEnableTexture");
1419 OGLRef.uniformPolyEnableFog = glGetUniformLocation(OGLRef.programGeometryID, "polyEnableFog");
1420
1421 return OGLERROR_NOERR;
1422 }
1423
InitGeometryProgram(const std::string & vertexShaderProgram,const std::string & fragmentShaderProgram)1424 Render3DError OpenGLRenderer_1_2::InitGeometryProgram(const std::string &vertexShaderProgram, const std::string &fragmentShaderProgram)
1425 {
1426 OGLRenderRef &OGLRef = *this->ref;
1427
1428 OGLRef.vertexGeometryShaderID = glCreateShader(GL_VERTEX_SHADER);
1429 if(!OGLRef.vertexGeometryShaderID)
1430 {
1431 INFO("OpenGL: Failed to create the vertex shader. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n");
1432 return OGLERROR_SHADER_CREATE_ERROR;
1433 }
1434
1435 const char *vertexShaderProgramChar = vertexShaderProgram.c_str();
1436 glShaderSource(OGLRef.vertexGeometryShaderID, 1, (const GLchar **)&vertexShaderProgramChar, NULL);
1437 glCompileShader(OGLRef.vertexGeometryShaderID);
1438 if (!this->ValidateShaderCompile(OGLRef.vertexGeometryShaderID))
1439 {
1440 glDeleteShader(OGLRef.vertexGeometryShaderID);
1441 INFO("OpenGL: Failed to compile the vertex shader. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n");
1442 return OGLERROR_SHADER_CREATE_ERROR;
1443 }
1444
1445 OGLRef.fragmentGeometryShaderID = glCreateShader(GL_FRAGMENT_SHADER);
1446 if(!OGLRef.fragmentGeometryShaderID)
1447 {
1448 glDeleteShader(OGLRef.vertexGeometryShaderID);
1449 INFO("OpenGL: Failed to create the fragment shader. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n");
1450 return OGLERROR_SHADER_CREATE_ERROR;
1451 }
1452
1453 const char *fragmentShaderProgramChar = fragmentShaderProgram.c_str();
1454 glShaderSource(OGLRef.fragmentGeometryShaderID, 1, (const GLchar **)&fragmentShaderProgramChar, NULL);
1455 glCompileShader(OGLRef.fragmentGeometryShaderID);
1456 if (!this->ValidateShaderCompile(OGLRef.fragmentGeometryShaderID))
1457 {
1458 glDeleteShader(OGLRef.vertexGeometryShaderID);
1459 glDeleteShader(OGLRef.fragmentGeometryShaderID);
1460 INFO("OpenGL: Failed to compile the fragment shader. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n");
1461 return OGLERROR_SHADER_CREATE_ERROR;
1462 }
1463
1464 OGLRef.programGeometryID = glCreateProgram();
1465 if(!OGLRef.programGeometryID)
1466 {
1467 glDeleteShader(OGLRef.vertexGeometryShaderID);
1468 glDeleteShader(OGLRef.fragmentGeometryShaderID);
1469 INFO("OpenGL: Failed to create the shader program. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n");
1470 return OGLERROR_SHADER_CREATE_ERROR;
1471 }
1472
1473 glAttachShader(OGLRef.programGeometryID, OGLRef.vertexGeometryShaderID);
1474 glAttachShader(OGLRef.programGeometryID, OGLRef.fragmentGeometryShaderID);
1475
1476 this->InitGeometryProgramBindings();
1477
1478 glLinkProgram(OGLRef.programGeometryID);
1479 if (!this->ValidateShaderProgramLink(OGLRef.programGeometryID))
1480 {
1481 glDetachShader(OGLRef.programGeometryID, OGLRef.vertexGeometryShaderID);
1482 glDetachShader(OGLRef.programGeometryID, OGLRef.fragmentGeometryShaderID);
1483 glDeleteProgram(OGLRef.programGeometryID);
1484 glDeleteShader(OGLRef.vertexGeometryShaderID);
1485 glDeleteShader(OGLRef.fragmentGeometryShaderID);
1486 INFO("OpenGL: Failed to link the shader program. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n");
1487 return OGLERROR_SHADER_CREATE_ERROR;
1488 }
1489
1490 glValidateProgram(OGLRef.programGeometryID);
1491
1492 this->InitGeometryProgramShaderLocations();
1493
1494 INFO("OpenGL: Successfully created shaders.\n");
1495
1496 this->CreateToonTable();
1497
1498 return OGLERROR_NOERR;
1499 }
1500
DestroyGeometryProgram()1501 void OpenGLRenderer_1_2::DestroyGeometryProgram()
1502 {
1503 if(!this->isShaderSupported)
1504 {
1505 return;
1506 }
1507
1508 OGLRenderRef &OGLRef = *this->ref;
1509
1510 glUseProgram(0);
1511
1512 glDetachShader(OGLRef.programGeometryID, OGLRef.vertexGeometryShaderID);
1513 glDetachShader(OGLRef.programGeometryID, OGLRef.fragmentGeometryShaderID);
1514
1515 glDeleteProgram(OGLRef.programGeometryID);
1516 glDeleteShader(OGLRef.vertexGeometryShaderID);
1517 glDeleteShader(OGLRef.fragmentGeometryShaderID);
1518
1519 this->DestroyToonTable();
1520
1521 this->isShaderSupported = false;
1522 }
1523
CreateVAOs()1524 Render3DError OpenGLRenderer_1_2::CreateVAOs()
1525 {
1526 OGLRenderRef &OGLRef = *this->ref;
1527
1528 glGenVertexArrays(1, &OGLRef.vaoGeometryStatesID);
1529 glGenVertexArrays(1, &OGLRef.vaoPostprocessStatesID);
1530
1531 glBindVertexArray(OGLRef.vaoGeometryStatesID);
1532 glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboGeometryVtxID);
1533 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, OGLRef.iboGeometryIndexID);
1534
1535 glEnableVertexAttribArray(OGLVertexAttributeID_Position);
1536 glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0);
1537 glEnableVertexAttribArray(OGLVertexAttributeID_Color);
1538 glVertexAttribPointer(OGLVertexAttributeID_Position, 4, GL_FLOAT, GL_FALSE, sizeof(VERT), (const GLvoid *)offsetof(VERT, coord));
1539 glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(VERT), (const GLvoid *)offsetof(VERT, texcoord));
1540 glVertexAttribPointer(OGLVertexAttributeID_Color, 3, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(VERT), (const GLvoid *)offsetof(VERT, color));
1541
1542 glBindVertexArray(0);
1543
1544 glBindVertexArray(OGLRef.vaoPostprocessStatesID);
1545 glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboPostprocessVtxID);
1546 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, OGLRef.iboPostprocessIndexID);
1547
1548 glEnableVertexAttribArray(OGLVertexAttributeID_Position);
1549 glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0);
1550 glVertexAttribPointer(OGLVertexAttributeID_Position, 2, GL_FLOAT, GL_FALSE, 0, 0);
1551 glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)(sizeof(GLfloat) * 8));
1552
1553 glBindVertexArray(0);
1554
1555 return OGLERROR_NOERR;
1556 }
1557
DestroyVAOs()1558 void OpenGLRenderer_1_2::DestroyVAOs()
1559 {
1560 OGLRenderRef &OGLRef = *this->ref;
1561
1562 if (!this->isVAOSupported)
1563 {
1564 return;
1565 }
1566
1567 glBindVertexArray(0);
1568 glDeleteVertexArrays(1, &OGLRef.vaoGeometryStatesID);
1569 glDeleteVertexArrays(1, &OGLRef.vaoPostprocessStatesID);
1570
1571 this->isVAOSupported = false;
1572 }
1573
CreateFBOs()1574 Render3DError OpenGLRenderer_1_2::CreateFBOs()
1575 {
1576 OGLRenderRef &OGLRef = *this->ref;
1577
1578 // Set up FBO render targets
1579 glGenTextures(1, &OGLRef.texCIColorID);
1580 glGenTextures(1, &OGLRef.texCIDepthID);
1581 glGenTextures(1, &OGLRef.texCIFogAttrID);
1582 glGenTextures(1, &OGLRef.texCIPolyID);
1583 glGenTextures(1, &OGLRef.texCIDepthStencilID);
1584
1585 glGenTextures(1, &OGLRef.texFinalColorID);
1586 glGenTextures(1, &OGLRef.texGColorID);
1587 glGenTextures(1, &OGLRef.texGDepthID);
1588 glGenTextures(1, &OGLRef.texGFogAttrID);
1589 glGenTextures(1, &OGLRef.texGPolyID);
1590 glGenTextures(1, &OGLRef.texGDepthStencilID);
1591 glGenTextures(1, &OGLRef.texPostprocessFogID);
1592
1593 if (this->willFlipFramebufferOnGPU)
1594 {
1595 glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FinalColor);
1596 glBindTexture(GL_TEXTURE_2D, OGLRef.texFinalColorID);
1597 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1598 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1599 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1600 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1601 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
1602 }
1603
1604 glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GColor);
1605 glBindTexture(GL_TEXTURE_2D, OGLRef.texGDepthStencilID);
1606 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1607 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1608 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1609 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1610 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
1611 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8_EXT, this->_framebufferWidth, this->_framebufferHeight, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL);
1612
1613 glBindTexture(GL_TEXTURE_2D, OGLRef.texGColorID);
1614 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1615 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1616 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1617 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1618 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
1619
1620 glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GDepth);
1621 glBindTexture(GL_TEXTURE_2D, OGLRef.texGDepthID);
1622 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1623 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1624 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1625 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1626 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
1627
1628 glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GPolyID);
1629 glBindTexture(GL_TEXTURE_2D, OGLRef.texGPolyID);
1630 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1631 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1632 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1633 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1634 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
1635
1636 glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FogAttr);
1637 glBindTexture(GL_TEXTURE_2D, OGLRef.texGFogAttrID);
1638 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1639 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1640 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1641 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1642 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
1643
1644 glActiveTexture(GL_TEXTURE0);
1645
1646 glBindTexture(GL_TEXTURE_2D, OGLRef.texPostprocessFogID);
1647 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1648 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1649 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1650 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1651 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
1652
1653 glBindTexture(GL_TEXTURE_2D, OGLRef.texCIColorID);
1654 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1655 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1656 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1657 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1658 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
1659
1660 glBindTexture(GL_TEXTURE_2D, OGLRef.texCIDepthStencilID);
1661 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1662 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1663 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1664 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1665 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
1666 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8_EXT, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL);
1667
1668 glBindTexture(GL_TEXTURE_2D, OGLRef.texCIDepthID);
1669 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1670 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1671 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1672 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1673 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
1674
1675 glBindTexture(GL_TEXTURE_2D, OGLRef.texCIPolyID);
1676 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1677 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1678 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1679 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1680 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
1681
1682 glBindTexture(GL_TEXTURE_2D, OGLRef.texCIFogAttrID);
1683 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1684 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1685 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1686 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1687 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
1688
1689 glBindTexture(GL_TEXTURE_2D, 0);
1690
1691 // Set up RBOs
1692 if (this->willConvertFramebufferOnGPU)
1693 {
1694 glGenRenderbuffersEXT(1, &OGLRef.rboFramebufferRGBA6665ID);
1695 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboFramebufferRGBA6665ID);
1696 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight);
1697 }
1698
1699 // Set up FBOs
1700 glGenFramebuffersEXT(1, &OGLRef.fboClearImageID);
1701 glGenFramebuffersEXT(1, &OGLRef.fboRenderID);
1702 glGenFramebuffersEXT(1, &OGLRef.fboPostprocessID);
1703
1704 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboClearImageID);
1705 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, OGLRef.texCIColorID, 0);
1706 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, OGLRef.texCIDepthID, 0);
1707 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT2_EXT, GL_TEXTURE_2D, OGLRef.texCIPolyID, 0);
1708 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT3_EXT, GL_TEXTURE_2D, OGLRef.texCIFogAttrID, 0);
1709 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, OGLRef.texCIDepthStencilID, 0);
1710 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, OGLRef.texCIDepthStencilID, 0);
1711
1712 if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
1713 {
1714 INFO("OpenGL: Failed to created FBOs. Some emulation features will be disabled.\n");
1715
1716 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1717 glDeleteFramebuffersEXT(1, &OGLRef.fboClearImageID);
1718 glDeleteFramebuffersEXT(1, &OGLRef.fboRenderID);
1719 glDeleteFramebuffersEXT(1, &OGLRef.fboPostprocessID);
1720 glDeleteTextures(1, &OGLRef.texCIColorID);
1721 glDeleteTextures(1, &OGLRef.texCIDepthID);
1722 glDeleteTextures(1, &OGLRef.texCIFogAttrID);
1723 glDeleteTextures(1, &OGLRef.texCIPolyID);
1724 glDeleteTextures(1, &OGLRef.texCIDepthStencilID);
1725 glDeleteTextures(1, &OGLRef.texGColorID);
1726 glDeleteTextures(1, &OGLRef.texGDepthID);
1727 glDeleteTextures(1, &OGLRef.texGPolyID);
1728 glDeleteTextures(1, &OGLRef.texGFogAttrID);
1729 glDeleteTextures(1, &OGLRef.texGDepthStencilID);
1730 glDeleteTextures(1, &OGLRef.texPostprocessFogID);
1731 glDeleteTextures(1, &OGLRef.texFinalColorID);
1732 glDeleteRenderbuffersEXT(1, &OGLRef.rboFramebufferRGBA6665ID);
1733
1734 OGLRef.fboClearImageID = 0;
1735 OGLRef.fboRenderID = 0;
1736 OGLRef.fboPostprocessID = 0;
1737
1738 this->isFBOSupported = false;
1739 return OGLERROR_FBO_CREATE_ERROR;
1740 }
1741
1742 glDrawBuffers(4, RenderDrawList);
1743 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
1744
1745 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboRenderID);
1746 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, OGLRef.texGColorID, 0);
1747 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, OGLRef.texGDepthID, 0);
1748 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT2_EXT, GL_TEXTURE_2D, OGLRef.texGPolyID, 0);
1749 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT3_EXT, GL_TEXTURE_2D, OGLRef.texGFogAttrID, 0);
1750 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, OGLRef.texGDepthStencilID, 0);
1751 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, OGLRef.texGDepthStencilID, 0);
1752
1753 if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
1754 {
1755 INFO("OpenGL: Failed to created FBOs. Some emulation features will be disabled.\n");
1756
1757 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1758 glDeleteFramebuffersEXT(1, &OGLRef.fboClearImageID);
1759 glDeleteFramebuffersEXT(1, &OGLRef.fboRenderID);
1760 glDeleteFramebuffersEXT(1, &OGLRef.fboPostprocessID);
1761 glDeleteTextures(1, &OGLRef.texCIColorID);
1762 glDeleteTextures(1, &OGLRef.texCIDepthID);
1763 glDeleteTextures(1, &OGLRef.texCIFogAttrID);
1764 glDeleteTextures(1, &OGLRef.texCIPolyID);
1765 glDeleteTextures(1, &OGLRef.texCIDepthStencilID);
1766 glDeleteTextures(1, &OGLRef.texGColorID);
1767 glDeleteTextures(1, &OGLRef.texGDepthID);
1768 glDeleteTextures(1, &OGLRef.texGPolyID);
1769 glDeleteTextures(1, &OGLRef.texGFogAttrID);
1770 glDeleteTextures(1, &OGLRef.texGDepthStencilID);
1771 glDeleteTextures(1, &OGLRef.texPostprocessFogID);
1772 glDeleteTextures(1, &OGLRef.texFinalColorID);
1773 glDeleteRenderbuffersEXT(1, &OGLRef.rboFramebufferRGBA6665ID);
1774
1775 OGLRef.fboClearImageID = 0;
1776 OGLRef.fboRenderID = 0;
1777 OGLRef.fboPostprocessID = 0;
1778
1779 this->isFBOSupported = false;
1780 return OGLERROR_FBO_CREATE_ERROR;
1781 }
1782
1783 glDrawBuffers(4, RenderDrawList);
1784 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
1785
1786 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboPostprocessID);
1787 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, OGLRef.texPostprocessFogID, 0);
1788
1789 if (this->willFlipFramebufferOnGPU)
1790 {
1791 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, OGLRef.texFinalColorID, 0);
1792 }
1793
1794 if (this->willConvertFramebufferOnGPU)
1795 {
1796 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT2_EXT, GL_RENDERBUFFER_EXT, OGLRef.rboFramebufferRGBA6665ID);
1797 }
1798
1799 if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
1800 {
1801 INFO("OpenGL: Failed to created FBOs. Some emulation features will be disabled.\n");
1802
1803 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1804 glDeleteFramebuffersEXT(1, &OGLRef.fboClearImageID);
1805 glDeleteFramebuffersEXT(1, &OGLRef.fboRenderID);
1806 glDeleteFramebuffersEXT(1, &OGLRef.fboPostprocessID);
1807 glDeleteTextures(1, &OGLRef.texCIColorID);
1808 glDeleteTextures(1, &OGLRef.texCIDepthID);
1809 glDeleteTextures(1, &OGLRef.texCIFogAttrID);
1810 glDeleteTextures(1, &OGLRef.texCIPolyID);
1811 glDeleteTextures(1, &OGLRef.texCIDepthStencilID);
1812 glDeleteTextures(1, &OGLRef.texGColorID);
1813 glDeleteTextures(1, &OGLRef.texGDepthID);
1814 glDeleteTextures(1, &OGLRef.texGPolyID);
1815 glDeleteTextures(1, &OGLRef.texGFogAttrID);
1816 glDeleteTextures(1, &OGLRef.texGDepthStencilID);
1817 glDeleteTextures(1, &OGLRef.texPostprocessFogID);
1818 glDeleteTextures(1, &OGLRef.texFinalColorID);
1819 glDeleteRenderbuffersEXT(1, &OGLRef.rboFramebufferRGBA6665ID);
1820
1821 OGLRef.fboClearImageID = 0;
1822 OGLRef.fboRenderID = 0;
1823 OGLRef.fboPostprocessID = 0;
1824
1825 this->isFBOSupported = false;
1826 return OGLERROR_FBO_CREATE_ERROR;
1827 }
1828
1829 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
1830 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
1831
1832 OGLRef.selectedRenderingFBO = OGLRef.fboRenderID;
1833 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.selectedRenderingFBO);
1834 INFO("OpenGL: Successfully created FBOs.\n");
1835
1836 return OGLERROR_NOERR;
1837 }
1838
DestroyFBOs()1839 void OpenGLRenderer_1_2::DestroyFBOs()
1840 {
1841 if (!this->isFBOSupported)
1842 {
1843 return;
1844 }
1845
1846 OGLRenderRef &OGLRef = *this->ref;
1847
1848 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1849 glDeleteFramebuffersEXT(1, &OGLRef.fboClearImageID);
1850 glDeleteFramebuffersEXT(1, &OGLRef.fboRenderID);
1851 glDeleteFramebuffersEXT(1, &OGLRef.fboPostprocessID);
1852 glDeleteTextures(1, &OGLRef.texCIColorID);
1853 glDeleteTextures(1, &OGLRef.texCIDepthID);
1854 glDeleteTextures(1, &OGLRef.texCIFogAttrID);
1855 glDeleteTextures(1, &OGLRef.texCIPolyID);
1856 glDeleteTextures(1, &OGLRef.texCIDepthStencilID);
1857 glDeleteTextures(1, &OGLRef.texGColorID);
1858 glDeleteTextures(1, &OGLRef.texGDepthID);
1859 glDeleteTextures(1, &OGLRef.texGPolyID);
1860 glDeleteTextures(1, &OGLRef.texGFogAttrID);
1861 glDeleteTextures(1, &OGLRef.texGDepthStencilID);
1862 glDeleteTextures(1, &OGLRef.texPostprocessFogID);
1863 glDeleteTextures(1, &OGLRef.texFinalColorID);
1864 glDeleteRenderbuffersEXT(1, &OGLRef.rboFramebufferRGBA6665ID);
1865
1866 OGLRef.fboClearImageID = 0;
1867 OGLRef.fboRenderID = 0;
1868 OGLRef.fboPostprocessID = 0;
1869
1870 this->isFBOSupported = false;
1871 }
1872
CreateMultisampledFBO()1873 Render3DError OpenGLRenderer_1_2::CreateMultisampledFBO()
1874 {
1875 // Check the maximum number of samples that the driver supports and use that.
1876 // Since our target resolution is only 256x192 pixels, using the most samples
1877 // possible is the best thing to do.
1878 GLint maxSamples = 0;
1879 glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples);
1880
1881 if (maxSamples < 2)
1882 {
1883 INFO("OpenGL: Driver does not support at least 2x multisampled FBOs. Multisample antialiasing will be disabled.\n");
1884 return OGLERROR_FEATURE_UNSUPPORTED;
1885 }
1886 else if (maxSamples > OGLRENDER_MAX_MULTISAMPLES)
1887 {
1888 maxSamples = OGLRENDER_MAX_MULTISAMPLES;
1889 }
1890
1891 OGLRenderRef &OGLRef = *this->ref;
1892
1893 // Set up FBO render targets
1894 glGenRenderbuffersEXT(1, &OGLRef.rboMSGColorID);
1895 glGenRenderbuffersEXT(1, &OGLRef.rboMSGDepthID);
1896 glGenRenderbuffersEXT(1, &OGLRef.rboMSGPolyID);
1897 glGenRenderbuffersEXT(1, &OGLRef.rboMSGFogAttrID);
1898 glGenRenderbuffersEXT(1, &OGLRef.rboMSGDepthStencilID);
1899
1900 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGColorID);
1901 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight);
1902 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGDepthID);
1903 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight);
1904 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGPolyID);
1905 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight);
1906 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGFogAttrID);
1907 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight);
1908 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGDepthStencilID);
1909 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_DEPTH24_STENCIL8_EXT, this->_framebufferWidth, this->_framebufferHeight);
1910
1911 // Set up multisampled rendering FBO
1912 glGenFramebuffersEXT(1, &OGLRef.fboMSIntermediateRenderID);
1913
1914 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboMSIntermediateRenderID);
1915 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, OGLRef.rboMSGColorID);
1916 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_RENDERBUFFER_EXT, OGLRef.rboMSGDepthID);
1917 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT2_EXT, GL_RENDERBUFFER_EXT, OGLRef.rboMSGPolyID);
1918 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT3_EXT, GL_RENDERBUFFER_EXT, OGLRef.rboMSGFogAttrID);
1919 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, OGLRef.rboMSGDepthStencilID);
1920 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, OGLRef.rboMSGDepthStencilID);
1921
1922 if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
1923 {
1924 INFO("OpenGL: Failed to create multisampled FBO. Multisample antialiasing will be disabled.\n");
1925
1926 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1927 glDeleteFramebuffersEXT(1, &OGLRef.fboMSIntermediateRenderID);
1928 glDeleteRenderbuffersEXT(1, &OGLRef.rboMSGColorID);
1929 glDeleteRenderbuffersEXT(1, &OGLRef.rboMSGDepthID);
1930 glDeleteRenderbuffersEXT(1, &OGLRef.rboMSGPolyID);
1931 glDeleteRenderbuffersEXT(1, &OGLRef.rboMSGFogAttrID);
1932 glDeleteRenderbuffersEXT(1, &OGLRef.rboMSGDepthStencilID);
1933
1934 return OGLERROR_FBO_CREATE_ERROR;
1935 }
1936
1937 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboRenderID);
1938 INFO("OpenGL: Successfully created multisampled FBO.\n");
1939
1940 return OGLERROR_NOERR;
1941 }
1942
DestroyMultisampledFBO()1943 void OpenGLRenderer_1_2::DestroyMultisampledFBO()
1944 {
1945 if (!this->isMultisampledFBOSupported)
1946 {
1947 return;
1948 }
1949
1950 OGLRenderRef &OGLRef = *this->ref;
1951
1952 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1953 glDeleteFramebuffersEXT(1, &OGLRef.fboMSIntermediateRenderID);
1954 glDeleteRenderbuffersEXT(1, &OGLRef.rboMSGColorID);
1955 glDeleteRenderbuffersEXT(1, &OGLRef.rboMSGDepthID);
1956 glDeleteRenderbuffersEXT(1, &OGLRef.rboMSGPolyID);
1957 glDeleteRenderbuffersEXT(1, &OGLRef.rboMSGFogAttrID);
1958 glDeleteRenderbuffersEXT(1, &OGLRef.rboMSGDepthStencilID);
1959
1960 this->isMultisampledFBOSupported = false;
1961 }
1962
InitFinalRenderStates(const std::set<std::string> * oglExtensionSet)1963 Render3DError OpenGLRenderer_1_2::InitFinalRenderStates(const std::set<std::string> *oglExtensionSet)
1964 {
1965 OGLRenderRef &OGLRef = *this->ref;
1966
1967 bool isTexMirroredRepeatSupported = this->IsExtensionPresent(oglExtensionSet, "GL_ARB_texture_mirrored_repeat");
1968 bool isBlendFuncSeparateSupported = this->IsExtensionPresent(oglExtensionSet, "GL_EXT_blend_func_separate");
1969 bool isBlendEquationSeparateSupported = this->IsExtensionPresent(oglExtensionSet, "GL_EXT_blend_equation_separate");
1970
1971 // Blending Support
1972 if (isBlendFuncSeparateSupported)
1973 {
1974 if (isBlendEquationSeparateSupported)
1975 {
1976 // we want to use alpha destination blending so we can track the last-rendered alpha value
1977 // test: new super mario brothers renders the stormclouds at the beginning
1978 glBlendFuncSeparateEXT(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, GL_DST_ALPHA);
1979 glBlendEquationSeparateEXT(GL_FUNC_ADD, GL_MAX);
1980 }
1981 else
1982 {
1983 glBlendFuncSeparateEXT(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_DST_ALPHA);
1984 }
1985 }
1986 else
1987 {
1988 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1989 }
1990
1991 // Mirrored Repeat Mode Support
1992 OGLRef.stateTexMirroredRepeat = isTexMirroredRepeatSupported ? GL_MIRRORED_REPEAT : GL_REPEAT;
1993
1994 // Map the vertex list's colors with 4 floats per color. This is being done
1995 // because OpenGL needs 4-colors per vertex to support translucency. (The DS
1996 // uses 3-colors per vertex, and adds alpha through the poly, so we can't
1997 // simply reference the colors+alpha from just the vertices by themselves.)
1998 OGLRef.color4fBuffer = (this->isShaderSupported) ? NULL : new GLfloat[VERTLIST_SIZE * 4];
1999
2000 // If VBOs aren't supported, then we need to create the index buffer on the
2001 // client side so that we have a buffer to update.
2002 OGLRef.vertIndexBuffer = (this->isVBOSupported) ? NULL : new GLushort[OGLRENDER_VERT_INDEX_BUFFER_COUNT];
2003
2004 return OGLERROR_NOERR;
2005 }
2006
InitTextures()2007 Render3DError OpenGLRenderer_1_2::InitTextures()
2008 {
2009 this->ExpandFreeTextures();
2010
2011 return OGLERROR_NOERR;
2012 }
2013
InitTables()2014 Render3DError OpenGLRenderer_1_2::InitTables()
2015 {
2016 static bool needTableInit = true;
2017
2018 if (needTableInit)
2019 {
2020 for (size_t i = 0; i < 256; i++)
2021 material_8bit_to_float[i] = (GLfloat)(i * 4) / 255.0f;
2022
2023 needTableInit = false;
2024 }
2025
2026 return OGLERROR_NOERR;
2027 }
2028
InitPostprocessingPrograms(const std::string & edgeMarkVtxShader,const std::string & edgeMarkFragShader,const std::string & fogVtxShader,const std::string & fogFragShader,const std::string & framebufferOutputVtxShader,const std::string & framebufferOutputRGBA6665FragShader,const std::string & framebufferOutputRGBA8888FragShader)2029 Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const std::string &edgeMarkVtxShader,
2030 const std::string &edgeMarkFragShader,
2031 const std::string &fogVtxShader,
2032 const std::string &fogFragShader,
2033 const std::string &framebufferOutputVtxShader,
2034 const std::string &framebufferOutputRGBA6665FragShader,
2035 const std::string &framebufferOutputRGBA8888FragShader)
2036 {
2037 return OGLERROR_FEATURE_UNSUPPORTED;
2038 }
2039
DestroyPostprocessingPrograms()2040 Render3DError OpenGLRenderer_1_2::DestroyPostprocessingPrograms()
2041 {
2042 return OGLERROR_FEATURE_UNSUPPORTED;
2043 }
2044
InitEdgeMarkProgramBindings()2045 Render3DError OpenGLRenderer_1_2::InitEdgeMarkProgramBindings()
2046 {
2047 return OGLERROR_FEATURE_UNSUPPORTED;
2048 }
2049
InitEdgeMarkProgramShaderLocations()2050 Render3DError OpenGLRenderer_1_2::InitEdgeMarkProgramShaderLocations()
2051 {
2052 return OGLERROR_FEATURE_UNSUPPORTED;
2053 }
2054
InitFogProgramBindings()2055 Render3DError OpenGLRenderer_1_2::InitFogProgramBindings()
2056 {
2057 return OGLERROR_FEATURE_UNSUPPORTED;
2058 }
2059
InitFogProgramShaderLocations()2060 Render3DError OpenGLRenderer_1_2::InitFogProgramShaderLocations()
2061 {
2062 return OGLERROR_FEATURE_UNSUPPORTED;
2063 }
2064
InitFramebufferOutputProgramBindings()2065 Render3DError OpenGLRenderer_1_2::InitFramebufferOutputProgramBindings()
2066 {
2067 return OGLERROR_FEATURE_UNSUPPORTED;
2068 }
2069
InitFramebufferOutputShaderLocations()2070 Render3DError OpenGLRenderer_1_2::InitFramebufferOutputShaderLocations()
2071 {
2072 return OGLERROR_FEATURE_UNSUPPORTED;
2073 }
2074
CreateToonTable()2075 Render3DError OpenGLRenderer_1_2::CreateToonTable()
2076 {
2077 OGLRenderRef &OGLRef = *this->ref;
2078 u16 tempToonTable[32];
2079 memset(tempToonTable, 0, sizeof(tempToonTable));
2080
2081 // The toon table is a special 1D texture where each pixel corresponds
2082 // to a specific color in the toon table.
2083 glGenTextures(1, &OGLRef.texToonTableID);
2084 glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_ToonTable);
2085 glBindTexture(GL_TEXTURE_1D, OGLRef.texToonTableID);
2086
2087 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2088 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2089 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2090 glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 32, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, tempToonTable);
2091
2092 glActiveTextureARB(GL_TEXTURE0_ARB);
2093
2094 return OGLERROR_NOERR;
2095 }
2096
DestroyToonTable()2097 Render3DError OpenGLRenderer_1_2::DestroyToonTable()
2098 {
2099 glDeleteTextures(1, &this->ref->texToonTableID);
2100
2101 return OGLERROR_NOERR;
2102 }
2103
UploadClearImage(const u16 * __restrict colorBuffer,const u32 * __restrict depthBuffer,const u8 * __restrict fogBuffer,const u8 * __restrict polyIDBuffer)2104 Render3DError OpenGLRenderer_1_2::UploadClearImage(const u16 *__restrict colorBuffer, const u32 *__restrict depthBuffer, const u8 *__restrict fogBuffer, const u8 *__restrict polyIDBuffer)
2105 {
2106 OGLRenderRef &OGLRef = *this->ref;
2107
2108 if (this->isShaderSupported)
2109 {
2110 for (size_t i = 0; i < GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT; i++)
2111 {
2112 OGLRef.workingCIDepthStencilBuffer[i] = (depthBuffer[i] << 8) | polyIDBuffer[i];
2113 OGLRef.workingCIDepthBuffer[i] = depthBuffer[i] | 0xFF000000;
2114 OGLRef.workingCIFogAttributesBuffer[i] = (fogBuffer[i]) ? 0xFF0000FF : 0xFF000000;
2115 OGLRef.workingCIPolyIDBuffer[i] = (GLuint)polyIDBuffer[i] | 0xFF000000;
2116 }
2117 }
2118 else
2119 {
2120 for (size_t i = 0; i < GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT; i++)
2121 {
2122 OGLRef.workingCIDepthStencilBuffer[i] = (depthBuffer[i] << 8) | polyIDBuffer[i];
2123 }
2124 }
2125
2126 glActiveTextureARB(GL_TEXTURE0_ARB);
2127
2128 glBindTexture(GL_TEXTURE_2D, OGLRef.texCIColorID);
2129 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, colorBuffer);
2130 glBindTexture(GL_TEXTURE_2D, OGLRef.texCIDepthStencilID);
2131 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, OGLRef.workingCIDepthStencilBuffer);
2132
2133 if (this->isShaderSupported)
2134 {
2135 glBindTexture(GL_TEXTURE_2D, OGLRef.texCIDepthID);
2136 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, OGLRef.workingCIDepthBuffer);
2137
2138 glBindTexture(GL_TEXTURE_2D, OGLRef.texCIFogAttrID);
2139 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, OGLRef.workingCIFogAttributesBuffer);
2140
2141 glBindTexture(GL_TEXTURE_2D, OGLRef.texCIPolyID);
2142 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, OGLRef.workingCIPolyIDBuffer);
2143 }
2144
2145 glBindTexture(GL_TEXTURE_2D, 0);
2146
2147 return OGLERROR_NOERR;
2148 }
2149
GetExtensionSet(std::set<std::string> * oglExtensionSet)2150 void OpenGLRenderer_1_2::GetExtensionSet(std::set<std::string> *oglExtensionSet)
2151 {
2152 std::string oglExtensionString = std::string((const char *)glGetString(GL_EXTENSIONS));
2153
2154 size_t extStringStartLoc = 0;
2155 size_t delimiterLoc = oglExtensionString.find_first_of(' ', extStringStartLoc);
2156 while (delimiterLoc != std::string::npos)
2157 {
2158 std::string extensionName = oglExtensionString.substr(extStringStartLoc, delimiterLoc - extStringStartLoc);
2159 oglExtensionSet->insert(extensionName);
2160
2161 extStringStartLoc = delimiterLoc + 1;
2162 delimiterLoc = oglExtensionString.find_first_of(' ', extStringStartLoc);
2163 }
2164
2165 if (extStringStartLoc - oglExtensionString.length() > 0)
2166 {
2167 std::string extensionName = oglExtensionString.substr(extStringStartLoc, oglExtensionString.length() - extStringStartLoc);
2168 oglExtensionSet->insert(extensionName);
2169 }
2170 }
2171
ExpandFreeTextures()2172 Render3DError OpenGLRenderer_1_2::ExpandFreeTextures()
2173 {
2174 static const GLsizei kInitTextures = 128;
2175 GLuint oglTempTextureID[kInitTextures];
2176 glGenTextures(kInitTextures, oglTempTextureID);
2177
2178 for(GLsizei i = 0; i < kInitTextures; i++)
2179 {
2180 this->ref->freeTextureIDs.push(oglTempTextureID[i]);
2181 }
2182
2183 return OGLERROR_NOERR;
2184 }
2185
EnableVertexAttributes()2186 Render3DError OpenGLRenderer_1_2::EnableVertexAttributes()
2187 {
2188 OGLRenderRef &OGLRef = *this->ref;
2189
2190 if (this->isVAOSupported)
2191 {
2192 glBindVertexArray(OGLRef.vaoGeometryStatesID);
2193 }
2194 else
2195 {
2196 if (this->isShaderSupported)
2197 {
2198 glEnableVertexAttribArray(OGLVertexAttributeID_Position);
2199 glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0);
2200 glEnableVertexAttribArray(OGLVertexAttributeID_Color);
2201 glVertexAttribPointer(OGLVertexAttributeID_Position, 4, GL_FLOAT, GL_FALSE, sizeof(VERT), OGLRef.vtxPtrPosition);
2202 glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(VERT), OGLRef.vtxPtrTexCoord);
2203 glVertexAttribPointer(OGLVertexAttributeID_Color, 3, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(VERT), OGLRef.vtxPtrColor);
2204 }
2205 else
2206 {
2207 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
2208 glEnableClientState(GL_COLOR_ARRAY);
2209 glEnableClientState(GL_VERTEX_ARRAY);
2210
2211 if (this->isVBOSupported)
2212 {
2213 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
2214 glColorPointer(4, GL_FLOAT, 0, OGLRef.vtxPtrColor);
2215 glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboGeometryVtxID);
2216 }
2217 else
2218 {
2219 glColorPointer(4, GL_FLOAT, 0, OGLRef.vtxPtrColor);
2220 }
2221
2222 glVertexPointer(4, GL_FLOAT, sizeof(VERT), OGLRef.vtxPtrPosition);
2223 glTexCoordPointer(2, GL_FLOAT, sizeof(VERT), OGLRef.vtxPtrTexCoord);
2224 }
2225 }
2226
2227 glActiveTextureARB(GL_TEXTURE0_ARB);
2228
2229 return OGLERROR_NOERR;
2230 }
2231
DisableVertexAttributes()2232 Render3DError OpenGLRenderer_1_2::DisableVertexAttributes()
2233 {
2234 if (this->isVAOSupported)
2235 {
2236 glBindVertexArray(0);
2237 }
2238 else
2239 {
2240 if (this->isShaderSupported)
2241 {
2242 glDisableVertexAttribArray(OGLVertexAttributeID_Position);
2243 glDisableVertexAttribArray(OGLVertexAttributeID_TexCoord0);
2244 glDisableVertexAttribArray(OGLVertexAttributeID_Color);
2245 }
2246 else
2247 {
2248 glDisableClientState(GL_VERTEX_ARRAY);
2249 glDisableClientState(GL_COLOR_ARRAY);
2250 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
2251 }
2252 }
2253
2254 return OGLERROR_NOERR;
2255 }
2256
DownsampleFBO()2257 Render3DError OpenGLRenderer_1_2::DownsampleFBO()
2258 {
2259 OGLRenderRef &OGLRef = *this->ref;
2260
2261 if (this->isMultisampledFBOSupported && OGLRef.selectedRenderingFBO == OGLRef.fboMSIntermediateRenderID)
2262 {
2263 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, OGLRef.fboMSIntermediateRenderID);
2264 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, OGLRef.fboRenderID);
2265
2266 // Blit the color buffer
2267 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
2268 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
2269 glBlitFramebufferEXT(0, 0, this->_framebufferWidth, this->_framebufferHeight, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
2270
2271 // Blit the working depth buffer
2272 glReadBuffer(GL_COLOR_ATTACHMENT1_EXT);
2273 glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT);
2274 glBlitFramebufferEXT(0, 0, this->_framebufferWidth, this->_framebufferHeight, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
2275
2276 // Blit the polygon ID buffer
2277 glReadBuffer(GL_COLOR_ATTACHMENT2_EXT);
2278 glDrawBuffer(GL_COLOR_ATTACHMENT2_EXT);
2279 glBlitFramebufferEXT(0, 0, this->_framebufferWidth, this->_framebufferHeight, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
2280
2281 // Blit the fog buffer
2282 glReadBuffer(GL_COLOR_ATTACHMENT3_EXT);
2283 glDrawBuffer(GL_COLOR_ATTACHMENT3_EXT);
2284 glBlitFramebufferEXT(0, 0, this->_framebufferWidth, this->_framebufferHeight, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
2285
2286 // Reset framebuffer targets
2287 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
2288 glDrawBuffers(4, RenderDrawList);
2289 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboRenderID);
2290 }
2291
2292 return OGLERROR_NOERR;
2293 }
2294
ReadBackPixels()2295 Render3DError OpenGLRenderer_1_2::ReadBackPixels()
2296 {
2297 OGLRenderRef &OGLRef = *this->ref;
2298
2299 if (!this->isPBOSupported)
2300 {
2301 this->_pixelReadNeedsFinish = true;
2302 return OGLERROR_NOERR;
2303 }
2304
2305 if (this->_mappedFramebuffer != NULL)
2306 {
2307 glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
2308 this->_mappedFramebuffer = NULL;
2309 }
2310
2311 // Flip the framebuffer in Y to match the coordinates of OpenGL and the NDS hardware.
2312 if (this->willFlipFramebufferOnGPU)
2313 {
2314 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, OGLRef.fboPostprocessID);
2315 glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT);
2316 glBlitFramebufferEXT(0, this->_framebufferHeight, this->_framebufferWidth, 0, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
2317 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboPostprocessID);
2318 glReadBuffer(GL_COLOR_ATTACHMENT1_EXT);
2319 }
2320
2321 if (this->willConvertFramebufferOnGPU)
2322 {
2323 // Perform the color space conversion while we're still on the GPU so
2324 // that we can avoid having to do it on the CPU.
2325 const GLuint convertProgramID = (this->_outputFormat == NDSColorFormat_BGR666_Rev) ? OGLRef.programFramebufferRGBA6665OutputID : OGLRef.programFramebufferRGBA8888OutputID;
2326 glDrawBuffer(GL_COLOR_ATTACHMENT2_EXT);
2327
2328 glUseProgram(convertProgramID);
2329 glViewport(0, 0, this->_framebufferWidth, this->_framebufferHeight);
2330 glDisable(GL_DEPTH_TEST);
2331 glDisable(GL_STENCIL_TEST);
2332 glDisable(GL_BLEND);
2333 glDisable(GL_CULL_FACE);
2334
2335 glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboPostprocessVtxID);
2336 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboPostprocessIndexID);
2337 glBindVertexArray(OGLRef.vaoPostprocessStatesID);
2338 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);
2339 glBindVertexArray(0);
2340
2341 // Read back the pixels.
2342 glReadBuffer(GL_COLOR_ATTACHMENT2_EXT);
2343 }
2344
2345 // Read back the pixels in BGRA format, since legacy OpenGL devices may experience a performance
2346 // penalty if the readback is in any other format.
2347 glReadPixels(0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_BGRA, GL_UNSIGNED_BYTE, 0);
2348
2349 // Set the read and draw target buffers back to color attachment 0, which is always the default.
2350 if (this->willFlipFramebufferOnGPU || this->willConvertFramebufferOnGPU)
2351 {
2352 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
2353 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
2354 }
2355
2356 this->_pixelReadNeedsFinish = true;
2357 return OGLERROR_NOERR;
2358 }
2359
DeleteTexture(const TexCacheItem * item)2360 Render3DError OpenGLRenderer_1_2::DeleteTexture(const TexCacheItem *item)
2361 {
2362 this->ref->freeTextureIDs.push((GLuint)item->texid);
2363 if(this->currTexture == item)
2364 {
2365 this->currTexture = NULL;
2366 }
2367
2368 return OGLERROR_NOERR;
2369 }
2370
BeginRender(const GFX3D & engine)2371 Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D &engine)
2372 {
2373 OGLRenderRef &OGLRef = *this->ref;
2374
2375 if(!BEGINGL())
2376 {
2377 return OGLERROR_BEGINGL_FAILED;
2378 }
2379
2380 if (this->isShaderSupported)
2381 {
2382 glUseProgram(OGLRef.programGeometryID);
2383 glUniform1i(OGLRef.uniformStateToonShadingMode, engine.renderState.shading);
2384 glUniform1i(OGLRef.uniformStateEnableAlphaTest, (engine.renderState.enableAlphaTest) ? GL_TRUE : GL_FALSE);
2385 glUniform1i(OGLRef.uniformStateEnableAntialiasing, (engine.renderState.enableAntialiasing) ? GL_TRUE : GL_FALSE);
2386 glUniform1i(OGLRef.uniformStateEnableEdgeMarking, (engine.renderState.enableEdgeMarking) ? GL_TRUE : GL_FALSE);
2387 glUniform1i(OGLRef.uniformStateUseWDepth, (engine.renderState.wbuffer) ? GL_TRUE : GL_FALSE);
2388 glUniform1f(OGLRef.uniformStateAlphaTestRef, divide5bitBy31_LUT[engine.renderState.alphaTestRef]);
2389 }
2390 else
2391 {
2392 if(engine.renderState.enableAlphaTest && (engine.renderState.alphaTestRef > 0))
2393 {
2394 glAlphaFunc(GL_GEQUAL, divide5bitBy31_LUT[engine.renderState.alphaTestRef]);
2395 }
2396 else
2397 {
2398 glAlphaFunc(GL_GREATER, 0);
2399 }
2400
2401 glMatrixMode(GL_PROJECTION);
2402 glLoadIdentity();
2403 }
2404
2405 GLushort *indexPtr = NULL;
2406
2407 if (this->isVBOSupported)
2408 {
2409 glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboGeometryVtxID);
2410 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, OGLRef.iboGeometryIndexID);
2411 indexPtr = (GLushort *)glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
2412 }
2413 else
2414 {
2415 // If VBOs aren't supported, we need to use the client-side buffers here.
2416 OGLRef.vtxPtrPosition = &engine.vertlist->list[0].coord;
2417 OGLRef.vtxPtrTexCoord = &engine.vertlist->list[0].texcoord;
2418 OGLRef.vtxPtrColor = (this->isShaderSupported) ? (GLvoid *)&engine.vertlist->list[0].color : OGLRef.color4fBuffer;
2419 indexPtr = OGLRef.vertIndexBuffer;
2420 }
2421
2422 size_t vertIndexCount = 0;
2423
2424 for (size_t i = 0; i < engine.polylist->count; i++)
2425 {
2426 const POLY *thePoly = &engine.polylist->list[engine.indexlist.list[i]];
2427 const size_t polyType = thePoly->type;
2428
2429 if (this->isShaderSupported)
2430 {
2431 for (size_t j = 0; j < polyType; j++)
2432 {
2433 const GLushort vertIndex = thePoly->vertIndexes[j];
2434
2435 // While we're looping through our vertices, add each vertex index to
2436 // a buffer. For GFX3D_QUADS and GFX3D_QUAD_STRIP, we also add additional
2437 // vertices here to convert them to GL_TRIANGLES, which are much easier
2438 // to work with and won't be deprecated in future OpenGL versions.
2439 indexPtr[vertIndexCount++] = vertIndex;
2440 if (thePoly->vtxFormat == GFX3D_QUADS || thePoly->vtxFormat == GFX3D_QUAD_STRIP)
2441 {
2442 if (j == 2)
2443 {
2444 indexPtr[vertIndexCount++] = vertIndex;
2445 }
2446 else if (j == 3)
2447 {
2448 indexPtr[vertIndexCount++] = thePoly->vertIndexes[0];
2449 }
2450 }
2451 }
2452 }
2453 else
2454 {
2455 const GLfloat thePolyAlpha = (!thePoly->isWireframe() && thePoly->isTranslucent()) ? divide5bitBy31_LUT[thePoly->getAttributeAlpha()] : 1.0f;
2456
2457 for (size_t j = 0; j < polyType; j++)
2458 {
2459 const GLushort vertIndex = thePoly->vertIndexes[j];
2460 const size_t colorIndex = vertIndex * 4;
2461
2462 // Consolidate the vertex color and the poly alpha to our internal color buffer
2463 // so that OpenGL can use it.
2464 const VERT *vert = &engine.vertlist->list[vertIndex];
2465 OGLRef.color4fBuffer[colorIndex+0] = material_8bit_to_float[vert->color[0]];
2466 OGLRef.color4fBuffer[colorIndex+1] = material_8bit_to_float[vert->color[1]];
2467 OGLRef.color4fBuffer[colorIndex+2] = material_8bit_to_float[vert->color[2]];
2468 OGLRef.color4fBuffer[colorIndex+3] = thePolyAlpha;
2469
2470 // While we're looping through our vertices, add each vertex index to a
2471 // buffer. For GFX3D_QUADS and GFX3D_QUAD_STRIP, we also add additional
2472 // vertices here to convert them to GL_TRIANGLES, which are much easier
2473 // to work with and won't be deprecated in future OpenGL versions.
2474 indexPtr[vertIndexCount++] = vertIndex;
2475 if (thePoly->vtxFormat == GFX3D_QUADS || thePoly->vtxFormat == GFX3D_QUAD_STRIP)
2476 {
2477 if (j == 2)
2478 {
2479 indexPtr[vertIndexCount++] = vertIndex;
2480 }
2481 else if (j == 3)
2482 {
2483 indexPtr[vertIndexCount++] = thePoly->vertIndexes[0];
2484 }
2485 }
2486 }
2487 }
2488 }
2489
2490 if (this->isVBOSupported)
2491 {
2492 glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
2493 glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(VERT) * engine.vertlist->count, engine.vertlist);
2494 }
2495
2496 return OGLERROR_NOERR;
2497 }
2498
RenderGeometry(const GFX3D_State & renderState,const POLYLIST * polyList,const INDEXLIST * indexList)2499 Render3DError OpenGLRenderer_1_2::RenderGeometry(const GFX3D_State &renderState, const POLYLIST *polyList, const INDEXLIST *indexList)
2500 {
2501 OGLRenderRef &OGLRef = *this->ref;
2502 const size_t polyCount = polyList->count;
2503
2504 // Map GFX3D_QUADS and GFX3D_QUAD_STRIP to GL_TRIANGLES since we will convert them.
2505 //
2506 // Also map GFX3D_TRIANGLE_STRIP to GL_TRIANGLES. This is okay since this is actually
2507 // how the POLY struct stores triangle strip vertices, which is in sets of 3 vertices
2508 // each. This redefinition is necessary since uploading more than 3 indices at a time
2509 // will cause glDrawElements() to draw the triangle strip incorrectly.
2510 static const GLenum oglPrimitiveType[] = {GL_TRIANGLES, GL_TRIANGLES, GL_TRIANGLES, GL_TRIANGLES,
2511 GL_LINE_LOOP, GL_LINE_LOOP, GL_LINE_STRIP, GL_LINE_STRIP};
2512
2513 static const GLsizei indexIncrementLUT[] = {3, 6, 3, 6, 3, 4, 3, 4};
2514
2515 if (polyCount > 0)
2516 {
2517 glEnable(GL_DEPTH_TEST);
2518
2519 if(renderState.enableAlphaBlending)
2520 {
2521 glEnable(GL_BLEND);
2522 }
2523 else
2524 {
2525 glDisable(GL_BLEND);
2526 }
2527
2528 this->EnableVertexAttributes();
2529
2530 this->_shadowPolyID.clear();
2531 for (size_t i = 0; i < polyCount; i++)
2532 {
2533 const POLY &thePoly = polyList->list[i];
2534
2535 if (thePoly.getAttributePolygonMode() != POLYGON_MODE_SHADOW)
2536 {
2537 continue;
2538 }
2539
2540 const u8 polyID = thePoly.getAttributePolygonID();
2541
2542 if ( (polyID == 0) || (std::find(this->_shadowPolyID.begin(), this->_shadowPolyID.end(), polyID) != this->_shadowPolyID.end()) )
2543 {
2544 continue;
2545 }
2546
2547 this->_shadowPolyID.push_back(polyID);
2548 }
2549
2550 const POLY &firstPoly = polyList->list[indexList->list[0]];
2551 u32 lastPolyAttr = firstPoly.polyAttr;
2552 u32 lastTexParams = firstPoly.texParam;
2553 u32 lastTexPalette = firstPoly.texPalette;
2554 u32 lastViewport = firstPoly.viewport;
2555
2556 this->SetupPolygon(firstPoly);
2557 this->SetupTexture(firstPoly, renderState.enableTexturing);
2558 this->SetupViewport(lastViewport);
2559
2560 GLsizei vertIndexCount = 0;
2561 GLushort *indexBufferPtr = OGLRef.vertIndexBuffer;
2562
2563 // Enumerate through all polygons and render
2564 for (size_t i = 0; i < polyCount; i++)
2565 {
2566 const POLY &thePoly = polyList->list[indexList->list[i]];
2567
2568 // Set up the polygon if it changed
2569 if (lastPolyAttr != thePoly.polyAttr)
2570 {
2571 lastPolyAttr = thePoly.polyAttr;
2572 this->SetupPolygon(thePoly);
2573 }
2574
2575 // Set up the texture if it changed
2576 if (lastTexParams != thePoly.texParam || lastTexPalette != thePoly.texPalette)
2577 {
2578 lastTexParams = thePoly.texParam;
2579 lastTexPalette = thePoly.texPalette;
2580 this->SetupTexture(thePoly, renderState.enableTexturing);
2581 }
2582
2583 // Set up the viewport if it changed
2584 if (lastViewport != thePoly.viewport)
2585 {
2586 lastViewport = thePoly.viewport;
2587 this->SetupViewport(thePoly.viewport);
2588 }
2589
2590 // In wireframe mode, redefine all primitives as GL_LINE_LOOP rather than
2591 // setting the polygon mode to GL_LINE though glPolygonMode(). Not only is
2592 // drawing more accurate this way, but it also allows GFX3D_QUADS and
2593 // GFX3D_QUAD_STRIP primitives to properly draw as wireframe without the
2594 // extra diagonal line.
2595 const GLenum polyPrimitive = (!thePoly.isWireframe()) ? oglPrimitiveType[thePoly.vtxFormat] : GL_LINE_LOOP;
2596
2597 // Increment the vertex count
2598 vertIndexCount += indexIncrementLUT[thePoly.vtxFormat];
2599
2600 // Look ahead to the next polygon to see if we can simply buffer the indices
2601 // instead of uploading them now. We can buffer if all polygon states remain
2602 // the same and we're not drawing a line loop or line strip.
2603 if (i+1 < polyCount)
2604 {
2605 const POLY *nextPoly = &polyList->list[indexList->list[i+1]];
2606
2607 if (lastPolyAttr == nextPoly->polyAttr &&
2608 lastTexParams == nextPoly->texParam &&
2609 lastTexPalette == nextPoly->texPalette &&
2610 lastViewport == nextPoly->viewport &&
2611 polyPrimitive == oglPrimitiveType[nextPoly->vtxFormat] &&
2612 polyPrimitive != GL_LINE_LOOP &&
2613 polyPrimitive != GL_LINE_STRIP &&
2614 oglPrimitiveType[nextPoly->vtxFormat] != GL_LINE_LOOP &&
2615 oglPrimitiveType[nextPoly->vtxFormat] != GL_LINE_STRIP)
2616 {
2617 continue;
2618 }
2619 }
2620
2621 // Render the polygons
2622 this->SetPolygonIndex(i);
2623 glDrawElements(polyPrimitive, vertIndexCount, GL_UNSIGNED_SHORT, indexBufferPtr);
2624 indexBufferPtr += vertIndexCount;
2625 vertIndexCount = 0;
2626 }
2627
2628 this->DisableVertexAttributes();
2629 }
2630
2631 this->DownsampleFBO();
2632
2633 return OGLERROR_NOERR;
2634 }
2635
EndRender(const u64 frameCount)2636 Render3DError OpenGLRenderer_1_2::EndRender(const u64 frameCount)
2637 {
2638 //needs to happen before endgl because it could free some textureids for expired cache items
2639 TexCache_EvictFrame();
2640
2641 this->ReadBackPixels();
2642
2643 ENDGL();
2644
2645 return OGLERROR_NOERR;
2646 }
2647
UpdateToonTable(const u16 * toonTableBuffer)2648 Render3DError OpenGLRenderer_1_2::UpdateToonTable(const u16 *toonTableBuffer)
2649 {
2650 glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_ToonTable);
2651 glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 32, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, toonTableBuffer);
2652
2653 return OGLERROR_NOERR;
2654 }
2655
ClearUsingImage(const u16 * __restrict colorBuffer,const u32 * __restrict depthBuffer,const u8 * __restrict fogBuffer,const u8 * __restrict polyIDBuffer)2656 Render3DError OpenGLRenderer_1_2::ClearUsingImage(const u16 *__restrict colorBuffer, const u32 *__restrict depthBuffer, const u8 *__restrict fogBuffer, const u8 *__restrict polyIDBuffer)
2657 {
2658 if (!this->isFBOSupported)
2659 {
2660 return OGLERROR_FEATURE_UNSUPPORTED;
2661 }
2662
2663 OGLRenderRef &OGLRef = *this->ref;
2664
2665 this->UploadClearImage(colorBuffer, depthBuffer, fogBuffer, polyIDBuffer);
2666
2667 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, OGLRef.fboClearImageID);
2668 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, OGLRef.fboRenderID);
2669
2670 // It might seem wasteful to be doing a separate glClear(GL_STENCIL_BUFFER_BIT) instead
2671 // of simply blitting the stencil buffer with everything else.
2672 //
2673 // We do this because glBlitFramebufferEXT() for GL_STENCIL_BUFFER_BIT has been tested
2674 // to be unsupported on ATI/AMD GPUs running in compatibility mode. So we do the separate
2675 // glClear() for GL_STENCIL_BUFFER_BIT to keep these GPUs working.
2676 glClearStencil(polyIDBuffer[0]);
2677 glClear(GL_STENCIL_BUFFER_BIT);
2678
2679 // Blit the working depth buffer
2680 glReadBuffer(GL_COLOR_ATTACHMENT1_EXT);
2681 glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT);
2682 glBlitFramebufferEXT(0, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GPU_FRAMEBUFFER_NATIVE_WIDTH, 0, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
2683
2684 // Blit the polygon ID buffer
2685 glReadBuffer(GL_COLOR_ATTACHMENT2_EXT);
2686 glDrawBuffer(GL_COLOR_ATTACHMENT2_EXT);
2687 glBlitFramebufferEXT(0, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GPU_FRAMEBUFFER_NATIVE_WIDTH, 0, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
2688
2689 // Blit the fog buffer
2690 glReadBuffer(GL_COLOR_ATTACHMENT3_EXT);
2691 glDrawBuffer(GL_COLOR_ATTACHMENT3_EXT);
2692 glBlitFramebufferEXT(0, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GPU_FRAMEBUFFER_NATIVE_WIDTH, 0, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
2693
2694 // Blit the color buffer. Do this last so that color attachment 0 is set to the read FBO.
2695 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
2696 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
2697 glBlitFramebufferEXT(0, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GPU_FRAMEBUFFER_NATIVE_WIDTH, 0, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
2698
2699 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboRenderID);
2700 glDrawBuffers(4, RenderDrawList);
2701
2702 if (this->isMultisampledFBOSupported)
2703 {
2704 OGLRef.selectedRenderingFBO = (CommonSettings.GFX3D_Renderer_Multisample) ? OGLRef.fboMSIntermediateRenderID : OGLRef.fboRenderID;
2705 if (OGLRef.selectedRenderingFBO == OGLRef.fboMSIntermediateRenderID)
2706 {
2707 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, OGLRef.fboRenderID);
2708 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, OGLRef.selectedRenderingFBO);
2709
2710 glClearStencil(polyIDBuffer[0]);
2711 glClear(GL_STENCIL_BUFFER_BIT);
2712
2713 // Blit the working depth buffer
2714 glReadBuffer(GL_COLOR_ATTACHMENT1_EXT);
2715 glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT);
2716 glBlitFramebufferEXT(0, 0, this->_framebufferWidth, this->_framebufferHeight, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
2717
2718 // Blit the polygon ID buffer
2719 glReadBuffer(GL_COLOR_ATTACHMENT2_EXT);
2720 glDrawBuffer(GL_COLOR_ATTACHMENT2_EXT);
2721 glBlitFramebufferEXT(0, 0, this->_framebufferWidth, this->_framebufferHeight, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
2722
2723 // Blit the fog buffer
2724 glReadBuffer(GL_COLOR_ATTACHMENT3_EXT);
2725 glDrawBuffer(GL_COLOR_ATTACHMENT3_EXT);
2726 glBlitFramebufferEXT(0, 0, this->_framebufferWidth, this->_framebufferHeight, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
2727
2728 // Blit the color buffer. Do this last so that color attachment 0 is set to the read FBO.
2729 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
2730 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
2731 glBlitFramebufferEXT(0, 0, this->_framebufferWidth, this->_framebufferHeight, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
2732
2733 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.selectedRenderingFBO);
2734 glDrawBuffers(4, RenderDrawList);
2735 }
2736 }
2737
2738 return OGLERROR_NOERR;
2739 }
2740
ClearUsingValues(const FragmentColor & clearColor,const FragmentAttributes & clearAttributes) const2741 Render3DError OpenGLRenderer_1_2::ClearUsingValues(const FragmentColor &clearColor, const FragmentAttributes &clearAttributes) const
2742 {
2743 OGLRenderRef &OGLRef = *this->ref;
2744
2745 if (this->isMultisampledFBOSupported)
2746 {
2747 OGLRef.selectedRenderingFBO = (CommonSettings.GFX3D_Renderer_Multisample) ? OGLRef.fboMSIntermediateRenderID : OGLRef.fboRenderID;
2748 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.selectedRenderingFBO);
2749 }
2750
2751 glDepthMask(GL_TRUE);
2752
2753 if (this->isShaderSupported && this->isFBOSupported)
2754 {
2755 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); // texGColorID
2756 glClearColor(divide5bitBy31_LUT[clearColor.r], divide5bitBy31_LUT[clearColor.g], divide5bitBy31_LUT[clearColor.b], divide5bitBy31_LUT[clearColor.a]);
2757 glClearDepth((GLclampd)clearAttributes.depth / (GLclampd)0x00FFFFFF);
2758 glClearStencil(0xFF);
2759 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2760
2761 glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT); // texGDepthID
2762 glClearColor((GLfloat)(clearAttributes.depth & 0x000000FF)/255.0f, (GLfloat)((clearAttributes.depth >> 8) & 0x000000FF)/255.0f, (GLfloat)((clearAttributes.depth >> 16) & 0x000000FF)/255.0f, 1.0);
2763 glClear(GL_COLOR_BUFFER_BIT);
2764
2765 glDrawBuffer(GL_COLOR_ATTACHMENT2_EXT); // texGPolyID
2766 glClearColor((GLfloat)clearAttributes.opaquePolyID/63.0f, 0.0, 0.0, 1.0);
2767 glClear(GL_COLOR_BUFFER_BIT);
2768
2769 glDrawBuffer(GL_COLOR_ATTACHMENT3_EXT); // texGFogAttrID
2770 glClearColor(clearAttributes.isFogged, 0.0, 0.0, 1.0);
2771 glClear(GL_COLOR_BUFFER_BIT);
2772
2773 glDrawBuffers(4, RenderDrawList);
2774 }
2775 else
2776 {
2777 glClearColor(divide5bitBy31_LUT[clearColor.r], divide5bitBy31_LUT[clearColor.g], divide5bitBy31_LUT[clearColor.b], divide5bitBy31_LUT[clearColor.a]);
2778 glClearDepth((GLclampd)clearAttributes.depth / (GLclampd)0x00FFFFFF);
2779 glClearStencil(clearAttributes.opaquePolyID);
2780 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2781 }
2782
2783 return OGLERROR_NOERR;
2784 }
2785
SetPolygonIndex(const size_t index)2786 void OpenGLRenderer_1_2::SetPolygonIndex(const size_t index)
2787 {
2788 this->_currentPolyIndex = index;
2789 }
2790
SetupPolygon(const POLY & thePoly)2791 Render3DError OpenGLRenderer_1_2::SetupPolygon(const POLY &thePoly)
2792 {
2793 const PolygonAttributes attr = thePoly.getAttributes();
2794
2795 // Set up depth test mode
2796 static const GLenum oglDepthFunc[2] = {GL_LESS, GL_EQUAL};
2797 glDepthFunc(oglDepthFunc[attr.enableDepthEqualTest]);
2798
2799 // Set up culling mode
2800 static const GLenum oglCullingMode[4] = {GL_FRONT_AND_BACK, GL_FRONT, GL_BACK, 0};
2801 GLenum cullingMode = oglCullingMode[attr.surfaceCullingMode];
2802
2803 if (cullingMode == 0)
2804 {
2805 glDisable(GL_CULL_FACE);
2806 }
2807 else
2808 {
2809 glEnable(GL_CULL_FACE);
2810 glCullFace(cullingMode);
2811 }
2812
2813 // Set up depth write
2814 GLboolean enableDepthWrite = GL_TRUE;
2815
2816 // Handle shadow polys. Do this after checking for depth write, since shadow polys
2817 // can change this too.
2818 if (attr.polygonMode == POLYGON_MODE_SHADOW)
2819 {
2820 glEnable(GL_STENCIL_TEST);
2821
2822 if (attr.polygonID == 0)
2823 {
2824 //when the polyID is zero, we are writing the shadow mask.
2825 //set stencilbuf = 1 where the shadow volume is obstructed by geometry.
2826 //do not write color or depth information.
2827 glStencilFunc(GL_NOTEQUAL, 0x80, 0xFF);
2828 glStencilOp(GL_KEEP, GL_ZERO, GL_KEEP);
2829 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2830 enableDepthWrite = GL_FALSE;
2831 }
2832 else
2833 {
2834 //when the polyid is nonzero, we are drawing the shadow poly.
2835 //only draw the shadow poly where the stencilbuf==1.
2836 glStencilFunc(GL_EQUAL, 0, 0xFF);
2837 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
2838 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2839 enableDepthWrite = GL_TRUE;
2840 }
2841 }
2842 else if ( attr.isTranslucent || (std::find(this->_shadowPolyID.begin(), this->_shadowPolyID.end(), attr.polygonID) == this->_shadowPolyID.end()) )
2843 {
2844 glDisable(GL_STENCIL_TEST);
2845 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2846 enableDepthWrite = (!attr.isTranslucent || ( (attr.polygonMode == POLYGON_MODE_DECAL) && attr.isOpaque ) || attr.enableAlphaDepthWrite) ? GL_TRUE : GL_FALSE;
2847 }
2848 else
2849 {
2850 glEnable(GL_STENCIL_TEST);
2851 glStencilFunc(GL_ALWAYS, 0x80, 0xFF);
2852 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
2853 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2854 enableDepthWrite = GL_TRUE;
2855 }
2856
2857 glDepthMask(enableDepthWrite);
2858
2859 // Set up polygon attributes
2860 if (this->isShaderSupported)
2861 {
2862 OGLRenderRef &OGLRef = *this->ref;
2863 glUniform1i(OGLRef.uniformPolyMode, attr.polygonMode);
2864 glUniform1i(OGLRef.uniformPolyEnableFog, (attr.enableRenderFog) ? GL_TRUE : GL_FALSE);
2865 glUniform1f(OGLRef.uniformPolyAlpha, (!attr.isWireframe && attr.isTranslucent) ? divide5bitBy31_LUT[attr.alpha] : 1.0f);
2866 glUniform1i(OGLRef.uniformPolyID, attr.polygonID);
2867 glUniform1i(OGLRef.uniformPolyEnableDepthWrite, enableDepthWrite);
2868 glUniform1i(OGLRef.uniformPolySetNewDepthForTranslucent, (attr.enableAlphaDepthWrite) ? GL_TRUE : GL_FALSE);
2869 }
2870 else
2871 {
2872 // Set the texture blending mode
2873 static const GLint oglTexBlendMode[4] = {GL_MODULATE, GL_DECAL, GL_MODULATE, GL_MODULATE};
2874 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, oglTexBlendMode[attr.polygonMode]);
2875 }
2876
2877 return OGLERROR_NOERR;
2878 }
2879
SetupTexture(const POLY & thePoly,bool enableTexturing)2880 Render3DError OpenGLRenderer_1_2::SetupTexture(const POLY &thePoly, bool enableTexturing)
2881 {
2882 OGLRenderRef &OGLRef = *this->ref;
2883 const PolygonTexParams params = thePoly.getTexParams();
2884
2885 // Check if we need to use textures
2886 if (params.texFormat == TEXMODE_NONE || !enableTexturing)
2887 {
2888 if (this->isShaderSupported)
2889 {
2890 glUniform1i(OGLRef.uniformPolyEnableTexture, GL_FALSE);
2891 }
2892 else
2893 {
2894 glDisable(GL_TEXTURE_2D);
2895 }
2896
2897 return OGLERROR_NOERR;
2898 }
2899
2900 // Enable textures if they weren't already enabled
2901 if (this->isShaderSupported)
2902 {
2903 glUniform1i(OGLRef.uniformPolyEnableTexture, GL_TRUE);
2904 }
2905 else
2906 {
2907 glEnable(GL_TEXTURE_2D);
2908 }
2909
2910 TexCacheItem *newTexture = TexCache_SetTexture(TexFormat_32bpp, thePoly.texParam, thePoly.texPalette);
2911 if(newTexture != this->currTexture)
2912 {
2913 this->currTexture = newTexture;
2914 //has the ogl renderer initialized the texture?
2915 if(this->currTexture->GetDeleteCallback() == NULL)
2916 {
2917 this->currTexture->SetDeleteCallback(&texDeleteCallback, this, NULL);
2918
2919 if(OGLRef.freeTextureIDs.empty())
2920 {
2921 this->ExpandFreeTextures();
2922 }
2923
2924 this->currTexture->texid = (u64)OGLRef.freeTextureIDs.front();
2925 OGLRef.freeTextureIDs.pop();
2926
2927 glBindTexture(GL_TEXTURE_2D, (GLuint)this->currTexture->texid);
2928 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2929 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2930 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (params.enableRepeatS ? (params.enableMirroredRepeatS ? OGLRef.stateTexMirroredRepeat : GL_REPEAT) : GL_CLAMP_TO_EDGE));
2931 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (params.enableRepeatT ? (params.enableMirroredRepeatT ? OGLRef.stateTexMirroredRepeat : GL_REPEAT) : GL_CLAMP_TO_EDGE));
2932
2933 u32 *textureSrc = (u32 *)currTexture->decoded;
2934 size_t texWidth = currTexture->sizeX;
2935 size_t texHeight = currTexture->sizeY;
2936
2937 if (this->_textureDeposterizeBuffer != NULL)
2938 {
2939 this->TextureDeposterize(textureSrc, texWidth, texHeight);
2940 textureSrc = this->_textureDeposterizeBuffer;
2941 }
2942
2943 switch (this->_textureScalingFactor)
2944 {
2945 case 2:
2946 {
2947 this->TextureUpscale<2>(textureSrc, texWidth, texHeight);
2948 textureSrc = this->_textureUpscaleBuffer;
2949 break;
2950 }
2951
2952 case 4:
2953 {
2954 this->TextureUpscale<4>(textureSrc, texWidth, texHeight);
2955 textureSrc = this->_textureUpscaleBuffer;
2956 break;
2957 }
2958
2959 default:
2960 break;
2961 }
2962
2963 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureSrc);
2964 }
2965 else
2966 {
2967 //otherwise, just bind it
2968 glBindTexture(GL_TEXTURE_2D, (GLuint)this->currTexture->texid);
2969 }
2970
2971 if (this->isShaderSupported)
2972 {
2973 glUniform2f(OGLRef.uniformPolyTexScale, this->currTexture->invSizeX, this->currTexture->invSizeY);
2974 }
2975 else
2976 {
2977 glMatrixMode(GL_TEXTURE);
2978 glLoadIdentity();
2979 glScalef(this->currTexture->invSizeX, this->currTexture->invSizeY, 1.0f);
2980 }
2981 }
2982
2983 return OGLERROR_NOERR;
2984 }
2985
SetupViewport(const u32 viewportValue)2986 Render3DError OpenGLRenderer_1_2::SetupViewport(const u32 viewportValue)
2987 {
2988 const GLfloat wScalar = this->_framebufferWidth / GPU_FRAMEBUFFER_NATIVE_WIDTH;
2989 const GLfloat hScalar = this->_framebufferHeight / GPU_FRAMEBUFFER_NATIVE_HEIGHT;
2990
2991 VIEWPORT viewport;
2992 viewport.decode(viewportValue);
2993 glViewport(viewport.x * wScalar, viewport.y * hScalar, viewport.width * wScalar, viewport.height * hScalar);
2994
2995 return OGLERROR_NOERR;
2996 }
2997
Reset()2998 Render3DError OpenGLRenderer_1_2::Reset()
2999 {
3000 OGLRenderRef &OGLRef = *this->ref;
3001
3002 if(!BEGINGL())
3003 {
3004 return OGLERROR_BEGINGL_FAILED;
3005 }
3006
3007 glFinish();
3008
3009 if (!this->isShaderSupported)
3010 {
3011 glEnable(GL_NORMALIZE);
3012 glEnable(GL_TEXTURE_1D);
3013 glEnable(GL_TEXTURE_2D);
3014 glAlphaFunc(GL_GREATER, 0);
3015 glEnable(GL_ALPHA_TEST);
3016 glEnable(GL_BLEND);
3017 }
3018
3019 ENDGL();
3020
3021 this->_pixelReadNeedsFinish = false;
3022
3023 if (OGLRef.color4fBuffer != NULL)
3024 {
3025 memset(OGLRef.color4fBuffer, 0, VERTLIST_SIZE * 4 * sizeof(GLfloat));
3026 }
3027
3028 if (OGLRef.vertIndexBuffer != NULL)
3029 {
3030 memset(OGLRef.vertIndexBuffer, 0, OGLRENDER_VERT_INDEX_BUFFER_COUNT * sizeof(GLushort));
3031 }
3032
3033 this->currTexture = NULL;
3034 this->_currentPolyIndex = 0;
3035
3036 OGLRef.vtxPtrPosition = (GLvoid *)offsetof(VERT, coord);
3037 OGLRef.vtxPtrTexCoord = (GLvoid *)offsetof(VERT, texcoord);
3038 OGLRef.vtxPtrColor = (this->isShaderSupported) ? (GLvoid *)offsetof(VERT, color) : OGLRef.color4fBuffer;
3039
3040 memset(this->clearImageColor16Buffer, 0, sizeof(this->clearImageColor16Buffer));
3041 memset(this->clearImageDepthBuffer, 0, sizeof(this->clearImageDepthBuffer));
3042 memset(this->clearImagePolyIDBuffer, 0, sizeof(this->clearImagePolyIDBuffer));
3043 memset(this->clearImageFogBuffer, 0, sizeof(this->clearImageFogBuffer));
3044
3045 TexCache_Reset();
3046
3047 return OGLERROR_NOERR;
3048 }
3049
RenderFinish()3050 Render3DError OpenGLRenderer_1_2::RenderFinish()
3051 {
3052 if (!this->_renderNeedsFinish || !this->_pixelReadNeedsFinish)
3053 {
3054 return OGLERROR_NOERR;
3055 }
3056
3057 FragmentColor *framebufferMain = (this->_willFlushFramebufferRGBA6665) ? GPU->GetEngineMain()->Get3DFramebufferRGBA6665() : NULL;
3058 u16 *framebufferRGBA5551 = (this->_willFlushFramebufferRGBA5551) ? GPU->GetEngineMain()->Get3DFramebufferRGBA5551() : NULL;
3059
3060 if ( (framebufferMain != NULL) || (framebufferRGBA5551 != NULL) )
3061 {
3062 if(!BEGINGL())
3063 {
3064 return OGLERROR_BEGINGL_FAILED;
3065 }
3066
3067 if (this->isPBOSupported)
3068 {
3069 this->_mappedFramebuffer = (FragmentColor *__restrict)glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
3070 this->FlushFramebuffer(this->_mappedFramebuffer, framebufferMain, framebufferRGBA5551);
3071 }
3072 else
3073 {
3074 glReadPixels(0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_BGRA, GL_UNSIGNED_BYTE, this->_framebufferColor);
3075 this->FlushFramebuffer(this->_framebufferColor, framebufferMain, framebufferRGBA5551);
3076 }
3077
3078 ENDGL();
3079 }
3080
3081 this->_pixelReadNeedsFinish = false;
3082
3083 return OGLERROR_NOERR;
3084 }
3085
SetFramebufferSize(size_t w,size_t h)3086 Render3DError OpenGLRenderer_1_2::SetFramebufferSize(size_t w, size_t h)
3087 {
3088 OGLRenderRef &OGLRef = *this->ref;
3089
3090 if (w < GPU_FRAMEBUFFER_NATIVE_WIDTH || h < GPU_FRAMEBUFFER_NATIVE_HEIGHT)
3091 {
3092 return OGLERROR_NOERR;
3093 }
3094
3095 if (!BEGINGL())
3096 {
3097 return OGLERROR_BEGINGL_FAILED;
3098 }
3099
3100 if (this->isPBOSupported)
3101 {
3102 if (this->_mappedFramebuffer != NULL)
3103 {
3104 glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
3105 this->_mappedFramebuffer = NULL;
3106 }
3107 }
3108
3109 if (this->isFBOSupported)
3110 {
3111 glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_GColor);
3112 glBindTexture(GL_TEXTURE_2D, OGLRef.texGDepthStencilID);
3113 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8_EXT, w, h, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL);
3114 glBindTexture(GL_TEXTURE_2D, OGLRef.texGColorID);
3115 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
3116
3117 glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_GDepth);
3118 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
3119
3120 glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_GPolyID);
3121 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
3122
3123 glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_FogAttr);
3124 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
3125
3126 glActiveTextureARB(GL_TEXTURE0_ARB);
3127 glBindTexture(GL_TEXTURE_2D, OGLRef.texPostprocessFogID);
3128 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
3129 }
3130
3131 if (this->isMultisampledFBOSupported)
3132 {
3133 GLint maxSamples = 0;
3134 glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples);
3135
3136 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGColorID);
3137 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, w, h);
3138 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGDepthID);
3139 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, w, h);
3140 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGPolyID);
3141 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, w, h);
3142 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGFogAttrID);
3143 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, w, h);
3144 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGDepthStencilID);
3145 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_DEPTH24_STENCIL8_EXT, w, h);
3146 }
3147
3148 if (this->willFlipFramebufferOnGPU)
3149 {
3150 glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_FinalColor);
3151 glBindTexture(GL_TEXTURE_2D, OGLRef.texFinalColorID);
3152 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
3153 }
3154
3155 if (this->willConvertFramebufferOnGPU)
3156 {
3157 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboFramebufferRGBA6665ID);
3158 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA, w, h);
3159 }
3160
3161 const size_t newFramebufferColorSizeBytes = w * h * sizeof(FragmentColor);
3162
3163 this->_framebufferWidth = w;
3164 this->_framebufferHeight = h;
3165 this->_framebufferColorSizeBytes = newFramebufferColorSizeBytes;
3166
3167 if (this->isPBOSupported)
3168 {
3169 glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, newFramebufferColorSizeBytes, NULL, GL_STREAM_READ_ARB);
3170 this->_framebufferColor = NULL;
3171 }
3172 else
3173 {
3174 FragmentColor *oldFramebufferColor = this->_framebufferColor;
3175 FragmentColor *newFramebufferColor = (FragmentColor *)memalign_alloc_aligned(newFramebufferColorSizeBytes);
3176 this->_framebufferColor = newFramebufferColor;
3177 free_aligned(oldFramebufferColor);
3178 }
3179
3180 if (oglrender_framebufferDidResizeCallback != NULL)
3181 {
3182 oglrender_framebufferDidResizeCallback(w, h);
3183 }
3184
3185 ENDGL();
3186
3187 return OGLERROR_NOERR;
3188 }
3189
CreateToonTable()3190 Render3DError OpenGLRenderer_1_3::CreateToonTable()
3191 {
3192 OGLRenderRef &OGLRef = *this->ref;
3193 u16 tempToonTable[32];
3194 memset(tempToonTable, 0, sizeof(tempToonTable));
3195
3196 // The toon table is a special 1D texture where each pixel corresponds
3197 // to a specific color in the toon table.
3198 glGenTextures(1, &OGLRef.texToonTableID);
3199 glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_ToonTable);
3200 glBindTexture(GL_TEXTURE_1D, OGLRef.texToonTableID);
3201
3202 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3203 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3204 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
3205 glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 32, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, tempToonTable);
3206
3207 glActiveTexture(GL_TEXTURE0);
3208
3209 return OGLERROR_NOERR;
3210 }
3211
UpdateToonTable(const u16 * toonTableBuffer)3212 Render3DError OpenGLRenderer_1_3::UpdateToonTable(const u16 *toonTableBuffer)
3213 {
3214 glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_ToonTable);
3215 glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 32, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, toonTableBuffer);
3216
3217 return OGLERROR_NOERR;
3218 }
3219
UploadClearImage(const u16 * __restrict colorBuffer,const u32 * __restrict depthBuffer,const u8 * __restrict fogBuffer,const u8 * __restrict polyIDBuffer)3220 Render3DError OpenGLRenderer_1_3::UploadClearImage(const u16 *__restrict colorBuffer, const u32 *__restrict depthBuffer, const u8 *__restrict fogBuffer, const u8 *__restrict polyIDBuffer)
3221 {
3222 OGLRenderRef &OGLRef = *this->ref;
3223
3224 if (this->isShaderSupported)
3225 {
3226 for (size_t i = 0; i < GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT; i++)
3227 {
3228 OGLRef.workingCIDepthStencilBuffer[i] = (depthBuffer[i] << 8) | polyIDBuffer[i];
3229 OGLRef.workingCIDepthBuffer[i] = depthBuffer[i] | 0xFF000000;
3230 OGLRef.workingCIFogAttributesBuffer[i] = (fogBuffer[i]) ? 0xFF0000FF : 0xFF000000;
3231 OGLRef.workingCIPolyIDBuffer[i] = (GLuint)polyIDBuffer[i] | 0xFF000000;
3232 }
3233 }
3234 else
3235 {
3236 for (size_t i = 0; i < GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT; i++)
3237 {
3238 OGLRef.workingCIDepthStencilBuffer[i] = (depthBuffer[i] << 8) | polyIDBuffer[i];
3239 }
3240 }
3241
3242 glActiveTexture(GL_TEXTURE0);
3243
3244 glBindTexture(GL_TEXTURE_2D, OGLRef.texCIColorID);
3245 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, colorBuffer);
3246 glBindTexture(GL_TEXTURE_2D, OGLRef.texCIDepthStencilID);
3247 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, OGLRef.workingCIDepthStencilBuffer);
3248
3249 if (this->isShaderSupported)
3250 {
3251 glBindTexture(GL_TEXTURE_2D, OGLRef.texCIDepthID);
3252 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, OGLRef.workingCIDepthBuffer);
3253
3254 glBindTexture(GL_TEXTURE_2D, OGLRef.texCIFogAttrID);
3255 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, OGLRef.workingCIFogAttributesBuffer);
3256
3257 glBindTexture(GL_TEXTURE_2D, OGLRef.texCIPolyID);
3258 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, OGLRef.workingCIPolyIDBuffer);
3259 }
3260
3261 glBindTexture(GL_TEXTURE_2D, 0);
3262
3263 return OGLERROR_NOERR;
3264 }
3265
SetFramebufferSize(size_t w,size_t h)3266 Render3DError OpenGLRenderer_1_3::SetFramebufferSize(size_t w, size_t h)
3267 {
3268 OGLRenderRef &OGLRef = *this->ref;
3269
3270 if (w < GPU_FRAMEBUFFER_NATIVE_WIDTH || h < GPU_FRAMEBUFFER_NATIVE_HEIGHT)
3271 {
3272 return OGLERROR_NOERR;
3273 }
3274
3275 if (!BEGINGL())
3276 {
3277 return OGLERROR_BEGINGL_FAILED;
3278 }
3279
3280 if (this->isPBOSupported)
3281 {
3282 if (this->_mappedFramebuffer != NULL)
3283 {
3284 glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
3285 this->_mappedFramebuffer = NULL;
3286 }
3287 }
3288
3289 if (this->isFBOSupported)
3290 {
3291 glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GColor);
3292 glBindTexture(GL_TEXTURE_2D, OGLRef.texGDepthStencilID);
3293 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8_EXT, w, h, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL);
3294 glBindTexture(GL_TEXTURE_2D, OGLRef.texGColorID);
3295 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
3296
3297 glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GDepth);
3298 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
3299
3300 glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GPolyID);
3301 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
3302
3303 glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FogAttr);
3304 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
3305
3306 glActiveTexture(GL_TEXTURE0);
3307 glBindTexture(GL_TEXTURE_2D, OGLRef.texPostprocessFogID);
3308 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
3309 }
3310
3311 if (this->isMultisampledFBOSupported)
3312 {
3313 GLint maxSamples = 0;
3314 glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples);
3315
3316 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGColorID);
3317 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, w, h);
3318 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGDepthID);
3319 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, w, h);
3320 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGPolyID);
3321 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, w, h);
3322 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGFogAttrID);
3323 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, w, h);
3324 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGDepthStencilID);
3325 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_DEPTH24_STENCIL8_EXT, w, h);
3326 }
3327
3328 if (this->willFlipFramebufferOnGPU)
3329 {
3330 glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FinalColor);
3331 glBindTexture(GL_TEXTURE_2D, OGLRef.texFinalColorID);
3332 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
3333 }
3334
3335 if (this->willConvertFramebufferOnGPU)
3336 {
3337 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboFramebufferRGBA6665ID);
3338 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA, w, h);
3339 }
3340
3341 const size_t newFramebufferColorSizeBytes = w * h * sizeof(FragmentColor);
3342
3343 this->_framebufferWidth = w;
3344 this->_framebufferHeight = h;
3345 this->_framebufferColorSizeBytes = newFramebufferColorSizeBytes;
3346
3347 if (this->isPBOSupported)
3348 {
3349 glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, newFramebufferColorSizeBytes, NULL, GL_STREAM_READ_ARB);
3350 this->_framebufferColor = NULL;
3351 }
3352 else
3353 {
3354 FragmentColor *oldFramebufferColor = this->_framebufferColor;
3355 FragmentColor *newFramebufferColor = (FragmentColor *)memalign_alloc_aligned(newFramebufferColorSizeBytes);
3356 this->_framebufferColor = newFramebufferColor;
3357 free_aligned(oldFramebufferColor);
3358 }
3359
3360 if (oglrender_framebufferDidResizeCallback != NULL)
3361 {
3362 oglrender_framebufferDidResizeCallback(w, h);
3363 }
3364
3365 ENDGL();
3366
3367 return OGLERROR_NOERR;
3368 }
3369
InitFinalRenderStates(const std::set<std::string> * oglExtensionSet)3370 Render3DError OpenGLRenderer_1_4::InitFinalRenderStates(const std::set<std::string> *oglExtensionSet)
3371 {
3372 OGLRenderRef &OGLRef = *this->ref;
3373
3374 bool isBlendEquationSeparateSupported = this->IsExtensionPresent(oglExtensionSet, "GL_EXT_blend_equation_separate");
3375
3376 // Blending Support
3377 if (isBlendEquationSeparateSupported)
3378 {
3379 // we want to use alpha destination blending so we can track the last-rendered alpha value
3380 // test: new super mario brothers renders the stormclouds at the beginning
3381 glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, GL_DST_ALPHA);
3382 glBlendEquationSeparateEXT(GL_FUNC_ADD, GL_MAX);
3383 }
3384 else
3385 {
3386 glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_DST_ALPHA);
3387 }
3388
3389 // Mirrored Repeat Mode Support
3390 OGLRef.stateTexMirroredRepeat = GL_MIRRORED_REPEAT;
3391
3392 // Map the vertex list's colors with 4 floats per color. This is being done
3393 // because OpenGL needs 4-colors per vertex to support translucency. (The DS
3394 // uses 3-colors per vertex, and adds alpha through the poly, so we can't
3395 // simply reference the colors+alpha from just the vertices by themselves.)
3396 OGLRef.color4fBuffer = (this->isShaderSupported) ? NULL : new GLfloat[VERTLIST_SIZE * 4];
3397
3398 // If VBOs aren't supported, then we need to create the index buffer on the
3399 // client side so that we have a buffer to update.
3400 OGLRef.vertIndexBuffer = (this->isVBOSupported) ? NULL : new GLushort[OGLRENDER_VERT_INDEX_BUFFER_COUNT];
3401
3402 return OGLERROR_NOERR;
3403 }
3404
~OpenGLRenderer_1_5()3405 OpenGLRenderer_1_5::~OpenGLRenderer_1_5()
3406 {
3407 glFinish();
3408
3409 DestroyVAOs();
3410 DestroyVBOs();
3411 DestroyPBOs();
3412 }
3413
CreateVBOs()3414 Render3DError OpenGLRenderer_1_5::CreateVBOs()
3415 {
3416 OGLRenderRef &OGLRef = *this->ref;
3417
3418 glGenBuffers(1, &OGLRef.vboGeometryVtxID);
3419 glGenBuffers(1, &OGLRef.iboGeometryIndexID);
3420 glGenBuffers(1, &OGLRef.vboPostprocessVtxID);
3421 glGenBuffers(1, &OGLRef.iboPostprocessIndexID);
3422
3423 glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboGeometryVtxID);
3424 glBufferData(GL_ARRAY_BUFFER, VERTLIST_SIZE * sizeof(VERT), NULL, GL_STREAM_DRAW);
3425 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboGeometryIndexID);
3426 glBufferData(GL_ELEMENT_ARRAY_BUFFER, OGLRENDER_VERT_INDEX_BUFFER_COUNT * sizeof(GLushort), NULL, GL_STREAM_DRAW);
3427
3428 glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboPostprocessVtxID);
3429 glBufferData(GL_ARRAY_BUFFER, sizeof(PostprocessVtxBuffer), PostprocessVtxBuffer, GL_STATIC_DRAW);
3430 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboPostprocessIndexID);
3431 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(PostprocessElementBuffer), PostprocessElementBuffer, GL_STATIC_DRAW);
3432
3433 glBindBuffer(GL_ARRAY_BUFFER, 0);
3434 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
3435
3436 return OGLERROR_NOERR;
3437 }
3438
DestroyVBOs()3439 void OpenGLRenderer_1_5::DestroyVBOs()
3440 {
3441 if (!this->isVBOSupported)
3442 {
3443 return;
3444 }
3445
3446 OGLRenderRef &OGLRef = *this->ref;
3447
3448 glBindBuffer(GL_ARRAY_BUFFER, 0);
3449 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
3450
3451 glDeleteBuffers(1, &OGLRef.vboGeometryVtxID);
3452 glDeleteBuffers(1, &OGLRef.iboGeometryIndexID);
3453 glDeleteBuffers(1, &OGLRef.vboPostprocessVtxID);
3454 glDeleteBuffers(1, &OGLRef.iboPostprocessIndexID);
3455
3456 this->isVBOSupported = false;
3457 }
3458
CreateVAOs()3459 Render3DError OpenGLRenderer_1_5::CreateVAOs()
3460 {
3461 OGLRenderRef &OGLRef = *this->ref;
3462
3463 glGenVertexArrays(1, &OGLRef.vaoGeometryStatesID);
3464 glGenVertexArrays(1, &OGLRef.vaoPostprocessStatesID);
3465
3466 glBindVertexArray(OGLRef.vaoGeometryStatesID);
3467 glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboGeometryVtxID);
3468 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboGeometryIndexID);
3469
3470 glEnableVertexAttribArray(OGLVertexAttributeID_Position);
3471 glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0);
3472 glEnableVertexAttribArray(OGLVertexAttributeID_Color);
3473 glVertexAttribPointer(OGLVertexAttributeID_Position, 4, GL_FLOAT, GL_FALSE, sizeof(VERT), (const GLvoid *)offsetof(VERT, coord));
3474 glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(VERT), (const GLvoid *)offsetof(VERT, texcoord));
3475 glVertexAttribPointer(OGLVertexAttributeID_Color, 3, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(VERT), (const GLvoid *)offsetof(VERT, color));
3476
3477 glBindVertexArray(0);
3478
3479 glBindVertexArray(OGLRef.vaoPostprocessStatesID);
3480 glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboPostprocessVtxID);
3481 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboPostprocessIndexID);
3482
3483 glEnableVertexAttribArray(OGLVertexAttributeID_Position);
3484 glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0);
3485 glVertexAttribPointer(OGLVertexAttributeID_Position, 2, GL_FLOAT, GL_FALSE, 0, 0);
3486 glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)(sizeof(GLfloat) * 8));
3487
3488 glBindVertexArray(0);
3489
3490 return OGLERROR_NOERR;
3491 }
3492
EnableVertexAttributes()3493 Render3DError OpenGLRenderer_1_5::EnableVertexAttributes()
3494 {
3495 OGLRenderRef &OGLRef = *this->ref;
3496
3497 if (this->isVAOSupported)
3498 {
3499 glBindVertexArray(OGLRef.vaoGeometryStatesID);
3500 }
3501 else
3502 {
3503 if (this->isShaderSupported)
3504 {
3505 glEnableVertexAttribArray(OGLVertexAttributeID_Position);
3506 glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0);
3507 glEnableVertexAttribArray(OGLVertexAttributeID_Color);
3508 glVertexAttribPointer(OGLVertexAttributeID_Position, 4, GL_FLOAT, GL_FALSE, sizeof(VERT), OGLRef.vtxPtrPosition);
3509 glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(VERT), OGLRef.vtxPtrTexCoord);
3510 glVertexAttribPointer(OGLVertexAttributeID_Color, 3, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(VERT), OGLRef.vtxPtrColor);
3511 }
3512 else
3513 {
3514 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
3515 glEnableClientState(GL_COLOR_ARRAY);
3516 glEnableClientState(GL_VERTEX_ARRAY);
3517
3518 glBindBuffer(GL_ARRAY_BUFFER, 0);
3519 glColorPointer(4, GL_FLOAT, 0, OGLRef.vtxPtrColor);
3520
3521 glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboGeometryVtxID);
3522 glVertexPointer(4, GL_FLOAT, sizeof(VERT), OGLRef.vtxPtrPosition);
3523 glTexCoordPointer(2, GL_FLOAT, sizeof(VERT), OGLRef.vtxPtrTexCoord);
3524 }
3525 }
3526
3527 glActiveTexture(GL_TEXTURE0);
3528
3529 return OGLERROR_NOERR;
3530 }
3531
DisableVertexAttributes()3532 Render3DError OpenGLRenderer_1_5::DisableVertexAttributes()
3533 {
3534 if (this->isVAOSupported)
3535 {
3536 glBindVertexArray(0);
3537 }
3538 else
3539 {
3540 if (this->isShaderSupported)
3541 {
3542 glDisableVertexAttribArray(OGLVertexAttributeID_Position);
3543 glDisableVertexAttribArray(OGLVertexAttributeID_TexCoord0);
3544 glDisableVertexAttribArray(OGLVertexAttributeID_Color);
3545 }
3546 else
3547 {
3548 glDisableClientState(GL_VERTEX_ARRAY);
3549 glDisableClientState(GL_COLOR_ARRAY);
3550 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
3551 }
3552 }
3553
3554 return OGLERROR_NOERR;
3555 }
3556
BeginRender(const GFX3D & engine)3557 Render3DError OpenGLRenderer_1_5::BeginRender(const GFX3D &engine)
3558 {
3559 OGLRenderRef &OGLRef = *this->ref;
3560
3561 if(!BEGINGL())
3562 {
3563 return OGLERROR_BEGINGL_FAILED;
3564 }
3565
3566 if (this->isShaderSupported)
3567 {
3568 glUseProgram(OGLRef.programGeometryID);
3569 glUniform1i(OGLRef.uniformStateToonShadingMode, engine.renderState.shading);
3570 glUniform1i(OGLRef.uniformStateEnableAlphaTest, (engine.renderState.enableAlphaTest) ? GL_TRUE : GL_FALSE);
3571 glUniform1i(OGLRef.uniformStateEnableAntialiasing, (engine.renderState.enableAntialiasing) ? GL_TRUE : GL_FALSE);
3572 glUniform1i(OGLRef.uniformStateEnableEdgeMarking, (engine.renderState.enableEdgeMarking) ? GL_TRUE : GL_FALSE);
3573 glUniform1i(OGLRef.uniformStateUseWDepth, (engine.renderState.wbuffer) ? GL_TRUE : GL_FALSE);
3574 glUniform1f(OGLRef.uniformStateAlphaTestRef, divide5bitBy31_LUT[engine.renderState.alphaTestRef]);
3575 }
3576 else
3577 {
3578 if(engine.renderState.enableAlphaTest && (engine.renderState.alphaTestRef > 0))
3579 {
3580 glAlphaFunc(GL_GEQUAL, divide5bitBy31_LUT[engine.renderState.alphaTestRef]);
3581 }
3582 else
3583 {
3584 glAlphaFunc(GL_GREATER, 0);
3585 }
3586
3587 glMatrixMode(GL_PROJECTION);
3588 glLoadIdentity();
3589 }
3590
3591 glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboGeometryVtxID);
3592 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboGeometryIndexID);
3593
3594 size_t vertIndexCount = 0;
3595 GLushort *indexPtr = (GLushort *)glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
3596
3597 for (size_t i = 0; i < engine.polylist->count; i++)
3598 {
3599 const POLY *thePoly = &engine.polylist->list[engine.indexlist.list[i]];
3600 const size_t polyType = thePoly->type;
3601
3602 for (size_t j = 0; j < polyType; j++)
3603 {
3604 const GLushort vertIndex = thePoly->vertIndexes[j];
3605
3606 // While we're looping through our vertices, add each vertex index to
3607 // a buffer. For GFX3D_QUADS and GFX3D_QUAD_STRIP, we also add additional
3608 // vertices here to convert them to GL_TRIANGLES, which are much easier
3609 // to work with and won't be deprecated in future OpenGL versions.
3610 indexPtr[vertIndexCount++] = vertIndex;
3611 if (thePoly->vtxFormat == GFX3D_QUADS || thePoly->vtxFormat == GFX3D_QUAD_STRIP)
3612 {
3613 if (j == 2)
3614 {
3615 indexPtr[vertIndexCount++] = vertIndex;
3616 }
3617 else if (j == 3)
3618 {
3619 indexPtr[vertIndexCount++] = thePoly->vertIndexes[0];
3620 }
3621 }
3622 }
3623 }
3624
3625 glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
3626 glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(VERT) * engine.vertlist->count, engine.vertlist);
3627
3628 return OGLERROR_NOERR;
3629 }
3630
InitExtensions()3631 Render3DError OpenGLRenderer_2_0::InitExtensions()
3632 {
3633 Render3DError error = OGLERROR_NOERR;
3634
3635 // Get OpenGL extensions
3636 std::set<std::string> oglExtensionSet;
3637 this->GetExtensionSet(&oglExtensionSet);
3638
3639 // Initialize OpenGL
3640 this->InitTables();
3641
3642 // Load and create shaders. Return on any error, since a v2.0 driver will assume that shaders are available.
3643 this->isShaderSupported = true;
3644
3645 std::string vertexShaderProgram;
3646 std::string fragmentShaderProgram;
3647 error = this->LoadGeometryShaders(vertexShaderProgram, fragmentShaderProgram);
3648 if (error != OGLERROR_NOERR)
3649 {
3650 this->isShaderSupported = false;
3651 return error;
3652 }
3653
3654 error = this->InitGeometryProgram(vertexShaderProgram, fragmentShaderProgram);
3655 if (error != OGLERROR_NOERR)
3656 {
3657 this->isShaderSupported = false;
3658 return error;
3659 }
3660
3661 std::string edgeMarkVtxShaderString = std::string(EdgeMarkVtxShader_100);
3662 std::string edgeMarkFragShaderString = std::string(EdgeMarkFragShader_100);
3663 std::string fogVtxShaderString = std::string(FogVtxShader_100);
3664 std::string fogFragShaderString = std::string(FogFragShader_100);
3665 std::string framebufferOutputVtxShaderString = std::string(FramebufferOutputVtxShader_100);
3666 std::string framebufferOutputRGBA6665FragShaderString = std::string(FramebufferOutputRGBA6665FragShader_100);
3667 std::string framebufferOutputRGBA8888FragShaderString = std::string(FramebufferOutputRGBA8888FragShader_100);
3668 error = this->InitPostprocessingPrograms(edgeMarkVtxShaderString,
3669 edgeMarkFragShaderString,
3670 fogVtxShaderString,
3671 fogFragShaderString,
3672 framebufferOutputVtxShaderString,
3673 framebufferOutputRGBA6665FragShaderString,
3674 framebufferOutputRGBA8888FragShaderString);
3675 if (error != OGLERROR_NOERR)
3676 {
3677 this->DestroyGeometryProgram();
3678 this->isShaderSupported = false;
3679 }
3680
3681 this->isVBOSupported = true;
3682 this->CreateVBOs();
3683
3684 this->isPBOSupported = this->IsExtensionPresent(&oglExtensionSet, "GL_ARB_vertex_buffer_object") &&
3685 (this->IsExtensionPresent(&oglExtensionSet, "GL_ARB_pixel_buffer_object") ||
3686 this->IsExtensionPresent(&oglExtensionSet, "GL_EXT_pixel_buffer_object"));
3687 if (this->isPBOSupported)
3688 {
3689 this->CreatePBOs();
3690 }
3691
3692 this->isVAOSupported = this->isShaderSupported &&
3693 this->isVBOSupported &&
3694 (this->IsExtensionPresent(&oglExtensionSet, "GL_ARB_vertex_array_object") ||
3695 this->IsExtensionPresent(&oglExtensionSet, "GL_APPLE_vertex_array_object"));
3696 if (this->isVAOSupported)
3697 {
3698 this->CreateVAOs();
3699 }
3700
3701 // Don't use ARB versions since we're using the EXT versions for backwards compatibility.
3702 this->isFBOSupported = this->IsExtensionPresent(&oglExtensionSet, "GL_EXT_framebuffer_object") &&
3703 this->IsExtensionPresent(&oglExtensionSet, "GL_EXT_framebuffer_blit") &&
3704 this->IsExtensionPresent(&oglExtensionSet, "GL_EXT_packed_depth_stencil");
3705 if (this->isFBOSupported)
3706 {
3707 this->willFlipFramebufferOnGPU = true;
3708 this->willConvertFramebufferOnGPU = (this->isShaderSupported && this->isVAOSupported && this->isPBOSupported && this->isFBOSupported);
3709
3710 error = this->CreateFBOs();
3711 if (error != OGLERROR_NOERR)
3712 {
3713 this->isFBOSupported = false;
3714 }
3715 }
3716 else
3717 {
3718 INFO("OpenGL: FBOs are unsupported. Some emulation features will be disabled.\n");
3719 }
3720
3721 // Set these again after FBO creation just in case FBO creation fails.
3722 this->willFlipFramebufferOnGPU = this->isFBOSupported;
3723 this->willConvertFramebufferOnGPU = (this->isShaderSupported && this->isVAOSupported && this->isPBOSupported && this->isFBOSupported);
3724
3725 // Don't use ARB versions since we're using the EXT versions for backwards compatibility.
3726 this->isMultisampledFBOSupported = this->isFBOSupported &&
3727 this->IsExtensionPresent(&oglExtensionSet, "GL_EXT_framebuffer_multisample");
3728 if (this->isMultisampledFBOSupported)
3729 {
3730 error = this->CreateMultisampledFBO();
3731 if (error != OGLERROR_NOERR)
3732 {
3733 this->isMultisampledFBOSupported = false;
3734 }
3735 }
3736 else
3737 {
3738 INFO("OpenGL: Multisampled FBOs are unsupported. Multisample antialiasing will be disabled.\n");
3739 }
3740
3741 this->InitTextures();
3742 this->InitFinalRenderStates(&oglExtensionSet); // This must be done last
3743
3744 return OGLERROR_NOERR;
3745 }
3746
InitFinalRenderStates(const std::set<std::string> * oglExtensionSet)3747 Render3DError OpenGLRenderer_2_0::InitFinalRenderStates(const std::set<std::string> *oglExtensionSet)
3748 {
3749 OGLRenderRef &OGLRef = *this->ref;
3750
3751 // we want to use alpha destination blending so we can track the last-rendered alpha value
3752 // test: new super mario brothers renders the stormclouds at the beginning
3753
3754 // Blending Support
3755 glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, GL_DST_ALPHA);
3756 glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX);
3757
3758 // Mirrored Repeat Mode Support
3759 OGLRef.stateTexMirroredRepeat = GL_MIRRORED_REPEAT;
3760
3761 // Ignore our color buffer since we'll transfer the polygon alpha through a uniform.
3762 OGLRef.color4fBuffer = NULL;
3763
3764 // VBOs are supported here, so just use the index buffer on the GPU.
3765 OGLRef.vertIndexBuffer = NULL;
3766
3767 return OGLERROR_NOERR;
3768 }
3769
InitPostprocessingPrograms(const std::string & edgeMarkVtxShader,const std::string & edgeMarkFragShader,const std::string & fogVtxShader,const std::string & fogFragShader,const std::string & framebufferOutputVtxShader,const std::string & framebufferOutputRGBA6665FragShader,const std::string & framebufferOutputRGBA8888FragShader)3770 Render3DError OpenGLRenderer_2_0::InitPostprocessingPrograms(const std::string &edgeMarkVtxShader,
3771 const std::string &edgeMarkFragShader,
3772 const std::string &fogVtxShader,
3773 const std::string &fogFragShader,
3774 const std::string &framebufferOutputVtxShader,
3775 const std::string &framebufferOutputRGBA6665FragShader,
3776 const std::string &framebufferOutputRGBA8888FragShader)
3777 {
3778 Render3DError error = OGLERROR_NOERR;
3779 OGLRenderRef &OGLRef = *this->ref;
3780
3781 OGLRef.vertexEdgeMarkShaderID = glCreateShader(GL_VERTEX_SHADER);
3782 if(!OGLRef.vertexEdgeMarkShaderID)
3783 {
3784 INFO("OpenGL: Failed to create the edge mark vertex shader.\n");
3785 return OGLERROR_SHADER_CREATE_ERROR;
3786 }
3787
3788 const char *edgeMarkVtxShaderCStr = edgeMarkVtxShader.c_str();
3789 glShaderSource(OGLRef.vertexEdgeMarkShaderID, 1, (const GLchar **)&edgeMarkVtxShaderCStr, NULL);
3790 glCompileShader(OGLRef.vertexEdgeMarkShaderID);
3791 if (!this->ValidateShaderCompile(OGLRef.vertexEdgeMarkShaderID))
3792 {
3793 glDeleteShader(OGLRef.vertexEdgeMarkShaderID);
3794 INFO("OpenGL: Failed to compile the edge mark vertex shader.\n");
3795 return OGLERROR_SHADER_CREATE_ERROR;
3796 }
3797
3798 OGLRef.fragmentEdgeMarkShaderID = glCreateShader(GL_FRAGMENT_SHADER);
3799 if(!OGLRef.fragmentEdgeMarkShaderID)
3800 {
3801 glDeleteShader(OGLRef.vertexEdgeMarkShaderID);
3802 INFO("OpenGL: Failed to create the edge mark fragment shader.\n");
3803 return OGLERROR_SHADER_CREATE_ERROR;
3804 }
3805
3806 const char *edgeMarkFragShaderCStr = edgeMarkFragShader.c_str();
3807 glShaderSource(OGLRef.fragmentEdgeMarkShaderID, 1, (const GLchar **)&edgeMarkFragShaderCStr, NULL);
3808 glCompileShader(OGLRef.fragmentEdgeMarkShaderID);
3809 if (!this->ValidateShaderCompile(OGLRef.fragmentEdgeMarkShaderID))
3810 {
3811 glDeleteShader(OGLRef.vertexEdgeMarkShaderID);
3812 glDeleteShader(OGLRef.fragmentEdgeMarkShaderID);
3813 INFO("OpenGL: Failed to compile the edge mark fragment shader.\n");
3814 return OGLERROR_SHADER_CREATE_ERROR;
3815 }
3816
3817 OGLRef.programEdgeMarkID = glCreateProgram();
3818 if(!OGLRef.programEdgeMarkID)
3819 {
3820 glDeleteShader(OGLRef.vertexEdgeMarkShaderID);
3821 glDeleteShader(OGLRef.fragmentEdgeMarkShaderID);
3822 INFO("OpenGL: Failed to create the edge mark shader program.\n");
3823 return OGLERROR_SHADER_CREATE_ERROR;
3824 }
3825
3826 glAttachShader(OGLRef.programEdgeMarkID, OGLRef.vertexEdgeMarkShaderID);
3827 glAttachShader(OGLRef.programEdgeMarkID, OGLRef.fragmentEdgeMarkShaderID);
3828
3829 error = this->InitEdgeMarkProgramBindings();
3830 if (error != OGLERROR_NOERR)
3831 {
3832 glDetachShader(OGLRef.programEdgeMarkID, OGLRef.vertexEdgeMarkShaderID);
3833 glDetachShader(OGLRef.programEdgeMarkID, OGLRef.fragmentEdgeMarkShaderID);
3834 glDeleteProgram(OGLRef.programEdgeMarkID);
3835 glDeleteShader(OGLRef.vertexEdgeMarkShaderID);
3836 glDeleteShader(OGLRef.fragmentEdgeMarkShaderID);
3837 INFO("OpenGL: Failed to make the edge mark shader bindings.\n");
3838 return error;
3839 }
3840
3841 glLinkProgram(OGLRef.programEdgeMarkID);
3842 if (!this->ValidateShaderProgramLink(OGLRef.programEdgeMarkID))
3843 {
3844 glDetachShader(OGLRef.programEdgeMarkID, OGLRef.vertexEdgeMarkShaderID);
3845 glDetachShader(OGLRef.programEdgeMarkID, OGLRef.fragmentEdgeMarkShaderID);
3846 glDeleteProgram(OGLRef.programEdgeMarkID);
3847 glDeleteShader(OGLRef.vertexEdgeMarkShaderID);
3848 glDeleteShader(OGLRef.fragmentEdgeMarkShaderID);
3849 INFO("OpenGL: Failed to link the edge mark shader program.\n");
3850 return OGLERROR_SHADER_CREATE_ERROR;
3851 }
3852
3853 glValidateProgram(OGLRef.programEdgeMarkID);
3854 this->InitEdgeMarkProgramShaderLocations();
3855
3856 // ------------------------------------------
3857
3858 OGLRef.vertexFogShaderID = glCreateShader(GL_VERTEX_SHADER);
3859 if(!OGLRef.vertexFogShaderID)
3860 {
3861 INFO("OpenGL: Failed to create the fog vertex shader.\n");
3862 return OGLERROR_SHADER_CREATE_ERROR;
3863 }
3864
3865 const char *fogVtxShaderCStr = fogVtxShader.c_str();
3866 glShaderSource(OGLRef.vertexFogShaderID, 1, (const GLchar **)&fogVtxShaderCStr, NULL);
3867 glCompileShader(OGLRef.vertexFogShaderID);
3868 if (!this->ValidateShaderCompile(OGLRef.vertexFogShaderID))
3869 {
3870 glDeleteShader(OGLRef.vertexFogShaderID);
3871 INFO("OpenGL: Failed to compile the fog vertex shader.\n");
3872 return OGLERROR_SHADER_CREATE_ERROR;
3873 }
3874
3875 OGLRef.fragmentFogShaderID = glCreateShader(GL_FRAGMENT_SHADER);
3876 if(!OGLRef.fragmentFogShaderID)
3877 {
3878 glDeleteShader(OGLRef.vertexFogShaderID);
3879 INFO("OpenGL: Failed to create the fog fragment shader.\n");
3880 return OGLERROR_SHADER_CREATE_ERROR;
3881 }
3882
3883 const char *fogFragShaderCStr = fogFragShader.c_str();
3884 glShaderSource(OGLRef.fragmentFogShaderID, 1, (const GLchar **)&fogFragShaderCStr, NULL);
3885 glCompileShader(OGLRef.fragmentFogShaderID);
3886 if (!this->ValidateShaderCompile(OGLRef.fragmentFogShaderID))
3887 {
3888 glDeleteShader(OGLRef.vertexFogShaderID);
3889 glDeleteShader(OGLRef.fragmentFogShaderID);
3890 INFO("OpenGL: Failed to compile the fog fragment shader.\n");
3891 return OGLERROR_SHADER_CREATE_ERROR;
3892 }
3893
3894 OGLRef.programFogID = glCreateProgram();
3895 if(!OGLRef.programFogID)
3896 {
3897 glDeleteShader(OGLRef.vertexFogShaderID);
3898 glDeleteShader(OGLRef.fragmentFogShaderID);
3899 INFO("OpenGL: Failed to create the fog shader program.\n");
3900 return OGLERROR_SHADER_CREATE_ERROR;
3901 }
3902
3903 glAttachShader(OGLRef.programFogID, OGLRef.vertexFogShaderID);
3904 glAttachShader(OGLRef.programFogID, OGLRef.fragmentFogShaderID);
3905
3906 error = this->InitFogProgramBindings();
3907 if (error != OGLERROR_NOERR)
3908 {
3909 glDetachShader(OGLRef.programFogID, OGLRef.vertexFogShaderID);
3910 glDetachShader(OGLRef.programFogID, OGLRef.fragmentFogShaderID);
3911 glDeleteProgram(OGLRef.programFogID);
3912 glDeleteShader(OGLRef.vertexFogShaderID);
3913 glDeleteShader(OGLRef.fragmentFogShaderID);
3914 INFO("OpenGL: Failed to make the fog shader bindings.\n");
3915 return error;
3916 }
3917
3918 glLinkProgram(OGLRef.programFogID);
3919 if (!this->ValidateShaderProgramLink(OGLRef.programFogID))
3920 {
3921 glDetachShader(OGLRef.programFogID, OGLRef.vertexFogShaderID);
3922 glDetachShader(OGLRef.programFogID, OGLRef.fragmentFogShaderID);
3923 glDeleteProgram(OGLRef.programFogID);
3924 glDeleteShader(OGLRef.vertexFogShaderID);
3925 glDeleteShader(OGLRef.fragmentFogShaderID);
3926 INFO("OpenGL: Failed to link the fog shader program.\n");
3927 return OGLERROR_SHADER_CREATE_ERROR;
3928 }
3929
3930 glValidateProgram(OGLRef.programFogID);
3931 this->InitFogProgramShaderLocations();
3932
3933 // ------------------------------------------
3934
3935 OGLRef.vertexFramebufferOutputShaderID = glCreateShader(GL_VERTEX_SHADER);
3936 if(!OGLRef.vertexFramebufferOutputShaderID)
3937 {
3938 INFO("OpenGL: Failed to create the framebuffer output vertex shader.\n");
3939 return OGLERROR_SHADER_CREATE_ERROR;
3940 }
3941
3942 const char *framebufferOutputVtxShaderCStr = framebufferOutputVtxShader.c_str();
3943 glShaderSource(OGLRef.vertexFramebufferOutputShaderID, 1, (const GLchar **)&framebufferOutputVtxShaderCStr, NULL);
3944 glCompileShader(OGLRef.vertexFramebufferOutputShaderID);
3945 if (!this->ValidateShaderCompile(OGLRef.vertexFramebufferOutputShaderID))
3946 {
3947 glDeleteShader(OGLRef.vertexFramebufferOutputShaderID);
3948 INFO("OpenGL: Failed to compile the framebuffer output vertex shader.\n");
3949 return OGLERROR_SHADER_CREATE_ERROR;
3950 }
3951
3952 OGLRef.fragmentFramebufferRGBA6665OutputShaderID = glCreateShader(GL_FRAGMENT_SHADER);
3953 if(!OGLRef.fragmentFramebufferRGBA6665OutputShaderID)
3954 {
3955 glDeleteShader(OGLRef.vertexFramebufferOutputShaderID);
3956 INFO("OpenGL: Failed to create the framebuffer output fragment shader.\n");
3957 return OGLERROR_SHADER_CREATE_ERROR;
3958 }
3959
3960 OGLRef.fragmentFramebufferRGBA8888OutputShaderID = glCreateShader(GL_FRAGMENT_SHADER);
3961 if(!OGLRef.fragmentFramebufferRGBA8888OutputShaderID)
3962 {
3963 glDeleteShader(OGLRef.vertexFramebufferOutputShaderID);
3964 glDeleteShader(OGLRef.fragmentFramebufferRGBA6665OutputShaderID);
3965 INFO("OpenGL: Failed to create the framebuffer output fragment shader.\n");
3966 return OGLERROR_SHADER_CREATE_ERROR;
3967 }
3968
3969 const char *framebufferOutputRGBA6665FragShaderCStr = framebufferOutputRGBA6665FragShader.c_str();
3970 glShaderSource(OGLRef.fragmentFramebufferRGBA6665OutputShaderID, 1, (const GLchar **)&framebufferOutputRGBA6665FragShaderCStr, NULL);
3971 glCompileShader(OGLRef.fragmentFramebufferRGBA6665OutputShaderID);
3972 if (!this->ValidateShaderCompile(OGLRef.fragmentFramebufferRGBA6665OutputShaderID))
3973 {
3974 glDeleteShader(OGLRef.vertexFramebufferOutputShaderID);
3975 glDeleteShader(OGLRef.fragmentFramebufferRGBA6665OutputShaderID);
3976 glDeleteShader(OGLRef.fragmentFramebufferRGBA8888OutputShaderID);
3977 INFO("OpenGL: Failed to compile the framebuffer output fragment shader.\n");
3978 return OGLERROR_SHADER_CREATE_ERROR;
3979 }
3980
3981 const char *framebufferOutputRGBA8888FragShaderCStr = framebufferOutputRGBA8888FragShader.c_str();
3982 glShaderSource(OGLRef.fragmentFramebufferRGBA8888OutputShaderID, 1, (const GLchar **)&framebufferOutputRGBA8888FragShaderCStr, NULL);
3983 glCompileShader(OGLRef.fragmentFramebufferRGBA8888OutputShaderID);
3984 if (!this->ValidateShaderCompile(OGLRef.fragmentFramebufferRGBA8888OutputShaderID))
3985 {
3986 glDeleteShader(OGLRef.vertexFramebufferOutputShaderID);
3987 glDeleteShader(OGLRef.fragmentFramebufferRGBA6665OutputShaderID);
3988 glDeleteShader(OGLRef.fragmentFramebufferRGBA8888OutputShaderID);
3989 INFO("OpenGL: Failed to compile the framebuffer output fragment shader.\n");
3990 return OGLERROR_SHADER_CREATE_ERROR;
3991 }
3992
3993 OGLRef.programFramebufferRGBA6665OutputID = glCreateProgram();
3994 if(!OGLRef.programFramebufferRGBA6665OutputID)
3995 {
3996 glDeleteShader(OGLRef.vertexFramebufferOutputShaderID);
3997 glDeleteShader(OGLRef.fragmentFramebufferRGBA6665OutputShaderID);
3998 glDeleteShader(OGLRef.fragmentFramebufferRGBA8888OutputShaderID);
3999 INFO("OpenGL: Failed to create the framebuffer output shader program.\n");
4000 return OGLERROR_SHADER_CREATE_ERROR;
4001 }
4002
4003 OGLRef.programFramebufferRGBA8888OutputID = glCreateProgram();
4004 if(!OGLRef.programFramebufferRGBA8888OutputID)
4005 {
4006 glDeleteShader(OGLRef.vertexFramebufferOutputShaderID);
4007 glDeleteShader(OGLRef.fragmentFramebufferRGBA6665OutputShaderID);
4008 glDeleteShader(OGLRef.fragmentFramebufferRGBA8888OutputShaderID);
4009 INFO("OpenGL: Failed to create the framebuffer output shader program.\n");
4010 return OGLERROR_SHADER_CREATE_ERROR;
4011 }
4012
4013 glAttachShader(OGLRef.programFramebufferRGBA6665OutputID, OGLRef.vertexFramebufferOutputShaderID);
4014 glAttachShader(OGLRef.programFramebufferRGBA6665OutputID, OGLRef.fragmentFramebufferRGBA6665OutputShaderID);
4015 glAttachShader(OGLRef.programFramebufferRGBA8888OutputID, OGLRef.vertexFramebufferOutputShaderID);
4016 glAttachShader(OGLRef.programFramebufferRGBA8888OutputID, OGLRef.fragmentFramebufferRGBA8888OutputShaderID);
4017
4018 error = this->InitFramebufferOutputProgramBindings();
4019 if (error != OGLERROR_NOERR)
4020 {
4021 glDetachShader(OGLRef.programFramebufferRGBA6665OutputID, OGLRef.vertexFramebufferOutputShaderID);
4022 glDetachShader(OGLRef.programFramebufferRGBA6665OutputID, OGLRef.fragmentFramebufferRGBA6665OutputShaderID);
4023 glDetachShader(OGLRef.programFramebufferRGBA8888OutputID, OGLRef.vertexFramebufferOutputShaderID);
4024 glDetachShader(OGLRef.programFramebufferRGBA8888OutputID, OGLRef.fragmentFramebufferRGBA8888OutputShaderID);
4025
4026 glDeleteProgram(OGLRef.programFramebufferRGBA6665OutputID);
4027 glDeleteProgram(OGLRef.programFramebufferRGBA8888OutputID);
4028 glDeleteShader(OGLRef.vertexFramebufferOutputShaderID);
4029 glDeleteShader(OGLRef.fragmentFramebufferRGBA6665OutputShaderID);
4030 glDeleteShader(OGLRef.fragmentFramebufferRGBA8888OutputShaderID);
4031 INFO("OpenGL: Failed to make the framebuffer output shader bindings.\n");
4032 return error;
4033 }
4034
4035 glLinkProgram(OGLRef.programFramebufferRGBA6665OutputID);
4036 glLinkProgram(OGLRef.programFramebufferRGBA8888OutputID);
4037
4038 if (!this->ValidateShaderProgramLink(OGLRef.programFramebufferRGBA6665OutputID) || !this->ValidateShaderProgramLink(OGLRef.programFramebufferRGBA8888OutputID))
4039 {
4040 glDetachShader(OGLRef.programFramebufferRGBA6665OutputID, OGLRef.vertexFramebufferOutputShaderID);
4041 glDetachShader(OGLRef.programFramebufferRGBA6665OutputID, OGLRef.fragmentFramebufferRGBA6665OutputShaderID);
4042 glDetachShader(OGLRef.programFramebufferRGBA8888OutputID, OGLRef.vertexFramebufferOutputShaderID);
4043 glDetachShader(OGLRef.programFramebufferRGBA8888OutputID, OGLRef.fragmentFramebufferRGBA8888OutputShaderID);
4044
4045 glDeleteProgram(OGLRef.programFramebufferRGBA6665OutputID);
4046 glDeleteProgram(OGLRef.programFramebufferRGBA8888OutputID);
4047 glDeleteShader(OGLRef.vertexFramebufferOutputShaderID);
4048 glDeleteShader(OGLRef.fragmentFramebufferRGBA6665OutputShaderID);
4049 glDeleteShader(OGLRef.fragmentFramebufferRGBA8888OutputShaderID);
4050 INFO("OpenGL: Failed to link the framebuffer output shader program.\n");
4051 return OGLERROR_SHADER_CREATE_ERROR;
4052 }
4053
4054 glValidateProgram(OGLRef.programFramebufferRGBA6665OutputID);
4055 glValidateProgram(OGLRef.programFramebufferRGBA8888OutputID);
4056 this->InitFramebufferOutputShaderLocations();
4057
4058 // ------------------------------------------
4059
4060 glUseProgram(OGLRef.programGeometryID);
4061 INFO("OpenGL: Successfully created postprocess shaders.\n");
4062
4063 return OGLERROR_NOERR;
4064 }
4065
DestroyPostprocessingPrograms()4066 Render3DError OpenGLRenderer_2_0::DestroyPostprocessingPrograms()
4067 {
4068 OGLRenderRef &OGLRef = *this->ref;
4069
4070 glUseProgram(0);
4071 glDetachShader(OGLRef.programEdgeMarkID, OGLRef.vertexEdgeMarkShaderID);
4072 glDetachShader(OGLRef.programEdgeMarkID, OGLRef.fragmentEdgeMarkShaderID);
4073 glDetachShader(OGLRef.programFogID, OGLRef.vertexFogShaderID);
4074 glDetachShader(OGLRef.programFogID, OGLRef.fragmentFogShaderID);
4075
4076 glDeleteProgram(OGLRef.programEdgeMarkID);
4077 glDeleteProgram(OGLRef.programFogID);
4078
4079 glDeleteShader(OGLRef.vertexEdgeMarkShaderID);
4080 glDeleteShader(OGLRef.fragmentEdgeMarkShaderID);
4081 glDeleteShader(OGLRef.vertexFogShaderID);
4082 glDeleteShader(OGLRef.fragmentFogShaderID);
4083
4084 glDetachShader(OGLRef.programFramebufferRGBA6665OutputID, OGLRef.vertexFramebufferOutputShaderID);
4085 glDetachShader(OGLRef.programFramebufferRGBA6665OutputID, OGLRef.fragmentFramebufferRGBA6665OutputShaderID);
4086 glDetachShader(OGLRef.programFramebufferRGBA8888OutputID, OGLRef.vertexFramebufferOutputShaderID);
4087 glDetachShader(OGLRef.programFramebufferRGBA8888OutputID, OGLRef.fragmentFramebufferRGBA8888OutputShaderID);
4088
4089 glDeleteProgram(OGLRef.programFramebufferRGBA6665OutputID);
4090 glDeleteProgram(OGLRef.programFramebufferRGBA8888OutputID);
4091 glDeleteShader(OGLRef.vertexFramebufferOutputShaderID);
4092 glDeleteShader(OGLRef.fragmentFramebufferRGBA6665OutputShaderID);
4093 glDeleteShader(OGLRef.fragmentFramebufferRGBA8888OutputShaderID);
4094
4095 return OGLERROR_NOERR;
4096 }
4097
InitEdgeMarkProgramBindings()4098 Render3DError OpenGLRenderer_2_0::InitEdgeMarkProgramBindings()
4099 {
4100 OGLRenderRef &OGLRef = *this->ref;
4101 glBindAttribLocation(OGLRef.programEdgeMarkID, OGLVertexAttributeID_Position, "inPosition");
4102 glBindAttribLocation(OGLRef.programEdgeMarkID, OGLVertexAttributeID_TexCoord0, "inTexCoord0");
4103
4104 return OGLERROR_NOERR;
4105 }
4106
InitEdgeMarkProgramShaderLocations()4107 Render3DError OpenGLRenderer_2_0::InitEdgeMarkProgramShaderLocations()
4108 {
4109 OGLRenderRef &OGLRef = *this->ref;
4110
4111 glUseProgram(OGLRef.programEdgeMarkID);
4112
4113 const GLint uniformTexGDepth = glGetUniformLocation(OGLRef.programEdgeMarkID, "texInFragDepth");
4114 const GLint uniformTexGPolyID = glGetUniformLocation(OGLRef.programEdgeMarkID, "texInPolyID");
4115 glUniform1i(uniformTexGDepth, OGLTextureUnitID_GDepth);
4116 glUniform1i(uniformTexGPolyID, OGLTextureUnitID_GPolyID);
4117
4118 OGLRef.uniformFramebufferSize = glGetUniformLocation(OGLRef.programEdgeMarkID, "framebufferSize");
4119 OGLRef.uniformStateEdgeColor = glGetUniformLocation(OGLRef.programEdgeMarkID, "stateEdgeColor");
4120
4121 return OGLERROR_NOERR;
4122 }
4123
InitFogProgramBindings()4124 Render3DError OpenGLRenderer_2_0::InitFogProgramBindings()
4125 {
4126 OGLRenderRef &OGLRef = *this->ref;
4127 glBindAttribLocation(OGLRef.programFogID, OGLVertexAttributeID_Position, "inPosition");
4128 glBindAttribLocation(OGLRef.programFogID, OGLVertexAttributeID_TexCoord0, "inTexCoord0");
4129
4130 return OGLERROR_NOERR;
4131 }
4132
InitFogProgramShaderLocations()4133 Render3DError OpenGLRenderer_2_0::InitFogProgramShaderLocations()
4134 {
4135 OGLRenderRef &OGLRef = *this->ref;
4136
4137 glUseProgram(OGLRef.programFogID);
4138
4139 const GLint uniformTexGColor = glGetUniformLocation(OGLRef.programFogID, "texInFragColor");
4140 const GLint uniformTexGDepth = glGetUniformLocation(OGLRef.programFogID, "texInFragDepth");
4141 const GLint uniformTexGFog = glGetUniformLocation(OGLRef.programFogID, "texInFogAttributes");
4142 glUniform1i(uniformTexGColor, OGLTextureUnitID_GColor);
4143 glUniform1i(uniformTexGDepth, OGLTextureUnitID_GDepth);
4144 glUniform1i(uniformTexGFog, OGLTextureUnitID_FogAttr);
4145
4146 OGLRef.uniformStateEnableFogAlphaOnly = glGetUniformLocation(OGLRef.programFogID, "stateEnableFogAlphaOnly");
4147 OGLRef.uniformStateFogColor = glGetUniformLocation(OGLRef.programFogID, "stateFogColor");
4148 OGLRef.uniformStateFogDensity = glGetUniformLocation(OGLRef.programFogID, "stateFogDensity");
4149 OGLRef.uniformStateFogOffset = glGetUniformLocation(OGLRef.programFogID, "stateFogOffset");
4150 OGLRef.uniformStateFogStep = glGetUniformLocation(OGLRef.programFogID, "stateFogStep");
4151
4152 return OGLERROR_NOERR;
4153 }
4154
InitFramebufferOutputProgramBindings()4155 Render3DError OpenGLRenderer_2_0::InitFramebufferOutputProgramBindings()
4156 {
4157 OGLRenderRef &OGLRef = *this->ref;
4158 glBindAttribLocation(OGLRef.programFramebufferRGBA6665OutputID, OGLVertexAttributeID_Position, "inPosition");
4159 glBindAttribLocation(OGLRef.programFramebufferRGBA6665OutputID, OGLVertexAttributeID_TexCoord0, "inTexCoord0");
4160 glBindAttribLocation(OGLRef.programFramebufferRGBA8888OutputID, OGLVertexAttributeID_Position, "inPosition");
4161 glBindAttribLocation(OGLRef.programFramebufferRGBA8888OutputID, OGLVertexAttributeID_TexCoord0, "inTexCoord0");
4162
4163 return OGLERROR_NOERR;
4164 }
4165
InitFramebufferOutputShaderLocations()4166 Render3DError OpenGLRenderer_2_0::InitFramebufferOutputShaderLocations()
4167 {
4168 OGLRenderRef &OGLRef = *this->ref;
4169
4170 glUseProgram(OGLRef.programFramebufferRGBA6665OutputID);
4171 const GLint uniformTexFinalColorRGBA6665 = glGetUniformLocation(OGLRef.programFramebufferRGBA6665OutputID, "texInFragColor");
4172 glUniform1i(uniformTexFinalColorRGBA6665, OGLTextureUnitID_FinalColor);
4173
4174 glUseProgram(OGLRef.programFramebufferRGBA8888OutputID);
4175 const GLint uniformTexFinalColorRGBA8888 = glGetUniformLocation(OGLRef.programFramebufferRGBA8888OutputID, "texInFragColor");
4176 glUniform1i(uniformTexFinalColorRGBA8888, OGLTextureUnitID_FinalColor);
4177
4178 return OGLERROR_NOERR;
4179 }
4180
EnableVertexAttributes()4181 Render3DError OpenGLRenderer_2_0::EnableVertexAttributes()
4182 {
4183 OGLRenderRef &OGLRef = *this->ref;
4184
4185 if (this->isVAOSupported)
4186 {
4187 glBindVertexArray(OGLRef.vaoGeometryStatesID);
4188 }
4189 else
4190 {
4191 glEnableVertexAttribArray(OGLVertexAttributeID_Position);
4192 glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0);
4193 glEnableVertexAttribArray(OGLVertexAttributeID_Color);
4194 glVertexAttribPointer(OGLVertexAttributeID_Position, 4, GL_FLOAT, GL_FALSE, sizeof(VERT), OGLRef.vtxPtrPosition);
4195 glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(VERT), OGLRef.vtxPtrTexCoord);
4196 glVertexAttribPointer(OGLVertexAttributeID_Color, 3, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(VERT), OGLRef.vtxPtrColor);
4197 }
4198
4199 glActiveTexture(GL_TEXTURE0);
4200
4201 return OGLERROR_NOERR;
4202 }
4203
DisableVertexAttributes()4204 Render3DError OpenGLRenderer_2_0::DisableVertexAttributes()
4205 {
4206 if (this->isVAOSupported)
4207 {
4208 glBindVertexArray(0);
4209 }
4210 else
4211 {
4212 glDisableVertexAttribArray(OGLVertexAttributeID_Position);
4213 glDisableVertexAttribArray(OGLVertexAttributeID_TexCoord0);
4214 glDisableVertexAttribArray(OGLVertexAttributeID_Color);
4215 }
4216
4217 return OGLERROR_NOERR;
4218 }
4219
BeginRender(const GFX3D & engine)4220 Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D &engine)
4221 {
4222 OGLRenderRef &OGLRef = *this->ref;
4223
4224 if(!BEGINGL())
4225 {
4226 return OGLERROR_BEGINGL_FAILED;
4227 }
4228
4229 // Setup render states
4230 glUseProgram(OGLRef.programGeometryID);
4231 glUniform1i(OGLRef.uniformStateToonShadingMode, engine.renderState.shading);
4232 glUniform1i(OGLRef.uniformStateEnableAlphaTest, (engine.renderState.enableAlphaTest) ? GL_TRUE : GL_FALSE);
4233 glUniform1i(OGLRef.uniformStateEnableAntialiasing, (engine.renderState.enableAntialiasing) ? GL_TRUE : GL_FALSE);
4234 glUniform1i(OGLRef.uniformStateEnableEdgeMarking, (engine.renderState.enableEdgeMarking) ? GL_TRUE : GL_FALSE);
4235 glUniform1i(OGLRef.uniformStateUseWDepth, (engine.renderState.wbuffer) ? GL_TRUE : GL_FALSE);
4236 glUniform1f(OGLRef.uniformStateAlphaTestRef, divide5bitBy31_LUT[engine.renderState.alphaTestRef]);
4237
4238 glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboGeometryVtxID);
4239 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboGeometryIndexID);
4240
4241 size_t vertIndexCount = 0;
4242 GLushort *indexPtr = (GLushort *)glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
4243
4244 for (size_t i = 0; i < engine.polylist->count; i++)
4245 {
4246 const POLY *thePoly = &engine.polylist->list[engine.indexlist.list[i]];
4247 const size_t polyType = thePoly->type;
4248
4249 for (size_t j = 0; j < polyType; j++)
4250 {
4251 const GLushort vertIndex = thePoly->vertIndexes[j];
4252
4253 // While we're looping through our vertices, add each vertex index to
4254 // a buffer. For GFX3D_QUADS and GFX3D_QUAD_STRIP, we also add additional
4255 // vertices here to convert them to GL_TRIANGLES, which are much easier
4256 // to work with and won't be deprecated in future OpenGL versions.
4257 indexPtr[vertIndexCount++] = vertIndex;
4258 if (thePoly->vtxFormat == GFX3D_QUADS || thePoly->vtxFormat == GFX3D_QUAD_STRIP)
4259 {
4260 if (j == 2)
4261 {
4262 indexPtr[vertIndexCount++] = vertIndex;
4263 }
4264 else if (j == 3)
4265 {
4266 indexPtr[vertIndexCount++] = thePoly->vertIndexes[0];
4267 }
4268 }
4269 }
4270 }
4271
4272 glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
4273 glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(VERT) * engine.vertlist->count, engine.vertlist);
4274
4275 return OGLERROR_NOERR;
4276 }
4277
RenderEdgeMarking(const u16 * colorTable,const bool useAntialias)4278 Render3DError OpenGLRenderer_2_0::RenderEdgeMarking(const u16 *colorTable, const bool useAntialias)
4279 {
4280 OGLRenderRef &OGLRef = *this->ref;
4281
4282 const GLfloat alpha = (useAntialias) ? (16.0f/31.0f) : 1.0f;
4283 const GLfloat oglColor[4*8] = {divide5bitBy31_LUT[(colorTable[0] ) & 0x001F],
4284 divide5bitBy31_LUT[(colorTable[0] >> 5) & 0x001F],
4285 divide5bitBy31_LUT[(colorTable[0] >> 10) & 0x001F],
4286 alpha,
4287 divide5bitBy31_LUT[(colorTable[1] ) & 0x001F],
4288 divide5bitBy31_LUT[(colorTable[1] >> 5) & 0x001F],
4289 divide5bitBy31_LUT[(colorTable[1] >> 10) & 0x001F],
4290 alpha,
4291 divide5bitBy31_LUT[(colorTable[2] ) & 0x001F],
4292 divide5bitBy31_LUT[(colorTable[2] >> 5) & 0x001F],
4293 divide5bitBy31_LUT[(colorTable[2] >> 10) & 0x001F],
4294 alpha,
4295 divide5bitBy31_LUT[(colorTable[3] ) & 0x001F],
4296 divide5bitBy31_LUT[(colorTable[3] >> 5) & 0x001F],
4297 divide5bitBy31_LUT[(colorTable[3] >> 10) & 0x001F],
4298 alpha,
4299 divide5bitBy31_LUT[(colorTable[4] ) & 0x001F],
4300 divide5bitBy31_LUT[(colorTable[4] >> 5) & 0x001F],
4301 divide5bitBy31_LUT[(colorTable[4] >> 10) & 0x001F],
4302 alpha,
4303 divide5bitBy31_LUT[(colorTable[5] ) & 0x001F],
4304 divide5bitBy31_LUT[(colorTable[5] >> 5) & 0x001F],
4305 divide5bitBy31_LUT[(colorTable[5] >> 10) & 0x001F],
4306 alpha,
4307 divide5bitBy31_LUT[(colorTable[6] ) & 0x001F],
4308 divide5bitBy31_LUT[(colorTable[6] >> 5) & 0x001F],
4309 divide5bitBy31_LUT[(colorTable[6] >> 10) & 0x001F],
4310 alpha,
4311 divide5bitBy31_LUT[(colorTable[7] ) & 0x001F],
4312 divide5bitBy31_LUT[(colorTable[7] >> 5) & 0x001F],
4313 divide5bitBy31_LUT[(colorTable[7] >> 10) & 0x001F],
4314 alpha};
4315
4316 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboRenderID);
4317 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
4318 glUseProgram(OGLRef.programEdgeMarkID);
4319 glUniform2f(OGLRef.uniformFramebufferSize, this->_framebufferWidth, this->_framebufferHeight);
4320 glUniform4fv(OGLRef.uniformStateEdgeColor, 8, oglColor);
4321
4322 glViewport(0, 0, this->_framebufferWidth, this->_framebufferHeight);
4323 glDisable(GL_DEPTH_TEST);
4324 glDisable(GL_STENCIL_TEST);
4325 glEnable(GL_BLEND);
4326 glDisable(GL_CULL_FACE);
4327
4328 glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboPostprocessVtxID);
4329 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboPostprocessIndexID);
4330
4331 if (this->isVAOSupported)
4332 {
4333 glBindVertexArray(OGLRef.vaoPostprocessStatesID);
4334 }
4335 else
4336 {
4337 glEnableVertexAttribArray(OGLVertexAttributeID_Position);
4338 glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0);
4339 glVertexAttribPointer(OGLVertexAttributeID_Position, 2, GL_FLOAT, GL_FALSE, 0, 0);
4340 glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)(sizeof(GLfloat) * 8));
4341 }
4342
4343 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);
4344
4345 if (this->isVAOSupported)
4346 {
4347 glBindVertexArray(0);
4348 }
4349 else
4350 {
4351 glDisableVertexAttribArray(OGLVertexAttributeID_Position);
4352 glDisableVertexAttribArray(OGLVertexAttributeID_TexCoord0);
4353 }
4354
4355 return RENDER3DERROR_NOERR;
4356 }
4357
RenderFog(const u8 * densityTable,const u32 color,const u32 offset,const u8 shift,const bool alphaOnly)4358 Render3DError OpenGLRenderer_2_0::RenderFog(const u8 *densityTable, const u32 color, const u32 offset, const u8 shift, const bool alphaOnly)
4359 {
4360 OGLRenderRef &OGLRef = *this->ref;
4361 static GLfloat oglDensityTable[32];
4362
4363 if (!this->isFBOSupported)
4364 {
4365 return OGLERROR_FEATURE_UNSUPPORTED;
4366 }
4367
4368 for (size_t i = 0; i < 32; i++)
4369 {
4370 oglDensityTable[i] = (densityTable[i] == 127) ? 1.0f : (GLfloat)densityTable[i] / 128.0f;
4371 }
4372
4373 const GLfloat oglColor[4] = {divide5bitBy31_LUT[(color ) & 0x0000001F],
4374 divide5bitBy31_LUT[(color >> 5) & 0x0000001F],
4375 divide5bitBy31_LUT[(color >> 10) & 0x0000001F],
4376 divide5bitBy31_LUT[(color >> 16) & 0x0000001F]};
4377
4378 const GLfloat oglOffset = (GLfloat)offset / 32767.0f;
4379 const GLfloat oglFogStep = (GLfloat)(0x0400 >> shift) / 32767.0f;
4380
4381 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboPostprocessID);
4382 glUseProgram(OGLRef.programFogID);
4383 glUniform1i(OGLRef.uniformStateEnableFogAlphaOnly, (alphaOnly) ? GL_TRUE : GL_FALSE);
4384 glUniform4f(OGLRef.uniformStateFogColor, oglColor[0], oglColor[1], oglColor[2], oglColor[3]);
4385 glUniform1f(OGLRef.uniformStateFogOffset, oglOffset);
4386 glUniform1f(OGLRef.uniformStateFogStep, oglFogStep);
4387 glUniform1fv(OGLRef.uniformStateFogDensity, 32, oglDensityTable);
4388
4389 glViewport(0, 0, this->_framebufferWidth, this->_framebufferHeight);
4390 glDisable(GL_DEPTH_TEST);
4391 glDisable(GL_STENCIL_TEST);
4392 glDisable(GL_BLEND);
4393 glDisable(GL_CULL_FACE);
4394
4395 glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboPostprocessVtxID);
4396 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboPostprocessIndexID);
4397
4398 if (this->isVAOSupported)
4399 {
4400 glBindVertexArray(OGLRef.vaoPostprocessStatesID);
4401 }
4402 else
4403 {
4404 glEnableVertexAttribArray(OGLVertexAttributeID_Position);
4405 glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0);
4406 glVertexAttribPointer(OGLVertexAttributeID_Position, 2, GL_FLOAT, GL_FALSE, 0, 0);
4407 glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)(sizeof(GLfloat) * 8));
4408 }
4409
4410 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);
4411
4412 if (this->isVAOSupported)
4413 {
4414 glBindVertexArray(0);
4415 }
4416 else
4417 {
4418 glDisableVertexAttribArray(OGLVertexAttributeID_Position);
4419 glDisableVertexAttribArray(OGLVertexAttributeID_TexCoord0);
4420 }
4421
4422 return OGLERROR_NOERR;
4423 }
4424
SetupPolygon(const POLY & thePoly)4425 Render3DError OpenGLRenderer_2_0::SetupPolygon(const POLY &thePoly)
4426 {
4427 const PolygonAttributes attr = thePoly.getAttributes();
4428
4429 // Set up depth test mode
4430 static const GLenum oglDepthFunc[2] = {GL_LESS, GL_EQUAL};
4431 glDepthFunc(oglDepthFunc[attr.enableDepthEqualTest]);
4432
4433 // Set up culling mode
4434 static const GLenum oglCullingMode[4] = {GL_FRONT_AND_BACK, GL_FRONT, GL_BACK, 0};
4435 GLenum cullingMode = oglCullingMode[attr.surfaceCullingMode];
4436
4437 if (cullingMode == 0)
4438 {
4439 glDisable(GL_CULL_FACE);
4440 }
4441 else
4442 {
4443 glEnable(GL_CULL_FACE);
4444 glCullFace(cullingMode);
4445 }
4446
4447 // Set up depth write
4448 GLboolean enableDepthWrite = GL_TRUE;
4449
4450 // Handle shadow polys. Do this after checking for depth write, since shadow polys
4451 // can change this too.
4452 if (attr.polygonMode == POLYGON_MODE_SHADOW)
4453 {
4454 glEnable(GL_STENCIL_TEST);
4455
4456 if (attr.polygonID == 0)
4457 {
4458 //when the polyID is zero, we are writing the shadow mask.
4459 //set stencilbuf = 1 where the shadow volume is obstructed by geometry.
4460 //do not write color or depth information.
4461 glStencilFunc(GL_NOTEQUAL, 0x80, 0xFF);
4462 glStencilOp(GL_KEEP, GL_ZERO, GL_KEEP);
4463 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
4464 enableDepthWrite = GL_FALSE;
4465 }
4466 else
4467 {
4468 //when the polyid is nonzero, we are drawing the shadow poly.
4469 //only draw the shadow poly where the stencilbuf==1.
4470 glStencilFunc(GL_EQUAL, 0, 0xFF);
4471 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
4472 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4473 enableDepthWrite = GL_TRUE;
4474 }
4475 }
4476 else if ( attr.isTranslucent || (std::find(this->_shadowPolyID.begin(), this->_shadowPolyID.end(), attr.polygonID) == this->_shadowPolyID.end()) )
4477 {
4478 glDisable(GL_STENCIL_TEST);
4479 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4480 enableDepthWrite = (!attr.isTranslucent || ( (attr.polygonMode == POLYGON_MODE_DECAL) && attr.isOpaque ) || attr.enableAlphaDepthWrite) ? GL_TRUE : GL_FALSE;
4481 }
4482 else
4483 {
4484 glEnable(GL_STENCIL_TEST);
4485 glStencilFunc(GL_ALWAYS, 0x80, 0xFF);
4486 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
4487 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4488 enableDepthWrite = GL_TRUE;
4489 }
4490
4491 glDepthMask(enableDepthWrite);
4492
4493 // Set up polygon attributes
4494 OGLRenderRef &OGLRef = *this->ref;
4495 glUniform1i(OGLRef.uniformPolyMode, attr.polygonMode);
4496 glUniform1i(OGLRef.uniformPolyEnableFog, (attr.enableRenderFog) ? GL_TRUE : GL_FALSE);
4497 glUniform1f(OGLRef.uniformPolyAlpha, (!attr.isWireframe && attr.isTranslucent) ? divide5bitBy31_LUT[attr.alpha] : 1.0f);
4498 glUniform1i(OGLRef.uniformPolyID, attr.polygonID);
4499 glUniform1i(OGLRef.uniformPolyEnableDepthWrite, enableDepthWrite);
4500 glUniform1i(OGLRef.uniformPolySetNewDepthForTranslucent, (attr.enableAlphaDepthWrite) ? GL_TRUE : GL_FALSE);
4501
4502 return OGLERROR_NOERR;
4503 }
4504
SetupTexture(const POLY & thePoly,bool enableTexturing)4505 Render3DError OpenGLRenderer_2_0::SetupTexture(const POLY &thePoly, bool enableTexturing)
4506 {
4507 OGLRenderRef &OGLRef = *this->ref;
4508 const PolygonTexParams params = thePoly.getTexParams();
4509
4510 // Check if we need to use textures
4511 if (params.texFormat == TEXMODE_NONE || !enableTexturing)
4512 {
4513 glUniform1i(OGLRef.uniformPolyEnableTexture, GL_FALSE);
4514 return OGLERROR_NOERR;
4515 }
4516
4517 glUniform1i(OGLRef.uniformPolyEnableTexture, GL_TRUE);
4518
4519 TexCacheItem *newTexture = TexCache_SetTexture(TexFormat_32bpp, thePoly.texParam, thePoly.texPalette);
4520 if(newTexture != this->currTexture)
4521 {
4522 this->currTexture = newTexture;
4523 //has the ogl renderer initialized the texture?
4524 if(this->currTexture->GetDeleteCallback() == NULL)
4525 {
4526 this->currTexture->SetDeleteCallback(&texDeleteCallback, this, NULL);
4527
4528 if(OGLRef.freeTextureIDs.empty())
4529 {
4530 this->ExpandFreeTextures();
4531 }
4532
4533 this->currTexture->texid = (u64)OGLRef.freeTextureIDs.front();
4534 OGLRef.freeTextureIDs.pop();
4535
4536 glBindTexture(GL_TEXTURE_2D, (GLuint)this->currTexture->texid);
4537 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4538 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4539 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (params.enableRepeatS ? (params.enableMirroredRepeatS ? GL_MIRRORED_REPEAT : GL_REPEAT) : GL_CLAMP_TO_EDGE));
4540 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (params.enableRepeatT ? (params.enableMirroredRepeatT ? GL_MIRRORED_REPEAT : GL_REPEAT) : GL_CLAMP_TO_EDGE));
4541
4542 u32 *textureSrc = (u32 *)currTexture->decoded;
4543 size_t texWidth = currTexture->sizeX;
4544 size_t texHeight = currTexture->sizeY;
4545
4546 if (this->_textureDeposterizeBuffer != NULL)
4547 {
4548 this->TextureDeposterize(textureSrc, texWidth, texHeight);
4549 textureSrc = this->_textureDeposterizeBuffer;
4550 }
4551
4552 switch (this->_textureScalingFactor)
4553 {
4554 case 2:
4555 {
4556 this->TextureUpscale<2>(textureSrc, texWidth, texHeight);
4557 textureSrc = this->_textureUpscaleBuffer;
4558 break;
4559 }
4560
4561 case 4:
4562 {
4563 this->TextureUpscale<4>(textureSrc, texWidth, texHeight);
4564 textureSrc = this->_textureUpscaleBuffer;
4565 break;
4566 }
4567
4568 default:
4569 break;
4570 }
4571
4572 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureSrc);
4573 }
4574 else
4575 {
4576 //otherwise, just bind it
4577 glBindTexture(GL_TEXTURE_2D, (GLuint)this->currTexture->texid);
4578 }
4579
4580 glUniform2f(OGLRef.uniformPolyTexScale, this->currTexture->invSizeX, this->currTexture->invSizeY);
4581 }
4582
4583 return OGLERROR_NOERR;
4584 }
4585
ReadBackPixels()4586 Render3DError OpenGLRenderer_2_1::ReadBackPixels()
4587 {
4588 OGLRenderRef &OGLRef = *this->ref;
4589
4590 if (this->_mappedFramebuffer != NULL)
4591 {
4592 glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
4593 this->_mappedFramebuffer = NULL;
4594 }
4595
4596 // Flip the framebuffer in Y to match the coordinates of OpenGL and the NDS hardware.
4597 if (this->willFlipFramebufferOnGPU)
4598 {
4599 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, OGLRef.fboPostprocessID);
4600 glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT);
4601 glBlitFramebufferEXT(0, this->_framebufferHeight, this->_framebufferWidth, 0, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
4602 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboPostprocessID);
4603 glReadBuffer(GL_COLOR_ATTACHMENT1_EXT);
4604 }
4605
4606 if (this->willConvertFramebufferOnGPU)
4607 {
4608 // Perform the color space conversion while we're still on the GPU so
4609 // that we can avoid having to do it on the CPU.
4610 const GLuint convertProgramID = (this->_outputFormat == NDSColorFormat_BGR666_Rev) ? OGLRef.programFramebufferRGBA6665OutputID : OGLRef.programFramebufferRGBA8888OutputID;
4611 glDrawBuffer(GL_COLOR_ATTACHMENT2_EXT);
4612
4613 glUseProgram(convertProgramID);
4614 glViewport(0, 0, this->_framebufferWidth, this->_framebufferHeight);
4615 glDisable(GL_DEPTH_TEST);
4616 glDisable(GL_STENCIL_TEST);
4617 glDisable(GL_BLEND);
4618 glDisable(GL_CULL_FACE);
4619
4620 glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboPostprocessVtxID);
4621 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboPostprocessIndexID);
4622 glBindVertexArray(OGLRef.vaoPostprocessStatesID);
4623 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);
4624 glBindVertexArray(0);
4625
4626 // Read back the pixels.
4627 glReadBuffer(GL_COLOR_ATTACHMENT2_EXT);
4628 }
4629
4630 // Read back the pixels in BGRA format, since legacy OpenGL devices may experience a performance
4631 // penalty if the readback is in any other format.
4632 glReadPixels(0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_BGRA, GL_UNSIGNED_BYTE, 0);
4633
4634 // Set the read and draw target buffers back to color attachment 0, which is always the default.
4635 if (this->willFlipFramebufferOnGPU || this->willConvertFramebufferOnGPU)
4636 {
4637 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
4638 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
4639 }
4640
4641 this->_pixelReadNeedsFinish = true;
4642 return OGLERROR_NOERR;
4643 }
4644
RenderFinish()4645 Render3DError OpenGLRenderer_2_1::RenderFinish()
4646 {
4647 if (!this->_renderNeedsFinish || !this->_pixelReadNeedsFinish)
4648 {
4649 return OGLERROR_NOERR;
4650 }
4651
4652 FragmentColor *framebufferMain = (this->_willFlushFramebufferRGBA6665) ? GPU->GetEngineMain()->Get3DFramebufferRGBA6665() : NULL;
4653 u16 *framebufferRGBA5551 = (this->_willFlushFramebufferRGBA5551) ? GPU->GetEngineMain()->Get3DFramebufferRGBA5551() : NULL;
4654
4655 if ( (framebufferMain != NULL) || (framebufferRGBA5551 != NULL) )
4656 {
4657 if(!BEGINGL())
4658 {
4659 return OGLERROR_BEGINGL_FAILED;
4660 }
4661
4662 this->_mappedFramebuffer = (FragmentColor *__restrict)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
4663 this->FlushFramebuffer(this->_mappedFramebuffer, framebufferMain, framebufferRGBA5551);
4664
4665 ENDGL();
4666 }
4667
4668 this->_pixelReadNeedsFinish = false;
4669
4670 return OGLERROR_NOERR;
4671 }
4672