1ff2c11b4fe2a0d9628d3db7b9ea79e705cdf53e
[sdk] / ecere / src / gfx / newFonts / drawManager.ec
1 import "OpenGLDisplayDriver"
2
3 #define _Noreturn
4
5 #include <stdio.h>
6 #include <math.h>
7 #include <stdlib.h>
8
9 #if !defined(_GLES)
10    #define SHADERS
11 #endif
12
13 #if defined(__EMSCRIPTEN__)
14 #if !defined(_GLES2)
15    #define _GLES2
16 #endif
17    #include <GLES2/gl2.h>
18 #endif
19
20 #if defined(__ANDROID__) || defined(__ODROID__)
21 #if !defined(_GLES)
22    #define _GLES
23 #endif
24    #include <GLES/gl.h>
25 #endif
26
27 #if !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) && !defined(__ODROID__)
28 #  if defined(SHADERS)
29 //#     include "gl_core_3_3.h"
30 #     include "gl_compat_4_4.h"     // FIXME: no glPushAttrib() in core profile
31 #  else
32 #     include "gl_compat_4_4.h"
33 #  endif
34 #endif
35
36 #ifdef SHADERS
37
38 #undef glEnableClientState
39 #undef glDisableClientState
40 #undef GL_VERTEX_ARRAY
41 #undef GL_NORMAL_ARRAY
42 #undef GL_TEXTURE_COORD_ARRAY
43 #undef GL_COLOR_ARRAY
44 #undef glVertexPointer
45 #undef glTexCoordPointer
46 #undef glColorPointer
47
48 #define glEnableClientState      glEnableVertexAttribArray
49 #define glDisableClientState     glDisableVertexAttribArray
50 #define GL_VERTEX_ARRAY          GLBufferContents::vertex
51 #define GL_NORMAL_ARRAY          GLBufferContents::normal
52 #define GL_TEXTURE_COORD_ARRAY   GLBufferContents::texCoord
53 #define GL_COLOR_ARRAY           GLBufferContents::color
54 #define glVertexPointer(n, t, s, p)    glVertexAttribPointer(GLBufferContents::vertex,   n, t, GL_FALSE, s, p)
55 #define glTexCoordPointer(n, t, s, p)  glVertexAttribPointer(GLBufferContents::texCoord, n, t, GL_FALSE, s, p)
56 #define glColorPointer(n, t, s, p)     glVertexAttribPointer(GLBufferContents::color,    n, t, GL_FALSE, s, p)
57
58 #endif
59
60 #if defined(_GLES) || defined(_GLES2) || defined(SHADERS)
61
62    #undef glRecti
63    #undef glBegin
64    #undef glTexCoord2i
65    #undef glVertex2i
66    #undef glTexCoord2d
67    #undef glVertex2d
68    #undef glTexCoord2f
69    #undef glVertex2f
70    #undef glEnd
71    #undef glColor3f
72    #undef glColor4ub
73    #undef glColor4fv
74    #undef glNormal3fv
75    #undef glNormal3f
76    #undef glTexCoord2fv
77    #undef glVertex3d
78    #undef glVertex3dv
79    #undef glVertex3f
80    #undef glVertex3fv
81
82    #undef glLoadMatrixd
83    #undef glLoadMatrixf
84    #undef glMultMatrixd
85    #undef glFrustum
86    #undef glOrtho
87    #undef glScaled
88    #undef glScalef
89    #undef glTranslated
90    #undef glRotated
91    #undef glMatrixMode
92    #undef glLoadIdentity
93    #undef glPushMatrix
94    #undef glPopMatrix
95
96    #undef glLineStipple
97    #undef glColorMaterial
98    #undef glLightModeli
99
100    #define glRecti               glimtkRecti
101    #define glBegin               glimtkBegin
102    #define glTexCoord2i          glimtkTexCoord2i
103    #define glVertex2i            glimtkVertex2i
104    #define glTexCoord2d          glimtkTexCoord2d
105    #define glVertex2d            glimtkVertex2d
106    #define glTexCoord2f          glimtkTexCoord2f
107    #define glVertex2f            glimtkVertex2f
108    #define glEnd                 glimtkEnd
109    #define glColor3f             glimtkColor3f
110    #define glColor4ub            glimtkColor4ub
111    #define glColor4fv            glimtkColor4fv
112    #define glNormal3fv           glimtkNormal3fv
113    #define glNormal3f            glimtkNormal3f
114    #define glTexCoord2fv         glimtkTexCoord2fv
115    #define glVertex3d            glimtkVertex3d
116    #define glVertex3dv           glimtkVertex3dv
117    #define glVertex3f            glimtkVertex3f
118    #define glVertex3fv           glimtkVertex3fv
119
120    #define glLoadMatrixd         glmsLoadMatrixd
121    #define glLoadMatrixf         glmsLoadMatrixf
122    #define glMultMatrixd         glmsMultMatrixd
123    #define glFrustum             glmsFrustum
124    #define glOrtho               glmsOrtho
125    #define glScaled              glmsScaled
126    #define glScalef              glmsScaled
127    #define glTranslated          glmsTranslated
128    #define glRotated             glmsRotated
129    #define glMatrixMode          glmsMatrixMode
130    #define glLoadIdentity        glmsLoadIdentity
131    #define glPushMatrix          glmsPushMatrix
132    #define glPopMatrix           glmsPopMatrix
133
134    #define glLineStipple         glesLineStipple
135    #define glColorMaterial       glesColorMaterial
136    #define glLightModeli         glesLightModeli
137
138 #endif
139
140 #include "cc.h"
141
142 #define OFFSET(s, m) ((uint)(uintptr) (&((s *) 0)->m))
143
144 import "textureManager"
145
146
147 #define DM_ENABLE_IMAGE_ROTATION (1)
148 #define DM_ENABLE_EXT_COLOR (1)
149
150 ////
151
152 static struct DMDrawVertexFlat
153 {
154   float vertex[2];
155   float texcoord0[2];
156   uint32 color;
157 #if DM_ENABLE_EXT_COLOR
158   uint32 extcolor;
159 #endif
160 } __attribute__((aligned(16)));
161
162 static struct DMDrawVertex
163 {
164   short vertex[2];
165   short texcoord0[2];
166   uint32 color;
167 #if DM_ENABLE_EXT_COLOR
168   uint32 extcolor;
169 #endif
170 } __attribute__((aligned(16)));
171
172 struct DMDrawBuffer
173 {
174    GLuint vbo;
175    int glType;
176    int vertexCount;
177    int vertexAlloc;
178    void *vertexBuffer;
179 };
180
181 class DMProgramFlags : uint { bool valid:1; }
182
183 struct DMProgram
184 {
185   GLuint glProgram;
186   GLuint vertexShader;
187   GLuint fragmentShader;
188   GLint matrixloc;
189   GLint vertexloc;
190   GLint texcoord0loc;
191   GLint texcoord1loc;
192   GLint colorloc;
193 #if DM_ENABLE_EXT_COLOR
194   GLint extcolorloc;
195 #endif
196   GLint texbaseloc;
197   DMProgramFlags flags;
198   int64 lastUpdateCount;
199 };
200
201 class DMImageFlags : uint16
202 {
203    bool empty:1;     // Image is empty, do not draw
204    bool blending:1;  // Must draw image with blending
205 }
206
207 public struct DMImage
208 {
209 private:
210    Texture texture;
211    DMImageFlags flags;
212    short programIndex;
213    short srcx, srcy;
214    short sizex, sizey;
215
216    // Computed order for sorted rendering, in defineImage()
217    uint32 orderMask;
218
219 public:
220    void clear()
221    {
222       this = { flags = { empty = true } };
223    }
224
225    void defineImage( Texture texture, int offsetx, int offsety, int sizex, int sizey, bool blending, int programIndex, int layerindex )
226    {
227       int ordx = offsetx >> 6;
228       int ordy = offsety >> 6;
229       uint32 orderimage = ccMortonNumber32( ordx, ordy ) & ( ( 1 << DM_IMAGE_ORDER_BITS ) - 1 );
230       this =
231       {
232          texture = texture;
233          srcx = (short)offsetx;
234          srcy = (short)offsety;
235          sizex = (short)sizex;
236          sizey = (short)sizey;
237          programIndex = (short)programIndex;
238          flags = { blending = blending };
239          orderMask = (orderimage << DM_IMAGE_ORDER_SHIFT) |
240                      (( blending == true ) << DM_BLEND_ORDER_SHIFT) |
241                      (programIndex << DM_PROGRAM_ORDER_SHIFT) |
242                      texture.orderMask |
243                      (layerindex << DM_LAYER_ORDER_SHIFT);
244       };
245    }
246 };
247
248 struct DMImageBuffer
249 {
250   DMImage *image;
251   short offsetx;
252   short offsety;
253   short sizex;
254   short sizey;
255 #if DM_ENABLE_IMAGE_ROTATION
256   short angcos;
257   short angsin;
258 #endif
259 #if DM_ENABLE_EXT_COLOR
260   uint32 extcolor;
261 #endif
262   uint32 color;
263   uint32 orderindex;
264 };
265
266
267 ////
268
269
270 define DM_IMAGE_ORDER_BITS = 8;
271 define DM_BLEND_ORDER_BITS = 1;
272 define DM_PROGRAM_ORDER_BITS = 4;
273 define DM_TEXTURE_ORDER_BITS = 10;
274 define DM_LAYER_ORDER_BITS = 4;
275 define DM_BARRIER_ORDER_BITS = 5;
276
277 define DM_IMAGE_ORDER_SHIFT = 0;
278 define DM_BLEND_ORDER_SHIFT = DM_IMAGE_ORDER_BITS;
279 define DM_PROGRAM_ORDER_SHIFT = DM_IMAGE_ORDER_BITS+DM_BLEND_ORDER_BITS;
280 define DM_TEXTURE_ORDER_SHIFT = DM_IMAGE_ORDER_BITS+DM_BLEND_ORDER_BITS+DM_PROGRAM_ORDER_BITS;
281 define DM_LAYER_ORDER_SHIFT = DM_IMAGE_ORDER_BITS+DM_BLEND_ORDER_BITS+DM_PROGRAM_ORDER_BITS+DM_TEXTURE_ORDER_BITS;
282 define DM_BARRIER_ORDER_SHIFT = DM_IMAGE_ORDER_BITS+DM_BLEND_ORDER_BITS+DM_PROGRAM_ORDER_BITS+DM_TEXTURE_ORDER_BITS+DM_LAYER_ORDER_BITS;
283
284 define DM_LAYER_COUNT = 1<<DM_LAYER_ORDER_BITS;
285 define DM_PROGRAM_COUNT = 1<<DM_PROGRAM_ORDER_BITS;
286
287 define DM_CONTEXT_DRAW_BUFFER_COUNT = 64;
288 define DM_CONTEXT_DRAW_BUFFER_VERTEX_ALLOC = 1024;
289
290
291 /* Range is from zero to DM_LAYER_COUNT */
292 enum DMLayer
293 {
294   DM_LAYER_0_BOTTOM,
295   DM_LAYER_1_BOTTOM,
296   DM_LAYER_2_BELOW,
297   DM_LAYER_3_BELOW,
298   DM_LAYER_4_BELOW,
299   DM_LAYER_5_NORMAL,
300   DM_LAYER_6_NORMAL,
301   DM_LAYER_7_NORMAL,
302   DM_LAYER_8_ABOVE,
303   DM_LAYER_9_ABOVE,
304   DM_LAYER_10_ABOVE,
305   DM_LAYER_11_OVERLAY,
306   DM_LAYER_12_OVERLAY,
307   DM_LAYER_13_OVERLAY,
308   DM_LAYER_14_TOP,
309   DM_LAYER_15_TOP,
310 };
311
312 define DM_LAYER_BOTTOM = DMLayer::DM_LAYER_0_BOTTOM;
313 define DM_LAYER_BELOW = DMLayer::DM_LAYER_3_BELOW;
314 define DM_LAYER_NORMAL = DMLayer::DM_LAYER_6_NORMAL;
315 define DM_LAYER_ABOVE = DMLayer::DM_LAYER_9_ABOVE;
316 define DM_LAYER_TOP = DMLayer::DM_LAYER_15_TOP;
317
318 define DM_PROGRAM_NORMAL = 0;
319 define DM_PROGRAM_ALPHABLEND = 1;
320 define DM_PROGRAM_ALPHABLEND_INTENSITY = 2;
321 define DM_PROGRAM_ALPHABLEND_INTENSITY_EXTCOLOR = 3;
322
323 #ifdef _DEBUG
324 static inline void OpenGLErrorCheck( const char *file, int line )
325 {
326    int error = glGetError();
327    if( error != GL_NO_ERROR )
328       printf( "ERROR %d at %s:%d\n", error, file, line );
329 }
330
331 #define ERRORCHECK() OpenGLErrorCheck(__FILE__,__LINE__)
332 #else
333 #define ERRORCHECK()
334 #endif
335
336 // Not using 32767.0 ; overflow when converting to int16 due to floating point crud causes problems
337 #define DM_IMAGE_ROTATION_NORMFACTOR (24576.0f)
338
339 #define DM_VERTEX_NORMSHIFT (2)
340 #define DM_VERTEX_NORMFACTOR (4.0f)
341
342 #define DM_TEXCOORD_NORMSHIFT (13)
343 #define DM_TEXCOORD_NORMFACTOR (8192.0 /*f*/)
344
345 #ifdef SHADERS
346 static GLuint dmCreateShader( GLenum type, const char *shadersource, const char *optionstring )
347 {
348   GLuint shader;
349   GLint status;
350   GLsizei loglength;
351   char infolog[8192];
352   const GLchar *sourcearray[2];
353
354   shader = glCreateShader( type );
355   if( !( shader ) )
356     return 0;
357
358   if( !( optionstring ) )
359     optionstring = "";
360   sourcearray[0] = optionstring;
361   sourcearray[1] = shadersource;
362   glShaderSource( shader, 2, sourcearray, NULL );
363   glCompileShader( shader );
364   glGetShaderiv( shader, GL_COMPILE_STATUS, &status );
365   if( status != GL_TRUE )
366   {
367     fprintf( stderr, "ERROR: Failed to compile shader\n" );
368     glGetShaderInfoLog( shader, 8192, &loglength,infolog );
369     fprintf( stderr, "ERROR: \n%s\n\n", infolog );
370     glDeleteShader( shader );
371     return 0;
372   }
373   return shader;
374 }
375
376 static bool dmCreateProgram( DMProgram program, const char *vertexsource, const char *fragmentsource, char *optionstring )
377 {
378   GLint status;
379   GLsizei loglength;
380   char infolog[8192];
381
382   program.glProgram = 0;
383   program.vertexShader = 0;
384   program.fragmentShader = 0;
385
386   program.vertexShader = dmCreateShader( GL_VERTEX_SHADER, vertexsource, optionstring );
387   if( !( program.vertexShader ) )
388   {
389     fprintf(stderr, "ERROR: Unable to load vertex shader\n");
390     goto error;
391   }
392   program.fragmentShader = dmCreateShader( GL_FRAGMENT_SHADER, fragmentsource, optionstring );
393   if( !( program.fragmentShader ) )
394   {
395     fprintf(stderr, "ERROR: Unable to load fragment shader\n");
396     goto error;
397   }
398   program.glProgram = glCreateProgram();
399   if( !( program.glProgram ) )
400   {
401     fprintf(stderr, "ERROR: Unable to create program\n");
402     goto error;
403   }
404
405   glAttachShader( program.glProgram, program.vertexShader );
406   glAttachShader( program.glProgram, program.fragmentShader );
407
408    glBindAttribLocation(program.glProgram, GLBufferContents::vertex, "vertex");
409    glBindAttribLocation(program.glProgram, GLBufferContents::texCoord, "texCoord");
410    glBindAttribLocation(program.glProgram, GLBufferContents::color, "color");
411    glBindAttribLocation(program.glProgram, GLBufferContents::normal, "normal");
412
413   glLinkProgram( program.glProgram );
414   glGetProgramiv( program.glProgram, GL_LINK_STATUS, &status );
415   if( status != GL_TRUE )
416   {
417     fprintf( stderr, "ERROR, failed to link shader program\n" );
418     glGetProgramInfoLog( program.glProgram, 8192, &loglength, infolog );
419     fprintf( stderr, "ERROR: \n%s\n\n", infolog );
420     goto error;
421   }
422
423   // glUseProgram( program.glProgram );
424
425   program.matrixloc = glGetUniformLocation( program.glProgram, "uniMatrix" );
426   program.vertexloc = glGetAttribLocation( program.glProgram, "inVertex" );
427   program.texcoord0loc = glGetAttribLocation( program.glProgram, "inTexcoord0" );
428   program.texcoord1loc = glGetAttribLocation( program.glProgram, "inTexcoord1" );
429   program.colorloc = glGetAttribLocation( program.glProgram, "inColor" );
430 #if DM_ENABLE_EXT_COLOR
431   program.extcolorloc = glGetAttribLocation( program.glProgram, "inExtColor" );
432 #endif
433   program.texbaseloc = glGetUniformLocation( program.glProgram, "texBase" );
434   program.flags.valid = true;
435
436   return true;
437
438   error:
439   if( program.fragmentShader )
440     glDeleteShader( program.fragmentShader );
441   if( program.vertexShader )
442     glDeleteShader( program.vertexShader );
443   if( program.glProgram )
444     glDeleteProgram( program.glProgram );
445   return false;
446 }
447
448
449 ////
450
451
452 const char *dmVertexShaderNormal =
453 "#version 130\n"
454 "uniform mat4 uniMatrix;\n"
455 "in vec2 inVertex;\n"
456 "in vec2 inTexcoord0;\n"
457 "in vec4 inColor;\n"
458 "out vec2 varTexcoord0;\n"
459 "out vec4 varColor;\n"
460 "void main()\n"
461 "{\n"
462 " \n"
463 "  varTexcoord0 = inTexcoord0 * (1.0/" CC_STRINGIFY(DM_TEXCOORD_NORMFACTOR) ");\n"
464 "  varColor = inColor;\n"
465 "  gl_Position = uniMatrix * vec4( inVertex, 0.0, 1.0 );\n"
466 "  return;\n"
467 "}\n"
468 ;
469
470
471 const char *dmFragmentShaderNormal =
472 "#version 130\n"
473 "uniform sampler2D texBase;\n"
474 "in vec2 varTexcoord0;\n"
475 "in vec4 varColor;\n"
476 "void main()\n"
477 "{\n"
478 "  gl_FragColor = varColor * texture2D( texBase, varTexcoord0 );\n"
479 "  return;\n"
480 "}\n"
481 ;
482
483
484 const char *dmVertexShaderAlpha =
485 "#version 130\n"
486 "uniform mat4 uniMatrix;\n"
487 "in vec2 inVertex;\n"
488 "in vec2 inTexcoord0;\n"
489 "in vec4 inColor;\n"
490 "out vec2 varTexcoord0;\n"
491 "out vec4 varColor;\n"
492 "void main()\n"
493 "{\n"
494 " \n"
495 "  varTexcoord0 = inTexcoord0 * (1.0/" CC_STRINGIFY(DM_TEXCOORD_NORMFACTOR) ");\n"
496 "  varColor = inColor;\n"
497 "  gl_Position = uniMatrix * vec4( inVertex, 0.0, 1.0 );\n"
498 "  return;\n"
499 "}\n"
500 ;
501
502
503 const char *dmFragmentShaderAlpha =
504 "#version 130\n"
505 "uniform sampler2D texBase;\n"
506 "in vec2 varTexcoord0;\n"
507 "in vec4 varColor;\n"
508 "void main()\n"
509 "{\n"
510 "  gl_FragColor = vec4( varColor.rgb, varColor.a * texture2D( texBase, varTexcoord0 ).r );\n"
511 "  return;\n"
512 "}\n"
513 ;
514
515 const char *dmVertexShaderAlphaIntensity =
516 "#version 130\n"
517 "uniform mat4 uniMatrix;\n"
518 "in vec2 inVertex;\n"
519 "in vec2 inTexcoord0;\n"
520 "in vec4 inColor;\n"
521 "out vec2 varTexcoord0;\n"
522 "out vec4 varColor;\n"
523 "void main()\n"
524 "{\n"
525 " \n"
526 "  varTexcoord0 = inTexcoord0 * (1.0/" CC_STRINGIFY(DM_TEXCOORD_NORMFACTOR) ");\n"
527 "  varColor = inColor;\n"
528 "  gl_Position = uniMatrix * vec4( inVertex, 0.0, 1.0 );\n"
529 "  return;\n"
530 "}\n"
531 ;
532
533
534 const char *dmFragmentShaderAlphaIntensity =
535 "#version 130\n"
536 "uniform sampler2D texBase;\n"
537 "in vec2 varTexcoord0;\n"
538 "in vec4 varColor;\n"
539 "void main()\n"
540 "{\n"
541 "  vec2 tex;\n"
542 "  tex = texture2D( texBase, varTexcoord0 ).rg;\n"
543 "  gl_FragColor = vec4( varColor.rgb * tex.g, varColor.a * tex.r );\n"
544 "  return;\n"
545 "}\n"
546 ;
547
548 const char *dmVertexShaderAlphaIntensityExtColor =
549 "#version 130\n"
550 "uniform mat4 uniMatrix;\n"
551 "in vec2 inVertex;\n"
552 "in vec2 inTexcoord0;\n"
553 "in vec4 inColor;\n"
554 "in vec4 inExtColor;\n"
555 "out vec2 varTexcoord0;\n"
556 "out vec4 varColor;\n"
557 "out vec4 varExtColor;\n"
558 "void main()\n"
559 "{\n"
560 " \n"
561 "  varTexcoord0 = inTexcoord0 * (1.0/" CC_STRINGIFY(DM_TEXCOORD_NORMFACTOR) ");\n"
562 "  varColor = inColor;\n"
563 "  varExtColor = inExtColor;\n"
564 "  gl_Position = uniMatrix * vec4( inVertex, 0.0, 1.0 );\n"
565 "  return;\n"
566 "}\n"
567 ;
568
569
570 const char *dmFragmentShaderAlphaIntensityExtColor =
571 "#version 130\n"
572 "uniform sampler2D texBase;\n"
573 "in vec2 varTexcoord0;\n"
574 "in vec4 varColor;\n"
575 "in vec4 varExtColor;\n"
576 "void main()\n"
577 "{\n"
578 "  vec2 tex;\n"
579 "  tex = texture2D( texBase, varTexcoord0 ).rg;\n"
580 "  gl_FragColor = vec4( mix( varExtColor.rgb, varColor.rgb, tex.g ), mix( varExtColor.a, varColor.a, tex.g ) * tex.r );\n"
581 "  return;\n"
582 "}\n"
583 ;
584
585 ////
586 #endif
587
588 static void matrixOrtho( float *m, float left, float right, float bottom, float top, float nearval, float farval )
589 {
590   float x = 2.0f / ( right - left );
591   float y = 2.0f / ( top - bottom );
592   float z = -2.0f / ( farval - nearval );
593   float tx = -( right + left ) / ( right - left );
594   float ty = -( top + bottom ) / ( top - bottom );
595   float tz = -( farval + nearval ) / ( farval - nearval );
596
597 #define M(row,col)  m[col*4+row]
598   M(0,0) = x;    M(0,1) = 0.0;  M(0,2) = 0.0;  M(0,3) = tx;
599   M(1,0) = 0.0;  M(1,1) = y;     M(1,2) = 0.0;  M(1,3) = ty;
600   M(2,0) = 0.0;  M(2,1) = 0.0;  M(2,2) = z;     M(2,3) = tz;
601   M(3,0) = 0.0;  M(3,1) = 0.0;  M(3,2) = 0.0;  M(3,3) = 1.0;
602 #undef M
603 }
604
605 ////
606
607
608 /* FIXME: Radix sort, not hybrid sort! */
609
610 static inline int dmSortImagesCmp( DMImageBuffer *draw0, DMImageBuffer *draw1 )
611 {
612   return ( ( draw0->orderindex < draw1->orderindex ) ? 0 : 1 );
613 }
614
615 #define HSORT_MAIN dmSortImages
616 #define HSORT_CMP dmSortImagesCmp
617 #define HSORT_TYPE DMImageBuffer
618 #include "cchybridsort.h"
619 #undef HSORT_MAIN
620 #undef HSORT_CMP
621 #undef HSORT_TYPE
622
623
624 ////
625
626 // TOFIX: Make this private, have a property
627 public class DrawManagerFlags : uint32 { public: bool prehistoricOpenGL:1; }
628
629 public class DrawManager
630 {
631    DrawManagerFlags flags;
632
633    // Matrix
634    float matrix[16];
635
636    int imageBufferCount;
637    int imageBufferSize;
638    DMImageBuffer *imageBuffer;
639    DMImageBuffer *imageBufferTmp;
640
641    // Buffers for drawimages() batching
642    DMDrawBuffer drawBuffer[DM_CONTEXT_DRAW_BUFFER_COUNT];
643    int drawBufferIndex;
644    int drawBarrierIndex;
645    uint32 orderBarrierMask;
646
647    // Counter to track program uniforms and such
648    int64 updateCount;
649
650    DMProgram shaderPrograms[DM_PROGRAM_COUNT];
651    GLuint prevProgram;
652
653    bool renderingFlipped;
654
655    static DMProgram *flushUseProgram( int programIndex )
656    {
657       DMProgram *program = &shaderPrograms[ programIndex ];
658       if( !program->flags.valid)
659       {
660 #ifdef SHADERS
661          glUseProgram( 0 );
662 #endif
663          return 0;
664       }
665
666 #ifdef SHADERS
667       glUseProgram( program->glProgram );
668 #endif
669       if( program->lastUpdateCount != this.updateCount )
670       {
671 #ifdef SHADERS
672          glUniformMatrix4fv( program->matrixloc, 1, GL_FALSE, this.matrix );
673          glUniform1i( program->texbaseloc, 0 );
674 #endif
675          program->lastUpdateCount = this.updateCount;
676       }
677       return program;
678    }
679
680 #if !defined(__EMSCRIPTEN__)
681    static void flushRenderDrawBufferArchaic( DMDrawBuffer drawBuffer, DMProgram program, int vertexCount )
682    {
683       glEnable( GL_TEXTURE_2D );
684       glBindBuffer( GL_ARRAY_BUFFER, drawBuffer.vbo );
685       glColor3f( 1.0, 1.0, 1.0 );
686
687       glEnableClientState( GL_VERTEX_ARRAY );
688       glEnableClientState( GL_TEXTURE_COORD_ARRAY );
689       glEnableClientState( GL_COLOR_ARRAY );
690
691       glVertexPointer( 2, GL_FLOAT, sizeof(DMDrawVertexFlat), (void *)OFFSET(DMDrawVertexFlat,vertex) );
692       glTexCoordPointer( 2, GL_FLOAT, sizeof(DMDrawVertexFlat), (void *)OFFSET(DMDrawVertexFlat,texcoord0) );
693       glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof(DMDrawVertexFlat), (void *)OFFSET(DMDrawVertexFlat,color) );
694
695       glDrawArrays( GL_TRIANGLES, 0, vertexCount );
696
697       glDisableClientState( GL_VERTEX_ARRAY );
698       glDisableClientState( GL_TEXTURE_COORD_ARRAY );
699       glDisableClientState( GL_COLOR_ARRAY );
700       glDisable( GL_TEXTURE_2D );
701
702    #if DM_FLUSH_EACH_RENDER_DRAW_BUFFER
703       glFlush();
704    #endif
705    }
706
707    void flushDrawImagesArchaic( )
708    {
709      bool flushflag, stateBlend;
710      int index, vertexCount, programIndex;
711      float vx0, vx1, vx2, vx3, vy0, vy1, vy2, vy3;
712    #if DM_ENABLE_IMAGE_ROTATION
713      float angsin, angcos, sizex, sizey;
714    #endif
715      float tx0, tx1, ty0, ty1;
716      DMImageBuffer *imageBuffer;
717      DMImage *image, *bindimage;
718      Texture texture, bindTexture;
719      DMDrawBuffer *drawBuffer;
720      DMDrawVertexFlat *vboVertex = null;
721 #if defined(_GLES) || defined(_GLES2)
722      DMDrawVertexFlat *vboStorage = null;
723 #endif
724      DMProgram *program;
725
726      ERRORCHECK();
727
728      drawBarrierIndex = 0;
729      orderBarrierMask = drawBarrierIndex << DM_BARRIER_ORDER_SHIFT;
730      if(imageBufferCount)
731      {
732         // Sort by image type and texture, minimize state changes
733         dmSortImages( this.imageBuffer, imageBufferTmp, imageBufferCount, (uint32)( (intptr_t)this.imageBuffer >> 4 ) );
734
735         // Fill a drawBuffer, write vertex and texcoords
736         drawBuffer = &this.drawBuffer[drawBufferIndex];
737         drawBufferIndex = ( drawBufferIndex + 1 ) % DM_CONTEXT_DRAW_BUFFER_COUNT;
738         glBindBuffer( GL_ARRAY_BUFFER, drawBuffer->vbo );
739 #if defined(_GLES) || defined(_GLES2)
740         vboVertex = vboStorage = new DMDrawVertexFlat[drawBuffer->vertexAlloc * 1];
741 #else
742         vboVertex = glMapBuffer( GL_ARRAY_BUFFER, GL_WRITE_ONLY );
743 #endif
744         vertexCount = 0;
745
746         glActiveTexture( GL_TEXTURE0 );
747         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
748         glDisable( GL_BLEND );
749         GLSetupLighting(false);
750
751       #if DM_RENDER_IMAGE_DEBUG
752       printf( " Flush %d images\n", (int)imageBufferCount );
753       #endif
754
755         bindimage = 0;
756         bindTexture = 0;
757         stateBlend = 0;
758         programIndex = -1;
759         program = 0;
760         imageBuffer = this.imageBuffer;
761         for( index = 0 ; index < imageBufferCount ; index++, imageBuffer++ )
762         {
763           image = imageBuffer->image;
764           texture = image->texture;
765
766           flushflag = 0;
767           if( image != bindimage )
768           {
769             if( stateBlend != image->flags.blending )
770               flushflag = 1;
771             if( texture != bindTexture )
772               flushflag = 1;
773           }
774           if( vertexCount >= ( drawBuffer->vertexAlloc - 6 ) )
775             flushflag = 1;
776
777           if( flushflag )
778           {
779             if( vertexCount )
780             {
781 #if defined(_GLES) || defined(_GLES2)
782               glBufferData( GL_ARRAY_BUFFER, drawBuffer->vertexAlloc * sizeof(DMDrawVertexFlat), vboStorage, GL_DYNAMIC_DRAW );
783 #else
784               glUnmapBuffer( GL_ARRAY_BUFFER );
785 #endif
786               // Flush font manager texture updates
787               flush( );
788               // Render buffered images
789               flushRenderDrawBufferArchaic( drawBuffer, program, vertexCount );
790               drawBuffer = &this.drawBuffer[drawBufferIndex];
791               drawBufferIndex = ( drawBufferIndex + 1 ) % DM_CONTEXT_DRAW_BUFFER_COUNT;
792               glBindBuffer( GL_ARRAY_BUFFER, drawBuffer->vbo );
793 #if defined(_GLES) || defined(_GLES2)
794               vboVertex = vboStorage;
795 #else
796               vboVertex = glMapBuffer( GL_ARRAY_BUFFER, GL_WRITE_ONLY );
797 #endif
798               vertexCount = 0;
799             }
800
801             if( stateBlend != ( image->flags.blending ) )
802             {
803               stateBlend = image->flags.blending;
804               ( stateBlend ? glEnable : glDisable )( GL_BLEND );
805       #if DM_RENDER_IMAGE_DEBUG
806       printf( "  Switch blending %d\n", stateBlend != false );
807       #endif
808             }
809             if( programIndex != image->programIndex )
810             {
811               programIndex = image->programIndex;
812               program = flushUseProgram( programIndex );
813             }
814             if( texture != bindTexture )
815             {
816               bindTexture = texture;
817               glBindTexture( GL_TEXTURE_2D, bindTexture.glTex );
818       #if DM_RENDER_IMAGE_DEBUG
819       printf( "  Switch to texture 0x%x\n", (int)texture.orderMask );
820       #endif
821             }
822             bindimage = image;
823           }
824
825       #if DM_RENDER_IMAGE_DEBUG
826       printf( "   Render image at %d %d, order 0x%x, texture %p\n", (int)imageBuffer->offsetx, (int)imageBuffer->offsety, (int)imageBuffer->orderindex, texture );
827       #endif
828
829       #if DM_ENABLE_IMAGE_ROTATION
830           angsin = (float)imageBuffer->angsin * (1.0f/DM_IMAGE_ROTATION_NORMFACTOR);
831           angcos = (float)imageBuffer->angcos * (1.0f/DM_IMAGE_ROTATION_NORMFACTOR);
832           sizex = (float)imageBuffer->sizex;
833           sizey = (float)imageBuffer->sizey;
834           vx0 = (float)imageBuffer->offsetx * (1.0f/DM_VERTEX_NORMFACTOR);
835           vy0 = (float)imageBuffer->offsety * (1.0f/DM_VERTEX_NORMFACTOR);
836           vx1 = vx0 + ( angcos * sizex );
837           vy1 = vy0 + ( angsin * sizex );
838           vx2 = vx0 - ( angsin * sizey );
839           vy2 = vy0 + ( angcos * sizey );
840           vx3 = vx0 + ( angcos * sizex ) - ( angsin * sizey );
841           vy3 = vy0 + ( angsin * sizex ) + ( angcos * sizey );
842       #else
843           vx0 = (float)imageBuffer->offsetx * (1.0f/DM_VERTEX_NORMFACTOR);
844           vy0 = (float)imageBuffer->offsety * (1.0f/DM_VERTEX_NORMFACTOR);
845           vx3 = vx0 + (float)( imageBuffer->sizex );
846           vy3 = vy0 + (float)( imageBuffer->sizey );
847           vx1 = vx3;
848           vy1 = vy0;
849           vx2 = vx0;
850           vy2 = vy3;
851       #endif
852
853           tx0 = (float)( image->srcx ) * texture.widthinv;
854           ty0 = (float)( image->srcy ) * texture.heightinv;
855           tx1 = (float)( image->srcx + image->sizex ) * texture.widthinv;
856           ty1 = (float)( image->srcy + image->sizey ) * texture.heightinv;
857
858           // Write data to VBO
859           vboVertex[0].vertex[0] = vx3;
860           vboVertex[0].vertex[1] = vy3;
861           vboVertex[0].texcoord0[0] = tx1;
862           vboVertex[0].texcoord0[1] = ty1;
863           vboVertex[0].color = imageBuffer->color;
864       #if DM_ENABLE_EXT_COLOR
865           vboVertex[0].extcolor = imageBuffer->extcolor;
866       #endif
867           vboVertex[1].vertex[0] = vx1;
868           vboVertex[1].vertex[1] = vy1;
869           vboVertex[1].texcoord0[0] = tx1;
870           vboVertex[1].texcoord0[1] = ty0;
871           vboVertex[1].color = imageBuffer->color;
872       #if DM_ENABLE_EXT_COLOR
873           vboVertex[1].extcolor = imageBuffer->extcolor;
874       #endif
875           vboVertex[2].vertex[0] = vx2;
876           vboVertex[2].vertex[1] = vy2;
877           vboVertex[2].texcoord0[0] = tx0;
878           vboVertex[2].texcoord0[1] = ty1;
879           vboVertex[2].color = imageBuffer->color;
880       #if DM_ENABLE_EXT_COLOR
881           vboVertex[2].extcolor = imageBuffer->extcolor;
882       #endif
883           vboVertex[3].vertex[0] = vx0;
884           vboVertex[3].vertex[1] = vy0;
885           vboVertex[3].texcoord0[0] = tx0;
886           vboVertex[3].texcoord0[1] = ty0;
887           vboVertex[3].color = imageBuffer->color;
888       #if DM_ENABLE_EXT_COLOR
889           vboVertex[3].extcolor = imageBuffer->extcolor;
890       #endif
891           vboVertex[4].vertex[0] = vx2;
892           vboVertex[4].vertex[1] = vy2;
893           vboVertex[4].texcoord0[0] = tx0;
894           vboVertex[4].texcoord0[1] = ty1;
895           vboVertex[4].color = imageBuffer->color;
896       #if DM_ENABLE_EXT_COLOR
897           vboVertex[4].extcolor = imageBuffer->extcolor;
898       #endif
899           vboVertex[5].vertex[0] = vx1;
900           vboVertex[5].vertex[1] = vy1;
901           vboVertex[5].texcoord0[0] = tx1;
902           vboVertex[5].texcoord0[1] = ty0;
903           vboVertex[5].color = imageBuffer->color;
904       #if DM_ENABLE_EXT_COLOR
905           vboVertex[5].extcolor = imageBuffer->extcolor;
906       #endif
907
908           vboVertex += 6;
909           vertexCount += 6;
910         }
911
912 #if defined(_GLES) || defined(_GLES2) // TODO:
913         glBufferData( GL_ARRAY_BUFFER, drawBuffer->vertexAlloc * sizeof(DMDrawVertexFlat), vboStorage, GL_DYNAMIC_DRAW );
914         delete vboStorage;
915 #else
916         glUnmapBuffer( GL_ARRAY_BUFFER );
917 #endif
918
919         // Flush font manager texture updates
920         flush();
921
922         // Render buffered images
923         flushRenderDrawBufferArchaic( drawBuffer, program, vertexCount );
924         imageBufferCount = 0;
925
926         ERRORCHECK();
927
928      }
929    }
930 #endif
931
932 #ifdef SHADERS
933    static void flushRenderDrawBuffer( DMDrawBuffer drawBuffer, DMProgram program, int vertexCount )
934    {
935       glabCurArrayBuffer = 0;
936
937       glBindBuffer( GL_ARRAY_BUFFER, drawBuffer.vbo );
938       if( program.vertexloc != -1 )
939       {
940          glEnableVertexAttribArray( program.vertexloc );
941          glVertexAttribPointer( program.vertexloc, 2, GL_SHORT, GL_FALSE, sizeof(DMDrawVertex), (void *)OFFSET(DMDrawVertex,vertex) );
942       }
943       if( program.texcoord0loc != -1 )
944       {
945          glEnableVertexAttribArray( program.texcoord0loc );
946          glVertexAttribPointer( program.texcoord0loc, 2, GL_SHORT, GL_FALSE, sizeof(DMDrawVertex), (void *)OFFSET(DMDrawVertex,texcoord0) );
947       }
948       if( program.colorloc != -1 )
949       {
950          glEnableVertexAttribArray( program.colorloc );
951          glVertexAttribPointer( program.colorloc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(DMDrawVertex), (void *)OFFSET(DMDrawVertex,color) );
952       }
953
954    #if DM_ENABLE_EXT_COLOR
955       if( program.extcolorloc != -1 )
956       {
957          glEnableVertexAttribArray( program.extcolorloc );
958          glVertexAttribPointer( program.extcolorloc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(DMDrawVertex), (void *)OFFSET(DMDrawVertex,extcolor) );
959       }
960    #endif
961
962       glDrawArrays( GL_TRIANGLES, 0, vertexCount );
963
964       if( program.vertexloc != -1 )
965          glDisableVertexAttribArray( program.vertexloc );
966       if( program.texcoord0loc != -1 )
967          glDisableVertexAttribArray( program.texcoord0loc );
968       if( program.colorloc != -1 )
969          glDisableVertexAttribArray( program.colorloc );
970
971    #if DM_FLUSH_EACH_RENDER_DRAW_BUFFER
972       glFlush();
973    #endif
974    }
975 #endif
976
977 #ifdef SHADERS
978    static void flushDrawImages( )
979    {
980       int index, stateblend, vertexcount, flushflag, programIndex;
981       float vx0, vx1, vx2, vx3, vy0, vy1, vy2, vy3;
982       #if DM_ENABLE_IMAGE_ROTATION
983       float angsin, angcos, sizex, sizey;
984       #endif
985       float tx0, tx1, ty0, ty1;
986       DMImageBuffer *imageBuffer;
987       DMImage *image, *bindimage;
988       Texture texture, bindtexture;
989       DMDrawBuffer *drawBuffer;
990       DMDrawVertex *vboVertex = null;
991       DMProgram *program;
992
993       glabCurArrayBuffer = 0;
994
995       ERRORCHECK();
996
997       this.drawBarrierIndex = 0;
998       orderBarrierMask = drawBarrierIndex << DM_BARRIER_ORDER_SHIFT;
999       if( imageBufferCount )
1000       {
1001          /* Sort by image type and texture, minimize state changes */
1002          dmSortImages( this.imageBuffer, this.imageBufferTmp, imageBufferCount, (uint32)( (uintptr)this.imageBuffer >> 4 ) );
1003
1004          /* Fill a drawBuffer, write vertex and texcoords */
1005          drawBuffer = &this.drawBuffer[this.drawBufferIndex];
1006          this.drawBufferIndex = ( this.drawBufferIndex + 1 ) % DM_CONTEXT_DRAW_BUFFER_COUNT;
1007          glBindBuffer( GL_ARRAY_BUFFER, drawBuffer->vbo );
1008
1009 #if !defined(_GLES) && !defined(_GLES2) // TODO:
1010          vboVertex = glMapBuffer( GL_ARRAY_BUFFER, GL_WRITE_ONLY );
1011 #endif
1012          vertexcount = 0;
1013
1014          glActiveTexture( GL_TEXTURE0 );
1015          glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1016          glDisable( GL_BLEND );
1017
1018          #if DM_RENDER_IMAGE_DEBUG
1019          printf( " Flush %d images\n", (int)imageBufferCount );
1020          #endif
1021
1022          bindimage = 0;
1023          bindtexture = 0;
1024          stateblend = 0;
1025          programIndex = -1;
1026          program = 0;
1027          imageBuffer = this.imageBuffer;
1028          for( index = 0 ; index < imageBufferCount ; index++, imageBuffer++ )
1029          {
1030           image = imageBuffer->image;
1031           texture = image->texture;
1032
1033           flushflag = 0;
1034           if( image != bindimage )
1035           {
1036             if( stateblend != ( image->flags.blending ) )
1037               flushflag = 1;
1038             if( texture != bindtexture )
1039               flushflag = 1;
1040           }
1041           if( vertexcount >= ( drawBuffer->vertexAlloc - 6 ) )
1042             flushflag = 1;
1043
1044           if( flushflag )
1045           {
1046             if( vertexcount )
1047             {
1048 #if !defined(_GLES) && !defined(_GLES2)  // TODO:
1049               glUnmapBuffer( GL_ARRAY_BUFFER );
1050 #endif
1051               // Flush font manager texture updates
1052               flush();
1053
1054               // Render buffered images
1055               flushRenderDrawBuffer( drawBuffer, program, vertexcount );
1056               drawBuffer = &this.drawBuffer[this.drawBufferIndex];
1057               this.drawBufferIndex = ( this.drawBufferIndex + 1 ) % DM_CONTEXT_DRAW_BUFFER_COUNT;
1058               glBindBuffer( GL_ARRAY_BUFFER, drawBuffer->vbo );
1059 #if !defined(_GLES) && !defined(_GLES2)   // TODO:
1060               vboVertex = glMapBuffer( GL_ARRAY_BUFFER, GL_WRITE_ONLY );
1061 #endif
1062               vertexcount = 0;
1063             }
1064
1065             if( stateblend != ( image->flags.blending ) )
1066             {
1067               stateblend = image->flags.blending;
1068               ( stateblend ? glEnable : glDisable )( GL_BLEND );
1069             #if DM_RENDER_IMAGE_DEBUG
1070                printf( "  Switch blending %d\n", ( stateblend != 0 ) );
1071             #endif
1072             }
1073             if( programIndex != image->programIndex )
1074             {
1075               programIndex = image->programIndex;
1076               program = flushUseProgram( programIndex );
1077             }
1078             if( texture != bindtexture )
1079             {
1080               bindtexture = texture;
1081               glBindTexture( GL_TEXTURE_2D, bindtexture.glTex );
1082       #if DM_RENDER_IMAGE_DEBUG
1083               printf( "  Switch to texture 0x%x\n", (int)texture.orderMask );
1084       #endif
1085             }
1086             bindimage = image;
1087           }
1088
1089          #if DM_RENDER_IMAGE_DEBUG
1090          printf( "   Render image at %d %d, order 0x%x, texture %p\n", (int)imageBuffer->offsetx, (int)imageBuffer->offsety, (int)imageBuffer->orderindex, texture );
1091          #endif
1092
1093       #if DM_ENABLE_IMAGE_ROTATION
1094           /* FIXME TODO: Don't go through float, compute texcoord integers directly */
1095           angsin = (float)imageBuffer->angsin * (1.0f/DM_IMAGE_ROTATION_NORMFACTOR);
1096           angcos = (float)imageBuffer->angcos * (1.0f/DM_IMAGE_ROTATION_NORMFACTOR);
1097           sizex = (float)imageBuffer->sizex;
1098           sizey = (float)imageBuffer->sizey;
1099           vx0 = (float)imageBuffer->offsetx * (1.0f/DM_VERTEX_NORMFACTOR);
1100           vy0 = (float)imageBuffer->offsety * (1.0f/DM_VERTEX_NORMFACTOR);
1101           vx1 = vx0 + ( angcos * sizex );
1102           vy1 = vy0 + ( angsin * sizex );
1103           vx2 = vx0 - ( angsin * sizey );
1104           vy2 = vy0 + ( angcos * sizey );
1105           vx3 = vx0 + ( angcos * sizex ) - ( angsin * sizey );
1106           vy3 = vy0 + ( angsin * sizex ) + ( angcos * sizey );
1107       #else
1108           /* FIXME TODO: Don't go through float, compute texcoord integers directly */
1109           vx0 = (float)imageBuffer->offsetx * (1.0f/DM_VERTEX_NORMFACTOR);
1110           vy0 = (float)imageBuffer->offsety * (1.0f/DM_VERTEX_NORMFACTOR);
1111           vx3 = vx0 + (float)( imageBuffer->sizex );
1112           vy3 = vy0 + (float)( imageBuffer->sizey );
1113           vx1 = vx3;
1114           vy1 = vy0;
1115           vx2 = vx0;
1116           vy2 = vy3;
1117       #endif
1118
1119           /* FIXME TODO: Don't go through float, compute texcoord integers directly */
1120           tx0 = (float)( image->srcx ) * texture.widthinv;
1121           ty0 = (float)( image->srcy ) * texture.heightinv;
1122           tx1 = (float)( image->srcx + image->sizex ) * texture.widthinv;
1123           ty1 = (float)( image->srcy + image->sizey ) * texture.heightinv;
1124
1125           /* Write data to VBO */
1126           /* TODO: write vertex/texcoord all at once with SSE */
1127           vboVertex[0].vertex[0] = (short)( vx3 * DM_VERTEX_NORMFACTOR );
1128           vboVertex[0].vertex[1] = (short)( vy3 * DM_VERTEX_NORMFACTOR );
1129           vboVertex[0].texcoord0[0] = (short)( tx1 * DM_TEXCOORD_NORMFACTOR );
1130           vboVertex[0].texcoord0[1] = (short)( ty1 * DM_TEXCOORD_NORMFACTOR );
1131           vboVertex[0].color = imageBuffer->color;
1132           vboVertex[0].extcolor = imageBuffer->extcolor;
1133           vboVertex[1].vertex[0] = (short)( vx1 * DM_VERTEX_NORMFACTOR );
1134           vboVertex[1].vertex[1] = (short)( vy1 * DM_VERTEX_NORMFACTOR );
1135           vboVertex[1].texcoord0[0] = (short)( tx1 * DM_TEXCOORD_NORMFACTOR );
1136           vboVertex[1].texcoord0[1] = (short)( ty0 * DM_TEXCOORD_NORMFACTOR );
1137           vboVertex[1].color = imageBuffer->color;
1138           vboVertex[1].extcolor = imageBuffer->extcolor;
1139           vboVertex[2].vertex[0] = (short)( vx2 * DM_VERTEX_NORMFACTOR );
1140           vboVertex[2].vertex[1] = (short)( vy2 * DM_VERTEX_NORMFACTOR );
1141           vboVertex[2].texcoord0[0] = (short)( tx0 * DM_TEXCOORD_NORMFACTOR );
1142           vboVertex[2].texcoord0[1] = (short)( ty1 * DM_TEXCOORD_NORMFACTOR );
1143           vboVertex[2].color = imageBuffer->color;
1144           vboVertex[2].extcolor = imageBuffer->extcolor;
1145           vboVertex[3].vertex[0] = (short)( vx0 * DM_VERTEX_NORMFACTOR );
1146           vboVertex[3].vertex[1] = (short)( vy0 * DM_VERTEX_NORMFACTOR );
1147           vboVertex[3].texcoord0[0] = (short)( tx0 * DM_TEXCOORD_NORMFACTOR );
1148           vboVertex[3].texcoord0[1] = (short)( ty0 * DM_TEXCOORD_NORMFACTOR );
1149           vboVertex[3].color = imageBuffer->color;
1150           vboVertex[3].extcolor = imageBuffer->extcolor;
1151           vboVertex[4].vertex[0] = (short)( vx2 * DM_VERTEX_NORMFACTOR );
1152           vboVertex[4].vertex[1] = (short)( vy2 * DM_VERTEX_NORMFACTOR );
1153           vboVertex[4].texcoord0[0] = (short)( tx0 * DM_TEXCOORD_NORMFACTOR );
1154           vboVertex[4].texcoord0[1] = (short)( ty1 * DM_TEXCOORD_NORMFACTOR );
1155           vboVertex[4].color = imageBuffer->color;
1156           vboVertex[4].extcolor = imageBuffer->extcolor;
1157           vboVertex[5].vertex[0] = (short)( vx1 * DM_VERTEX_NORMFACTOR );
1158           vboVertex[5].vertex[1] = (short)( vy1 * DM_VERTEX_NORMFACTOR );
1159           vboVertex[5].texcoord0[0] = (short)( tx1 * DM_TEXCOORD_NORMFACTOR );
1160           vboVertex[5].texcoord0[1] = (short)( ty0 * DM_TEXCOORD_NORMFACTOR );
1161           vboVertex[5].color = imageBuffer->color;
1162           vboVertex[5].extcolor = imageBuffer->extcolor;
1163
1164           vboVertex += 6;
1165           vertexcount += 6;
1166         }
1167
1168 #if !defined(_GLES) && !defined(_GLES2)      // TODO:
1169         glUnmapBuffer( GL_ARRAY_BUFFER );
1170 #endif
1171         // Flush font manager texture updates
1172         flush();
1173         // Render buffered images
1174         flushRenderDrawBuffer( drawBuffer, program, vertexcount );
1175         imageBufferCount = 0;
1176
1177         ERRORCHECK();
1178       }
1179    }
1180 #endif
1181
1182 public:
1183
1184    property bool renderingFlipped { set { renderingFlipped = value; } }
1185
1186    virtual void flush();
1187
1188    bool init( DrawManagerFlags flags )
1189    {
1190       int drawBufferIndex;
1191       DMDrawBuffer *drawBuffer;
1192       uint vertexSize;
1193
1194       imageBufferCount = 0;
1195       imageBufferSize = 4096;
1196       imageBuffer = new DMImageBuffer[imageBufferSize];
1197       imageBufferTmp = new DMImageBuffer[imageBufferSize];
1198
1199       this.flags = flags;
1200
1201       if( flags.prehistoricOpenGL )
1202          vertexSize = sizeof(DMDrawVertexFlat);
1203       else
1204       {
1205 #ifdef SHADERS
1206          DMProgram *program;
1207          int programIndex;
1208          for( programIndex = 0 ; programIndex < DM_PROGRAM_COUNT ; programIndex++ )
1209          {
1210             program = &shaderPrograms[ programIndex ];
1211             program->flags = 0;
1212             program->lastUpdateCount = -1;
1213          }
1214          program = &shaderPrograms[ DM_PROGRAM_NORMAL ];
1215          if( !( dmCreateProgram( program, dmVertexShaderNormal, dmFragmentShaderNormal, 0 ) ) )
1216             return false;
1217          program = &shaderPrograms[ DM_PROGRAM_ALPHABLEND ];
1218          if( !( dmCreateProgram( program, dmVertexShaderAlpha, dmFragmentShaderAlpha, 0 ) ) )
1219             return false;
1220          program = &shaderPrograms[ DM_PROGRAM_ALPHABLEND_INTENSITY ];
1221          if( !( dmCreateProgram( program, dmVertexShaderAlphaIntensity, dmFragmentShaderAlphaIntensity, 0 ) ) )
1222             return false;
1223         program = &shaderPrograms[ DM_PROGRAM_ALPHABLEND_INTENSITY_EXTCOLOR ];
1224         if( !( dmCreateProgram( program, dmVertexShaderAlphaIntensityExtColor, dmFragmentShaderAlphaIntensityExtColor, 0 ) ) )
1225             return false;
1226          // glUseProgram( 0 );
1227          vertexSize = sizeof(DMDrawVertex);
1228 #endif
1229       }
1230
1231       for( drawBufferIndex = 0 ; drawBufferIndex < DM_CONTEXT_DRAW_BUFFER_COUNT ; drawBufferIndex++ )
1232       {
1233          drawBuffer = &this.drawBuffer[drawBufferIndex];
1234          drawBuffer->glType = GL_FLOAT;
1235          drawBuffer->vertexCount = 0;
1236          drawBuffer->vertexAlloc = DM_CONTEXT_DRAW_BUFFER_VERTEX_ALLOC;
1237          if(vboAvailable)
1238          {
1239             glGenBuffers( 1, &drawBuffer->vbo );
1240             glBindBuffer( GL_ARRAY_BUFFER, drawBuffer->vbo );
1241             glBufferData( GL_ARRAY_BUFFER, drawBuffer->vertexAlloc * vertexSize, 0, GL_DYNAMIC_DRAW );
1242          }
1243          drawBuffer->vertexBuffer = new byte[drawBuffer->vertexAlloc * vertexSize];
1244       }
1245
1246       updateCount = 0;
1247
1248       glabCurArrayBuffer = 0;
1249
1250       return true;
1251    }
1252
1253    ~DrawManager()
1254    {
1255       end();
1256    }
1257
1258    void end( )
1259    {
1260       int i;
1261
1262       for( i = 0 ; i < DM_CONTEXT_DRAW_BUFFER_COUNT ; i++ )
1263       {
1264          DMDrawBuffer *db = &drawBuffer[i];
1265          if(db->vbo)
1266             glDeleteBuffers( 1, &db->vbo );
1267          delete db->vertexBuffer;
1268       }
1269
1270       // TODO: Destroy the shaders!
1271       delete imageBuffer;
1272       delete imageBufferTmp;
1273    }
1274
1275    void ready( int viewportwidth, int viewportheight )
1276    {
1277       int mindex;
1278       float norminv;
1279 #ifdef SHADERS
1280       if(!flags.prehistoricOpenGL && !prevProgram)
1281          glGetIntegerv(GL_CURRENT_PROGRAM, (GLint *)&prevProgram);
1282 #endif
1283       // while(glGetError());
1284
1285       // ERRORCHECK();
1286
1287       // Save OpenGL state
1288       // FIXME: no glPushAttrib() in core profile
1289 #if !defined(_GLES) && !defined(_GLES2)      // TODO:
1290       glPushClientAttrib( GL_CLIENT_ALL_ATTRIB_BITS );
1291       glPushAttrib( GL_ALL_ATTRIB_BITS );
1292 #endif
1293
1294       // Prepare rendering pass
1295       if(renderingFlipped)
1296          matrixOrtho( matrix, 0.0, (float)viewportwidth, 0.0, (float)viewportheight, -1.0f, 1.0 );
1297       else
1298          matrixOrtho( matrix, 0.0, (float)viewportwidth, (float)viewportheight, 0.0, -1.0f, 1.0 );
1299       norminv = 1.0f / DM_VERTEX_NORMFACTOR;
1300       for( mindex = 0 ; mindex < 12 ; mindex += 4 )
1301       {
1302         matrix[mindex+0] *= norminv;
1303         matrix[mindex+1] *= norminv;
1304         matrix[mindex+2] *= norminv;
1305       }
1306       drawBarrierIndex = 0;
1307       orderBarrierMask = drawBarrierIndex << DM_BARRIER_ORDER_SHIFT;
1308       orderBarrierMask = 0;
1309
1310       updateCount++;
1311
1312       if(flags.prehistoricOpenGL)
1313       {
1314          glMatrixMode(MatrixMode::projection);
1315          glLoadMatrixf(matrix);
1316
1317          glMatrixMode(MatrixMode::modelView);
1318          glLoadIdentity();
1319          glScalef(4,4,4);
1320       }
1321    }
1322
1323    void drawImage( DMImage image, int offsetx, int offsety, int sizex, int sizey, uint32 color )
1324    {
1325      DMImageBuffer *imageBuffer;
1326
1327      if( image.flags.empty || ( sizex <= 0 ) || ( sizey <= 0 ) )
1328        return;
1329
1330      if( imageBufferCount >= imageBufferSize )
1331      {
1332        imageBufferSize <<= 1;
1333        this.imageBuffer = renew this.imageBuffer DMImageBuffer[imageBufferSize];
1334        imageBufferTmp = renew imageBufferTmp DMImageBuffer[imageBufferSize];
1335      }
1336
1337      imageBuffer = &this.imageBuffer[ imageBufferCount ];
1338      imageBuffer->image = image;
1339      imageBuffer->offsetx = (short)(offsetx << DM_VERTEX_NORMSHIFT);
1340      imageBuffer->offsety = (short)(offsety << DM_VERTEX_NORMSHIFT);
1341      imageBuffer->sizex = (short)sizex;
1342      imageBuffer->sizey = (short)sizey;
1343    #if DM_ENABLE_IMAGE_ROTATION
1344      imageBuffer->angsin = 0;
1345      imageBuffer->angcos = (short)DM_IMAGE_ROTATION_NORMFACTOR;
1346    #endif
1347      imageBuffer->color = color;
1348      imageBuffer->orderindex = image.orderMask | orderBarrierMask;
1349
1350    #if DM_RENDER_IMAGE_DEBUG
1351    printf( "  Queue image at %d %d, order 0x%x\n", (int)imageBuffer->offsetx, (int)imageBuffer->offsety, (int)imageBuffer->orderindex );
1352    #endif
1353
1354      imageBufferCount++;
1355    }
1356
1357    void drawImageExtColor( DMImage image, int offsetx, int offsety, int sizex, int sizey, uint32 color, uint32 extcolor )
1358    {
1359      DMImageBuffer *imageBuffer;
1360
1361      if( ( image.flags.empty ) || ( sizex <= 0 ) || ( sizey <= 0 ) )
1362        return;
1363
1364      if( imageBufferCount >= imageBufferSize )
1365      {
1366        imageBufferSize <<= 1;
1367        this.imageBuffer = renew this.imageBuffer DMImageBuffer[imageBufferSize];
1368        imageBufferTmp = renew imageBufferTmp DMImageBuffer[imageBufferSize];
1369      }
1370
1371      imageBuffer = &this.imageBuffer[ imageBufferCount ];
1372      imageBuffer->image = image;
1373      imageBuffer->offsetx = (short)(offsetx << DM_VERTEX_NORMSHIFT);
1374      imageBuffer->offsety = (short)(offsety << DM_VERTEX_NORMSHIFT);
1375      imageBuffer->sizex = (short)sizex;
1376      imageBuffer->sizey = (short)sizey;
1377    #if DM_ENABLE_IMAGE_ROTATION
1378      imageBuffer->angsin = 0;
1379      imageBuffer->angcos = (short)DM_IMAGE_ROTATION_NORMFACTOR;
1380    #endif
1381      imageBuffer->color = color;
1382    #if DM_ENABLE_EXT_COLOR
1383      imageBuffer->extcolor = extcolor;
1384    #endif
1385      imageBuffer->orderindex = image.orderMask | orderBarrierMask;
1386
1387    #if DM_RENDER_IMAGE_DEBUG
1388    printf( "  Queue image at %d %d, order 0x%x\n", (int)imageBuffer->offsetx, (int)imageBuffer->offsety, (int)imageBuffer->orderindex );
1389    #endif
1390
1391      this.imageBufferCount++;
1392    }
1393
1394    void drawImageFloat( DMImage image, float offsetx, float offsety, float sizex, float sizey, float angsin, float angcos, uint32 color )
1395    {
1396      DMImageBuffer *imageBuffer;
1397
1398      if( image.flags.empty || sizex <= 0 || sizey <= 0 )
1399        return;
1400
1401      if( imageBufferCount >= imageBufferSize )
1402      {
1403        imageBufferSize <<= 1;
1404        this.imageBuffer = renew this.imageBuffer DMImageBuffer[imageBufferSize];
1405        imageBufferTmp = renew imageBufferTmp DMImageBuffer[imageBufferSize];
1406      }
1407
1408      imageBuffer = &this.imageBuffer[ imageBufferCount ];
1409      imageBuffer->image = image;
1410      imageBuffer->offsetx = (short)roundf(offsetx * DM_VERTEX_NORMFACTOR);
1411      imageBuffer->offsety = (short)roundf(offsety * DM_VERTEX_NORMFACTOR);
1412      imageBuffer->sizex = (short)sizex;
1413      imageBuffer->sizey = (short)sizey;
1414    #if DM_ENABLE_IMAGE_ROTATION
1415      imageBuffer->angsin = (short)roundf( angsin * DM_IMAGE_ROTATION_NORMFACTOR );
1416      imageBuffer->angcos = (short)roundf( angcos * DM_IMAGE_ROTATION_NORMFACTOR );
1417    #endif
1418      imageBuffer->color = color;
1419      imageBuffer->orderindex = image.orderMask | orderBarrierMask;
1420
1421    #if DM_RENDER_IMAGE_DEBUG
1422    printf( "  Queue image at %d %d, order 0x%x\n", (int)imageBuffer->offsetx, (int)imageBuffer->offsety, (int)imageBuffer->orderindex );
1423    #endif
1424
1425      imageBufferCount++;
1426    }
1427
1428    void drawImageFloatExtColor( DMImage image, float offsetx, float offsety, float sizex, float sizey, float angsin, float angcos, uint32 color, uint32 extcolor )
1429    {
1430      DMImageBuffer *imageBuffer;
1431
1432      if( ( image.flags.empty ) || ( sizex <= 0 ) || ( sizey <= 0 ) )
1433        return;
1434
1435      if( this.imageBufferCount >= this.imageBufferSize )
1436      {
1437        imageBufferSize <<= 1;
1438        this.imageBuffer = renew this.imageBuffer DMImageBuffer[imageBufferSize];
1439        imageBufferTmp = renew imageBufferTmp DMImageBuffer[imageBufferSize];
1440      }
1441
1442      imageBuffer = &this.imageBuffer[ imageBufferCount ];
1443      imageBuffer->image = image;
1444      imageBuffer->offsetx = (short)roundf( offsetx * DM_VERTEX_NORMFACTOR );
1445      imageBuffer->offsety = (short)roundf( offsety * DM_VERTEX_NORMFACTOR );
1446      imageBuffer->sizex = (short)sizex;
1447      imageBuffer->sizey = (short)sizey;
1448    #if DM_ENABLE_IMAGE_ROTATION
1449      imageBuffer->angsin = (short)roundf( angsin * DM_IMAGE_ROTATION_NORMFACTOR );
1450      imageBuffer->angcos = (short)roundf( angcos * DM_IMAGE_ROTATION_NORMFACTOR );
1451    #endif
1452      imageBuffer->color = color;
1453    #if DM_ENABLE_EXT_COLOR
1454      imageBuffer->extcolor = extcolor;
1455    #endif
1456      imageBuffer->orderindex = image.orderMask | orderBarrierMask;
1457
1458    #if DM_RENDER_IMAGE_DEBUG
1459    printf( "  Queue image at %d %d, order 0x%x\n", (int)imageBuffer->offsetx, (int)imageBuffer->offsety, (int)imageBuffer->orderindex );
1460    #endif
1461
1462      this.imageBufferCount++;
1463    }
1464
1465    void flushImages( )
1466    {
1467 #if !defined(_GLES2)
1468       if(flags.prehistoricOpenGL)
1469          flushDrawImagesArchaic();
1470 #endif
1471
1472 #if defined(SHADERS)
1473       if(!flags.prehistoricOpenGL)
1474          flushDrawImages( );
1475 #endif
1476    }
1477
1478    void finish()
1479    {
1480       flushImages();
1481
1482      if(vboAvailable)
1483         glBindBuffer( GL_ARRAY_BUFFER, 0 );
1484      glabCurArrayBuffer = 0;
1485 #ifdef SHADERS
1486      if( !flags.prehistoricOpenGL )
1487          glUseProgram( prevProgram );
1488 #endif
1489       // Restore OpenGL state
1490       // FIXME: no glPushAttrib() in core profile
1491 #if !defined(_GLES) && !defined(_GLES2)       // TODO:
1492       glPopAttrib();
1493       glPopClientAttrib();
1494 #endif
1495    }
1496
1497    void drawBarrier( )
1498    {
1499       drawBarrierIndex++;
1500       if( drawBarrierIndex >= ( 1 << DM_BARRIER_ORDER_BITS ) )
1501          flushImages( );
1502       orderBarrierMask = drawBarrierIndex << DM_BARRIER_ORDER_SHIFT;
1503    }
1504
1505    void clear()
1506    {
1507       imageBufferCount = 0;
1508    }
1509 }