f70b120ba1e1c2436cbdacfe3e7d6d4d2e7d774d
[xscreensaver] / hacks / glx / jwzgles.c
1 /* xscreensaver, Copyright (c) 2012 Jamie Zawinski <jwz@jwz.org>
2  *
3  * Permission to use, copy, modify, distribute, and sell this software and its
4  * documentation for any purpose is hereby granted without fee, provided that
5  * the above copyright notice appear in all copies and that both that
6  * copyright notice and this permission notice appear in supporting
7  * documentation.  No representations are made about the suitability of this
8  * software for any purpose.  It is provided "as is" without express or 
9  * implied warranty.
10  */
11
12 /* A compatibility shim to allow OpenGL 1.3 source code to work in an
13    OpenGLES environment, where almost every OpenGL 1.3 function has
14    been "deprecated".
15
16    There are two major operations going on here:
17
18      - Converting calls to glBegin + glVertex3f + glEnd to glDrawArrays
19      - Implementing display lists.
20
21
22    From an API point of view, OpenGL 1.3 and earlier code looks like this:
23
24       glLightfv (GL_LIGHT0, GL_POSITION, ...);
25       glLightfv (GL_LIGHT0, GL_AMBIENT,  ...);
26
27       glMatrixMode (GL_PROJECTION);
28       glLoadIdentity ();
29       gluPerspective (...);
30
31       glMatrixMode (GL_MODELVIEW);
32       glLoadIdentity ();
33       gluLookAt (...);
34
35       glPushMatrix ();
36
37       glRotatef (...);
38
39       glColor3f (...);
40
41       glBegin (GL_TRIANGLES);
42       glNormal3f (...);
43       glVertex3f (...);
44       glVertex3f (...);
45       glVertex3f (...);
46       glEnd ();
47
48       glPopMatrix ();
49
50       glFinish ();
51
52
53    OpenGLES broke that model by eliminating glBegin().  Instead of
54    iterating a sequence of vertexes, you need to pack your points into
55    an array first, e.g.:
56
57       GLfloat coords[] = {
58          0, 0, 0,
59          0, 1, 0,
60          ...
61       };
62
63       glDrawArrays (GL_TRIANGLES, 0, 3);
64
65    The projection model (glRotatef, etc.) works the same, but glColor()
66    is missing.  You're expected to encode that into your arrays.
67
68    Also, OpenGLES doesn't support display lists at all.
69
70
71    So this code shadows all of the functions that are allowed within
72    glBegin, builds up an array, and calls glDrawArrays at the end.
73
74    Likewise, it shadows all of the functions that are allowed within
75    glNewList and records those calls for later playback.
76
77
78    This code only handles OpenGLES 1.x, not 2.x.
79
80    OpenGLES 2.0 broke things further by eliminating the whole OpenGL
81    lighting model.  Instead of specifying the positions and properties
82    of your lights using the glLight* API, now you are expected to
83    implement it all yourself by downloading C-like code into the GPU
84    directly.  This is more flexible, in that if you wanted a completely
85    different lighting model than what OpenGL provides, you could do
86    that, but it leaves you needing to download boilerplate to reproduce
87    what used to be built in.
88
89
90    Incidentally, the OpenGL numbering scheme goes something like this:
91
92    OpenGL   1.0  1992
93    OpenGL   1.1  1997 (improved texture support)
94    OpenGL   1.2  1998 (nothing interesting)
95    OpenGL   1.3  2001 (multisampling, cubemaps)
96    OpenGL   1.4  2002 (added auto-mipmapping)
97    OpenGLES 1.0  2003 (deprecated 80% of the language; fork of OpenGL 1.3)
98    OpenGL   1.5  2003 (added VBOs)
99    OpenGLES 1.1  2004 (fork of OpenGL 1.5)
100    OpenGL   2.0  2004 (a political quagmire)
101    OpenGLES 2.0  2007 (deprecated 95% of the language; fork of OpenGL 2.0)
102    OpenGL   3.0  2008 (added FBOs, VAOs, deprecated 60% of the language)
103
104
105    Some things that are missing:
106
107     - glTexGeni, meaning no spherical environment-mapping textures.
108
109     - gluNewTess, meaning no tesselation of complex objects.
110
111     - glMap2f mesh evaluators, meaning no Utah Teapot.
112
113     - glPolygonMode with GL_LINE or GL_POINT, meaning no wireframe modes
114       that do hidden-surface removal.
115
116     - glSelectBuffer, meaning no mouse-hit detection on rendered objects.
117
118     - gluNewQuadric, gluCylinder, etc: rewrite your code to use tube.c, etc.
119
120     - Putting verts in a display list without a wrapping glBegin.
121       (I didn't realize that even worked!)
122
123     - Not every function is implemented; just the ones that I needed for
124       xscreensaver.  However, the trivial ones are trivial to enable
125       as they come up.  Harder ones will be harder.
126
127    As a result of that, these savers look wrong:
128
129       blocktube       Uses SPHERE_MAP.
130       bouncingcow     Uses OBJECT_LINEAR (when run with -texture)
131       dnalogo         Uses GLUtesselator.
132       extrusion       Uses all kinds of GLUT crap.
133       flyingtoasters  Uses SPHERE_MAP and OBJECT_LINEAR.
134       jigglypuff      Uses SPHERE_MAP (in chrome mode), GL_LINE (in wireframe)
135       jigsaw          Uses GLUtesselator.
136       lockward        Puts verts in lists without glBegin!
137       pinion          Uses glSelectBuffer and gluPickMatrix for mouse-clicks.
138       pipes           Uses glMap2f for the Utah Teapot.
139       polyhedra       Uses GLUtesselator (concave objects); also Utah Teapot.
140       skytentacles    Uses GL_LINE in -cel mode.
141       timetunnel      Uses GL_CONSTANT_ALPHA and all kinds of other stuff.
142
143 */
144
145
146 #undef DEBUG
147
148
149 #ifdef HAVE_CONFIG_H
150 # include "config.h"
151 #endif /* HAVE_CONFIG_H */
152
153 #ifdef HAVE_JWZGLES     /* whole file */
154
155 #include <stdio.h>
156 #include <string.h>
157 #include <stdlib.h>
158 #include <ctype.h>
159 #include <math.h>
160 #ifdef HAVE_UNISTD_H
161 # include <unistd.h>
162 #endif /* HAVE_UNISTD_H */
163
164 #if defined(USE_IPHONE)
165 # include <OpenGLES/ES1/gl.h>
166 # include <OpenGLES/ES1/glext.h>
167 #elif defined(HAVE_COCOA)
168 # include <OpenGL/gl.h>
169 # include <OpenGL/glu.h>
170 #else /* X11 */
171 # ifndef  GL_GLEXT_PROTOTYPES
172 #  define GL_GLEXT_PROTOTYPES /* for glBindBuffer */
173 # endif
174 # include <GL/glx.h>
175 # include <GL/glu.h>
176 #endif
177
178 #include "jwzglesI.h"
179
180 #define STRINGIFY(X) #X
181
182 #undef countof
183 #define countof(x) (sizeof((x))/sizeof((*x)))
184
185 #undef  Assert
186
187 #ifdef HAVE_COCOA
188   extern void jwxyz_abort (const char *fmt, ...) __dead2;
189 # define Assert(C,S) do { if (!(C)) { jwxyz_abort ("%s",S); }} while(0)
190 #else
191 # define Assert(C,S) do { \
192     if (!(C)) { \
193       fprintf (stderr, "jwzgles: %s\n", S); \
194       abort(); \
195     }} while(0)
196 #endif
197
198
199 typedef struct { GLfloat x, y, z; }    XYZ;
200 typedef struct { GLfloat x, y, z, w; } XYZW;
201 typedef struct { GLfloat s, t, r, q; } STRQ;
202 typedef struct { GLfloat r, g, b, a; } RGBA;
203
204
205 /* Used to record all calls to glVertex3f, glNormal3f, etc. 
206    while inside glBegin / glEnd so that we can convert that
207    to a single call to glDrawArrays.
208  */
209 typedef struct {
210   int mode;
211   int count, size;      /* size of each array */
212
213   XYZW *verts;          /* Arrays being built */
214   XYZ  *norms;
215   STRQ *tex;
216   RGBA *color;
217
218   int ncount;           /* How many normals, tex coords and colors were */
219   int tcount;           /* used.  We optimize based on "0, 1, or many". */
220   int ccount;
221   int materialistic;    /* Whether glMaterial was called inside glBegin */
222
223   XYZ  cnorm;           /* Prevailing normal/texture/color while building */
224   STRQ ctex;
225   RGBA ccolor;
226
227 } vert_set;
228
229
230 typedef void (*list_fn_cb) (void);
231
232
233 /* We need this nonsense because you can't cast a double to a void*
234    or vice versa.  They tend to be passed in different registers,
235    and you need to know about that because it's still 1972 here.
236  */
237 typedef union { const void *v; GLfloat f; GLuint i; } void_int;
238
239 typedef struct {                /* saved args for glDrawArrays */
240   int binding, size, type, stride, bytes;
241   void *data;
242 } draw_array;
243
244 typedef enum {                  /* shorthand describing arglist signature */
245   PROTO_VOID,   /* no args */
246   PROTO_I,      /* 1 int arg */
247   PROTO_F,      /* 1 float arg */
248   PROTO_II,     /* int, int */
249   PROTO_FF,     /* float, float */
250   PROTO_IF,     /* int, float */
251   PROTO_III,    /* int, int, int */
252   PROTO_FFF,    /* float, float, float */
253   PROTO_IIF,    /* int, int, float */
254   PROTO_IIII,   /* int, int, int, int */
255   PROTO_FFFF,   /* float, float, float, float */
256   PROTO_IIV,    /* int, int[4] */
257   PROTO_IFV,    /* int, float[4] */
258   PROTO_IIIV,   /* int, int, int[4] */
259   PROTO_IIFV,   /* int, int, float[4] */
260   PROTO_FV16,   /* float[16] */
261   PROTO_ARRAYS  /* glDrawArrays */
262 } fn_proto;
263
264 typedef struct {                /* A single element of a display list */
265   const char *name;
266   list_fn_cb fn;                /* saved function pointer */
267   fn_proto proto;               /* arglist prototype */
268   draw_array *arrays;           /* args for glDrawArrays */
269   void_int argv[16];            /* args for everything else */
270 } list_fn;
271
272
273 typedef struct {        /* a display list: saved activity within glNewList */
274   int id;
275   int size, count;
276   list_fn *fns;
277
278   /* Named buffer that should be freed when this display list is deleted. */
279   GLuint buffer;
280
281 } list;
282
283
284 typedef struct {        /* All display lists */
285   list *lists;
286   int count, size;
287 } list_set;
288
289
290 #define ISENABLED_TEXTURE_2D    (1<<0)
291 #define ISENABLED_TEXTURE_GEN_S (1<<1)
292 #define ISENABLED_TEXTURE_GEN_T (1<<2)
293 #define ISENABLED_LIGHTING      (1<<3)
294 #define ISENABLED_BLEND         (1<<4)
295 #define ISENABLED_DEPTH_TEST    (1<<5)
296 #define ISENABLED_CULL_FACE     (1<<6)
297 #define ISENABLED_NORMALIZE     (1<<7)
298 #define ISENABLED_FOG           (1<<8)
299 #define ISENABLED_COLMAT        (1<<9)
300 #define ISENABLED_VERT_ARRAY    (1<<10)
301 #define ISENABLED_NORM_ARRAY    (1<<11)
302 #define ISENABLED_TEX_ARRAY     (1<<12)
303 #define ISENABLED_COLOR_ARRAY   (1<<13)
304
305
306 typedef struct {        /* global state */
307
308   vert_set set;         /* set being built */
309
310   int compiling_list;   /* list id if inside glNewList; 0 means immediate */
311   int replaying_list;   /* depth of call stack to glCallList */
312   int compiling_verts;  /* inside glBegin */
313
314   list_set lists;       /* saved lists */
315   unsigned long enabled;
316
317 } jwzgles_state;
318
319
320 static jwzgles_state global_state = { { 0, }, 0, 0, 0, { 0, }, 0, };
321 static jwzgles_state *state = &global_state;
322
323
324 #ifdef DEBUG
325 # define LOG(A)                fprintf(stderr,"jwzgles: " A "\n")
326 # define LOG1(A,B)             fprintf(stderr,"jwzgles: " A "\n",B)
327 # define LOG2(A,B,C)           fprintf(stderr,"jwzgles: " A "\n",B,C)
328 # define LOG3(A,B,C,D)         fprintf(stderr,"jwzgles: " A "\n",B,C,D)
329 # define LOG4(A,B,C,D,E)       fprintf(stderr,"jwzgles: " A "\n",B,C,D,E)
330 # define LOG5(A,B,C,D,E,F)     fprintf(stderr,"jwzgles: " A "\n",B,C,D,E,F)
331 # define LOG6(A,B,C,D,E,F,G)   fprintf(stderr,"jwzgles: " A "\n",B,C,D,E,F,G)
332 # define LOG7(A,B,C,D,E,F,G,H) fprintf(stderr,"jwzgles: " A "\n",B,C,D,E,F,G,H)
333 # define LOG8(A,B,C,D,E,F,G,H,I)\
334          fprintf(stderr,"jwzgles: "A "\n",B,C,D,E,F,G,H,I)
335 # define LOG9(A,B,C,D,E,F,G,H,I,J)\
336          fprintf(stderr,"jwzgles: "A "\n",B,C,D,E,F,G,H,I,J)
337 # define LOG10(A,B,C,D,E,F,G,H,I,J,K)\
338          fprintf(stderr,"jwzgles: "A "\n",B,C,D,E,F,G,H,I,J,K)
339 # define LOG17(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R)\
340          fprintf(stderr,"jwzgles: "A "\n",B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R)
341 # define CHECK(S) check_gl_error(S)
342 #else
343 # define LOG(A)                       /* */
344 # define LOG1(A,B)                    /* */
345 # define LOG2(A,B,C)                  /* */
346 # define LOG3(A,B,C,D)                /* */
347 # define LOG4(A,B,C,D,E)              /* */
348 # define LOG5(A,B,C,D,E,F)            /* */
349 # define LOG6(A,B,C,D,E,F,G)          /* */
350 # define LOG7(A,B,C,D,E,F,G,H)        /* */
351 # define LOG8(A,B,C,D,E,F,G,H,I)      /* */
352 # define LOG9(A,B,C,D,E,F,G,H,I,J)    /* */
353 # define LOG10(A,B,C,D,E,F,G,H,I,J,K) /* */
354 # define LOG17(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R) /* */
355 # define CHECK(S)              /* */
356 #endif
357
358 #ifdef DEBUG
359 static const char *
360 mode_desc (int mode)    /* for debugging messages */
361 {
362   switch (mode) {
363 # define SS(X) case GL_##X: return STRINGIFY(X);
364   SS(ALPHA)
365   SS(ALPHA_TEST)
366   SS(AMBIENT)
367   SS(AMBIENT_AND_DIFFUSE)
368   SS(ARRAY_BUFFER)
369   SS(AUTO_NORMAL)
370   SS(BACK)
371   SS(BLEND)
372   SS(BLEND_DST)
373   SS(BLEND_SRC)
374   SS(BLEND_SRC_ALPHA)
375   SS(BYTE)
376   SS(C3F_V3F)
377   SS(C4F_N3F_V3F)
378   SS(C4UB_V2F)
379   SS(C4UB_V3F)
380   SS(CCW)
381   SS(CLAMP)
382   SS(COLOR_ARRAY)
383   SS(COLOR_ARRAY_BUFFER_BINDING);
384   SS(COLOR_MATERIAL)
385   SS(COLOR_MATERIAL_FACE)
386   SS(COLOR_MATERIAL_PARAMETER)
387   SS(COMPILE)
388   SS(CULL_FACE)
389   SS(CW)
390   SS(DECAL)
391   SS(DEPTH_BUFFER_BIT)
392   SS(DEPTH_TEST)
393   SS(DIFFUSE)
394   SS(DOUBLEBUFFER)
395   SS(DST_ALPHA)
396   SS(DST_COLOR)
397   SS(DYNAMIC_DRAW)
398   SS(ELEMENT_ARRAY_BUFFER)
399   SS(EYE_LINEAR)
400   SS(EYE_PLANE)
401   SS(FEEDBACK)
402   SS(FILL)
403   SS(FLAT)
404   SS(FLOAT)
405   SS(FOG)
406   SS(FRONT)
407   SS(FRONT_AND_BACK)
408   SS(GREATER)
409   SS(INTENSITY)
410   SS(INVALID_ENUM)
411   SS(INVALID_OPERATION)
412   SS(INVALID_VALUE)
413   SS(LESS)
414   SS(LIGHT0)
415   SS(LIGHT1)
416   SS(LIGHT2)
417   SS(LIGHT3)
418   SS(LIGHTING)
419   SS(LIGHT_MODEL_AMBIENT)
420   SS(LIGHT_MODEL_COLOR_CONTROL)
421   SS(LIGHT_MODEL_LOCAL_VIEWER)
422   SS(LIGHT_MODEL_TWO_SIDE)
423   SS(LINE)
424   SS(LINEAR)
425   SS(LINEAR_MIPMAP_LINEAR)
426   SS(LINEAR_MIPMAP_NEAREST)
427   SS(LINES)
428   SS(LINE_LOOP)
429   SS(LINE_STRIP)
430   SS(LUMINANCE)
431   SS(LUMINANCE_ALPHA)
432   SS(MATRIX_MODE)
433   SS(MODELVIEW)
434   SS(MODULATE)
435   SS(N3F_V3F)
436   SS(NEAREST)
437   SS(NEAREST_MIPMAP_LINEAR)
438   SS(NEAREST_MIPMAP_NEAREST)
439   SS(NORMALIZE)
440   SS(NORMAL_ARRAY)
441   SS(NORMAL_ARRAY_BUFFER_BINDING);
442   SS(OBJECT_LINEAR)
443   SS(OBJECT_PLANE)
444   SS(ONE_MINUS_DST_ALPHA)
445   SS(ONE_MINUS_DST_COLOR)
446   SS(ONE_MINUS_SRC_ALPHA)
447   SS(ONE_MINUS_SRC_COLOR)
448   SS(OUT_OF_MEMORY)
449   SS(PACK_ALIGNMENT)
450   SS(POINTS)
451   SS(POLYGON)
452   SS(POLYGON_OFFSET_FILL)
453   SS(POLYGON_SMOOTH)
454   SS(POLYGON_STIPPLE)
455   SS(POSITION)
456   SS(PROJECTION)
457   SS(Q)
458   SS(QUADS)
459   SS(QUAD_STRIP)
460   SS(R)
461   SS(RENDER)
462   SS(REPEAT)
463   SS(RGB)
464   SS(RGBA)
465   SS(RGBA_MODE)
466   SS(S)
467   SS(SELECT)
468   SS(SEPARATE_SPECULAR_COLOR)
469   SS(SHADE_MODEL)
470   SS(SHININESS)
471   SS(SHORT)
472   SS(SINGLE_COLOR)
473   SS(SMOOTH)
474   SS(SPECULAR)
475   SS(SPHERE_MAP)
476   SS(SRC_ALPHA)
477   SS(SRC_ALPHA_SATURATE)
478   SS(SRC_COLOR)
479   SS(STACK_OVERFLOW)
480   SS(STACK_UNDERFLOW)
481   SS(STATIC_DRAW)
482   SS(STENCIL_BUFFER_BIT)
483   SS(T)
484   SS(T2F_C3F_V3F)
485   SS(T2F_C4F_N3F_V3F)
486   SS(T2F_C4UB_V3F)
487   SS(T2F_N3F_V3F)
488   SS(T2F_V3F)
489   SS(T4F_C4F_N3F_V4F)
490   SS(T4F_V4F)
491   SS(TEXTURE)
492   SS(TEXTURE_1D)
493   SS(TEXTURE_2D)
494   SS(TEXTURE_ALPHA_SIZE)
495   SS(TEXTURE_BINDING_2D)
496   SS(TEXTURE_BLUE_SIZE)
497   SS(TEXTURE_BORDER)
498   SS(TEXTURE_BORDER_COLOR)
499   SS(TEXTURE_COMPONENTS)
500   SS(TEXTURE_COORD_ARRAY)
501   SS(TEXTURE_COORD_ARRAY_BUFFER_BINDING);
502   SS(TEXTURE_ENV)
503   SS(TEXTURE_ENV_COLOR)
504   SS(TEXTURE_ENV_MODE)
505   SS(TEXTURE_GEN_MODE)
506   SS(TEXTURE_GEN_Q)
507   SS(TEXTURE_GEN_R)
508   SS(TEXTURE_GEN_S)
509   SS(TEXTURE_GEN_T)
510   SS(TEXTURE_GREEN_SIZE)
511   SS(TEXTURE_HEIGHT)
512   SS(TEXTURE_INTENSITY_SIZE)
513   SS(TEXTURE_LUMINANCE_SIZE)
514   SS(TEXTURE_MAG_FILTER)
515   SS(TEXTURE_MIN_FILTER)
516   SS(TEXTURE_RED_SIZE)
517   SS(TEXTURE_WRAP_S)
518   SS(TEXTURE_WRAP_T)
519   SS(TRIANGLES)
520   SS(TRIANGLE_FAN)
521   SS(TRIANGLE_STRIP)
522   SS(UNPACK_ALIGNMENT)
523   SS(UNPACK_ROW_LENGTH)
524   SS(UNSIGNED_BYTE)
525   SS(UNSIGNED_INT_8_8_8_8_REV)
526   SS(UNSIGNED_SHORT)
527   SS(V2F)
528   SS(V3F)
529   SS(VERTEX_ARRAY)
530   SS(VERTEX_ARRAY_BUFFER_BINDING);
531 /*SS(COLOR_BUFFER_BIT) -- same value as GL_LIGHT0 */
532 # undef SS
533   case (GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT):
534     return "DEPTH_BUFFER_BIT | COLOR_BUFFER_BIT";
535 /* Oops, same as INVALID_ENUM.
536   case (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT):
537     return "DEPTH_BUFFER_BIT | STENCIL_BUFFER_BIT";
538 */
539   case (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT):
540     return "COLOR_BUFFER_BIT | STENCIL_BUFFER_BIT";
541   case (GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT):
542     return "DEPTH_BUFFER_BIT | COLOR_BUFFER_BIT | STENCIL_BUFFER_BIT";
543   default:
544     {
545       static char buf[255];
546       sprintf (buf, "0x%04X", mode);
547       return buf;
548     }
549   }
550 }
551
552 static void
553 check_gl_error (const char *s)
554 {
555   GLenum i = glGetError();
556   if (i == GL_NO_ERROR) return;
557   fprintf (stderr, "jwzgles: GL ERROR: %s: %s\n", s, mode_desc(i));
558 }
559
560 #endif /* DEBUG */
561
562
563 static void
564 make_room (const char *name, void **array, int span, int *count, int *size)
565 {
566   if (*count + 1 >= *size)
567     {
568       int new_size = (*count + 20) * 1.2;   /* mildly exponential */
569       *array = realloc (*array, new_size * span);
570       Assert (*array, "out of memory");
571       /* LOG3("%s: grew %d -> %d", name, *size, new_size); */
572       *size = new_size;
573     }
574 }
575
576
577 int
578 jwzgles_glGenLists (int n)
579 {
580   int i;
581   int ret = 0;
582
583   Assert (!state->compiling_verts, "glGenLists not allowed inside glBegin");
584
585   /* Ensure space in state->lists, clear the one at the end, and tick counter
586      Note that lists are never really deleted, and we can never re-use elements
587      of this array.  glDeleteLists zeroes out the contents of the list, but
588      the list ID is still valid for use with glNewList forever.
589      #### So maybe this should be a linked list instead of an array.
590   */
591   for (i = 0; i < n; i++)
592     {
593       list *L;
594       int id = 0;
595       make_room ("glGenLists", 
596                  (void **) &state->lists.lists,
597                  sizeof (*state->lists.lists),
598                  &state->lists.count, &state->lists.size);
599       state->lists.count++;
600       id = state->lists.count;
601       L = &state->lists.lists[id-1];
602
603       memset (L, 0, sizeof (*L));
604       L->id = id;
605       if (ret == 0) ret = id;
606       LOG1("glGenLists -> %d", L->id);
607     }
608
609   /* Return the ID of the first list allocated */
610
611   return ret;
612 }
613
614
615 void
616 jwzgles_glNewList (int id, int mode)
617 {
618   list *L;
619   Assert (id > 0 && id <= state->lists.count, "glNewList: bogus ID");
620   Assert (mode == GL_COMPILE, "glNewList: bad mode");
621   Assert (!state->compiling_verts, "glNewList not allowed inside glBegin");
622   Assert (!state->compiling_list, "nested glNewList");
623   Assert (state->set.count == 0, "missing glEnd");
624
625   L = &state->lists.lists[id-1];
626   Assert (L->id == id, "glNewList corrupted");
627
628   if (L->count != 0) jwzgles_glDeleteLists (L->id, 1); /* Overwriting */
629   Assert (L->count == 0, "glNewList corrupted");
630   
631   state->compiling_list = id;
632
633   LOG1("glNewList -> %d", id);
634 }
635
636
637 static void save_arrays (list_fn *, int);
638 static void restore_arrays (list_fn *, int);
639 static void copy_array_data (draw_array *, int, const char *);
640 static void optimize_arrays (void);
641
642 void
643 jwzgles_glEndList (void)
644 {
645   Assert (state->compiling_list, "extra glEndList");
646   Assert (state->set.count == 0, "missing glEnd");
647   Assert (!state->compiling_verts, "glEndList not allowed inside glBegin");
648   LOG1("glEndList %d", state->compiling_list);
649   optimize_arrays();
650   state->compiling_list = 0;
651 }
652
653
654 static void
655 list_push (const char * const name, 
656            list_fn_cb fn, fn_proto proto, void_int *av)
657 {
658   list *L;
659   list_fn *F;
660   int i;
661
662   Assert (state->compiling_list > 0, "not inside glNewList");
663   Assert (state->compiling_list <= state->lists.count, "glNewList corrupted");
664
665   L = &state->lists.lists[state->compiling_list-1];
666   Assert (L, "glNewList: no list");
667
668   make_room ("glNewLists", 
669              (void **) &L->fns, sizeof (*L->fns),
670              &L->count, &L->size);
671   memset (&L->fns[L->count], 0, sizeof (*L->fns));
672   F = L->fns + L->count;
673
674   F->name = name;
675   F->fn = fn;
676   F->proto = proto;
677   if (proto != PROTO_VOID)
678     for (i = 0; i < countof(F->argv); i++)
679       F->argv[i] = av[i];
680
681 # ifdef DEBUG
682   switch (proto) {
683   case PROTO_VOID:
684     LOG1 ("  push %-12s", name);
685     break;
686   case PROTO_I:
687     if (fn == (list_fn_cb) &jwzgles_glBegin ||
688         fn == (list_fn_cb) &jwzgles_glFrontFace ||
689         fn == (list_fn_cb) &jwzgles_glEnable ||
690         fn == (list_fn_cb) &jwzgles_glDisable ||
691         fn == (list_fn_cb) &jwzgles_glEnableClientState ||
692         fn == (list_fn_cb) &jwzgles_glDisableClientState ||
693         fn == (list_fn_cb) &jwzgles_glShadeModel ||
694         fn == (list_fn_cb) &jwzgles_glMatrixMode)
695       LOG2 ("  push %-12s %s", name, mode_desc (av[0].i));
696     else
697       LOG2 ("  push %-12s %d", name, av[0].i);
698     break;
699   case PROTO_F:
700     LOG2 ("  push %-12s %7.3f", name, av[0].f);
701     break;
702   case PROTO_II:
703     if (fn == (list_fn_cb) &jwzgles_glBindTexture ||
704         fn == (list_fn_cb) &jwzgles_glBindBuffer)
705       LOG3 ("  push %-12s %s %d", name, mode_desc (av[0].i), av[1].i);
706     else
707       LOG3 ("  push %-12s %d %d", name, av[0].i, av[1].i);
708     break;
709   case PROTO_FF:
710     LOG3 ("  push %-12s %7.3f %7.3f", name, av[0].f, av[1].f);
711     break;
712   case PROTO_IF:
713     LOG3 ("  push %-12s %s %7.3f", name, mode_desc (av[0].i), av[1].f);
714     break;
715   case PROTO_III:
716   case PROTO_ARRAYS:
717     if (fn == (list_fn_cb) &jwzgles_glDrawArrays ||
718         fn == (list_fn_cb) &jwzgles_glTexParameteri)
719       LOG4 ("  push %-12s %s %d %d", name, mode_desc (av[0].i), 
720             av[1].i, av[2].i);
721     else
722       LOG4 ("  push %-12s %d %d %d", name, av[0].i, av[1].i, av[2].i);
723     break;
724   case PROTO_FFF:
725     LOG4 ("  push %-12s %7.3f %7.3f %7.3f", name, av[0].f, av[1].f, av[2].f);
726     break;
727   case PROTO_IIF:
728     LOG4 ("  push %-12s %s %s %7.3f", name,
729              mode_desc(av[0].i), mode_desc(av[1].i), av[2].f);
730     break;
731   case PROTO_IIII:
732     LOG5 ("  push %-12s %d %d %d %d", name, 
733           av[0].i, av[1].i, av[2].i, av[3].i);
734     break;
735   case PROTO_FFFF:
736     LOG5 ("  push %-12s %7.3f %7.3f %7.3f %7.3f", name,
737              av[0].f, av[1].f, av[2].f, av[3].f);
738     break;
739   case PROTO_IFV:
740     LOG6 ("  push %-12s %s %3.1f %3.1f %3.1f %3.1f", name, mode_desc (av[0].i),
741              av[1].f, av[2].f, av[3].f, av[4].f);
742     break;
743   case PROTO_IIV:
744     LOG6 ("  push %-12s %s %d %d %d %d", name, mode_desc (av[0].i),
745              av[1].i, av[2].i, av[3].i, av[4].i);
746     break;
747   case PROTO_IIFV:
748     LOG7 ("  push %-12s %s %-8s %3.1f %3.1f %3.1f %3.1f", name,
749           mode_desc (av[0].i), mode_desc (av[1].i),
750              av[2].f, av[3].f, av[4].f, av[5].f);
751     break;
752   case PROTO_IIIV:
753     LOG7 ("  push %-12s %s %-8s %3d %3d %3d %3d", name,
754           mode_desc (av[0].i), mode_desc (av[1].i),
755              av[2].i, av[3].i, av[4].i, av[5].i);
756     break;
757   case PROTO_FV16:
758     LOG17 ("  push %-12s ["
759            "%8.3f %8.3f %8.3f %8.3f "   "\n\t\t\t       "
760            "%8.3f %8.3f %8.3f %8.3f "   "\n\t\t\t       "
761            "%8.3f %8.3f %8.3f %8.3f "   "\n\t\t\t       "
762            "%8.3f %8.3f %8.3f %8.3f ]",
763            name,
764            av[0].f,  av[1].f,  av[2].f,  av[3].f,
765            av[4].f,  av[5].f,  av[6].f,  av[7].f,
766            av[8].f,  av[9].f,  av[10].f, av[11].f,
767            av[12].f, av[13].f, av[14].f, av[15].f);
768     break;
769   default:
770     Assert (0, "bogus prototype");
771     break;
772   }
773 # endif /* DEBUG */
774
775   if (proto == PROTO_ARRAYS) /* glDrawArrays */
776     save_arrays (F, av[1].i + av[2].i);
777
778   L->count++;
779 }
780
781
782 void
783 jwzgles_glBegin (int mode)
784 {
785   Assert (!state->compiling_verts, "nested glBegin");
786   state->compiling_verts++;
787
788   /* Only these commands are allowed inside glBegin:
789
790      glVertex           -- not allowed outside
791      glColor
792      glSecondaryColor
793      glIndex
794      glNormal
795      glFogCoord
796      glTexCoord
797      glMultiTexCoord
798      glVertexAttrib
799      glEvalCoord
800      glEvalPoint
801      glArrayElement     -- not allowed outside
802      glMaterial
803      glEdgeFlag
804      glCallList
805      glCallLists
806    */
807
808   if (!state->replaying_list)
809     LOG2 ("%sglBegin %s", 
810           (state->compiling_list || state->replaying_list ? "  " : ""),
811           mode_desc (mode));
812
813   Assert (state->set.count == 0, "glBegin corrupted");
814   state->set.mode   = mode;
815   state->set.count  = 0;
816   state->set.ncount = 0;
817   state->set.tcount = 0;
818   state->set.ccount = 0;
819 }
820
821
822 void
823 jwzgles_glDeleteLists (int id0, int range)
824 {
825   Assert (!state->compiling_verts, "glDeleteLists not allowed inside glBegin");
826
827   if (state->compiling_list)
828     {
829       void_int vv[2];
830       vv[0].i = id0;
831       vv[1].i = range;
832       list_push ("glDeleteLists", (list_fn_cb) &jwzgles_glDeleteLists, 
833                  PROTO_II, vv);
834     }
835   else
836     {
837       int id;
838
839       if (!state->replaying_list)
840         LOG2 ("glDeleteLists %d %d", id0, range);
841
842       for (id = id0 + range - 1; id >= id0; id--)
843         {
844           int i;
845           list *L;
846           if (id == 0) continue;  /* People do this stupid thing */
847           if (id > state->lists.count) break;   /* this too */
848           Assert (id > 0 && id <= state->lists.count,
849                   "glDeleteLists: bogus ID");
850           L = &state->lists.lists[id-1];
851           Assert (L->id == id, "glDeleteLists corrupted");
852
853           for (i = 0; i < L->count; i++)
854             {
855               list_fn *lf = &L->fns[i];
856               if (lf->arrays)
857                 {
858                   int j;
859                   for (j = 0; j < 4; j++)
860                     /* If there's a binding, 'data' is an index, not a ptr. */
861                     if (!lf->arrays[j].binding &&
862                         lf->arrays[j].data)
863                       free (lf->arrays[j].data);
864                   free (lf->arrays);
865                 }
866             }
867           if (L->fns) 
868             free (L->fns);
869           if (L->buffer)
870             glDeleteBuffers (1, &L->buffer);
871
872           memset (L, 0, sizeof (*L));
873           L->id = id;
874         }
875     }
876 }
877
878
879 extern GLboolean
880 jwzgles_glIsList (GLuint id)
881 {
882   return (id > 0 && id < state->lists.count);
883 }
884
885
886
887 void
888 jwzgles_glNormal3fv (const GLfloat *v)
889 {
890   if (state->compiling_list && !state->compiling_verts)
891     {
892       void_int vv[3];
893       vv[0].f = v[0];
894       vv[1].f = v[1];
895       vv[2].f = v[2];
896       list_push ("glNormal3f", (list_fn_cb) &jwzgles_glNormal3f, 
897                  PROTO_FFF, vv);
898     }
899   else
900     {
901       if (!state->replaying_list)
902         LOG5 ("%s%sglNormal3f   %7.3f %7.3f %7.3f",
903               (state->compiling_list || state->replaying_list ? "  " : ""),
904               (state->compiling_verts ? "  rec  " : ""),
905               v[0], v[1], v[2]);
906
907       if (state->compiling_verts)       /* inside glBegin */
908         {
909           state->set.cnorm.x = v[0];
910           state->set.cnorm.y = v[1];
911           state->set.cnorm.z = v[2];
912           state->set.ncount++;
913           if (state->set.count > 0 && state->set.ncount == 1)  /* not first! */
914             state->set.ncount++;
915         }
916       else                              /* outside glBegin */
917         {
918           glNormal3f (v[0], v[1], v[2]);
919           CHECK("glNormal3f");
920         }
921     }
922 }
923
924
925 void
926 jwzgles_glNormal3f (GLfloat x, GLfloat y, GLfloat z)
927 {
928   GLfloat v[3];
929   v[0] = x;
930   v[1] = y;
931   v[2] = z;
932   jwzgles_glNormal3fv (v);
933 }
934
935
936 void
937 jwzgles_glTexCoord4fv (const GLfloat *v)
938 {
939   if (state->compiling_list && !state->compiling_verts)
940     {
941       void_int vv[4];
942       vv[0].f = v[0];
943       vv[1].f = v[1];
944       vv[2].f = v[2];
945       vv[3].f = v[3];
946       list_push ("glTexCoord4f", (list_fn_cb) &jwzgles_glTexCoord4f,
947                  PROTO_FFFF, vv);
948     }
949   else
950     {
951       if (!state->replaying_list)
952         LOG6 ("%s%sglTexCoord4f %7.3f %7.3f %7.3f %7.3f", 
953               (state->compiling_list || state->replaying_list ? "  " : ""),
954               (state->compiling_verts ? "  rec  " : ""),
955               v[0], v[1], v[2], v[3]);
956
957       Assert (state->compiling_verts, "glTexCoord4fv outside glBegin");
958
959       if (state->compiling_verts)       /* inside glBegin */
960         {
961           state->set.ctex.s = v[0];
962           state->set.ctex.t = v[1];
963           state->set.ctex.r = v[2];
964           state->set.ctex.q = v[3];
965           state->set.tcount++;
966           if (state->set.count > 0 && state->set.tcount == 1)  /* not first! */
967             state->set.tcount++;
968         }
969     }
970 }
971
972
973 void
974 jwzgles_glTexCoord4f (GLfloat s, GLfloat t, GLfloat r, GLfloat q)
975 {
976   GLfloat v[4];
977   v[0] = s;
978   v[1] = t;
979   v[2] = r;
980   v[3] = q;
981   jwzgles_glTexCoord4fv (v);
982 }
983
984
985 void
986 jwzgles_glTexCoord3fv (const GLfloat *v)
987 {
988   GLfloat vv[4];
989   vv[0] = v[0];
990   vv[1] = v[1];
991   vv[2] = v[2];
992   vv[3] = 1;
993   jwzgles_glTexCoord4fv (vv);
994 }
995
996
997 void
998 jwzgles_glTexCoord2fv (const GLfloat *v)
999 {
1000   GLfloat vv[4];
1001   vv[0] = v[0];
1002   vv[1] = v[1];
1003   vv[2] = 0;
1004   vv[3] = 1;
1005   jwzgles_glTexCoord4fv (vv);
1006 }
1007
1008
1009 void
1010 jwzgles_glTexCoord3f (GLfloat s, GLfloat t, GLfloat r)
1011 {
1012   jwzgles_glTexCoord4f (s, t, r, 1);
1013 }
1014
1015
1016 void
1017 jwzgles_glTexCoord2f (GLfloat s, GLfloat t)
1018 {
1019   jwzgles_glTexCoord4f (s, t, 0, 1);
1020 }
1021
1022
1023 void
1024 jwzgles_glTexCoord1f (GLfloat s)
1025 {
1026   jwzgles_glTexCoord4f (s, 0, 0, 1);
1027 }
1028
1029
1030
1031 void
1032 jwzgles_glColor4fv (const GLfloat *v)
1033 {
1034   if (state->compiling_list && !state->compiling_verts)
1035     {
1036       void_int vv[4];
1037       vv[0].f = v[0];
1038       vv[1].f = v[1];
1039       vv[2].f = v[2];
1040       vv[3].f = v[3];
1041       list_push ("glColor4f", (list_fn_cb) &jwzgles_glColor4f, 
1042                  PROTO_FFFF, vv);
1043     }
1044   else
1045     {
1046       if (!state->replaying_list)
1047         LOG6 ("%s%sglColor4f    %7.3f %7.3f %7.3f %7.3f", 
1048               (state->compiling_list || state->replaying_list ? "  " : ""),
1049               (state->compiling_verts ? "  rec  " : ""),
1050               v[0], v[1], v[2], v[3]);
1051
1052       if (state->compiling_verts)       /* inside glBegin */
1053         {
1054           state->set.ccolor.r = v[0];
1055           state->set.ccolor.g = v[1];
1056           state->set.ccolor.b = v[2];
1057           state->set.ccolor.a = v[3];
1058           state->set.ccount++;
1059           if (state->set.count > 0 && state->set.ccount == 1)  /* not first! */
1060             state->set.ccount++;
1061         }
1062       else                              /* outside glBegin */
1063         {
1064           glColor4f (v[0], v[1], v[2], v[3]);
1065           CHECK("glColor4");
1066         }
1067     }
1068 }
1069
1070
1071 void
1072 jwzgles_glColor4f (GLfloat r, GLfloat g, GLfloat b, GLfloat a)
1073 {
1074   GLfloat v[4];
1075   v[0] = r;
1076   v[1] = g;
1077   v[2] = b;
1078   v[3] = a;
1079   jwzgles_glColor4fv (v);
1080 }
1081
1082
1083 void
1084 jwzgles_glColor3f (GLfloat r, GLfloat g, GLfloat b)
1085 {
1086   jwzgles_glColor4f (r, g, b, 1);
1087 }
1088
1089
1090 void
1091 jwzgles_glColor3fv (const GLfloat *v)
1092 {
1093   GLfloat vv[4];
1094   vv[0] = v[0];
1095   vv[1] = v[1];
1096   vv[2] = v[2];
1097   vv[3] = 1;
1098   jwzgles_glColor4fv (vv);
1099 }
1100
1101
1102 void
1103 jwzgles_glColor4i (GLuint r, GLuint g, GLuint b, GLuint a)
1104 {
1105   jwzgles_glColor4f (r, g, b, a);
1106 }
1107
1108
1109 void
1110 jwzgles_glColor3i (GLuint r, GLuint g, GLuint b)
1111 {
1112   jwzgles_glColor4f (r, g, b, 1);
1113 }
1114
1115
1116 void
1117 jwzgles_glColor4iv (const GLint *v)
1118 {
1119   GLfloat vv[4];
1120   vv[0] = v[0];
1121   vv[1] = v[1];
1122   vv[2] = v[2];
1123   vv[3] = v[3];
1124   jwzgles_glColor4fv (vv);
1125 }
1126
1127
1128 void
1129 jwzgles_glColor3iv (const GLint *v)
1130 {
1131   GLfloat vv[4];
1132   vv[0] = v[0];
1133   vv[1] = v[1];
1134   vv[2] = v[2];
1135   vv[3] = 1;
1136   jwzgles_glColor4fv (vv);
1137 }
1138
1139
1140 void
1141 jwzgles_glColor4ub (GLubyte r, GLubyte g, GLubyte b, GLubyte a)
1142 {
1143   jwzgles_glColor4f (r, g, b, a);
1144 }
1145
1146
1147 void
1148 jwzgles_glColor3ub (GLubyte r, GLubyte g, GLubyte b)
1149 {
1150   jwzgles_glColor4f (r, g, b, 1);
1151 }
1152
1153
1154 void
1155 jwzgles_glMaterialfv (GLenum face, GLenum pname, const GLfloat *color)
1156 {
1157   /* If this is called inside glBegin/glEnd with a front ambient color,
1158      then treat it the same as glColor: set the color of the upcoming
1159      vertex.
1160
1161      Other faces or lighting types within glBegin are ignored.
1162    */
1163
1164   if (state->compiling_verts)
1165     {
1166       if ((face == GL_FRONT || 
1167            face == GL_FRONT_AND_BACK) &&
1168           (pname == GL_AMBIENT || 
1169            pname == GL_DIFFUSE || 
1170            pname == GL_AMBIENT_AND_DIFFUSE))
1171         {
1172           jwzgles_glColor4f (color[0], color[1], color[2], color[3]);
1173           state->set.materialistic++;
1174         }
1175       else
1176         LOG2 ("  IGNORING glMaterialfv %s %s",
1177               mode_desc(face), mode_desc(pname));
1178     }
1179   else if (state->compiling_list)
1180     {
1181       void_int vv[6];
1182       vv[0].i = face;
1183       vv[1].i = pname;
1184       vv[2].f = color[0];
1185       vv[3].f = color[1];
1186       vv[4].f = color[2];
1187       vv[5].f = color[3];
1188       list_push ("glMaterialfv", (list_fn_cb) &jwzgles_glMaterialfv, 
1189                  PROTO_IIFV, vv);
1190     }
1191   else
1192     {
1193       /* If this is called outside of glBegin/glEnd with a front
1194          ambient color, then the intent is presumably for that color
1195          to apply to the upcoming vertexes (which may be played back
1196          from a list that does not have vertex colors in it).  In that
1197          case, the only way to make the colors show up is to call
1198          glColor() with GL_COLOR_MATERIAL enabled.
1199
1200          I'm not sure if this will have other inappropriate side effects...
1201        */
1202       if ((face == GL_FRONT ||
1203            face == GL_FRONT_AND_BACK) &&
1204           (pname == GL_AMBIENT ||
1205            pname == GL_DIFFUSE ||
1206            pname == GL_AMBIENT_AND_DIFFUSE))
1207         {
1208           jwzgles_glEnable (GL_COLOR_MATERIAL);
1209           jwzgles_glColor4f (color[0], color[1], color[2], color[3]);
1210         }
1211
1212       /* OpenGLES seems to throw "invalid enum" for GL_FRONT -- but it
1213          goes ahead and sets the material anyway!  No error if we just
1214          always use GL_FRONT_AND_BACK.
1215        */
1216       if (face == GL_FRONT)
1217         face = GL_FRONT_AND_BACK;
1218       if (! state->replaying_list)
1219         LOG7 ("direct %-12s %s %s %7.3f %7.3f %7.3f %7.3f", "glMaterialfv",
1220               mode_desc(face), mode_desc(pname),
1221               color[0], color[1], color[2], color[3]);
1222       glMaterialfv (face, pname, color);  /* the real one */
1223       CHECK("glMaterialfv");
1224     }
1225 }
1226
1227
1228 void
1229 jwzgles_glMaterialiv (GLenum face, GLenum pname, const GLint *v)
1230 {
1231   GLfloat vv[4];
1232   vv[0] = v[0];
1233   vv[1] = v[1];
1234   vv[2] = v[2];
1235   vv[3] = 1;
1236   jwzgles_glMaterialfv (face, pname, vv);
1237 }
1238
1239 void
1240 jwzgles_glMaterialf (GLenum face, GLenum pname, const GLfloat c)
1241 {
1242   GLfloat vv[4];
1243   vv[0] = c;
1244   vv[1] = c;
1245   vv[2] = c;
1246   vv[3] = 1;
1247   jwzgles_glMaterialfv (face, pname, vv);
1248 }
1249
1250
1251 void
1252 jwzgles_glMateriali (GLenum face, GLenum pname, const GLuint c)
1253 {
1254   jwzgles_glMaterialf (face, pname, c);
1255 }
1256
1257
1258 void
1259 jwzgles_glColorMaterial (GLenum face, GLenum mode)
1260 {
1261   Assert (!state->compiling_verts,
1262           "glColorMaterial not allowed inside glBegin");
1263 #if 0
1264   if (state->compiling_list)
1265     {
1266       void_int vv[2];
1267       vv[0].i = face;
1268       vv[1].i = mode;
1269       list_push ("glColorMaterial", (list_fn_cb) &jwzgles_glColorMaterial, 
1270                  PROTO_II, vv);
1271     }
1272   else
1273     {
1274       /* No real analog to this distinction in OpenGLES, since color
1275          arrays don't distinguish between "color" and "material", */
1276       Assert (0, "glColorMaterial: unimplemented mode");
1277     }
1278 #endif
1279 }
1280
1281
1282
1283
1284 void
1285 jwzgles_glVertex4fv (const GLfloat *v)
1286 {
1287   vert_set *s = &state->set;
1288   int count = s->count;
1289
1290   Assert (state->compiling_verts, "glVertex4fv not inside glBegin");
1291
1292   LOG5("%s  rec  glVertex4f   %7.3f %7.3f %7.3f %7.3f",
1293        (state->compiling_list || state->replaying_list ? "  " : ""),
1294        v[0], v[1], v[2], v[3]);
1295
1296   if (count >= s->size - 1)
1297     {
1298       int new_size = 20 + (s->size * 1.2);
1299
1300       /* 4 arrays, different element sizes...
1301          We allocate all 4 arrays just in case we need them,
1302          but we might not end up using them all at the end.
1303       */
1304
1305       s->verts = (XYZW *) realloc (s->verts, new_size * sizeof (*s->verts));
1306       Assert (s->verts, "out of memory");
1307
1308       s->norms = (XYZ *) realloc (s->norms, new_size * sizeof (*s->norms));
1309       Assert (s->norms, "out of memory");
1310
1311       s->tex = (STRQ *) realloc (s->tex, new_size * sizeof (*s->tex));
1312       Assert (s->tex, "out of memory");
1313
1314       s->color = (RGBA *) realloc (s->color, new_size * sizeof (*s->color));
1315       Assert (s->color, "out of memory");
1316
1317       s->size = new_size;
1318     }
1319
1320   s->verts [count].x = v[0];
1321   s->verts [count].y = v[1];
1322   s->verts [count].z = v[2];
1323   s->verts [count].w = v[3];
1324   s->norms [count] = s->cnorm;
1325   s->tex   [count] = s->ctex;
1326   s->color [count] = s->ccolor;
1327   s->count++;
1328 }
1329
1330
1331 void
1332 jwzgles_glVertex4f (GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1333 {
1334   GLfloat v[4];
1335   v[0] = x;
1336   v[1] = y;
1337   v[2] = z;
1338   v[3] = w;
1339   jwzgles_glVertex4fv (v);
1340 }
1341
1342 void
1343 jwzgles_glVertex4i (GLint x, GLint y, GLint z, GLint w)
1344 {
1345   jwzgles_glVertex4f (x, y, z, w);
1346 }
1347
1348 void
1349 jwzgles_glVertex3f (GLfloat x, GLfloat y, GLfloat z)
1350 {
1351   GLfloat v[4];
1352   v[0] = x;
1353   v[1] = y;
1354   v[2] = z;
1355   v[3] = 1;
1356   jwzgles_glVertex4fv (v);
1357 }
1358
1359 void
1360 jwzgles_glVertex3i (GLint x, GLint y, GLint z)
1361 {
1362   jwzgles_glVertex3f (x, y, z);
1363 }
1364
1365 void
1366 jwzgles_glVertex3fv (const GLfloat *v)
1367 {
1368   jwzgles_glVertex3f (v[0], v[1], v[2]);
1369 }
1370
1371 void
1372 jwzgles_glVertex3dv (const GLdouble *v)
1373 {
1374   jwzgles_glVertex3f (v[0], v[1], v[2]);
1375 }
1376
1377
1378 void
1379 jwzgles_glVertex2f (GLfloat x, GLfloat y)
1380 {
1381   GLfloat v[3];
1382   v[0] = x;
1383   v[1] = y;
1384   v[2] = 0;
1385   jwzgles_glVertex3fv (v);
1386 }
1387
1388 void
1389 jwzgles_glVertex2fv (const GLfloat *v)
1390 {
1391   jwzgles_glVertex2f (v[0], v[1]);
1392 }
1393
1394 void
1395 jwzgles_glVertex2i (GLint x, GLint y)
1396 {
1397   jwzgles_glVertex2f (x, y);
1398 }
1399
1400
1401 void
1402 jwzgles_glLightiv (GLenum light, GLenum pname, const GLint *params)
1403 {
1404   GLfloat v[4];
1405   v[0] = params[0];
1406   v[1] = params[1];
1407   v[2] = params[2];
1408   v[3] = params[3];
1409   jwzgles_glLightfv (light, pname, v);
1410 }
1411
1412 void
1413 jwzgles_glLightModeliv (GLenum pname, const GLint *params)
1414 {
1415   GLfloat v[4];
1416   v[0] = params[0];
1417   v[1] = params[1];
1418   v[2] = params[2];
1419   v[3] = params[3];
1420   jwzgles_glLightModelfv (pname, v);
1421 }
1422
1423 void
1424 jwzgles_glFogiv (GLenum pname, const GLint *params)
1425 {
1426   GLfloat v[4];
1427   v[0] = params[0];
1428   v[1] = params[1];
1429   v[2] = params[2];
1430   v[3] = params[3];
1431   jwzgles_glFogfv (pname, v);
1432 }
1433
1434 void
1435 jwzgles_glLighti (GLenum light, GLenum pname, GLint param)
1436 {
1437   jwzgles_glLightf (light, pname, param);
1438 }
1439
1440 void
1441 jwzgles_glLightModeli (GLenum pname, GLint param)
1442 {
1443   jwzgles_glLightModelf (pname, param);
1444 }
1445
1446 void
1447 jwzgles_glFogi (GLenum pname, GLint param)
1448 {
1449   jwzgles_glFogf (pname, param);
1450 }
1451
1452
1453 void
1454 jwzgles_glRotated (GLdouble angle, GLdouble x, GLdouble y, GLdouble z)
1455 {
1456   jwzgles_glRotatef (angle, x, y, z);
1457 }
1458
1459
1460 void
1461 jwzgles_glClipPlane (GLenum plane, const GLdouble *equation)
1462 {
1463   Assert (state->compiling_verts, "glClipPlane not inside glBegin");
1464   Assert (0, "glClipPlane unimplemented");  /* no GLES equivalent... */
1465 }
1466
1467
1468 void
1469 jwzgles_glPolygonMode (GLenum face, GLenum mode)
1470 {
1471   Assert (!state->compiling_verts, "not inside glBegin");
1472   if (state->compiling_list)
1473     {
1474       void_int vv[2];
1475       vv[0].i = face;
1476       vv[1].i = mode;
1477       list_push ("glPolygonMode", (list_fn_cb) &jwzgles_glPolygonMode, 
1478                  PROTO_II, vv);
1479     }
1480   else
1481     {
1482       /* POINT and LINE don't exist in GLES */
1483       Assert (mode == GL_FILL, "glPolygonMode: unimplemented mode");
1484     }
1485 }
1486
1487
1488 void
1489 jwzgles_glDrawBuffer (GLenum buf)
1490 {
1491   Assert (!state->compiling_verts, "not inside glBegin");
1492   if (state->compiling_list)
1493     {
1494       void_int vv[1];
1495       vv[0].i = buf;
1496       list_push ("glDrawBuffer", (list_fn_cb) &jwzgles_glDrawBuffer, 
1497                  PROTO_I, vv);
1498     }
1499   else
1500     {
1501 /*      Assert (buf == GL_BACK, "glDrawBuffer: back buffer only"); */
1502 # ifndef GL_VERSION_ES_CM_1_0  /* not compiling against OpenGLES 1.x */
1503       if (! state->replaying_list)
1504         LOG1 ("direct %-12s", "glDrawBuffer");
1505       glDrawBuffer (buf);      /* the real one */
1506       CHECK("glDrawBuffer");
1507 # endif
1508     }
1509 }
1510
1511
1512 /* Given an array of sets of 4 elements of arbitrary size, convert it
1513    to an array of sets of 6 elements instead: ABCD becomes ABC BCD.
1514  */
1515 static int
1516 cq2t (unsigned char **arrayP, int stride, int count)
1517 {
1518   int count2 = count * 6 / 4;
1519   int size  = stride * count;
1520   int size2 = stride * count2;
1521   const unsigned char    *oarray,  *in;
1522   unsigned char *array2, *oarray2, *out;
1523   int i;
1524
1525   oarray = *arrayP;
1526   if (!oarray || count == 0)
1527     return count2;
1528
1529   array2 = (unsigned char *) malloc (size2);
1530   Assert (array2, "out of memory");
1531   oarray2 = array2;
1532
1533   in =  oarray;
1534   out = oarray2;
1535   for (i = 0; i < count / 4; i++)
1536     {
1537       const unsigned char *a, *b, *c, *d;       /* the 4 corners */
1538       a = in; in += stride;
1539       b = in; in += stride;
1540       c = in; in += stride;
1541       d = in; in += stride;
1542
1543 # define PUSH(IN) do {                  \
1544          const unsigned char *ii = IN;  \
1545          int j;                         \
1546          for (j = 0; j < stride; j++) { \
1547            *out++ = *ii++;              \
1548          }} while(0)
1549
1550       PUSH (a); PUSH (b); PUSH (d);             /* the 2 triangles */
1551       PUSH (b); PUSH (c); PUSH (d);
1552 # undef PUSH
1553     }
1554
1555   Assert (in  == oarray  + size,  "convert_quads corrupted");
1556   Assert (out == oarray2 + size2, "convert_quads corrupted");
1557
1558   free (*arrayP);
1559   *arrayP = oarray2;
1560   return count2;
1561 }
1562                               
1563
1564 /* Convert all coordinates in a GL_QUADS vert_set to GL_TRIANGLES.
1565  */
1566 static void
1567 convert_quads_to_triangles (vert_set *s)
1568 {
1569   int count2;
1570   Assert (s->mode == GL_QUADS, "convert_quads bad mode");
1571   count2 =
1572    cq2t ((unsigned char **) &s->verts, sizeof(*s->verts), s->count);
1573    cq2t ((unsigned char **) &s->norms, sizeof(*s->norms), s->count);
1574    cq2t ((unsigned char **) &s->tex,   sizeof(*s->tex),   s->count);
1575    cq2t ((unsigned char **) &s->color, sizeof(*s->color), s->count);
1576   s->count = count2;
1577   s->size  = count2;
1578   s->mode = GL_TRIANGLES;
1579 }
1580
1581
1582 void
1583 jwzgles_glEnd (void)
1584 {
1585   vert_set *s = &state->set;
1586   int was_norm, was_tex, was_color, was_mat;
1587   int  is_norm,  is_tex,  is_color,  is_mat;
1588
1589   Assert (state->compiling_verts == 1, "missing glBegin");
1590   state->compiling_verts--;
1591
1592   Assert (!state->replaying_list, "how did glEnd get into a display list?");
1593
1594   if (!state->replaying_list)
1595     {
1596       LOG5 ("%s  [V = %d, N = %d, T = %d, C = %d]",
1597             (state->compiling_list || state->replaying_list ? "  " : ""),
1598             s->count, s->ncount, s->tcount, s->ccount);
1599       LOG1 ("%sglEnd",
1600             (state->compiling_list || state->replaying_list ? "  " : ""));
1601     }
1602
1603   if (s->count == 0) return;
1604
1605   if (s->mode == GL_QUADS)
1606     convert_quads_to_triangles (s);
1607   else if (s->mode == GL_QUAD_STRIP)
1608     s->mode = GL_TRIANGLE_STRIP;        /* They do the same thing! */
1609   else if (s->mode == GL_POLYGON)
1610     s->mode = GL_TRIANGLE_FAN;          /* They do the same thing! */
1611
1612   glVertexPointer   (4, GL_FLOAT, sizeof(*s->verts), s->verts);  /* XYZW */
1613   glNormalPointer   (   GL_FLOAT, sizeof(*s->norms), s->norms);  /* XYZ  */
1614   glTexCoordPointer (4, GL_FLOAT, sizeof(*s->tex),   s->tex);    /* STRQ */
1615   glColorPointer    (4, GL_FLOAT, sizeof(*s->color), s->color);  /* RGBA */
1616   CHECK("glColorPointer");
1617
1618   /* If there were no calls to glNormal3f inside of glBegin/glEnd,
1619      don't bother enabling the normals array.
1620
1621      If there was exactly *one* call to glNormal3f inside of glBegin/glEnd,
1622      and it was before the first glVertex3f, then also don't enable the
1623      normals array, but do emit that call to glNormal3f before calling
1624      glDrawArrays.
1625
1626      Likewise for texture coordinates and colors.
1627
1628      Be careful to leave the arrays' enabled/disabled state the same as
1629      before, or a later caller might end up using one of our arrays by
1630      mistake.  #### Actually this isn't quite right: if glEnd is in a
1631      list, it saves the trailing enable/disable calls in the list, instead
1632      if restoring them to what their state was before the list was run.
1633   */
1634   was_norm  = jwzgles_glIsEnabled (GL_NORMAL_ARRAY);
1635   was_tex   = jwzgles_glIsEnabled (GL_TEXTURE_COORD_ARRAY);
1636   was_color = jwzgles_glIsEnabled (GL_COLOR_ARRAY);
1637   was_mat   = jwzgles_glIsEnabled (GL_COLOR_MATERIAL);
1638
1639   /* If we're executing glEnd in immediate mode, not from inside a display
1640      list (which is the only way it happens, because glEnd doesn't go into
1641      display lists), make sure we're not stomping on a saved buffer list:
1642      in immediate mode, vertexes are client-side only.
1643    */
1644   if (! state->compiling_list)
1645     jwzgles_glBindBuffer (GL_ARRAY_BUFFER, 0);
1646
1647   if (s->ncount > 1)
1648     {
1649       is_norm = 1;
1650       jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
1651     }
1652   else
1653     {
1654       is_norm = 0;
1655       if (s->ncount == 1)
1656         jwzgles_glNormal3f (s->cnorm.x, s->cnorm.y, s->cnorm.z);
1657       jwzgles_glDisableClientState (GL_NORMAL_ARRAY);
1658     }
1659
1660   if (s->tcount > 1)
1661     {
1662       is_tex = 1;
1663       jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
1664     }
1665   else
1666     {
1667       is_tex = 0;
1668       if (s->tcount == 1)
1669         jwzgles_glTexCoord4f (s->ctex.s, s->ctex.t, s->ctex.r, s->ctex.q);
1670       jwzgles_glDisableClientState (GL_TEXTURE_COORD_ARRAY);
1671     }
1672
1673   if (s->ccount > 1)
1674     {
1675       is_color = 1;
1676       jwzgles_glEnableClientState (GL_COLOR_ARRAY);
1677     }
1678   else
1679     {
1680       is_color = 0;
1681       if (s->ccount == 1)
1682         jwzgles_glColor4f (s->ccolor.r, s->ccolor.g, s->ccolor.b, s->ccolor.a);
1683       jwzgles_glDisableClientState (GL_COLOR_ARRAY);
1684     }
1685
1686   jwzgles_glEnableClientState (GL_VERTEX_ARRAY);
1687
1688   /* We translated the glMaterial calls to per-vertex colors, which are
1689      of the glColor sort, not the glMaterial sort, so automatically
1690      turn on material mapping.  Maybe this is a bad idea.
1691    */
1692   if (s->materialistic && !jwzgles_glIsEnabled (GL_COLOR_MATERIAL))
1693     {
1694       is_mat = 1;
1695       jwzgles_glEnable (GL_COLOR_MATERIAL);
1696     }
1697   else
1698     is_mat = 0;
1699
1700   glBindBuffer (GL_ARRAY_BUFFER, 0);    /* This comes later. */
1701   jwzgles_glDrawArrays (s->mode, 0, s->count);
1702   glBindBuffer (GL_ARRAY_BUFFER, 0);    /* Keep out of others' hands */
1703
1704 # define RESET(VAR,FN,ARG) do { \
1705          if (is_##VAR != was_##VAR) { \
1706             if (was_##VAR) jwzgles_glEnable##FN (ARG); \
1707             else jwzgles_glDisable##FN (ARG); \
1708          }} while(0)
1709   RESET (norm,  ClientState, GL_NORMAL_ARRAY);
1710   RESET (tex,   ClientState, GL_TEXTURE_COORD_ARRAY);
1711   RESET (color, ClientState, GL_COLOR_ARRAY);
1712   RESET (mat,   ,            GL_COLOR_MATERIAL);
1713 # undef RESET
1714
1715   s->count  = 0;
1716   s->ncount = 0;
1717   s->tcount = 0;
1718   s->ccount = 0;
1719   s->materialistic = 0;
1720 }
1721
1722
1723 /* The display list is full of calls to glDrawArrays(), plus saved arrays
1724    of the values we need to restore before calling it.  "Restore" means
1725    "ship them off to the GPU before each call".
1726
1727    So instead, this function walks through the display list and
1728    combines all of those vertex, normal, texture and color values into
1729    a single VBO array; ships those values off to the GPU *once* at the
1730    time of glEndList; and when running the list with glCallList, the
1731    values are already on the GPU and don't need to be sent over again.
1732
1733    The VBO persists in the GPU until the display list is deleted.
1734  */
1735 static void
1736 optimize_arrays (void)
1737 {
1738   list *L = &state->lists.lists[state->compiling_list-1];
1739   int i, j;
1740   GLfloat *combo = 0;
1741   int combo_count = 0;
1742   int combo_size = 0;
1743   GLuint buf_name = 0;
1744
1745   Assert (state->compiling_list, "not compiling a list");
1746   Assert (L, "no list");
1747   Assert (!L->buffer, "list already has a buffer");
1748
1749   glGenBuffers (1, &buf_name);
1750   CHECK("glGenBuffers");
1751   if (! buf_name) return;
1752
1753   L->buffer = buf_name;
1754
1755   /* Go through the list and dump the contents of the various saved arrays
1756      into one large array.
1757    */
1758   for (i = 0; i < L->count; i++)
1759     {
1760       list_fn *F = &L->fns[i];
1761       int count;
1762       if (! F->arrays)
1763         continue;
1764       count = F->argv[2].i;  /* 3rd arg to glDrawArrays */
1765
1766       for (j = 0; j < 4; j++)
1767         {
1768           draw_array *A = &F->arrays[j];
1769           int ocount = combo_count;
1770
1771           /* If some caller is using arrays that don't have floats in them,
1772              we just leave them as-is and ship them over at each call.
1773              Doubt this ever really happens.
1774            */
1775           if (A->type != GL_FLOAT)
1776             continue;
1777
1778           if (! A->data)        /* No array. */
1779             continue;
1780
1781           Assert (A->bytes > 0, "no bytes in draw_array");
1782           Assert (((unsigned long) A->data > 0xFFFF),
1783                   "buffer data not a pointer");
1784
1785           combo_count += A->bytes / sizeof(*combo);
1786           make_room ("optimize_arrays",
1787                      (void **) &combo, sizeof(*combo),
1788                      &combo_count, &combo_size);
1789           memcpy (combo + ocount, A->data, A->bytes);
1790           A->binding = buf_name;
1791           free (A->data);
1792           /* 'data' is now the byte offset into the VBO. */
1793           A->data = (void *) (ocount * sizeof(*combo));
1794           /* LOG3("    loaded %lu floats to pos %d of buffer %d",
1795                A->bytes / sizeof(*combo), ocount, buf_name); */
1796         }
1797     }
1798
1799   if (combo_count == 0)         /* Nothing to do! */
1800     {
1801       if (combo) free (combo);
1802       glDeleteBuffers (1, &buf_name);
1803       L->buffer = 0;
1804       return;
1805     }
1806
1807   glBindBuffer (GL_ARRAY_BUFFER, buf_name);
1808   glBufferData (GL_ARRAY_BUFFER, 
1809                 combo_count * sizeof (*combo),
1810                 combo,
1811                 GL_STATIC_DRAW);
1812   glBindBuffer (GL_ARRAY_BUFFER, 0);    /* Keep out of others' hands */
1813
1814   LOG3("  loaded %d floats of list %d into VBO %d",
1815        combo_count, state->compiling_list, buf_name);
1816
1817 # ifdef DEBUG
1818 #  if 0
1819   for (i = 0; i < combo_count; i++)
1820     {
1821       if (i % 4 == 0)
1822         fprintf (stderr, "\njwzgles:    %4d: ", i);
1823       fprintf (stderr, " %7.3f", combo[i]);
1824     }
1825   fprintf (stderr, "\n");
1826 #  endif
1827 # endif /* DEBUG */
1828
1829   if (combo) free (combo);
1830 }
1831
1832
1833 void
1834 jwzgles_glCallList (int id)
1835 {
1836   if (state->compiling_list)
1837     {
1838       /* Yes, you can call lists inside of lists.
1839          Yes, recursion would be a mistake. */
1840       void_int vv[1];
1841       vv[0].i = id;
1842       list_push ("glCallList", (list_fn_cb) &jwzgles_glCallList, PROTO_I, vv);
1843     }
1844   else
1845     {
1846       list *L;
1847       int i;
1848
1849       state->replaying_list++;
1850
1851 # ifdef DEBUG
1852       fprintf (stderr, "\n");
1853       LOG1 ("glCallList %d", id);
1854 # endif
1855
1856       Assert (id > 0 && id <= state->lists.count, "glCallList: bogus ID");
1857       L = &state->lists.lists[id-1];
1858       Assert (id == L->id, "glCallList corrupted");
1859
1860       for (i = 0; i < L->count; i++)
1861         {
1862           list_fn *F = &L->fns[i];
1863           list_fn_cb fn = F->fn;
1864           void_int *av = F->argv;
1865
1866           switch (F->proto) {
1867           case PROTO_VOID:
1868             LOG1 ("  call %-12s", F->name);
1869             ((void (*) (void)) fn) ();
1870             break;
1871
1872           case PROTO_I:
1873             if (fn == (list_fn_cb) &jwzgles_glBegin ||
1874                 fn == (list_fn_cb) &jwzgles_glFrontFace ||
1875                 fn == (list_fn_cb) &jwzgles_glEnable ||
1876                 fn == (list_fn_cb) &jwzgles_glDisable ||
1877                 fn == (list_fn_cb) &jwzgles_glEnableClientState ||
1878                 fn == (list_fn_cb) &jwzgles_glDisableClientState ||
1879                 fn == (list_fn_cb) &jwzgles_glShadeModel ||
1880                 fn == (list_fn_cb) &jwzgles_glMatrixMode)
1881               LOG2 ("  call %-12s %s", F->name, mode_desc (av[0].i));
1882             else
1883               LOG2 ("  call %-12s %d", F->name, av[0].i);
1884             ((void (*) (int)) fn) (av[0].i);
1885             break;
1886
1887           case PROTO_F:
1888             LOG2 ("  call %-12s %7.3f", F->name, av[0].f);
1889             ((void (*) (GLfloat)) fn) (av[0].f);
1890             break;
1891
1892           case PROTO_II:
1893             if (fn == (list_fn_cb) &jwzgles_glBindTexture ||
1894                 fn == (list_fn_cb) &jwzgles_glBindBuffer)
1895               LOG3 ("  call %-12s %s %d", F->name, 
1896                     mode_desc (av[0].i), av[1].i);
1897             else
1898               LOG3 ("  call %-12s %d %d", F->name, av[0].i, av[1].i);
1899             ((void (*) (int, int)) fn) (av[0].i, av[1].i);
1900             break;
1901
1902           case PROTO_FF:
1903             LOG3 ("  call %-12s %7.3f %7.3f", F->name, av[0].f, av[1].f);
1904             ((void (*) (GLfloat, GLfloat)) fn) (av[0].f, av[1].f);
1905             break;
1906
1907           case PROTO_IF:
1908             LOG3 ("  call %-12s %s %7.3f", F->name, 
1909                   mode_desc (av[0].f), av[1].f);
1910             ((void (*) (GLint, GLfloat)) fn) (av[0].i, av[1].f);
1911             break;
1912
1913           case PROTO_III: III:
1914             if (fn == (list_fn_cb) &jwzgles_glDrawArrays ||
1915                 fn == (list_fn_cb) &jwzgles_glTexParameteri)
1916               LOG4 ("  call %-12s %s %d %d", F->name, 
1917                     mode_desc (av[0].i), av[1].i, av[2].i);
1918             else
1919               LOG4 ("  call %-12s %d %d %d", F->name, 
1920                     av[0].i, av[1].i, av[2].i);
1921             ((void (*) (int, int, int)) fn) (av[0].i, av[1].i, av[2].i);
1922             break;
1923
1924           case PROTO_FFF:
1925             LOG4 ("  call %-12s %7.3f %7.3f %7.3f", F->name,
1926                   av[0].f, av[1].f, av[2].f);
1927             ((void (*) (GLfloat, GLfloat, GLfloat)) fn)
1928               (av[0].f, av[1].f, av[2].f);
1929             break;
1930
1931           case PROTO_IIF:
1932             LOG4 ("  call %-12s %s %s %7.3f", F->name,
1933                   mode_desc (av[0].i), mode_desc (av[1].i), av[2].f);
1934             ((void (*) (int, int, GLfloat)) fn) (av[0].i, av[1].i, av[2].f);
1935             break;
1936
1937           case PROTO_IIII:
1938             LOG5 ("  call %-12s %d %d %d %d", F->name,
1939                   av[0].i, av[1].i, av[2].i, av[3].i);
1940             ((void (*) (int, int, int, int)) fn) 
1941               (av[0].i, av[1].i, av[2].i, av[3].i);
1942             break;
1943
1944           case PROTO_FFFF:
1945             LOG5 ("  call %-12s %7.3f %7.3f %7.3f %7.3f", F->name,
1946                   av[0].f, av[1].f, av[2].f, av[3].f);
1947             ((void (*) (GLfloat, GLfloat, GLfloat, GLfloat)) fn)
1948               (av[0].f, av[1].f, av[2].f, av[3].f);
1949             break;
1950
1951           case PROTO_IFV:
1952             {
1953               GLfloat v[4];
1954               v[0] = av[1].f;
1955               v[1] = av[2].f;
1956               v[2] = av[3].f;
1957               v[3] = av[4].f;
1958               LOG6 ("  call %-12s %s %3.1f %3.1f %3.1f %3.1f", F->name,
1959                     mode_desc (av[0].i),
1960                     av[1].f, av[2].f, av[3].f, av[4].f);
1961               ((void (*) (int, const GLfloat *)) fn) (av[0].i, v);
1962             }
1963             break;
1964
1965           case PROTO_IIFV:
1966             {
1967               GLfloat v[4];
1968               v[0] = av[2].f;
1969               v[1] = av[3].f;
1970               v[2] = av[4].f;
1971               v[3] = av[5].f;
1972               LOG7 ("  call %-12s %s %-8s %3.1f %3.1f %3.1f %3.1f", F->name,
1973                     mode_desc (av[0].i), mode_desc (av[1].i), 
1974                     av[2].f, av[3].f, av[4].f, av[5].f);
1975               ((void (*) (int, int, const GLfloat *)) fn) 
1976                 (av[0].i, av[1].i, v);
1977             }
1978             break;
1979
1980           case PROTO_IIV:
1981             {
1982               int v[4];
1983               v[0] = av[1].i;
1984               v[1] = av[2].i;
1985               v[2] = av[3].i;
1986               v[3] = av[4].i;
1987               LOG6 ("  call %-12s %s %3d %3d %3d %3d", F->name, 
1988                     mode_desc (av[0].i),
1989                     av[1].i, av[2].i, av[3].i, av[4].i);
1990               ((void (*) (int, const int *)) fn) (av[0].i, v);
1991             }
1992             break;
1993
1994           case PROTO_IIIV:
1995             {
1996               int v[4];
1997               v[0] = av[2].i;
1998               v[1] = av[3].i;
1999               v[2] = av[4].i;
2000               v[3] = av[5].i;
2001               LOG7 ("  call %-12s %s %-8s %3d %3d %3d %3d", F->name,
2002                     mode_desc (av[0].i), mode_desc (av[1].i), 
2003                     av[2].i, av[3].i, av[4].i, av[5].i);
2004               ((void (*) (int, int, const int *)) fn) 
2005                 (av[0].i, av[1].i, v);
2006             }
2007             break;
2008
2009           case PROTO_ARRAYS:
2010             restore_arrays (F, av[1].i + av[2].i);
2011             goto III;
2012             break;
2013
2014           case PROTO_FV16:
2015             {
2016               GLfloat m[16];
2017               int i;
2018               for (i = 0; i < countof(m); i++)
2019                 m[i] = av[i].f;
2020               LOG17 ("  call %-12s ["
2021                      "%8.3f %8.3f %8.3f %8.3f " "\n\t\t\t       "
2022                      "%8.3f %8.3f %8.3f %8.3f " "\n\t\t\t       "
2023                      "%8.3f %8.3f %8.3f %8.3f " "\n\t\t\t       "
2024                      "%8.3f %8.3f %8.3f %8.3f ]",
2025                      F->name,
2026                      m[0],  m[1],  m[2],  m[3],
2027                      m[4],  m[5],  m[6],  m[7],
2028                      m[8],  m[9],  m[10], m[11],
2029                      m[12], m[13], m[14], m[15]);
2030               ((void (*) (GLfloat *)) fn) (m);
2031             }
2032             break;
2033
2034           default:
2035             Assert (0, "bogus prototype");
2036             break;
2037           }
2038         }
2039
2040       LOG1 ("glCallList %d done\n", id);
2041
2042       state->replaying_list--;
2043       Assert (state->replaying_list >= 0, "glCallList corrupted");
2044     }
2045 }
2046
2047
2048 /* When we save a call to glDrawArrays into a display list, we also need to
2049    save the prevailing copy of the arrays that it will use, and restore them
2050    later.
2051  */
2052 static void
2053 save_arrays (list_fn *F, int count)
2054 {
2055   int i = 0;
2056   draw_array *A = (draw_array *) calloc (4, sizeof (*A));
2057   Assert (A, "out of memory");
2058
2059 /*  if (state->set.count > 0) */
2060     {
2061       glGetIntegerv (GL_VERTEX_ARRAY_BUFFER_BINDING, &A[i].binding);
2062       glGetIntegerv (GL_VERTEX_ARRAY_SIZE,    &A[i].size);
2063       glGetIntegerv (GL_VERTEX_ARRAY_TYPE,    &A[i].type);
2064       glGetIntegerv (GL_VERTEX_ARRAY_STRIDE,  &A[i].stride);
2065       glGetPointerv (GL_VERTEX_ARRAY_POINTER, &A[i].data);
2066       CHECK("glGetPointerv");
2067       copy_array_data (&A[i], count, "vert");
2068     }
2069
2070   i++;
2071   if (state->set.ncount > 1)
2072     {
2073       A[i].size = 3;
2074       glGetIntegerv (GL_NORMAL_ARRAY_BUFFER_BINDING, &A[i].binding);
2075       glGetIntegerv (GL_NORMAL_ARRAY_TYPE,    &A[i].type);
2076       glGetIntegerv (GL_NORMAL_ARRAY_STRIDE,  &A[i].stride);
2077       glGetPointerv (GL_NORMAL_ARRAY_POINTER, &A[i].data);
2078       CHECK("glGetPointerv");
2079       copy_array_data (&A[i], count, "norm");
2080     }
2081
2082   i++;
2083   if (state->set.tcount > 1)
2084     {
2085       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING, &A[i].binding);
2086       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_SIZE,    &A[i].size);
2087       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_TYPE,    &A[i].type);
2088       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_STRIDE,  &A[i].stride);
2089       glGetPointerv (GL_TEXTURE_COORD_ARRAY_POINTER, &A[i].data);
2090       CHECK("glGetPointerv");
2091       copy_array_data (&A[i], count, "tex ");
2092     }
2093
2094   i++;
2095   if (state->set.ccount > 1)
2096     {
2097       glGetIntegerv (GL_COLOR_ARRAY_BUFFER_BINDING, &A[i].binding);
2098       glGetIntegerv (GL_COLOR_ARRAY_SIZE,    &A[i].size);
2099       glGetIntegerv (GL_COLOR_ARRAY_TYPE,    &A[i].type);
2100       glGetIntegerv (GL_COLOR_ARRAY_STRIDE,  &A[i].stride);
2101       glGetPointerv (GL_COLOR_ARRAY_POINTER, &A[i].data);
2102       CHECK("glGetPointerv");
2103       copy_array_data (&A[i], count, "col ");
2104     }
2105
2106   /* Freed by glDeleteLists. */
2107
2108   Assert (!F->arrays, "save_arrays corrupted");
2109   F->arrays = A;
2110 }
2111
2112
2113 #ifdef DEBUG
2114
2115 static void
2116 dump_array_data (draw_array *A, int count,
2117                  const char *action, const char *name, const void *old)
2118 {
2119   int bytes = count * A->stride;
2120
2121   if (A->binding)
2122     {
2123       fprintf (stderr, 
2124                "jwzgles:     %s %s %d %s %2d, %4d = %5d   bind %d @ %d\n", 
2125                action, name,
2126                A->size, mode_desc(A->type), A->stride, 
2127                count, bytes, A->binding, (int) A->data);
2128     }
2129   else
2130     {
2131       Assert (bytes == A->bytes, "array data corrupted");
2132
2133       fprintf (stderr, "jwzgles:     %s %s %d %s %2d, %4d = %5d @ %lX", 
2134                action, name,
2135                A->size, mode_desc(A->type), A->stride, 
2136                count, bytes, (unsigned long) A->data);
2137       if (old)
2138         fprintf (stderr, " / %lX", (unsigned long) old);
2139       fprintf (stderr, "\n");
2140     }
2141
2142   if (A->binding)
2143     {
2144       Assert (((unsigned long) A->data < 0xFFFF),
2145               "buffer binding should be a numeric index,"
2146               " but looks like a pointer");
2147
2148 # if 0
2149       /* glGetBufferSubData doesn't actually exist in OpenGLES, but this
2150          was helpful for debugging on real OpenGL... */
2151       GLfloat *d;
2152       int i;
2153       fprintf (stderr, "jwzgles: read back:\n");
2154       d = (GLfloat *) malloc (A->bytes);
2155       glGetBufferSubData (GL_ARRAY_BUFFER, (int) A->data,
2156                           count * A->stride, (void *) d);
2157       CHECK("glGetBufferSubData");
2158       for (i = 0; i < count * A->size; i++)
2159         {
2160           if (i % 4 == 0)
2161             fprintf (stderr, "\njwzgles:    %4d: ", 
2162                      i + (int) A->data / sizeof(GLfloat));
2163           fprintf (stderr, " %7.3f", d[i]);
2164         }
2165       fprintf (stderr, "\n");
2166       free (d);
2167 # endif
2168     }
2169 # if 0
2170   else
2171     {
2172       unsigned char *b = (unsigned char *) A->data;
2173       int i;
2174       if ((unsigned long) A->data < 0xFFFF)
2175         {
2176           Assert (0, "buffer data not a pointer");
2177           return;
2178         }
2179       for (i = 0; i < count; i++)
2180         {
2181           int j;
2182           GLfloat *f = (GLfloat *) b;
2183           int s = A->size;
2184           if (s == 0) s = 3;  /* normals */
2185           fprintf (stderr, "jwzgles:    ");
2186           for (j = 0; j < s; j++)
2187             fprintf (stderr, " %7.3f", f[j]);
2188           fprintf (stderr, "\n");
2189           b += A->stride;
2190         }
2191     }
2192 # endif
2193 }
2194
2195 static void
2196 dump_direct_array_data (int count)
2197 {
2198   draw_array A = { 0, };
2199
2200   if (jwzgles_glIsEnabled (GL_VERTEX_ARRAY))
2201     {
2202       glGetIntegerv (GL_VERTEX_ARRAY_BUFFER_BINDING, &A.binding);
2203       glGetIntegerv (GL_VERTEX_ARRAY_SIZE,    &A.size);
2204       glGetIntegerv (GL_VERTEX_ARRAY_TYPE,    &A.type);
2205       glGetIntegerv (GL_VERTEX_ARRAY_STRIDE,  &A.stride);
2206       glGetPointerv (GL_VERTEX_ARRAY_POINTER, &A.data);
2207       A.bytes = count * A.stride;
2208       dump_array_data (&A, count, "direct", "vertex ", 0);
2209     }
2210   if (jwzgles_glIsEnabled (GL_NORMAL_ARRAY))
2211     {
2212       A.size = 0;
2213       glGetIntegerv (GL_NORMAL_ARRAY_BUFFER_BINDING, &A.binding);
2214       glGetIntegerv (GL_NORMAL_ARRAY_TYPE,    &A.type);
2215       glGetIntegerv (GL_NORMAL_ARRAY_STRIDE,  &A.stride);
2216       glGetPointerv (GL_NORMAL_ARRAY_POINTER, &A.data);
2217       A.bytes = count * A.stride;
2218       dump_array_data (&A, count, "direct", "normal ", 0);
2219     }
2220   if (jwzgles_glIsEnabled (GL_TEXTURE_COORD_ARRAY))
2221     {
2222       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING, &A.binding);
2223       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_SIZE,    &A.size);
2224       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_TYPE,    &A.type);
2225       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_STRIDE,  &A.stride);
2226       glGetPointerv (GL_TEXTURE_COORD_ARRAY_POINTER, &A.data);
2227       A.bytes = count * A.stride;
2228       dump_array_data (&A, count, "direct", "texture", 0);
2229     }
2230   if (jwzgles_glIsEnabled (GL_COLOR_ARRAY))
2231     {
2232       glGetIntegerv (GL_COLOR_ARRAY_BUFFER_BINDING, &A.binding);
2233       glGetIntegerv (GL_COLOR_ARRAY_SIZE,    &A.size);
2234       glGetIntegerv (GL_COLOR_ARRAY_TYPE,    &A.type);
2235       glGetIntegerv (GL_COLOR_ARRAY_STRIDE,  &A.stride);
2236       glGetPointerv (GL_COLOR_ARRAY_POINTER, &A.data);
2237       A.bytes = count * A.stride;
2238       dump_array_data (&A, count, "direct", "color ", 0);
2239     }
2240 }
2241
2242 #endif /* DEBUG */
2243
2244
2245 static void
2246 copy_array_data (draw_array *A, int count, const char *name)
2247 {
2248   /* Instead of just memcopy'ing the whole array and obeying its previous
2249      'stride' value, we make up a more compact array.  This is because if
2250      the same array data is being used with multiple component types,
2251      e.g. with glInterleavedArrays, we don't want to copy all of the
2252      data multiple times.
2253    */
2254   int stride2, bytes, i, j;
2255   const void *old;
2256   void *data2;
2257   const GLfloat *IF;
2258   GLfloat *OF;
2259   const unsigned char *IB;
2260   unsigned char *OB;
2261
2262   if (((unsigned long) A->data) < 0xFFFF)
2263     {
2264       Assert (0, "buffer data not a pointer");
2265       return;
2266     }
2267
2268   Assert (A->size >= 2 && A->size <= 4, "bogus array size");
2269
2270   switch (A->type) {
2271   case GL_FLOAT:         stride2 = A->size * sizeof(GLfloat); break;
2272   case GL_UNSIGNED_BYTE: stride2 = A->size; break;
2273   default: Assert (0, "bogus array type"); break;
2274   }
2275
2276   bytes = count * stride2;
2277   Assert (bytes > 0, "bogus array count or stride");
2278   Assert (A->data, "missing array data");
2279   data2 = (void *) malloc (bytes);
2280   Assert (data2, "out of memory");
2281
2282   IB = (const unsigned char *) A->data;
2283   OB = (unsigned char *) data2;
2284   IF = (const GLfloat *) A->data;
2285   OF = (GLfloat *) data2;
2286
2287   switch (A->type) {
2288   case GL_FLOAT:
2289     for (i = 0; i < count; i++)
2290       {
2291         for (j = 0; j < A->size; j++)
2292           *OF++ = IF[j];
2293         IF = (const GLfloat *) (((const unsigned char *) IF) + A->stride);
2294       }
2295     break;
2296   case GL_UNSIGNED_BYTE:
2297     for (i = 0; i < count; i++)
2298       {
2299         for (j = 0; j < A->size; j++)
2300           *OB++ = IB[j];
2301         IB += A->stride;
2302       }
2303     break;
2304   default:
2305     Assert (0, "bogus array type");
2306     break;
2307   }
2308
2309   old = A->data;
2310   A->data = data2;
2311   A->bytes = bytes;
2312   A->stride = stride2;
2313
2314 # ifdef DEBUG
2315   dump_array_data (A, count, "saved", name, old);
2316 # endif
2317 }
2318
2319
2320 static void
2321 restore_arrays (list_fn *F, int count)
2322 {
2323   int i = 0;
2324   draw_array *A = F->arrays;
2325   Assert (A, "missing array");
2326
2327   for (i = 0; i < 4; i++)
2328     {
2329       const char *name = 0;
2330
2331       if (!A[i].size)
2332         continue;
2333
2334       Assert ((A[i].binding || A[i].data),
2335               "array has neither buffer binding nor data");
2336
2337       glBindBuffer (GL_ARRAY_BUFFER, A[i].binding);
2338       CHECK("glBindBuffer");
2339
2340       switch (i) {
2341       case 0: glVertexPointer  (A[i].size, A[i].type, A[i].stride, A[i].data);
2342         name = "vertex ";
2343         CHECK("glVertexPointer");
2344         break;
2345       case 1: glNormalPointer  (           A[i].type, A[i].stride, A[i].data);
2346         name = "normal ";
2347         CHECK("glNormalPointer");
2348         break;
2349       case 2: glTexCoordPointer(A[i].size, A[i].type, A[i].stride, A[i].data);
2350         name = "texture";
2351         CHECK("glTexCoordPointer");
2352         break;
2353       case 3: glColorPointer   (A[i].size, A[i].type, A[i].stride, A[i].data);
2354         name = "color  ";
2355         CHECK("glColorPointer");
2356         break;
2357       default: Assert (0, "wat"); break;
2358       }
2359
2360 # ifdef DEBUG
2361       dump_array_data (&A[i], count, "restored", name, 0);
2362 # endif
2363     }
2364
2365   glBindBuffer (GL_ARRAY_BUFFER, 0);    /* Keep out of others' hands */
2366 }
2367
2368
2369 void
2370 jwzgles_glDrawArrays (GLuint mode, GLuint first, GLuint count)
2371 {
2372   if (state->compiling_list)
2373     {
2374       void_int vv[3];
2375       vv[0].i = mode;
2376       vv[1].i = first;
2377       vv[2].i = count;
2378       list_push ("glDrawArrays", (list_fn_cb) &jwzgles_glDrawArrays,
2379                  PROTO_ARRAYS, vv);
2380     }
2381   else
2382     {
2383 # ifdef DEBUG
2384       if (! state->replaying_list) {
2385         LOG4("direct %-12s %d %d %d", "glDrawArrays", mode, first, count);
2386         dump_direct_array_data (first + count);
2387       }
2388 # endif
2389       glDrawArrays (mode, first, count);  /* the real one */
2390       CHECK("glDrawArrays");
2391     }
2392 }
2393
2394
2395 void
2396 jwzgles_glInterleavedArrays (GLenum format, GLsizei stride, const void *data)
2397 {
2398   /* We can implement this by calling the various *Pointer functions
2399      with offsets into the same data, taking advantage of stride.
2400    */
2401   const unsigned char *c = (const unsigned char *) data;
2402 # define B 1
2403 # define F sizeof(GLfloat)
2404
2405   Assert (!state->compiling_verts,
2406           "glInterleavedArrays not allowed inside glBegin");
2407
2408   jwzgles_glEnableClientState (GL_VERTEX_ARRAY);
2409
2410   if (!state->replaying_list)
2411     LOG4 ("%sglInterleavedArrays %s %d %lX", 
2412           (state->compiling_list || state->replaying_list ? "  " : ""),
2413           mode_desc (format), stride, (unsigned long) data);
2414
2415   switch (format) {
2416   case GL_V2F:
2417     glVertexPointer (2, GL_FLOAT, stride, c);
2418     CHECK("glVertexPointer");
2419     if (!state->replaying_list)
2420       LOG3 ("%s  -> glVertexPointer 2 FLOAT %d %lX", 
2421             (state->compiling_list || state->replaying_list ? "  " : ""),
2422             stride, (unsigned long) c);
2423     break;
2424   case GL_V3F:
2425     glVertexPointer (3, GL_FLOAT, stride, c);
2426     CHECK("glVertexPointer");
2427     if (!state->replaying_list)
2428       LOG3 ("%s  -> glVertexPointer 3 FLOAT %d %lX", 
2429             (state->compiling_list || state->replaying_list ? "  " : ""),
2430             stride, (unsigned long) c);
2431     break;
2432   case GL_C4UB_V2F:     
2433     if (stride == 0)
2434       stride = 4*B + 2*F;
2435     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2436     glColorPointer (4, GL_UNSIGNED_BYTE, stride, c);
2437     CHECK("glColorPointer");
2438     c += 4*B;   /* #### might be incorrect float-aligned address */
2439     glVertexPointer (2, GL_FLOAT, stride, c);
2440     break;
2441   case GL_C4UB_V3F:
2442     if (stride == 0)
2443       stride = 4*B + 3*F;
2444     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2445     glColorPointer (4, GL_UNSIGNED_BYTE, stride, c);
2446     CHECK("glColorPointer");
2447     c += 4*B;
2448     glVertexPointer (3, GL_FLOAT, stride, c);
2449     CHECK("glVertexPointer");
2450     break;
2451   case GL_C3F_V3F:
2452     if (stride == 0)
2453       stride = 3*F + 3*F;
2454     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2455     glColorPointer (3, GL_FLOAT, stride, c);
2456     CHECK("glColorPointer");
2457     c += 3*F;
2458     glVertexPointer (3, GL_FLOAT, stride, c);
2459     CHECK("glVertexPointer");
2460     break;
2461   case GL_N3F_V3F:
2462     if (stride == 0)
2463       stride = 3*F + 3*F;
2464     jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
2465     glNormalPointer (GL_FLOAT, stride, c);
2466     CHECK("glNormalPointer");
2467     if (!state->replaying_list)
2468       LOG3 ("%s  -> glNormalPointer   FLOAT %d %lX", 
2469             (state->compiling_list || state->replaying_list ? "  " : ""),
2470             stride, (unsigned long) c);
2471     c += 3*F;
2472     glVertexPointer (3, GL_FLOAT, stride, c);
2473     CHECK("glVertexPointer");
2474     if (!state->replaying_list)
2475       LOG3 ("%s  -> glVertexPointer 3 FLOAT %d %lX", 
2476             (state->compiling_list || state->replaying_list ? "  " : ""),
2477             stride, (unsigned long) c);
2478     break;
2479   case GL_C4F_N3F_V3F:
2480     if (stride == 0)
2481       stride = 4*F + 3*F + 3*F;
2482     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2483     glColorPointer (4, GL_FLOAT, stride, c);
2484     CHECK("glColorPointer");
2485     c += 4*F;
2486     jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
2487     glNormalPointer (GL_FLOAT, stride, c);
2488     CHECK("glNormalPointer");
2489     c += 3*F;
2490     glVertexPointer (3, GL_FLOAT, stride, c);
2491     CHECK("glVertexPointer");
2492     break;
2493   case GL_T2F_V3F:
2494     if (stride == 0)
2495       stride = 2*F + 3*F;
2496     jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2497     glTexCoordPointer (2, GL_FLOAT, stride, c);
2498     CHECK("glTexCoordPointer");
2499     c += 2*F;
2500     glVertexPointer (3, GL_FLOAT, stride, c);
2501     CHECK("glVertexPointer");
2502     break;
2503   case GL_T4F_V4F:
2504     if (stride == 0)
2505       stride = 4*F + 4*F;
2506     jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2507     glTexCoordPointer (4, GL_FLOAT, stride, c);
2508     CHECK("glTexCoordPointer");
2509     c += 4*F;
2510     glVertexPointer (4, GL_FLOAT, stride, c);
2511     CHECK("glVertexPointer");
2512     break;
2513   case GL_T2F_C4UB_V3F:
2514     if (stride == 0)
2515       stride = 2*F + 4*B + 3*F;
2516     jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2517     glTexCoordPointer (2, GL_FLOAT, stride, c);
2518     CHECK("glTexCoordPointer");
2519     c += 2*F;
2520     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2521     glColorPointer  (4, GL_UNSIGNED_BYTE, stride, c);
2522     CHECK("glColorPointer");
2523     c += 4*B;
2524     glVertexPointer (3, GL_FLOAT, stride, c);
2525     CHECK("glVertexPointer");
2526     break;
2527   case GL_T2F_C3F_V3F:
2528     if (stride == 0)
2529       stride = 2*F + 3*F + 3*F;
2530     jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2531     glTexCoordPointer (2, GL_FLOAT, stride, c);
2532     CHECK("glTexCoordPointer");
2533     c += 2*F;
2534     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2535     glColorPointer  (3, GL_FLOAT, stride, c);
2536     CHECK("glColorPointer");
2537     c += 3*F;
2538     glVertexPointer (3, GL_FLOAT, stride, c);
2539     CHECK("glVertexPointer");
2540     break;
2541   case GL_T2F_N3F_V3F:
2542     if (stride == 0)
2543       stride = 2*F + 3*F + 3*F;
2544     jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2545     glTexCoordPointer (2, GL_FLOAT, stride, c);
2546     CHECK("glTexCoordPointer");
2547     c += 2*F;
2548     jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
2549     glNormalPointer (GL_FLOAT, stride, c);
2550     CHECK("glNormalPointer");
2551     c += 3*F;
2552     glVertexPointer (3, GL_FLOAT, stride, c);
2553     CHECK("glVertexPointer");
2554     break;
2555   case GL_T2F_C4F_N3F_V3F:
2556     if (stride == 0)
2557       stride = 2*F + 4*F + 3*F + 3*F;
2558     jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2559     glTexCoordPointer (2, GL_FLOAT, stride, c);
2560     CHECK("glTexCoordPointer");
2561     c += 2*F;
2562     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2563     glColorPointer  (3, GL_FLOAT, stride, c);
2564     CHECK("glColorPointer");
2565     c += 3*F;
2566     jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
2567     glNormalPointer (GL_FLOAT, stride, c);
2568     CHECK("glNormalPointer");
2569     c += 3*F;
2570     glVertexPointer (3, GL_FLOAT, stride, c);
2571     CHECK("glVertexPointer");
2572     break;
2573   case GL_T4F_C4F_N3F_V4F:
2574     if (stride == 0)
2575       stride = 4*F + 4*F + 3*F + 4*F;
2576     jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2577     glTexCoordPointer (4, GL_FLOAT, stride, c);
2578     CHECK("glTexCoordPointer");
2579     c += 4*F;
2580     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2581     glColorPointer  (4, GL_FLOAT, stride, c);
2582     CHECK("glColorPointer");
2583     c += 4*F;
2584     jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
2585     glNormalPointer (GL_FLOAT, stride, c);
2586     CHECK("glNormalPointer");
2587     c += 3*F;
2588     glVertexPointer (3, GL_FLOAT, stride, c);
2589     CHECK("glVertexPointer");
2590     break;
2591   default:
2592     Assert (0, "glInterleavedArrays: bogus format");
2593     break;
2594   }
2595
2596 # undef B
2597 # undef F
2598 }
2599
2600
2601
2602 void
2603 jwzgles_glEnableClientState (GLuint cap)
2604 {
2605   if (state->compiling_list)
2606     {
2607       void_int vv[1];
2608       vv[0].i = cap;
2609       list_push ("glEnableClientState", 
2610                  (list_fn_cb) &jwzgles_glEnableClientState,
2611                  PROTO_I, vv);
2612     }
2613   else
2614     {
2615       if (! state->replaying_list)
2616         LOG2 ("direct %-12s %s", "glEnableClientState", mode_desc(cap));
2617       glEnableClientState (cap);  /* the real one */
2618       CHECK("glEnableClientState");
2619     }
2620
2621   switch (cap) {
2622   case GL_VERTEX_ARRAY:
2623     state->enabled |= ISENABLED_VERT_ARRAY;
2624     break;
2625   case GL_NORMAL_ARRAY:
2626     if (! state->compiling_verts)
2627       state->set.ncount += 2;
2628     state->enabled |= ISENABLED_NORM_ARRAY;
2629     break;
2630   case GL_TEXTURE_COORD_ARRAY:
2631     if (! state->compiling_verts)
2632       state->set.tcount += 2;
2633     state->enabled |= ISENABLED_TEX_ARRAY;
2634     break;
2635   case GL_COLOR_ARRAY:
2636     if (! state->compiling_verts)
2637       state->set.ccount += 2;
2638     state->enabled |= ISENABLED_COLOR_ARRAY;
2639     break;
2640   default: break;
2641   }
2642 }
2643
2644
2645 void
2646 jwzgles_glDisableClientState (GLuint cap)
2647 {
2648   if (state->compiling_list)
2649     {
2650       void_int vv[1];
2651       vv[0].i = cap;
2652       list_push ("glDisableClientState", 
2653                  (list_fn_cb) &jwzgles_glDisableClientState,
2654                  PROTO_I, vv);
2655     }
2656   else
2657     {
2658       if (! state->replaying_list)
2659         LOG2 ("direct %-12s %s", "glDisableClientState", mode_desc(cap));
2660       glDisableClientState (cap);  /* the real one */
2661       CHECK("glDisableClientState");
2662     }
2663
2664   switch (cap) {
2665   case GL_VERTEX_ARRAY:
2666     state->enabled &= ~ISENABLED_VERT_ARRAY;
2667     break;
2668   case GL_NORMAL_ARRAY:
2669     if (! state->compiling_verts)
2670       state->set.ncount = 0;
2671     state->enabled &= ~ISENABLED_NORM_ARRAY;
2672     break;
2673   case GL_TEXTURE_COORD_ARRAY:
2674     if (! state->compiling_verts)
2675       state->set.tcount = 0;
2676     state->enabled &= ~ISENABLED_TEX_ARRAY;
2677     break;
2678   case GL_COLOR_ARRAY:
2679     if (! state->compiling_verts)
2680       state->set.ccount = 0;
2681     state->enabled &= ~ISENABLED_COLOR_ARRAY;
2682     break;
2683   default:
2684     break;
2685   }
2686 }
2687
2688
2689 void
2690 jwzgles_glMultMatrixf (const GLfloat *m)
2691 {
2692   Assert (!state->compiling_verts,
2693           "glMultMatrixf not allowed inside glBegin");
2694   if (state->compiling_list)
2695     {
2696       void_int vv[16];
2697       int i;
2698       for (i = 0; i < countof(vv); i++)
2699         vv[i].f = m[i];
2700       list_push ("glMultMatrixf", (list_fn_cb) &jwzgles_glMultMatrixf,
2701                  PROTO_FV16, vv);
2702     }
2703   else
2704     {
2705       if (! state->replaying_list)
2706         LOG1 ("direct %-12s", "glMultMatrixf");
2707       glMultMatrixf (m);  /* the real one */
2708       CHECK("glMultMatrixf");
2709     }
2710 }
2711
2712
2713 void
2714 jwzgles_glClearIndex(GLfloat c)
2715 {
2716   /* Does GLES even do indexed color? */
2717   Assert (0, "glClearIndex unimplemented");
2718 }
2719
2720
2721 void
2722 jwzgles_glBitmap (GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig,
2723                   GLfloat xmove, GLfloat ymove, const GLubyte *bitmap)
2724 {
2725   Assert (0, "glBitmap unimplemented");
2726 }
2727
2728 void
2729 jwzgles_glPushAttrib(int flags)
2730 {
2731   Assert (0, "glPushAttrib unimplemented");
2732 }
2733
2734 void
2735 jwzgles_glPopAttrib(void)
2736 {
2737   Assert (0, "glPopAttrib unimplemented");
2738 }
2739
2740
2741 /* These are needed for object hit detection in pinion.
2742    Might need to rewrite that code entirely.  Punt for now.
2743  */
2744 void
2745 jwzgles_glInitNames (void)
2746 {
2747 /*  Assert (0, "glInitNames unimplemented");*/
2748 }
2749
2750 void
2751 jwzgles_glPushName (GLuint name)
2752 {
2753 /*  Assert (0, "glPushName unimplemented");*/
2754 }
2755
2756 GLuint
2757 jwzgles_glPopName (void)
2758 {
2759 /*  Assert (0, "glPopName unimplemented");*/
2760   return 0;
2761 }
2762
2763 GLuint
2764 jwzgles_glRenderMode (GLuint mode)
2765 {
2766 /*  Assert (0, "glRenderMode unimplemented");*/
2767   return 0;
2768 }
2769
2770 void
2771 jwzgles_glSelectBuffer (GLsizei size, GLuint *buf)
2772 {
2773 /*  Assert (0, "glSelectBuffer unimplemented");*/
2774 }
2775
2776
2777 void
2778 jwzgles_glGenTextures (GLuint n, GLuint *ret)
2779 {
2780   Assert (!state->compiling_verts,
2781           "glGenTextures not allowed inside glBegin");
2782   /* technically legal, but stupid! */
2783   Assert (!state->compiling_list,
2784           "glGenTextures not allowed inside glNewList");
2785   if (! state->replaying_list)
2786     LOG1 ("direct %-12s", "glGenTextures");
2787   glGenTextures (n, ret);  /* the real one */
2788   CHECK("glGenTextures");
2789 }
2790
2791
2792 /* return the next larger power of 2. */
2793 static int
2794 to_pow2 (int value)
2795 {
2796   int i = 1;
2797   while (i < value) i <<= 1;
2798   return i;
2799 }
2800
2801 void
2802 jwzgles_glTexImage1D (GLenum target, GLint level,
2803                       GLint internalFormat,
2804                       GLsizei width, GLint border,
2805                       GLenum format, GLenum type,
2806                       const GLvoid *data)
2807 {
2808   Assert (!state->compiling_verts, "glTexImage1D not allowed inside glBegin");
2809   /* technically legal, but stupid! */
2810   Assert (!state->compiling_list, "glTexImage1D inside glNewList");
2811   Assert (width  == to_pow2(width), "width must be a power of 2");
2812
2813   if (target == GL_TEXTURE_1D) target = GL_TEXTURE_2D;
2814   jwzgles_glTexImage2D (target, level, internalFormat, width, 1,
2815                         border, format, type, data);
2816 }
2817
2818 void
2819 jwzgles_glTexImage2D (GLenum target,
2820                       GLint     level,
2821                       GLint     internalFormat,
2822                       GLsizei   width,
2823                       GLsizei   height,
2824                       GLint     border,
2825                       GLenum    format,
2826                       GLenum    type,
2827                       const GLvoid *data)
2828 {
2829   GLvoid *d2 = (GLvoid *) data;
2830   Assert (!state->compiling_verts, "glTexImage2D not allowed inside glBegin");
2831   Assert (!state->compiling_list,  /* technically legal, but stupid! */
2832           "glTexImage2D not allowed inside glNewList");
2833
2834   Assert (width  == to_pow2(width),   "width must be a power of 2");
2835   Assert (height == to_pow2(height), "height must be a power of 2");
2836
2837   /* OpenGLES no longer supports "4" as a synonym for "RGBA". */
2838   switch (internalFormat) {
2839   case 1: internalFormat = GL_LUMINANCE; break;
2840   case 2: internalFormat = GL_LUMINANCE_ALPHA; break;
2841   case 3: internalFormat = GL_RGB; break;
2842   case 4: internalFormat = GL_RGBA; break;
2843   }
2844
2845   /* GLES does not let us omit the data pointer to create a blank texture. */
2846   if (! data)
2847     {
2848       d2 = (GLvoid *) calloc (1, width * height * sizeof(GLfloat) * 4);
2849       Assert (d2, "out of memory");
2850     }
2851
2852   if (internalFormat == GL_RGB && format == GL_RGBA)
2853     internalFormat = GL_RGBA;  /* WTF */
2854   if (type == GL_UNSIGNED_INT_8_8_8_8_REV)
2855     type = GL_UNSIGNED_BYTE;
2856
2857   if (! state->replaying_list)
2858     LOG10 ("direct %-12s %s %d %s %d %d %d %s %s 0x%lX", "glTexImage2D", 
2859            mode_desc(target), level, mode_desc(internalFormat),
2860            width, height, border, mode_desc(format), mode_desc(type),
2861            (unsigned long) d2);
2862   glTexImage2D (target, level, internalFormat, width, height, border,
2863                 format, type, d2);  /* the real one */
2864   CHECK("glTexImage2D");
2865
2866   if (d2 != data) free (d2);
2867 }
2868
2869 void
2870 jwzgles_glTexSubImage2D (GLenum target, GLint level,
2871                          GLint xoffset, GLint yoffset,
2872                          GLsizei width, GLsizei height,
2873                          GLenum format, GLenum type,
2874                          const GLvoid *pixels)
2875 {
2876   Assert (!state->compiling_verts,
2877           "glTexSubImage2D not allowed inside glBegin");
2878   Assert (!state->compiling_list,   /* technically legal, but stupid! */
2879           "glTexSubImage2D not allowed inside glNewList");
2880
2881   if (! state->replaying_list)
2882     LOG10 ("direct %-12s %s %d %d %d %d %d %s %s 0x%lX", "glTexSubImage2D", 
2883            mode_desc(target), level, xoffset, yoffset, width, height,
2884            mode_desc (format), mode_desc (type), (unsigned long) pixels);
2885   glTexSubImage2D (target, level, xoffset, yoffset, width, height,
2886                    format, type, pixels);  /* the real one */
2887   CHECK("glTexSubImage2D");
2888 }
2889
2890 void
2891 jwzgles_glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat,
2892                           GLint x, GLint y, GLsizei width, GLsizei height,
2893                           GLint border)
2894 {
2895   Assert (!state->compiling_verts, 
2896           "glCopyTexImage2D not allowed inside glBegin");
2897   Assert (!state->compiling_list,    /* technically legal, but stupid! */
2898           "glCopyTexImage2D not allowed inside glNewList");
2899   if (! state->replaying_list)
2900     LOG9 ("direct %-12s %s %d %s %d %d %d %d %d", "glCopyTexImage2D", 
2901           mode_desc(target), level, mode_desc(internalformat),
2902           x, y, width, height, border);
2903   glCopyTexImage2D (target, level, internalformat, x, y, width, height,
2904                     border);  /* the real one */
2905   CHECK("glCopyTexImage2D");
2906 }
2907
2908
2909 void
2910 jwzgles_glTexGenfv (GLenum coord, GLenum pname, const GLfloat *params)
2911 {
2912   /* OpenGLES doesn't have this at all!
2913      "Oh, just rewrite that code to use GPU shaders", they say.
2914      How fucking convenient.
2915
2916      So, when this is enabled, we could emit a GL_TEXTURE_COORD_ARRAY
2917      and compute coords for each vertex in the current GL_VERTEX_ARRAY
2918      as per http://www.opengl.org/wiki/Mathematics_of_glTexGen
2919      but holy shit, what a pain in the ass!
2920
2921      For GL_OBJECT_LINEAR, we can just re-use the vertex array as
2922      the texture array, using a proper stride.  That's hardly worth
2923      the effort, though, because bouncingcow is the only hack that
2924      uses that, and not even by default.
2925    */
2926   Assert (coord == GL_S || coord == GL_T, "glTexGenfv: unimplemented coord");
2927
2928   /* This is probably default-ish, so do nothing. */
2929   if (pname == GL_EYE_PLANE) return;
2930
2931   Assert (pname == GL_TEXTURE_GEN_MODE, "glTexGenfv: unimplemented name");
2932   Assert (params[0] == GL_EYE_LINEAR, "glTexGenfv: unimplemented mode");
2933 }
2934
2935 void
2936 jwzgles_glTexGeni (GLenum coord, GLenum pname, GLint param)
2937 {
2938   GLfloat v = param;
2939   jwzgles_glTexGenfv (coord, pname, &v);
2940 }
2941
2942
2943 int
2944 jwzgles_gluBuild2DMipmaps (GLenum target,
2945                            GLint        internalFormat,
2946                            GLsizei      width,
2947                            GLsizei      height,
2948                            GLenum       format,
2949                            GLenum       type,
2950                            const GLvoid *data)
2951 {
2952   /* Not really bothering with mipmapping; only making one level.
2953      Note that this required a corresponding hack in glTexParameterf().
2954    */
2955
2956   int w2 = to_pow2(width);
2957   int h2 = to_pow2(height);
2958
2959   void *d2 = (void *) data;
2960
2961   /* OpenGLES no longer supports "4" as a synonym for "RGBA". */
2962   switch (internalFormat) {
2963   case 1: internalFormat = GL_LUMINANCE; break;
2964   case 2: internalFormat = GL_LUMINANCE_ALPHA; break;
2965   case 3: internalFormat = GL_RGB; break;
2966   case 4: internalFormat = GL_RGBA; break;
2967   }
2968
2969 /*  if (w2 < h2) w2 = h2;
2970   if (h2 < w2) h2 = w2;*/
2971
2972   if (w2 != width || h2 != height)
2973     {
2974       /* Scale up the image bits to fit the power-of-2 texture.
2975          We have to do this because the mipmap API assumes that
2976          the texture bits go to texture coordinates 1.0 x 1.0.
2977          This could be more efficient, but it doesn't happen often.
2978       */
2979       int istride = (format == GL_RGBA ? 4 : 3);
2980       int ostride = 4;
2981       int ibpl = istride * width;
2982       int obpl = ostride * w2;
2983       int oy;
2984       const unsigned char *in = (unsigned char *) data;
2985       unsigned char *out = (void *) malloc (h2 * obpl);
2986       Assert (out, "out of memory");
2987       d2 = out;
2988
2989       for (oy = 0; oy < h2; oy++)
2990         {
2991           int iy = oy * height / h2;
2992           const unsigned char *iline = in  + (iy * ibpl);
2993           unsigned char       *oline = out + (oy * obpl);
2994           int ox;
2995           for (ox = 0; ox < w2; ox++)
2996             {
2997               int ix = ox * width / w2;
2998               const unsigned char *i = iline + (ix * istride);
2999               unsigned char       *o = oline + (ox * ostride);
3000               *o++ = *i++;  /* R */
3001               *o++ = *i++;  /* G */
3002               *o++ = *i++;  /* B */
3003               *o++ = (istride == 4 ? *i : 0xFF); /* A */
3004             }
3005         }
3006       width  = w2;
3007       height = h2;
3008       internalFormat = GL_RGBA;
3009       format = GL_RGBA;
3010     }
3011
3012   jwzgles_glTexImage2D (target, 0, internalFormat, w2, h2, 0, 
3013                         format, type, d2);
3014   if (d2 != data) free (d2);
3015
3016   return 0;
3017 }
3018
3019
3020 void
3021 jwzgles_glRectf (GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
3022 {
3023   jwzgles_glBegin (GL_POLYGON);
3024   jwzgles_glVertex2f (x1, y1);
3025   jwzgles_glVertex2f (x2, y1);
3026   jwzgles_glVertex2f (x2, y2);
3027   jwzgles_glVertex2f (x1, y2);
3028   jwzgles_glEnd ();
3029 }
3030
3031 void
3032 jwzgles_glRecti (GLint x1, GLint y1, GLint x2, GLint y2)
3033 {
3034   jwzgles_glRectf (x1, y1, x2, y2);
3035 }
3036
3037 void
3038 jwzgles_glClearDepth (GLfloat d)
3039 {
3040   /* Not sure what to do here */
3041   Assert (d == 1.0, "glClearDepth unimplemented");
3042 }
3043
3044
3045 void
3046 jwzgles_glEnable (GLuint bit)
3047 {
3048   Assert (!state->compiling_verts, "glEnable not allowed inside glBegin");
3049   if (state->compiling_list)
3050     {
3051       void_int vv[1];
3052       vv[0].i = bit;
3053       list_push ("glEnable", (list_fn_cb) &jwzgles_glEnable, PROTO_I, vv);
3054     }
3055   else
3056     {
3057       if (! state->replaying_list)
3058         LOG2 ("direct %-12s %s", "glEnable", mode_desc(bit));
3059       glEnable (bit);  /* the real one */
3060       CHECK("glEnable");
3061
3062       switch (bit) {
3063       case GL_TEXTURE_2D: state->enabled |= ISENABLED_TEXTURE_2D; break;
3064       case GL_TEXTURE_GEN_S: state->enabled |= ISENABLED_TEXTURE_GEN_S; break;
3065       case GL_TEXTURE_GEN_T: state->enabled |= ISENABLED_TEXTURE_GEN_T; break;
3066       case GL_LIGHTING: state->enabled |= ISENABLED_LIGHTING; break;
3067       case GL_BLEND: state->enabled |= ISENABLED_BLEND; break;
3068       case GL_DEPTH_TEST: state->enabled |= ISENABLED_DEPTH_TEST; break;
3069       case GL_CULL_FACE: state->enabled |= ISENABLED_CULL_FACE; break;
3070       case GL_NORMALIZE: state->enabled |= ISENABLED_NORMALIZE; break;
3071       case GL_FOG: state->enabled |= ISENABLED_FOG; break;
3072       case GL_COLOR_MATERIAL: state->enabled |= ISENABLED_COLMAT; break;
3073
3074       /* Do these work with glEnable or only with glEnableClientState? */
3075       case GL_VERTEX_ARRAY: state->enabled |= ISENABLED_VERT_ARRAY; break;
3076       case GL_NORMAL_ARRAY: state->enabled |= ISENABLED_NORM_ARRAY; break;
3077       case GL_TEXTURE_COORD_ARRAY: state->enabled |= ISENABLED_TEX_ARRAY;break;
3078       case GL_COLOR_ARRAY:  state->enabled |= ISENABLED_COLOR_ARRAY; break;
3079
3080       default: break;
3081       }
3082     }
3083 }
3084
3085
3086 void
3087 jwzgles_glDisable (GLuint bit)
3088 {
3089   Assert (!state->compiling_verts, "glDisable not allowed inside glBegin");
3090   if (state->compiling_list)
3091     {
3092       void_int vv[1];
3093       vv[0].i = bit;
3094       list_push ("glDisable", (list_fn_cb) &jwzgles_glDisable, PROTO_I, vv);
3095     }
3096   else
3097     {
3098       if (! state->replaying_list)
3099         LOG2 ("direct %-12s %s", "glDisable", mode_desc(bit));
3100       glDisable (bit);  /* the real one */
3101       CHECK("glDisable");
3102
3103       switch (bit) {
3104       case GL_TEXTURE_2D: state->enabled &= ~ISENABLED_TEXTURE_2D; break;
3105       case GL_TEXTURE_GEN_S: state->enabled &= ~ISENABLED_TEXTURE_GEN_S; break;
3106       case GL_TEXTURE_GEN_T: state->enabled &= ~ISENABLED_TEXTURE_GEN_T; break;
3107       case GL_LIGHTING: state->enabled &= ~ISENABLED_LIGHTING; break;
3108       case GL_BLEND: state->enabled &= ~ISENABLED_BLEND; break;
3109       case GL_DEPTH_TEST: state->enabled &= ~ISENABLED_DEPTH_TEST; break;
3110       case GL_CULL_FACE: state->enabled &= ~ISENABLED_CULL_FACE; break;
3111       case GL_NORMALIZE: state->enabled &= ~ISENABLED_NORMALIZE; break;
3112       case GL_FOG: state->enabled &= ~ISENABLED_FOG; break;
3113       case GL_COLOR_MATERIAL: state->enabled &= ~ISENABLED_COLMAT; break;
3114
3115       /* Do these work with glEnable or only with glEnableClientState? */
3116       case GL_VERTEX_ARRAY: state->enabled &= ~ISENABLED_VERT_ARRAY; break;
3117       case GL_NORMAL_ARRAY: state->enabled &= ~ISENABLED_NORM_ARRAY; break;
3118       case GL_TEXTURE_COORD_ARRAY: state->enabled &= ~ISENABLED_TEX_ARRAY;break;
3119       case GL_COLOR_ARRAY:  state->enabled &= ~ISENABLED_COLOR_ARRAY; break;
3120
3121       default: break;
3122       }
3123     }
3124 }
3125
3126
3127 GLboolean
3128 jwzgles_glIsEnabled (GLuint bit)
3129 {
3130  /*
3131   Assert (!state->compiling_verts, "glIsEnabled not allowed inside glBegin");
3132   Assert (!state->compiling_list,  "glIsEnabled not allowed inside glNewList");
3133   */
3134   switch (bit) {
3135   case GL_TEXTURE_2D: return !!(state->enabled & ISENABLED_TEXTURE_2D);
3136   case GL_TEXTURE_GEN_S: return !!(state->enabled & ISENABLED_TEXTURE_GEN_S);
3137   case GL_TEXTURE_GEN_T: return !!(state->enabled & ISENABLED_TEXTURE_GEN_T);
3138   case GL_LIGHTING: return !!(state->enabled & ISENABLED_LIGHTING);
3139   case GL_BLEND: return !!(state->enabled & ISENABLED_BLEND);
3140   case GL_DEPTH_TEST: return !!(state->enabled & ISENABLED_DEPTH_TEST);
3141   case GL_CULL_FACE: return !!(state->enabled & ISENABLED_CULL_FACE);
3142   case GL_NORMALIZE: return !!(state->enabled & ISENABLED_NORMALIZE);
3143   case GL_FOG: return !!(state->enabled & ISENABLED_FOG);
3144   case GL_COLOR_MATERIAL: return !!(state->enabled & ISENABLED_COLMAT);
3145
3146   /* Do these work with glEnable or only with glEnableClientState?
3147      We need to query them, and there is no glIsClientStateEnabled.
3148    */
3149   case GL_VERTEX_ARRAY: return !!(state->enabled & ISENABLED_VERT_ARRAY);
3150   case GL_NORMAL_ARRAY: return !!(state->enabled & ISENABLED_NORM_ARRAY);
3151   case GL_TEXTURE_COORD_ARRAY: return !!(state->enabled & ISENABLED_TEX_ARRAY);
3152   case GL_COLOR_ARRAY: return !!(state->enabled & ISENABLED_COLOR_ARRAY);
3153   default: Assert (0, "glIsEnabled unimplemented bit"); break;
3154   }
3155 }
3156
3157
3158 /* The spec says that OpenGLES 1.x doesn't implement glGetFloatv.
3159    Were this true, it would suck, for it would mean that there was no
3160    way to retrieve the prevailing matrixes.  To implement this, we'd
3161    have to keep track of them all on the client side by combining in
3162    all the actions of glMultMatrixf, glRotatef, etc.
3163
3164    However, Apple's iOS OpenGLES *does* provide glGetFloatv!
3165  */
3166 void
3167 jwzgles_glGetFloatv (GLenum pname, GLfloat *params)
3168 {
3169   if (! state->replaying_list)
3170     LOG2 ("direct %-12s %s", "glGetFloatv", mode_desc(pname));
3171   glGetFloatv (pname, params);  /* the real one */
3172   CHECK("glGetFloatv");
3173 }
3174
3175
3176 /* Likewise: not supposed to be there, but it is. */
3177 void
3178 jwzgles_glGetPointerv (GLenum pname, GLvoid *params)
3179 {
3180   if (! state->replaying_list)
3181     LOG2 ("direct %-12s %s", "glGetPointerv", mode_desc(pname));
3182   glGetPointerv (pname, params);  /* the real one */
3183   CHECK("glGetPointerv");
3184 }
3185
3186
3187 /* How many cells are written into the *params array.
3188    We need to know this to avoid smashing the caller's stack
3189    if they asked for a single-value parameter.
3190  */
3191 static int
3192 glGet_ret_count (GLenum pname)
3193 {
3194   switch (pname) {
3195 /*case GL_COLOR_MATRIX: */
3196   case GL_MODELVIEW_MATRIX:
3197   case GL_PROJECTION_MATRIX:
3198   case GL_TEXTURE_MATRIX:
3199 /*case GL_TRANSPOSE_COLOR_MATRIX: */
3200 /*case GL_TRANSPOSE_MODELVIEW_MATRIX: */
3201 /*case GL_TRANSPOSE_PROJECTION_MATRIX: */
3202 /*case GL_TRANSPOSE_TEXTURE_MATRIX: */
3203     return 16;
3204 /*case GL_ACCUM_CLEAR_VALUE: */
3205 /*case GL_BLEND_COLOR: */
3206   case GL_COLOR_CLEAR_VALUE:
3207   case GL_COLOR_WRITEMASK:
3208   case GL_CURRENT_COLOR:
3209 /*case GL_CURRENT_RASTER_COLOR: */
3210 /*case GL_CURRENT_RASTER_POSITION: */
3211 /*case GL_CURRENT_RASTER_SECONDARY_COLOR: */
3212 /*case GL_CURRENT_RASTER_TEXTURE_COORDS: */
3213 /*case GL_CURRENT_SECONDARY_COLOR: */
3214   case GL_CURRENT_TEXTURE_COORDS:
3215   case GL_FOG_COLOR:
3216   case GL_LIGHT_MODEL_AMBIENT:
3217 /*case GL_MAP2_GRID_DOMAIN: */
3218   case GL_SCISSOR_BOX:
3219   case GL_VIEWPORT:
3220     return 4;
3221   case GL_CURRENT_NORMAL:
3222   case GL_POINT_DISTANCE_ATTENUATION:
3223     return 3;
3224   case GL_ALIASED_LINE_WIDTH_RANGE:
3225   case GL_ALIASED_POINT_SIZE_RANGE:
3226   case GL_DEPTH_RANGE:
3227 /*case GL_LINE_WIDTH_RANGE: */
3228 /*case GL_MAP1_GRID_DOMAIN: */
3229 /*case GL_MAP2_GRID_SEGMENTS: */
3230   case GL_MAX_VIEWPORT_DIMS:
3231 /*case GL_POINT_SIZE_RANGE: */
3232   case GL_POLYGON_MODE:
3233   case GL_SMOOTH_LINE_WIDTH_RANGE:
3234   case GL_SMOOTH_POINT_SIZE_RANGE:
3235     return 2;
3236   default:
3237     return 1;
3238   }
3239 }
3240
3241
3242 void
3243 jwzgles_glGetDoublev (GLenum pname, GLdouble *params)
3244 {
3245   GLfloat m[16];
3246   int i, j = glGet_ret_count (pname);
3247   jwzgles_glGetFloatv (pname, m);
3248   for (i = 0; i < j; i++)
3249     params[i] = m[i];
3250 }
3251
3252
3253 void
3254 jwzgles_glGetIntegerv (GLenum pname, GLint *params)
3255 {
3256   GLfloat m[16];
3257   int i, j = glGet_ret_count (pname);
3258   jwzgles_glGetFloatv (pname, m);
3259   for (i = 0; i < j; i++)
3260     params[i] = m[i];
3261 }
3262
3263
3264 void
3265 jwzgles_glGetBooleanv (GLenum pname, GLboolean *params)
3266 {
3267   GLfloat m[16];
3268   int i, j = glGet_ret_count (pname);
3269   jwzgles_glGetFloatv (pname, m);
3270   for (i = 0; i < j; i++)
3271     params[i] = (m[i] != 0.0);
3272 }
3273
3274
3275 const char *
3276 jwzgles_gluErrorString (GLenum error)
3277 {
3278   static char s[20];
3279   sprintf (s, "0x%lX", (unsigned long) error);
3280   return s;
3281 }
3282
3283
3284 /* These four *Pointer calls (plus glBindBuffer and glBufferData) can
3285    be included inside glNewList, but they actually execute immediately
3286    anyway, because their data is recorded in the list by the
3287    subsequently-recorded call to glDrawArrays.  This is a little weird.
3288  */
3289 void
3290 jwzgles_glVertexPointer (GLuint size, GLuint type, GLuint stride, 
3291                          const GLvoid *ptr)
3292 {
3293   if (! state->replaying_list)
3294     LOG5 ("direct %-12s %d %s %d 0x%lX", "glVertexPointer", 
3295           size, mode_desc(type), stride, (unsigned long) ptr);
3296   glVertexPointer (size, type, stride, ptr);  /* the real one */
3297   CHECK("glVertexPointer");
3298 }
3299
3300 void
3301 jwzgles_glNormalPointer (GLuint type, GLuint stride, const GLvoid *ptr)
3302 {
3303   if (! state->replaying_list)
3304     LOG4 ("direct %-12s %s %d 0x%lX", "glNormalPointer", 
3305           mode_desc(type), stride, (unsigned long) ptr);
3306   glNormalPointer (type, stride, ptr);  /* the real one */
3307   CHECK("glNormalPointer");
3308 }
3309
3310 void
3311 jwzgles_glColorPointer (GLuint size, GLuint type, GLuint stride, 
3312                         const GLvoid *ptr)
3313 {
3314   if (! state->replaying_list)
3315     LOG5 ("direct %-12s %d %s %d 0x%lX", "glColorPointer", 
3316           size, mode_desc(type), stride, (unsigned long) ptr);
3317   glColorPointer (size, type, stride, ptr);  /* the real one */
3318   CHECK("glColorPointer");
3319 }
3320
3321 void
3322 jwzgles_glTexCoordPointer (GLuint size, GLuint type, GLuint stride, 
3323                            const GLvoid *ptr)
3324 {
3325   if (! state->replaying_list)
3326     LOG5 ("direct %-12s %d %s %d 0x%lX", "glTexCoordPointer", 
3327           size, mode_desc(type), stride, (unsigned long) ptr);
3328   glTexCoordPointer (size, type, stride, ptr);  /* the real one */
3329   CHECK("glTexCoordPointer");
3330 }
3331
3332 void
3333 jwzgles_glBindBuffer (GLuint target, GLuint buffer)
3334 {
3335   if (! state->replaying_list)
3336     LOG3 ("direct %-12s %s %d", "glBindBuffer", mode_desc(target), buffer);
3337   glBindBuffer (target, buffer);  /* the real one */
3338   CHECK("glBindBuffer");
3339 }
3340
3341 void
3342 jwzgles_glBufferData (GLenum target, GLsizeiptr size, const void *data,
3343                       GLenum usage)
3344 {
3345   if (! state->replaying_list)
3346     LOG5 ("direct %-12s %s %ld 0x%lX %s", "glBufferData",
3347           mode_desc(target), size, (unsigned long) data, mode_desc(usage));
3348   glBufferData (target, size, data, usage);  /* the real one */
3349   CHECK("glBufferData");
3350 }
3351
3352
3353 void
3354 jwzgles_glTexParameterf (GLuint target, GLuint pname, GLfloat param)
3355 {
3356   Assert (!state->compiling_verts,
3357           "glTexParameterf not allowed inside glBegin");
3358
3359   /* We don't *really* implement mipmaps, so just turn this off. */
3360   if (param == GL_LINEAR_MIPMAP_LINEAR)   param = GL_LINEAR;
3361   if (param == GL_NEAREST_MIPMAP_LINEAR)  param = GL_LINEAR;
3362   if (param == GL_LINEAR_MIPMAP_NEAREST)  param = GL_NEAREST;
3363   if (param == GL_NEAREST_MIPMAP_NEAREST) param = GL_NEAREST;
3364
3365   /* We implement 1D textures as 2D textures. */
3366   if (target == GL_TEXTURE_1D) target = GL_TEXTURE_2D;
3367
3368   /* Apparently this is another invalid enum. Just ignore it. */
3369   if ((pname == GL_TEXTURE_WRAP_S || pname == GL_TEXTURE_WRAP_T) &&
3370       param == GL_CLAMP)
3371     return;
3372
3373   if (state->compiling_list)
3374     {
3375       void_int vv[3];
3376       vv[0].i = target;
3377       vv[1].i = pname;
3378       vv[2].f = param;
3379       list_push ("glTexParameterf", (list_fn_cb) &jwzgles_glTexParameterf,
3380                  PROTO_IIF, vv);
3381     }
3382   else
3383     {
3384       if (! state->replaying_list)
3385         LOG4 ("direct %-12s %s %s %7.3f", "glTexParameterf", 
3386               mode_desc(target), mode_desc(pname), param);
3387       glTexParameterf (target, pname, param);  /* the real one */
3388       CHECK("glTexParameterf");
3389     }
3390 }
3391
3392 void
3393 jwzgles_glTexParameteri (GLuint target, GLuint pname, GLuint param)
3394 {
3395   jwzgles_glTexParameterf (target, pname, param);
3396 }
3397
3398
3399 void
3400 jwzgles_glBindTexture (GLuint target, GLuint texture)
3401 {
3402   Assert (!state->compiling_verts,
3403           "glBindTexture not allowed inside glBegin");
3404
3405   /* We implement 1D textures as 2D textures. */
3406   if (target == GL_TEXTURE_1D) target = GL_TEXTURE_2D;
3407
3408   if (state->compiling_list)
3409     {
3410       void_int vv[2];
3411       vv[0].i = target;
3412       vv[1].i = texture;
3413       list_push ("glBindTexture", (list_fn_cb) &jwzgles_glBindTexture,
3414                  PROTO_II, vv);
3415     }
3416   else
3417     {
3418       if (! state->replaying_list)
3419         LOG3 ("direct %-12s %s %d", "glBindTexture", 
3420               mode_desc(target), texture);
3421       glBindTexture (target, texture);  /* the real one */
3422       CHECK("glBindTexture");
3423     }
3424 }
3425
3426
3427
3428 /* Matrix functions, mostly cribbed from Mesa.
3429  */
3430
3431 void
3432 jwzgles_glFrustum (GLfloat left,   GLfloat right,
3433                    GLfloat bottom, GLfloat top,
3434                    GLfloat near,   GLfloat far)
3435 {
3436   GLfloat m[16];
3437   GLfloat x = (2 * near)        / (right-left);
3438   GLfloat y = (2 * near)        / (top - bottom);
3439   GLfloat a = (right + left)    / (right - left);
3440   GLfloat b = (top + bottom)    / (top - bottom);
3441   GLfloat c = -(far + near)     / (far - near);
3442   GLfloat d = -(2 * far * near) / (far - near);
3443
3444 # define M(X,Y)  m[Y * 4 + X]
3445   M(0,0) = x; M(0,1) = 0; M(0,2) =  a; M(0,3) = 0;
3446   M(1,0) = 0; M(1,1) = y; M(1,2) =  b; M(1,3) = 0;
3447   M(2,0) = 0; M(2,1) = 0; M(2,2) =  c; M(2,3) = d;
3448   M(3,0) = 0; M(3,1) = 0; M(3,2) = -1; M(3,3) = 0;
3449 # undef M
3450
3451   jwzgles_glMultMatrixf (m);
3452 }
3453
3454
3455 void
3456 jwzgles_glOrtho (GLfloat left,   GLfloat right,
3457                  GLfloat bottom, GLfloat top,
3458                  GLfloat near,   GLfloat far)
3459 {
3460   GLfloat m[16];
3461   GLfloat a = 2 / (right - left);
3462   GLfloat b = -(right + left) / (right - left);
3463   GLfloat c = 2 / (top - bottom);
3464   GLfloat d = -(top + bottom) / (top - bottom);
3465   GLfloat e = -2 / (far - near);
3466   GLfloat f = -(far + near) / (far - near);
3467
3468 # define M(X,Y)  m[Y * 4 + X]
3469   M(0,0) = a; M(0,1) = 0; M(0,2) = 0; M(0,3) = b;
3470   M(1,0) = 0; M(1,1) = c; M(1,2) = 0; M(1,3) = d;
3471   M(2,0) = 0; M(2,1) = 0; M(2,2) = e; M(2,3) = f;
3472   M(3,0) = 0; M(3,1) = 0; M(3,2) = 0; M(3,3) = 1;
3473 # undef M
3474
3475   jwzgles_glMultMatrixf (m);
3476 }
3477
3478
3479 void
3480 jwzgles_gluPerspective (GLdouble fovy, GLdouble aspect, 
3481                         GLdouble near, GLdouble far)
3482 {
3483   GLfloat m[16];
3484   double si, co, dz;
3485   double rad = fovy / 2 * M_PI / 180;
3486   double a, b, c, d;
3487
3488   dz = far - near;
3489   si = sin(rad);
3490   if (dz == 0 || si == 0 || aspect == 0)
3491     return;
3492   co = cos(rad) / si;
3493
3494   a = co / aspect;
3495   b = co;
3496   c = -(far + near) / dz;
3497   d = -2 * near * far / dz;
3498
3499 # define M(X,Y)  m[Y * 4 + X]
3500   M(0,0) = a; M(0,1) = 0; M(0,2) = 0;  M(0,3) = 0;
3501   M(1,0) = 0; M(1,1) = b; M(1,2) = 0;  M(1,3) = 0;
3502   M(2,0) = 0; M(2,1) = 0; M(2,2) = c;  M(2,3) = d;
3503   M(3,0) = 0; M(3,1) = 0; M(3,2) = -1; M(3,3) = 0;
3504 # undef M
3505
3506   jwzgles_glMultMatrixf (m);
3507 }
3508
3509
3510 void
3511 jwzgles_gluLookAt (GLfloat eyex, GLfloat eyey, GLfloat eyez,
3512                    GLfloat centerx, GLfloat centery, GLfloat centerz,
3513                    GLfloat upx, GLfloat upy, GLfloat upz)
3514 {
3515   GLfloat m[16];
3516   GLfloat x[3], y[3], z[3];
3517   GLfloat mag;
3518     
3519   /* Make rotation matrix */
3520     
3521   /* Z vector */
3522   z[0] = eyex - centerx;
3523   z[1] = eyey - centery;
3524   z[2] = eyez - centerz;
3525   mag = sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]);
3526   if (mag) {          /* mpichler, 19950515 */
3527     z[0] /= mag;
3528     z[1] /= mag;
3529     z[2] /= mag;
3530   }
3531     
3532   /* Y vector */
3533   y[0] = upx;
3534   y[1] = upy;
3535   y[2] = upz;
3536     
3537   /* X vector = Y cross Z */
3538   x[0] = y[1] * z[2] - y[2] * z[1];
3539   x[1] = -y[0] * z[2] + y[2] * z[0];
3540   x[2] = y[0] * z[1] - y[1] * z[0];
3541     
3542   /* Recompute Y = Z cross X */
3543   y[0] = z[1] * x[2] - z[2] * x[1];
3544   y[1] = -z[0] * x[2] + z[2] * x[0];
3545   y[2] = z[0] * x[1] - z[1] * x[0];
3546     
3547   /* mpichler, 19950515 */
3548   /* cross product gives area of parallelogram, which is < 1.0 for
3549    * non-perpendicular unit-length vectors; so normalize x, y here
3550    */
3551     
3552   mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
3553   if (mag) {
3554     x[0] /= mag;
3555     x[1] /= mag;
3556     x[2] /= mag;
3557   }
3558     
3559   mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
3560   if (mag) {
3561     y[0] /= mag;
3562     y[1] /= mag;
3563     y[2] /= mag;
3564   }
3565     
3566 #define M(row,col)  m[col*4+row]
3567   M(0, 0) = x[0]; M(0, 1) = x[1]; M(0, 2) = x[2]; M(0, 3) = 0.0;
3568   M(1, 0) = y[0]; M(1, 1) = y[1]; M(1, 2) = y[2]; M(1, 3) = 0.0;
3569   M(2, 0) = z[0]; M(2, 1) = z[1]; M(2, 2) = z[2]; M(2, 3) = 0.0;
3570   M(3, 0) = 0.0;  M(3, 1) = 0.0;  M(3, 2) = 0.0;  M(3, 3) = 1.0;
3571 #undef M
3572
3573   jwzgles_glMultMatrixf(m);
3574     
3575   /* Translate Eye to Origin */
3576   jwzgles_glTranslatef(-eyex, -eyey, -eyez);
3577 }
3578
3579
3580 static void __gluMultMatrixVecd (const GLdouble matrix[16],
3581                                  const GLdouble in[4],
3582                                  GLdouble out[4])
3583 {
3584   int i;
3585
3586   for (i=0; i<4; i++) {
3587     out[i] = 
3588       in[0] * matrix[0*4+i] +
3589       in[1] * matrix[1*4+i] +
3590       in[2] * matrix[2*4+i] +
3591       in[3] * matrix[3*4+i];
3592   }
3593 }
3594
3595 GLint
3596 jwzgles_gluProject (GLdouble objx, GLdouble objy, GLdouble objz, 
3597                     const GLdouble modelMatrix[16], 
3598                     const GLdouble projMatrix[16],
3599                     const GLint viewport[4],
3600                     GLdouble *winx, GLdouble *winy, GLdouble *winz)
3601 {
3602   GLdouble in[4];
3603   GLdouble out[4];
3604
3605   /* #### I suspect this is not working right.  I was seeing crazy values
3606      in lament.c.  Maybe there's some float-vs-double confusion going on?
3607    */
3608
3609   in[0]=objx;
3610   in[1]=objy;
3611   in[2]=objz;
3612   in[3]=1.0;
3613   __gluMultMatrixVecd(modelMatrix, in, out);
3614   __gluMultMatrixVecd(projMatrix, out, in);
3615   if (in[3] == 0.0) return(GL_FALSE);
3616   in[0] /= in[3];
3617   in[1] /= in[3];
3618   in[2] /= in[3];
3619   /* Map x, y and z to range 0-1 */
3620   in[0] = in[0] * 0.5 + 0.5;
3621   in[1] = in[1] * 0.5 + 0.5;
3622   in[2] = in[2] * 0.5 + 0.5;
3623
3624   /* Map x,y to viewport */
3625   in[0] = in[0] * viewport[2] + viewport[0];
3626   in[1] = in[1] * viewport[3] + viewport[1];
3627
3628   *winx=in[0];
3629   *winy=in[1];
3630   *winz=in[2];
3631   return(GL_TRUE);
3632 }
3633
3634
3635 /* The following functions are present in both OpenGL 1.1 and in OpenGLES 1,
3636    but are allowed within glNewList/glEndList, so we must wrap them to allow
3637    them to either be recorded in lists, or run directly.
3638
3639    All this CPP obscenity is me screaming in rage at all the ways that C is
3640    not Lisp, as all I want to do here is DEFADVICE.
3641  */
3642
3643 #define PROTO_V   PROTO_VOID
3644 #define TYPE_V    GLuint
3645 #define ARGS_V    void
3646 #define VARS_V    /* */
3647 #define LOGS_V    "\n"
3648 #define FILL_V    /* */
3649
3650 #define TYPE_I    GLuint
3651 #define TYPE_II   TYPE_I
3652 #define TYPE_III  TYPE_I
3653 #define TYPE_IIII TYPE_I
3654 #define ARGS_I    TYPE_I a
3655 #define ARGS_II   TYPE_I a, TYPE_I b
3656 #define ARGS_III  TYPE_I a, TYPE_I b, TYPE_I c
3657 #define ARGS_IIII TYPE_I a, TYPE_I b, TYPE_I c, TYPE_I d
3658 #define LOGS_I    "%s\n", mode_desc(a)
3659 #define LOGS_II   "%s %d\n", mode_desc(a), b
3660 #define LOGS_III  "%s %s %s\n", mode_desc(a), mode_desc(b), mode_desc(c)
3661 #define LOGS_IIII "%d %d %d %d\n", a, b, c, d
3662 #define VARS_I    a
3663 #define VARS_II   a, b
3664 #define VARS_III  a, b, c
3665 #define VARS_IIII a, b, c, d
3666 #define FILL_I    vv[0].i = a;
3667 #define FILL_II   vv[0].i = a; vv[1].i = b;
3668 #define FILL_III  vv[0].i = a; vv[1].i = b; vv[2].i = c;
3669 #define FILL_IIII vv[0].i = a; vv[1].i = b; vv[2].i = c; vv[3].i = d;
3670
3671 #define TYPE_F    GLfloat
3672 #define TYPE_FF   TYPE_F
3673 #define TYPE_FFF  TYPE_F
3674 #define TYPE_FFFF TYPE_F
3675 #define ARGS_F    TYPE_F a
3676 #define ARGS_FF   TYPE_F a, TYPE_F b
3677 #define ARGS_FFF  TYPE_F a, TYPE_F b, TYPE_F c
3678 #define ARGS_FFFF TYPE_F a, TYPE_F b, TYPE_F c, TYPE_F d
3679 #define LOGS_F    "%7.3f\n", a
3680 #define LOGS_FF   "%7.3f %7.3f\n", a, b
3681 #define LOGS_FFF  "%7.3f %7.3f %7.3f\n", a, b, c
3682 #define LOGS_FFFF "%7.3f %7.3f %7.3f %7.3f\n", a, b, c, d
3683 #define VARS_F    VARS_I
3684 #define VARS_FF   VARS_II
3685 #define VARS_FFF  VARS_III
3686 #define VARS_FFFF VARS_IIII
3687 #define FILL_F    vv[0].f = a;
3688 #define FILL_FF   vv[0].f = a; vv[1].f = b;
3689 #define FILL_FFF  vv[0].f = a; vv[1].f = b; vv[2].f = c;
3690 #define FILL_FFFF vv[0].f = a; vv[1].f = b; vv[2].f = c; vv[3].f = d;
3691
3692 #define ARGS_IF   TYPE_I a, TYPE_F b
3693 #define VARS_IF   VARS_II
3694 #define LOGS_IF   "%s %7.3f\n", mode_desc(a), b
3695 #define FILL_IF   vv[0].i = a; vv[1].f = b;
3696
3697 #define ARGS_IIF  TYPE_I a, TYPE_I b, TYPE_F c
3698 #define VARS_IIF  VARS_III
3699 #define LOGS_IIF  "%s %s %7.3f\n", mode_desc(a), mode_desc(b), c
3700 #define FILL_IIF  vv[0].i = a; vv[1].i = b; vv[2].f = c;
3701
3702 #define TYPE_IV   GLint
3703 #define ARGS_IIV  TYPE_I a, const TYPE_IV *b
3704 #define VARS_IIV  VARS_II
3705 #define LOGS_IIV  "%s %d %d %d %d\n", mode_desc(a), b[0], b[1], b[2], b[3]
3706 #define FILL_IIV  vv[0].i = a; \
3707                   vv[1].i = b[0]; vv[2].i = b[1]; \
3708                   vv[3].i = b[2]; vv[4].i = b[3];
3709
3710 #define ARGS_IFV  TYPE_I a, const TYPE_F *b
3711 #define VARS_IFV  VARS_II
3712 #define LOGS_IFV  "%s %7.3f %7.3f %7.3f %7.3f\n", mode_desc(a), \
3713                   b[0], b[1], b[2], b[3]
3714 #define FILL_IFV  vv[0].i = a; \
3715                   vv[1].f = b[0]; vv[2].f = b[1]; \
3716                   vv[3].f = b[2]; vv[4].f = b[3];
3717
3718 #define ARGS_IIIV TYPE_I a, TYPE_I b, const TYPE_IV *c
3719 #define VARS_IIIV VARS_III
3720 #define LOGS_IIIV "%s %-8s %3d %3d %3d %3d\n", mode_desc(a), mode_desc(b), \
3721                   c[0], c[1], c[2], c[3]
3722 #define FILL_IIIV vv[0].i = a; vv[1].i = b; \
3723                   vv[2].i = c[0]; vv[3].i = c[1]; \
3724                   vv[4].i = c[2]; vv[5].i = c[3];
3725
3726 #define ARGS_IIFV TYPE_I a, TYPE_I b, const TYPE_F *c
3727 #define VARS_IIFV VARS_III
3728 #define LOGS_IIFV "%s %-8s %7.3f %7.3f %7.3f %7.3f\n", \
3729                   mode_desc(a), mode_desc(b), \
3730                   c[0], c[1], c[2], c[3]
3731 #define FILL_IIFV vv[0].i = a; vv[1].i = b; \
3732                   vv[2].f = c[0]; vv[3].f = c[1]; \
3733                   vv[4].f = c[2]; vv[5].f = c[3];
3734
3735 #ifdef DEBUG
3736 # define WLOG(NAME,ARGS) \
3737   fprintf (stderr, "jwzgles: direct %-12s ", NAME); \
3738   fprintf (stderr, ARGS)
3739 #else
3740 # define WLOG(NAME,ARGS) /* */
3741 #endif
3742
3743 #define WRAP(NAME,SIG) \
3744 void jwzgles_##NAME (ARGS_##SIG)                                        \
3745 {                                                                       \
3746   Assert (!state->compiling_verts,                                      \
3747           STRINGIFY(NAME) " not allowed inside glBegin");               \
3748   if (state->compiling_list) {                                          \
3749     void_int vv[10];                                                    \
3750     FILL_##SIG                                                          \
3751     list_push (STRINGIFY(NAME), (list_fn_cb) &jwzgles_##NAME,           \
3752                PROTO_##SIG, vv);                                        \
3753   } else {                                                              \
3754     if (! state->replaying_list) {                                      \
3755       WLOG (STRINGIFY(NAME), LOGS_##SIG);                               \
3756     }                                                                   \
3757     NAME (VARS_##SIG);                                                  \
3758     CHECK(STRINGIFY(NAME));                                             \
3759   }                                                                     \
3760 }
3761
3762 WRAP (glActiveTexture,  I)
3763 WRAP (glAlphaFunc,      IF)
3764 WRAP (glBlendFunc,      II)
3765 WRAP (glClear,          I)
3766 WRAP (glClearColor,     FFFF)
3767 WRAP (glClearStencil,   I)
3768 WRAP (glColorMask,      IIII)
3769 WRAP (glCullFace,       I)
3770 WRAP (glDepthFunc,      I)
3771 WRAP (glDepthMask,      I)
3772 WRAP (glFinish,         V)
3773 WRAP (glFlush,          V)
3774 WRAP (glFogf,           IF)
3775 WRAP (glFogfv,          IFV)
3776 WRAP (glFrontFace,      I)
3777 WRAP (glHint,           II)
3778 WRAP (glLightModelf,    IF)
3779 WRAP (glLightModelfv,   IFV)
3780 WRAP (glLightf,         IIF)
3781 WRAP (glLightfv,        IIFV)
3782 WRAP (glLineWidth,      F)
3783 WRAP (glLoadIdentity,   V)
3784 WRAP (glLogicOp,        I)
3785 WRAP (glMatrixMode,     I)
3786 WRAP (glPixelStorei,    II)
3787 WRAP (glPointSize,      F)
3788 WRAP (glPolygonOffset,  FF)
3789 WRAP (glPopMatrix,      V)
3790 WRAP (glPushMatrix,     V)
3791 WRAP (glRotatef,        FFFF)
3792 WRAP (glScalef,         FFF)
3793 WRAP (glScissor,        IIII)
3794 WRAP (glShadeModel,     I)
3795 WRAP (glStencilFunc,    III)
3796 WRAP (glStencilMask,    I)
3797 WRAP (glStencilOp,      III)
3798 WRAP (glTexEnvf,        IIF)
3799 WRAP (glTexEnvi,        III)
3800 WRAP (glTranslatef,     FFF)
3801 WRAP (glViewport,       IIII)
3802 #undef  TYPE_IV
3803 #define TYPE_IV GLuint
3804 WRAP (glDeleteTextures, IIV)
3805
3806
3807 #endif /* HAVE_JWZGLES - whole file */