ecere/gfx/fontRendering: Improved rendering of some fonts e.g. MS Sans Serif having...
[sdk] / ecere / src / gfx / drivers / OpenGLDisplayDriver.ec
1 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
2
3 // #define DIAGNOSTICS
4 #if defined(_DEBUG) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) && !defined(__ODROID__)
5  #define GL_DEBUGGING
6 #endif
7
8 import "Display"
9
10 import "glab"
11 import "immediate"
12 import "matrixStack"
13 import "defaultShader"
14
15 namespace gfx::drivers;
16
17 #include "gl123es.h"
18
19 // **********   GL PLATFORMS INCLUDES   **********
20 // UNIX
21 #if defined(__unix__) || defined(__APPLE__)
22
23    // EGL
24    #if defined(__ANDROID__) || defined(__ODROID__)
25       import "egl"
26
27       #if defined(__ANDROID__)
28          #include <android/native_activity.h>
29          #include <android/log.h>
30          #define printf(...)  ((void)__android_log_print(ANDROID_LOG_VERBOSE, "ecere-app", __VA_ARGS__))
31       #endif
32
33    // Emscripten
34    #elif defined(__EMSCRIPTEN__)
35       #define property _property
36       #define uint _uint
37
38       #include <emscripten/emscripten.h>
39       #include <emscripten/html5.h>
40
41       #undef property
42       #undef uint
43
44    // GLX
45    #elif !defined(__ANDROID__) && !defined(__ODROID__) && !defined(__EMSCRIPTEN__)
46       #define pointer _pointer
47       #define GL_GLEXT_PROTOTYPES
48
49       #define property _property
50       #define new _new
51       #define class _class
52
53       #define Window    X11Window
54       #define Cursor    X11Cursor
55       #define Font      X11Font
56       #define Display   X11Display
57       #define Time      X11Time
58       #define KeyCode   X11KeyCode
59       #define Picture   X11Picture
60       #define Glyph     X11Glyph
61       #define uint _uint
62
63       #include <X11/Xlib.h>
64       #include <X11/Xutil.h>
65       #include <GL/glx.h>
66       #include <X11/extensions/XShm.h>
67       #include <sys/ipc.h>
68       #include <sys/shm.h>
69       #include <X11/extensions/Xrender.h>
70       #include <X11/extensions/shape.h>
71
72       #undef Window
73       #undef Cursor
74       #undef Font
75       #undef Display
76       #undef Time
77       #undef KeyCode
78       #undef Picture
79       #undef Glyph
80       #undef uint
81       #undef new
82       #undef property
83       #undef class
84       #undef pointer
85
86       #if !defined(__APPLE__)
87       default GLAPI void APIENTRY glLockArraysEXT (GLint first, GLsizei count);
88       default GLAPI void APIENTRY glUnlockArraysEXT (void);
89       #endif
90
91       import "XInterface"
92
93       // We were using PBUFFER for alpha compositing on Linux before, but it does not seem to work, nor be required anymore.
94       // #define USEPBUFFER
95
96    #endif
97
98 // Apple
99 #elif defined(__APPLE__)
100    #include <OpenGl/gl.h>
101
102 // WGL
103 #elif defined(__WIN32__)
104    //#define WIN32_LEAN_AND_MEAN
105    #undef _WIN32_WINNT
106    #define _WIN32_WINNT 0x0502
107    #define String Sting_
108    #include <windows.h>
109    #undef String
110
111    #include "wglDefs.h"
112 #endif
113
114 #if defined(__WIN32__)
115 #elif !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__ODROID__) && !defined(__EMSCRIPTEN__)
116 default:
117 private:
118 #endif
119
120 /*                                                            OpenGL Versions Features Quick Reference
121
122                                  | OpenGL 1.1  | OpenGL 1.5  | GL ES 1.1  |  OpenGL 2  | GL 3 (Compat) | GL 3 (Core) |  GL ES 2    |  WebGL 1   |  GL ES 3   |   WebGL 2
123    =======================================================================================================================================================================
124    glBegin()                     |      X      |      X      |     -      |     X      |       X       |      -      |      -      |     -      |     -      |     -
125    glLoadMatrix()                |      X      |      X      |     -      |     X      |       X       |      -      |      -      |     -      |     -      |     -
126    glLineWidth()                 |      X      |      X      |     -      |     X      |       X       |      -      |      -      |     -      |     -      |     -
127    glPointSize()                 |      X      |      X      |     -      |     X      |       X       |      -      |      -      |     -      |     -      |     -
128    glLineStipple()               |      X      |      X      |     -      |     X      |       X       |      -      |      -      |     -      |     -      |     -
129    glPolygonStipple()            |      X      |      X      |     -      |     X      |       X       |      -      |      -      |     -      |     -      |     -
130    glColorMaterial()             |      X      |      X      |     -      |     X      |       X       |      -      |      -      |     -      |     -      |     -
131    GL_QUADS                      |      X      |      X      |     -      |     X      |       X       |      -      |      -      |     -      |     -      |     -
132    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------
133    GL_INT / GL_DOUBLE            |      X      |      X      |     -      |     X      |       X       |      X      |      -      |     -      |     -      |     -
134    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------
135    GL_SELECT                     |      X      |      X      |     -      |   (Slow)   |     (Slow)    |    (Slow)   |      -      |     -      |     -      |     -
136    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------
137    Non ² Textures                |      -      |      -      |     -      |     X      |       X       |      X      |      -      |     -      |     -      |     -
138    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------
139    glVertexPointer()       (PTR) |      X      |      X      |     X      |     X      |       X       |      -      |      -      |     -      |     -      |     -
140    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------
141    glVertexPointer()       (VBO) |      -      |      X      |     X      |     X      |       X       |      -      |      -      |     -      |     -      |     -
142    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------
143    glBufferData()                |      -      |      X      |     X      |     X      |       X       |      X      |      X      |     X      |     X      |     X
144    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------
145    glMapBuffer()                 |      -      |      X      |   OES x    |     X      |       X       |      X      |    OES x    |     -      |    OES x   |     -
146    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------
147    glBindFramebuffer()           |      -      |      -      |   OES x    |     -      |       X       |      X      |      X      |     X      |     X      |     X
148    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------
149    glVertexAttribPointer() (PTR) |      -      |      -      |     -      |     X      |       X       |      X      |      X      |     -      |     X      |     -
150    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------
151    glVertexAttribPointer() (VBO) |      -      |      -      |     -      |     X      |       X       |      X      |      X      |     X      |     X      |     X
152    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------
153    GLSL Version                  |      -      |      -      |     -      |    1.10    |     1.30      |    1.30     |     1.00    |    1.00    |    3.00    |    3.00
154    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------
155    bool legacy          :1; //   |      X      |      X      |     -      |     X      |       X       |      -      |      -      |     -      |     -      |     -
156    bool shaders         :1; //   |      -      |      -      |     -      |     X      |       X       |      X      |      X      |     X      |     X      |     X
157    bool nonPow2Textures :1; //   |      -      |      -      |     -      |     X      |       X       |      X      |      -      |     -      |     -      |     -
158    bool vertexBuffer    :1; //   |      -      |      X      |     X      |     X      |       X       |      X      |      X      |     X      |     X      |     X
159    bool frameBuffer     :1; //   |      -      |      -      |     ~      |     -      |       X       |      X      |      X      |     X      |     X      |     X
160 // bool mapBuffer       :1; //   |      -      |      X      |     ~      |     X      |       X       |      X      |      ~      |     -      |     ~      |     -
161 */
162
163 default:
164 // Capabilities Global set to capabilities of Display being rendered to
165 GLCapabilities glCaps;
166 // Requiring Graphics Reload:
167 bool glCaps_nonPow2Textures, glCaps_vertexBuffer, glCaps_quads, glCaps_intAndDouble, glCaps_legacyFormats, glCaps_compatible, glCaps_vertexPointer;
168 // Might toggle without Reload:
169 bool glCaps_core, glCaps_shaders, glCaps_fixedFunction, glCaps_immediate, glCaps_legacy, glCaps_pointSize, glCaps_frameBuffer, glCaps_vao, glCaps_select;
170 // bool mapBuffer;
171 private:
172
173
174 // **********   Errors and Debugging   **********
175 /*
176 void CheckGLErrors()
177 {
178    int e, nCount = 0;
179    while((e = glGetError()) && nCount++ < 10)
180       printf("GL error %d!\n", e);
181 }
182 */
183 #ifdef GL_DEBUGGING
184 #ifndef APIENTRY
185    #define APIENTRY
186 #endif
187 static void APIENTRY openglCallbackFunction(GLenum source,
188                                            GLenum type,
189                                            GLuint id,
190                                            GLenum severity,
191                                            GLsizei length,
192                                            const GLchar* message,
193                                            const void* userParam)
194 {
195    if(severity == GL_DEBUG_SEVERITY_NOTIFICATION)
196       return;
197    PrintLn("---------------------opengl-callback-start------------");
198    PrintLn("message: ", message);
199    PrintLn("type: ");
200    switch (type)
201    {
202       case GL_DEBUG_TYPE_ERROR: PrintLn("ERROR"); break;
203       case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: PrintLn("DEPRECATED_BEHAVIOR"); break;
204       case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: PrintLn("UNDEFINED_BEHAVIOR"); break;
205       case GL_DEBUG_TYPE_PORTABILITY: PrintLn("PORTABILITY"); break;
206       case GL_DEBUG_TYPE_PERFORMANCE: PrintLn("PERFORMANCE"); break;
207       case GL_DEBUG_TYPE_OTHER: PrintLn("OTHER"); break;
208    }
209
210    PrintLn("id: ", id);
211    Print("severity: ");
212    switch (severity)
213    {
214       case GL_DEBUG_SEVERITY_LOW: PrintLn("LOW"); break;
215       case GL_DEBUG_SEVERITY_MEDIUM: PrintLn("MEDIUM"); break;
216       case GL_DEBUG_SEVERITY_HIGH: PrintLn("HIGH"); break;
217       default: PrintLn("(other)");
218    }
219    PrintLn("---------------------opengl-callback-end--------------");
220 }
221
222 static void setupDebugging()
223 {
224    if(glDebugMessageCallback)
225    {
226       GLuint unusedIds = 0;
227
228       glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
229
230       glDebugMessageCallback(openglCallbackFunction, null);
231       glDebugMessageControl(GL_DONT_CARE,
232           GL_DONT_CARE,
233           GL_DONT_CARE,
234           0,
235           &unusedIds,
236           GL_TRUE);
237    }
238 }
239 #endif
240
241
242 static GLuint stippleTexture;
243 static bool stippleEnabled;
244
245 public void glsupLineStipple( int i, uint16 j )
246 {
247    uint texture[1*16];
248    int x;
249    for(x = 0; x < 16; x++)
250    {
251       bool v = (j & (1 << x)) != 0;
252       texture[x] = v ? 0xFFFFFFFF : 0;
253    }
254    if(!stippleTexture)
255       glGenTextures(1, &stippleTexture);
256    glBindTexture(GL_TEXTURE_2D, stippleTexture);
257    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture);
258
259    // TOOD: Special shading code for stippling?
260    GLSetupTexturing(true);
261    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
262    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
263    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
264    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
265    GLMatrixMode(GL_TEXTURE);
266    GLLoadIdentity();
267    //glTranslated(1.0/backAttrib->texW/2.0f, 1.0/backAttrib->texH/2.0f, 0.0f);
268    GLScaled(i/16.0, 1, 1.0f);
269    GLTranslated(0.5, 0.5, 0);
270    GLMatrixMode(MatrixMode::projection);
271 }
272
273    // Exported to build _GLES version...
274    public void glsupLightModeli( unsigned int pname, int param )
275    {
276 #if ENABLE_GL_FFP
277       if(pname == GL_LIGHT_MODEL_TWO_SIDE)
278          glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, param);
279 #endif
280    }
281
282 #ifdef _GLES
283    void glFogi( unsigned int pname, int param ) { }
284    void glPolygonMode( unsigned int i, unsigned int j ) { }
285    void glBlendFuncSeparate(int a, int b, int c, int d)
286    {
287       glBlendFunc(a, b);
288    }
289
290 #endif
291
292 #if defined(_GLES) || defined(_GLES2)
293 void glClearDepth( double depth ) { glClearDepthf((float)depth); }
294 #endif
295
296 #if !ENABLE_GL_SELECT
297
298 // *** Picking won't be supported for now ***
299 void glPushName( unsigned int i ) { }
300 void glLoadName( unsigned int i ) { }
301 void glPopName() { }
302
303 #endif
304
305 #if !defined(ECERE_NO3D) && !defined(ECERE_VANILLA)
306 static inline uint getPrimitiveType(RenderPrimitiveType type)
307 {
308    static int primitiveTypes[RenderPrimitiveType] =
309    {
310       GL_POINTS, GL_LINES, GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN,
311       GLIMTKMode::quads,
312       GLIMTKMode::quadStrip,
313       GL_LINE_STRIP
314    };
315    // NOTE: This will only work for single quads
316    return (type == quads && !glCaps_quads) ? GL_TRIANGLE_FAN : primitiveTypes[type];
317 }
318
319 public void GLSetupTexturing(bool enable)
320 {
321 #if ENABLE_GL_SHADERS
322    if(glCaps_shaders)
323       defaultShader.texturing(enable);
324 #endif
325
326 #if ENABLE_GL_FFP
327    if(!glCaps_shaders)
328       (enable ? glEnable : glDisable)(GL_TEXTURE_2D);
329 #endif
330 }
331
332 public void GLSetupFog(bool enable)
333 {
334 #if ENABLE_GL_SHADERS
335    if(glCaps_shaders)
336       defaultShader.fog(enable);
337 #endif
338
339 #if ENABLE_GL_FFP
340    if(!glCaps_shaders)
341       (enable ? glEnable : glDisable)(GL_FOG);
342 #endif
343 }
344
345 bool lightingEnabled;
346
347 public void GLSetupLighting(bool enable)
348 {
349    lightingEnabled = enable;
350 #if ENABLE_GL_SHADERS
351    if(glCaps_shaders)
352       defaultShader.lighting(enable);
353 #endif
354
355 #if ENABLE_GL_FFP
356    if(!glCaps_shaders)
357       (enable ? glEnable : glDisable)(GL_LIGHTING);
358 #endif
359 }
360 #endif
361
362 /*static */GLuint lastBlitTex;
363
364 Shader activeShader;
365
366 static int displayWidth, displayHeight;
367
368 #define GL_CLAMP_TO_EDGE 0x812F
369
370 static bool useSingleGLContext = false;
371 class OGLDisplay : struct
372 {
373    GLCapabilities capabilities, originalCapabilities;
374    bool compat;
375    int version;
376
377    ColorAlpha * flippingBuffer;
378    int flipBufH, flipBufW;
379    bool depthWrite;
380    int x, y;
381    uint vao;
382    int maxTMU;
383
384 #if defined(__WIN32__)
385    HDC hdc;
386    HGLRC glrc;
387
388    HBITMAP memBitmap;
389    HDC memDC;
390    byte * picture;
391    uint stride;
392    void * pBuffer;
393    /*
394    int imageBuffers[2];
395    byte * pboMemory1, * pboMemory2;
396    */
397 #elif !defined(__ANDROID__) && !defined(__ODROID__) && !defined(__EMSCRIPTEN__)
398    GLXContext glContext;
399
400    Pixmap pixmap;
401    XShmSegmentInfo shminfo;
402    XImage * image;
403    XShmSegmentInfo shminfoShape;
404    XImage * shapeImage;
405    byte * picture;
406    uint stride;
407    GLXPbuffer pBuffer;
408    X11Picture windowPicture;
409    X11Picture pixmapPicture;
410    Pixmap shapePixmap;
411    X11Picture shapePicture;
412 #endif
413 };
414
415 class OGLSystem : struct
416 {
417    int maxTextureSize;
418    bool loadingFont;
419 #if defined(__WIN32__)
420    PIXELFORMATDESCRIPTOR pfd;
421    int format;
422    HDC hdc;
423    HGLRC glrc;
424    HWND hwnd;
425 #elif defined(__EMSCRIPTEN__)
426    EMSCRIPTEN_WEBGL_CONTEXT_HANDLE glc;
427 #elif !defined(__ANDROID__) && !defined(__ODROID__)
428    XVisualInfo * visualInfo;
429    GLXContext glContext;
430    GLXDrawable glxDrawable;
431 #endif
432    GLCapabilities capabilities;
433    bool compat;
434    int version;
435
436    // Buffer Data
437    uint16 *shortBDBuffer;
438    uint shortBDSize;
439 };
440
441 class OGLSurface : struct
442 {
443    Font font;
444    bool opaqueText;
445    int xOffset;
446    bool writingText;
447    bool writingOutline;
448
449    float foreground[4], background[4], bitmapMult[4];
450 } OGLSurface;
451
452 class OGLMesh : struct
453 {
454    GLAB vertices;
455    GLAB normals;
456    GLAB tangents;
457    GLAB lightVectors;
458    GLAB texCoords;
459    GLAB texCoords2;
460    GLAB colors;
461 };
462
463 class OGLIndices : struct
464 {
465    uint16 * indices;
466    GLEAB buffer;
467    uint nIndices;
468 };
469
470 int current;
471 void * previous;
472
473 #if defined(__WIN32__)
474 static HGLRC winCreateContext(HDC hdc, int * contextVersion, bool * isCompatible, bool compatible)
475 {
476    HGLRC result = 0;
477    if(wglCreateContextAttribsARB)
478    {
479       int versions[12][2] =
480       {
481          { 4, 5 }, { 4, 4 }, { 4, 3 }, { 4, 2 }, { 4, 1 }, { 4, 0 },
482                              { 3, 3 }, { 3, 2 }, { 3, 1 }, { 3, 0 },
483                                                  { 2, 1 }, { 2, 0 }
484       };
485
486       bool tryingCompat = compatible;
487       int v = 0;
488       while(!result)
489       {
490          for(v = 0; !result && v < sizeof(versions) / sizeof(versions[0]); v++)
491          {
492             int v0 = versions[v][0], v1 = versions[v][1];
493             if(!tryingCompat || v0 >= 3)
494             {
495                bool coreNotion = v0 > 3 || (v0 == 3 && v1 >= 3);
496                int attribs[] =
497                {
498                   WGL_CONTEXT_MAJOR_VERSION_ARB, v0, WGL_CONTEXT_MINOR_VERSION_ARB, v1,
499          #ifdef _DEBUG
500                   WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB,
501          #endif
502                   coreNotion ? WGL_CONTEXT_PROFILE_MASK_ARB : 0, coreNotion ? (tryingCompat ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : WGL_CONTEXT_CORE_PROFILE_BIT_ARB) : 0,
503                   0,0
504                };
505                result = wglCreateContextAttribsARB(hdc, null, attribs);
506                if(result)
507                {
508                   if(contextVersion) *contextVersion = v0;
509                   if(isCompatible)   *isCompatible = tryingCompat || !coreNotion;
510                }
511             }
512          }
513          if(tryingCompat)
514             tryingCompat = false;
515          else
516             break;
517       }
518    }
519    if(!result)
520    {
521       if(contextVersion) *contextVersion = 1;
522       if(isCompatible)   *isCompatible = true;
523       result = wglCreateContext(hdc);
524    }
525    return result;
526 }
527 #endif
528
529 class OpenGLDisplayDriver : DisplayDriver
530 {
531    class_property(name) = "OpenGL";
532
533    bool LockSystem(DisplaySystem displaySystem)
534    {
535 #if defined(__EMSCRIPTEN__)
536       OGLSystem oglSystem = displaySystem.driverData;
537       emscripten_webgl_make_context_current(oglSystem.glc);
538 #elif !defined(__ANDROID__) && !defined(__ODROID__)
539       OGLSystem oglSystem = displaySystem.driverData;
540       if(useSingleGLContext) return true;
541    #if defined(__WIN32__)
542       wglMakeCurrent(oglSystem.hdc, oglSystem.glrc);
543    #elif defined(__unix__) || defined(__APPLE__)
544       //if(previous) return true;
545       // printf("Making SYSTEM current\n");
546       glXMakeCurrent(xGlobalDisplay, (GLXDrawable)oglSystem.glxDrawable, oglSystem.glContext);
547       //previous = oglSystem.glContext;
548    #endif
549 #endif
550       GLABBindBuffer(GL_ARRAY_BUFFER, 0);
551       GLABBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
552       return true;
553    }
554
555    void UnlockSystem(DisplaySystem displaySystem)
556    {
557       if(useSingleGLContext) return;
558    #if defined(__WIN32__)
559       wglMakeCurrent(null, null);
560    #elif defined(__unix__) || defined(__APPLE__)
561       // printf("Making NULL current\n");
562       #if defined(__ANDROID__) || defined(__ODROID__) || defined(__EMSCRIPTEN__)
563       #else
564       glXMakeCurrent(xGlobalDisplay, None, null);
565       #endif
566       // previous = null;
567    #endif
568    }
569
570    bool Lock(Display display)
571    {
572 #if !defined(__ANDROID__) && !defined(__ODROID__) && !defined(__EMSCRIPTEN__)
573       OGLDisplay oglDisplay = display.driverData;
574       if(useSingleGLContext) return true;
575    #if defined(__WIN32__)
576       wglMakeCurrent(oglDisplay.hdc, oglDisplay.glrc);
577    #elif defined(__unix__) || defined(__APPLE__)
578       // if(previous) glXMakeCurrent(xGlobalDisplay, None, null);
579       // printf("   Making DISPLAY current\n");
580       glXMakeCurrent(xGlobalDisplay, (GLXDrawable)display.window, oglDisplay.glContext);
581    #endif
582 #endif
583       GLABBindBuffer(GL_ARRAY_BUFFER, 0);
584       GLABBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
585       return true;
586    }
587
588    void Unlock(Display display)
589    {
590       if(useSingleGLContext) return;
591       //printf("   Making NULL current\n");
592       //glXMakeCurrent(xGlobalDisplay, None, null);
593       // if(previous)
594          LockSystem(display.displaySystem);
595    }
596
597    void DestroyDisplay(Display display)
598    {
599       OGLDisplay oglDisplay = display.driverData;
600
601       if(oglDisplay)
602       {
603    #if defined(__WIN32__)
604          wglMakeCurrent( null, null );
605
606          if(oglDisplay.glrc)
607             wglDeleteContext(oglDisplay.glrc);
608
609          if(oglDisplay.hdc && oglDisplay.pBuffer)
610             wglReleasePbufferDCARB(oglDisplay.pBuffer, oglDisplay.hdc);
611
612          if(oglDisplay.pBuffer)
613             wglDestroyPbufferARB(oglDisplay.pBuffer);
614
615          if(oglDisplay.hdc)
616             ReleaseDC(display.window, oglDisplay.hdc);
617
618          if(oglDisplay.memDC) DeleteDC(oglDisplay.memDC);
619          if(oglDisplay.memBitmap) DeleteObject(oglDisplay.memBitmap);
620
621    #elif defined(__unix__) || defined(__APPLE__)
622       #if defined(__ANDROID__) || defined(__ODROID__) || defined(__EMSCRIPTEN__)
623       #else
624          if(oglDisplay.shapePixmap)
625             XFreePixmap(xGlobalDisplay, oglDisplay.shapePixmap);
626          if(oglDisplay.pixmap)
627             XFreePixmap(xGlobalDisplay, oglDisplay.pixmap);
628          if(oglDisplay.image)
629          {
630             if(oglDisplay.shminfoShape.shmid != -1)
631             {
632                XShmDetach(xGlobalDisplay, &oglDisplay.shminfo);
633                if(oglDisplay.shminfo.shmaddr != (void *)-1)
634                   shmdt(oglDisplay.shminfo.shmaddr);
635                shmctl(oglDisplay.shminfo.shmid, IPC_RMID, 0);
636             }
637          }
638          if(oglDisplay.shapeImage)
639          {
640             if(oglDisplay.shminfoShape.shmid != -1)
641             {
642                XShmDetach(xGlobalDisplay, &oglDisplay.shminfoShape);
643                if(oglDisplay.shminfoShape.shmaddr != (void *)-1)
644                   shmdt(oglDisplay.shminfoShape.shmaddr);
645                shmctl(oglDisplay.shminfoShape.shmid, IPC_RMID, 0);
646             }
647             XDestroyImage(oglDisplay.shapeImage);
648             oglDisplay.shapeImage = None;
649          }
650
651          glXMakeCurrent(xGlobalDisplay, None, null);
652
653          if(oglDisplay.glContext)
654             glXDestroyContext(xGlobalDisplay, oglDisplay.glContext);
655       #endif
656    #endif
657          delete oglDisplay.flippingBuffer;
658          delete oglDisplay;
659          display.driverData = null;
660       }
661    }
662
663 #if !defined(__EMSCRIPTEN__)
664    void ::CheckCapabilities(OGLSystem oglSystem, OGLDisplay oglDisplay, bool canCheckExtensions)
665    {
666       GLCapabilities capabilities;
667 #if !defined(_GLES2)
668       const char * extensions = (canCheckExtensions && (!oglDisplay || oglDisplay.compat)) ? (const char *)glGetString(GL_EXTENSIONS) : null;
669 #endif
670 #ifdef DIAGNOSTICS
671       printf("extensions: %s\n", extensions);
672 #endif
673
674       glGetIntegerv(GL_MAX_TEXTURE_SIZE, &oglSystem.maxTextureSize);
675
676 #if defined(_GLES)
677       capabilities = { fixedFunction = true, vertexPointer = true, vertexBuffer = true, pointSize = true, legacyFormats = true, frameBuffer = extensions && strstr(extensions, "GL_OES_framebuffer_object") };
678 #elif defined(_GLES2)
679       capabilities = { glCaps_shaders = true, vertexBuffer = true, pointSize = true, frameBuffer = true, legacyFormats = true };
680 #else
681       capabilities =
682       {
683          nonPow2Textures = glGetStringi || (extensions && (strstr(extensions, "GL_ARB_texture_non_power_of_two")));
684          intAndDouble = true;
685 #ifdef GL_DEBUGGING
686          debug = true;
687 #endif
688          compatible = oglDisplay.compat;
689          pointSize = oglDisplay.compat;
690 #if ENABLE_GL_LEGACY
691          legacy         = glBegin != null && oglDisplay.compat;
692          legacyFormats  = glBegin != null && oglDisplay.compat;
693          immediate      = glBegin != null && oglDisplay.compat;
694          fixedFunction  = glBegin != null && oglDisplay.compat;
695          quads          = glBegin != null && oglDisplay.compat;
696          select         = glSelectBuffer != null && oglDisplay.compat;
697 #endif
698 #if ENABLE_GL_SHADERS
699          shaders = glCreateProgram != null;
700 #endif
701 #if ENABLE_GL_POINTER
702          vertexPointer = oglDisplay.compat;
703 #endif
704 #if ENABLE_GL_VAO
705          vao = glBindVertexArray != null && !oglDisplay.compat;
706 #endif
707 #if ENABLE_GL_FBO
708          frameBuffer = glBindFramebuffer != null;
709 #endif
710          vertexBuffer = glBindBuffer != null;
711          // mapBuffer = glMapBuffer != null;
712       };
713 #endif
714
715 #ifdef DIAGNOSTICS
716       PrintLn("max texture size: ", oglSystem.maxTextureSize);
717 #endif
718       if(oglDisplay) oglDisplay.capabilities = capabilities;
719       if(oglSystem)  oglSystem.capabilities = capabilities;
720    }
721 #endif
722
723    bool CreateDisplaySystem(DisplaySystem displaySystem)
724    {
725       bool result = false;
726       OGLSystem oglSystem = displaySystem.driverData = OGLSystem { };
727
728 #ifdef _GLES
729       oglSystem.capabilities = { fixedFunction = true, vertexBuffer = true, frameBuffer = true, pointSize = true };
730 #elif defined(_GLES2)
731       oglSystem.capabilities = { shaders = true, vertexBuffer = true, frameBuffer = true, pointSize = true };
732 #else
733       oglSystem.capabilities = { compatible = glCaps_compatible, shaders = true, fixedFunction = true, immediate = true, legacy = true, pointSize = true, quads = true, intAndDouble = true, vertexBuffer = true, frameBuffer = true, vao = true, nonPow2Textures = true };
734 #endif
735
736 #ifdef DIAGNOSTICS
737       PrintLn("OpenGL driver's CreateDisplaySystem()");
738 #endif
739
740    #ifdef __WIN32__
741       oglSystem.hwnd = CreateWindow("static", null, 0,0,0,0,0,null,null,null,null);
742
743       oglSystem.hdc = GetDC(oglSystem.hwnd);
744       if(oglSystem.hdc)
745       {
746
747          oglSystem.pfd.nSize = (short)sizeof(oglSystem.pfd);
748          oglSystem.pfd.nVersion = 1;
749          oglSystem.pfd.dwFlags = PFD_DRAW_TO_WINDOW /*PFD_DRAW_TO_BITMAP*/ | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
750          oglSystem.pfd.iPixelType = PFD_TYPE_RGBA;
751          oglSystem.pfd.cColorBits = 24;
752          oglSystem.pfd.cAlphaBits = 8;
753          oglSystem.pfd.cDepthBits = 24;
754          oglSystem.pfd.iLayerType = PFD_MAIN_PLANE;
755
756          oglSystem.format = ChoosePixelFormat(oglSystem.hdc, &oglSystem.pfd);
757          DescribePixelFormat(oglSystem.hdc, oglSystem.format, sizeof(oglSystem.pfd), &oglSystem.pfd);
758
759          if(oglSystem.pfd.cColorBits > 8)
760          {
761             SetPixelFormat(oglSystem.hdc, oglSystem.format, &oglSystem.pfd);
762             oglSystem.glrc = wglCreateContext(oglSystem.hdc);
763             if(oglSystem.glrc)
764             {
765                wglMakeCurrent(oglSystem.hdc, oglSystem.glrc);
766
767                wglChoosePixelFormatARB = (void *) wglGetProcAddress("wglChoosePixelFormatARB");
768                wglGetExtensionsStringARB = (void *)wglGetProcAddress("wglGetExtensionsStringARB");
769                wglCreatePbufferARB = (void *)wglGetProcAddress("wglCreatePbufferARB");
770                wglGetPbufferDCARB = (void *)wglGetProcAddress("wglGetPbufferDCARB");
771                wglQueryPbufferARB = (void *)wglGetProcAddress("wglQueryPbufferARB");
772                wglDestroyPbufferARB = (void *)wglGetProcAddress("wglDestroyPbufferARB");
773                wglReleasePbufferDCARB = (void *)wglGetProcAddress("wglReleasePbufferDCARB");
774                wglBindTexImageARB = (void *)wglGetProcAddress("wglBindTexImageARB");
775                wglReleaseTexImageARB = (void *)wglGetProcAddress("wglReleaseTexImageARB");
776                wglSwapIntervalEXT = (void *)wglGetProcAddress("wglSwapIntervalEXT");
777                wglCreateContextAttribsARB = (void *)wglGetProcAddress("wglCreateContextAttribsARB");
778
779                glLockArraysEXT = (void *) wglGetProcAddress("glLockArraysEXT" );
780                glUnlockArraysEXT = (void *) wglGetProcAddress("glUnlockArraysEXT");
781
782                // eSystem_LoggingMode(LOG_MSGBOX, null);
783
784                if(wglChoosePixelFormatARB)
785                {
786                   int pixelFormat;
787                   int valid;
788                   int numFormats;
789                   float fAttributes[] = {0,0};
790                   int iAttributes[] =
791                   {
792                      WGL_DRAW_TO_WINDOW_ARB,GL_TRUE,
793                      WGL_SUPPORT_OPENGL_ARB,GL_TRUE,
794                      WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB,
795                      WGL_COLOR_BITS_ARB,24,
796                      WGL_ALPHA_BITS_ARB,8,
797                      WGL_DEPTH_BITS_ARB,16,
798                      WGL_STENCIL_BITS_ARB,0,
799                      WGL_DOUBLE_BUFFER_ARB,GL_TRUE,
800                      WGL_SAMPLE_BUFFERS_ARB,GL_TRUE,
801                      WGL_SAMPLES_ARB, 4,                  // Check For 4x Multisampling
802                      0,0
803                   };
804
805                   //Log("Found wglChoosePixelFormatARB\n");
806
807                   valid = wglChoosePixelFormatARB(oglSystem.hdc,iAttributes,fAttributes,1,&pixelFormat,&numFormats);
808                   if(!valid || !numFormats)
809                   {
810                      //Log("Can't find 4x multi sampling\n");
811                      iAttributes[19] = 2;
812                      valid = wglChoosePixelFormatARB(oglSystem.hdc,iAttributes,fAttributes,1,&pixelFormat,&numFormats);
813                      if(!valid || !numFormats)
814                      {
815                         // Log("Can't find 2x multi sampling\n");
816                         iAttributes[16] = 0;
817                         iAttributes[17] = 0;
818                         valid = wglChoosePixelFormatARB(oglSystem.hdc,iAttributes,fAttributes,1,&pixelFormat,&numFormats);
819                      }
820                   }
821                   if(valid && numFormats)
822                   {
823                      oglSystem.format = pixelFormat;
824                      wglMakeCurrent(null, null);
825                      wglDeleteContext(oglSystem.glrc);
826
827                      // *** DescribePixelFormat does not support WGL pixel formats! ***
828                      //DescribePixelFormat(oglSystem.hdc, oglSystem.format, sizeof(oglSystem.pfd), &oglSystem.pfd);
829                      SetPixelFormat(oglSystem.hdc, oglSystem.format, &oglSystem.pfd);
830                      //Log("Successfully set pixel format\n");
831
832 #ifdef DIAGNOSTICS
833                      PrintLn("winCreateContext()");
834 #endif
835                      oglSystem.glrc = winCreateContext(oglSystem.hdc, &oglSystem.version, &oglSystem.compat, displaySystem.glCapabilities.compatible);
836 #ifdef DIAGNOSTICS
837                      PrintLn("wglMakeCurrent()");
838 #endif
839                      if(oglSystem.glrc)
840                         wglMakeCurrent(oglSystem.hdc, oglSystem.glrc);
841                   }
842                }
843                /*else
844                   eSystem_Logf("Can't find wglChoosePixelFormatARB\n");*/
845
846                result = true;
847
848                wglMakeCurrent(null, null);
849
850                //eSystem_DumpErrors(true);
851             }
852          }
853       }
854    #elif defined(__unix__) || defined(__APPLE__)
855       #if defined(__ANDROID__) || defined(__ODROID__)
856          #if defined(__ANDROID__)
857          egl_init_display(guiApp.desktop.windowHandle);
858          #elif defined(__ODROID__)
859          egl_init_display((uint)displaySystem.window);
860          #endif
861          CheckCapabilities(oglSystem, null, true);
862
863          // TODO: Clean this up? Needed here?
864          GLEnableClientState(VERTICES);
865          /*
866          // Initialize GL state.
867          glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
868          glEnable(GL_CULL_FACE);
869          glShadeModel(GL_SMOOTH);
870          glDisable(GL_DEPTH_TEST);
871          */
872          glDisable(GL_CULL_FACE);
873          glDisable(GL_DEPTH_TEST);
874
875          glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
876          glEnable(GL_BLEND);
877
878          matrixStack[0][0].Identity();
879          matrixStack[1][0].Identity();
880          matrixStack[2][0].Identity();
881
882          GLMatrixMode(GL_MODELVIEW);
883          GLScaled(1.0, 1.0, -1.0);
884          GLMatrixMode(GL_PROJECTION);
885          glShadeModel(GL_FLAT);
886
887 #if !defined(_GLES)
888          if(!glCaps_shaders)
889             ;//GLLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
890 #endif
891          glFogi(GL_FOG_MODE, GL_EXP);
892          glFogf(GL_FOG_DENSITY, 0);
893          glEnable(GL_NORMALIZE);
894          glDepthFunc(GL_LESS);
895          glClearDepth(1.0);
896          glDisable(GL_MULTISAMPLE);
897
898          glViewport(0,0,eglWidth,eglHeight);
899          GLLoadIdentity();
900          GLOrtho(0,eglWidth,eglHeight,0,0.0,1.0);
901
902          glabCurArrayBuffer = 0;
903          glabCurElementBuffer = 0;
904
905          result = true;
906       #elif defined(__EMSCRIPTEN__)
907          {
908             EmscriptenWebGLContextAttributes attribs = { 0 };
909             attribs.depth = 1;
910             attribs.antialias = 1;
911
912             /*
913               EM_BOOL alpha;
914               EM_BOOL depth;
915               EM_BOOL stencil;
916               EM_BOOL antialias;
917               EM_BOOL premultipliedAlpha;
918               EM_BOOL preserveDrawingBuffer;
919               EM_BOOL preferLowPowerToHighPerformance;
920               EM_BOOL failIfMajorPerformanceCaveat;
921               int majorVersion;
922               int minorVersion;
923               EM_BOOL enableExtensionsByDefault;
924               */
925
926             emscripten_webgl_init_context_attributes(&attribs);
927             oglSystem.maxTextureSize = 16384;
928             oglSystem.glc = emscripten_webgl_create_context("canvas", &attribs);
929             if(emscripten_webgl_make_context_current(oglSystem.glc) == EMSCRIPTEN_RESULT_SUCCESS)
930                result = true;
931
932             /*glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
933             glEnable(GL_BLEND);*/
934          }
935       #else
936       {
937          X11Window root = RootWindow( xGlobalDisplay, DefaultScreen( xGlobalDisplay ) );
938          XSetWindowAttributes attr;
939          unsigned long mask;
940
941          int attrList[] =
942          {
943       #ifndef ECERE_MINIGLX
944             GLX_USE_GL, GLX_DEPTH_SIZE, 1,
945       #endif
946             GLX_RGBA,
947             GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1,
948             GLX_DOUBLEBUFFER,
949             None
950          };
951          oglSystem.visualInfo = glXChooseVisual( xGlobalDisplay,  DefaultScreen( xGlobalDisplay ), attrList );
952          attr.background_pixel = 0;
953          attr.border_pixel = 0;
954          attr.colormap = XCreateColormap( xGlobalDisplay, root, oglSystem.visualInfo->visual, AllocNone);
955          attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
956          mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
957
958          oglSystem.glxDrawable = XCreateWindow( xGlobalDisplay, root, 0, 0, 1, 1, 0, oglSystem.visualInfo->depth, InputOutput,
959             oglSystem.visualInfo->visual, mask, &attr );
960       }
961       if(oglSystem.visualInfo)
962       {
963          oglSystem.glContext = glXCreateContext(xGlobalDisplay, oglSystem.visualInfo, null, True);
964          if(oglSystem.glContext)
965          {
966             glXMakeCurrent(xGlobalDisplay, oglSystem.glxDrawable, oglSystem.glContext);
967             glXMakeCurrent(xGlobalDisplay, None, null);
968             result = true;
969          }
970       }
971       #endif
972    #endif
973
974       displaySystem.flags.alpha = true;
975       displaySystem.flags.flipping = true;
976       displaySystem.pixelFormat = pixelFormat888;
977       return result;
978    }
979
980    void DestroyDisplaySystem(DisplaySystem displaySystem)
981    {
982       OGLSystem oglSystem = displaySystem.driverData;
983       if(stippleTexture)
984       {
985          glDeleteTextures(1, &stippleTexture);
986          stippleTexture = 0;
987       }
988
989 #if ENABLE_GL_SHADERS
990       defaultShader.free();
991       activeShader = null;
992 #endif
993
994       delete oglSystem.shortBDBuffer;
995       glimtkTerminate();
996
997    #if defined(__WIN32__)
998       wglMakeCurrent( null, null );
999
1000       if(oglSystem.glrc)
1001          wglDeleteContext(oglSystem.glrc);
1002
1003       if(oglSystem.hdc)
1004          ReleaseDC(oglSystem.hwnd, oglSystem.hdc);
1005       DestroyWindow(oglSystem.hwnd);
1006
1007    #elif defined(__unix__) || defined(__APPLE__)
1008       #if defined(__ANDROID__) || defined(__ODROID__)
1009          egl_term_display();
1010       #elif defined(__EMSCRIPTEN__)
1011          emscripten_webgl_destroy_context(oglSystem.glc);
1012       #else
1013       if(oglSystem.visualInfo)
1014       {
1015    #ifdef   ECERE_MINIGLX
1016          __miniglx_XFree(oglSystem.visualInfo);
1017    #else
1018          XFree(oglSystem.visualInfo);
1019    #endif
1020       }
1021       if(oglSystem.glContext)
1022         glXDestroyContext(xGlobalDisplay, oglSystem.glContext);
1023
1024       if(oglSystem.glxDrawable)
1025       {
1026          XDestroyWindow(xGlobalDisplay, oglSystem.glxDrawable);
1027          oglSystem.glxDrawable = 0;
1028       }
1029       #endif
1030    #endif
1031       delete oglSystem;
1032    }
1033
1034    /*static */bool ::initialDisplaySetup(Display display, bool canCheckExtensions, bool loadExtensions)
1035    {
1036       OGLDisplay oglDisplay = display.driverData;
1037       OGLSystem oglSystem = display.displaySystem.driverData;
1038       bool result = true;
1039
1040 #if !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) && !defined(__ODROID__)
1041       if(loadExtensions && ogl_LoadFunctions() == ogl_LOAD_FAILED)
1042          PrintLn("ogl_LoadFunctions() failed!");
1043       CheckCapabilities(oglSystem, oglDisplay, canCheckExtensions);
1044 #endif
1045
1046       {
1047          GLCapabilities capabilities = *&display.glCapabilities;
1048          // PrintLn("Available OpenGL Capabilities: ", oglDisplay.capabilities);
1049          // PrintLn("Desired OpenGL Capabilities: ", capabilities);
1050
1051          oglDisplay.originalCapabilities = oglDisplay.capabilities;
1052
1053          // Re-enable glCaps_shaders if no fixed function support
1054          if(!oglDisplay.capabilities.fixedFunction)
1055             capabilities.shaders = true;
1056          // Re-enable fixed function if no glCaps_shaders support
1057          if(!oglDisplay.capabilities.shaders)
1058          {
1059             capabilities.fixedFunction = true;
1060             capabilities.shaders = false;
1061          }
1062
1063          if(!capabilities.shaders && !capabilities.fixedFunction)
1064          {
1065             capabilities.fixedFunction = oglDisplay.capabilities.fixedFunction;
1066             capabilities.shaders = oglDisplay.capabilities.shaders;
1067          }
1068
1069          // Disable things that don't work with glCaps_shaders
1070          if(capabilities.shaders)
1071          {
1072             capabilities.fixedFunction = false;
1073             capabilities.legacy = false;
1074             capabilities.immediate = false;
1075          }
1076
1077          #if !ENABLE_GL_POINTER
1078          // Re-enable vertex buffer if no pointer support
1079          capabilities.vertexBuffer = true;
1080          #endif
1081
1082          oglDisplay.capabilities &= capabilities;
1083
1084          // PrintLn("Selected OpenGL Capabilities: ", oglDisplay.capabilities);
1085          oglSystem.capabilities = oglDisplay.capabilities;
1086       }
1087
1088    #ifdef GL_DEBUGGING
1089       if(oglDisplay.capabilities.debug)
1090          setupDebugging();
1091    #else
1092       oglDisplay.capabilities.debug = false;
1093    #endif
1094
1095 #if ENABLE_GL_VAO
1096       if(oglDisplay.capabilities.vao)
1097       {
1098          glGenVertexArrays(1, &oglDisplay.vao);
1099          glBindVertexArray(oglDisplay.vao);
1100       }
1101 #endif
1102
1103       oglSystem.capabilities = oglDisplay.capabilities;
1104       SETCAPS(oglDisplay.capabilities);
1105
1106 #if ENABLE_GL_SHADERS
1107       if(glCaps_shaders)
1108       {
1109 #if ENABLE_GL_LEGACY
1110          if(oglDisplay.compat)
1111          {
1112             glDisableClientState(GL_VERTEX_ARRAY);
1113             glDisableClientState(GL_NORMAL_ARRAY);
1114             glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1115             glDisableClientState(GL_COLOR_ARRAY);
1116          }
1117 #endif
1118          defaultShader.select();
1119       }
1120 #if ENABLE_GL_LEGACY
1121       else
1122       {
1123          glDisableVertexAttribArray(GLBufferContents::color);
1124          glDisableVertexAttribArray(GLBufferContents::normal);
1125          glDisableVertexAttribArray(GLBufferContents::texCoord);
1126          glDisableVertexAttribArray(GLBufferContents::vertex);
1127          glDisableVertexAttribArray(GLBufferContents::tangent1);
1128          glDisableVertexAttribArray(GLBufferContents::tangent2);
1129 #if ENABLE_GL_VAO
1130          glBindVertexArray(0);
1131 #endif
1132          glUseProgram(0);
1133       }
1134 #endif
1135
1136 #endif
1137
1138 #if ENABLE_GL_VAO
1139       if(glCaps_vao)
1140          glBindVertexArray(oglDisplay.vao);
1141 #endif
1142
1143       GLEnableClientState(VERTICES);
1144
1145       GLABBindBuffer(GL_ARRAY_BUFFER, 0);
1146       GLABBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1147
1148 #if defined(__WIN32__)
1149       if(glBlendFuncSeparate)
1150          glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1151       else
1152          glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1153 #else
1154       glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1155 #endif
1156       glEnable(GL_BLEND);
1157
1158       GLMatrixMode(MatrixMode::texture);
1159       GLLoadIdentity();
1160
1161       GLMatrixMode(MatrixMode::modelView);
1162       GLLoadIdentity(); // For setting up GLES stack
1163       GLScaled(1.0, 1.0, -1.0);
1164       // glTranslatef(0.375f, 0.375f, 0.0f);
1165       // glTranslatef(-0.625f, -0.625f, 0.0f);
1166       GLMatrixMode(MatrixMode::projection);
1167       GLLoadIdentity();
1168       if(display.width && display.height)
1169          GLOrtho(0,display.width,display.height,0,0.0,1.0);
1170
1171 #if ENABLE_GL_FFP
1172       if(!glCaps_shaders)
1173       {
1174          glShadeModel(GL_FLAT);
1175
1176          #define GL_LIGHT_MODEL_LOCAL_VIEWER 0x0B51
1177          GLLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1178
1179 #if !defined(_GLES)
1180          ;//GLLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1181 #endif
1182          glFogi(GL_FOG_MODE, GL_EXP);
1183          glFogf(GL_FOG_DENSITY, 0);
1184          glEnable(GL_NORMALIZE);
1185       }
1186 #endif
1187       glDepthFunc(GL_LESS);
1188       glClearDepth(1.0);
1189 #if !defined(__EMSCRIPTEN__)
1190       glDisable(GL_MULTISAMPLE);
1191 #endif
1192
1193 #if !defined(ECERE_NO3D) && !defined(ECERE_VANILLA)
1194       display.ambient = Color { 50,50,50 };
1195 #endif
1196       return result;
1197    }
1198
1199    bool CreateDisplay(Display display)
1200    {
1201       bool result = false;
1202       OGLDisplay oglDisplay = display.driverData;
1203       OGLSystem oglSystem = display.displaySystem.driverData;
1204
1205       if(!oglDisplay)
1206          oglDisplay = display.driverData = OGLDisplay { };
1207       oglDisplay.capabilities = oglSystem.capabilities;
1208
1209 #if defined(__WIN32__) || defined(USEPBUFFER)
1210       if(!display.alphaBlend)
1211 #endif
1212       {
1213 #if defined(__WIN32__)
1214          oglDisplay.hdc = GetDC(display.window);
1215          SetPixelFormat(oglDisplay.hdc, oglSystem.format, &oglSystem.pfd);
1216          if((oglDisplay.glrc = winCreateContext(oglDisplay.hdc, &oglDisplay.version, &oglDisplay.compat, (*&display.glCapabilities).compatible)))
1217          {
1218             wglShareLists(oglSystem.glrc, oglDisplay.glrc);
1219             wglMakeCurrent(oglDisplay.hdc, oglDisplay.glrc);
1220             result = true;
1221          }
1222          else
1223             ReleaseDC(display.window, oglDisplay.hdc);
1224 #elif defined(__unix__) || defined(__APPLE__)
1225 #  if defined(__ANDROID__) || defined(__EMSCRIPTEN__) || defined(__ODROID__)
1226          result = true;
1227 #  else
1228          XVisualInfo * visualInfo = ((XWindowData)display.windowDriverData).visual;
1229          /*
1230 #if defined(__APPLE__)
1231          XVisualInfo template = { 0 };
1232          XWindowAttributes winAttr;
1233          int n;
1234          XGetWindowAttributes(xGlobalDisplay, (X11Window)display.window, &winAttr);
1235          template.visualid = XVisualIDFromVisual(winAttr.visual);
1236          visualInfo = XGetVisualInfo(xGlobalDisplay, VisualIDMask, &template, &n);
1237 #ifdef _DEBUG
1238          printf("XGetVisualInfo visual ID = %d\n", template.visualid);
1239          printf("visualInfo visual ID = %d\n", visualInfo->visualid);
1240          printf("oglSystem.visualInfo visual ID = %d\n", oglSystem.visualInfo->visualid);
1241          printf("((XWindowData)display.windowDriverData).visual visual ID = %d\n", ((XWindowData)display.windowDriverData).visual->visualid);
1242 #endif
1243          // visualInfo = oglSystem.visualInfo;
1244 //#endif
1245          */
1246 #if !defined(__APPLE__)
1247          oglDisplay.compat = true;
1248          oglDisplay.version = 4;
1249 #endif
1250
1251          if(visualInfo)
1252          {
1253             //printf("visualInfo is not null\n");
1254             // printf("Creating Display Context, sharing with %x!\n", oglSystem.glContext);
1255             oglDisplay.glContext = glXCreateContext(xGlobalDisplay, visualInfo, oglSystem.glContext, True);
1256             //XFree(visualInfo);
1257          }
1258
1259          // oglDisplay.glContext = glXCreateContext(xGlobalDisplay, oglSystem.visualInfo, oglSystem.glContext, True);
1260          if(oglDisplay.glContext)
1261          {
1262             //printf("CreateDisplay Got a Context\n");
1263             glXMakeCurrent(xGlobalDisplay, (GLXDrawable)display.window, oglDisplay.glContext);
1264             result = true;
1265          }
1266 #  endif
1267 #endif
1268       }
1269 #if defined(__WIN32__) || defined(USEPBUFFER)
1270       else
1271       {
1272          oglDisplay.compat = (*&display.glCapabilities).compatible;
1273          result = true;
1274          wglMakeCurrent(oglSystem.hdc, oglSystem.glrc);
1275       }
1276 #endif
1277       if(result)
1278       {
1279 #if defined(__EMSCRIPTEN__)
1280          emscripten_webgl_make_context_current(oglSystem.glc);
1281 #endif
1282
1283 #if defined(__WIN32__) || defined(USEPBUFFER)
1284          initialDisplaySetup(display, !display.alphaBlend, true);
1285 #else
1286          initialDisplaySetup(display, true, true);
1287 #endif
1288       }
1289
1290       if(!useSingleGLContext)
1291       {
1292    #if defined(__WIN32__)
1293          wglMakeCurrent(null, null);
1294    #elif defined(__unix__) || defined(__APPLE__)
1295       #if defined(__ANDROID__) || defined(__ODROID__) || defined(__EMSCRIPTEN__)
1296          result = true;
1297       #else
1298          glXMakeCurrent(xGlobalDisplay, None, null);
1299       #endif
1300    #endif
1301       }
1302       else
1303       {
1304       #if defined(__ANDROID__) || defined(__EMSCRIPTEN__) || defined(__ODROID__)
1305          result = true;
1306       #endif
1307       }
1308       return result;
1309    }
1310
1311    bool DisplaySize(Display display, int width, int height)
1312    {
1313       OGLDisplay oglDisplay = display.driverData;
1314       bool result = false;
1315
1316 #if defined(__WIN32__) || defined(USEPBUFFER)
1317       OGLSystem oglSystem = display.displaySystem.driverData;
1318       if(display.alphaBlend)
1319       {
1320 #if defined(__WIN32__)
1321          const int attributes[]=
1322          {
1323             /*WGL_TEXTURE_FORMAT_ARB, WGL_TEXTURE_RGBA_ARB,
1324             WGL_TEXTURE_TARGET_ARB, WGL_TEXTURE_2D_ARB, */0
1325          };
1326          int pixelFormat = 0;
1327          if(wglChoosePixelFormatARB)
1328          {
1329             int valid;
1330             int numFormats;
1331             float fAttributes[] = {0,0};
1332             int iAttributes[] =
1333             {
1334                //WGL_DRAW_TO_BITMAP_ARB, GL_TRUE,
1335                WGL_DRAW_TO_PBUFFER_ARB,GL_TRUE,
1336                WGL_SUPPORT_OPENGL_ARB,GL_TRUE,
1337                WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB,
1338                WGL_COLOR_BITS_ARB,24,
1339                WGL_ALPHA_BITS_ARB,8,
1340                WGL_DEPTH_BITS_ARB,16,
1341                WGL_STENCIL_BITS_ARB,0,
1342                WGL_DOUBLE_BUFFER_ARB,GL_FALSE,
1343                WGL_SAMPLE_BUFFERS_ARB,GL_TRUE,
1344                WGL_SAMPLES_ARB, 4,                  // Check For 4x Multisampling
1345                0,0
1346             };
1347
1348             //Log("Found wglChoosePixelFormatARB\n");
1349
1350             valid = wglChoosePixelFormatARB(oglSystem.hdc,iAttributes,fAttributes,1,&pixelFormat,&numFormats);
1351             if(!valid || !numFormats)
1352             {
1353                //Log("Can't find 4x multi sampling\n");
1354                iAttributes[19] = 2;
1355                valid = wglChoosePixelFormatARB(oglSystem.hdc,iAttributes,fAttributes,1,&pixelFormat,&numFormats);
1356                if(!valid || !numFormats)
1357                {
1358                   // Log("Can't find 2x multi sampling\n");
1359                   iAttributes[16] = 0;
1360                   iAttributes[17] = 0;
1361                   valid = wglChoosePixelFormatARB(oglSystem.hdc,iAttributes,fAttributes,1,&pixelFormat,&numFormats);
1362                   if(!valid || !numFormats)
1363                   {
1364                      int iAttributes[] =
1365                      {
1366                         WGL_DRAW_TO_PBUFFER_ARB,GL_TRUE,
1367                         //WGL_DRAW_TO_BITMAP_ARB,GL_TRUE,
1368                         WGL_SUPPORT_OPENGL_ARB,GL_TRUE,
1369                         WGL_COLOR_BITS_ARB,24,
1370                         WGL_ALPHA_BITS_ARB,8,
1371                         WGL_DEPTH_BITS_ARB,16,
1372                         0,0
1373                      };
1374                      valid = wglChoosePixelFormatARB(oglSystem.hdc,iAttributes,fAttributes,1,&pixelFormat,&numFormats);
1375                   }
1376                }
1377             }
1378             if(valid && numFormats)
1379             {
1380                wglMakeCurrent(null, null);
1381             }
1382          }
1383
1384          wglMakeCurrent( null, null );
1385          wglMakeCurrent( oglDisplay.hdc, oglDisplay.glrc );
1386          if(oglDisplay.hdc && oglDisplay.pBuffer)
1387             wglReleasePbufferDCARB(oglDisplay.pBuffer, oglDisplay.hdc);
1388
1389          wglDestroyPbufferARB(oglDisplay.pBuffer);
1390
1391          if(!useSingleGLContext)
1392             wglMakeCurrent( null, null );
1393
1394          if(oglDisplay.glrc)
1395             wglDeleteContext(oglDisplay.glrc);
1396
1397          oglDisplay.pBuffer = wglCreatePbufferARB(oglSystem.hdc, pixelFormat, width, height, attributes);
1398          oglDisplay.hdc = wglGetPbufferDCARB(oglDisplay.pBuffer);
1399          if((oglDisplay.glrc = winCreateContext(oglDisplay.hdc, null, null, oglDisplay.capabilities.compatible)))
1400          {
1401             BITMAPINFO * info;
1402             HDC hdc = GetDC(display.window);
1403
1404             wglShareLists(oglSystem.glrc, oglDisplay.glrc);
1405             wglMakeCurrent(oglDisplay.hdc, oglDisplay.glrc);
1406
1407             //wglQueryPbufferARB(pBuffer, WGL_PBUFFER_WIDTH_ARB, &width);
1408             //wglQueryPbufferARB(pBuffer, WGL_PBUFFER_HEIGHT_ARB, &height);
1409
1410             // glDeleteBuffersARB(2, oglDisplay.imageBuffers);
1411
1412             if((info = (BITMAPINFO *)new0 byte[sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256]))
1413             {
1414                HBITMAP newBitmap;
1415
1416                if(oglDisplay.memDC) DeleteDC(oglDisplay.memDC);
1417                oglDisplay.memDC = CreateCompatibleDC(hdc);
1418                SetMapMode(oglDisplay.memDC, MM_TEXT);
1419                info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1420                info->bmiHeader.biPlanes = 1;
1421                info->bmiHeader.biCompression = BI_RGB;
1422                info->bmiHeader.biBitCount = 32; //(uint16)GetDeviceCaps(hdc, BITSPIXEL);
1423                info->bmiHeader.biWidth = width;
1424                info->bmiHeader.biHeight = height;
1425                newBitmap = CreateDIBSection(hdc, info, DIB_RGB_COLORS, &oglDisplay.picture, null, 0);
1426                if(newBitmap)
1427                {
1428                   SelectObject(oglDisplay.memDC, newBitmap);
1429                   if(oglDisplay.memBitmap) DeleteObject(oglDisplay.memBitmap);
1430                   /*
1431                   {
1432                      PIXELFORMATDESCRIPTOR pfd = { 0 };
1433                      pfd.nSize = (short)sizeof(pfd);
1434                      pfd.nVersion = 1;
1435                      pfd.dwFlags = PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL;
1436                      pfd.iPixelType = PFD_TYPE_RGBA;
1437                      pfd.cColorBits = 32;
1438                      //pfd.cAlphaBits = 8;
1439                      pfd.cDepthBits = 24;
1440                      pfd.iLayerType = PFD_MAIN_PLANE;
1441
1442                      oglDisplay.hdc = oglDisplay.memDC;
1443
1444                      pixelFormat = ChoosePixelFormat(oglSystem.hdc, &pfd);
1445                      DescribePixelFormat(oglDisplay.hdc, pixelFormat, sizeof(pfd), &pfd);
1446                      SetPixelFormat(oglDisplay.hdc, pixelFormat, &pfd);
1447
1448                      oglDisplay.glrc = wglCreateContext(oglDisplay.hdc);
1449                      wglShareLists(oglSystem.glrc, oglDisplay.glrc);
1450                      wglMakeCurrent(oglDisplay.hdc, oglDisplay.glrc);
1451                   }
1452                   */
1453                   /*
1454                   {
1455                      const int imageSize = width * height * 4;
1456
1457                      glGenBuffersARB(2, oglDisplay.imageBuffers);
1458
1459                      glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, oglDisplay.imageBuffers[0]);
1460                      glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, imageSize, null, GL_STREAM_READ);
1461                      // glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, oglDisplay.imageBuffers[1]);
1462                      // glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, imageSize / 2, null, GL_STREAM_READ);
1463                   }
1464                   */
1465                   oglDisplay.memBitmap = newBitmap;
1466                   oglDisplay.stride = width;
1467
1468                   result = true;
1469                }
1470                delete info;
1471             }
1472             ReleaseDC(display.window, hdc);
1473          }
1474 #elif defined(__unix__) || defined(__APPLE__)
1475       #if defined(__ANDROID__) || defined(__ODROID__) || defined(__EMSCRIPTEN__)
1476          result = true;
1477       #else
1478          int attrib[] =
1479          {
1480             GLX_DOUBLEBUFFER,  True,
1481             GLX_DEPTH_SIZE,    1,
1482             GLX_RED_SIZE,      8,
1483             GLX_GREEN_SIZE,    8,
1484             GLX_BLUE_SIZE,     8,
1485             GLX_ALPHA_SIZE,    8,
1486             GLX_STENCIL_SIZE,  1,
1487             //GLX_DEPTH_SIZE,    24,
1488             GLX_RENDER_TYPE,   GLX_RGBA_BIT,
1489             GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT,
1490             None
1491          };
1492
1493          int PBattrib[] =
1494          {
1495             GLX_PBUFFER_WIDTH,   width,
1496             GLX_PBUFFER_HEIGHT,  height,
1497             GLX_LARGEST_PBUFFER, False,
1498             None
1499          };
1500
1501          // choose a pixel format that meets our minimum requirements
1502          int count = 0;
1503
1504          GLXFBConfig *config = glXChooseFBConfig(xGlobalDisplay, DefaultScreen(xGlobalDisplay), attrib, &count);
1505          if(config)
1506          {
1507             if(oglDisplay.pixmap)
1508             {
1509                XFreePixmap(xGlobalDisplay, oglDisplay.pixmap);
1510                oglDisplay.pixmap = None;
1511             }
1512             if(oglDisplay.shapePixmap)
1513             {
1514                XFreePixmap(xGlobalDisplay, oglDisplay.shapePixmap);
1515                oglDisplay.shapePixmap = None;
1516             }
1517
1518             // Free Shared Memory Pixmap
1519             if(oglDisplay.image)
1520             {
1521                if(oglDisplay.shminfoShape.shmid != -1)
1522                {
1523                   XShmDetach(xGlobalDisplay, &oglDisplay.shminfo);
1524                   if(oglDisplay.shminfo.shmaddr != (void *)-1)
1525                      shmdt(oglDisplay.shminfo.shmaddr);
1526                   shmctl(oglDisplay.shminfo.shmid, IPC_RMID, 0);
1527                }
1528                XDestroyImage(oglDisplay.image);
1529                oglDisplay.image = None;
1530             }
1531             if(oglDisplay.shapeImage)
1532             {
1533                if(oglDisplay.shminfoShape.shmid != -1)
1534                {
1535                   XShmDetach(xGlobalDisplay, &oglDisplay.shminfoShape);
1536                   if(oglDisplay.shminfoShape.shmaddr != (void *)-1)
1537                      shmdt(oglDisplay.shminfoShape.shmaddr);
1538                   shmctl(oglDisplay.shminfoShape.shmid, IPC_RMID, 0);
1539                }
1540                XDestroyImage(oglDisplay.shapeImage);
1541                oglDisplay.shapeImage = None;
1542             }
1543
1544             if(oglDisplay.windowPicture)
1545                XRenderFreePicture(xGlobalDisplay, oglDisplay.windowPicture);
1546             if(oglDisplay.pixmapPicture)
1547                XRenderFreePicture(xGlobalDisplay, oglDisplay.pixmapPicture);
1548
1549             if(oglDisplay.pixmap)
1550                XFreePixmap(xGlobalDisplay, oglDisplay.pixmap);
1551
1552             if(oglDisplay.glContext)
1553               glXDestroyContext(xGlobalDisplay, oglDisplay.glContext);
1554             if(oglDisplay.pBuffer)
1555                glXDestroyPbuffer(xGlobalDisplay, oglDisplay.pBuffer);
1556
1557             oglDisplay.pBuffer = glXCreatePbuffer(xGlobalDisplay, config[0], PBattrib);
1558             if(oglDisplay.pBuffer)
1559             {
1560                oglDisplay.glContext = glXCreateNewContext(xGlobalDisplay, config[0], GLX_RGBA_TYPE, oglSystem.glContext, True);
1561                if(oglDisplay.glContext)
1562                {
1563                   glXMakeCurrent(xGlobalDisplay, None, null);
1564                   glXMakeCurrent(xGlobalDisplay, (GLXDrawable)display.window, oglDisplay.glContext);
1565
1566                   // Initialize Shared Memory Pixmap
1567                   oglDisplay.image = XShmCreateImage(xGlobalDisplay, DefaultVisual(xGlobalDisplay, DefaultScreen(xGlobalDisplay)), 32,
1568                      ZPixmap, null, &oglDisplay.shminfo, width, height);
1569                   if(oglDisplay.image)
1570                   {
1571                      oglDisplay.shminfo.shmid = shmget(IPC_PRIVATE,
1572                         oglDisplay.image->bytes_per_line * oglDisplay.image->height, IPC_CREAT|0777);
1573                      if(oglDisplay.shminfo.shmid != -1)
1574                      {
1575                         oglDisplay.shminfo.shmaddr = shmat(oglDisplay.shminfo.shmid, 0, 0);
1576                         if(oglDisplay.shminfo.shmaddr != (void *)-1)
1577                         {
1578                            oglDisplay.shminfo.readOnly = False;
1579                            if(XShmAttach(xGlobalDisplay, &oglDisplay.shminfo))
1580                            {
1581                               oglDisplay.pixmap = XShmCreatePixmap(xGlobalDisplay, (X11Window)display.window, oglDisplay.shminfo.shmaddr,
1582                                  &oglDisplay.shminfo, width, height, 32);
1583
1584                               // Initialize Shared Memory Shape Pixmap
1585                               oglDisplay.shapeImage = XShmCreateImage(xGlobalDisplay, DefaultVisual(xGlobalDisplay, DefaultScreen(xGlobalDisplay)), 1,
1586                                  ZPixmap, null, &oglDisplay.shminfoShape, width, height);
1587                               if(oglDisplay.shapeImage)
1588                               {
1589                                  oglDisplay.shminfoShape.shmid = shmget(IPC_PRIVATE,
1590                                     oglDisplay.shapeImage->bytes_per_line * oglDisplay.shapeImage->height, IPC_CREAT|0777);
1591                                  if(oglDisplay.shminfoShape.shmid != -1)
1592                                  {
1593                                     oglDisplay.shminfoShape.shmaddr = shmat(oglDisplay.shminfoShape.shmid, 0, 0);
1594                                     if(oglDisplay.shminfoShape.shmaddr != (void *)-1)
1595                                     {
1596                                        oglDisplay.shminfoShape.readOnly = False;
1597                                        if(XShmAttach(xGlobalDisplay, &oglDisplay.shminfoShape))
1598                                        {
1599                                           oglDisplay.shapePixmap = XShmCreatePixmap(xGlobalDisplay, (X11Window)display.window, oglDisplay.shminfoShape.shmaddr,
1600                                              &oglDisplay.shminfoShape, width, height, 1);
1601                                           //oglDisplay.shapePixmap = XCreatePixmap(xGlobalDisplay, (X11Window)display.window, width, height, 1);
1602
1603                                           {
1604                                              XRenderPictureAttributes attributes = { 0 };
1605                                              XRenderPictFormat * format = XRenderFindStandardFormat(xGlobalDisplay, /*PictStandardRGB24*/ PictStandardARGB32);
1606                                              #if !defined(__APPLE__)
1607                                              attributes.repeat = RepeatNormal;
1608                                              #else
1609                                              attributes.repeat = 1;
1610                                              #endif
1611                                              oglDisplay.pixmapPicture = XRenderCreatePicture(xGlobalDisplay, oglDisplay.pixmap, format, CPRepeat, &attributes);
1612                                              oglDisplay.windowPicture = XRenderCreatePicture(xGlobalDisplay, (X11Window)display.window, format, 0, &attributes);
1613                                              oglDisplay.shapePicture = XRenderCreatePicture(xGlobalDisplay, oglDisplay.shapePixmap,
1614                                                 XRenderFindStandardFormat(xGlobalDisplay, PictStandardA1), 0, &attributes);
1615                                           }
1616
1617                                           oglDisplay.picture = oglDisplay.shminfo.shmaddr;
1618                                           oglDisplay.stride = oglDisplay.image->bytes_per_line / 4;
1619
1620                                           result = true;
1621                                        }
1622                                     }
1623                                  }
1624                               }
1625                            }
1626                         }
1627                      }
1628                   }
1629                }
1630             }
1631             XFree(config);
1632          }
1633      #endif
1634 #endif
1635          CreateDisplay(display);
1636 #if defined(__WIN32__)
1637          wglMakeCurrent(oglDisplay.hdc, oglDisplay.glrc);
1638 #elif defined(__unix__) || defined(__APPLE__)
1639       #if defined(__ANDROID__) || defined(__ODROID__)
1640          width = eglWidth;
1641          height = eglHeight;
1642       #elif defined(__EMSCRIPTEN__)
1643          emscripten_webgl_make_context_current(oglSystem.glc);
1644       #else
1645          glXMakeCurrent(xGlobalDisplay, (GLXDrawable)display.window, oglDisplay.glContext);
1646       #endif
1647 #endif
1648       }
1649       else
1650 #endif
1651          result = true;
1652
1653       SETCAPS(oglDisplay.capabilities);
1654
1655       if(display.alphaBlend && result)
1656          initialDisplaySetup(display, true, false);
1657
1658       if(!result && display.alphaBlend)
1659       {
1660          printf("Alpha blending windows not supported on this display\n");
1661       }
1662       if(!result)
1663          return false;
1664
1665       result = false;
1666
1667       glViewport(0,0,width,height);
1668       GLMatrixMode(MatrixMode::projection);
1669       GLLoadIdentity();
1670       GLOrtho(0,width,height,0,0.0,1.0);
1671       displayWidth = display.width = width;
1672       displayHeight = display.height = height;
1673
1674       if(!oglDisplay.flippingBuffer || oglDisplay.flipBufW < width || oglDisplay.flipBufH < height)
1675       {
1676          oglDisplay.flipBufW = width;
1677          oglDisplay.flipBufH = height;
1678 #if defined(_GLES) || defined(_GLES2)
1679          result = true;
1680 #else
1681          oglDisplay.flippingBuffer = renew oglDisplay.flippingBuffer ColorAlpha [width * height];
1682 #endif
1683       }
1684       if(oglDisplay.flippingBuffer || !width || !height)
1685          result = true;
1686
1687       return result;
1688    }
1689
1690    void DisplayPosition(Display display, int x, int y)
1691    {
1692       OGLDisplay oglDisplay = display.driverData;
1693
1694       oglDisplay.x = x;
1695       oglDisplay.y = y;
1696    }
1697
1698    void SetPalette(Display display, ColorAlpha * palette, bool colorMatch)
1699    {
1700    }
1701
1702    void RestorePalette(Display display)
1703    {
1704    }
1705
1706    void StartUpdate(Display display)
1707    {
1708 #if ENABLE_GL_VAO
1709       if(glCaps_vao)
1710       {
1711          OGLDisplay oglDisplay = display.driverData;
1712          glBindVertexArray(oglDisplay.vao);
1713       }
1714 #endif
1715       GLABBindBuffer(GL_ARRAY_BUFFER, 0);
1716       GLABBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1717 #if ENABLE_GL_SHADERS
1718       activeProgram = 0;
1719 #endif
1720    }
1721
1722    void EndUpdate(Display display)
1723    {
1724    }
1725
1726    void Scroll(Display display, Box scroll, int x, int y, Extent dirty)
1727    {
1728    }
1729
1730    void Update(Display display, Box updateBox)
1731    {
1732 #if defined(__WIN32__) || defined(USEPBUFFER)
1733       OGLDisplay oglDisplay = display.driverData;
1734 #endif
1735
1736 #if !defined(__ANDROID__)
1737       /*glFlush();
1738       glFinish();*/
1739 #endif
1740
1741 #if defined(__WIN32__) || defined(USEPBUFFER)
1742       if(display.alphaBlend)
1743       {
1744          glPixelStorei(GL_PACK_ALIGNMENT, 4);
1745          glPixelStorei(GL_PACK_ROW_LENGTH, oglDisplay.stride);
1746          glPixelStorei(GL_PACK_SKIP_ROWS, 0);
1747          glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
1748          glReadPixels(0,0,display.width,display.height,GL_BGRA_EXT,GL_UNSIGNED_BYTE, oglDisplay.picture);
1749
1750          {
1751 #if defined(__WIN32__)
1752             HDC hdc = GetDC(0);
1753             POINT point = { oglDisplay.x, oglDisplay.y};
1754             POINT srcPoint = { 0, 0 };
1755             BLENDFUNCTION blend = { 0 };
1756             SIZE size;
1757             size.cx = display.width;
1758             size.cy = display.height;
1759             blend.BlendOp = AC_SRC_OVER;
1760             blend.BlendFlags = 0;
1761             blend.SourceConstantAlpha = 255;
1762             blend.AlphaFormat = AC_SRC_ALPHA;
1763
1764             /*
1765             // Process partial images.  Mapping the buffer waits for
1766             // outstanding DMA transfers into the buffer to finish.
1767             glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, oglDisplay.imageBuffers[0]);
1768             oglDisplay.pboMemory1 = (byte *)glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
1769
1770             // glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, oglDisplay.imageBuffers[1]);
1771             // oglDisplay.pboMemory2 = (byte *)glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB,GL_READ_ONLY);
1772
1773
1774             memcpy(oglDisplay.picture, oglDisplay.pboMemory1, display.width * display.height * 4);
1775             //memcpy(oglDisplay.picture + display.width * display.height * 4 / 2, oglDisplay.pboMemory2, display.width * display.height * 4/ 2);
1776             */
1777
1778             UpdateLayeredWindow(display.window, hdc, &point, &size, oglDisplay.memDC, &srcPoint, 0, &blend, ULW_ALPHA);
1779             /*
1780
1781             // Unmap the image buffers
1782             glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, oglDisplay.imageBuffers[0]);
1783             glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
1784
1785             // glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, oglDisplay.imageBuffers[1]);
1786             // glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
1787
1788             // Bind two different buffer objects and start the glReadPixels
1789             // asynchronously. Each call will return directly after
1790             // starting the DMA transfer.
1791             glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, oglDisplay.imageBuffers[0]);
1792             glReadPixels(0, 0, display.width, display.height, GL_BGRA, GL_UNSIGNED_BYTE, 0);
1793
1794             // glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, oglDisplay.imageBuffers[1]);
1795             // glReadPixels(0, display.height/2, display.width, display.height/2, GL_BGRA, GL_UNSIGNED_BYTE, 0);
1796             */
1797
1798             ReleaseDC(0, hdc);
1799 #elif defined(__unix__) || defined(__APPLE__)
1800       #if defined(__ANDROID__) || defined(__ODROID__) || defined(__EMSCRIPTEN__)
1801       #else
1802             XTransform transform =
1803             {
1804                {
1805                   { (int)(1.0f * (1<<16)), (int)(0.0f * (1<<16)),  (int)(0 * (1 << 16)) },
1806                   { (int)(0.0f),           (int)(-1.0f * (1<<16)), (int)(0 * (1<<16)) },
1807                   { (int)(0.0f * (1<<16)), (int)(0.0f * (1<<16)),  (int)(1.0f * (1<<16)) }
1808                }
1809             };
1810             XRenderSetPictureTransform(xGlobalDisplay, oglDisplay.pixmapPicture, &transform);
1811             XRenderComposite(xGlobalDisplay, PictOpSrc, oglDisplay.pixmapPicture, None, oglDisplay.shapePicture, 0, 0, 0, 0, 0, 0, display.width, display.height);
1812             XRenderComposite(xGlobalDisplay, PictOpSrc, oglDisplay.pixmapPicture, None, oglDisplay.windowPicture, 0, 0, 0, 0, 0, 0, display.width, display.height);
1813             #if !defined(__APPLE__)
1814             XShapeCombineMask(xGlobalDisplay, (X11Window)display.window, ShapeInput, 0, 0, oglDisplay.shapePixmap, ShapeSet);
1815             #else
1816             XShapeCombineMask(xGlobalDisplay, display.window, 2, 0, 0, oglDisplay.shapePixmap, ShapeSet);
1817             #endif
1818             XFlush(xGlobalDisplay);
1819      #endif
1820 #endif
1821          }
1822       }
1823       else
1824 #endif
1825       {
1826 #if defined(__WIN32__)
1827          //wglSwapLayerBuffers(oglDisplay.hdc,WGL_SWAP_MAIN_PLANE);
1828          SwapBuffers(oglDisplay.hdc);
1829          //ecere::sys::Sleep(0.1);
1830 #elif defined(__unix__) || defined(__APPLE__)
1831       #if defined(__ANDROID__) || defined(__ODROID__)
1832          egl_swap_buffers();
1833       #elif defined(__EMSCRIPTEN__)
1834       #else
1835          glXSwapBuffers(xGlobalDisplay, (GLXDrawable)display.window);
1836       #endif
1837 #endif
1838       }
1839    }
1840
1841    void FreeBitmap(DisplaySystem displaySystem, Bitmap bitmap)
1842    {
1843       if(bitmap.driverData)
1844       {
1845          GLuint tex = (GLuint)(uintptr)bitmap.driverData;
1846          glDeleteTextures(1, &tex);
1847          bitmap.driverData = 0;
1848       }
1849       bitmap.driver = ((subclass(DisplayDriver))class(LFBDisplayDriver));
1850    }
1851
1852    bool AllocateBitmap(DisplaySystem displaySystem, Bitmap bitmap, int width, int height, int stride, PixelFormat format, bool allocatePalette)
1853    {
1854       OGLSystem oglSystem = displaySystem.driverData;
1855       GLCapabilities capabilities = oglSystem.capabilities;
1856       bool result = false;
1857       Bitmap mipMap { };
1858       GLuint glBitmap = 0;
1859
1860       uint w = width, h = height;
1861       if(!capabilities.nonPow2Textures)
1862       {
1863          w = pow2i(w);
1864          h = pow2i(h);
1865       }
1866       w = Min(w, oglSystem.maxTextureSize);
1867       h = Min(h, oglSystem.maxTextureSize);
1868
1869       glGenTextures(1, &glBitmap);
1870       glBindTexture(GL_TEXTURE_2D, glBitmap);
1871
1872       glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
1873
1874       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1875       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1876
1877       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1878       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1879
1880 #if ENABLE_GL_FFP
1881       if(!capabilities.shaders)
1882          glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
1883 #endif
1884
1885       mipMap.Allocate(null, w, h, w, pixelFormatRGBA, false);
1886
1887       // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, mipMap.picture);
1888       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, mipMap.picture);
1889
1890       delete mipMap;
1891
1892       bitmap.driverData = (void *)(uintptr)glBitmap;
1893       bitmap.driver = displaySystem.driver;
1894       bitmap.width = w;
1895       bitmap.height = h;
1896
1897       result = true;
1898       return result;
1899    }
1900
1901    bool MakeDDBitmap(DisplaySystem displaySystem, Bitmap bitmap, bool mipMaps, uint cubeMapFace)
1902    {
1903       bool result = false;
1904       OGLSystem oglSystem = displaySystem.driverData;
1905       GLCapabilities capabilities = oglSystem.capabilities;
1906       Bitmap convBitmap = bitmap;
1907       bool oldStyleCubeMap = (cubeMapFace >> 3) != 0;
1908       int face = (cubeMapFace & 7) - 1;
1909       if(bitmap.keepData)
1910       {
1911          convBitmap = { };
1912          convBitmap.Copy(bitmap);
1913       }
1914
1915       // Pre process the bitmap... First make it 32 bit
1916       if(/*bitmap.pixelFormat == pixelFormatRGBA || */convBitmap.Convert(null, pixelFormat888, null))
1917       {
1918          int c, level;
1919          uint w = bitmap.width, h = bitmap.height;
1920          GLuint glBitmap = cubeMapFace && face > 0 ? (GLuint)(uintptr)bitmap.driverData : 0;
1921          int target = cubeMapFace ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
1922          if(!capabilities.nonPow2Textures)
1923          {
1924             w = pow2i(w);
1925             h = pow2i(h);
1926          }
1927          w = Min(w, oglSystem.maxTextureSize);
1928          h = Min(h, oglSystem.maxTextureSize);
1929
1930          if(mipMaps)
1931          {
1932             while(w * 2 < h) w *= 2;
1933             while(h * 2 < w) h *= 2;
1934          }
1935
1936          // Switch ARGB to RGBA
1937          //if(bitmap.format != pixelFormatRGBA)
1938          {
1939             int size = convBitmap.stride * convBitmap.height;
1940             for(c = 0; c < size; c++)
1941             {
1942                // ((ColorRGBA *)bitmap.picture)[c] = ((ColorAlpha *)bitmap.picture)[c];
1943                // TODO:
1944                ColorAlpha color = ((ColorAlpha *)convBitmap.picture)[c];
1945                ((ColorRGBA *)convBitmap.picture)[c] = ColorRGBA { color.color.r, color.color.g, color.color.b, color.a };
1946             }
1947          }
1948          // convBitmap.pixelFormat = pixelFormat888;
1949
1950          if(cubeMapFace && oldStyleCubeMap)
1951          {
1952             if(face == 0 || face == 1 || face == 4 || face == 5)
1953             {
1954                uint w = convBitmap.width;
1955                uint32 * tmp = new uint [convBitmap.width];
1956                int x, y;
1957                for(y = 0; y < convBitmap.height; y++)
1958                {
1959                   uint32 * pic = (uint32 *)((byte *)convBitmap.picture + y * w * 4);
1960                   for(x = 0; x < w; x++)
1961                      tmp[x] = pic[w-1-x];
1962                   memcpy(pic, tmp, w*4);
1963                }
1964                delete tmp;
1965             }
1966             else if(face == 2 || face == 3)
1967             {
1968                int y;
1969                Bitmap tmp { };
1970                tmp.Allocate(null, convBitmap.width, convBitmap.height, 0, convBitmap.pixelFormat, false);
1971                for(y = 0; y < convBitmap.height; y++)
1972                {
1973                   memcpy(tmp.picture + convBitmap.width * 4 * y,
1974                      convBitmap.picture + (convBitmap.height-1-y) * convBitmap.width * 4,
1975                      convBitmap.width * 4);
1976                }
1977                memcpy(convBitmap.picture, tmp.picture, convBitmap.sizeBytes);
1978                delete tmp;
1979             }
1980          }
1981
1982          glGetError();
1983          if(!glBitmap)
1984             glGenTextures(1, &glBitmap);
1985          if(glBitmap == 0)
1986          {
1987             //int error = glGetError();
1988             return false;
1989          }
1990
1991          glBindTexture(target, glBitmap);
1992          glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
1993
1994          glTexParameteri(target, GL_TEXTURE_MIN_FILTER, mipMaps ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
1995          glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1996
1997          //glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1998
1999          //glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP);
2000          //glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP);
2001
2002          glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2003          glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2004
2005 #ifndef GL_TEXTURE_WRAP_R
2006    #define GL_TEXTURE_WRAP_R 0x8072
2007 #endif
2008
2009 #if !defined(__EMSCRIPTEN__)
2010          if(cubeMapFace)
2011             glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
2012 #endif
2013
2014 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
2015          glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.0 );
2016 #endif
2017
2018 #if ENABLE_GL_FFP
2019       if(!capabilities.shaders)
2020          glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
2021 #endif
2022
2023          result = true;
2024
2025          for(level = 0; result && (w >= 1 || h >= 1); level++, w >>= 1, h >>= 1)
2026          {
2027             Bitmap mipMap;
2028             if(!w) w = 1;
2029             if(!h) h = 1;
2030             if(bitmap.width != w || bitmap.height != h)
2031             {
2032                mipMap = Bitmap { };
2033                if(mipMap.Allocate(null, w, h, w, convBitmap.pixelFormat, false))
2034                {
2035                   Surface mipSurface = mipMap.GetSurface(0,0,null);
2036                   mipSurface.blend = false;
2037                   mipSurface.Filter(convBitmap, 0,0,0,0, w, h, convBitmap.width, convBitmap.height);
2038                   delete mipSurface;
2039                }
2040                else
2041                {
2042                   result = false;
2043                   delete mipMap;
2044                }
2045             }
2046             else
2047                mipMap = convBitmap;
2048
2049             if(result)
2050             {
2051                int error;
2052                //int width = 0;
2053                glGetError();
2054                // glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, mipMap.picture);
2055                glTexImage2D(cubeMapFace ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + face : GL_TEXTURE_2D, level, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, mipMap.picture);
2056                //printf("Calling glTexImage2D\n");
2057                //glGetTexLevelParameteriv(GL_TEXTURE_2D, level, GL_TEXTURE_WIDTH, &width);
2058                //printf("width = %d (Should be %d, %d)\n", width, w, h);
2059                if((error = glGetError()))
2060                {
2061                   //Logf("OpenGL Bitmap MakeDD error: %d...\n", error);
2062                   //printf("OpenGL Bitmap MakeDD error: %d...\n", error);
2063                   result = false;
2064                }
2065             }
2066             if(mipMap != convBitmap)
2067                delete mipMap;
2068             if(!mipMaps) break;
2069          }
2070
2071          convBitmap.driver.FreeBitmap(convBitmap.displaySystem, convBitmap);
2072          bitmap.driverData = (void *)(uintptr)glBitmap;
2073          bitmap.driver = displaySystem.driver;
2074          if(bitmap.keepData)
2075             delete convBitmap;
2076
2077          if(!result)
2078             FreeBitmap(displaySystem, bitmap);
2079          else if(oglSystem.loadingFont)
2080          {
2081             glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2082             glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2083             oglSystem.loadingFont = false;
2084          }
2085       }
2086       return result;
2087    }
2088
2089    void ReleaseSurface(Display display, Surface surface)
2090    {
2091       glDisable(GL_SCISSOR_TEST);
2092       delete surface.driverData;
2093       surface.driverData = null;
2094    }
2095
2096    bool GetBitmapSurface(DisplaySystem displaySystem, Surface surface, Bitmap bitmap, int x, int y, Box clip)
2097    {
2098       return false;
2099    }
2100
2101    bool GetSurface(Display display, Surface surface, int x,int y, Box clip)
2102    {
2103       bool result = false;
2104       OGLDisplay oglDisplay = display.driverData;
2105       OGLSurface oglSurface = surface.driverData = OGLSurface { };
2106       if(oglSurface)
2107       {
2108          SETCAPS(oglDisplay.capabilities);
2109          if(displayWidth != display.width || displayHeight != display.height)
2110          {
2111             displayWidth = display.width;
2112             displayHeight = display.height;
2113
2114             glViewport(0,0,display.width,display.height);
2115             GLLoadIdentity();
2116             GLOrtho(0,display.width,display.height,0,0.0,1.0);
2117          }
2118
2119          surface.offset.x = x;
2120          surface.offset.y = y;
2121          surface.unclippedBox = surface.box = clip;
2122          oglSurface.bitmapMult[0] = 1;
2123          oglSurface.bitmapMult[1] = 1;
2124          oglSurface.bitmapMult[2] = 1;
2125          oglSurface.bitmapMult[3] = 1;
2126
2127          glEnable(GL_SCISSOR_TEST);
2128          glScissor(
2129             x+clip.left,
2130             (display.height) -(y+clip.bottom)-1,
2131             clip.right-clip.left+1,
2132             clip.bottom-clip.top+1);
2133          result = true;
2134       }
2135       return result;
2136    }
2137
2138    void Clip(Display display, Surface surface, Box clip)
2139    {
2140       Box box;
2141
2142       if(clip != null)
2143       {
2144          box = clip;
2145          box.Clip(surface.unclippedBox);
2146          surface.box = box;
2147       }
2148       else
2149          box = surface.box = surface.unclippedBox;
2150       box.left += surface.offset.x;
2151       box.top  += surface.offset.y;
2152       box.right+= surface.offset.x;
2153       box.bottom += surface.offset.y;
2154
2155       glScissor(
2156          box.left,display.height - box.bottom - 1,
2157          box.right-box.left+1, box.bottom-box.top+1);
2158    }
2159
2160    bool GrabScreen(Display display, Bitmap bitmap, int x, int y, unsigned int w, unsigned int h)
2161    {
2162       bool result = false;
2163       OGLDisplay oglDisplay = display.driverData;
2164       ColorAlpha * flippingBuffer = oglDisplay.flippingBuffer;
2165
2166       if(oglDisplay.flippingBuffer)
2167       {
2168          if(bitmap.pixelFormat != pixelFormat888 || bitmap.width < w || bitmap.height < h)
2169          {
2170             bitmap.Free();
2171             bitmap.Allocate(null, w,h,w, pixelFormat888, false);
2172          }
2173          if(bitmap)
2174          {
2175             uint row;
2176
2177             glPixelStorei(GL_PACK_ALIGNMENT, 4);
2178 #if ENABLE_GL_LEGACY
2179             glPixelStorei(GL_PACK_ROW_LENGTH, bitmap.stride);
2180             glPixelStorei(GL_PACK_SKIP_ROWS, 0);
2181             glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
2182 #endif
2183             glReadPixels(x,display.height-h-y,w,h,GL_BGRA_EXT,GL_UNSIGNED_BYTE, flippingBuffer);
2184
2185             // Need a flip...
2186             for(row = 0; row<h; row++)
2187                CopyBytesBy4(((ColorAlpha *)bitmap.picture) + row * w, ((ColorAlpha *)flippingBuffer) + (h-row-1) * w, w);
2188             result = true;
2189          }
2190       }
2191       return result;
2192    }
2193
2194    void SetForeground(Display display, Surface surface, ColorAlpha color)
2195    {
2196       OGLSurface oglSurface = surface.driverData;
2197
2198       oglSurface.foreground[0] = color.color.r/255.0f;
2199       oglSurface.foreground[1] = color.color.g/255.0f;
2200       oglSurface.foreground[2] = color.color.b/255.0f;
2201       //oglSurface.foreground[3] = 1.0f;
2202       oglSurface.foreground[3] = color.a/255.0f;
2203
2204       //if(!oglSurface.foreground[3])printf("bug");
2205    }
2206
2207    void SetBackground(Display display, Surface surface, ColorAlpha color)
2208    {
2209       OGLSurface oglSurface = surface.driverData;
2210
2211       oglSurface.background[0] = color.color.r/255.0f;
2212       oglSurface.background[1] = color.color.g/255.0f;
2213       oglSurface.background[2] = color.color.b/255.0f;
2214       //oglSurface.background[3] = 1.0;
2215       oglSurface.background[3] = color.a/255.0f;
2216    }
2217
2218    void SetBlitTint(Display display, Surface surface, ColorAlpha color)
2219    {
2220       OGLSurface oglSurface = surface.driverData;
2221
2222       oglSurface.bitmapMult[0] = color.color.r/255.0f;
2223       oglSurface.bitmapMult[1] = color.color.g/255.0f;
2224       oglSurface.bitmapMult[2] = color.color.b/255.0f;
2225       oglSurface.bitmapMult[3] = color.a/255.0f;
2226    }
2227
2228    ColorAlpha GetPixel(Display display, Surface surface,int x,int y)
2229    {
2230       return 0;
2231    }
2232
2233    void PutPixel(Display display, Surface surface,int x,int y)
2234    {
2235       OGLSurface oglSurface = surface.driverData;
2236       GLColor4fv(oglSurface.foreground);
2237       GLBegin(GL_POINTS);
2238       // glVertex2i(x+surface.offset.x, y+surface.offset.y);
2239       GLVertex2f(x+surface.offset.x + 0.5f, y+surface.offset.y + 0.5f);
2240       GLEnd();
2241    }
2242
2243    void DrawLine(Display display, Surface surface, int _x1, int _y1, int _x2, int _y2)
2244    {
2245       OGLSurface oglSurface = surface.driverData;
2246       float x1 = _x1, x2 = _x2, y1 = _y1, y2 = _y2;
2247       if(_x1 == _x2)
2248       {
2249          if(_y2 >= _y1)
2250             y2 += 1;
2251          else
2252             y1 += 1;
2253       }
2254       else if(_y1 == _y2)
2255       {
2256          if(_x2 >= _x1)
2257             x2 += 1;
2258          else
2259             x1 += 1;
2260       }
2261       x1 += surface.offset.x;
2262       y1 += surface.offset.y;
2263       x2 += surface.offset.x;
2264       y2 += surface.offset.y;
2265
2266       GLColor4fv(oglSurface.foreground);
2267       GLBegin(GL_LINES);
2268       if(stippleEnabled)
2269       {
2270          GLTexCoord2f(0.5f, 0);
2271          GLVertex2f(x1 + 0.5f, y1 + 0.5f);
2272          GLTexCoord2f(Max(x2-x1, y2-y1) + 0.5f, 0);
2273          GLVertex2f(x2 + 0.5f, y2 + 0.5f);
2274       }
2275       else
2276       {
2277          /*
2278          GLVertex2i(x1, y1);
2279          GLVertex2i(x2, y2);
2280          */
2281          GLVertex2f(x1 + 0.5f, y1 + 0.5f);
2282          GLVertex2f(x2 + 0.5f, y2 + 0.5f);
2283       }
2284
2285       GLEnd();
2286    }
2287
2288    void Rectangle(Display display, Surface surface,int x1,int y1,int x2,int y2)
2289    {
2290       OGLSurface oglSurface = surface.driverData;
2291       x1 += surface.offset.x;
2292       y1 += surface.offset.y;
2293       x2 += surface.offset.x;
2294       y2 += surface.offset.y;
2295
2296       GLColor4fv(oglSurface.foreground);
2297       if(stippleEnabled)
2298       {
2299          GLBegin(GL_LINES);
2300
2301          GLTexCoord2f(0.5f, 0);
2302          GLVertex2f(x1 + 0.5f, y1 + 0.5f);
2303          GLTexCoord2f(y2-y1 + 0.5f, 0);
2304          GLVertex2f(x1 + 0.5f, y2 + 0.5f);
2305
2306          GLTexCoord2f(0.5f, 0);
2307          GLVertex2f(x1 + 0.5f, y2 + 0.5f);
2308          GLTexCoord2f(x2 - x1 + 0.5f, 0);
2309          GLVertex2f(x2 + 0.5f, y2 + 0.5f);
2310
2311          GLTexCoord2f(0.5f, 0);
2312          GLVertex2f(x2 + 0.5f, y2 + 0.5f);
2313          GLTexCoord2f(y1 - y2 + 0.5f, 0);
2314          GLVertex2f(x2 + 0.5f, y1 + 0.5f);
2315
2316          GLTexCoord2f(0.5f, 0);
2317          GLVertex2f(x2 + 0.5f, y1 + 0.5f);
2318          GLTexCoord2f(x1 - x2 + 0.5f, 0);
2319          GLVertex2f(x1 + 0.5f, y1 + 0.5f);
2320       }
2321       else
2322       {
2323          GLBegin(GL_LINE_LOOP);
2324          /*
2325          glVertex2i(x1, y1);
2326          glVertex2i(x1, y2);
2327          glVertex2i(x2, y2);
2328          glVertex2i(x2, y1);
2329          */
2330          GLVertex2f(x1 + 0.5f, y1 + 0.5f);
2331          GLVertex2f(x1 + 0.5f, y2 + 0.5f);
2332          GLVertex2f(x2 + 0.5f, y2 + 0.5f);
2333          GLVertex2f(x2 + 0.5f, y1 + 0.5f);
2334       }
2335       GLEnd();
2336    }
2337
2338    void Area(Display display, Surface surface,int x1,int y1,int x2,int y2)
2339    {
2340       OGLSurface oglSurface = surface.driverData;
2341
2342       GLColor4fv(oglSurface.background);
2343
2344       GLRecti(x1+surface.offset.x, y1+surface.offset.y,
2345               x2+surface.offset.x + 1, y2+surface.offset.y + 1);
2346       /*
2347       GLRectf(x1+surface.offset.x, y1+surface.offset.y,
2348               x2+surface.offset.x + 1, y2+surface.offset.y + 1);
2349       */
2350    }
2351
2352    void Clear(Display display, Surface surface, ClearType type)
2353    {
2354       OGLDisplay oglDisplay = display.driverData;
2355       OGLSurface oglSurface = surface.driverData;
2356
2357       //Logf("Clear\n");
2358       if(type != depthBuffer)
2359          glClearColor(oglSurface.background[0], oglSurface.background[1], oglSurface.background[2], oglSurface.background[3]);
2360       if(type != colorBuffer && !oglDisplay.depthWrite)
2361       {
2362          glDepthMask((byte)bool::true);
2363       }
2364       glClear(((type != depthBuffer) ? GL_COLOR_BUFFER_BIT : 0) |
2365               ((type != colorBuffer) ? GL_DEPTH_BUFFER_BIT : 0));
2366       if(type != colorBuffer && !oglDisplay.depthWrite)
2367       {
2368          glDepthMask((byte)bool::false);
2369       }
2370    }
2371
2372    bool ConvertBitmap(DisplaySystem displaySystem, Bitmap bitmap, PixelFormat format, ColorAlpha * palette)
2373    {
2374       return true;
2375    }
2376
2377    void Blit(Display display, Surface surface, Bitmap bitmap, int dx, int dy, int sx, int sy, int w, int h)
2378    {
2379       OGLSurface oglSurface = surface.driverData;
2380       GLuint tex = (GLuint)(uintptr)bitmap.driverData;
2381       if(!tex) return;
2382
2383       if(!oglSurface.writingText)
2384       {
2385          // glTranslatef(-0.375f, -0.375f, 0.0f);
2386          GLSetupTexturing(true);
2387          GLColor4fv(oglSurface.bitmapMult);
2388          glBindTexture(GL_TEXTURE_2D, tex);
2389          GLBegin(GLIMTKMode::quads);
2390       }
2391       else if(lastBlitTex != tex)
2392       {
2393          if(lastBlitTex)
2394             GLEnd();
2395          glBindTexture(GL_TEXTURE_2D, tex);
2396          GLBegin(GLIMTKMode::quads);
2397          lastBlitTex = tex;
2398       }
2399
2400       if(h < 0)
2401       {
2402          GLTexCoord2f((float)sx/ bitmap.width, (float)(sy-h)/ bitmap.height);
2403          GLVertex2i(dx+surface.offset.x, dy+surface.offset.y);
2404          GLTexCoord2f((float)(sx+w) / bitmap.width, (float)(sy-h)/ bitmap.height);
2405          GLVertex2i(dx+w+surface.offset.x, dy+surface.offset.y);
2406          GLTexCoord2f((float)(sx+w)/ bitmap.width, (float)sy/ bitmap.height);
2407          GLVertex2i(dx+w+surface.offset.x, dy-h+surface.offset.y);
2408          GLTexCoord2f((float)sx / bitmap.width, (float)sy/ bitmap.height);
2409          GLVertex2i(dx+surface.offset.x, dy-h+surface.offset.y);
2410       }
2411       else
2412       {
2413          /*
2414          GLTexCoord2f((float)sx / bitmap.width, (float)sy/ bitmap.height);
2415          GLVertex2i(dx+surface.offset.x, dy+surface.offset.y);
2416          GLTexCoord2f((float)(sx+w)/ bitmap.width, (float)sy/ bitmap.height);
2417          GLVertex2i(dx+w+surface.offset.x, dy+surface.offset.y);
2418          GLTexCoord2f((float)(sx+w) / bitmap.width, (float)(sy+h)/ bitmap.height);
2419          GLVertex2i(dx+w+surface.offset.x, dy+h+surface.offset.y);
2420          GLTexCoord2f((float)sx/ bitmap.width, (float)(sy+h)/ bitmap.height);
2421          GLVertex2i(dx+surface.offset.x, dy+h+surface.offset.y);
2422          */
2423
2424          GLTexCoord2f((float)sx / bitmap.width, (float)sy/ bitmap.height);
2425          GLVertex2f((float)dx+surface.offset.x, (float)dy+surface.offset.y);
2426          GLTexCoord2f((float)(sx+w)/ bitmap.width, (float)sy/ bitmap.height);
2427          GLVertex2f((float)dx+w+surface.offset.x, (float)dy+surface.offset.y);
2428          GLTexCoord2f((float)(sx+w) / bitmap.width, (float)(sy+h)/ bitmap.height);
2429          GLVertex2f((float)dx+w+surface.offset.x, (float)dy+h+surface.offset.y);
2430          GLTexCoord2f((float)sx/ bitmap.width, (float)(sy+h)/ bitmap.height);
2431          GLVertex2f((float)dx+surface.offset.x, (float)dy+h+surface.offset.y);
2432       }
2433       if(!oglSurface.writingText)
2434       {
2435          GLEnd();
2436          GLSetupTexturing(false);
2437          //glTranslate(0.375, 0.375, 0.0);
2438       }
2439    }
2440
2441    void Stretch(Display display, Surface surface, Bitmap bitmap, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
2442    {
2443       OGLSurface oglSurface = surface.driverData;
2444
2445       //glTranslate(-0.375, -0.375, 0.0);
2446
2447       GLSetupTexturing(true);
2448       glBindTexture(GL_TEXTURE_2D, (GLuint)(uintptr)bitmap.driverData);
2449
2450       GLColor4fv(oglSurface.bitmapMult);
2451
2452       GLBegin(GLIMTKMode::quads);
2453
2454       if(h < 0)
2455       {
2456          GLTexCoord2f((float)(sx)/ bitmap.width, (float)(sy+sh)/ bitmap.height);
2457          GLVertex2i(dx+surface.offset.x, dy+surface.offset.y);
2458
2459          GLTexCoord2f((float)(sx+sw) / bitmap.width, (float)(sy+sh)/ bitmap.height);
2460          GLVertex2i(dx+w+surface.offset.x, dy+surface.offset.y);
2461
2462          GLTexCoord2f((float)(sx+sw)/ bitmap.width, (float)(sy)/ bitmap.height);
2463          GLVertex2i(dx+w+surface.offset.x, dy-h+surface.offset.y);
2464
2465          GLTexCoord2f((float)(sx) / bitmap.width, (float)(sy)/ bitmap.height);
2466          GLVertex2i(dx+surface.offset.x, dy-h+surface.offset.y);
2467       }
2468       else
2469       {
2470          GLTexCoord2f((float)(sx) / bitmap.width, (float)(sy)/ bitmap.height);
2471          GLVertex2i(dx+surface.offset.x, dy+surface.offset.y);
2472
2473          GLTexCoord2f((float)(sx+sw)/ bitmap.width, (float)(sy)/ bitmap.height);
2474          GLVertex2i(dx+w+surface.offset.x, dy+surface.offset.y);
2475
2476          GLTexCoord2f((float)(sx+sw) / bitmap.width, (float)(sy+sh)/ bitmap.height);
2477          GLVertex2i(dx+w+surface.offset.x, dy+h+surface.offset.y);
2478
2479          GLTexCoord2f((float)(sx)/ bitmap.width, (float)(sy+sh)/ bitmap.height);
2480          GLVertex2i(dx+surface.offset.x, dy+h+surface.offset.y);
2481       }
2482
2483       GLEnd();
2484
2485       GLSetupTexturing(false);
2486
2487       //glTranslate(0.375, 0.375, 0.0);
2488    }
2489
2490    void Filter(Display display, Surface surface, Bitmap bitmap, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
2491    {
2492       Stretch(display, surface, bitmap, dx, dy, sx, sy, w, h, sw, sh);
2493    }
2494
2495    void StretchDI(Display display, Surface surface, Bitmap bitmap, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
2496    {
2497       float s2dw,s2dh,d2sw,d2sh;
2498       //bool flipX = false, flipY = false;
2499
2500       if(Sgn(w) != Sgn(sw))
2501       {
2502          w = Abs(w);
2503          sw = Abs(sw);
2504          //flipX = true;
2505       }
2506       if(Sgn(h) != Sgn(sh))
2507       {
2508          h = Abs(h);
2509          sh = Abs(sh);
2510          //flipY = true;
2511       }
2512
2513       s2dw=(float)w / sw;
2514       s2dh=(float)h / sh;
2515       d2sw=(float)sw / w;
2516       d2sh=(float)sh / h;
2517
2518       //Clip against the edges of the source
2519       if(sx<0)
2520       {
2521          dx+=(int)((0-sx) * s2dw);
2522          w-=(int)((0-sx) * s2dw);
2523          sw-=0-sx;
2524          sx=0;
2525       }
2526       if(sy<0)
2527       {
2528          dy+=(int)((0-sy) * s2dh);
2529          h-=(int)((0-sy) * s2dh);
2530
2531          sh-=0-sy;
2532          sy=0;
2533       }
2534       if(sx+sw>bitmap.width-1)
2535       {
2536          w-=(int)((sx+sw-(bitmap.width-1)-1)*s2dw);
2537          sw-=sx+sw-(bitmap.width-1)-1;
2538       }
2539       if(sy+sh>(bitmap.height-1))
2540       {
2541          h-=(int)((sy+sh-(bitmap.height-1)-1)*s2dh);
2542          sh-=sy+sh-(bitmap.height-1)-1;
2543       }
2544       //Clip against the edges of the surfaceination
2545       if(dx<surface.box.left)
2546       {
2547          //if(!flip)
2548          sx+=(int)((surface.box.left-dx)*d2sw);
2549          sw-=(int)((surface.box.left-dx)*d2sw);
2550          w-=surface.box.left-dx;
2551          dx=surface.box.left;
2552       }
2553       if(dy<surface.box.top)
2554       {
2555          sy+=(int)((surface.box.top-dy)*d2sh);
2556          sh-=(int)((surface.box.top-dy)*d2sh);
2557          h-=surface.box.top-dy;
2558          dy=surface.box.top;
2559       }
2560       if(dx+w>surface.box.right)
2561       {
2562          //if(flip) sx+=(int)((dx+w-surface.box.right-1)*d2sw);
2563          sw-=(int)((dx+w-surface.box.right-1)*d2sw);
2564          w-=dx+w-surface.box.right-1;
2565       }
2566       if(dy+h>surface.box.bottom)
2567       {
2568          sh-=(int)((dy+h-surface.box.bottom-1)*d2sh);
2569          h-=dy+h-surface.box.bottom-1;
2570       }
2571       if((w<=0)||(h<=0)||(sw<=0)||(sh<=0)) return;
2572
2573       dx += surface.offset.x;
2574       dy += surface.offset.y;
2575
2576       if(bitmap.pixelFormat == pixelFormat888 && !bitmap.paletteShades)
2577       {
2578          glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
2579 #if ENABLE_GL_LEGACY
2580          if(glCaps_legacy)
2581          {
2582             glPixelStorei(GL_UNPACK_ROW_LENGTH, bitmap.stride);
2583             glPixelStorei(GL_UNPACK_SKIP_PIXELS, sx);
2584             glPixelStorei(GL_UNPACK_SKIP_ROWS, sy);
2585             glRasterPos2d(dx,dy);
2586             //glPixelZoom(flipX ? -s2dw : s2dw, flipY ? s2dh : -s2dh);
2587             glPixelZoom(s2dw, -s2dh);
2588             glDrawPixels(sw,sh,GL_BGRA_EXT,GL_UNSIGNED_BYTE, bitmap.picture);
2589             glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
2590             glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
2591             glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
2592          }
2593 #endif
2594          glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
2595       }
2596    }
2597
2598    void BlitDI(Display display, Surface surface, Bitmap bitmap, int dx, int dy, int sx, int sy, int w, int h)
2599    {
2600       //Clip against the edges of the source
2601       if(sx<0)
2602       {
2603          dx+=-sx;
2604          w-=-sx;
2605          sx=0;
2606       }
2607       if(sy<0)
2608       {
2609          dy+=0-sy;
2610          h-=0-sy;
2611          sy=0;
2612       }
2613       if(sx+w>bitmap.width-1)
2614          w-=sx+w-(bitmap.width-1)-1;
2615       if(sy+h>bitmap.height-1)
2616          h-=sy+h-(bitmap.height-1)-1;
2617       //Clip against the edges of the surfaceination
2618       if(dx<surface.box.left)
2619       {
2620          //if(!flip)
2621          sx+=surface.box.left-dx;
2622          w-=surface.box.left-dx;
2623          dx=surface.box.left;
2624       }
2625       if(dy<surface.box.top)
2626       {
2627          sy+=surface.box.top-dy;
2628          h-=surface.box.top-dy;
2629          dy=surface.box.top;
2630       }
2631       if(dx+w>surface.box.right)
2632       {
2633          //if(flip) sx+=dx+w-surface.box.right-1;
2634          w-=dx+w-surface.box.right-1;
2635       }
2636       if(dy+h>surface.box.bottom)
2637          h-=dy+h-surface.box.bottom-1;
2638       if((w<=0)||(h<=0))
2639          return;
2640
2641       dx += surface.offset.x;
2642       dy += surface.offset.y;
2643
2644       if(bitmap.pixelFormat == pixelFormat888 && !bitmap.paletteShades)
2645       {
2646          glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
2647 #if ENABLE_GL_LEGACY
2648          if(glCaps_legacy)
2649          {
2650             glPixelStorei(GL_UNPACK_ROW_LENGTH, bitmap.stride);
2651             glPixelStorei(GL_UNPACK_SKIP_PIXELS, sx);
2652             glPixelStorei(GL_UNPACK_SKIP_ROWS, sy);
2653             glRasterPos2d(dx,dy);
2654             glPixelZoom(1,-1);
2655             glDrawPixels(w,h,GL_BGRA_EXT,GL_UNSIGNED_BYTE, bitmap.picture);
2656             glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
2657             glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
2658             glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
2659          }
2660 #endif
2661          glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
2662       }
2663    }
2664
2665    void FilterDI(Display display, Surface surface, Bitmap bitmap, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
2666    {
2667       StretchDI(display, surface, bitmap, dx, dy, sx, sy, w, h, sw, sh);
2668    }
2669
2670    void UnloadFont(DisplaySystem displaySystem, Font font)
2671    {
2672       ((subclass(DisplayDriver))class(LFBDisplayDriver)).UnloadFont(displaySystem, font);
2673    }
2674
2675    Font LoadFont(DisplaySystem displaySystem, const char * faceName, float size, FontFlags flags, float outlineSize, float outlineFade)
2676    {
2677       Font font;
2678       OGLSystem oglSystem = displaySystem.driverData;
2679       oglSystem.loadingFont = true;
2680       font = ((subclass(DisplayDriver))class(LFBDisplayDriver)).LoadFont(displaySystem, faceName, size, flags, outlineSize, outlineFade);
2681       return font;
2682    }
2683
2684    void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
2685    {
2686       ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height, prevGlyph, rPrevGlyph, adv);
2687    }
2688
2689    void WriteText(Display display, Surface surface, int x, int y, const char * text, int len, int prevGlyph, int * rPrevGlyph)
2690    {
2691       if(len && text[0] && surface.font)
2692       {
2693          OGLSurface oglSurface = surface.driverData;
2694          OGLSystem oglSystem = display.displaySystem.driverData;
2695          oglSystem.loadingFont = true;
2696
2697          //glTranslated(-0.375, -0.375, 0.0);
2698
2699          if(surface.textOpacity)
2700          {
2701             int w = 0, h, adv = 0;
2702             FontExtent(display.displaySystem, surface.font, text, len, &w, &h, 0, null, &adv);
2703             w += adv;
2704             display.displaySystem.driver.Area(display, surface,x,y,x+w-1,y+h-1);
2705          }
2706
2707          oglSurface.writingText = true;
2708
2709          GLSetupTexturing(true);
2710
2711          x <<= 6;
2712          if(surface.font.outlineSize)
2713          {
2714             ColorAlpha outlineColor = surface.outlineColor;
2715             int fx = x;
2716
2717             GLColor4ub(outlineColor.color.r, outlineColor.color.g, outlineColor.color.b, outlineColor.a);
2718             oglSurface.writingOutline = true;
2719             lastBlitTex = 0;
2720             oglSurface.font.ProcessString(surface.displaySystem, (const byte *)text, len, true, surface, display, &fx, y, prevGlyph, rPrevGlyph, null);
2721             if(lastBlitTex) GLEnd();
2722             oglSurface.writingOutline = false;
2723          }
2724          GLColor4fv(oglSurface.foreground);
2725
2726          lastBlitTex = 0;
2727          oglSurface.font.ProcessString(surface.displaySystem, (const byte *)text, len, true, surface, display, &x, y, prevGlyph, rPrevGlyph, null);
2728
2729          if(lastBlitTex) GLEnd();
2730          lastBlitTex = 0;
2731
2732          oglSurface.writingText = false;
2733          oglSystem.loadingFont = false;
2734
2735          GLSetupTexturing(false);
2736
2737          //glTranslated(0.375, 0.375, 0.0);
2738       }
2739    }
2740
2741    void TextFont(Display display, Surface surface, Font font)
2742    {
2743       ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextFont(display, surface, font);
2744    }
2745
2746    void TextOpacity(Display display, Surface surface, bool opaque)
2747    {
2748       OGLSurface oglSurface = surface.driverData;
2749       oglSurface.opaqueText = opaque;
2750    }
2751
2752    void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
2753    {
2754       OGLSurface oglSurface = surface.driverData;
2755       OGLSystem oglSystem = display.displaySystem.driverData;
2756       oglSystem.loadingFont = true;
2757       FontExtent(display.displaySystem, oglSurface.font, text, len, width, height, prevGlyph, rPrevGlyph, adv);
2758       oglSystem.loadingFont = false;
2759    }
2760
2761    void DrawingChar(Display display, Surface surface, char character)
2762    {
2763
2764    }
2765
2766    void LineStipple(Display display, Surface surface, uint32 stipple)
2767    {
2768       if(stipple)
2769       {
2770 #if ENABLE_GL_LEGACY
2771          if(glCaps_legacy)
2772          {
2773             glLineStipple(1, (uint16)stipple);
2774             glEnable(GL_LINE_STIPPLE);
2775          }
2776          else
2777 #endif
2778          {
2779             stippleEnabled = true;
2780             glsupLineStipple(1, (uint16)stipple);
2781          }
2782       }
2783       else
2784       {
2785 #if ENABLE_GL_LEGACY
2786          if(glCaps_legacy)
2787             glDisable(GL_LINE_STIPPLE);
2788          else
2789 #endif
2790          {
2791             stippleEnabled = false;
2792             GLMatrixMode(GL_TEXTURE);
2793             GLLoadIdentity();
2794             GLMatrixMode(MatrixMode::projection);
2795             GLSetupTexturing(false);   // TODO: Special shading code for stipple?
2796          }
2797       }
2798    }
2799 #if ENABLE_GL_FFP
2800    void ::disableRemainingTMUs(Display display, int lastTMU)
2801    {
2802       OGLDisplay oglDisplay = display.driverData;
2803       int t;
2804       for(t = lastTMU; t < oglDisplay.maxTMU; t++)
2805       {
2806          glActiveTexture(GL_TEXTURE0 + t);
2807          glClientActiveTexture(GL_TEXTURE0 + t);
2808          glDisable(GL_TEXTURE_2D);
2809          glDisable(GL_TEXTURE_CUBE_MAP);
2810          GLDisableClientState(TEXCOORDS);
2811       }
2812       glActiveTexture(GL_TEXTURE0);
2813       glClientActiveTexture(GL_TEXTURE0);
2814       oglDisplay.maxTMU = lastTMU;
2815    }
2816 #endif
2817
2818 #if !defined(ECERE_NO3D) && !defined(ECERE_VANILLA)
2819    void SetRenderState(Display display, RenderState state, uint value)
2820    {
2821       OGLDisplay oglDisplay = display.driverData;
2822       switch(state)
2823       {
2824          case antiAlias:
2825 #ifndef __EMSCRIPTEN__
2826             if(value)
2827                glEnable(GL_MULTISAMPLE);
2828             else
2829                glDisable(GL_MULTISAMPLE);
2830 #endif
2831             break;
2832          case fillMode:
2833 #if ENABLE_GL_LEGACY
2834             if(glCaps_legacy)
2835                glPolygonMode(GL_FRONT_AND_BACK, ((FillModeValue)value == solid) ? GL_FILL : GL_LINE);
2836 #endif
2837             break;
2838          case depthTest:
2839             if(value) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
2840             break;
2841          case depthWrite:
2842             if(value) glDepthMask((byte)bool::true); else glDepthMask((byte)bool::false);
2843             oglDisplay.depthWrite = (bool)value;
2844             break;
2845          case fogColor:
2846          {
2847             float color[4] = { ((Color)value).r/255.0f, ((Color)value).g/255.0f, ((Color)value).b/255.0f, 1.0f };
2848 #if ENABLE_GL_SHADERS
2849             if(glCaps_shaders)
2850                defaultShader.setFogColor(color[0], color[1], color[2]);
2851 #endif
2852
2853 #if ENABLE_GL_FFP
2854             if(!glCaps_shaders)
2855                glFogfv(GL_FOG_COLOR, (float *)&color);
2856 #endif
2857             break;
2858          }
2859          case fogDensity:
2860 #if ENABLE_GL_SHADERS
2861             if(glCaps_shaders)
2862                defaultShader.setFogDensity((float)(RenderStateFloat { ui = value }.f * nearPlane));
2863 #endif
2864
2865 #if ENABLE_GL_FFP
2866             if(!glCaps_shaders)
2867                glFogf(GL_FOG_DENSITY, (float)(RenderStateFloat { ui = value }.f * nearPlane));
2868 #endif
2869             break;
2870          case blend:
2871 //#if !defined(__EMSCRIPTEN__)
2872             if(value) glEnable(GL_BLEND); else glDisable(GL_BLEND);
2873 //#endif
2874             break;
2875          case ambient:
2876          {
2877 #if ENABLE_GL_SHADERS
2878             if(glCaps_shaders)
2879                defaultShader.setGlobalAmbient(((Color)value).r / 255.0f, ((Color)value).g / 255.0f, ((Color)value).b / 255.0f, 1.0f);
2880 #endif
2881
2882 #if ENABLE_GL_FFP
2883             if(!glCaps_shaders)
2884             {
2885                float ambient[4] = { ((Color)value).r/255.0f, ((Color)value).g/255.0f, ((Color)value).b/255.0f, 1.0f };
2886                glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
2887             }
2888 #endif
2889             break;
2890          }
2891          case alphaWrite:
2892          {
2893             if(value) glColorMask(1,1,1,1); else glColorMask(1,1,1,0);
2894             break;
2895          }
2896          case vSync:
2897          {
2898 #if defined(__WIN32__)
2899             if(wglSwapIntervalEXT)
2900                wglSwapIntervalEXT(value ? 1 : 0);
2901 #endif
2902             break;
2903          }
2904       }
2905    }
2906
2907    void SetLight(Display display, int id, Light light)
2908    {
2909 #if ENABLE_GL_SHADERS
2910       if(glCaps_shaders)
2911          defaultShader.setLight(display, id, light);
2912 #endif
2913
2914 #if ENABLE_GL_FFP
2915       if(!glCaps_shaders)
2916       {
2917          if(light != null && !light.flags.off)
2918          {
2919             Object lightObject = light.lightObject;
2920             float position[4] = { 0, 0, 0, 0 };
2921             float color[4] = { 0, 0, 0, 1 };
2922             Vector3D l;
2923
2924             glEnable(GL_LIGHT0 + id);
2925
2926             if(!light.multiplier) light.multiplier = 1.0f;
2927
2928             GLFlushMatrices();
2929
2930             color[0] = light.diffuse.r * light.multiplier;
2931             color[1] = light.diffuse.g * light.multiplier;
2932             color[2] = light.diffuse.b * light.multiplier;
2933             glLightfv(GL_LIGHT0 + id, GL_DIFFUSE, color);
2934
2935             color[0] = light.ambient.r * light.multiplier;
2936             color[1] = light.ambient.g * light.multiplier;
2937             color[2] = light.ambient.b * light.multiplier;
2938             glLightfv(GL_LIGHT0 + id, GL_AMBIENT, color);
2939
2940             color[0] = light.specular.r * light.multiplier;
2941             color[1] = light.specular.g * light.multiplier;
2942             color[2] = light.specular.b * light.multiplier;
2943             glLightfv(GL_LIGHT0 + id, GL_SPECULAR,color);
2944
2945             if(lightObject)
2946             {
2947                // Positional Lights, including Spot Lights (and omni light with flags.spot not set)
2948                Matrix * mat = &lightObject.matrix;
2949                l = { mat->m[3][0], mat->m[3][1], mat->m[3][2] };
2950                if(display.display3D && display.display3D.camera)
2951                   l.Subtract(l, display.display3D.camera.cPosition);
2952
2953                position[0] = (float)l.x, position[1] = (float)l.y, position[2] = (float)l.z, position[3] = 1;
2954
2955                if(light.flags.attenuation)
2956                {
2957                   glLightf(GL_LIGHT0 + id, GL_CONSTANT_ATTENUATION, light.Kc);
2958                   glLightf(GL_LIGHT0 + id, GL_LINEAR_ATTENUATION, light.Kl);
2959                   glLightf(GL_LIGHT0 + id, GL_QUADRATIC_ATTENUATION, light.Kq);
2960                }
2961                else
2962                {
2963                   glLightf(GL_LIGHT0 + id, GL_CONSTANT_ATTENUATION, 1);
2964                   glLightf(GL_LIGHT0 + id, GL_LINEAR_ATTENUATION, 0);
2965                   glLightf(GL_LIGHT0 + id, GL_QUADRATIC_ATTENUATION, 0);
2966                }
2967
2968                if((light.flags.spot && light.fallOff < 360) || (lightObject && (light.direction.x || light.direction.y || light.direction.z)))
2969                {
2970                   // Figure out exponent out of the hot spot
2971                   #define MAXLIGHT  0.9
2972                   float exponent = light.flags.spot ? (float)(log(MAXLIGHT) / log(cos(light.hotSpot / 2))) : 1;
2973                   Degrees cutOff = light.flags.spot ? light.fallOff/2 : 90;
2974                   float direction[4] = { (float)light.direction.x, (float)light.direction.y, (float)light.direction.z, 1 };
2975
2976                   glLightfv(GL_LIGHT0 + id, GL_SPOT_DIRECTION, direction);
2977                   glLightf(GL_LIGHT0 + id, GL_SPOT_CUTOFF, (float)cutOff);
2978                   glLightf(GL_LIGHT0 + id, GL_SPOT_EXPONENT, exponent);
2979                }
2980                else
2981                {
2982                   float d[4] = { 0, 0, 1, 0 };
2983                   glLightfv(GL_LIGHT0 + id, GL_SPOT_DIRECTION, d);
2984                   glLightf(GL_LIGHT0 + id, GL_SPOT_CUTOFF, 180);
2985                   glLightf(GL_LIGHT0 + id, GL_SPOT_EXPONENT, 1);
2986                }
2987
2988                /*
2989                if(lightObject)
2990                {
2991                   // Display Light Position
2992                   glDisable(GL_LIGHTING);
2993                   glDisable(GL_DEPTH_TEST);
2994                   glColor3f(1,1,1);
2995                   glPointSize(10);
2996                   glBegin(GL_POINTS);
2997                   glVertex3fv(position);
2998                   glEnd();
2999                   glEnable(GL_DEPTH_TEST);
3000                   glEnable(GL_LIGHTING);
3001
3002
3003                   // Display Target
3004                   if(lightObject.flags.root || !lightObject.parent)
3005                   {
3006                      positionVector = light.target.transform.position;
3007                      positionVector.Subtract(positionVector, display.camera.cPosition);
3008                   }
3009                   else
3010                   {
3011                      positionVector.MultMatrix(light.target.transform.position,
3012                         lightObject.light.target.parent.matrix);
3013                      positionVector.Subtract(positionVector, display.camera.cPosition);
3014                   }
3015
3016                   position[0] = positionVector.x;
3017                   position[1] = positionVector.y;
3018                   position[2] = positionVector.z;
3019
3020                   glDisable(GL_LIGHTING);
3021                   glDisable(GL_DEPTH_TEST);
3022                   glColor3f(1,1,0);
3023                   glPointSize(10);
3024                   glBegin(GL_POINTS);
3025                   glVertex3fv(position);
3026                   glEnd();
3027                   glEnable(GL_DEPTH_TEST);
3028                   glEnable(GL_LIGHTING);
3029                }
3030                */
3031             }
3032             else
3033             {
3034                // Directional Light
3035                Vector3D vector { 0,0,-1 };
3036                Vector3D direction;
3037                Matrix mat;
3038                mat.RotationQuaternion(light.orientation);
3039                direction.MultMatrix(vector, mat);
3040                l.Normalize(direction);
3041                position[0] = (float)l.x, position[1] = (float)l.y, position[2] = (float)l.z, position[3] = 0;
3042             }
3043             glLightfv(GL_LIGHT0 + id, GL_POSITION, position);
3044             if(display.display3D)
3045             {
3046                Matrix m;
3047                Vector3Df v { position[0], position[1], position[2] };
3048                Vector3Df l;
3049                float * lp = display.display3D.light0Pos;
3050                if(display.display3D.camera)
3051                   m = display.display3D.camera.viewMatrix;
3052                else
3053                   m.Identity();
3054                l.MultMatrix(v, m);
3055                lp[0] = l.x;
3056                lp[1] =-l.y;
3057                lp[2] =-l.z;
3058                lp[3] = position[3];
3059             }
3060          }
3061          else
3062             glDisable(GL_LIGHT0 + id);
3063       }
3064 #endif
3065    }
3066
3067    void SetCamera(Display display, Surface surface, Camera camera)
3068    {
3069       OGLDisplay oglDisplay = display.driverData;
3070
3071       if(surface && camera)
3072       {
3073          int left = surface.box.left + surface.offset.x;
3074          int top = surface.box.top  + surface.offset.y;
3075          int right = surface.box.right + surface.offset.x;
3076          int bottom = surface.box.bottom + surface.offset.y;
3077          float origX = surface.offset.x + camera.origin.x;
3078          float origY = surface.offset.y + camera.origin.y;
3079          int x = left;
3080          int y = display.height - bottom - 1;
3081          int w = right - left + 1;
3082          int h = bottom - top + 1;
3083
3084          // *** ViewPort ***
3085          glViewport(x, y, w, h);
3086
3087          GLMatrixMode(MatrixMode::texture);
3088          if(!display.display3D.camera)
3089             GLPushMatrix();
3090          GLLoadIdentity();
3091
3092          // *** Projection Matrix ***
3093          GLMatrixMode(MatrixMode::projection);
3094          if(!display.display3D.camera)
3095             GLPushMatrix();
3096
3097          if(display.display3D.collectingHits)
3098          {
3099             float pickX = display.display3D.pickX + surface.offset.x;
3100             float pickY = display.height - (display.display3D.pickY + surface.offset.y) - 1;
3101             Matrix pickMatrix
3102             {
3103                {
3104                   w / display.display3D.pickWidth, 0, 0, 0,
3105                   0, h / display.display3D.pickHeight, 0, 0,
3106                   0, 0, 1, 0,
3107                   (w + 2.0f * (x - pickX)) / display.display3D.pickWidth,
3108                   (h + 2.0f * (y - pickY)) / display.display3D.pickHeight, 0, 1
3109                }
3110             };
3111             GLLoadMatrixd(pickMatrix.array);
3112          }
3113          else
3114             GLLoadIdentity();
3115          GLFrustum(
3116             (left   - origX) * camera.zMin / camera.focalX,
3117             (right  - origX) * camera.zMin / camera.focalX,
3118             (bottom - origY) * camera.zMin / camera.focalY,
3119             (top    - origY) * camera.zMin / camera.focalY,
3120             camera.zMin, camera.zMax);
3121
3122          glDisable(GL_BLEND);
3123
3124          // *** Z Inverted Identity Matrix ***
3125          GLMatrixMode(MatrixMode::modelView);
3126          if(!display.display3D.camera)
3127             GLPushMatrix();
3128
3129          GLLoadIdentity();
3130
3131          GLScaled(1.0/nearPlane, 1.0/nearPlane, -1.0/nearPlane);
3132
3133          // *** View Matrix ***
3134          GLMultMatrixd(camera.viewMatrix.array);
3135
3136 #if ENABLE_GL_SHADERS
3137          if(glCaps_shaders)
3138          {
3139             defaultShader.select();
3140             defaultShader.setCamera(camera);
3141          }
3142 #endif
3143
3144          // *** Lights ***
3145          // ...
3146
3147          glEnable(GL_DEPTH_TEST);
3148
3149          GLSetupLighting(true);
3150 #if ENABLE_GL_FFP
3151          if(!glCaps_shaders)
3152             glShadeModel(GL_SMOOTH);
3153 #endif
3154          glDepthMask((byte)bool::true);
3155          oglDisplay.depthWrite = true;
3156
3157 #ifndef __EMSCRIPTEN__
3158          glEnable(GL_MULTISAMPLE);
3159 #endif
3160       }
3161       else if(surface && display.display3D.camera)
3162       {
3163          nearPlane = 1;
3164          oglDisplay.depthWrite = false;
3165          glViewport(0,0,display.width,display.height);
3166
3167          glDisable(GL_CULL_FACE);
3168          glDisable(GL_DEPTH_TEST);
3169
3170          GLDisableClientState(COLORS);
3171 #if ENABLE_GL_SHADERS
3172          if(glCaps_shaders)
3173          {
3174             GLDisableClientState(TANGENTS1);
3175             GLDisableClientState(TANGENTS2);
3176          }
3177 #endif
3178          GLDisableClientState(NORMALS);
3179 #if ENABLE_GL_FFP
3180          if(!glCaps_shaders)
3181             GLDisableClientState(LIGHTVECTORS);
3182 #endif
3183
3184          // *** Restore 2D MODELVIEW Matrix ***
3185          GLMatrixMode(MatrixMode::modelView);
3186          GLPopMatrix();
3187
3188          // *** Restore 2D TEXTURE Matrix ***
3189          GLMatrixMode(MatrixMode::texture);
3190          GLPopMatrix();
3191
3192          // *** Restore 2D PROJECTION Matrix ***
3193          GLMatrixMode(MatrixMode::projection);
3194          GLPopMatrix();
3195
3196          // NOTE: We expect the 2D projection matrix to be the active one for GetSurface to call glOrtho()
3197
3198 #if ENABLE_GL_SHADERS
3199          if(glCaps_shaders)
3200             defaultShader.select();
3201 #endif
3202
3203 #if ENABLE_GL_FFP
3204          if(!glCaps_shaders)
3205          {
3206             disableRemainingTMUs(display, 0);
3207             glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
3208
3209             glDisable(GL_TEXTURE_CUBE_MAP);
3210          #if _GLES
3211             glDisable(GL_TEXTURE_GEN_STR);
3212          #else
3213             glDisable(GL_TEXTURE_GEN_R);
3214             glDisable(GL_TEXTURE_GEN_S);
3215             glDisable(GL_TEXTURE_GEN_T);
3216          #endif
3217          }
3218 #endif
3219
3220          GLSetupTexturing(false);
3221          GLSetupLighting(false);
3222          GLSetupFog(false);
3223
3224 #if ENABLE_GL_SHADERS
3225          if(glCaps_shaders)
3226          {
3227             defaultShader.setPerVertexColor(false);
3228             defaultShader.setMaterial(null, 0);
3229          }
3230 #endif
3231
3232 #if ENABLE_GL_FFP
3233          if(!glCaps_shaders)
3234             glShadeModel(GL_FLAT);
3235 #endif
3236          glEnable(GL_BLEND);
3237 #if !defined(__EMSCRIPTEN__)
3238          glDisable(GL_MULTISAMPLE);
3239 #endif
3240       }
3241    }
3242
3243    void ApplyMaterial(Display display, Material material, Mesh mesh)
3244    {
3245       Shader shader = material.shader ? material.shader : defaultShader;
3246       MaterialFlags flags = material.flags;
3247 #if ENABLE_GL_FFP
3248       static int lastSeparate = 0;
3249       int tmu = 0;
3250       bool normalMapped = false;
3251       OGLMesh oglMesh = mesh ? mesh.data : null;
3252 #endif
3253
3254 #if ENABLE_GL_SHADERS
3255       if(glCaps_shaders && shader)
3256          shader.select();
3257 #endif
3258
3259       // Basic Properties
3260       if(flags.doubleSided)
3261       {
3262 #if ENABLE_GL_FFP
3263          if(!glCaps_shaders)
3264             GLLightModeli(GL_LIGHT_MODEL_TWO_SIDE, !flags.singleSideLight);
3265 #endif
3266          glDisable(GL_CULL_FACE);
3267       }
3268       else
3269       {
3270 #if ENABLE_GL_FFP
3271          if(!glCaps_shaders)
3272             GLLightModeli(GL_LIGHT_MODEL_TWO_SIDE, bool::false);
3273 #endif
3274          glEnable(GL_CULL_FACE);
3275       }
3276
3277       // Fog
3278       GLSetupFog(!flags.noFog);
3279
3280 #if ENABLE_GL_SHADERS
3281       if(glCaps_shaders)
3282          activeShader.setMaterial(material, mesh.flags);
3283 #endif
3284
3285 #if ENABLE_GL_FFP
3286       if(!glCaps_shaders)
3287       {
3288          if(material.bumpMap && mesh.lightVectors)
3289          {
3290             float color[4] = { 1,1,1,1 };
3291             glActiveTexture(GL_TEXTURE0 + tmu);
3292             glClientActiveTexture(GL_TEXTURE0 + tmu++);
3293             glBindTexture(GL_TEXTURE_2D, (GLuint)(uintptr)material.bumpMap.driverData);
3294             glDisable(GL_TEXTURE_CUBE_MAP);
3295             glEnable(GL_TEXTURE_2D);
3296
3297             glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
3298             glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB);
3299             glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
3300             glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR);
3301             glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
3302             glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE);
3303             glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
3304
3305             if(0) //((DefaultShaderBits)defaultShader.state).debugging)
3306             {
3307                glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
3308                glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR);
3309                glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_CONSTANT);
3310                glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR);
3311                glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color );
3312             }
3313
3314          #if _GLES
3315             glDisable(GL_TEXTURE_GEN_STR);
3316          #else
3317             glDisable(GL_TEXTURE_GEN_R);
3318             glDisable(GL_TEXTURE_GEN_S);
3319             glDisable(GL_TEXTURE_GEN_T);
3320          #endif
3321             glDisable(GL_LIGHTING);
3322             lightingEnabled = false;
3323
3324             GLMatrixMode(GL_TEXTURE);
3325             GLLoadIdentity();
3326             if(material.uScale && material.vScale)
3327                GLScalef(material.uScale, material.vScale, 1);
3328             GLMatrixMode(MatrixMode::modelView);
3329
3330             if(flags.tile)
3331             {
3332                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
3333                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
3334             }
3335             else
3336             {
3337                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
3338                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
3339             }
3340
3341             glActiveTexture(GL_TEXTURE0 + tmu);
3342             glClientActiveTexture(GL_TEXTURE0 + tmu);
3343
3344             normalMapped = true;
3345
3346             // Modulate base color
3347             if(material.diffuse.r < 1 || material.diffuse.g < 1 || material.diffuse.b < 1)
3348             {
3349                tmu++;
3350                glDisable(GL_TEXTURE_CUBE_MAP);
3351                glEnable(GL_TEXTURE_2D);
3352                glBindTexture(GL_TEXTURE_2D, (GLuint)(uintptr)material.bumpMap.driverData);
3353                glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
3354                glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
3355                glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
3356
3357                glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
3358                glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
3359                glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
3360                glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
3361
3362                glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
3363                glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT);
3364                glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
3365                glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
3366
3367                color[0] = material.diffuse.r, color[1] = material.diffuse.g, color[2] = material.diffuse.b, color[3] = 1.0;
3368                glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color );
3369                glActiveTexture(GL_TEXTURE0 + tmu);
3370                glClientActiveTexture(GL_TEXTURE0 + tmu);
3371             }
3372
3373             // Add ambient light
3374             {
3375                ColorRGB ambient { material.ambient.r * 0.2f, material.ambient.g * 0.2f, material.ambient.g * 0.2f };
3376                if(ambient.r > 0 || ambient.g > 0 || ambient.b > 0)
3377                {
3378                   tmu++;
3379                   glDisable(GL_TEXTURE_CUBE_MAP);
3380                   glEnable(GL_TEXTURE_2D);
3381                   glBindTexture(GL_TEXTURE_2D, (GLuint)(uintptr)material.bumpMap.driverData);
3382                   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
3383                   glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
3384                   glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
3385
3386                   glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
3387                   glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
3388                   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
3389                   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
3390
3391                   glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
3392                   glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT);
3393                   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
3394                   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
3395
3396                   color[0] = ambient.r, color[1] = ambient.g, color[2] = ambient.b, color[3] = 1.0;
3397                   glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color );
3398                   glActiveTexture(GL_TEXTURE0 + tmu);
3399                   glClientActiveTexture(GL_TEXTURE0 + tmu);
3400                }
3401             }
3402          }
3403          else
3404          {
3405             GLDisableClientState(LIGHTVECTORS);
3406             if(!lightingEnabled)
3407             {
3408                glEnable(GL_LIGHTING);
3409                lightingEnabled = true;
3410             }
3411          }
3412       }
3413 #endif
3414       // Maps
3415       if(flags.cubeMap || (material.baseMap && (mesh.texCoords || mesh.flags.texCoords1)))
3416       {
3417          Bitmap map = material.baseMap;
3418          int diffuseTarget = flags.cubeMap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
3419
3420 #if ENABLE_GL_FFP
3421          if(!glCaps_shaders)
3422          {
3423             glActiveTexture(GL_TEXTURE0 + tmu);
3424             glClientActiveTexture(GL_TEXTURE0 + tmu++);
3425             glEnable(diffuseTarget);
3426             glDisable(flags.cubeMap ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP);
3427          }
3428 #endif
3429
3430 #if ENABLE_GL_SHADERS
3431          if(glCaps_shaders && !flags.cubeMap)
3432             GLSetupTexturing(true);
3433 #endif
3434
3435          glBindTexture(diffuseTarget, (GLuint)(uintptr)map.driverData);
3436
3437 #if ENABLE_GL_FFP
3438          if(!glCaps_shaders)
3439          {
3440             glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
3441             /* // This did not have the desired effect with a GL_ALPHA texture
3442             glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
3443             glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
3444             glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
3445             glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
3446             glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE);
3447             glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
3448             glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE);
3449             glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
3450             glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
3451             glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
3452             glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
3453             */
3454
3455             if(flags.cubeMap)
3456             {
3457             #if _GLES
3458                glEnable(GL_TEXTURE_GEN_STR);
3459                // GL_OBJECT_LINEAR: No extension support?
3460                // glTexGeni(GL_TEXTURE_GEN_STR_OES, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
3461             #else
3462                GLfloat xPlane[] = { 1.0f, 0.0f, 0.0f, 0 };
3463                GLfloat yPlane[] = { 0.0f,-1.0f, 0.0f, 0 };
3464                GLfloat zPlane[] = { 0.0f, 0.0f,-1.0f, 0 };
3465                glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
3466                glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
3467                glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
3468                glTexGenfv(GL_R, GL_OBJECT_PLANE, zPlane);
3469                glTexGenfv(GL_S, GL_OBJECT_PLANE, xPlane);
3470                glTexGenfv(GL_T, GL_OBJECT_PLANE, yPlane);
3471
3472                glEnable(GL_TEXTURE_GEN_R);
3473                glEnable(GL_TEXTURE_GEN_S);
3474                glEnable(GL_TEXTURE_GEN_T);
3475             #endif
3476
3477                GLDisableClientState(TEXCOORDS);
3478             }
3479             else
3480             {
3481             #if _GLES
3482                glDisable(GL_TEXTURE_GEN_STR);
3483             #else
3484                glDisable(GL_TEXTURE_GEN_R);
3485                glDisable(GL_TEXTURE_GEN_S);
3486                glDisable(GL_TEXTURE_GEN_T);
3487             #endif
3488
3489                if(tmu > 1)
3490                   oglMesh.texCoords.use(texCoord, 2, GL_FLOAT, 0, oglMesh.texCoords.buffer ? null : mesh.texCoords);
3491                GLEnableClientState(TEXCOORDS);
3492             }
3493             glClientActiveTexture(GL_TEXTURE0);
3494          }
3495 #endif
3496          if(flags.tile)
3497          {
3498             glTexParameteri(diffuseTarget, GL_TEXTURE_WRAP_S, GL_REPEAT);
3499             glTexParameteri(diffuseTarget, GL_TEXTURE_WRAP_T, GL_REPEAT);
3500          }
3501          else
3502          {
3503             glTexParameteri(diffuseTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
3504             glTexParameteri(diffuseTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
3505          }
3506       }
3507       else
3508       {
3509          GLSetupTexturing(false);
3510       }
3511
3512 #if ENABLE_GL_FFP && !defined(_GLES)
3513       if(!glCaps_shaders)
3514       {
3515          int separate = material.flags.separateSpecular ? GL_SEPARATE_SPECULAR_COLOR : GL_SINGLE_COLOR;
3516          if(separate != lastSeparate)
3517          {
3518             GLLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, separate);
3519             lastSeparate = separate;
3520          }
3521       }
3522 #endif
3523
3524       if((flags.cubeMap && material.baseMap) ||
3525          (mesh.texCoords && (material.baseMap || material.bumpMap || material.specularMap || material.reflectMap)))
3526       {
3527 #if ENABLE_GL_FFP
3528          if(!glCaps_shaders)
3529          {
3530             glActiveTexture(GL_TEXTURE0 + tmu - 1);
3531             glClientActiveTexture(GL_TEXTURE0 + tmu - 1);
3532          }
3533 #endif
3534          GLMatrixMode(GL_TEXTURE);
3535          GLLoadIdentity();
3536          if(material.uScale && material.vScale)
3537             GLScalef(material.uScale, material.vScale, 1);
3538          GLMatrixMode(MatrixMode::modelView);
3539 #if ENABLE_GL_FFP
3540          if(!glCaps_shaders)
3541          {
3542             glActiveTexture(GL_TEXTURE0);
3543             glClientActiveTexture(GL_TEXTURE0);
3544          }
3545 #endif
3546       }
3547
3548 #if ENABLE_GL_FFP
3549       if(!glCaps_shaders)
3550       {
3551          if(material.envMap && material.refractiveIndex)
3552          {
3553             float color[4] = { material.opacity, material.opacity, material.opacity, 1.0 };
3554             glActiveTexture(GL_TEXTURE0 + tmu);
3555             glClientActiveTexture(GL_TEXTURE0 + tmu++);
3556             glBindTexture(GL_TEXTURE_CUBE_MAP, (GLuint)(uintptr)material.envMap.driverData);
3557             glEnable(GL_TEXTURE_CUBE_MAP);
3558          #if _GLES
3559             glEnable(GL_TEXTURE_GEN_STR);
3560             glTexGeni(GL_TEXTURE_GEN_STR_OES, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
3561          #else
3562             glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
3563             glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
3564             glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
3565             glEnable(GL_TEXTURE_GEN_R);
3566             glEnable(GL_TEXTURE_GEN_S);
3567             glEnable(GL_TEXTURE_GEN_T);
3568          #endif
3569
3570             glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
3571
3572             if(normalMapped)
3573                glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
3574             else
3575                glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
3576             glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
3577
3578             glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
3579             glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
3580
3581             glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE);
3582             glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE);
3583
3584             glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
3585             glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
3586
3587             glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
3588             glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
3589
3590             if(!normalMapped)
3591             {
3592                glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_CONSTANT);
3593                glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_ALPHA, GL_CONSTANT);
3594                glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR);
3595                glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA);
3596             }
3597
3598             glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color );
3599
3600             GLMatrixMode(MatrixMode::texture);
3601             {
3602                double * s = display.display3D.camera.viewMatrix.array;
3603                double k = 2.0;
3604                Matrix m
3605                { {
3606                   k*s[0],-k*s[4],-k*s[8], 0,
3607                   k*s[1],-k*s[5],-k*s[9], 0,
3608                   k*s[2],-k*s[6],-k*s[10],0,
3609                   0,0,0,1
3610                } };
3611                GLLoadMatrixd(m.array);
3612             }
3613             GLMatrixMode(MatrixMode::modelView);
3614          }
3615
3616          if(material.envMap && material.reflectivity)
3617          {
3618             float color[4] = { 1.0f - material.reflectivity, 1.0f - material.reflectivity, 1.0f - material.reflectivity, 1.0 };
3619             glActiveTexture(GL_TEXTURE0 + tmu);
3620             glClientActiveTexture(GL_TEXTURE0 + tmu++);
3621             glBindTexture(GL_TEXTURE_CUBE_MAP, (GLuint)(uintptr)material.envMap.driverData);
3622             glEnable(GL_TEXTURE_CUBE_MAP);
3623          #if _GLES
3624             glEnable(GL_TEXTURE_GEN_STR);
3625             glTexGeni(GL_TEXTURE_GEN_STR_OES, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
3626          #else
3627             glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
3628             glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
3629             glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
3630             glEnable(GL_TEXTURE_GEN_R);
3631             glEnable(GL_TEXTURE_GEN_S);
3632             glEnable(GL_TEXTURE_GEN_T);
3633          #endif
3634
3635             glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
3636
3637             if(normalMapped)
3638                glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
3639             else
3640                glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
3641             glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
3642
3643             glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
3644             glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
3645
3646             glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE);
3647             glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE);
3648             glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
3649             glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
3650             glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
3651             glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
3652
3653             if(!normalMapped)
3654             {
3655                glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_CONSTANT);
3656                glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_ALPHA, GL_CONSTANT);
3657                glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR);
3658                glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA);
3659             }
3660
3661             glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color );
3662
3663             GLMatrixMode(MatrixMode::texture);
3664             {
3665                double * s = display.display3D.camera.inverseTranspose.array;
3666                Matrix m
3667                { {
3668                   s[0],s[1],-s[2],0,
3669                   s[4],-s[5],-s[6],0,
3670                   -s[8],s[9],s[10],0,
3671                   0,0,0,1
3672                } };
3673                GLLoadMatrixd(m.array);
3674             }
3675             GLMatrixMode(MatrixMode::modelView);
3676          }
3677       }
3678 #endif
3679
3680 #if ENABLE_GL_FFP
3681       if(!glCaps_shaders)
3682       {
3683          disableRemainingTMUs(display, tmu);
3684
3685          if(mesh.flags.colors)
3686          {
3687             GLColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
3688             glEnable(GL_COLOR_MATERIAL);
3689          }
3690          else
3691          {
3692             glDisable(GL_COLOR_MATERIAL);
3693             {
3694                float color[4] = { material.diffuse.r, material.diffuse.g, material.diffuse.b, material.opacity };
3695                glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color);
3696             }
3697             {
3698                float color[4] = { material.ambient.r, material.ambient.g, material.ambient.b, 0 };
3699                glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color);
3700             }
3701          }
3702          if(material.power > 0.1)
3703          {
3704             float color[4] = { material.specular.r, material.specular.g, material.specular.b, 0 };
3705             glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color);
3706          }
3707          else
3708          {
3709             float color[4] = { 0,0,0,0 };
3710             glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color);
3711          }
3712          {
3713             float color[4] = { material.emissive.r, material.emissive.g, material.emissive.b, 0 };
3714             glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, color);
3715          }
3716          glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &material.power);
3717       }
3718 #endif
3719    }
3720
3721    void FreeMesh(DisplaySystem displaySystem, Mesh mesh)
3722    {
3723       OGLMesh oglMesh = mesh.data;
3724       if(oglMesh)
3725       {
3726          OGLSystem oglSystem = displaySystem.driverData;
3727          GLCapabilities caps = glCaps;
3728          SETCAPS(oglSystem.capabilities);
3729
3730          if(!mesh.flags.vertices)
3731          {
3732             oglMesh.vertices.free();
3733             delete mesh.vertices;
3734          }
3735          if(!mesh.flags.normals)
3736          {
3737             oglMesh.normals.free();
3738             delete mesh.normals;
3739          }
3740          if(!mesh.flags.tangents)
3741          {
3742             oglMesh.tangents.free();
3743             delete mesh.tangents;
3744          }
3745          if(!mesh.flags.lightVectors)
3746          {
3747             oglMesh.lightVectors.free();
3748             delete mesh.lightVectors;
3749          }
3750          if(!mesh.flags.texCoords1)
3751          {
3752             oglMesh.texCoords.free();
3753             delete mesh.texCoords;
3754          }
3755          if(!mesh.flags.texCoords2)
3756          {
3757             oglMesh.texCoords2.free();
3758             // delete mesh.texCoords2;
3759          }
3760          if(!mesh.flags.colors)
3761          {
3762             oglMesh.colors.free();
3763             delete mesh.colors;
3764          }
3765          if(!mesh.flags)
3766          {
3767             delete oglMesh;
3768             mesh.data = null;
3769          }
3770          SETCAPS(caps);
3771       }
3772    }
3773
3774    bool AllocateMesh(DisplaySystem displaySystem, Mesh mesh, MeshFeatures flags, int nVertices)
3775    {
3776       bool result = false;
3777
3778       if(!mesh.data)
3779          mesh.data = OGLMesh { };
3780       if(mesh.data)
3781       {
3782          if(mesh.nVertices == nVertices)
3783          {
3784             // Same number of vertices, adding features (Leaves the other features pointers alone)
3785             if(mesh.flags != flags)
3786             {
3787                if(!mesh.flags.vertices && flags.vertices)
3788                {
3789                   if(flags.doubleVertices)
3790                   {
3791                      mesh.vertices = (Vector3Df *)new Vector3D[nVertices];
3792                   }
3793                   else
3794                      mesh.vertices = new Vector3Df[nVertices];
3795                }
3796                if(!mesh.flags.normals && flags.normals)
3797                {
3798                   if(flags.doubleNormals)
3799                   {
3800                      mesh.normals = (Vector3Df *)new Vector3D[nVertices];
3801                   }
3802                   else
3803                      mesh.normals = new Vector3Df[nVertices];
3804                }
3805                if(!mesh.flags.tangents && flags.tangents)
3806                {
3807                   mesh.tangents = new Vector3Df[2*nVertices];
3808                }
3809                if(!mesh.flags.lightVectors && flags.lightVectors)
3810                {
3811                   mesh.lightVectors = new ColorRGB[nVertices];
3812                }
3813                if(!mesh.flags.texCoords1 && flags.texCoords1)
3814                {
3815                   mesh.texCoords = new Pointf[nVertices];
3816                }
3817                if(!mesh.flags.colors && flags.colors)
3818                {
3819                   mesh.colors = new ColorRGBAf[nVertices];
3820                }
3821             }
3822          }
3823          else
3824          {
3825             // New number of vertices, reallocate all current and new features
3826             flags |= mesh.flags;
3827             if(flags.vertices)
3828             {
3829                if(flags.doubleVertices)
3830                {
3831                   mesh.vertices = (Vector3Df *)renew mesh.vertices Vector3D[nVertices];
3832                }
3833                else
3834                   mesh.vertices = renew mesh.vertices Vector3Df[nVertices];
3835             }
3836             if(flags.normals)
3837             {
3838                if(flags.doubleNormals)
3839                {
3840                   mesh.normals = (Vector3Df *)renew mesh.normals Vector3D[nVertices];
3841                }
3842                else
3843                   mesh.normals = renew mesh.normals Vector3Df[nVertices];
3844             }
3845             if(flags.texCoords1)
3846             {
3847                mesh.texCoords = renew mesh.texCoords Pointf[nVertices];
3848             }
3849             if(flags.colors)
3850             {
3851                mesh.colors = renew mesh.colors ColorRGBAf[nVertices];
3852             }
3853             if(flags.tangents)
3854             {
3855                mesh.tangents = renew mesh.tangents Vector3Df[2 * nVertices];
3856             }
3857             if(flags.lightVectors)
3858             {
3859                mesh.lightVectors = renew mesh.lightVectors ColorRGB[nVertices];
3860             }
3861          }
3862          result = true;
3863       }
3864       return result;
3865    }
3866
3867    void UnlockMesh(DisplaySystem displaySystem, Mesh mesh, MeshFeatures flags)
3868    {
3869       OGLSystem oglSystem = displaySystem.driverData;
3870       GLCapabilities caps = glCaps;
3871       SETCAPS(oglSystem.capabilities);
3872
3873       if(glCaps_vertexBuffer)
3874       {
3875          OGLMesh oglMesh = mesh.data;
3876          if(!flags) flags = mesh.flags;
3877          if(flags.vertices)
3878             oglMesh.vertices.allocate(
3879                mesh.nVertices * (mesh.flags.doubleVertices ? sizeof(Vector3D) : sizeof(Vector3Df)), mesh.vertices, staticDraw);
3880
3881          if(flags.normals)
3882             oglMesh.normals.allocate(
3883                mesh.nVertices * (mesh.flags.doubleNormals ? sizeof(Vector3D) : sizeof(Vector3Df)), mesh.normals, staticDraw);
3884
3885          if(flags.texCoords1)
3886             oglMesh.texCoords.allocate(
3887                mesh.nVertices * sizeof(Pointf), mesh.texCoords, staticDraw);
3888
3889          if(flags.colors)
3890             oglMesh.colors.allocate(
3891                mesh.nVertices * sizeof(ColorRGBAf), mesh.colors, staticDraw);
3892
3893          if(flags.tangents)
3894             oglMesh.tangents.allocate(mesh.nVertices * 2*sizeof(Vector3Df), mesh.tangents, staticDraw);
3895
3896          if(flags.lightVectors)
3897             oglMesh.lightVectors.allocate(mesh.nVertices * sizeof(ColorRGB), mesh.lightVectors, staticDraw);
3898       }
3899       SETCAPS(caps);
3900    }
3901
3902    bool LockMesh(DisplaySystem displaySystem, Mesh mesh, MeshFeatures flags)
3903    {
3904       bool result = true;
3905
3906       return result;
3907    }
3908
3909    void FreeIndices(DisplaySystem displaySystem, OGLIndices oglIndices)
3910    {
3911       OGLSystem oglSystem = displaySystem.driverData;
3912       GLCapabilities caps = glCaps;
3913       SETCAPS(oglSystem.capabilities);
3914
3915       if(oglIndices)
3916       {
3917          oglIndices.buffer.free();
3918          delete oglIndices.indices;
3919          delete oglIndices;
3920       }
3921       SETCAPS(caps);
3922    }
3923
3924    void * AllocateIndices(DisplaySystem displaySystem, int nIndices, bool indices32bit)
3925    {
3926       OGLIndices oglIndices = OGLIndices { };
3927       if(oglIndices)
3928       {
3929          oglIndices.indices = (void *)(indices32bit ? new uint32[nIndices] : new uint16[nIndices]);
3930          oglIndices.nIndices = nIndices;
3931       }
3932       return oglIndices;
3933    }
3934
3935    void UnlockIndices(DisplaySystem displaySystem, OGLIndices oglIndices, bool indices32bit, int nIndices)
3936    {
3937       OGLSystem oglSystem = displaySystem.driverData;
3938       GLCapabilities caps = glCaps;
3939       SETCAPS(oglSystem.capabilities);
3940
3941       if(glCaps_vertexBuffer)
3942       {
3943          if(!glCaps_intAndDouble && indices32bit)
3944          {
3945             if(!oglIndices.buffer.buffer)
3946                glGenBuffers(1, &oglIndices.buffer.buffer);
3947             if(glabCurElementBuffer != oglIndices.buffer.buffer)
3948                GLABBindBuffer(GL_ELEMENT_ARRAY_BUFFER, oglIndices.buffer.buffer);
3949
3950             {
3951                uint * pointer = (uint *)oglIndices.indices;
3952                int i;
3953                uint16 * b;
3954                if(nIndices > oglSystem.shortBDSize)
3955                {
3956                   oglSystem.shortBDSize = nIndices;
3957                   oglSystem.shortBDBuffer = renew oglSystem.shortBDBuffer uint16[oglSystem.shortBDSize];
3958                }
3959                b = oglSystem.shortBDBuffer;
3960                for(i = 0; i < nIndices; i++)
3961                   b[i] = (uint16)pointer[i];
3962
3963                glBufferData(GL_ELEMENT_ARRAY_BUFFER, nIndices * sizeof(uint16), b, GL_STATIC_DRAW);
3964             }
3965          }
3966          else
3967             oglIndices.buffer.allocate(
3968                nIndices * (indices32bit ? sizeof(uint32) : sizeof(uint16)),
3969                oglIndices.indices, staticDraw);
3970       }
3971       SETCAPS(caps);
3972    }
3973
3974    uint16 * LockIndices(DisplaySystem displaySystem, OGLIndices oglIndices)
3975    {
3976
3977       return oglIndices.indices;
3978    }
3979
3980    void SelectMesh(Display display, Mesh mesh)
3981    {
3982 #if !defined( __ANDROID__) && !defined(__APPLE__) && !defined(__ODROID__) && !defined(__EMSCRIPTEN__)
3983 #if defined(__WIN32__)
3984       if(glUnlockArraysEXT)
3985 #endif
3986          if(!glCaps_vertexBuffer && display.display3D.mesh)
3987             glUnlockArraysEXT();
3988 #endif
3989       if(mesh)
3990       {
3991          OGLMesh oglMesh = mesh.data;
3992
3993          // *** Vertex Stream ***
3994          GLEnableClientState(VERTICES);
3995          if(!display.display3D.collectingHits && oglMesh)
3996          {
3997             oglMesh.vertices.use(vertex, 3, (mesh.flags.doubleVertices ? GL_DOUBLE : GL_FLOAT), 0, oglMesh.vertices.buffer ? null : (double *)mesh.vertices);
3998
3999             // *** Normals Stream ***
4000             if(mesh.normals || mesh.flags.normals)
4001             {
4002                GLEnableClientState(NORMALS);
4003                oglMesh.normals.use(normal, 3, GL_FLOAT, 0, oglMesh.normals.buffer ? null : mesh.normals);
4004             }
4005             else
4006                GLDisableClientState(NORMALS);
4007
4008 #if ENABLE_GL_SHADERS
4009             if(glCaps_shaders)
4010             {
4011                // *** Tangents Stream ***
4012                if(mesh.tangents || mesh.flags.tangents)
4013                {
4014                   GLEnableClientState(TANGENTS1);
4015                   GLEnableClientState(TANGENTS2);
4016                   oglMesh.tangents.use(tangent1, 3, GL_FLOAT, sizeof(Vector3Df)*2, oglMesh.tangents.buffer ? null : mesh.tangents);
4017                   oglMesh.tangents.use(tangent2, 3, GL_FLOAT, sizeof(Vector3Df)*2, oglMesh.tangents.buffer ? (void *)sizeof(Vector3Df) : mesh.tangents+1);
4018                }
4019                else
4020                {
4021                   GLDisableClientState(TANGENTS1);
4022                   GLDisableClientState(TANGENTS2);
4023                }
4024             }
4025 #endif
4026
4027             // *** Texture Coordinates Stream ***
4028             if(mesh.texCoords || mesh.flags.texCoords1)
4029             {
4030                GLEnableClientState(TEXCOORDS);
4031                oglMesh.texCoords.use(texCoord, 2, GL_FLOAT, 0, oglMesh.texCoords.buffer ? null : mesh.texCoords);
4032             }
4033             else
4034                GLDisableClientState(TEXCOORDS);
4035
4036 #if ENABLE_GL_FFP
4037             if(!glCaps_shaders)
4038             {
4039                // *** Normal Map Aligned Light Vector ***
4040                if(mesh.lightVectors || mesh.flags.lightVectors)
4041                {
4042                   GLEnableClientState(LIGHTVECTORS);
4043                   oglMesh.lightVectors.use(lightVector, 3, GL_FLOAT, 0, oglMesh.lightVectors.buffer ? null : mesh.lightVectors);
4044                }
4045                else
4046                   GLDisableClientState(LIGHTVECTORS);
4047             }
4048             else
4049 #endif
4050             // *** Color Stream ***
4051             if(mesh.colors || mesh.flags.colors)
4052             {
4053                GLEnableClientState(COLORS);
4054                oglMesh.colors.use(color, 4, GL_FLOAT, 0, oglMesh.colors.buffer ? null : mesh.colors);
4055             }
4056             else
4057                GLDisableClientState(COLORS);
4058          }
4059          else
4060          {
4061             noAB.use(vertex, 3, (mesh.flags.doubleVertices ? GL_DOUBLE : GL_FLOAT), 0, (double *)mesh.vertices);
4062             if((mesh.normals || mesh.flags.normals) && !display.display3D.collectingHits)
4063             {
4064                GLEnableClientState(NORMALS);
4065                noAB.use(normal, 3, GL_FLOAT, 0, mesh.normals);
4066             }
4067             else
4068                GLDisableClientState(NORMALS);
4069 #if ENABLE_GL_SHADERS
4070             if(glCaps_shaders)
4071             {
4072                if((mesh.tangents || mesh.flags.tangents) && !display.display3D.collectingHits)
4073                {
4074                   GLEnableClientState(TANGENTS1);
4075                   GLEnableClientState(TANGENTS2);
4076                   noAB.use(tangent1, 3, GL_FLOAT, sizeof(Vector3Df)*2, mesh.tangents);
4077                   noAB.use(tangent2, 3, GL_FLOAT, sizeof(Vector3Df)*2, mesh.tangents+1);
4078                }
4079                else
4080                {
4081                   GLDisableClientState(TANGENTS1);
4082                   GLDisableClientState(TANGENTS2);
4083                }
4084             }
4085 #endif
4086
4087             if((mesh.texCoords || mesh.flags.texCoords1) && !display.display3D.collectingHits)
4088             {
4089                GLEnableClientState(TEXCOORDS);
4090                noAB.use(texCoord, 2, GL_FLOAT, 0, mesh.texCoords);
4091             }
4092             else
4093                GLDisableClientState(TEXCOORDS);
4094
4095 #if ENABLE_GL_FFP
4096             if(!glCaps_shaders)
4097             {
4098                if((mesh.lightVectors || mesh.flags.lightVectors) && !display.display3D.collectingHits)
4099                {
4100                   GLEnableClientState(LIGHTVECTORS);
4101                   noAB.use(lightVector, 3, GL_FLOAT, sizeof(ColorRGB), mesh.lightVectors);
4102                }
4103                else
4104                   GLDisableClientState(LIGHTVECTORS);
4105             }
4106             else
4107 #endif
4108             if((mesh.colors || mesh.flags.colors) && !display.display3D.collectingHits)
4109             {
4110                GLEnableClientState(COLORS);
4111                noAB.use(color, 4, GL_FLOAT, 0, mesh.colors);
4112             }
4113             else
4114                GLDisableClientState(COLORS);
4115          }
4116
4117 #if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__ODROID__) && !defined(__EMSCRIPTEN__)
4118
4119 #if defined(__WIN32__)
4120          if(glLockArraysEXT)
4121 #endif
4122             if(!glCaps_vertexBuffer)
4123                glLockArraysEXT(0, mesh.nVertices);
4124 #endif
4125       }
4126    }
4127
4128    void DrawPrimitives(Display display, PrimitiveSingle * primitive, Mesh mesh)
4129    {
4130       if(primitive->type.vertexRange)
4131       {
4132          GLFlushMatrices();
4133          glDrawArrays(getPrimitiveType(primitive->type.primitiveType), primitive->first, primitive->nVertices);
4134       }
4135       else
4136       {
4137          OGLIndices oglIndices = primitive->data;
4138          GLEAB eab = ((!display.display3D.collectingHits && oglIndices && glCaps_vertexBuffer) ? oglIndices.buffer : noEAB);
4139          if(!glCaps_intAndDouble && !glCaps_vertexBuffer && primitive->type.indices32bit)
4140          {
4141             uint16 * temp = new uint16[primitive->nIndices];
4142             uint32 * src = (uint32 *)(oglIndices ? oglIndices.indices : primitive->indices);
4143             int i;
4144             for(i = 0; i < primitive->nIndices; i++)
4145                temp[i] = (uint16)src[i];
4146             eab.draw(getPrimitiveType(primitive->type.primitiveType), primitive->nIndices, GL_UNSIGNED_SHORT, temp);
4147             delete temp;
4148          }
4149          else
4150             eab.draw(getPrimitiveType(primitive->type.primitiveType), primitive->nIndices,
4151                primitive->type.indices32bit ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT,
4152                eab.buffer ? 0 : (oglIndices ? oglIndices.indices : primitive->indices));
4153          GLABBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
4154       }
4155    }
4156
4157    void PushMatrix(Display display)
4158    {
4159       GLPushMatrix();
4160    }
4161
4162    void PopMatrix(Display display, bool setMatrix)
4163    {
4164       GLPopMatrix();
4165    }
4166
4167    void SetTransform(Display display, Matrix transMatrix, bool viewSpace, bool useCamera)
4168    {
4169       Matrix matrix = transMatrix;
4170       Camera camera = useCamera ? display.display3D.camera : null;
4171
4172       if(viewSpace)
4173       {
4174          GLLoadIdentity();
4175          GLScaled(1.0/nearPlane, 1.0/nearPlane, -1.0/nearPlane);
4176       }
4177       else if(camera)
4178       {
4179          GLTranslated(
4180             matrix.m[3][0] - camera.cPosition.x,
4181             matrix.m[3][1] - camera.cPosition.y,
4182             matrix.m[3][2] - camera.cPosition.z);
4183       }
4184       else
4185          GLTranslated(
4186             matrix.m[3][0],
4187             matrix.m[3][1],
4188             matrix.m[3][2]);
4189
4190       matrix.m[3][0] = 0;
4191       matrix.m[3][1] = 0;
4192       matrix.m[3][2] = 0;
4193
4194       GLMultMatrixd(matrix.array);
4195    }
4196 #endif
4197 }
4198
4199 public void UseSingleGLContext(bool useSingle)
4200 {
4201    useSingleGLContext = useSingle;
4202 }
4203
4204 default dllexport void *
4205 #if defined(__WIN32__)
4206 __attribute__((stdcall))
4207 #endif
4208 IS_GLGetContext(DisplaySystem displaySystem)
4209 {
4210    if(displaySystem)
4211    {
4212 #if defined(__WIN32__)
4213       OGLSystem system = displaySystem.driverData;
4214       return system.glrc;
4215 #elif defined(__ANDROID__) || defined(__ODROID__)
4216       return eglContext;
4217 #elif defined(__EMSCRIPTEN__)
4218       OGLSystem system = displaySystem.driverData;
4219       return (void *)system.glc;
4220 #else
4221       OGLSystem system = displaySystem.driverData;
4222       return system.glContext;
4223 #endif
4224    }
4225    return null;
4226 }
4227
4228 #endif