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