Glide Plugin GLES2 port from mupen64plus-ae, but with special FrameSkip code
[mupen64plus-pandora.git] / source / gles2glide64 / src / Glitch64 / geometry.cpp
1 /*
2 * Glide64 - Glide video plugin for Nintendo 64 emulators.
3 * Copyright (c) 2002  Dave2001
4 * Copyright (c) 2003-2009  Sergey 'Gonetz' Lipski
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include <stdio.h>
22 #include <string.h>
23 #ifdef _WIN32
24 #include <windows.h>
25 #endif // _WIN32
26 #include "glide.h"
27 #include "main.h"
28 #include "../Glide64/winlnxdefs.h"
29 #include "../Glide64/rdp.h"
30
31
32
33 #define Z_MAX (65536.0f)
34 #define VERTEX_SIZE sizeof(VERTEX) //Size of vertex struct
35
36 #ifdef PAULSCODE
37 //#include "ae_bridge.h"
38 static float polygonOffsetFactor;
39 static float polygonOffsetUnits;
40 #endif
41
42 static int xy_off;
43 static int xy_en;
44 static int z_en;
45 static int z_off;
46 static int q_off;
47 static int q_en;
48 static int pargb_off;
49 static int pargb_en;
50 static int st0_off;
51 static int st0_en;
52 static int st1_off;
53 static int st1_en;
54 static int fog_ext_off;
55 static int fog_ext_en;
56
57 int w_buffer_mode;
58 int inverted_culling;
59 int culling_mode;
60
61 #define VERTEX_BUFFER_SIZE 1500 //Max amount of vertices to buffer, this seems large enough.
62 static VERTEX vertex_buffer[VERTEX_BUFFER_SIZE];
63 static int vertex_buffer_count = 0;
64 static GLenum vertex_draw_mode;
65 static bool vertex_buffer_enabled = false;
66
67 void vbo_init()
68 {
69   
70 }
71
72 void vbo_draw()
73 {
74   if(vertex_buffer_count)
75   {
76     glDrawArrays(vertex_draw_mode,0,vertex_buffer_count);
77     vertex_buffer_count = 0;
78   }
79 }
80
81 #ifdef PAULSCODE
82 void vbo_resetcount()
83 {
84         vertex_buffer_count = 0;
85 }
86 #endif
87
88 //Buffer vertices instead of glDrawArrays(...)
89 void vbo_buffer(GLenum mode,GLint first,GLsizei count,void* pointers)
90 {
91   if((count != 3 && mode != GL_TRIANGLES) || vertex_buffer_count + count > VERTEX_BUFFER_SIZE)
92   {
93     vbo_draw();
94   }
95
96   memcpy(&vertex_buffer[vertex_buffer_count],pointers,count * VERTEX_SIZE);
97   vertex_buffer_count += count;
98
99   if(count == 3 || mode == GL_TRIANGLES)
100   {
101     vertex_draw_mode = GL_TRIANGLES;
102   }
103   else
104   {
105     vertex_draw_mode = mode;
106     vbo_draw(); //Triangle fans and strips can't be joined as easily, just draw them straight away.
107   }
108
109
110 }
111
112 void vbo_enable()
113 {
114   if(vertex_buffer_enabled)
115     return;
116
117   vertex_buffer_enabled = true;
118   glEnableVertexAttribArray(POSITION_ATTR);
119   glVertexAttribPointer(POSITION_ATTR, 4, GL_FLOAT, false, VERTEX_SIZE, &vertex_buffer[0].x); //Position
120
121   glEnableVertexAttribArray(COLOUR_ATTR);
122   glVertexAttribPointer(COLOUR_ATTR, 4, GL_UNSIGNED_BYTE, true, VERTEX_SIZE, &vertex_buffer[0].b); //Colour
123
124   glEnableVertexAttribArray(TEXCOORD_0_ATTR);
125   glVertexAttribPointer(TEXCOORD_0_ATTR, 2, GL_FLOAT, false, VERTEX_SIZE, &vertex_buffer[0].coord[2]); //Tex0
126
127   glEnableVertexAttribArray(TEXCOORD_1_ATTR);
128   glVertexAttribPointer(TEXCOORD_1_ATTR, 2, GL_FLOAT, false, VERTEX_SIZE, &vertex_buffer[0].coord[0]); //Tex1
129
130   glEnableVertexAttribArray(FOG_ATTR);
131   glVertexAttribPointer(FOG_ATTR, 1, GL_FLOAT, false, VERTEX_SIZE, &vertex_buffer[0].f); //Fog
132 }
133
134 void vbo_disable()
135 {
136   vbo_draw();
137   vertex_buffer_enabled = false;
138 }
139
140
141 inline float ZCALC(const float & z, const float & q) {
142   float res = z_en ? ((z) / Z_MAX) / (q) : 1.0f;
143   return res;
144 }
145
146 /*
147 #define zclamp (1.0f-1.0f/zscale)
148 static inline void zclamp_glVertex4f(float a, float b, float c, float d)
149 {
150   if (c<zclamp) c = zclamp;
151   glVertex4f(a,b,c,d);
152 }
153 #define glVertex4f(a,b,c,d) zclamp_glVertex4f(a,b,c,d)
154 */
155
156
157 static inline float ytex(int tmu, float y) {
158   if (invtex[tmu])
159     return invtex[tmu] - y;
160   else
161     return y;
162 }
163
164 void init_geometry()
165 {
166   xy_en = q_en = pargb_en = st0_en = st1_en = z_en = 0;
167   w_buffer_mode = 0;
168   inverted_culling = 0;
169
170   glDisable(GL_CULL_FACE);
171   glDisable(GL_DEPTH_TEST);
172
173   vbo_init();
174 }
175
176 FX_ENTRY void FX_CALL
177 grCoordinateSpace( GrCoordinateSpaceMode_t mode )
178 {
179   LOG("grCoordinateSpace(%d)\r\n", mode);
180   switch(mode)
181   {
182   case GR_WINDOW_COORDS:
183     break;
184   default:
185     display_warning("unknwown coordinate space : %x", mode);
186   }
187 }
188
189 FX_ENTRY void FX_CALL
190 grVertexLayout(FxU32 param, FxI32 offset, FxU32 mode)
191 {
192   LOG("grVertexLayout(%d,%d,%d)\r\n", param, offset, mode);
193   switch(param)
194   {
195   case GR_PARAM_XY:
196     xy_en = mode;
197     xy_off = offset;
198     break;
199   case GR_PARAM_Z:
200     z_en = mode;
201     z_off = offset;
202     break;
203   case GR_PARAM_Q:
204     q_en = mode;
205     q_off = offset;
206     break;
207   case GR_PARAM_FOG_EXT:
208     fog_ext_en = mode;
209     fog_ext_off = offset;
210     break;
211   case GR_PARAM_PARGB:
212     pargb_en = mode;
213     pargb_off = offset;
214     break;
215   case GR_PARAM_ST0:
216     st0_en = mode;
217     st0_off = offset;
218     break;
219   case GR_PARAM_ST1:
220     st1_en = mode;
221     st1_off = offset;
222     break;
223   default:
224     display_warning("unknown grVertexLayout parameter : %x", param);
225   }
226 }
227
228 FX_ENTRY void FX_CALL
229 grCullMode( GrCullMode_t mode )
230 {
231   LOG("grCullMode(%d)\r\n", mode);
232   static int oldmode = -1, oldinv = -1;
233   culling_mode = mode;
234   if (inverted_culling == oldinv && oldmode == mode)
235     return;
236   oldmode = mode;
237   oldinv = inverted_culling;
238   switch(mode)
239   {
240   case GR_CULL_DISABLE:
241     glDisable(GL_CULL_FACE);
242     break;
243   case GR_CULL_NEGATIVE:
244     if (!inverted_culling)
245       glCullFace(GL_FRONT);
246     else
247       glCullFace(GL_BACK);
248     glEnable(GL_CULL_FACE);
249     break;
250   case GR_CULL_POSITIVE:
251     if (!inverted_culling)
252       glCullFace(GL_BACK);
253     else
254       glCullFace(GL_FRONT);
255     glEnable(GL_CULL_FACE);
256     break;
257   default:
258     display_warning("unknown cull mode : %x", mode);
259   }
260 }
261
262 // Depth buffer
263
264 FX_ENTRY void FX_CALL
265 grDepthBufferMode( GrDepthBufferMode_t mode )
266 {
267   LOG("grDepthBufferMode(%d)\r\n", mode);
268   switch(mode)
269   {
270   case GR_DEPTHBUFFER_DISABLE:
271     glDisable(GL_DEPTH_TEST);
272     w_buffer_mode = 0;
273     return;
274   case GR_DEPTHBUFFER_WBUFFER:
275   case GR_DEPTHBUFFER_WBUFFER_COMPARE_TO_BIAS:
276     glEnable(GL_DEPTH_TEST);
277     w_buffer_mode = 1;
278     break;
279   case GR_DEPTHBUFFER_ZBUFFER:
280   case GR_DEPTHBUFFER_ZBUFFER_COMPARE_TO_BIAS:
281     glEnable(GL_DEPTH_TEST);
282     w_buffer_mode = 0;
283     break;
284   default:
285     display_warning("unknown depth buffer mode : %x", mode);
286   }
287 }
288
289 FX_ENTRY void FX_CALL
290 grDepthBufferFunction( GrCmpFnc_t function )
291 {
292   LOG("grDepthBufferFunction(%d)\r\n", function);
293   switch(function)
294   {
295   case GR_CMP_GEQUAL:
296     if (w_buffer_mode)
297       glDepthFunc(GL_LEQUAL);
298     else
299       glDepthFunc(GL_GEQUAL);
300     break;
301   case GR_CMP_LEQUAL:
302     if (w_buffer_mode)
303       glDepthFunc(GL_GEQUAL);
304     else
305       glDepthFunc(GL_LEQUAL);
306     break;
307   case GR_CMP_LESS:
308     if (w_buffer_mode)
309       glDepthFunc(GL_GREATER);
310     else
311       glDepthFunc(GL_LESS);
312     break;
313   case GR_CMP_ALWAYS:
314     glDepthFunc(GL_ALWAYS);
315     break;
316   case GR_CMP_EQUAL:
317     glDepthFunc(GL_EQUAL);
318     break;
319   case GR_CMP_GREATER:
320     if (w_buffer_mode)
321       glDepthFunc(GL_LESS);
322     else
323       glDepthFunc(GL_GREATER);
324     break;
325   case GR_CMP_NEVER:
326     glDepthFunc(GL_NEVER);
327     break;
328   case GR_CMP_NOTEQUAL:
329     glDepthFunc(GL_NOTEQUAL);
330     break;
331
332   default:
333     display_warning("unknown depth buffer function : %x", function);
334   }
335 }
336
337 FX_ENTRY void FX_CALL
338 grDepthMask( FxBool mask )
339 {
340   LOG("grDepthMask(%d)\r\n", mask);
341   glDepthMask(mask);
342 }
343
344 float biasFactor = 0;
345 void FindBestDepthBias()
346 {
347 #ifdef PAULSCODE
348 /*  int hardwareType = Android_JNI_GetHardwareType();
349   Android_JNI_GetPolygonOffset(hardwareType, 1, &polygonOffsetFactor, &polygonOffsetUnits);*/
350 //  glPolygonOffset(0.2f, 0.2f);
351         polygonOffsetFactor=0.2f;
352         polygonOffsetUnits=0.2f;
353 #else
354   float f, bestz = 0.25f;
355   int x;
356   if (biasFactor) return;
357   biasFactor = 64.0f; // default value
358   glPushAttrib(GL_ALL_ATTRIB_BITS);
359   glEnable(GL_DEPTH_TEST);
360   glDepthFunc(GL_ALWAYS);
361   glEnable(GL_POLYGON_OFFSET_FILL);
362   glDrawBuffer(GL_BACK);
363   glReadBuffer(GL_BACK);
364   glDisable(GL_BLEND);
365   glDisable(GL_ALPHA_TEST);
366   glColor4ub(255,255,255,255);
367   glDepthMask(GL_TRUE);
368   for (x=0, f=1.0f; f<=65536.0f; x+=4, f*=2.0f) {
369     float z;
370     glPolygonOffset(0, f);
371     glBegin(GL_TRIANGLE_STRIP);
372     glVertex3f(float(x+4 - widtho)/(width/2), float(0 - heighto)/(height/2), 0.5);
373     glVertex3f(float(x - widtho)/(width/2), float(0 - heighto)/(height/2), 0.5);
374     glVertex3f(float(x+4 - widtho)/(width/2), float(4 - heighto)/(height/2), 0.5);
375     glVertex3f(float(x - widtho)/(width/2), float(4 - heighto)/(height/2), 0.5);
376     glEnd();
377     glReadPixels(x+2, 2+viewport_offset, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &z);
378     z -= 0.75f + 8e-6f;
379     if (z<0.0f) z = -z;
380     if (z > 0.01f) continue;
381     if (z < bestz) {
382       bestz = z;
383       biasFactor = f;
384     }
385     //printf("f %g z %g\n", f, z);
386   }
387   //printf(" --> bias factor %g\n", biasFactor);
388   glPopAttrib();
389 #endif
390 }
391
392 FX_ENTRY void FX_CALL
393 grDepthBiasLevel( FxI32 level )
394 {
395   LOG("grDepthBiasLevel(%d)\r\n", level);
396   if (level)
397   {
398     #ifdef PAULSCODE
399     glPolygonOffset(polygonOffsetFactor, polygonOffsetUnits);
400 /*    if(w_buffer_mode)
401       glPolygonOffset(1.0f, -(float)level*polygonOffsetUnits);
402     else
403       glPolygonOffset(0, (float)level*3.0f);*/
404     #else
405     if(w_buffer_mode)
406       glPolygonOffset(1.0f, -(float)level*zscale/255.0f);
407     else
408       glPolygonOffset(0, (float)level*biasFactor);
409     #endif
410     glEnable(GL_POLYGON_OFFSET_FILL);
411   }
412   else
413   {
414     glPolygonOffset(0,0);
415     glDisable(GL_POLYGON_OFFSET_FILL);
416   }
417 }
418
419 // draw
420
421 FX_ENTRY void FX_CALL
422 grDrawTriangle( const void *a, const void *b, const void *c )
423 {
424   LOG("grDrawTriangle()\r\n\t");
425 /*  
426   if(nvidia_viewport_hack && !render_to_texture)
427   {
428     glViewport(0, viewport_offset, viewport_width, viewport_height);
429     nvidia_viewport_hack = 0;
430   }
431 */
432   reloadTexture();
433
434   if(need_to_compile) compile_shader();
435
436   if(vertex_buffer_count + 3 > VERTEX_BUFFER_SIZE)
437   {
438     vbo_draw();
439   }
440   vertex_draw_mode = GL_TRIANGLES;
441   memcpy(&vertex_buffer[vertex_buffer_count],a,VERTEX_SIZE);
442   memcpy(&vertex_buffer[vertex_buffer_count+1],b,VERTEX_SIZE);
443   memcpy(&vertex_buffer[vertex_buffer_count+2],c,VERTEX_SIZE);
444   vertex_buffer_count += 3;
445 }
446
447 FX_ENTRY void FX_CALL
448 grDrawPoint( const void *pt )
449 {
450 /*
451   float *x = (float*)pt + xy_off/sizeof(float);
452   float *y = (float*)pt + xy_off/sizeof(float) + 1;
453   float *z = (float*)pt + z_off/sizeof(float);
454   float *q = (float*)pt + q_off/sizeof(float);
455   unsigned char *pargb = (unsigned char*)pt + pargb_off;
456   float *s0 = (float*)pt + st0_off/sizeof(float);
457   float *t0 = (float*)pt + st0_off/sizeof(float) + 1;
458   float *s1 = (float*)pt + st1_off/sizeof(float);
459   float *t1 = (float*)pt + st1_off/sizeof(float) + 1;
460   float *fog = (float*)pt + fog_ext_off/sizeof(float);
461   LOG("grDrawPoint()\r\n");
462
463   if(nvidia_viewport_hack && !render_to_texture)
464   {
465     glViewport(0, viewport_offset, viewport_width, viewport_height);
466     nvidia_viewport_hack = 0;
467   }
468
469   reloadTexture();
470
471   if(need_to_compile) compile_shader();
472
473   glBegin(GL_POINTS);
474
475   if (nbTextureUnits > 2)
476   {
477     if (st0_en)
478       glMultiTexCoord2fARB(GL_TEXTURE1_ARB, *s0 / *q / (float)tex1_width,
479       ytex(0, *t0 / *q / (float)tex1_height));
480     if (st1_en)
481       glMultiTexCoord2fARB(GL_TEXTURE0_ARB, *s1 / *q / (float)tex0_width,
482       ytex(1, *t1 / *q / (float)tex0_height));
483   }
484   else
485   {
486     if (st0_en)
487       glTexCoord2f(*s0 / *q / (float)tex0_width,
488       ytex(0, *t0 / *q / (float)tex0_height));
489   }
490   if (pargb_en)
491     glColor4f(pargb[2]/255.0f, pargb[1]/255.0f, pargb[0]/255.0f, pargb[3]/255.0f);
492   if (fog_enabled && fog_coord_support)
493   {
494     if(!fog_ext_en || fog_enabled != 2)
495       glSecondaryColor3f((1.0f / *q) / 255.0f, 0.0f, 0.0f);
496     else
497       glSecondaryColor3f((1.0f / *fog) / 255.0f, 0.0f, 0.0f);
498   }
499   glVertex4f((*x - (float)widtho) / (float)(width/2) / *q,
500     -(*y - (float)heighto) / (float)(height/2) / *q, ZCALC(*z ,*q), 1.0f / *q);
501
502   glEnd();
503 */
504 }
505
506 FX_ENTRY void FX_CALL
507 grDrawLine( const void *a, const void *b )
508 {
509 /*
510   float *a_x = (float*)a + xy_off/sizeof(float);
511   float *a_y = (float*)a + xy_off/sizeof(float) + 1;
512   float *a_z = (float*)a + z_off/sizeof(float);
513   float *a_q = (float*)a + q_off/sizeof(float);
514   unsigned char *a_pargb = (unsigned char*)a + pargb_off;
515   float *a_s0 = (float*)a + st0_off/sizeof(float);
516   float *a_t0 = (float*)a + st0_off/sizeof(float) + 1;
517   float *a_s1 = (float*)a + st1_off/sizeof(float);
518   float *a_t1 = (float*)a + st1_off/sizeof(float) + 1;
519   float *a_fog = (float*)a + fog_ext_off/sizeof(float);
520
521   float *b_x = (float*)b + xy_off/sizeof(float);
522   float *b_y = (float*)b + xy_off/sizeof(float) + 1;
523   float *b_z = (float*)b + z_off/sizeof(float);
524   float *b_q = (float*)b + q_off/sizeof(float);
525   unsigned char *b_pargb = (unsigned char*)b + pargb_off;
526   float *b_s0 = (float*)b + st0_off/sizeof(float);
527   float *b_t0 = (float*)b + st0_off/sizeof(float) + 1;
528   float *b_s1 = (float*)b + st1_off/sizeof(float);
529   float *b_t1 = (float*)b + st1_off/sizeof(float) + 1;
530   float *b_fog = (float*)b + fog_ext_off/sizeof(float);
531   LOG("grDrawLine()\r\n");
532
533   if(nvidia_viewport_hack && !render_to_texture)
534   {
535     glViewport(0, viewport_offset, viewport_width, viewport_height);
536     nvidia_viewport_hack = 0;
537   }
538
539   reloadTexture();
540
541   if(need_to_compile) compile_shader();
542
543   glBegin(GL_LINES);
544
545   if (nbTextureUnits > 2)
546   {
547     if (st0_en)
548       glMultiTexCoord2fARB(GL_TEXTURE1_ARB, *a_s0 / *a_q / (float)tex1_width, ytex(0, *a_t0 / *a_q / (float)tex1_height));
549     if (st1_en)
550       glMultiTexCoord2fARB(GL_TEXTURE0_ARB, *a_s1 / *a_q / (float)tex0_width, ytex(1, *a_t1 / *a_q / (float)tex0_height));
551   }
552   else
553   {
554     if (st0_en)
555       glTexCoord2f(*a_s0 / *a_q / (float)tex0_width, ytex(0, *a_t0 / *a_q / (float)tex0_height));
556   }
557   if (pargb_en)
558     glColor4f(a_pargb[2]/255.0f, a_pargb[1]/255.0f, a_pargb[0]/255.0f, a_pargb[3]/255.0f);
559   if (fog_enabled && fog_coord_support)
560   {
561     if(!fog_ext_en || fog_enabled != 2)
562       glSecondaryColor3f((1.0f / *a_q) / 255.0f, 0.0f, 0.0f);
563     else
564       glSecondaryColor3f((1.0f / *a_fog) / 255.0f, 0.0f, 0.0f);
565   }
566   glVertex4f((*a_x - (float)widtho) / (float)(width/2) / *a_q,
567     -(*a_y - (float)heighto) / (float)(height/2) / *a_q, ZCALC(*a_z, *a_q), 1.0f / *a_q);
568
569   if (nbTextureUnits > 2)
570   {
571     if (st0_en)
572       glMultiTexCoord2fARB(GL_TEXTURE1_ARB, *b_s0 / *b_q / (float)tex1_width,
573       ytex(0, *b_t0 / *b_q / (float)tex1_height));
574     if (st1_en)
575       glMultiTexCoord2fARB(GL_TEXTURE0_ARB, *b_s1 / *b_q / (float)tex0_width,
576       ytex(1, *b_t1 / *b_q / (float)tex0_height));
577   }
578   else
579   {
580     if (st0_en)
581       glTexCoord2f(*b_s0 / *b_q / (float)tex0_width,
582       ytex(0, *b_t0 / *b_q / (float)tex0_height));
583   }
584   if (pargb_en)
585     glColor4f(b_pargb[2]/255.0f, b_pargb[1]/255.0f, b_pargb[0]/255.0f, b_pargb[3]/255.0f);
586   if (fog_enabled && fog_coord_support)
587   {
588     if(!fog_ext_en || fog_enabled != 2)
589       glSecondaryColor3f((1.0f / *b_q) / 255.0f, 0.0f, 0.0f);
590     else
591       glSecondaryColor3f((1.0f / *b_fog) / 255.0f, 0.0f, 0.0f);
592   }
593   glVertex4f((*b_x - (float)widtho) / (float)(width/2) / *b_q,
594     -(*b_y - (float)heighto) / (float)(height/2) / *b_q, ZCALC(*b_z, *b_q), 1.0f / *b_q);
595
596   glEnd();
597 */
598 }
599
600 FX_ENTRY void FX_CALL
601 grDrawVertexArray(FxU32 mode, FxU32 Count, void *pointers2)
602 {
603   void **pointers = (void**)pointers2;
604   LOG("grDrawVertexArray(%d,%d)\r\n", mode, Count);
605 /*
606   if(nvidia_viewport_hack && !render_to_texture)
607   {
608     glViewport(0, viewport_offset, viewport_width, viewport_height);
609     nvidia_viewport_hack = 0;
610   }
611 */
612   reloadTexture();
613
614   if(need_to_compile) compile_shader();
615
616   if(mode != GR_TRIANGLE_FAN)
617   {
618     display_warning("grDrawVertexArray : unknown mode : %x", mode);
619   }
620
621   vbo_enable();
622   vbo_buffer(GL_TRIANGLE_FAN,0,Count,pointers[0]);
623 }
624
625 FX_ENTRY void FX_CALL
626 grDrawVertexArrayContiguous(FxU32 mode, FxU32 Count, void *pointers, FxU32 stride)
627 {
628   LOG("grDrawVertexArrayContiguous(%d,%d,%d)\r\n", mode, Count, stride);
629 /*
630   if(nvidia_viewport_hack && !render_to_texture)
631   {
632     glViewport(0, viewport_offset, viewport_width, viewport_height);
633     nvidia_viewport_hack = 0;
634   }
635 */
636   if(stride != 156)
637   {
638           LOGINFO("Incompatible stride\n");
639   }
640
641   reloadTexture();
642
643   if(need_to_compile) compile_shader();
644
645   vbo_enable();
646
647   switch(mode)
648   {
649   case GR_TRIANGLE_STRIP:
650     vbo_buffer(GL_TRIANGLE_STRIP,0,Count,pointers);
651     break;
652   case GR_TRIANGLE_FAN:
653     vbo_buffer(GL_TRIANGLE_FAN,0,Count,pointers);
654     break;
655   default:
656     display_warning("grDrawVertexArrayContiguous : unknown mode : %x", mode);
657   }
658 }