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