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