1 #ifndef H_GAPI_GL
2 #define H_GAPI_GL
3 
4 #include "core.h"
5 
6 #if defined(_DEBUG) || defined(PROFILE)
7     //#define _DEBUG_SHADERS "../../OpenLara/src/shaders/"
8 #endif
9 
10 #ifdef _OS_WIN
11     #include <gl/GL.h>
12     #include <gl/glext.h>
13     #include <gl/wglext.h>
14 #elif _OS_ANDROID
15     #include <dlfcn.h>
16 
17 //    #define _GAPI_GLES2 // for old devices
18 
19     #ifdef _GAPI_GLES2
20         #include <GLES2/gl2.h>
21         #include <GLES2/gl2ext.h>
22 
23         #define GL_CLAMP_TO_BORDER          0x812D
24         #define GL_TEXTURE_BORDER_COLOR     0x1004
25 
26         #define GL_TEXTURE_COMPARE_MODE     0x884C
27         #define GL_TEXTURE_COMPARE_FUNC     0x884D
28         #define GL_COMPARE_REF_TO_TEXTURE   0x884E
29 
30         #undef  GL_RG
31         #undef  GL_RG32F
32         #undef  GL_RG16F
33         #undef  GL_RGBA32F
34         #undef  GL_RGBA16F
35         #undef  GL_HALF_FLOAT
36 
37         #define GL_RG           GL_RGBA
38         #define GL_RGBA32F      GL_RGBA
39         #define GL_RGBA16F      GL_RGBA
40         #define GL_RG32F        GL_RGBA
41         #define GL_RG16F        GL_RGBA
42         #define GL_HALF_FLOAT   GL_HALF_FLOAT_OES
43 
44         #define GL_TEXTURE_3D           0
45         #define GL_TEXTURE_WRAP_R       0
46         #define GL_DEPTH_STENCIL        GL_DEPTH_STENCIL_OES
47         #define GL_UNSIGNED_INT_24_8    GL_UNSIGNED_INT_24_8_OES
48 
49         #define glTexImage3D(...) 0
50 
51         #define glGenVertexArrays(...)
52         #define glDeleteVertexArrays(...)
53         #define glBindVertexArray(...)
54 
55         #define GL_PROGRAM_BINARY_LENGTH     GL_PROGRAM_BINARY_LENGTH_OES
56         #define glGetProgramBinary(...)
57         #define glProgramBinary(...)
58 
59         #define glInvalidateFramebuffer(...)
60     #else
61         #include <GLES3/gl3.h>
62         #include <GLES3/gl3ext.h>
63         #include <GLES2/gl2ext.h>
64     #endif
65 
66 #elif defined(__SDL2__)
67     #include <SDL2/SDL.h>
68 
69     #if defined(_GAPI_GLES) // Default in SDL2 is GLES3. If we want GLES2, pass -D_GAPI_GLES2.
70     #if defined (_GAPI_GLES2) // We want GLES2 on SDL2
71         #include <SDL2/SDL_opengles2.h>
72         #include <SDL2/SDL_opengles2_gl2ext.h>
73 
74         #define GL_CLAMP_TO_BORDER          0x812D
75         #define GL_TEXTURE_BORDER_COLOR     0x1004
76 
77         #define GL_TEXTURE_COMPARE_MODE     0x884C
78         #define GL_TEXTURE_COMPARE_FUNC     0x884D
79         #define GL_COMPARE_REF_TO_TEXTURE   0x884E
80 
81         #undef  GL_RG
82         #undef  GL_RG32F
83         #undef  GL_RG16F
84         #undef  GL_RGBA32F
85         #undef  GL_RGBA16F
86         #undef  GL_HALF_FLOAT
87 
88         #define GL_RG           GL_RGBA
89         #define GL_RGBA32F      GL_RGBA
90         #define GL_RGBA16F      GL_RGBA
91         #define GL_RG32F        GL_RGBA
92         #define GL_RG16F        GL_RGBA
93         #define GL_HALF_FLOAT   GL_HALF_FLOAT_OES
94 
95         #define GL_TEXTURE_WRAP_R       0
96         #define GL_DEPTH_STENCIL        GL_DEPTH_STENCIL_OES
97         #define GL_UNSIGNED_INT_24_8    GL_UNSIGNED_INT_24_8_OES
98         //We need this on GLES2, too.
99         #define GL_TEXTURE_MAX_LEVEL     GL_TEXTURE_MAX_LEVEL_APPLE
100 
101         #define glTexImage3D(...) 0
102         #ifndef GL_TEXTURE_3D // WUUUUUT!?
103         #define GL_TEXTURE_3D GL_TEXTURE_3D_OES
104         #endif
105 
106         #define GL_PROGRAM_BINARY_LENGTH     GL_PROGRAM_BINARY_LENGTH_OES
107         #else // We want GLES3 on SDL2
108         #include <GLES3/gl3.h>
109         #include <GLES3/gl3ext.h>
110         #include <GLES2/gl2ext.h>
111         #endif //GAPI_GLES2
112 
113     // These are needed for both GLES2 and GLES3 on SDL2
114     #define glGenVertexArrays(...)
115     #define glDeleteVertexArrays(...)
116     #define glBindVertexArray(...)
117     #define glGetProgramBinary(...)
118     #define glProgramBinary(...)
119 
120     #define PFNGLGENVERTEXARRAYSPROC    PFNGLGENVERTEXARRAYSOESPROC
121     #define PFNGLDELETEVERTEXARRAYSPROC PFNGLDELETEVERTEXARRAYSOESPROC
122     #define PFNGLBINDVERTEXARRAYPROC    PFNGLBINDVERTEXARRAYOESPROC
123     #define PFNGLGETPROGRAMBINARYPROC   PFNGLGETPROGRAMBINARYOESPROC
124     #define PFNGLPROGRAMBINARYPROC      PFNGLPROGRAMBINARYOESPROC
125 
126     #else // We want OpenGL on SDL2, not GLES
127         #include <SDL2/SDL_opengl.h>
128         #include <SDL2/SDL_opengl_glext.h>
129     #endif
130 
131 #elif defined(_OS_PSC)
132     #include <GLES3/gl3.h>
133     #include <GLES2/gl2ext.h>
134     extern EGLDisplay display;
135 #elif defined(_OS_GCW0)
136     #include <GLES2/gl2.h>
137     #include <GLES2/gl2ext.h>
138     #include <EGL/egl.h>
139     #include <EGL/eglext.h>
140 
141     #define GL_TEXTURE_MAX_LEVEL        GL_TEXTURE_MAX_LEVEL_APPLE
142     #define GL_TEXTURE_3D               0
143     #define GL_TEXTURE_WRAP_R           0
144     #define GL_TEXTURE_COMPARE_MODE     0x884C
145     #define GL_TEXTURE_COMPARE_FUNC     0x884D
146     #define GL_COMPARE_REF_TO_TEXTURE   0x884E
147 
148     #undef  GL_RG
149     #undef  GL_RG32F
150     #undef  GL_RG16F
151     #undef  GL_RGBA32F
152     #undef  GL_RGBA16F
153     #undef  GL_HALF_FLOAT
154 
155     #define GL_RG           GL_RGBA
156     #define GL_RGBA32F      GL_RGBA
157     #define GL_RGBA16F      GL_RGBA
158     #define GL_RG32F        GL_RGBA
159     #define GL_RG16F        GL_RGBA
160     #define GL_HALF_FLOAT   GL_HALF_FLOAT_OES
161 
162     #define glTexImage3D(...) 0
163 
164     #define GL_PROGRAM_BINARY_LENGTH     GL_PROGRAM_BINARY_LENGTH_OES
165 
166     #define PFNGLGENVERTEXARRAYSPROC    PFNGLGENVERTEXARRAYSOESPROC
167     #define PFNGLDELETEVERTEXARRAYSPROC PFNGLDELETEVERTEXARRAYSOESPROC
168     #define PFNGLBINDVERTEXARRAYPROC    PFNGLBINDVERTEXARRAYOESPROC
169     #define PFNGLGETPROGRAMBINARYPROC   PFNGLGETPROGRAMBINARYOESPROC
170     #define PFNGLPROGRAMBINARYPROC      PFNGLPROGRAMBINARYOESPROC
171 
172     #define glGenVertexArrays    glGenVertexArraysOES
173     #define glDeleteVertexArrays glDeleteVertexArraysOES
174     #define glBindVertexArray    glBindVertexArrayOES
175     #define glGetProgramBinary   glGetProgramBinaryOES
176     #define glProgramBinary      glProgramBinaryOES
177 
178     extern EGLDisplay display;
179 #elif defined(_OS_RPI) || defined(_OS_CLOVER)
180     #include <GLES2/gl2.h>
181     #include <GLES2/gl2ext.h>
182     #include <EGL/egl.h>
183     #include <EGL/eglext.h>
184 
185     #define GL_CLAMP_TO_BORDER          0x812D
186     #define GL_TEXTURE_BORDER_COLOR     0x1004
187     #define GL_TEXTURE_MAX_LEVEL        GL_TEXTURE_MAX_LEVEL_APPLE
188     #define GL_TEXTURE_COMPARE_MODE     0x884C
189     #define GL_TEXTURE_COMPARE_FUNC     0x884D
190     #define GL_COMPARE_REF_TO_TEXTURE   0x884E
191 
192     #undef  GL_RG
193     #undef  GL_RG32F
194     #undef  GL_RG16F
195     #undef  GL_RGBA32F
196     #undef  GL_RGBA16F
197     #undef  GL_HALF_FLOAT
198 
199     #define GL_RG           GL_RGBA
200     #define GL_RGBA32F      GL_RGBA
201     #define GL_RGBA16F      GL_RGBA
202     #define GL_RG32F        GL_RGBA
203     #define GL_RG16F        GL_RGBA
204     #define GL_HALF_FLOAT   GL_HALF_FLOAT_OES
205 
206     #define GL_TEXTURE_3D           0
207     #define GL_TEXTURE_WRAP_R       0
208     #define GL_DEPTH_STENCIL        GL_DEPTH_STENCIL_OES
209     #define GL_UNSIGNED_INT_24_8    GL_UNSIGNED_INT_24_8_OES
210 
211     #define glTexImage3D(...) 0
212 
213     #define glGenVertexArrays(...)
214     #define glDeleteVertexArrays(...)
215     #define glBindVertexArray(...)
216 
217     #define GL_PROGRAM_BINARY_LENGTH     GL_PROGRAM_BINARY_LENGTH_OES
218     #define glGetProgramBinary(...)
219     #define glProgramBinary(...)
220 
221     extern EGLDisplay display;
222 #elif _OS_SWITCH
223     #define GL_GLEXT_PROTOTYPES
224     #include <EGL/egl.h>
225     #include <EGL/eglext.h>
226     #include <GL/gl.h>
227     #include <GL/glext.h>
228 
229     extern EGLDisplay display;
230 #elif _OS_LINUX
231     #include <GL/gl.h>
232     #include <GL/glext.h>
233     #include <GL/glx.h>
234 #elif __APPLE__
235     #ifdef _OS_IOS
236         #include <OpenGLES/ES2/gl.h>
237         #include <OpenGLES/ES2/glext.h>
238         #include <OpenGLES/ES3/glext.h>
239 
240         #define PFNGLGENVERTEXARRAYSPROC    PFNGLGENVERTEXARRAYSOESPROC
241         #define PFNGLDELETEVERTEXARRAYSPROC PFNGLDELETEVERTEXARRAYSOESPROC
242         #define PFNGLBINDVERTEXARRAYPROC    PFNGLBINDVERTEXARRAYOESPROC
243         #define glGenVertexArrays           glGenVertexArraysOES
244         #define glDeleteVertexArrays        glDeleteVertexArraysOES
245         #define glBindVertexArray           glBindVertexArrayOES
246 
247         #define GL_CLAMP_TO_BORDER          0x812D
248         #define GL_TEXTURE_BORDER_COLOR     0x1004
249 
250         // TODO: WTF?
251         #undef  GL_RG
252         #undef  GL_RGBA32F
253         #undef  GL_RGBA16F
254         #undef  GL_RG32F
255         #undef  GL_RG16F
256         #undef  GL_HALF_FLOAT
257 
258         #define GL_RG           GL_RGBA
259         #define GL_RG16F        GL_RGBA
260         #define GL_RG32F        GL_RGBA
261         #define GL_RGBA32F      GL_RGBA
262         #define GL_RGBA16F      GL_RGBA
263         #define GL_HALF_FLOAT   GL_HALF_FLOAT_OES
264 
265         //#define GL_TEXTURE_COMPARE_MODE     GL_TEXTURE_COMPARE_MODE_EXT
266         //#define GL_TEXTURE_COMPARE_FUNC     GL_TEXTURE_COMPARE_FUNC_EXT
267         //#define GL_COMPARE_REF_TO_TEXTURE   GL_COMPARE_REF_TO_TEXTURE_EXT
268     #else
269         #include <Carbon/Carbon.h>
270         #include <AudioToolbox/AudioQueue.h>
271         #include <OpenGL/OpenGL.h>
272         #include <OpenGL/gl.h>
273         #include <OpenGL/glext.h>
274         #include <AGL/agl.h>
275 
276         #define GL_RG                       0x8227
277         #define GL_RG16F                    0x822F
278         #define GL_RG32F                    0x8230
279         #define GL_RGBA16F                  0x881A
280         #define GL_RGBA32F                  0x8814
281         #define GL_HALF_FLOAT               0x140B
282 
283         #define GL_RGB565                   GL_RGBA
284         #define GL_TEXTURE_COMPARE_MODE     0x884C
285         #define GL_TEXTURE_COMPARE_FUNC     0x884D
286         #define GL_COMPARE_REF_TO_TEXTURE   0x884E
287 
288         #define glGenVertexArrays    glGenVertexArraysAPPLE
289         #define glDeleteVertexArrays glDeleteVertexArraysAPPLE
290         #define glBindVertexArray    glBindVertexArrayAPPLE
291 
292         #define GL_PROGRAM_BINARY_LENGTH 0
293         #define glGetProgramBinary(...)  0
294         #define glProgramBinary(...)     0
295     #endif
296 #elif _OS_WEB
297     #include <emscripten/emscripten.h>
298     #include <emscripten/html5.h>
299     #include <GLES/gl.h>
300     #include <GLES3/gl3.h>
301     #include <GLES3/gl2ext.h>
302 
303     #define GL_CLAMP_TO_BORDER          GL_CLAMP_TO_BORDER_EXT
304     #define GL_TEXTURE_BORDER_COLOR     GL_TEXTURE_BORDER_COLOR_EXT
305 
306     #define glGetProgramBinary(...)
307     #define glProgramBinary(...)
308 #endif
309 
310 #if defined(_OS_WIN) || defined(_OS_LINUX) || defined(_OS_GCW0) || (defined(__SDL2__) && (defined(_GAPI_GLES2) || defined(_SDL2_OPENGL)))
311 
GetProc(const char * name)312     void* GetProc(const char *name) {
313         #ifdef _OS_WIN
314             return (void*)wglGetProcAddress(name);
315         #elif _OS_LINUX
316             return (void*)glXGetProcAddress((GLubyte*)name);
317         #elif __SDL2__
318             return (void*)SDL_GL_GetProcAddress(name);
319         #else // EGL
320             return (void*)eglGetProcAddress(name);
321         #endif
322     }
323 
324     #define GetProcOGL(x) x=(decltype(x))GetProc(#x)
325 
326     // TODO: different systems, different headers, different extension suffixes... fuck this shit and make your own OGL header!
327 
328 // Texture
329     #ifdef _OS_WIN
330         PFNGLACTIVETEXTUREPROC              glActiveTexture;
331     #endif
332 
333 // VSync
334     #ifdef _OS_WIN
335         typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval);
336         PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
337     #elif _OS_LINUX
338         typedef int (*PFNGLXSWAPINTERVALSGIPROC) (int interval);
339         PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI;
340     #endif
341 
342     #if defined(_OS_WIN) || defined(_OS_LINUX) || (defined(__SDL2__) && !defined(_GAPI_GLES2))
343         PFNGLGENERATEMIPMAPPROC             glGenerateMipmap;
344         #ifdef _OS_WIN
345             PFNGLTEXIMAGE3DPROC             glTexImage3D;
346         #endif
347         PFNGLGETSTRINGIPROC                 glGetStringi;
348     // Profiling
349         #ifdef PROFILE
350             PFNGLOBJECTLABELPROC                glObjectLabel;
351             PFNGLPUSHDEBUGGROUPPROC             glPushDebugGroup;
352             PFNGLPOPDEBUGGROUPPROC              glPopDebugGroup;
353             PFNGLGENQUERIESPROC                 glGenQueries;
354             PFNGLDELETEQUERIESPROC              glDeleteQueries;
355             PFNGLGETQUERYOBJECTIVPROC           glGetQueryObjectiv;
356             PFNGLBEGINQUERYPROC                 glBeginQuery;
357             PFNGLENDQUERYPROC                   glEndQuery;
358         #endif
359     // Shader
360         PFNGLCREATEPROGRAMPROC              glCreateProgram;
361         PFNGLDELETEPROGRAMPROC              glDeleteProgram;
362         PFNGLLINKPROGRAMPROC                glLinkProgram;
363         PFNGLUSEPROGRAMPROC                 glUseProgram;
364         PFNGLGETPROGRAMINFOLOGPROC          glGetProgramInfoLog;
365         PFNGLCREATESHADERPROC               glCreateShader;
366         PFNGLDELETESHADERPROC               glDeleteShader;
367         PFNGLSHADERSOURCEPROC               glShaderSource;
368         PFNGLATTACHSHADERPROC               glAttachShader;
369         PFNGLCOMPILESHADERPROC              glCompileShader;
370         PFNGLGETSHADERINFOLOGPROC           glGetShaderInfoLog;
371         PFNGLGETUNIFORMLOCATIONPROC         glGetUniformLocation;
372         PFNGLUNIFORM1IVPROC                 glUniform1iv;
373         PFNGLUNIFORM1FVPROC                 glUniform1fv;
374         PFNGLUNIFORM2FVPROC                 glUniform2fv;
375         PFNGLUNIFORM3FVPROC                 glUniform3fv;
376         PFNGLUNIFORM4FVPROC                 glUniform4fv;
377         PFNGLUNIFORMMATRIX4FVPROC           glUniformMatrix4fv;
378         PFNGLBINDATTRIBLOCATIONPROC         glBindAttribLocation;
379         PFNGLENABLEVERTEXATTRIBARRAYPROC    glEnableVertexAttribArray;
380         PFNGLDISABLEVERTEXATTRIBARRAYPROC   glDisableVertexAttribArray;
381         PFNGLVERTEXATTRIBPOINTERPROC        glVertexAttribPointer;
382         PFNGLGETPROGRAMIVPROC               glGetProgramiv;
383     // Render to texture
384         PFNGLGENFRAMEBUFFERSPROC                     glGenFramebuffers;
385         PFNGLBINDFRAMEBUFFERPROC                     glBindFramebuffer;
386         PFNGLGENRENDERBUFFERSPROC                    glGenRenderbuffers;
387         PFNGLBINDRENDERBUFFERPROC                    glBindRenderbuffer;
388         PFNGLFRAMEBUFFERTEXTURE2DPROC                glFramebufferTexture2D;
389         PFNGLFRAMEBUFFERRENDERBUFFERPROC             glFramebufferRenderbuffer;
390         PFNGLRENDERBUFFERSTORAGEPROC                 glRenderbufferStorage;
391         PFNGLCHECKFRAMEBUFFERSTATUSPROC              glCheckFramebufferStatus;
392         PFNGLDELETEFRAMEBUFFERSPROC                  glDeleteFramebuffers;
393         PFNGLDELETERENDERBUFFERSPROC                 glDeleteRenderbuffers;
394         PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv;
395     // Mesh
396         PFNGLGENBUFFERSARBPROC              glGenBuffers;
397         PFNGLDELETEBUFFERSARBPROC           glDeleteBuffers;
398         PFNGLBINDBUFFERARBPROC              glBindBuffer;
399         PFNGLBUFFERDATAARBPROC              glBufferData;
400         PFNGLBUFFERSUBDATAARBPROC           glBufferSubData;
401     #endif
402 
403 // Vertex Arrays
404     PFNGLGENVERTEXARRAYSPROC            glGenVertexArrays;
405     PFNGLDELETEVERTEXARRAYSPROC         glDeleteVertexArrays;
406     PFNGLBINDVERTEXARRAYPROC            glBindVertexArray;
407 // Binary shaders
408     PFNGLGETPROGRAMBINARYPROC           glGetProgramBinary;
409     PFNGLPROGRAMBINARYPROC              glProgramBinary;
410 
411     #if defined(_GAPI_GLES)
412         PFNGLDISCARDFRAMEBUFFEREXTPROC      glDiscardFramebufferEXT;
413     #endif
414 #endif
415 
416 #ifdef PROFILE
417    //#define USE_CV_MARKERS
418 
419    #ifdef USE_CV_MARKERS
420        #include <libs/cvmarkers/cvmarkersobj.h>
421        using namespace Concurrency::diagnostic;
422 
423        marker_series *series[256];
424        int seriesIndex;
425    #endif
426 
427     struct Marker {
428         #ifdef USE_CV_MARKERS
429             span *cvSpan;
430         #endif
431 
MarkerMarker432         Marker(const char *title) {
433             if (Core::support.profMarker) glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 1, -1, title);
434             #ifdef USE_CV_MARKERS
435                 marker_series *&s = series[seriesIndex];
436                 if (s == NULL) {
437                    char seriesTitle[64];
438                    sprintf(seriesTitle, "events - %d", seriesIndex);
439                    s = new marker_series(seriesTitle);
440                 }
441                 cvSpan = new span(*s, normal_importance, _T(title));
442                 seriesIndex++;
443             #endif
444         }
445 
~MarkerMarker446         ~Marker() {
447             if (Core::support.profMarker) glPopDebugGroup();
448             #ifdef USE_CV_MARKERS
449                 delete cvSpan;
450                 seriesIndex--;
451             #endif
452         }
453 
setLabelMarker454         static void setLabel(GLenum id, GLuint name, const char *label) {
455             if (Core::support.profMarker) glObjectLabel(id, name, -1, label);
456         }
457     };
458 
459     struct Timing {
460         GLuint  ID;
461         int     &result;
462 
TimingTiming463         Timing(int &result) : result(result) {
464             if (!Core::support.profTiming) return;
465             glGenQueries(1, &ID);
466             glBeginQuery(GL_TIME_ELAPSED, ID);
467         }
468 
~TimingTiming469         ~Timing() {
470             if (!Core::support.profTiming) return;
471             glEndQuery(GL_TIME_ELAPSED);
472             glGetQueryObjectiv(ID, GL_QUERY_RESULT, (GLint*)&result);
473             glDeleteQueries(1, &ID);
474         }
475     };
476 
477     #define PROFILE_MARKER(title)               Marker marker(title)
478     #define PROFILE_LABEL(id, name, label)      Marker::setLabel(GL_##id, name, label)
479     #define PROFILE_TIMING(result)              Timing timing(result)
480 #else
481     #define PROFILE_MARKER(title)
482     #define PROFILE_LABEL(id, name, label)
483     #define PROFILE_TIMING(time)
484 #endif
485 
486 
487 namespace GAPI {
488 
489     using namespace Core;
490 
491     typedef ::Vertex Vertex;
492 
493     int cullMode, blendMode;
494     bool depthWrite;
495 
496     char GLSL_HEADER_VERT[512];
497     char GLSL_HEADER_FRAG[512];
498 
499     bool GL_VER_3 = false;
500 
501 // Shader
502     #ifndef FFP
503         const char SHADER_COMPOSE[] =
504             #include "../shaders/compose.glsl"
505         ;
506 
507         const char SHADER_SHADOW[] =
508             #include "../shaders/shadow.glsl"
509         ;
510 
511         const char SHADER_AMBIENT[] =
512             #include "../shaders/ambient.glsl"
513         ;
514 
515         const char SHADER_SKY[] =
516             #include "../shaders/sky.glsl"
517         ;
518 
519         const char SHADER_WATER[] =
520             #include "../shaders/water.glsl"
521         ;
522 
523         const char SHADER_FILTER[] =
524             #include "../shaders/filter.glsl"
525         ;
526 
527         const char SHADER_GUI[] =
528             #include "../shaders/gui.glsl"
529         ;
530 
531         const char *DefineName[SD_MAX]  = { SHADER_DEFINES(DECL_STR) };
532     #endif
533 
534     static const struct Binding {
535         bool vec; // true - vec4, false - mat4
536         int  reg;
537     } bindings[uMAX] = {
538         { true,   0 }, // uParam
539         { true,   1 }, // uTexParam
540         { false,  2 }, // uViewProj
541         { true,   6 }, // uBasis
542         { false, 70 }, // uLightProj
543         { true,  74 }, // uMaterial
544         { true,  75 }, // uAmbient
545         { true,  81 }, // uFogParams
546         { true,  82 }, // uViewPos
547         { true,  83 }, // uLightPos
548         { true,  87 }, // uLightColor
549         { true,  91 }, // uRoomSize
550         { true,  92 }, // uPosScale
551         { true,  98 }, // uContacts
552     };
553 
554     struct Shader {
555     #ifdef FFP
initShader556         void init(Core::Pass pass, int type, int *def, int defCount) {}
deinitShader557         void deinit() {}
bindShader558         void bind() {}
validateShader559         void validate() {}
560         void setParam(UniformType uType, const vec4  &value, int count = 1) {}
561         void setParam(UniformType uType, const mat4  &value, int count = 1) {}
562     #else
563         GLuint  ID;
564         int32   uID[uMAX];
565 
566         vec4  cbMem[98 + MAX_CONTACTS];
567         int   cbCount[uMAX];
568 
569         bool  rebind;
570 
571         void init(Pass pass, int type, int *def, int defCount) {
572             const char *source;
573             switch (pass) {
574                 case Core::passCompose : source = SHADER_COMPOSE; break;
575                 case Core::passShadow  : source = SHADER_SHADOW;  break;
576                 case Core::passAmbient : source = SHADER_AMBIENT; break;
577                 case Core::passSky     : source = SHADER_SKY;     break;
578                 case Core::passWater   : source = SHADER_WATER;   break;
579                 case Core::passFilter  : source = SHADER_FILTER;  break;
580                 case Core::passGUI     : source = SHADER_GUI;     break;
581                 default                : ASSERT(false); LOG("! wrong pass id\n"); return;
582             }
583 
584             #ifdef _DEBUG_SHADERS
585                 Stream *stream = NULL;
586                 switch (pass) {
587                     case Core::passCompose : stream = new Stream(_DEBUG_SHADERS "compose.glsl"); break;
588                     case Core::passShadow  : stream = new Stream(_DEBUG_SHADERS "shadow.glsl");  break;
589                     case Core::passAmbient : stream = new Stream(_DEBUG_SHADERS "ambient.glsl"); break;
590                     case Core::passSky     : stream = new Stream(_DEBUG_SHADERS "sky.glsl");     break;
591                     case Core::passWater   : stream = new Stream(_DEBUG_SHADERS "water.glsl");   break;
592                     case Core::passFilter  : stream = new Stream(_DEBUG_SHADERS "filter.glsl");  break;
593                     case Core::passGUI     : stream = new Stream(_DEBUG_SHADERS "gui.glsl");     break;
594                     default                : ASSERT(false);  return;
595                 }
596 
597                 char *sourceData = new char[stream->size + 1];
598                 stream->raw(sourceData, stream->size);
599                 sourceData[stream->size] = 0;
600 
601                 source = sourceData;
602                 for (int i = 0; i < stream->size; i++) // trim string resource begin tag
603                     if (sourceData[i] == '(') {
604                         source = sourceData + i + 1;
605                         break;
606                     }
607 
608                 for (int i = stream->size - 1; i >= 0; i--) // trim string resource end tag
609                     if (sourceData[i] == ')') {
610                         sourceData[i] = 0;
611                         break;
612                     }
613 
614                 delete stream;
615             #endif
616 
617             char defines[1024];
618             defines[0] = 0;
619             strcat(defines, "#define VER3\n");
620 
621             for (int i = 0; i < defCount; i++) {
622                 sprintf(defines + strlen(defines), "#define %s\n", DefineName[def[i]]);
623             }
624 
625             sprintf(defines + strlen(defines), "#define SHADOW_SIZE %d.0\n", SHADOW_TEX_SIZE);
626 
627             #ifdef MERGE_MODELS
628                 strcat(defines, "#define MESH_SKINNING\n");
629             #endif
630 
631             // etnaviv driver has no sin/cos/abs implementation
632             #if !defined(_OS_GCW0)
633                 strcat(defines, "#define VERT_CAUSTICS\n");
634             #endif
635 
636             #if defined(_OS_RPI) || defined(_OS_CLOVER) || defined(_OS_GCW0) || (defined (__SDL2__) && defined(_GAPI_GLES))
637                 strcat(defines, "#define OPT_VLIGHTPROJ\n");
638                 strcat(defines, "#define OPT_VLIGHTVEC\n");
639                 strcat(defines, "#define OPT_SHADOW_ONETAP\n");
640             #endif
641 
642             if (support.tex3D) {
643                 strcat(defines, "#define OPT_TEXTURE_3D\n");
644             }
645 
646             #ifndef _OS_CLOVER
647                 // TODO: only for non Mali-400?
648                 strcat(defines, "#define OPT_TRAPEZOID\n");
649                 if (Core::settings.detail.water > Core::Settings::LOW)
650                     strcat(defines, "#define OPT_UNDERWATER_FOG\n");
651             #endif
652 
653             char fileName[255];
654         // generate shader file path
655             if (Core::support.shaderBinary) {
656                 uint32 hash = fnv32(defines, (int32)strlen(defines), fnv32(source, (int32)strlen(source)));
657                 sprintf(fileName, "%08X.xsh", hash);
658             }
659 
660             ID = glCreateProgram();
661 
662             if (!(Core::support.shaderBinary && linkBinary(fileName))) { // try to load cached shader
663                 if (linkSource(source, defines) && Core::support.shaderBinary) { // compile shader from source and dump it into cache
664                 #ifndef _OS_WEB
665                     GLenum format = 0, size;
666                     glGetProgramiv(ID, GL_PROGRAM_BINARY_LENGTH, (GLsizei*)&size);
667                     char *data = new char[8 + size];
668                     glGetProgramBinary(ID, size, NULL, &format, &data[8]);
669                     *(int*)(&data[0]) = format;
670                     *(int*)(&data[4]) = size;
671                     Stream::cacheWrite(fileName, data, 8 + size);
672                     delete[] data;
673                 #endif
674                 }
675             }
676 
677             #ifdef _DEBUG_SHADERS
678                 delete[] sourceData;
679             #endif
680 
681             Core::active.shader = this;
682             glUseProgram(ID);
683 
684             for (int st = 0; st < sMAX; st++) {
685                 GLint idx = glGetUniformLocation(ID, (GLchar*)SamplerName[st]);
686                 if (idx != -1)
687                     glUniform1iv(idx, 1, &st);
688             }
689 
690             for (int ut = 0; ut < uMAX; ut++)
691                 uID[ut] = glGetUniformLocation(ID, (GLchar*)UniformName[ut]);
692 
693             rebind = true;
694         }
695 
696         void deinit() {
697             glDeleteProgram(ID);
698         }
699 
700         bool linkSource(const char *text, const char *defines = "") {
701             const int type[2] = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER };
702             const char *code[2][4] = {
703                     { GLSL_HEADER_VERT, defines, "#line 0\n", text },
704                     { GLSL_HEADER_FRAG, defines, "#line 0\n", text }
705                 };
706 
707             GLchar info[1024];
708 
709             for (int i = 0; i < 2; i++) {
710                 GLuint obj = glCreateShader(type[i]);
711                 glShaderSource(obj, 4, code[i], NULL);
712                 glCompileShader(obj);
713 
714                 glGetShaderInfoLog(obj, sizeof(info), NULL, info);
715                 if (info[0] && strlen(info) > 8) LOG("! shader: %s\n", info);
716 
717                 glAttachShader(ID, obj);
718                 glDeleteShader(obj);
719             }
720 
721             for (int at = 0; at < aMAX; at++)
722                 glBindAttribLocation(ID, at, AttribName[at]);
723 
724             glLinkProgram(ID);
725 
726             glGetProgramInfoLog(ID, sizeof(info), NULL, info);
727             if (info[0] && strlen(info) > 8) LOG("! program: %s\n", info);
728 
729             return checkLink();
730         }
731 
732         bool linkBinary(const char *name) {
733             // non-async code!
734             char path[255];
735             strcpy(path, cacheDir);
736             strcat(path, name);
737 
738             if (!Stream::exists(path))
739                 return false;
740 
741             Stream *stream = new Stream(path);
742             if (!stream)
743                 return false;
744 
745             GLenum size, format;
746             stream->read(format);
747             stream->read(size);
748             char *data = new char[size];
749             stream->raw(data, size);
750             glProgramBinary(ID, format, data, size);
751             delete[] data;
752             delete stream;
753 
754             return checkLink();
755         }
756 
757         bool checkLink() {
758             GLint success;
759             glGetProgramiv(ID, GL_LINK_STATUS, &success);
760             return success != 0;
761         }
762 
763         void bind() {
764             if (Core::active.shader != this) {
765                 Core::active.shader = this;
766                 memset(cbCount, 0, sizeof(cbCount));
767                 rebind = true;
768             }
769         }
770 
771         void validate() {
772             if (rebind) {
773                 glUseProgram(ID);
774                 rebind = false;
775             }
776 
777             for (int uType = 0; uType < uMAX; uType++) {
778                 if (!cbCount[uType]) continue;
779 
780                 const Binding &b = bindings[uType];
781 
782                 if (b.vec)
783                     glUniform4fv(uID[uType], cbCount[uType], (GLfloat*)(cbMem + b.reg));
784                 else
785                     glUniformMatrix4fv(uID[uType], cbCount[uType] / 4, false, (GLfloat*)(cbMem + b.reg));
786 
787                 cbCount[uType] = 0;
788                 Core::stats.cb++;
789             }
790         }
791 
792         void setParam(UniformType uType, float *value, int count) {
793             cbCount[uType] = count;
794             memcpy(cbMem + bindings[uType].reg, value, count * 16);
795         }
796 
797         void setParam(UniformType uType, const vec4 &value, int count = 1) {
798             if (uID[uType] != -1) setParam(uType, (float*)&value, count);
799         }
800 
801         void setParam(UniformType uType, const mat4 &value, int count = 1) {
802             if (uID[uType] != -1) setParam(uType, (float*)&value, count * 4);
803         }
804     #endif
805     };
806 
807 
808 // Texture
809     static const struct FormatDesc {
810         GLuint ifmt, fmt;
811         GLenum type;
812     } formats[FMT_MAX] = {
813         { GL_LUMINANCE,       GL_LUMINANCE,       GL_UNSIGNED_BYTE          }, // LUMINANCE
814         { GL_RGBA,            GL_RGBA,            GL_UNSIGNED_BYTE          }, // RGBA
815         { GL_RGB,             GL_RGB,             GL_UNSIGNED_SHORT_5_6_5   }, // RGB16
816         { GL_RGBA,            GL_RGBA,            GL_UNSIGNED_SHORT_5_5_5_1 }, // RGBA16
817         { GL_RG32F,           GL_RG,              GL_FLOAT                  }, // RG_FLOAT
818         { GL_RG16F,           GL_RG,              GL_HALF_FLOAT             }, // RG_HALF
819         { GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT         }, // DEPTH
820         { GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT         }, // SHADOW
821     };
822 
823     struct Texture {
824         uint32     ID;
825         int        width, height, depth, origWidth, origHeight, origDepth;
826         TexFormat  fmt;
827         uint32     opt;
828         GLenum     target;
829 
TextureTexture830         Texture(int width, int height, int depth, uint32 opt) : ID(0), width(width), height(height), depth(depth), origWidth(width), origHeight(height), origDepth(depth), fmt(FMT_RGBA), opt(opt) {}
831 
initTexture832         void init(void *data) {
833             ASSERT((opt & OPT_PROXY) == 0);
834 
835             bool filter   = (opt & OPT_NEAREST) == 0;
836             bool mipmaps  = (opt & OPT_MIPMAPS) != 0;
837             bool isCube   = (opt & OPT_CUBEMAP) != 0;
838             bool isVolume = (opt & OPT_VOLUME)  != 0;
839             bool isShadow = fmt == FMT_SHADOW;
840 
841             target = isVolume ? GL_TEXTURE_3D : (isCube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D);
842 
843             glGenTextures(1, &ID);
844 
845             Core::active.textures[0] = NULL;
846             bind(0);
847 
848             if (isShadow) {
849                 glTexParameteri(target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
850                 glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
851             }
852 
853             glTexParameteri(target, GL_TEXTURE_WRAP_S, (opt & OPT_REPEAT) ? GL_REPEAT : GL_CLAMP_TO_EDGE);
854             glTexParameteri(target, GL_TEXTURE_WRAP_T, (opt & OPT_REPEAT) ? GL_REPEAT : GL_CLAMP_TO_EDGE);
855             if (isVolume) {
856                 glTexParameteri(target, GL_TEXTURE_WRAP_R, (opt & OPT_REPEAT) ? GL_REPEAT : GL_CLAMP_TO_EDGE);
857             }
858 
859             glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter ? (mipmaps ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR) : (mipmaps ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST));
860             glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter ? GL_LINEAR : GL_NEAREST);
861 
862             FormatDesc desc = getFormat();
863 
864             void *pix = (width == origWidth && height == origHeight && depth == origDepth) ? data : NULL;
865 
866             if (isVolume) {
867                 glTexImage3D(target, 0, desc.ifmt, width, height, depth, 0, desc.fmt, desc.type, pix);
868             } else if (isCube) {
869                 for (int i = 0; i < 6; i++) {
870                     glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, desc.ifmt, width, height, 0, desc.fmt, desc.type, pix);
871                 }
872             } else {
873                 glTexImage2D(target, 0, desc.ifmt, width, height, 0, desc.fmt, desc.type, pix);
874             }
875 
876             if (pix != data) {
877                 update(data);
878             }
879         }
880 
deinitTexture881         void deinit() {
882             if (ID) {
883                 glDeleteTextures(1, &ID);
884             }
885         }
886 
getFormatTexture887         FormatDesc getFormat() {
888             FormatDesc desc = formats[fmt];
889 
890             if ((fmt == FMT_RG_FLOAT || fmt == FMT_RG_HALF) && !Core::support.texRG) {
891                 desc.ifmt = (fmt == FMT_RG_FLOAT) ? GL_RGBA32F : GL_RGBA16F;
892                 desc.fmt  = GL_RGBA;
893             }
894 
895             if (fmt == FMT_LUMINANCE && Core::support.texRG) {
896                 desc.ifmt = GL_R8;
897                 desc.fmt  = GL_RED;
898             }
899 
900             #ifdef _OS_WEB // fucking firefox!
901                 if (WEBGL_VERSION == 1) {
902                     if (fmt == FMT_RG_FLOAT) {
903                         if (Core::support.texFloat) {
904                             desc.ifmt = GL_RGBA;
905                             desc.type = GL_FLOAT;
906                         }
907                     }
908 
909                     if (fmt == FMT_RG_HALF) {
910                         if (Core::support.texHalf) {
911                             desc.ifmt = GL_RGBA;
912                             desc.type = GL_HALF_FLOAT_OES;
913                         }
914                     }
915                 } else {
916                     if (fmt == FMT_DEPTH || fmt == FMT_SHADOW) {
917                         desc.ifmt = GL_DEPTH_COMPONENT16;
918                     }
919                 }
920             #else
921                 if ((fmt == FMT_RG_FLOAT && !Core::support.colorFloat) || (fmt == FMT_RG_HALF && !Core::support.colorHalf)) {
922                     desc.ifmt = GL_RGBA;
923                     #ifdef _GAPI_GLES
924                         if (fmt == FMT_RG_HALF) {
925                             desc.type = GL_HALF_FLOAT_OES;
926                         }
927                     #endif
928                 }
929             #endif
930             return desc;
931         }
932 
generateMipMapTexture933         void generateMipMap() {
934             bind(0);
935             if (glGenerateMipmap) {
936                 glGenerateMipmap(target);
937             }
938             if ((opt & (OPT_VOLUME | OPT_CUBEMAP | OPT_NEAREST)) == 0 && (Core::support.maxAniso > 0)) {
939                 glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, min(int(Core::support.maxAniso), 8));
940                 if (Core::support.texMaxLevel) {
941                     glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, 3);
942                 }
943             }
944         }
945 
updateTexture946         void update(void *data) {
947             ASSERT((opt & (OPT_VOLUME | OPT_CUBEMAP)) == 0);
948             bind(0);
949             FormatDesc desc = getFormat();
950             glTexSubImage2D(target, 0, 0, 0, origWidth, origHeight, desc.fmt, desc.type, data);
951         }
952 
bindTexture953         void bind(int sampler) {
954             if (opt & OPT_PROXY) return;
955             ASSERT(ID);
956 
957             if (Core::active.textures[sampler] != this) {
958                 Core::active.textures[sampler] = this;
959             #ifdef FFP
960                 if (sampler != sDiffuse) {
961                     return;
962                 }
963             #else
964                 glActiveTexture(GL_TEXTURE0 + sampler);
965             #endif
966                 glBindTexture(target, ID);
967             }
968         }
969 
unbindTexture970         void unbind(int sampler) {
971             if (Core::active.textures[sampler]) {
972                 Core::active.textures[sampler] = NULL;
973             #ifdef FFP
974                 if (sampler != sDiffuse) {
975                     return;
976                 }
977             #else
978                 glActiveTexture(GL_TEXTURE0 + sampler);
979             #endif
980                 glBindTexture(target, 0);
981             }
982         }
983 
setFilterQualityTexture984         void setFilterQuality(int value) {
985             bool filter  = (opt & OPT_NEAREST) == 0 && (value > Core::Settings::LOW);
986             bool mipmaps = (opt & OPT_MIPMAPS) != 0;
987 
988             Core::active.textures[0] = NULL;
989             bind(0);
990             if (Core::support.maxAniso > 0) {
991                 glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, value > Core::Settings::MEDIUM ? min(int(Core::support.maxAniso), 8) : 1);
992             }
993             glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter ? (mipmaps ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR ) : ( mipmaps ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST ));
994             glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter ? GL_LINEAR : GL_NEAREST);
995         }
996     };
997 
998 // Mesh
999     struct Mesh {
1000         Index  *iBuffer;
1001         Vertex *vBuffer;
1002         GLuint *VAO;
1003         GLuint ID[2];
1004 
1005         int    iCount;
1006         int    vCount;
1007         int    aCount;
1008         bool   dynamic;
1009 
MeshMesh1010         Mesh(bool dynamic) : iBuffer(NULL), vBuffer(NULL), VAO(NULL), dynamic(dynamic) {
1011             ID[0] = ID[1] = 0;
1012         }
1013 
initMesh1014         void init(Index *indices, int iCount, ::Vertex *vertices, int vCount, int aCount) {
1015             this->iCount = iCount;
1016             this->vCount = vCount;
1017             this->aCount = aCount;
1018 
1019             if (Core::support.VAO)
1020                 glBindVertexArray(Core::active.VAO = 0);
1021 
1022             bool useVBO = Core::support.VBO;
1023 
1024             #ifdef DYNGEOM_NO_VBO
1025                 if (!vertices && !indices) {
1026                     useVBO = false;
1027                 }
1028             #endif
1029 
1030             ASSERT(sizeof(GAPI::Vertex) == sizeof(::Vertex));
1031 
1032             if (useVBO) {
1033                 glGenBuffers(2, ID);
1034                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ID[0]);
1035                 glBindBuffer(GL_ARRAY_BUFFER,         ID[1]);
1036                 glBufferData(GL_ELEMENT_ARRAY_BUFFER, iCount * sizeof(Index),  indices,  dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
1037                 glBufferData(GL_ARRAY_BUFFER,         vCount * sizeof(Vertex), vertices, dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
1038             } else {
1039                 iBuffer = new Index[iCount];
1040                 vBuffer = new GAPI::Vertex[vCount];
1041                 update(indices, iCount, vertices, vCount);
1042             }
1043 
1044             if (Core::support.VAO && aCount) {
1045                 VAO = new GLuint[aCount];
1046                 glGenVertexArrays(aCount, VAO);
1047             }
1048         }
1049 
deinitMesh1050         void deinit() {
1051             if (iBuffer || vBuffer) {
1052                 delete[] iBuffer;
1053                 delete[] vBuffer;
1054             } else {
1055                 if (VAO) {
1056                     glDeleteVertexArrays(aCount, VAO);
1057                     delete[] VAO;
1058                 }
1059                 glDeleteBuffers(2, ID);
1060             }
1061         }
1062 
updateMesh1063         void update(Index *indices, int iCount, ::Vertex *vertices, int vCount) {
1064             ASSERT(sizeof(GAPI::Vertex) == sizeof(::Vertex));
1065 
1066             if (Core::support.VAO && Core::active.VAO != 0)
1067                 glBindVertexArray(Core::active.VAO = 0);
1068 
1069             if (indices && iCount) {
1070                 if (iBuffer) {
1071                     memcpy(iBuffer, indices, iCount * sizeof(Index));
1072                 } else {
1073                     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Core::active.iBuffer = ID[0]);
1074                     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, iCount * sizeof(Index), indices);
1075                 }
1076             }
1077             if (vertices && vCount) {
1078                 if (vBuffer) {
1079                     memcpy(vBuffer, vertices, vCount * sizeof(GAPI::Vertex));
1080                 } else {
1081                     glBindBuffer(GL_ARRAY_BUFFER, Core::active.vBuffer = ID[1]);
1082                     glBufferSubData(GL_ARRAY_BUFFER, 0, vCount * sizeof(GAPI::Vertex), vertices);
1083                 }
1084             }
1085         }
1086 
setupFVFMesh1087         void setupFVF(GAPI::Vertex *v) const {
1088             #ifdef FFP
1089                 glTexCoordPointer (2, GL_SHORT,         sizeof(*v), &v->texCoord);
1090                 glColorPointer    (4, GL_UNSIGNED_BYTE, sizeof(*v), &v->light);
1091                 glNormalPointer   (   GL_SHORT,         sizeof(*v), &v->normal);
1092                 glVertexPointer   (3, GL_SHORT,         sizeof(*v), &v->coord);
1093             #else
1094                 glEnableVertexAttribArray(aCoord);
1095                 glEnableVertexAttribArray(aNormal);
1096                 glEnableVertexAttribArray(aTexCoord);
1097                 glEnableVertexAttribArray(aColor);
1098                 glEnableVertexAttribArray(aLight);
1099 
1100                 glVertexAttribPointer(aCoord,    4, GL_SHORT,         false, sizeof(*v), &v->coord);
1101                 glVertexAttribPointer(aNormal,   4, GL_SHORT,         true,  sizeof(*v), &v->normal);
1102                 glVertexAttribPointer(aTexCoord, 4, GL_SHORT,         true,  sizeof(*v), &v->texCoord);
1103                 glVertexAttribPointer(aColor,    4, GL_UNSIGNED_BYTE, true,  sizeof(*v), &v->color);
1104                 glVertexAttribPointer(aLight,    4, GL_UNSIGNED_BYTE, true,  sizeof(*v), &v->light);
1105             #endif
1106         }
1107 
bindMesh1108         void bind(const MeshRange &range) const {
1109             if (range.aIndex == -1) {
1110                 if (Core::support.VBO && Core::active.iBuffer != ID[0])
1111                     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Core::active.iBuffer = ID[0]);
1112                 if (Core::support.VBO && Core::active.vBuffer != ID[1])
1113                     glBindBuffer(GL_ARRAY_BUFFER, Core::active.vBuffer = ID[1]);
1114                 setupFVF(vBuffer + range.vStart);
1115             } else {
1116                 ASSERT(Core::support.VAO);
1117                 GLuint vao = VAO[range.aIndex];
1118                 if (Core::active.VAO != vao)
1119                     glBindVertexArray(Core::active.VAO = vao);
1120             }
1121         }
1122 
initNextRangeMesh1123         void initNextRange(MeshRange &range, int &aIndex) const {
1124             if (Core::support.VAO && VAO) {
1125                 ASSERT(aIndex < aCount);
1126 
1127                 Core::active.iBuffer = 0;
1128                 Core::active.vBuffer = 0;
1129                 Core::active.VAO     = 0;
1130 
1131                 range.aIndex = aIndex++;    // get new VAO index
1132                 bind(range);                // bind VAO
1133                 range.aIndex = -1;          // reset VAO to -1
1134                 bind(range);                // bind buffers and setup vertex format
1135                 range.aIndex = aIndex - 1;  // set VAO index back to the new
1136 
1137                 glBindVertexArray(Core::active.VAO = 0);
1138             } else
1139                 range.aIndex = -1;
1140         }
1141     };
1142 
1143 
1144     GLuint FBO, defaultFBO;
1145     struct RenderTargetCacheItem {
1146         GLuint  ID;
1147         int     width;
1148         int     height;
1149     };
1150     Array<RenderTargetCacheItem> rtCache[2];
1151 
1152 
extSupport(const char * str)1153     bool extSupport(const char *str) {
1154         if (glGetStringi != NULL) {
1155             GLint count = 0;
1156             glGetIntegerv(GL_NUM_EXTENSIONS, &count);
1157             for (int i = 0; i < count; i++) {
1158                 const char *ext = (const char*)glGetStringi(GL_EXTENSIONS, i);
1159                 if (strstr(ext, str) != NULL) {
1160                     return true;
1161                 }
1162             }
1163         } else {
1164             const char *ext =  (const char*)glGetString(GL_EXTENSIONS);
1165             if (!ext) {
1166                 return false;
1167             }
1168             return strstr(ext, str) != NULL;
1169         }
1170 
1171         return false;
1172     }
1173 
init()1174     void init() {
1175         #ifdef _OS_ANDROID
1176             //void *libGL = dlopen("libGLESv2.so", RTLD_LAZY);
1177         #endif
1178 
1179         #if (defined(__SDL2__) && defined(_GAPI_GLES2))
1180                 GetProcOGL(glDiscardFramebufferEXT);
1181         #endif
1182 
1183         #if defined(_OS_WIN) || defined(_OS_LINUX) || defined(_OS_GCW0) || (defined(__SDL2__) && !defined(_GAPI_GLES))
1184             #ifdef _OS_WIN
1185                 GetProcOGL(glActiveTexture);
1186             #endif
1187 
1188             #ifdef _OS_WIN
1189                 GetProcOGL(wglSwapIntervalEXT);
1190             #elif _OS_LINUX
1191                 GetProcOGL(glXSwapIntervalSGI);
1192             #endif
1193 
1194             #if defined(_OS_WIN) || defined(_OS_LINUX) || (defined(__SDL2__) && (defined(_GAPI_GLES2) || defined(_SDL2_OPENGL)))
1195                 GetProcOGL(glGenerateMipmap);
1196                 #ifdef _OS_WIN
1197                     GetProcOGL(glTexImage3D);
1198                 #endif
1199 
1200                 GetProcOGL(glGetStringi);
1201 
1202                 #ifdef PROFILE
1203                     GetProcOGL(glObjectLabel);
1204                     GetProcOGL(glPushDebugGroup);
1205                     GetProcOGL(glPopDebugGroup);
1206                     GetProcOGL(glGenQueries);
1207                     GetProcOGL(glDeleteQueries);
1208                     GetProcOGL(glGetQueryObjectiv);
1209                     GetProcOGL(glBeginQuery);
1210                     GetProcOGL(glEndQuery);
1211                 #endif
1212 
1213                 GetProcOGL(glCreateProgram);
1214                 GetProcOGL(glDeleteProgram);
1215                 GetProcOGL(glLinkProgram);
1216                 GetProcOGL(glUseProgram);
1217                 GetProcOGL(glGetProgramInfoLog);
1218                 GetProcOGL(glCreateShader);
1219                 GetProcOGL(glDeleteShader);
1220                 GetProcOGL(glShaderSource);
1221                 GetProcOGL(glAttachShader);
1222                 GetProcOGL(glCompileShader);
1223                 GetProcOGL(glGetShaderInfoLog);
1224                 GetProcOGL(glGetUniformLocation);
1225                 GetProcOGL(glUniform1iv);
1226                 GetProcOGL(glUniform1fv);
1227                 GetProcOGL(glUniform2fv);
1228                 GetProcOGL(glUniform3fv);
1229                 GetProcOGL(glUniform4fv);
1230                 GetProcOGL(glUniformMatrix4fv);
1231                 GetProcOGL(glBindAttribLocation);
1232                 GetProcOGL(glEnableVertexAttribArray);
1233                 GetProcOGL(glDisableVertexAttribArray);
1234                 GetProcOGL(glVertexAttribPointer);
1235                 GetProcOGL(glGetProgramiv);
1236 
1237                 GetProcOGL(glGenFramebuffers);
1238                 GetProcOGL(glBindFramebuffer);
1239                 GetProcOGL(glGenRenderbuffers);
1240                 GetProcOGL(glBindRenderbuffer);
1241                 GetProcOGL(glFramebufferTexture2D);
1242                 GetProcOGL(glFramebufferRenderbuffer);
1243                 GetProcOGL(glRenderbufferStorage);
1244                 GetProcOGL(glCheckFramebufferStatus);
1245                 GetProcOGL(glDeleteFramebuffers);
1246                 GetProcOGL(glDeleteRenderbuffers);
1247                 GetProcOGL(glGetFramebufferAttachmentParameteriv);
1248 
1249                 GetProcOGL(glGenBuffers);
1250                 GetProcOGL(glDeleteBuffers);
1251                 GetProcOGL(glBindBuffer);
1252                 GetProcOGL(glBufferData);
1253                 GetProcOGL(glBufferSubData);
1254             #endif
1255 
1256             GetProcOGL(glGenVertexArrays);
1257             GetProcOGL(glDeleteVertexArrays);
1258             GetProcOGL(glBindVertexArray);
1259 
1260             GetProcOGL(glGetProgramBinary);
1261             GetProcOGL(glProgramBinary);
1262 
1263             #if defined(_GAPI_GLES)
1264                 GetProcOGL(glDiscardFramebufferEXT);
1265             #endif
1266         #endif
1267 
1268         LOG("Vendor   : %s\n", (char*)glGetString(GL_VENDOR));
1269         LOG("Renderer : %s\n", (char*)glGetString(GL_RENDERER));
1270         LOG("Version  : %s\n", (char*)glGetString(GL_VERSION));
1271 
1272     #ifndef FFP
1273         bool GLES3 = false;
1274         #ifdef _OS_WEB
1275             GLES3 = WEBGL_VERSION != 1;
1276         #else
1277             #if defined(_GAPI_GLES) && !defined(_GAPI_GLES2)
1278                 int GLES_VERSION = 1;
1279                 #if defined(__SDL2__)
1280                     SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &GLES_VERSION);
1281                 #else
1282                     #if defined(_OS_RPI) || defined(_OS_CLOVER) || defined(_OS_GCW0)
1283                         GLES_VERSION = 2;
1284                     #else
1285                         glGetIntegerv(GL_MAJOR_VERSION, &GLES_VERSION);
1286                     #endif
1287                 #endif
1288                 GLES3 = GLES_VERSION > 2;
1289             #endif
1290         #endif
1291 
1292         bool _GL_EXT_shadow_samplers      = extSupport("GL_EXT_shadow_samplers");
1293         bool _GL_ARB_shadow               = extSupport("GL_ARB_shadow");
1294         bool _GL_OES_standard_derivatives = extSupport("GL_OES_standard_derivatives");
1295 
1296         support.shaderBinary   = extSupport("_program_binary");
1297         support.VAO            = GLES3 || extSupport("_vertex_array_object");
1298         support.VBO            = glGenBuffers != NULL;
1299         support.depthTexture   = GLES3 || extSupport("_depth_texture");
1300         support.shadowSampler  = _GL_EXT_shadow_samplers || _GL_ARB_shadow;
1301         support.discardFrame   = extSupport("_discard_framebuffer");
1302         support.texNPOT        = GLES3 || extSupport("_texture_npot") || extSupport("_texture_non_power_of_two");
1303         support.texRG          = GLES3 || extSupport("_texture_rg");
1304         support.texMaxLevel    = GLES3 || extSupport("_texture_max_level");
1305 
1306         #ifdef _GAPI_GLES2 // TODO
1307             support.shaderBinary = false;
1308             support.VAO = false;
1309             support.texRG = false;
1310             support.discardFrame = false;
1311         #endif
1312         #ifdef _GAPI_GLES
1313             support.derivatives = GLES3 || _GL_OES_standard_derivatives;
1314             support.tex3D       = GLES3;
1315         #else
1316             support.derivatives = true;
1317             support.tex3D       = glTexImage3D != NULL;
1318         #endif
1319         support.texBorder      = extSupport("_texture_border_clamp");
1320         support.maxAniso       = extSupport("_texture_filter_anisotropic");
1321         support.colorFloat     = extSupport("_color_buffer_float");
1322         support.colorHalf      = extSupport("_color_buffer_half_float") || extSupport("GL_ARB_half_float_pixel");
1323         support.texFloatLinear = support.colorFloat || extSupport("GL_ARB_texture_float") || extSupport("_texture_float_linear");
1324         support.texFloat       = support.texFloatLinear || extSupport("_texture_float");
1325         support.texHalfLinear  = support.colorHalf || extSupport("GL_ARB_texture_float") || extSupport("_texture_half_float_linear") || extSupport("_color_buffer_half_float");
1326 
1327         support.texHalf        = support.texHalfLinear || extSupport("_texture_half_float");
1328 
1329         #ifdef SDL2_GLES
1330             support.shaderBinary  = false; // TODO
1331             support.VAO           = false; // TODO
1332             support.shadowSampler = false; // TODO
1333         #endif
1334 
1335         #ifdef PROFILE
1336             support.profMarker = extSupport("_KHR_debug");
1337             support.profTiming = extSupport("_timer_query");
1338         #endif
1339 
1340         if (support.maxAniso)
1341             glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &support.maxAniso);
1342         #ifdef _GAPI_GLES
1343             glGetIntegerv(GL_MAX_VARYING_VECTORS, &support.maxVectors);
1344         #else
1345             support.maxVectors = 16;
1346         #endif
1347     #endif
1348 
1349         glEnable(GL_SCISSOR_TEST);
1350         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1351 
1352         glDepthFunc(GL_LEQUAL);
1353 
1354     #ifdef FFP
1355         glEnable(GL_TEXTURE_2D);
1356         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1357         glEnableClientState(GL_COLOR_ARRAY);
1358         glEnableClientState(GL_NORMAL_ARRAY);
1359         glEnableClientState(GL_VERTEX_ARRAY);
1360 
1361         glAlphaFunc(GL_GREATER, 0.5f);
1362 
1363         glMatrixMode(GL_TEXTURE);
1364         glLoadIdentity();
1365         glScalef(1.0f / 32767.0f, 1.0f / 32767.0f, 1.0f / 32767.0f);
1366 
1367         glClearColor(0, 0, 0, 0);
1368     #else
1369         glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&defaultFBO);
1370         glGenFramebuffers(1, &FBO);
1371 
1372         char extHeader[256];
1373         GLSL_HEADER_VERT[0] = GLSL_HEADER_FRAG[0] = extHeader[0] = 0;
1374         if (_GL_OES_standard_derivatives) {
1375             if (!GLES3) {
1376                 strcat(extHeader, "#extension GL_OES_standard_derivatives : enable\n");
1377             }
1378         }
1379 
1380         if (_GL_EXT_shadow_samplers && !_GL_ARB_shadow) {
1381             if (!GLES3) {
1382                 strcat(extHeader, "#extension GL_EXT_shadow_samplers : enable\n");
1383             }
1384         }
1385 
1386     #ifdef _GAPI_GLES
1387         if (GLES3) {
1388             // vertex
1389             strcat(GLSL_HEADER_VERT, "#version 300 es\n"
1390                                      "precision lowp  int;\n"
1391                                      "precision highp float;\n"
1392                                      "#define VERTEX\n"
1393                                      "#define varying   out\n"
1394                                      "#define attribute in\n"
1395                                      "#define texture2D texture\n");
1396             // fragment
1397             strcat(GLSL_HEADER_FRAG, "#version 300 es\n");
1398             strcat(GLSL_HEADER_FRAG, extHeader);
1399             strcat(GLSL_HEADER_FRAG, "precision lowp  int;\n"
1400                                      "precision highp float;\n"
1401                                      "precision lowp  sampler3D;\n"
1402                                      "#define FRAGMENT\n"
1403                                      "#define varying     in\n"
1404                                      "#define texture2D   texture\n"
1405                                      "#define texture3D   texture\n"
1406                                      "#define textureCube texture\n"
1407                                      "#define FETCH_SHADOW2D(a,b) texture(a,b)\n"
1408                                      "out vec4 fragColor;\n");
1409         } else {
1410             // vertex
1411             strcat(GLSL_HEADER_VERT, "#version 100\n"
1412                                      "precision lowp  int;\n"
1413                                      "precision highp float;\n"
1414                                      "#define VERTEX\n");
1415             // fragment
1416             strcat(GLSL_HEADER_FRAG, "#version 100\n");
1417             strcat(GLSL_HEADER_FRAG, extHeader);
1418             strcat(GLSL_HEADER_FRAG, "precision lowp  int;\n"
1419                                      "precision highp float;\n"
1420                                      "#define FRAGMENT\n"
1421                                      "#define FETCH_SHADOW2D(a,b) shadow2DEXT(a,b)\n"
1422                                      "#define fragColor gl_FragColor\n");
1423         }
1424 
1425         if (support.shadowSampler) {
1426             strcat(GLSL_HEADER_FRAG, "#define sampler2DShadow lowp sampler2DShadow\n");
1427         }
1428     #else
1429         if (GL_VER_3) {
1430             strcat(GLSL_HEADER_VERT, "#version 150\n"
1431                                      "#define VERTEX\n"
1432                                      "#define varying   out\n"
1433                                      "#define attribute in\n"
1434                                      "#define texture2D texture\n");
1435             // fragment
1436             strcat(GLSL_HEADER_FRAG, "#version 150\n");
1437             strcat(GLSL_HEADER_FRAG, extHeader);
1438             strcat(GLSL_HEADER_FRAG, "#define FRAGMENT\n"
1439                                      "#define varying     in\n"
1440                                      "#define texture2D   texture\n"
1441                                      "#define texture3D   texture\n"
1442                                      "#define textureCube texture\n"
1443                                      "#define FETCH_SHADOW2D(a,b) texture(a,b)\n"
1444                                      "out vec4 fragColor;\n");
1445         } else {
1446             // vertex
1447             strcat(GLSL_HEADER_VERT, "#version 110\n"
1448                                      "#define VERTEX\n");
1449             // fragment
1450             strcat(GLSL_HEADER_FRAG, "#version 110\n");
1451             strcat(GLSL_HEADER_FRAG, extHeader);
1452             strcat(GLSL_HEADER_FRAG, "#define FRAGMENT\n"
1453                                      "#define FETCH_SHADOW2D(a,b) shadow2D(a,b).x\n"
1454                                      "#define fragColor gl_FragColor\n");
1455         }
1456     #endif
1457         ASSERT(strlen(GLSL_HEADER_VERT) < COUNT(GLSL_HEADER_VERT));
1458         ASSERT(strlen(GLSL_HEADER_FRAG) < COUNT(GLSL_HEADER_FRAG));
1459     #endif // FFP
1460     }
1461 
deinit()1462     void deinit() {
1463         #ifdef FFP
1464             return;
1465         #endif
1466         glBindFramebuffer(GL_FRAMEBUFFER, 0);
1467         glDeleteFramebuffers(1, &FBO);
1468 
1469         glBindRenderbuffer(GL_RENDERBUFFER, 0);
1470         for (int b = 0; b < 2; b++) {
1471             for (int i = 0; i < rtCache[b].length; i++) {
1472                 glDeleteRenderbuffers(1, &rtCache[b][i].ID);
1473             }
1474             rtCache[b].clear();
1475         }
1476     }
1477 
getProjRange()1478     inline mat4::ProjRange getProjRange() {
1479         return mat4::PROJ_NEG_POS;
1480     }
1481 
ortho(float l,float r,float b,float t,float znear,float zfar)1482     mat4 ortho(float l, float r, float b, float t, float znear, float zfar) {
1483         mat4 m;
1484         m.ortho(getProjRange(), l, r, b, t, znear, zfar);
1485         return m;
1486     }
1487 
perspective(float fov,float aspect,float znear,float zfar,float eye)1488     mat4 perspective(float fov, float aspect, float znear, float zfar, float eye) {
1489         mat4 m;
1490         m.perspective(getProjRange(), fov, aspect, znear, zfar, eye);
1491         return m;
1492     }
1493 
beginFrame()1494     bool beginFrame() {
1495         return true;
1496     }
1497 
endFrame()1498     void endFrame() {}
1499 
resetState()1500     void resetState() {
1501         if (Core::support.VAO)
1502             glBindVertexArray(0);
1503 
1504         #ifndef FFP
1505             glActiveTexture(GL_TEXTURE0);
1506             glUseProgram(0);
1507         #endif
1508 
1509         if (Core::support.VBO) {
1510             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1511             glBindBuffer(GL_ARRAY_BUFFER, 0);
1512         }
1513     }
1514 
cacheRenderTarget(bool depth,int width,int height)1515     int cacheRenderTarget(bool depth, int width, int height) {
1516         Array<RenderTargetCacheItem> &items = rtCache[depth];
1517 
1518         for (int i = 0; i < items.length; i++)
1519             if (items[i].width == width && items[i].height == height) {
1520                 RenderTargetCacheItem item = items[i];
1521                 items.remove(i);
1522                 return items.push(item);
1523             }
1524 
1525         if (items.length >= MAX_RENDER_BUFFERS) {
1526             glDeleteRenderbuffers(1, &items[0].ID);
1527             items.remove(0);
1528         }
1529 
1530         RenderTargetCacheItem item;
1531         item.width  = width;
1532         item.height = height;
1533 
1534         glGenRenderbuffers(1, &item.ID);
1535         glBindRenderbuffer(GL_RENDERBUFFER, item.ID);
1536         glRenderbufferStorage(GL_RENDERBUFFER, depth ? GL_DEPTH_COMPONENT16 : GL_RGB565, width, height);
1537         glBindRenderbuffer(GL_RENDERBUFFER, 0);
1538         return items.push(item);
1539     }
1540 
bindTarget(Texture * target,int face)1541     void bindTarget(Texture *target, int face) {
1542         if (!target) { // may be a null
1543             glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
1544         } else {
1545             GLenum texTarget = GL_TEXTURE_2D;
1546             if (target->opt & OPT_CUBEMAP) {
1547                 texTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
1548             }
1549 
1550             bool depth = target->fmt == FMT_DEPTH || target->fmt == FMT_SHADOW;
1551 
1552             int rtIndex = cacheRenderTarget(!depth, target->width, target->height);
1553 
1554             glBindFramebuffer(GL_FRAMEBUFFER, FBO);
1555             glFramebufferTexture2D    (GL_FRAMEBUFFER, depth ? GL_DEPTH_ATTACHMENT  : GL_COLOR_ATTACHMENT0, texTarget,       target->ID, 0);
1556             glFramebufferRenderbuffer (GL_FRAMEBUFFER, depth ? GL_COLOR_ATTACHMENT0 : GL_DEPTH_ATTACHMENT,  GL_RENDERBUFFER, rtCache[!depth].items[rtIndex].ID);
1557             GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
1558             if (status != GL_FRAMEBUFFER_COMPLETE) {
1559                 LOG("status: 0x%04X\n", (int)status);
1560             }
1561         }
1562     }
1563 
discardTarget(bool color,bool depth)1564     void discardTarget(bool color, bool depth) {
1565     #ifdef _GAPI_GLES
1566         if (Core::support.discardFrame) {
1567             int count = 0;
1568             GLenum discard[2];
1569             if (color) discard[count++] = Core::active.target ? GL_COLOR_ATTACHMENT0 : GL_COLOR_EXT;
1570             if (depth) discard[count++] = Core::active.target ? GL_DEPTH_ATTACHMENT  : GL_DEPTH_EXT;
1571             if (count) {
1572                 #if defined(_OS_ANDROID) || (defined(__SDL2__) && !defined(_GAPI_GLES2))
1573                    /* glInvalidateBuffer() is the GLES3 version of glDiscardFramebufferEXT(), also
1574                       available on Android. Not available in any GLES2 implementation, this is GLES3 stuff.*/
1575                     glInvalidateFramebuffer(GL_FRAMEBUFFER, count, discard);
1576                 #elif !defined(_OS_WEB) || (defined(__SDL2__) && defined(_GAPI_GLES2))
1577                     /* glDiscardFramebufferEXT() is available even in GLES2 MESA implementations,
1578                        but we have to get the extension function pointer address to use it.
1579                        Not available in GLES3, which is SDL2 default GLES version. */
1580                     glDiscardFramebufferEXT(GL_FRAMEBUFFER, count, discard);
1581                 #endif
1582             }
1583         }
1584     #endif
1585     }
1586 
copyTarget(Texture * dst,int xOffset,int yOffset,int x,int y,int width,int height)1587     void copyTarget(Texture *dst, int xOffset, int yOffset, int x, int y, int width, int height) {
1588         Core::active.textures[0] = NULL;
1589         glActiveTexture(GL_TEXTURE0);
1590         glBindTexture(GL_TEXTURE_2D, dst->ID);
1591         glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, x, y, width, height);
1592         glBindTexture(GL_TEXTURE_2D, 0);
1593     }
1594 
setVSync(bool enable)1595     void setVSync(bool enable) {
1596         #ifdef _OS_WIN
1597             if (wglSwapIntervalEXT) wglSwapIntervalEXT(enable ? 1 : 0);
1598         #elif _OS_LINUX
1599             if (glXSwapIntervalSGI) glXSwapIntervalSGI(enable ? 1 : 0);
1600         #elif defined(__SDL2__)
1601             SDL_GL_SetSwapInterval(enable ? 1 : 0);
1602         #elif defined(_OS_RPI) || defined(_OS_CLOVER) || defined(_OS_SWITCH)
1603             eglSwapInterval(display, enable ? 1 : 0);
1604         #endif
1605     }
1606 
waitVBlank()1607     void waitVBlank() {}
1608 
clear(bool color,bool depth)1609     void clear(bool color, bool depth) {
1610         uint32 mask = (color ? GL_COLOR_BUFFER_BIT : 0) | (depth ? GL_DEPTH_BUFFER_BIT : 0);
1611         if (mask) {
1612             if (depth && !depthWrite) {
1613                 glDepthMask(GL_TRUE);
1614                 glClear(mask);
1615                 glDepthMask(GL_FALSE);
1616             } else {
1617                 glClear(mask);
1618             }
1619         }
1620     }
1621 
setClearColor(const vec4 & color)1622     void setClearColor(const vec4 &color) {
1623         glClearColor(color.x, color.y, color.z, color.w);
1624     }
1625 
setViewport(const short4 & v)1626     void setViewport(const short4 &v) {
1627         glViewport(v.x, v.y, v.z, v.w);
1628     }
1629 
setScissor(const short4 & s)1630     void setScissor(const short4 &s) {
1631         glScissor(s.x, s.y, s.z, s.w);
1632     }
1633 
setDepthTest(bool enable)1634     void setDepthTest(bool enable) {
1635         if (enable)
1636             glEnable(GL_DEPTH_TEST);
1637         else
1638             glDisable(GL_DEPTH_TEST);
1639     }
1640 
setDepthWrite(bool enable)1641     void setDepthWrite(bool enable) {
1642         depthWrite = enable;
1643         glDepthMask(enable ? GL_TRUE : GL_FALSE);
1644     }
1645 
setColorWrite(bool r,bool g,bool b,bool a)1646     void setColorWrite(bool r, bool g, bool b, bool a) {
1647         glColorMask(r, g, b, a);
1648     }
1649 
setAlphaTest(bool enable)1650     void setAlphaTest(bool enable) {
1651     #ifdef FFP
1652         if (enable)
1653             glEnable(GL_ALPHA_TEST);
1654         else
1655             glDisable(GL_ALPHA_TEST);
1656     #endif
1657     }
1658 
setCullMode(int rsMask)1659     void setCullMode(int rsMask) {
1660         cullMode = rsMask;
1661         switch (rsMask) {
1662             case RS_CULL_BACK  : glCullFace(GL_BACK);     break;
1663             case RS_CULL_FRONT : glCullFace(GL_FRONT);    break;
1664             default            : glDisable(GL_CULL_FACE); return;
1665         }
1666         glEnable(GL_CULL_FACE);
1667     }
1668 
setBlendMode(int rsMask)1669     void setBlendMode(int rsMask) {
1670         blendMode = rsMask;
1671         switch (rsMask) {
1672             case RS_BLEND_ALPHA   : glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break;
1673             case RS_BLEND_ADD     : glBlendFunc(GL_ONE, GL_ONE);                       break;
1674             case RS_BLEND_MULT    : glBlendFunc(GL_DST_COLOR, GL_ZERO);                break;
1675             case RS_BLEND_PREMULT : glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);       break;
1676             default               : glDisable(GL_BLEND); return;
1677         }
1678         glEnable(GL_BLEND);
1679     }
1680 
setViewProj(const mat4 & mView,const mat4 & mProj)1681     void setViewProj(const mat4 &mView, const mat4 &mProj) {
1682     #ifdef FFP
1683         glMatrixMode(GL_PROJECTION);
1684         glLoadMatrixf((float*)&mProj);
1685     #endif
1686     }
1687 
updateLights(vec4 * lightPos,vec4 * lightColor,int count)1688     void updateLights(vec4 *lightPos, vec4 *lightColor, int count) {
1689     #ifdef FFP
1690         int lightsCount = 0;
1691 
1692         glMatrixMode(GL_MODELVIEW);
1693         glPushMatrix();
1694         glLoadIdentity();
1695 
1696         vec4 amb(vec3(Core::active.material.y), 1.0f);
1697         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (GLfloat*)&amb);
1698 
1699         for (int i = 0; i < count; i++) {
1700             GLenum light = GL_LIGHT0 + i;
1701 
1702             if (lightColor[i].w != 1.0f) {
1703                 glEnable(light);
1704                 lightsCount++;
1705             } else {
1706                 glDisable(light);
1707                 continue;
1708             }
1709 
1710             vec4 pos(lightPos[i].xyz(), 1.0f);
1711             vec4 color(lightColor[i].xyz(), 1.0f);
1712             float att = lightColor[i].w * lightColor[i].w;
1713 
1714             glLightfv(light, GL_POSITION, (GLfloat*)&pos);
1715             glLightfv(light, GL_DIFFUSE,  (GLfloat*)&color);
1716             glLightfv(light, GL_QUADRATIC_ATTENUATION, (GLfloat*)&att);
1717         }
1718 
1719         glPopMatrix();
1720 
1721         if (lightsCount) {
1722             glEnable(GL_COLOR_MATERIAL);
1723             glEnable(GL_LIGHTING);
1724         } else {
1725             glDisable(GL_COLOR_MATERIAL);
1726             glDisable(GL_LIGHTING);
1727         }
1728     #else
1729         if (Core::active.shader) {
1730             Core::active.shader->setParam(uLightColor, lightColor[0], count);
1731             Core::active.shader->setParam(uLightPos,   lightPos[0],   count);
1732         }
1733     #endif
1734     }
1735 
setFog(const vec4 & params)1736     void setFog(const vec4 &params) {
1737         // FFP TODO
1738     }
1739 
DIP(Mesh * mesh,const MeshRange & range)1740     void DIP(Mesh *mesh, const MeshRange &range) {
1741     #ifdef FFP
1742         mat4 m = mView * mModel;
1743         glMatrixMode(GL_MODELVIEW);
1744         glLoadMatrixf((GLfloat*)&m);
1745     #endif
1746         if (Core::active.shader) {
1747             Core::active.shader->validate();
1748         }
1749 
1750         glDrawElements(GL_TRIANGLES, range.iCount, sizeof(Index) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, mesh->iBuffer + range.iStart);
1751     }
1752 
copyPixel(int x,int y)1753     vec4 copyPixel(int x, int y) {
1754         ubyte4 c;
1755         glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &c);
1756         return vec4(float(c.x), float(c.y), float(c.z), float(c.w)) * (1.0f / 255.0f);
1757     }
1758 }
1759 
1760 #endif
1761