ecere/gfx/newFonts: Further tweaks for Emscripten
[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 ES1_1
11 #else
12    #define SHADERS
13 #endif
14
15 #if defined(__EMSCRIPTEN__)
16    #define ES2
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.0f)
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    static DMProgram *flushUseProgram( int programIndex )
647    {
648       DMProgram *program = &shaderPrograms[ programIndex ];
649       if( !program->flags.valid)
650       {
651          glUseProgram( 0 );
652          return 0;
653       }
654
655       glUseProgram( program->glProgram );
656       if( program->lastUpdateCount != this.updateCount )
657       {
658          glUniformMatrix4fv( program->matrixloc, 1, GL_FALSE, this.matrix );
659          glUniform1i( program->texbaseloc, 0 );
660          program->lastUpdateCount = this.updateCount;
661       }
662
663       return program;
664    }
665
666 #if !defined(__EMSCRIPTEN__)
667    static void flushRenderDrawBufferArchaic( DMDrawBuffer drawBuffer, DMProgram program, int vertexCount )
668    {
669       glEnable( GL_TEXTURE_2D );
670       glBindBuffer( GL_ARRAY_BUFFER, drawBuffer.vbo );
671       glColor3f( 1.0, 1.0, 1.0 );
672
673       glEnableClientState( GL_VERTEX_ARRAY );
674       glEnableClientState( GL_TEXTURE_COORD_ARRAY );
675       glEnableClientState( GL_COLOR_ARRAY );
676
677       glVertexPointer( 2, GL_FLOAT, sizeof(DMDrawVertexFlat), (void *)OFFSET(DMDrawVertexFlat,vertex) );
678       glTexCoordPointer( 2, GL_FLOAT, sizeof(DMDrawVertexFlat), (void *)OFFSET(DMDrawVertexFlat,texcoord0) );
679       glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof(DMDrawVertexFlat), (void *)OFFSET(DMDrawVertexFlat,color) );
680
681       glDrawArrays( GL_TRIANGLES, 0, vertexCount );
682
683       glDisableClientState( GL_VERTEX_ARRAY );
684       glDisableClientState( GL_TEXTURE_COORD_ARRAY );
685       glDisableClientState( GL_COLOR_ARRAY );
686       glDisable( GL_TEXTURE_2D );
687
688    #if DM_FLUSH_EACH_RENDER_DRAW_BUFFER
689       glFlush();
690    #endif
691    }
692
693    void flushDrawImagesArchaic( )
694    {
695      bool flushflag, stateBlend;
696      int index, vertexCount, programIndex;
697      float vx0, vx1, vx2, vx3, vy0, vy1, vy2, vy3;
698    #if DM_ENABLE_IMAGE_ROTATION
699      float angsin, angcos, sizex, sizey;
700    #endif
701      float tx0, tx1, ty0, ty1;
702      DMImageBuffer *imageBuffer;
703      DMImage *image, *bindimage;
704      Texture texture, bindTexture;
705      DMDrawBuffer *drawBuffer;
706      DMDrawVertexFlat *vboVertex;
707      DMProgram *program;
708
709      ERRORCHECK();
710
711      drawBarrierIndex = 0;
712      orderBarrierMask = drawBarrierIndex << DM_BARRIER_ORDER_SHIFT;
713      if(imageBufferCount)
714      {
715         // Sort by image type and texture, minimize state changes
716         dmSortImages( this.imageBuffer, imageBufferTmp, imageBufferCount, (uint32)( (intptr_t)this.imageBuffer >> 4 ) );
717
718         // Fill a drawBuffer, write vertex and texcoords
719         drawBuffer = &this.drawBuffer[drawBufferIndex];
720         drawBufferIndex = ( drawBufferIndex + 1 ) % DM_CONTEXT_DRAW_BUFFER_COUNT;
721         glBindBuffer( GL_ARRAY_BUFFER, drawBuffer->vbo );
722         vboVertex = glMapBuffer( GL_ARRAY_BUFFER, GL_WRITE_ONLY );
723         vertexCount = 0;
724
725         glActiveTexture( GL_TEXTURE0 );
726         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
727         glDisable( GL_BLEND );
728
729       #if DM_RENDER_IMAGE_DEBUG
730       printf( " Flush %d images\n", (int)imageBufferCount );
731       #endif
732
733         bindimage = 0;
734         bindTexture = 0;
735         stateBlend = 0;
736         programIndex = -1;
737         program = 0;
738         imageBuffer = this.imageBuffer;
739         for( index = 0 ; index < imageBufferCount ; index++, imageBuffer++ )
740         {
741           image = imageBuffer->image;
742           texture = image->texture;
743
744           flushflag = 0;
745           if( image != bindimage )
746           {
747             if( stateBlend != image->flags.blending )
748               flushflag = 1;
749             if( texture != bindTexture )
750               flushflag = 1;
751           }
752           if( vertexCount >= ( drawBuffer->vertexAlloc - 6 ) )
753             flushflag = 1;
754
755           if( flushflag )
756           {
757             if( vertexCount )
758             {
759               glUnmapBuffer( GL_ARRAY_BUFFER );
760               // Flush font manager texture updates
761               flush( );
762               // Render buffered images
763               flushRenderDrawBufferArchaic( drawBuffer, program, vertexCount );
764               drawBuffer = &this.drawBuffer[drawBufferIndex];
765               drawBufferIndex = ( drawBufferIndex + 1 ) % DM_CONTEXT_DRAW_BUFFER_COUNT;
766               glBindBuffer( GL_ARRAY_BUFFER, drawBuffer->vbo );
767               vboVertex = glMapBuffer( GL_ARRAY_BUFFER, GL_WRITE_ONLY );
768               vertexCount = 0;
769             }
770
771             if( stateBlend != ( image->flags.blending ) )
772             {
773               stateBlend = image->flags.blending;
774               ( stateBlend ? glEnable : glDisable )( GL_BLEND );
775       #if DM_RENDER_IMAGE_DEBUG
776       printf( "  Switch blending %d\n", stateBlend != false );
777       #endif
778             }
779             if( programIndex != image->programIndex )
780             {
781               programIndex = image->programIndex;
782               program = flushUseProgram( programIndex );
783             }
784             if( texture != bindTexture )
785             {
786               bindTexture = texture;
787               glBindTexture( GL_TEXTURE_2D, bindTexture.glTex );
788       #if DM_RENDER_IMAGE_DEBUG
789       printf( "  Switch to texture 0x%x\n", (int)texture.orderMask );
790       #endif
791             }
792             bindimage = image;
793           }
794
795       #if DM_RENDER_IMAGE_DEBUG
796       printf( "   Render image at %d %d, order 0x%x, texture %p\n", (int)imageBuffer->offsetx, (int)imageBuffer->offsety, (int)imageBuffer->orderindex, texture );
797       #endif
798
799       #if DM_ENABLE_IMAGE_ROTATION
800           angsin = (float)imageBuffer->angsin * (1.0f/DM_IMAGE_ROTATION_NORMFACTOR);
801           angcos = (float)imageBuffer->angcos * (1.0f/DM_IMAGE_ROTATION_NORMFACTOR);
802           sizex = (float)imageBuffer->sizex;
803           sizey = (float)imageBuffer->sizey;
804           vx0 = (float)imageBuffer->offsetx * (1.0f/DM_VERTEX_NORMFACTOR);
805           vy0 = (float)imageBuffer->offsety * (1.0f/DM_VERTEX_NORMFACTOR);
806           vx1 = vx0 + ( angcos * sizex );
807           vy1 = vy0 + ( angsin * sizex );
808           vx2 = vx0 - ( angsin * sizey );
809           vy2 = vy0 + ( angcos * sizey );
810           vx3 = vx0 + ( angcos * sizex ) - ( angsin * sizey );
811           vy3 = vy0 + ( angsin * sizex ) + ( angcos * sizey );
812       #else
813           vx0 = (float)imageBuffer->offsetx * (1.0f/DM_VERTEX_NORMFACTOR);
814           vy0 = (float)imageBuffer->offsety * (1.0f/DM_VERTEX_NORMFACTOR);
815           vx3 = vx0 + (float)( imageBuffer->sizex );
816           vy3 = vy0 + (float)( imageBuffer->sizey );
817           vx1 = vx3;
818           vy1 = vy0;
819           vx2 = vx0;
820           vy2 = vy3;
821       #endif
822
823           tx0 = (float)( image->srcx ) * texture.widthinv;
824           ty0 = (float)( image->srcy ) * texture.heightinv;
825           tx1 = (float)( image->srcx + image->sizex ) * texture.widthinv;
826           ty1 = (float)( image->srcy + image->sizey ) * texture.heightinv;
827
828           // Write data to VBO
829           vboVertex[0].vertex[0] = vx3;
830           vboVertex[0].vertex[1] = vy3;
831           vboVertex[0].texcoord0[0] = tx1;
832           vboVertex[0].texcoord0[1] = ty1;
833           vboVertex[0].color = imageBuffer->color;
834       #if DM_ENABLE_EXT_COLOR
835           vboVertex[0].extcolor = imageBuffer->extcolor;
836       #endif
837           vboVertex[1].vertex[0] = vx1;
838           vboVertex[1].vertex[1] = vy1;
839           vboVertex[1].texcoord0[0] = tx1;
840           vboVertex[1].texcoord0[1] = ty0;
841           vboVertex[1].color = imageBuffer->color;
842       #if DM_ENABLE_EXT_COLOR
843           vboVertex[1].extcolor = imageBuffer->extcolor;
844       #endif
845           vboVertex[2].vertex[0] = vx2;
846           vboVertex[2].vertex[1] = vy2;
847           vboVertex[2].texcoord0[0] = tx0;
848           vboVertex[2].texcoord0[1] = ty1;
849           vboVertex[2].color = imageBuffer->color;
850       #if DM_ENABLE_EXT_COLOR
851           vboVertex[2].extcolor = imageBuffer->extcolor;
852       #endif
853           vboVertex[3].vertex[0] = vx0;
854           vboVertex[3].vertex[1] = vy0;
855           vboVertex[3].texcoord0[0] = tx0;
856           vboVertex[3].texcoord0[1] = ty0;
857           vboVertex[3].color = imageBuffer->color;
858       #if DM_ENABLE_EXT_COLOR
859           vboVertex[3].extcolor = imageBuffer->extcolor;
860       #endif
861           vboVertex[4].vertex[0] = vx2;
862           vboVertex[4].vertex[1] = vy2;
863           vboVertex[4].texcoord0[0] = tx0;
864           vboVertex[4].texcoord0[1] = ty1;
865           vboVertex[4].color = imageBuffer->color;
866       #if DM_ENABLE_EXT_COLOR
867           vboVertex[4].extcolor = imageBuffer->extcolor;
868       #endif
869           vboVertex[5].vertex[0] = vx1;
870           vboVertex[5].vertex[1] = vy1;
871           vboVertex[5].texcoord0[0] = tx1;
872           vboVertex[5].texcoord0[1] = ty0;
873           vboVertex[5].color = imageBuffer->color;
874       #if DM_ENABLE_EXT_COLOR
875           vboVertex[5].extcolor = imageBuffer->extcolor;
876       #endif
877
878           vboVertex += 6;
879           vertexCount += 6;
880         }
881
882         glUnmapBuffer( GL_ARRAY_BUFFER );
883
884         // Flush font manager texture updates
885         flush();
886
887         // Render buffered images
888         flushRenderDrawBufferArchaic( drawBuffer, program, vertexCount );
889         imageBufferCount = 0;
890
891         ERRORCHECK();
892
893      }
894    }
895 #endif
896
897    void flushRenderDrawBuffer( DMDrawBuffer drawBuffer, DMProgram program, int vertexCount )
898    {
899       glBindBuffer( GL_ARRAY_BUFFER, drawBuffer.vbo );
900       if( program.vertexloc != -1 )
901       {
902          glEnableVertexAttribArray( program.vertexloc );
903          glVertexAttribPointer( program.vertexloc, 2, GL_SHORT, GL_FALSE, sizeof(DMDrawVertex), (void *)OFFSET(DMDrawVertex,vertex) );
904       }
905       if( program.texcoord0loc != -1 )
906       {
907          glEnableVertexAttribArray( program.texcoord0loc );
908          glVertexAttribPointer( program.texcoord0loc, 2, GL_SHORT, GL_FALSE, sizeof(DMDrawVertex), (void *)OFFSET(DMDrawVertex,texcoord0) );
909       }
910       if( program.colorloc != -1 )
911       {
912          glEnableVertexAttribArray( program.colorloc );
913          glVertexAttribPointer( program.colorloc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(DMDrawVertex), (void *)OFFSET(DMDrawVertex,color) );
914       }
915
916    #if DM_ENABLE_EXT_COLOR
917       if( program.extcolorloc != -1 )
918       {
919          glEnableVertexAttribArray( program.extcolorloc );
920          glVertexAttribPointer( program.extcolorloc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(DMDrawVertex), (void *)OFFSET(DMDrawVertex,extcolor) );
921       }
922    #endif
923
924       glDrawArrays( GL_TRIANGLES, 0, vertexCount );
925
926       if( program.vertexloc != -1 )
927          glDisableVertexAttribArray( program.vertexloc );
928       if( program.texcoord0loc != -1 )
929          glDisableVertexAttribArray( program.texcoord0loc );
930       if( program.colorloc != -1 )
931          glDisableVertexAttribArray( program.colorloc );
932
933    #if DM_FLUSH_EACH_RENDER_DRAW_BUFFER
934       glFlush();
935    #endif
936    }
937
938    void flushDrawImages( )
939    {
940       int index, stateblend, vertexcount, flushflag, programIndex;
941       float vx0, vx1, vx2, vx3, vy0, vy1, vy2, vy3;
942       #if DM_ENABLE_IMAGE_ROTATION
943       float angsin, angcos, sizex, sizey;
944       #endif
945       float tx0, tx1, ty0, ty1;
946       DMImageBuffer *imageBuffer;
947       DMImage *image, *bindimage;
948       Texture texture, bindtexture;
949       DMDrawBuffer *drawBuffer;
950       DMDrawVertex *vboVertex;
951       DMProgram *program;
952
953       ERRORCHECK();
954
955       this.drawBarrierIndex = 0;
956       orderBarrierMask = drawBarrierIndex << DM_BARRIER_ORDER_SHIFT;
957       if( imageBufferCount )
958       {
959          /* Sort by image type and texture, minimize state changes */
960          dmSortImages( this.imageBuffer, this.imageBufferTmp, imageBufferCount, (uint32)( (uintptr)this.imageBuffer >> 4 ) );
961
962          /* Fill a drawBuffer, write vertex and texcoords */
963          drawBuffer = &this.drawBuffer[this.drawBufferIndex];
964          this.drawBufferIndex = ( this.drawBufferIndex + 1 ) % DM_CONTEXT_DRAW_BUFFER_COUNT;
965          glBindBuffer( GL_ARRAY_BUFFER, drawBuffer->vbo );
966
967 #if !defined(__EMSCRIPTEN__)
968          vboVertex = glMapBuffer( GL_ARRAY_BUFFER, GL_WRITE_ONLY );
969 #endif
970          vertexcount = 0;
971
972          glActiveTexture( GL_TEXTURE0 );
973          glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
974          glDisable( GL_BLEND );
975
976          #if DM_RENDER_IMAGE_DEBUG
977          printf( " Flush %d images\n", (int)imageBufferCount );
978          #endif
979
980          bindimage = 0;
981          bindtexture = 0;
982          stateblend = 0;
983          programIndex = -1;
984          program = 0;
985          imageBuffer = this.imageBuffer;
986          for( index = 0 ; index < imageBufferCount ; index++, imageBuffer++ )
987          {
988           image = imageBuffer->image;
989           texture = image->texture;
990
991           flushflag = 0;
992           if( image != bindimage )
993           {
994             if( stateblend != ( image->flags.blending ) )
995               flushflag = 1;
996             if( texture != bindtexture )
997               flushflag = 1;
998           }
999           if( vertexcount >= ( drawBuffer->vertexAlloc - 6 ) )
1000             flushflag = 1;
1001
1002           if( flushflag )
1003           {
1004             if( vertexcount )
1005             {
1006 #if !defined(__EMSCRIPTEN__)
1007               glUnmapBuffer( GL_ARRAY_BUFFER );
1008 #endif
1009               // Flush font manager texture updates
1010               flush();
1011
1012               // Render buffered images
1013               flushRenderDrawBuffer( drawBuffer, program, vertexcount );
1014               drawBuffer = &this.drawBuffer[this.drawBufferIndex];
1015               this.drawBufferIndex = ( this.drawBufferIndex + 1 ) % DM_CONTEXT_DRAW_BUFFER_COUNT;
1016               glBindBuffer( GL_ARRAY_BUFFER, drawBuffer->vbo );
1017 #if !defined(__EMSCRIPTEN__)
1018               vboVertex = glMapBuffer( GL_ARRAY_BUFFER, GL_WRITE_ONLY );
1019 #endif
1020               vertexcount = 0;
1021             }
1022
1023             if( stateblend != ( image->flags.blending ) )
1024             {
1025               stateblend = image->flags.blending;
1026               ( stateblend ? glEnable : glDisable )( GL_BLEND );
1027             #if DM_RENDER_IMAGE_DEBUG
1028                printf( "  Switch blending %d\n", ( stateblend != 0 ) );
1029             #endif
1030             }
1031             if( programIndex != image->programIndex )
1032             {
1033               programIndex = image->programIndex;
1034               program = flushUseProgram( programIndex );
1035             }
1036             if( texture != bindtexture )
1037             {
1038               bindtexture = texture;
1039               glBindTexture( GL_TEXTURE_2D, bindtexture.glTex );
1040       #if DM_RENDER_IMAGE_DEBUG
1041               printf( "  Switch to texture 0x%x\n", (int)texture.orderMask );
1042       #endif
1043             }
1044             bindimage = image;
1045           }
1046
1047          #if DM_RENDER_IMAGE_DEBUG
1048          printf( "   Render image at %d %d, order 0x%x, texture %p\n", (int)imageBuffer->offsetx, (int)imageBuffer->offsety, (int)imageBuffer->orderindex, texture );
1049          #endif
1050
1051       #if DM_ENABLE_IMAGE_ROTATION
1052           /* FIXME TODO: Don't go through float, compute texcoord integers directly */
1053           angsin = (float)imageBuffer->angsin * (1.0f/DM_IMAGE_ROTATION_NORMFACTOR);
1054           angcos = (float)imageBuffer->angcos * (1.0f/DM_IMAGE_ROTATION_NORMFACTOR);
1055           sizex = (float)imageBuffer->sizex;
1056           sizey = (float)imageBuffer->sizey;
1057           vx0 = (float)imageBuffer->offsetx * (1.0f/DM_VERTEX_NORMFACTOR);
1058           vy0 = (float)imageBuffer->offsety * (1.0f/DM_VERTEX_NORMFACTOR);
1059           vx1 = vx0 + ( angcos * sizex );
1060           vy1 = vy0 + ( angsin * sizex );
1061           vx2 = vx0 - ( angsin * sizey );
1062           vy2 = vy0 + ( angcos * sizey );
1063           vx3 = vx0 + ( angcos * sizex ) - ( angsin * sizey );
1064           vy3 = vy0 + ( angsin * sizex ) + ( angcos * sizey );
1065       #else
1066           /* FIXME TODO: Don't go through float, compute texcoord integers directly */
1067           vx0 = (float)imageBuffer->offsetx * (1.0f/DM_VERTEX_NORMFACTOR);
1068           vy0 = (float)imageBuffer->offsety * (1.0f/DM_VERTEX_NORMFACTOR);
1069           vx3 = vx0 + (float)( imageBuffer->sizex );
1070           vy3 = vy0 + (float)( imageBuffer->sizey );
1071           vx1 = vx3;
1072           vy1 = vy0;
1073           vx2 = vx0;
1074           vy2 = vy3;
1075       #endif
1076
1077           /* FIXME TODO: Don't go through float, compute texcoord integers directly */
1078           tx0 = (float)( image->srcx ) * texture.widthinv;
1079           ty0 = (float)( image->srcy ) * texture.heightinv;
1080           tx1 = (float)( image->srcx + image->sizex ) * texture.widthinv;
1081           ty1 = (float)( image->srcy + image->sizey ) * texture.heightinv;
1082
1083           /* Write data to VBO */
1084           /* TODO: write vertex/texcoord all at once with SSE */
1085           vboVertex[0].vertex[0] = (short)( vx3 * DM_VERTEX_NORMFACTOR );
1086           vboVertex[0].vertex[1] = (short)( vy3 * DM_VERTEX_NORMFACTOR );
1087           vboVertex[0].texcoord0[0] = (short)( tx1 * DM_TEXCOORD_NORMFACTOR );
1088           vboVertex[0].texcoord0[1] = (short)( ty1 * DM_TEXCOORD_NORMFACTOR );
1089           vboVertex[0].color = imageBuffer->color;
1090           vboVertex[0].extcolor = imageBuffer->extcolor;
1091           vboVertex[1].vertex[0] = (short)( vx1 * DM_VERTEX_NORMFACTOR );
1092           vboVertex[1].vertex[1] = (short)( vy1 * DM_VERTEX_NORMFACTOR );
1093           vboVertex[1].texcoord0[0] = (short)( tx1 * DM_TEXCOORD_NORMFACTOR );
1094           vboVertex[1].texcoord0[1] = (short)( ty0 * DM_TEXCOORD_NORMFACTOR );
1095           vboVertex[1].color = imageBuffer->color;
1096           vboVertex[1].extcolor = imageBuffer->extcolor;
1097           vboVertex[2].vertex[0] = (short)( vx2 * DM_VERTEX_NORMFACTOR );
1098           vboVertex[2].vertex[1] = (short)( vy2 * DM_VERTEX_NORMFACTOR );
1099           vboVertex[2].texcoord0[0] = (short)( tx0 * DM_TEXCOORD_NORMFACTOR );
1100           vboVertex[2].texcoord0[1] = (short)( ty1 * DM_TEXCOORD_NORMFACTOR );
1101           vboVertex[2].color = imageBuffer->color;
1102           vboVertex[2].extcolor = imageBuffer->extcolor;
1103           vboVertex[3].vertex[0] = (short)( vx0 * DM_VERTEX_NORMFACTOR );
1104           vboVertex[3].vertex[1] = (short)( vy0 * DM_VERTEX_NORMFACTOR );
1105           vboVertex[3].texcoord0[0] = (short)( tx0 * DM_TEXCOORD_NORMFACTOR );
1106           vboVertex[3].texcoord0[1] = (short)( ty0 * DM_TEXCOORD_NORMFACTOR );
1107           vboVertex[3].color = imageBuffer->color;
1108           vboVertex[3].extcolor = imageBuffer->extcolor;
1109           vboVertex[4].vertex[0] = (short)( vx2 * DM_VERTEX_NORMFACTOR );
1110           vboVertex[4].vertex[1] = (short)( vy2 * DM_VERTEX_NORMFACTOR );
1111           vboVertex[4].texcoord0[0] = (short)( tx0 * DM_TEXCOORD_NORMFACTOR );
1112           vboVertex[4].texcoord0[1] = (short)( ty1 * DM_TEXCOORD_NORMFACTOR );
1113           vboVertex[4].color = imageBuffer->color;
1114           vboVertex[4].extcolor = imageBuffer->extcolor;
1115           vboVertex[5].vertex[0] = (short)( vx1 * DM_VERTEX_NORMFACTOR );
1116           vboVertex[5].vertex[1] = (short)( vy1 * DM_VERTEX_NORMFACTOR );
1117           vboVertex[5].texcoord0[0] = (short)( tx1 * DM_TEXCOORD_NORMFACTOR );
1118           vboVertex[5].texcoord0[1] = (short)( ty0 * DM_TEXCOORD_NORMFACTOR );
1119           vboVertex[5].color = imageBuffer->color;
1120           vboVertex[5].extcolor = imageBuffer->extcolor;
1121
1122           vboVertex += 6;
1123           vertexcount += 6;
1124         }
1125
1126 #if !defined(__EMSCRIPTEN__)
1127         glUnmapBuffer( GL_ARRAY_BUFFER );
1128 #endif
1129         // Flush font manager texture updates
1130         flush();
1131         // Render buffered images
1132         flushRenderDrawBuffer( drawBuffer, program, vertexcount );
1133         imageBufferCount = 0;
1134
1135         ERRORCHECK();
1136       }
1137    }
1138
1139 public:
1140
1141    virtual void flush();
1142
1143    bool init( DrawManagerFlags flags )
1144    {
1145       int drawBufferIndex, programIndex;
1146       DMDrawBuffer *drawBuffer;
1147       uint vertexSize;
1148
1149       imageBufferCount = 0;
1150       imageBufferSize = 4096;
1151       imageBuffer = new DMImageBuffer[imageBufferSize];
1152       imageBufferTmp = new DMImageBuffer[imageBufferSize];
1153
1154       this.flags = flags;
1155
1156       if( flags.prehistoricOpenGL )
1157          vertexSize = sizeof(DMDrawVertexFlat);
1158       else
1159       {
1160          DMProgram *program;
1161          for( programIndex = 0 ; programIndex < DM_PROGRAM_COUNT ; programIndex++ )
1162          {
1163             program = &shaderPrograms[ programIndex ];
1164             program->flags = 0;
1165             program->lastUpdateCount = -1;
1166          }
1167          program = &shaderPrograms[ DM_PROGRAM_NORMAL ];
1168          if( !( dmCreateProgram( program, dmVertexShaderNormal, dmFragmentShaderNormal, 0 ) ) )
1169             return false;
1170          program = &shaderPrograms[ DM_PROGRAM_ALPHABLEND ];
1171          if( !( dmCreateProgram( program, dmVertexShaderAlpha, dmFragmentShaderAlpha, 0 ) ) )
1172             return false;
1173          program = &shaderPrograms[ DM_PROGRAM_ALPHABLEND_INTENSITY ];
1174          if( !( dmCreateProgram( program, dmVertexShaderAlphaIntensity, dmFragmentShaderAlphaIntensity, 0 ) ) )
1175             return false;
1176         program = &shaderPrograms[ DM_PROGRAM_ALPHABLEND_INTENSITY_EXTCOLOR ];
1177         if( !( dmCreateProgram( program, dmVertexShaderAlphaIntensityExtColor, dmFragmentShaderAlphaIntensityExtColor, 0 ) ) )
1178             return false;
1179          // glUseProgram( 0 );
1180          vertexSize = sizeof(DMDrawVertex);
1181       }
1182
1183       for( drawBufferIndex = 0 ; drawBufferIndex < DM_CONTEXT_DRAW_BUFFER_COUNT ; drawBufferIndex++ )
1184       {
1185          drawBuffer = &this.drawBuffer[drawBufferIndex];
1186          drawBuffer->glType = GL_FLOAT;
1187          drawBuffer->vertexCount = 0;
1188          drawBuffer->vertexAlloc = DM_CONTEXT_DRAW_BUFFER_VERTEX_ALLOC;
1189          if(vboAvailable)
1190          {
1191             glGenBuffers( 1, &drawBuffer->vbo );
1192             glBindBuffer( GL_ARRAY_BUFFER, drawBuffer->vbo );
1193             glBufferData( GL_ARRAY_BUFFER, drawBuffer->vertexAlloc * vertexSize, 0, GL_DYNAMIC_DRAW );
1194          }
1195          drawBuffer->vertexBuffer = new byte[drawBuffer->vertexAlloc * vertexSize];
1196       }
1197
1198       updateCount = 0;
1199
1200       return true;
1201    }
1202
1203
1204    void end( )
1205    {
1206       int i;
1207
1208       for( i = 0 ; i < DM_CONTEXT_DRAW_BUFFER_COUNT ; i++ )
1209       {
1210          DMDrawBuffer *db = &drawBuffer[i];
1211          if(db->vbo)
1212             glDeleteBuffers( 1, &db->vbo );
1213          delete db->vertexBuffer;
1214       }
1215
1216       // TODO: Destroy the shaders!
1217       delete imageBuffer;
1218       delete imageBufferTmp;
1219    }
1220
1221    void ready( int viewportwidth, int viewportheight )
1222    {
1223       int mindex;
1224       float norminv;
1225       if(!flags.prehistoricOpenGL && !prevProgram)
1226          glGetIntegerv(GL_CURRENT_PROGRAM, (GLint *)&prevProgram);
1227       // while(glGetError());
1228
1229       // ERRORCHECK();
1230
1231       // Save OpenGL state
1232       // FIXME: no glPushAttrib() in core profile
1233 #if !defined(__EMSCRIPTEN__)
1234       glPushClientAttrib( GL_CLIENT_ALL_ATTRIB_BITS );
1235       glPushAttrib( GL_ALL_ATTRIB_BITS );
1236 #endif
1237
1238       // Prepare rendering pass
1239       matrixOrtho( matrix, 0.0, (float)viewportwidth, (float)viewportheight, 0.0, -1.0f, 1.0 );
1240       norminv = 1.0f / DM_VERTEX_NORMFACTOR;
1241       for( mindex = 0 ; mindex < 12 ; mindex += 4 )
1242       {
1243         matrix[mindex+0] *= norminv;
1244         matrix[mindex+1] *= norminv;
1245         matrix[mindex+2] *= norminv;
1246       }
1247       drawBarrierIndex = 0;
1248       orderBarrierMask = drawBarrierIndex << DM_BARRIER_ORDER_SHIFT;
1249       orderBarrierMask = 0;
1250
1251       updateCount++;
1252
1253       if(flags.prehistoricOpenGL)
1254       {
1255          glMatrixMode(MatrixMode::projection);
1256          glLoadMatrixf(matrix);
1257
1258          glMatrixMode(MatrixMode::modelView);
1259          glLoadIdentity();
1260          glScalef(4,4,4);
1261       }
1262    }
1263
1264    void drawImage( DMImage image, int offsetx, int offsety, int sizex, int sizey, uint32 color )
1265    {
1266      DMImageBuffer *imageBuffer;
1267
1268      if( image.flags.empty || ( sizex <= 0 ) || ( sizey <= 0 ) )
1269        return;
1270
1271      if( imageBufferCount >= imageBufferSize )
1272      {
1273        imageBufferSize <<= 1;
1274        this.imageBuffer = renew this.imageBuffer DMImageBuffer[imageBufferSize];
1275        imageBufferTmp = renew imageBufferTmp DMImageBuffer[imageBufferSize];
1276      }
1277
1278      imageBuffer = &this.imageBuffer[ imageBufferCount ];
1279      imageBuffer->image = image;
1280      imageBuffer->offsetx = (short)(offsetx << DM_VERTEX_NORMSHIFT);
1281      imageBuffer->offsety = (short)(offsety << DM_VERTEX_NORMSHIFT);
1282      imageBuffer->sizex = (short)sizex;
1283      imageBuffer->sizey = (short)sizey;
1284    #if DM_ENABLE_IMAGE_ROTATION
1285      imageBuffer->angsin = 0;
1286      imageBuffer->angcos = (short)DM_IMAGE_ROTATION_NORMFACTOR;
1287    #endif
1288      imageBuffer->color = color;
1289      imageBuffer->orderindex = image.orderMask | orderBarrierMask;
1290
1291    #if DM_RENDER_IMAGE_DEBUG
1292    printf( "  Queue image at %d %d, order 0x%x\n", (int)imageBuffer->offsetx, (int)imageBuffer->offsety, (int)imageBuffer->orderindex );
1293    #endif
1294
1295      imageBufferCount++;
1296    }
1297
1298    void drawImageExtColor( DMImage image, int offsetx, int offsety, int sizex, int sizey, uint32 color, uint32 extcolor )
1299    {
1300      DMImageBuffer *imageBuffer;
1301
1302      if( ( image.flags.empty ) || ( sizex <= 0 ) || ( sizey <= 0 ) )
1303        return;
1304
1305      if( imageBufferCount >= imageBufferSize )
1306      {
1307        imageBufferSize <<= 1;
1308        this.imageBuffer = renew this.imageBuffer DMImageBuffer[imageBufferSize];
1309        imageBufferTmp = renew imageBufferTmp DMImageBuffer[imageBufferSize];
1310      }
1311
1312      imageBuffer = &this.imageBuffer[ imageBufferCount ];
1313      imageBuffer->image = image;
1314      imageBuffer->offsetx = (short)(offsetx << DM_VERTEX_NORMSHIFT);
1315      imageBuffer->offsety = (short)(offsety << DM_VERTEX_NORMSHIFT);
1316      imageBuffer->sizex = (short)sizex;
1317      imageBuffer->sizey = (short)sizey;
1318    #if DM_ENABLE_IMAGE_ROTATION
1319      imageBuffer->angsin = 0;
1320      imageBuffer->angcos = (short)DM_IMAGE_ROTATION_NORMFACTOR;
1321    #endif
1322      imageBuffer->color = color;
1323    #if DM_ENABLE_EXT_COLOR
1324      imageBuffer->extcolor = extcolor;
1325    #endif
1326      imageBuffer->orderindex = image.orderMask | orderBarrierMask;
1327
1328    #if DM_RENDER_IMAGE_DEBUG
1329    printf( "  Queue image at %d %d, order 0x%x\n", (int)imageBuffer->offsetx, (int)imageBuffer->offsety, (int)imageBuffer->orderindex );
1330    #endif
1331
1332      this.imageBufferCount++;
1333    }
1334
1335    void drawImageFloat( DMImage image, float offsetx, float offsety, float sizex, float sizey, float angsin, float angcos, uint32 color )
1336    {
1337      DMImageBuffer *imageBuffer;
1338
1339      if( image.flags.empty || sizex <= 0 || sizey <= 0 )
1340        return;
1341
1342      if( imageBufferCount >= imageBufferSize )
1343      {
1344        imageBufferSize <<= 1;
1345        this.imageBuffer = renew this.imageBuffer DMImageBuffer[imageBufferSize];
1346        imageBufferTmp = renew imageBufferTmp DMImageBuffer[imageBufferSize];
1347      }
1348
1349      imageBuffer = &this.imageBuffer[ imageBufferCount ];
1350      imageBuffer->image = image;
1351      imageBuffer->offsetx = (short)roundf(offsetx * DM_VERTEX_NORMFACTOR);
1352      imageBuffer->offsety = (short)roundf(offsety * DM_VERTEX_NORMFACTOR);
1353      imageBuffer->sizex = (short)sizex;
1354      imageBuffer->sizey = (short)sizey;
1355    #if DM_ENABLE_IMAGE_ROTATION
1356      imageBuffer->angsin = (short)roundf( angsin * DM_IMAGE_ROTATION_NORMFACTOR );
1357      imageBuffer->angcos = (short)roundf( angcos * DM_IMAGE_ROTATION_NORMFACTOR );
1358    #endif
1359      imageBuffer->color = color;
1360      imageBuffer->orderindex = image.orderMask | orderBarrierMask;
1361
1362    #if DM_RENDER_IMAGE_DEBUG
1363    printf( "  Queue image at %d %d, order 0x%x\n", (int)imageBuffer->offsetx, (int)imageBuffer->offsety, (int)imageBuffer->orderindex );
1364    #endif
1365
1366      imageBufferCount++;
1367    }
1368
1369    void drawImageFloatExtColor( DMImage image, float offsetx, float offsety, float sizex, float sizey, float angsin, float angcos, uint32 color, uint32 extcolor )
1370    {
1371      DMImageBuffer *imageBuffer;
1372
1373      if( ( image.flags.empty ) || ( sizex <= 0 ) || ( sizey <= 0 ) )
1374        return;
1375
1376      if( this.imageBufferCount >= this.imageBufferSize )
1377      {
1378        imageBufferSize <<= 1;
1379        this.imageBuffer = renew this.imageBuffer DMImageBuffer[imageBufferSize];
1380        imageBufferTmp = renew imageBufferTmp DMImageBuffer[imageBufferSize];
1381      }
1382
1383      imageBuffer = &this.imageBuffer[ imageBufferCount ];
1384      imageBuffer->image = image;
1385      imageBuffer->offsetx = (short)roundf( offsetx * DM_VERTEX_NORMFACTOR );
1386      imageBuffer->offsety = (short)roundf( offsety * DM_VERTEX_NORMFACTOR );
1387      imageBuffer->sizex = (short)sizex;
1388      imageBuffer->sizey = (short)sizey;
1389    #if DM_ENABLE_IMAGE_ROTATION
1390      imageBuffer->angsin = (short)roundf( angsin * DM_IMAGE_ROTATION_NORMFACTOR );
1391      imageBuffer->angcos = (short)roundf( angcos * DM_IMAGE_ROTATION_NORMFACTOR );
1392    #endif
1393      imageBuffer->color = color;
1394    #if DM_ENABLE_EXT_COLOR
1395      imageBuffer->extcolor = extcolor;
1396    #endif
1397      imageBuffer->orderindex = image.orderMask | orderBarrierMask;
1398
1399    #if DM_RENDER_IMAGE_DEBUG
1400    printf( "  Queue image at %d %d, order 0x%x\n", (int)imageBuffer->offsetx, (int)imageBuffer->offsety, (int)imageBuffer->orderindex );
1401    #endif
1402
1403      this.imageBufferCount++;
1404    }
1405
1406    void flushImages( )
1407    {
1408 #if !defined(__EMSCRIPTEN__)
1409      if( flags.prehistoricOpenGL )
1410        flushDrawImagesArchaic( );
1411      else
1412 #endif
1413        flushDrawImages( );
1414
1415      if(vboAvailable)
1416         glBindBuffer( GL_ARRAY_BUFFER, 0 );
1417      glabCurArrayBuffer = 0;
1418      if( !flags.prehistoricOpenGL )
1419          glUseProgram( prevProgram );
1420       // Restore OpenGL state
1421       // FIXME: no glPushAttrib() in core profile
1422 #if !defined(__EMSCRIPTEN__)
1423       glPopAttrib();
1424       glPopClientAttrib();
1425 #endif
1426    }
1427
1428    void drawBarrier( )
1429    {
1430       drawBarrierIndex++;
1431       if( drawBarrierIndex >= ( 1 << DM_BARRIER_ORDER_BITS ) )
1432          flushImages( );
1433       orderBarrierMask = drawBarrierIndex << DM_BARRIER_ORDER_SHIFT;
1434    }
1435 }