From http://www.jwz.org/xscreensaver/xscreensaver-5.22.tar.gz
[xscreensaver] / hacks / glx / jwzgles.c
1 /* xscreensaver, Copyright (c) 2012-2013 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 /* glColor: GLfloat */
1031
1032 void
1033 jwzgles_glColor4fv (const GLfloat *v)
1034 {
1035   if (state->compiling_list && !state->compiling_verts)
1036     {
1037       void_int vv[4];
1038       vv[0].f = v[0];
1039       vv[1].f = v[1];
1040       vv[2].f = v[2];
1041       vv[3].f = v[3];
1042       list_push ("glColor4f", (list_fn_cb) &jwzgles_glColor4f, 
1043                  PROTO_FFFF, vv);
1044     }
1045   else
1046     {
1047       if (!state->replaying_list)
1048         LOG6 ("%s%sglColor4f    %7.3f %7.3f %7.3f %7.3f", 
1049               (state->compiling_list || state->replaying_list ? "  " : ""),
1050               (state->compiling_verts ? "  rec  " : ""),
1051               v[0], v[1], v[2], v[3]);
1052
1053       if (state->compiling_verts)       /* inside glBegin */
1054         {
1055           state->set.ccolor.r = v[0];
1056           state->set.ccolor.g = v[1];
1057           state->set.ccolor.b = v[2];
1058           state->set.ccolor.a = v[3];
1059           state->set.ccount++;
1060           if (state->set.count > 0 && state->set.ccount == 1)  /* not first! */
1061             state->set.ccount++;
1062         }
1063       else                              /* outside glBegin */
1064         {
1065           glColor4f (v[0], v[1], v[2], v[3]);
1066           CHECK("glColor4");
1067         }
1068     }
1069 }
1070
1071
1072 void
1073 jwzgles_glColor4f (GLfloat r, GLfloat g, GLfloat b, GLfloat a)
1074 {
1075   GLfloat v[4];
1076   v[0] = r;
1077   v[1] = g;
1078   v[2] = b;
1079   v[3] = a;
1080   jwzgles_glColor4fv (v);
1081 }
1082
1083 void
1084 jwzgles_glColor3f (GLfloat r, GLfloat g, GLfloat b)
1085 {
1086   jwzgles_glColor4f (r, g, b, 1);
1087 }
1088
1089 void
1090 jwzgles_glColor3fv (const GLfloat *v)
1091 {
1092   jwzgles_glColor3f (v[0], v[1], v[2]);
1093 }
1094
1095
1096 /* glColor: GLdouble */
1097
1098 void
1099 jwzgles_glColor4d (GLdouble r, GLdouble g, GLdouble b, GLdouble a)
1100 {
1101   jwzgles_glColor4f (r, g, b, a);
1102 }
1103
1104 void
1105 jwzgles_glColor4dv (const GLdouble *v)
1106 {
1107   jwzgles_glColor4d (v[0], v[1], v[2], v[3]);
1108 }
1109
1110 void
1111 jwzgles_glColor3d (GLdouble r, GLdouble g, GLdouble b)
1112 {
1113   jwzgles_glColor4d (r, g, b, 1.0);
1114 }
1115
1116 void
1117 jwzgles_glColor3dv (const GLdouble *v)
1118 {
1119   jwzgles_glColor3d (v[0], v[1], v[2]);
1120 }
1121
1122
1123 /* glColor: GLint (INT_MIN - INT_MAX) */
1124
1125 void
1126 jwzgles_glColor4i (GLint r, GLint g, GLint b, GLint a)
1127 {
1128   /* -0x8000000 - 0x7FFFFFFF  =>  0.0 - 1.0 */
1129   jwzgles_glColor4f (0.5 + (GLfloat) r / 0xFFFFFFFF,
1130                      0.5 + (GLfloat) g / 0xFFFFFFFF, 
1131                      0.5 + (GLfloat) b / 0xFFFFFFFF,
1132                      0.5 + (GLfloat) a / 0xFFFFFFFF);
1133 }
1134
1135 void
1136 jwzgles_glColor4iv (const GLint *v)
1137 {
1138   jwzgles_glColor4i (v[0], v[1], v[2], v[3]);
1139 }
1140
1141
1142 void
1143 jwzgles_glColor3i (GLint r, GLint g, GLint b)
1144 {
1145   jwzgles_glColor4i (r, g, b, 0x7FFFFFFF);
1146 }
1147
1148 void
1149 jwzgles_glColor3iv (const GLint *v)
1150 {
1151   jwzgles_glColor3i (v[0], v[1], v[2]);
1152 }
1153
1154
1155 /* glColor: GLuint (0 - UINT_MAX) */
1156
1157 void
1158 jwzgles_glColor4ui (GLuint r, GLuint g, GLuint b, GLuint a)
1159 {
1160   /* 0 - 0xFFFFFFFF  =>  0.0 - 1.0 */
1161   jwzgles_glColor4f ((GLfloat) r / 0xFFFFFFFF,
1162                      (GLfloat) g / 0xFFFFFFFF, 
1163                      (GLfloat) b / 0xFFFFFFFF,
1164                      (GLfloat) a / 0xFFFFFFFF);
1165 }
1166
1167 void
1168 jwzgles_glColor4uiv (const GLuint *v)
1169 {
1170   jwzgles_glColor4ui (v[0], v[1], v[2], v[3]);
1171 }
1172
1173 void
1174 jwzgles_glColor3ui (GLuint r, GLuint g, GLuint b)
1175 {
1176   jwzgles_glColor4ui (r, g, b, 0xFFFFFFFF);
1177 }
1178
1179 void
1180 jwzgles_glColor3uiv (const GLuint *v)
1181 {
1182   jwzgles_glColor3ui (v[0], v[1], v[2]);
1183 }
1184
1185
1186 /* glColor: GLshort (SHRT_MIN - SHRT_MAX) */
1187
1188 void
1189 jwzgles_glColor4s (GLshort r, GLshort g, GLshort b, GLshort a)
1190 {
1191   /* -0x8000 - 0x7FFF  =>  0.0 - 1.0 */
1192   jwzgles_glColor4f (0.5 + (GLfloat) r / 0xFFFF,
1193                      0.5 + (GLfloat) g / 0xFFFF,
1194                      0.5 + (GLfloat) b / 0xFFFF,
1195                      0.5 + (GLfloat) a / 0xFFFF);
1196 }
1197
1198 void
1199 jwzgles_glColor4sv (const GLshort *v)
1200 {
1201   jwzgles_glColor4s (v[0], v[1], v[2], v[3]);
1202 }
1203
1204 void
1205 jwzgles_glColor3s (GLshort r, GLshort g, GLshort b)
1206 {
1207   jwzgles_glColor4s (r, g, b, 0x7FFF);
1208 }
1209
1210 void
1211 jwzgles_glColor3sv (const GLshort *v)
1212 {
1213   jwzgles_glColor3s (v[0], v[1], v[2]);
1214 }
1215
1216
1217 /* glColor: GLushort (0 - USHRT_MAX) */
1218
1219 void
1220 jwzgles_glColor4us (GLushort r, GLushort g, GLushort b, GLushort a)
1221 {
1222   /* 0 - 0xFFFF  =>  0.0 - 1.0 */
1223   jwzgles_glColor4f ((GLfloat) r / 0xFFFF,
1224                      (GLfloat) g / 0xFFFF,
1225                      (GLfloat) b / 0xFFFF,
1226                      (GLfloat) a / 0xFFFF);
1227 }
1228
1229 void
1230 jwzgles_glColor4usv (const GLushort *v)
1231 {
1232   jwzgles_glColor4us (v[0], v[1], v[2], v[3]);
1233 }
1234
1235 void
1236 jwzgles_glColor3us (GLushort r, GLushort g, GLushort b)
1237 {
1238   jwzgles_glColor4us (r, g, b, 0xFFFF);
1239 }
1240
1241 void
1242 jwzgles_glColor3usv (const GLushort *v)
1243 {
1244   jwzgles_glColor3us (v[0], v[1], v[2]);
1245 }
1246
1247
1248 /* glColor: GLbyte (-128 - 127) */
1249
1250 void
1251 jwzgles_glColor4b (GLbyte r, GLbyte g, GLbyte b, GLbyte a)
1252 {
1253   /* -128 - 127  =>  0.0 - 1.0 */
1254   jwzgles_glColor4f (0.5 + (GLfloat) r / 255,
1255                      0.5 + (GLfloat) g / 255,
1256                      0.5 + (GLfloat) b / 255,
1257                      0.5 + (GLfloat) a / 255);
1258 }
1259
1260 void
1261 jwzgles_glColor4bv (const GLbyte *v)
1262 {
1263   jwzgles_glColor4b (v[0], v[1], v[2], v[3]);
1264 }
1265
1266 void
1267 jwzgles_glColor3b (GLbyte r, GLbyte g, GLbyte b)
1268 {
1269   jwzgles_glColor4b (r, g, b, 127);
1270 }
1271
1272 void
1273 jwzgles_glColor3bv (const GLbyte *v)
1274 {
1275   jwzgles_glColor3b (v[0], v[1], v[2]);
1276 }
1277
1278
1279 /* glColor: GLubyte (0 - 255) */
1280
1281 void
1282 jwzgles_glColor4ub (GLubyte r, GLubyte g, GLubyte b, GLubyte a)
1283 {
1284   /* 0 - 255  =>  0.0 - 1.0 */
1285   jwzgles_glColor4f (r / 255.0, g / 255.0, b / 255.0, a / 255.0);
1286 }
1287
1288 void
1289 jwzgles_glColor4ubv (const GLubyte *v)
1290 {
1291   jwzgles_glColor4ub (v[0], v[1], v[2], v[3]);
1292 }
1293
1294 void
1295 jwzgles_glColor3ub (GLubyte r, GLubyte g, GLubyte b)
1296 {
1297   jwzgles_glColor4ub (r, g, b, 255);
1298 }
1299
1300 void
1301 jwzgles_glColor3ubv (const GLubyte *v)
1302 {
1303   jwzgles_glColor3ub (v[0], v[1], v[2]);
1304 }
1305
1306
1307
1308 void
1309 jwzgles_glMaterialfv (GLenum face, GLenum pname, const GLfloat *color)
1310 {
1311   /* If this is called inside glBegin/glEnd with a front ambient color,
1312      then treat it the same as glColor: set the color of the upcoming
1313      vertex.
1314
1315      Other faces or lighting types within glBegin are ignored.
1316    */
1317
1318   if (state->compiling_verts)
1319     {
1320       if ((face == GL_FRONT || 
1321            face == GL_FRONT_AND_BACK) &&
1322           (pname == GL_AMBIENT || 
1323            pname == GL_DIFFUSE || 
1324            pname == GL_AMBIENT_AND_DIFFUSE))
1325         {
1326           jwzgles_glColor4f (color[0], color[1], color[2], color[3]);
1327           state->set.materialistic++;
1328         }
1329       else
1330         LOG2 ("  IGNORING glMaterialfv %s %s",
1331               mode_desc(face), mode_desc(pname));
1332     }
1333   else if (state->compiling_list)
1334     {
1335       void_int vv[6];
1336       vv[0].i = face;
1337       vv[1].i = pname;
1338       vv[2].f = color[0];
1339       vv[3].f = color[1];
1340       vv[4].f = color[2];
1341       vv[5].f = color[3];
1342       list_push ("glMaterialfv", (list_fn_cb) &jwzgles_glMaterialfv, 
1343                  PROTO_IIFV, vv);
1344     }
1345   else
1346     {
1347       /* If this is called outside of glBegin/glEnd with a front
1348          ambient color, then the intent is presumably for that color
1349          to apply to the upcoming vertexes (which may be played back
1350          from a list that does not have vertex colors in it).  In that
1351          case, the only way to make the colors show up is to call
1352          glColor() with GL_COLOR_MATERIAL enabled.
1353
1354          I'm not sure if this will have other inappropriate side effects...
1355        */
1356       if ((face == GL_FRONT ||
1357            face == GL_FRONT_AND_BACK) &&
1358           (pname == GL_AMBIENT ||
1359            pname == GL_DIFFUSE ||
1360            pname == GL_AMBIENT_AND_DIFFUSE))
1361         {
1362           jwzgles_glEnable (GL_COLOR_MATERIAL);
1363           jwzgles_glColor4f (color[0], color[1], color[2], color[3]);
1364         }
1365
1366       /* OpenGLES seems to throw "invalid enum" for GL_FRONT -- but it
1367          goes ahead and sets the material anyway!  No error if we just
1368          always use GL_FRONT_AND_BACK.
1369        */
1370       if (face == GL_FRONT)
1371         face = GL_FRONT_AND_BACK;
1372       if (! state->replaying_list)
1373         LOG7 ("direct %-12s %s %s %7.3f %7.3f %7.3f %7.3f", "glMaterialfv",
1374               mode_desc(face), mode_desc(pname),
1375               color[0], color[1], color[2], color[3]);
1376       glMaterialfv (face, pname, color);  /* the real one */
1377       CHECK("glMaterialfv");
1378     }
1379 }
1380
1381
1382 void
1383 jwzgles_glMaterialiv (GLenum face, GLenum pname, const GLint *v)
1384 {
1385   GLfloat vv[4];
1386   vv[0] = v[0];
1387   vv[1] = v[1];
1388   vv[2] = v[2];
1389   vv[3] = 1;
1390   jwzgles_glMaterialfv (face, pname, vv);
1391 }
1392
1393 void
1394 jwzgles_glMaterialf (GLenum face, GLenum pname, const GLfloat c)
1395 {
1396   GLfloat vv[4];
1397   vv[0] = c;
1398   vv[1] = c;
1399   vv[2] = c;
1400   vv[3] = 1;
1401   jwzgles_glMaterialfv (face, pname, vv);
1402 }
1403
1404
1405 void
1406 jwzgles_glMateriali (GLenum face, GLenum pname, const GLuint c)
1407 {
1408   jwzgles_glMaterialf (face, pname, c);
1409 }
1410
1411
1412 void
1413 jwzgles_glColorMaterial (GLenum face, GLenum mode)
1414 {
1415   Assert (!state->compiling_verts,
1416           "glColorMaterial not allowed inside glBegin");
1417 #if 0
1418   if (state->compiling_list)
1419     {
1420       void_int vv[2];
1421       vv[0].i = face;
1422       vv[1].i = mode;
1423       list_push ("glColorMaterial", (list_fn_cb) &jwzgles_glColorMaterial, 
1424                  PROTO_II, vv);
1425     }
1426   else
1427     {
1428       /* No real analog to this distinction in OpenGLES, since color
1429          arrays don't distinguish between "color" and "material", */
1430       Assert (0, "glColorMaterial: unimplemented mode");
1431     }
1432 #endif
1433 }
1434
1435
1436
1437
1438 void
1439 jwzgles_glVertex4fv (const GLfloat *v)
1440 {
1441   vert_set *s = &state->set;
1442   int count = s->count;
1443
1444   Assert (state->compiling_verts, "glVertex4fv not inside glBegin");
1445
1446   LOG5("%s  rec  glVertex4f   %7.3f %7.3f %7.3f %7.3f",
1447        (state->compiling_list || state->replaying_list ? "  " : ""),
1448        v[0], v[1], v[2], v[3]);
1449
1450   if (count >= s->size - 1)
1451     {
1452       int new_size = 20 + (s->size * 1.2);
1453
1454       /* 4 arrays, different element sizes...
1455          We allocate all 4 arrays just in case we need them,
1456          but we might not end up using them all at the end.
1457       */
1458
1459       s->verts = (XYZW *) realloc (s->verts, new_size * sizeof (*s->verts));
1460       Assert (s->verts, "out of memory");
1461
1462       s->norms = (XYZ *) realloc (s->norms, new_size * sizeof (*s->norms));
1463       Assert (s->norms, "out of memory");
1464
1465       s->tex = (STRQ *) realloc (s->tex, new_size * sizeof (*s->tex));
1466       Assert (s->tex, "out of memory");
1467
1468       s->color = (RGBA *) realloc (s->color, new_size * sizeof (*s->color));
1469       Assert (s->color, "out of memory");
1470
1471       s->size = new_size;
1472     }
1473
1474   s->verts [count].x = v[0];
1475   s->verts [count].y = v[1];
1476   s->verts [count].z = v[2];
1477   s->verts [count].w = v[3];
1478   s->norms [count] = s->cnorm;
1479   s->tex   [count] = s->ctex;
1480   s->color [count] = s->ccolor;
1481   s->count++;
1482 }
1483
1484
1485 void
1486 jwzgles_glVertex4f (GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1487 {
1488   GLfloat v[4];
1489   v[0] = x;
1490   v[1] = y;
1491   v[2] = z;
1492   v[3] = w;
1493   jwzgles_glVertex4fv (v);
1494 }
1495
1496 void
1497 jwzgles_glVertex4i (GLint x, GLint y, GLint z, GLint w)
1498 {
1499   jwzgles_glVertex4f (x, y, z, w);
1500 }
1501
1502 void
1503 jwzgles_glVertex3f (GLfloat x, GLfloat y, GLfloat z)
1504 {
1505   GLfloat v[4];
1506   v[0] = x;
1507   v[1] = y;
1508   v[2] = z;
1509   v[3] = 1;
1510   jwzgles_glVertex4fv (v);
1511 }
1512
1513 void
1514 jwzgles_glVertex3i (GLint x, GLint y, GLint z)
1515 {
1516   jwzgles_glVertex3f (x, y, z);
1517 }
1518
1519 void
1520 jwzgles_glVertex3fv (const GLfloat *v)
1521 {
1522   jwzgles_glVertex3f (v[0], v[1], v[2]);
1523 }
1524
1525 void
1526 jwzgles_glVertex3dv (const GLdouble *v)
1527 {
1528   jwzgles_glVertex3f (v[0], v[1], v[2]);
1529 }
1530
1531
1532 void
1533 jwzgles_glVertex2f (GLfloat x, GLfloat y)
1534 {
1535   GLfloat v[3];
1536   v[0] = x;
1537   v[1] = y;
1538   v[2] = 0;
1539   jwzgles_glVertex3fv (v);
1540 }
1541
1542 void
1543 jwzgles_glVertex2fv (const GLfloat *v)
1544 {
1545   jwzgles_glVertex2f (v[0], v[1]);
1546 }
1547
1548 void
1549 jwzgles_glVertex2i (GLint x, GLint y)
1550 {
1551   jwzgles_glVertex2f (x, y);
1552 }
1553
1554
1555 void
1556 jwzgles_glLightiv (GLenum light, GLenum pname, const GLint *params)
1557 {
1558   GLfloat v[4];
1559   v[0] = params[0];
1560   v[1] = params[1];
1561   v[2] = params[2];
1562   v[3] = params[3];
1563   jwzgles_glLightfv (light, pname, v);
1564 }
1565
1566 void
1567 jwzgles_glLightModeliv (GLenum pname, const GLint *params)
1568 {
1569   GLfloat v[4];
1570   v[0] = params[0];
1571   v[1] = params[1];
1572   v[2] = params[2];
1573   v[3] = params[3];
1574   jwzgles_glLightModelfv (pname, v);
1575 }
1576
1577 void
1578 jwzgles_glFogiv (GLenum pname, const GLint *params)
1579 {
1580   GLfloat v[4];
1581   v[0] = params[0];
1582   v[1] = params[1];
1583   v[2] = params[2];
1584   v[3] = params[3];
1585   jwzgles_glFogfv (pname, v);
1586 }
1587
1588 void
1589 jwzgles_glLighti (GLenum light, GLenum pname, GLint param)
1590 {
1591   jwzgles_glLightf (light, pname, param);
1592 }
1593
1594 void
1595 jwzgles_glLightModeli (GLenum pname, GLint param)
1596 {
1597   jwzgles_glLightModelf (pname, param);
1598 }
1599
1600 void
1601 jwzgles_glFogi (GLenum pname, GLint param)
1602 {
1603   jwzgles_glFogf (pname, param);
1604 }
1605
1606
1607 void
1608 jwzgles_glRotated (GLdouble angle, GLdouble x, GLdouble y, GLdouble z)
1609 {
1610   jwzgles_glRotatef (angle, x, y, z);
1611 }
1612
1613
1614 void
1615 jwzgles_glClipPlane (GLenum plane, const GLdouble *equation)
1616 {
1617   Assert (state->compiling_verts, "glClipPlane not inside glBegin");
1618   Assert (0, "glClipPlane unimplemented");  /* no GLES equivalent... */
1619 }
1620
1621
1622 void
1623 jwzgles_glPolygonMode (GLenum face, GLenum mode)
1624 {
1625   Assert (!state->compiling_verts, "not inside glBegin");
1626   if (state->compiling_list)
1627     {
1628       void_int vv[2];
1629       vv[0].i = face;
1630       vv[1].i = mode;
1631       list_push ("glPolygonMode", (list_fn_cb) &jwzgles_glPolygonMode, 
1632                  PROTO_II, vv);
1633     }
1634   else
1635     {
1636       /* POINT and LINE don't exist in GLES */
1637       Assert (mode == GL_FILL, "glPolygonMode: unimplemented mode");
1638     }
1639 }
1640
1641
1642 void
1643 jwzgles_glDrawBuffer (GLenum buf)
1644 {
1645   Assert (!state->compiling_verts, "not inside glBegin");
1646   if (state->compiling_list)
1647     {
1648       void_int vv[1];
1649       vv[0].i = buf;
1650       list_push ("glDrawBuffer", (list_fn_cb) &jwzgles_glDrawBuffer, 
1651                  PROTO_I, vv);
1652     }
1653   else
1654     {
1655 /*      Assert (buf == GL_BACK, "glDrawBuffer: back buffer only"); */
1656 # ifndef GL_VERSION_ES_CM_1_0  /* not compiling against OpenGLES 1.x */
1657       if (! state->replaying_list)
1658         LOG1 ("direct %-12s", "glDrawBuffer");
1659       glDrawBuffer (buf);      /* the real one */
1660       CHECK("glDrawBuffer");
1661 # endif
1662     }
1663 }
1664
1665
1666 /* Given an array of sets of 4 elements of arbitrary size, convert it
1667    to an array of sets of 6 elements instead: ABCD becomes ABC BCD.
1668  */
1669 static int
1670 cq2t (unsigned char **arrayP, int stride, int count)
1671 {
1672   int count2 = count * 6 / 4;
1673   int size  = stride * count;
1674   int size2 = stride * count2;
1675   const unsigned char    *oarray,  *in;
1676   unsigned char *array2, *oarray2, *out;
1677   int i;
1678
1679   oarray = *arrayP;
1680   if (!oarray || count == 0)
1681     return count2;
1682
1683   array2 = (unsigned char *) malloc (size2);
1684   Assert (array2, "out of memory");
1685   oarray2 = array2;
1686
1687   in =  oarray;
1688   out = oarray2;
1689   for (i = 0; i < count / 4; i++)
1690     {
1691       const unsigned char *a, *b, *c, *d;       /* the 4 corners */
1692       a = in; in += stride;
1693       b = in; in += stride;
1694       c = in; in += stride;
1695       d = in; in += stride;
1696
1697 # define PUSH(IN) do {                  \
1698          const unsigned char *ii = IN;  \
1699          int j;                         \
1700          for (j = 0; j < stride; j++) { \
1701            *out++ = *ii++;              \
1702          }} while(0)
1703
1704       PUSH (a); PUSH (b); PUSH (d);             /* the 2 triangles */
1705       PUSH (b); PUSH (c); PUSH (d);
1706 # undef PUSH
1707     }
1708
1709   Assert (in  == oarray  + size,  "convert_quads corrupted");
1710   Assert (out == oarray2 + size2, "convert_quads corrupted");
1711
1712   free (*arrayP);
1713   *arrayP = oarray2;
1714   return count2;
1715 }
1716                               
1717
1718 /* Convert all coordinates in a GL_QUADS vert_set to GL_TRIANGLES.
1719  */
1720 static void
1721 convert_quads_to_triangles (vert_set *s)
1722 {
1723   int count2;
1724   Assert (s->mode == GL_QUADS, "convert_quads bad mode");
1725   count2 =
1726    cq2t ((unsigned char **) &s->verts, sizeof(*s->verts), s->count);
1727    cq2t ((unsigned char **) &s->norms, sizeof(*s->norms), s->count);
1728    cq2t ((unsigned char **) &s->tex,   sizeof(*s->tex),   s->count);
1729    cq2t ((unsigned char **) &s->color, sizeof(*s->color), s->count);
1730   s->count = count2;
1731   s->size  = count2;
1732   s->mode = GL_TRIANGLES;
1733 }
1734
1735
1736 void
1737 jwzgles_glEnd (void)
1738 {
1739   vert_set *s = &state->set;
1740   int was_norm, was_tex, was_color, was_mat;
1741   int  is_norm,  is_tex,  is_color,  is_mat;
1742
1743   Assert (state->compiling_verts == 1, "missing glBegin");
1744   state->compiling_verts--;
1745
1746   Assert (!state->replaying_list, "how did glEnd get into a display list?");
1747
1748   if (!state->replaying_list)
1749     {
1750       LOG5 ("%s  [V = %d, N = %d, T = %d, C = %d]",
1751             (state->compiling_list || state->replaying_list ? "  " : ""),
1752             s->count, s->ncount, s->tcount, s->ccount);
1753       LOG1 ("%sglEnd",
1754             (state->compiling_list || state->replaying_list ? "  " : ""));
1755     }
1756
1757   if (s->count == 0) return;
1758
1759   if (s->mode == GL_QUADS)
1760     convert_quads_to_triangles (s);
1761   else if (s->mode == GL_QUAD_STRIP)
1762     s->mode = GL_TRIANGLE_STRIP;        /* They do the same thing! */
1763   else if (s->mode == GL_POLYGON)
1764     s->mode = GL_TRIANGLE_FAN;          /* They do the same thing! */
1765
1766   glVertexPointer   (4, GL_FLOAT, sizeof(*s->verts), s->verts);  /* XYZW */
1767   glNormalPointer   (   GL_FLOAT, sizeof(*s->norms), s->norms);  /* XYZ  */
1768   glTexCoordPointer (4, GL_FLOAT, sizeof(*s->tex),   s->tex);    /* STRQ */
1769   glColorPointer    (4, GL_FLOAT, sizeof(*s->color), s->color);  /* RGBA */
1770   CHECK("glColorPointer");
1771
1772   /* If there were no calls to glNormal3f inside of glBegin/glEnd,
1773      don't bother enabling the normals array.
1774
1775      If there was exactly *one* call to glNormal3f inside of glBegin/glEnd,
1776      and it was before the first glVertex3f, then also don't enable the
1777      normals array, but do emit that call to glNormal3f before calling
1778      glDrawArrays.
1779
1780      Likewise for texture coordinates and colors.
1781
1782      Be careful to leave the arrays' enabled/disabled state the same as
1783      before, or a later caller might end up using one of our arrays by
1784      mistake.  #### Actually this isn't quite right: if glEnd is in a
1785      list, it saves the trailing enable/disable calls in the list, instead
1786      if restoring them to what their state was before the list was run.
1787   */
1788   was_norm  = jwzgles_glIsEnabled (GL_NORMAL_ARRAY);
1789   was_tex   = jwzgles_glIsEnabled (GL_TEXTURE_COORD_ARRAY);
1790   was_color = jwzgles_glIsEnabled (GL_COLOR_ARRAY);
1791   was_mat   = jwzgles_glIsEnabled (GL_COLOR_MATERIAL);
1792
1793   /* If we're executing glEnd in immediate mode, not from inside a display
1794      list (which is the only way it happens, because glEnd doesn't go into
1795      display lists), make sure we're not stomping on a saved buffer list:
1796      in immediate mode, vertexes are client-side only.
1797    */
1798   if (! state->compiling_list)
1799     jwzgles_glBindBuffer (GL_ARRAY_BUFFER, 0);
1800
1801   if (s->ncount > 1)
1802     {
1803       is_norm = 1;
1804       jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
1805     }
1806   else
1807     {
1808       is_norm = 0;
1809       if (s->ncount == 1)
1810         jwzgles_glNormal3f (s->cnorm.x, s->cnorm.y, s->cnorm.z);
1811       jwzgles_glDisableClientState (GL_NORMAL_ARRAY);
1812     }
1813
1814   if (s->tcount > 1)
1815     {
1816       is_tex = 1;
1817       jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
1818     }
1819   else
1820     {
1821       is_tex = 0;
1822       if (s->tcount == 1)
1823         jwzgles_glTexCoord4f (s->ctex.s, s->ctex.t, s->ctex.r, s->ctex.q);
1824       jwzgles_glDisableClientState (GL_TEXTURE_COORD_ARRAY);
1825     }
1826
1827   if (s->ccount > 1)
1828     {
1829       is_color = 1;
1830       jwzgles_glEnableClientState (GL_COLOR_ARRAY);
1831     }
1832   else
1833     {
1834       is_color = 0;
1835       if (s->ccount == 1)
1836         jwzgles_glColor4f (s->ccolor.r, s->ccolor.g, s->ccolor.b, s->ccolor.a);
1837       jwzgles_glDisableClientState (GL_COLOR_ARRAY);
1838     }
1839
1840   jwzgles_glEnableClientState (GL_VERTEX_ARRAY);
1841
1842   /* We translated the glMaterial calls to per-vertex colors, which are
1843      of the glColor sort, not the glMaterial sort, so automatically
1844      turn on material mapping.  Maybe this is a bad idea.
1845    */
1846   if (s->materialistic && !jwzgles_glIsEnabled (GL_COLOR_MATERIAL))
1847     {
1848       is_mat = 1;
1849       jwzgles_glEnable (GL_COLOR_MATERIAL);
1850     }
1851   else
1852     is_mat = 0;
1853
1854   glBindBuffer (GL_ARRAY_BUFFER, 0);    /* This comes later. */
1855   jwzgles_glDrawArrays (s->mode, 0, s->count);
1856   glBindBuffer (GL_ARRAY_BUFFER, 0);    /* Keep out of others' hands */
1857
1858 # define RESET(VAR,FN,ARG) do { \
1859          if (is_##VAR != was_##VAR) { \
1860             if (was_##VAR) jwzgles_glEnable##FN (ARG); \
1861             else jwzgles_glDisable##FN (ARG); \
1862          }} while(0)
1863   RESET (norm,  ClientState, GL_NORMAL_ARRAY);
1864   RESET (tex,   ClientState, GL_TEXTURE_COORD_ARRAY);
1865   RESET (color, ClientState, GL_COLOR_ARRAY);
1866   RESET (mat,   ,            GL_COLOR_MATERIAL);
1867 # undef RESET
1868
1869   s->count  = 0;
1870   s->ncount = 0;
1871   s->tcount = 0;
1872   s->ccount = 0;
1873   s->materialistic = 0;
1874 }
1875
1876
1877 /* The display list is full of calls to glDrawArrays(), plus saved arrays
1878    of the values we need to restore before calling it.  "Restore" means
1879    "ship them off to the GPU before each call".
1880
1881    So instead, this function walks through the display list and
1882    combines all of those vertex, normal, texture and color values into
1883    a single VBO array; ships those values off to the GPU *once* at the
1884    time of glEndList; and when running the list with glCallList, the
1885    values are already on the GPU and don't need to be sent over again.
1886
1887    The VBO persists in the GPU until the display list is deleted.
1888  */
1889 static void
1890 optimize_arrays (void)
1891 {
1892   list *L = &state->lists.lists[state->compiling_list-1];
1893   int i, j;
1894   GLfloat *combo = 0;
1895   int combo_count = 0;
1896   int combo_size = 0;
1897   GLuint buf_name = 0;
1898
1899   Assert (state->compiling_list, "not compiling a list");
1900   Assert (L, "no list");
1901   Assert (!L->buffer, "list already has a buffer");
1902
1903   glGenBuffers (1, &buf_name);
1904   CHECK("glGenBuffers");
1905   if (! buf_name) return;
1906
1907   L->buffer = buf_name;
1908
1909   /* Go through the list and dump the contents of the various saved arrays
1910      into one large array.
1911    */
1912   for (i = 0; i < L->count; i++)
1913     {
1914       list_fn *F = &L->fns[i];
1915 /*      int count; */
1916       if (! F->arrays)
1917         continue;
1918 /*      count = F->argv[2].i;*/  /* 3rd arg to glDrawArrays */
1919
1920       for (j = 0; j < 4; j++)
1921         {
1922           draw_array *A = &F->arrays[j];
1923           int ocount = combo_count;
1924
1925           /* If some caller is using arrays that don't have floats in them,
1926              we just leave them as-is and ship them over at each call.
1927              Doubt this ever really happens.
1928            */
1929           if (A->type != GL_FLOAT)
1930             continue;
1931
1932           if (! A->data)        /* No array. */
1933             continue;
1934
1935           Assert (A->bytes > 0, "no bytes in draw_array");
1936           Assert (((unsigned long) A->data > 0xFFFF),
1937                   "buffer data not a pointer");
1938
1939           combo_count += A->bytes / sizeof(*combo);
1940           make_room ("optimize_arrays",
1941                      (void **) &combo, sizeof(*combo),
1942                      &combo_count, &combo_size);
1943           memcpy (combo + ocount, A->data, A->bytes);
1944           A->binding = buf_name;
1945           free (A->data);
1946           /* 'data' is now the byte offset into the VBO. */
1947           A->data = (void *) (ocount * sizeof(*combo));
1948           /* LOG3("    loaded %lu floats to pos %d of buffer %d",
1949                A->bytes / sizeof(*combo), ocount, buf_name); */
1950         }
1951     }
1952
1953   if (combo_count == 0)         /* Nothing to do! */
1954     {
1955       if (combo) free (combo);
1956       glDeleteBuffers (1, &buf_name);
1957       L->buffer = 0;
1958       return;
1959     }
1960
1961   glBindBuffer (GL_ARRAY_BUFFER, buf_name);
1962   glBufferData (GL_ARRAY_BUFFER, 
1963                 combo_count * sizeof (*combo),
1964                 combo,
1965                 GL_STATIC_DRAW);
1966   glBindBuffer (GL_ARRAY_BUFFER, 0);    /* Keep out of others' hands */
1967
1968   LOG3("  loaded %d floats of list %d into VBO %d",
1969        combo_count, state->compiling_list, buf_name);
1970
1971 # ifdef DEBUG
1972 #  if 0
1973   for (i = 0; i < combo_count; i++)
1974     {
1975       if (i % 4 == 0)
1976         fprintf (stderr, "\njwzgles:    %4d: ", i);
1977       fprintf (stderr, " %7.3f", combo[i]);
1978     }
1979   fprintf (stderr, "\n");
1980 #  endif
1981 # endif /* DEBUG */
1982
1983   if (combo) free (combo);
1984 }
1985
1986
1987 void
1988 jwzgles_glCallList (int id)
1989 {
1990   if (state->compiling_list)
1991     {
1992       /* Yes, you can call lists inside of lists.
1993          Yes, recursion would be a mistake. */
1994       void_int vv[1];
1995       vv[0].i = id;
1996       list_push ("glCallList", (list_fn_cb) &jwzgles_glCallList, PROTO_I, vv);
1997     }
1998   else
1999     {
2000       list *L;
2001       int i;
2002
2003       state->replaying_list++;
2004
2005 # ifdef DEBUG
2006       fprintf (stderr, "\n");
2007       LOG1 ("glCallList %d", id);
2008 # endif
2009
2010       Assert (id > 0 && id <= state->lists.count, "glCallList: bogus ID");
2011       L = &state->lists.lists[id-1];
2012       Assert (id == L->id, "glCallList corrupted");
2013
2014       for (i = 0; i < L->count; i++)
2015         {
2016           list_fn *F = &L->fns[i];
2017           list_fn_cb fn = F->fn;
2018           void_int *av = F->argv;
2019
2020           switch (F->proto) {
2021           case PROTO_VOID:
2022             LOG1 ("  call %-12s", F->name);
2023             ((void (*) (void)) fn) ();
2024             break;
2025
2026           case PROTO_I:
2027             if (fn == (list_fn_cb) &jwzgles_glBegin ||
2028                 fn == (list_fn_cb) &jwzgles_glFrontFace ||
2029                 fn == (list_fn_cb) &jwzgles_glEnable ||
2030                 fn == (list_fn_cb) &jwzgles_glDisable ||
2031                 fn == (list_fn_cb) &jwzgles_glEnableClientState ||
2032                 fn == (list_fn_cb) &jwzgles_glDisableClientState ||
2033                 fn == (list_fn_cb) &jwzgles_glShadeModel ||
2034                 fn == (list_fn_cb) &jwzgles_glMatrixMode)
2035               LOG2 ("  call %-12s %s", F->name, mode_desc (av[0].i));
2036             else
2037               LOG2 ("  call %-12s %d", F->name, av[0].i);
2038             ((void (*) (int)) fn) (av[0].i);
2039             break;
2040
2041           case PROTO_F:
2042             LOG2 ("  call %-12s %7.3f", F->name, av[0].f);
2043             ((void (*) (GLfloat)) fn) (av[0].f);
2044             break;
2045
2046           case PROTO_II:
2047             if (fn == (list_fn_cb) &jwzgles_glBindTexture ||
2048                 fn == (list_fn_cb) &jwzgles_glBindBuffer)
2049               LOG3 ("  call %-12s %s %d", F->name, 
2050                     mode_desc (av[0].i), av[1].i);
2051             else
2052               LOG3 ("  call %-12s %d %d", F->name, av[0].i, av[1].i);
2053             ((void (*) (int, int)) fn) (av[0].i, av[1].i);
2054             break;
2055
2056           case PROTO_FF:
2057             LOG3 ("  call %-12s %7.3f %7.3f", F->name, av[0].f, av[1].f);
2058             ((void (*) (GLfloat, GLfloat)) fn) (av[0].f, av[1].f);
2059             break;
2060
2061           case PROTO_IF:
2062             LOG3 ("  call %-12s %s %7.3f", F->name, 
2063                   mode_desc (av[0].f), av[1].f);
2064             ((void (*) (GLint, GLfloat)) fn) (av[0].i, av[1].f);
2065             break;
2066
2067           case PROTO_III: III:
2068             if (fn == (list_fn_cb) &jwzgles_glDrawArrays ||
2069                 fn == (list_fn_cb) &jwzgles_glTexParameteri)
2070               LOG4 ("  call %-12s %s %d %d", F->name, 
2071                     mode_desc (av[0].i), av[1].i, av[2].i);
2072             else
2073               LOG4 ("  call %-12s %d %d %d", F->name, 
2074                     av[0].i, av[1].i, av[2].i);
2075             ((void (*) (int, int, int)) fn) (av[0].i, av[1].i, av[2].i);
2076             break;
2077
2078           case PROTO_FFF:
2079             LOG4 ("  call %-12s %7.3f %7.3f %7.3f", F->name,
2080                   av[0].f, av[1].f, av[2].f);
2081             ((void (*) (GLfloat, GLfloat, GLfloat)) fn)
2082               (av[0].f, av[1].f, av[2].f);
2083             break;
2084
2085           case PROTO_IIF:
2086             LOG4 ("  call %-12s %s %s %7.3f", F->name,
2087                   mode_desc (av[0].i), mode_desc (av[1].i), av[2].f);
2088             ((void (*) (int, int, GLfloat)) fn) (av[0].i, av[1].i, av[2].f);
2089             break;
2090
2091           case PROTO_IIII:
2092             LOG5 ("  call %-12s %d %d %d %d", F->name,
2093                   av[0].i, av[1].i, av[2].i, av[3].i);
2094             ((void (*) (int, int, int, int)) fn) 
2095               (av[0].i, av[1].i, av[2].i, av[3].i);
2096             break;
2097
2098           case PROTO_FFFF:
2099             LOG5 ("  call %-12s %7.3f %7.3f %7.3f %7.3f", F->name,
2100                   av[0].f, av[1].f, av[2].f, av[3].f);
2101             ((void (*) (GLfloat, GLfloat, GLfloat, GLfloat)) fn)
2102               (av[0].f, av[1].f, av[2].f, av[3].f);
2103             break;
2104
2105           case PROTO_IFV:
2106             {
2107               GLfloat v[4];
2108               v[0] = av[1].f;
2109               v[1] = av[2].f;
2110               v[2] = av[3].f;
2111               v[3] = av[4].f;
2112               LOG6 ("  call %-12s %s %3.1f %3.1f %3.1f %3.1f", F->name,
2113                     mode_desc (av[0].i),
2114                     av[1].f, av[2].f, av[3].f, av[4].f);
2115               ((void (*) (int, const GLfloat *)) fn) (av[0].i, v);
2116             }
2117             break;
2118
2119           case PROTO_IIFV:
2120             {
2121               GLfloat v[4];
2122               v[0] = av[2].f;
2123               v[1] = av[3].f;
2124               v[2] = av[4].f;
2125               v[3] = av[5].f;
2126               LOG7 ("  call %-12s %s %-8s %3.1f %3.1f %3.1f %3.1f", F->name,
2127                     mode_desc (av[0].i), mode_desc (av[1].i), 
2128                     av[2].f, av[3].f, av[4].f, av[5].f);
2129               ((void (*) (int, int, const GLfloat *)) fn) 
2130                 (av[0].i, av[1].i, v);
2131             }
2132             break;
2133
2134           case PROTO_IIV:
2135             {
2136               int v[4];
2137               v[0] = av[1].i;
2138               v[1] = av[2].i;
2139               v[2] = av[3].i;
2140               v[3] = av[4].i;
2141               LOG6 ("  call %-12s %s %3d %3d %3d %3d", F->name, 
2142                     mode_desc (av[0].i),
2143                     av[1].i, av[2].i, av[3].i, av[4].i);
2144               ((void (*) (int, const int *)) fn) (av[0].i, v);
2145             }
2146             break;
2147
2148           case PROTO_IIIV:
2149             {
2150               int v[4];
2151               v[0] = av[2].i;
2152               v[1] = av[3].i;
2153               v[2] = av[4].i;
2154               v[3] = av[5].i;
2155               LOG7 ("  call %-12s %s %-8s %3d %3d %3d %3d", F->name,
2156                     mode_desc (av[0].i), mode_desc (av[1].i), 
2157                     av[2].i, av[3].i, av[4].i, av[5].i);
2158               ((void (*) (int, int, const int *)) fn) 
2159                 (av[0].i, av[1].i, v);
2160             }
2161             break;
2162
2163           case PROTO_ARRAYS:
2164             restore_arrays (F, av[1].i + av[2].i);
2165             goto III;
2166             break;
2167
2168           case PROTO_FV16:
2169             {
2170               GLfloat m[16];
2171               int i;
2172               for (i = 0; i < countof(m); i++)
2173                 m[i] = av[i].f;
2174               LOG17 ("  call %-12s ["
2175                      "%8.3f %8.3f %8.3f %8.3f " "\n\t\t\t       "
2176                      "%8.3f %8.3f %8.3f %8.3f " "\n\t\t\t       "
2177                      "%8.3f %8.3f %8.3f %8.3f " "\n\t\t\t       "
2178                      "%8.3f %8.3f %8.3f %8.3f ]",
2179                      F->name,
2180                      m[0],  m[1],  m[2],  m[3],
2181                      m[4],  m[5],  m[6],  m[7],
2182                      m[8],  m[9],  m[10], m[11],
2183                      m[12], m[13], m[14], m[15]);
2184               ((void (*) (GLfloat *)) fn) (m);
2185             }
2186             break;
2187
2188           default:
2189             Assert (0, "bogus prototype");
2190             break;
2191           }
2192         }
2193
2194       LOG1 ("glCallList %d done\n", id);
2195
2196       state->replaying_list--;
2197       Assert (state->replaying_list >= 0, "glCallList corrupted");
2198     }
2199 }
2200
2201
2202 /* When we save a call to glDrawArrays into a display list, we also need to
2203    save the prevailing copy of the arrays that it will use, and restore them
2204    later.
2205  */
2206 static void
2207 save_arrays (list_fn *F, int count)
2208 {
2209   int i = 0;
2210   draw_array *A = (draw_array *) calloc (4, sizeof (*A));
2211   Assert (A, "out of memory");
2212
2213 /*  if (state->set.count > 0) */
2214     {
2215       glGetIntegerv (GL_VERTEX_ARRAY_BUFFER_BINDING, &A[i].binding);
2216       glGetIntegerv (GL_VERTEX_ARRAY_SIZE,    &A[i].size);
2217       glGetIntegerv (GL_VERTEX_ARRAY_TYPE,    &A[i].type);
2218       glGetIntegerv (GL_VERTEX_ARRAY_STRIDE,  &A[i].stride);
2219       glGetPointerv (GL_VERTEX_ARRAY_POINTER, &A[i].data);
2220       CHECK("glGetPointerv");
2221       copy_array_data (&A[i], count, "vert");
2222     }
2223
2224   i++;
2225   if (state->set.ncount > 1)
2226     {
2227       A[i].size = 3;
2228       glGetIntegerv (GL_NORMAL_ARRAY_BUFFER_BINDING, &A[i].binding);
2229       glGetIntegerv (GL_NORMAL_ARRAY_TYPE,    &A[i].type);
2230       glGetIntegerv (GL_NORMAL_ARRAY_STRIDE,  &A[i].stride);
2231       glGetPointerv (GL_NORMAL_ARRAY_POINTER, &A[i].data);
2232       CHECK("glGetPointerv");
2233       copy_array_data (&A[i], count, "norm");
2234     }
2235
2236   i++;
2237   if (state->set.tcount > 1)
2238     {
2239       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING, &A[i].binding);
2240       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_SIZE,    &A[i].size);
2241       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_TYPE,    &A[i].type);
2242       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_STRIDE,  &A[i].stride);
2243       glGetPointerv (GL_TEXTURE_COORD_ARRAY_POINTER, &A[i].data);
2244       CHECK("glGetPointerv");
2245       copy_array_data (&A[i], count, "tex ");
2246     }
2247
2248   i++;
2249   if (state->set.ccount > 1)
2250     {
2251       glGetIntegerv (GL_COLOR_ARRAY_BUFFER_BINDING, &A[i].binding);
2252       glGetIntegerv (GL_COLOR_ARRAY_SIZE,    &A[i].size);
2253       glGetIntegerv (GL_COLOR_ARRAY_TYPE,    &A[i].type);
2254       glGetIntegerv (GL_COLOR_ARRAY_STRIDE,  &A[i].stride);
2255       glGetPointerv (GL_COLOR_ARRAY_POINTER, &A[i].data);
2256       CHECK("glGetPointerv");
2257       copy_array_data (&A[i], count, "col ");
2258     }
2259
2260   /* Freed by glDeleteLists. */
2261
2262   Assert (!F->arrays, "save_arrays corrupted");
2263   F->arrays = A;
2264 }
2265
2266
2267 #ifdef DEBUG
2268
2269 static void
2270 dump_array_data (draw_array *A, int count,
2271                  const char *action, const char *name, const void *old)
2272 {
2273   int bytes = count * A->stride;
2274
2275   if (A->binding)
2276     {
2277       fprintf (stderr, 
2278                "jwzgles:     %s %s %d %s %2d, %4d = %5d   bind %d @ %d\n", 
2279                action, name,
2280                A->size, mode_desc(A->type), A->stride, 
2281                count, bytes, A->binding, (int) A->data);
2282     }
2283   else
2284     {
2285       Assert (bytes == A->bytes, "array data corrupted");
2286
2287       fprintf (stderr, "jwzgles:     %s %s %d %s %2d, %4d = %5d @ %lX", 
2288                action, name,
2289                A->size, mode_desc(A->type), A->stride, 
2290                count, bytes, (unsigned long) A->data);
2291       if (old)
2292         fprintf (stderr, " / %lX", (unsigned long) old);
2293       fprintf (stderr, "\n");
2294     }
2295
2296   if (A->binding)
2297     {
2298       Assert (((unsigned long) A->data < 0xFFFF),
2299               "buffer binding should be a numeric index,"
2300               " but looks like a pointer");
2301
2302 # if 0
2303       /* glGetBufferSubData doesn't actually exist in OpenGLES, but this
2304          was helpful for debugging on real OpenGL... */
2305       GLfloat *d;
2306       int i;
2307       fprintf (stderr, "jwzgles: read back:\n");
2308       d = (GLfloat *) malloc (A->bytes);
2309       glGetBufferSubData (GL_ARRAY_BUFFER, (int) A->data,
2310                           count * A->stride, (void *) d);
2311       CHECK("glGetBufferSubData");
2312       for (i = 0; i < count * A->size; i++)
2313         {
2314           if (i % 4 == 0)
2315             fprintf (stderr, "\njwzgles:    %4d: ", 
2316                      i + (int) A->data / sizeof(GLfloat));
2317           fprintf (stderr, " %7.3f", d[i]);
2318         }
2319       fprintf (stderr, "\n");
2320       free (d);
2321 # endif
2322     }
2323 # if 0
2324   else
2325     {
2326       unsigned char *b = (unsigned char *) A->data;
2327       int i;
2328       if ((unsigned long) A->data < 0xFFFF)
2329         {
2330           Assert (0, "buffer data not a pointer");
2331           return;
2332         }
2333       for (i = 0; i < count; i++)
2334         {
2335           int j;
2336           GLfloat *f = (GLfloat *) b;
2337           int s = A->size;
2338           if (s == 0) s = 3;  /* normals */
2339           fprintf (stderr, "jwzgles:    ");
2340           for (j = 0; j < s; j++)
2341             fprintf (stderr, " %7.3f", f[j]);
2342           fprintf (stderr, "\n");
2343           b += A->stride;
2344         }
2345     }
2346 # endif
2347 }
2348
2349 static void
2350 dump_direct_array_data (int count)
2351 {
2352   draw_array A = { 0, };
2353
2354   if (jwzgles_glIsEnabled (GL_VERTEX_ARRAY))
2355     {
2356       glGetIntegerv (GL_VERTEX_ARRAY_BUFFER_BINDING, &A.binding);
2357       glGetIntegerv (GL_VERTEX_ARRAY_SIZE,    &A.size);
2358       glGetIntegerv (GL_VERTEX_ARRAY_TYPE,    &A.type);
2359       glGetIntegerv (GL_VERTEX_ARRAY_STRIDE,  &A.stride);
2360       glGetPointerv (GL_VERTEX_ARRAY_POINTER, &A.data);
2361       A.bytes = count * A.stride;
2362       dump_array_data (&A, count, "direct", "vertex ", 0);
2363     }
2364   if (jwzgles_glIsEnabled (GL_NORMAL_ARRAY))
2365     {
2366       A.size = 0;
2367       glGetIntegerv (GL_NORMAL_ARRAY_BUFFER_BINDING, &A.binding);
2368       glGetIntegerv (GL_NORMAL_ARRAY_TYPE,    &A.type);
2369       glGetIntegerv (GL_NORMAL_ARRAY_STRIDE,  &A.stride);
2370       glGetPointerv (GL_NORMAL_ARRAY_POINTER, &A.data);
2371       A.bytes = count * A.stride;
2372       dump_array_data (&A, count, "direct", "normal ", 0);
2373     }
2374   if (jwzgles_glIsEnabled (GL_TEXTURE_COORD_ARRAY))
2375     {
2376       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING, &A.binding);
2377       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_SIZE,    &A.size);
2378       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_TYPE,    &A.type);
2379       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_STRIDE,  &A.stride);
2380       glGetPointerv (GL_TEXTURE_COORD_ARRAY_POINTER, &A.data);
2381       A.bytes = count * A.stride;
2382       dump_array_data (&A, count, "direct", "texture", 0);
2383     }
2384   if (jwzgles_glIsEnabled (GL_COLOR_ARRAY))
2385     {
2386       glGetIntegerv (GL_COLOR_ARRAY_BUFFER_BINDING, &A.binding);
2387       glGetIntegerv (GL_COLOR_ARRAY_SIZE,    &A.size);
2388       glGetIntegerv (GL_COLOR_ARRAY_TYPE,    &A.type);
2389       glGetIntegerv (GL_COLOR_ARRAY_STRIDE,  &A.stride);
2390       glGetPointerv (GL_COLOR_ARRAY_POINTER, &A.data);
2391       A.bytes = count * A.stride;
2392       dump_array_data (&A, count, "direct", "color ", 0);
2393     }
2394 }
2395
2396 #endif /* DEBUG */
2397
2398
2399 static void
2400 copy_array_data (draw_array *A, int count, const char *name)
2401 {
2402   /* Instead of just memcopy'ing the whole array and obeying its previous
2403      'stride' value, we make up a more compact array.  This is because if
2404      the same array data is being used with multiple component types,
2405      e.g. with glInterleavedArrays, we don't want to copy all of the
2406      data multiple times.
2407    */
2408   int stride2, bytes, i, j;
2409   void *data2;
2410   const GLfloat *IF;
2411   GLfloat *OF;
2412   const unsigned char *IB;
2413   unsigned char *OB;
2414
2415   if (((unsigned long) A->data) < 0xFFFF)
2416     {
2417       Assert (0, "buffer data not a pointer");
2418       return;
2419     }
2420
2421   Assert (A->size >= 2 && A->size <= 4, "bogus array size");
2422
2423   switch (A->type) {
2424   case GL_FLOAT:         stride2 = A->size * sizeof(GLfloat); break;
2425   case GL_UNSIGNED_BYTE: stride2 = A->size; break;
2426   default: Assert (0, "bogus array type"); break;
2427   }
2428
2429   bytes = count * stride2;
2430   Assert (bytes > 0, "bogus array count or stride");
2431   Assert (A->data, "missing array data");
2432   data2 = (void *) malloc (bytes);
2433   Assert (data2, "out of memory");
2434
2435   IB = (const unsigned char *) A->data;
2436   OB = (unsigned char *) data2;
2437   IF = (const GLfloat *) A->data;
2438   OF = (GLfloat *) data2;
2439
2440   switch (A->type) {
2441   case GL_FLOAT:
2442     for (i = 0; i < count; i++)
2443       {
2444         for (j = 0; j < A->size; j++)
2445           *OF++ = IF[j];
2446         IF = (const GLfloat *) (((const unsigned char *) IF) + A->stride);
2447       }
2448     break;
2449   case GL_UNSIGNED_BYTE:
2450     for (i = 0; i < count; i++)
2451       {
2452         for (j = 0; j < A->size; j++)
2453           *OB++ = IB[j];
2454         IB += A->stride;
2455       }
2456     break;
2457   default:
2458     Assert (0, "bogus array type");
2459     break;
2460   }
2461
2462   A->data = data2;
2463   A->bytes = bytes;
2464   A->stride = stride2;
2465
2466 # ifdef DEBUG
2467   dump_array_data (A, count, "saved", name, old);
2468 # endif
2469 }
2470
2471
2472 static void
2473 restore_arrays (list_fn *F, int count)
2474 {
2475   int i = 0;
2476   draw_array *A = F->arrays;
2477   Assert (A, "missing array");
2478
2479   for (i = 0; i < 4; i++)
2480     {
2481       const char *name = 0;
2482
2483       if (!A[i].size)
2484         continue;
2485
2486       Assert ((A[i].binding || A[i].data),
2487               "array has neither buffer binding nor data");
2488
2489       glBindBuffer (GL_ARRAY_BUFFER, A[i].binding);
2490       CHECK("glBindBuffer");
2491
2492       switch (i) {
2493       case 0: glVertexPointer  (A[i].size, A[i].type, A[i].stride, A[i].data);
2494         name = "vertex ";
2495         CHECK("glVertexPointer");
2496         break;
2497       case 1: glNormalPointer  (           A[i].type, A[i].stride, A[i].data);
2498         name = "normal ";
2499         CHECK("glNormalPointer");
2500         break;
2501       case 2: glTexCoordPointer(A[i].size, A[i].type, A[i].stride, A[i].data);
2502         name = "texture";
2503         CHECK("glTexCoordPointer");
2504         break;
2505       case 3: glColorPointer   (A[i].size, A[i].type, A[i].stride, A[i].data);
2506         name = "color  ";
2507         CHECK("glColorPointer");
2508         break;
2509       default: Assert (0, "wat"); break;
2510       }
2511
2512 # ifdef DEBUG
2513       dump_array_data (&A[i], count, "restored", name, 0);
2514 # endif
2515     }
2516
2517   glBindBuffer (GL_ARRAY_BUFFER, 0);    /* Keep out of others' hands */
2518 }
2519
2520
2521 void
2522 jwzgles_glDrawArrays (GLuint mode, GLuint first, GLuint count)
2523 {
2524   if (state->compiling_list)
2525     {
2526       void_int vv[3];
2527       vv[0].i = mode;
2528       vv[1].i = first;
2529       vv[2].i = count;
2530       list_push ("glDrawArrays", (list_fn_cb) &jwzgles_glDrawArrays,
2531                  PROTO_ARRAYS, vv);
2532     }
2533   else
2534     {
2535 # ifdef DEBUG
2536       if (! state->replaying_list) {
2537         LOG4("direct %-12s %d %d %d", "glDrawArrays", mode, first, count);
2538         dump_direct_array_data (first + count);
2539       }
2540 # endif
2541       glDrawArrays (mode, first, count);  /* the real one */
2542       CHECK("glDrawArrays");
2543     }
2544 }
2545
2546
2547 void
2548 jwzgles_glInterleavedArrays (GLenum format, GLsizei stride, const void *data)
2549 {
2550   /* We can implement this by calling the various *Pointer functions
2551      with offsets into the same data, taking advantage of stride.
2552    */
2553   const unsigned char *c = (const unsigned char *) data;
2554 # define B 1
2555 # define F sizeof(GLfloat)
2556
2557   Assert (!state->compiling_verts,
2558           "glInterleavedArrays not allowed inside glBegin");
2559
2560   jwzgles_glEnableClientState (GL_VERTEX_ARRAY);
2561
2562   if (!state->replaying_list)
2563     LOG4 ("%sglInterleavedArrays %s %d %lX", 
2564           (state->compiling_list || state->replaying_list ? "  " : ""),
2565           mode_desc (format), stride, (unsigned long) data);
2566
2567   switch (format) {
2568   case GL_V2F:
2569     glVertexPointer (2, GL_FLOAT, stride, c);
2570     CHECK("glVertexPointer");
2571     if (!state->replaying_list)
2572       LOG3 ("%s  -> glVertexPointer 2 FLOAT %d %lX", 
2573             (state->compiling_list || state->replaying_list ? "  " : ""),
2574             stride, (unsigned long) c);
2575     break;
2576   case GL_V3F:
2577     glVertexPointer (3, GL_FLOAT, stride, c);
2578     CHECK("glVertexPointer");
2579     if (!state->replaying_list)
2580       LOG3 ("%s  -> glVertexPointer 3 FLOAT %d %lX", 
2581             (state->compiling_list || state->replaying_list ? "  " : ""),
2582             stride, (unsigned long) c);
2583     break;
2584   case GL_C4UB_V2F:     
2585     if (stride == 0)
2586       stride = 4*B + 2*F;
2587     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2588     glColorPointer (4, GL_UNSIGNED_BYTE, stride, c);
2589     CHECK("glColorPointer");
2590     c += 4*B;   /* #### might be incorrect float-aligned address */
2591     glVertexPointer (2, GL_FLOAT, stride, c);
2592     break;
2593   case GL_C4UB_V3F:
2594     if (stride == 0)
2595       stride = 4*B + 3*F;
2596     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2597     glColorPointer (4, GL_UNSIGNED_BYTE, stride, c);
2598     CHECK("glColorPointer");
2599     c += 4*B;
2600     glVertexPointer (3, GL_FLOAT, stride, c);
2601     CHECK("glVertexPointer");
2602     break;
2603   case GL_C3F_V3F:
2604     if (stride == 0)
2605       stride = 3*F + 3*F;
2606     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2607     glColorPointer (3, GL_FLOAT, stride, c);
2608     CHECK("glColorPointer");
2609     c += 3*F;
2610     glVertexPointer (3, GL_FLOAT, stride, c);
2611     CHECK("glVertexPointer");
2612     break;
2613   case GL_N3F_V3F:
2614     if (stride == 0)
2615       stride = 3*F + 3*F;
2616     jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
2617     glNormalPointer (GL_FLOAT, stride, c);
2618     CHECK("glNormalPointer");
2619     if (!state->replaying_list)
2620       LOG3 ("%s  -> glNormalPointer   FLOAT %d %lX", 
2621             (state->compiling_list || state->replaying_list ? "  " : ""),
2622             stride, (unsigned long) c);
2623     c += 3*F;
2624     glVertexPointer (3, GL_FLOAT, stride, c);
2625     CHECK("glVertexPointer");
2626     if (!state->replaying_list)
2627       LOG3 ("%s  -> glVertexPointer 3 FLOAT %d %lX", 
2628             (state->compiling_list || state->replaying_list ? "  " : ""),
2629             stride, (unsigned long) c);
2630     break;
2631   case GL_C4F_N3F_V3F:
2632     if (stride == 0)
2633       stride = 4*F + 3*F + 3*F;
2634     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2635     glColorPointer (4, GL_FLOAT, stride, c);
2636     CHECK("glColorPointer");
2637     c += 4*F;
2638     jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
2639     glNormalPointer (GL_FLOAT, stride, c);
2640     CHECK("glNormalPointer");
2641     c += 3*F;
2642     glVertexPointer (3, GL_FLOAT, stride, c);
2643     CHECK("glVertexPointer");
2644     break;
2645   case GL_T2F_V3F:
2646     if (stride == 0)
2647       stride = 2*F + 3*F;
2648     jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2649     glTexCoordPointer (2, GL_FLOAT, stride, c);
2650     CHECK("glTexCoordPointer");
2651     c += 2*F;
2652     glVertexPointer (3, GL_FLOAT, stride, c);
2653     CHECK("glVertexPointer");
2654     break;
2655   case GL_T4F_V4F:
2656     if (stride == 0)
2657       stride = 4*F + 4*F;
2658     jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2659     glTexCoordPointer (4, GL_FLOAT, stride, c);
2660     CHECK("glTexCoordPointer");
2661     c += 4*F;
2662     glVertexPointer (4, GL_FLOAT, stride, c);
2663     CHECK("glVertexPointer");
2664     break;
2665   case GL_T2F_C4UB_V3F:
2666     if (stride == 0)
2667       stride = 2*F + 4*B + 3*F;
2668     jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2669     glTexCoordPointer (2, GL_FLOAT, stride, c);
2670     CHECK("glTexCoordPointer");
2671     c += 2*F;
2672     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2673     glColorPointer  (4, GL_UNSIGNED_BYTE, stride, c);
2674     CHECK("glColorPointer");
2675     c += 4*B;
2676     glVertexPointer (3, GL_FLOAT, stride, c);
2677     CHECK("glVertexPointer");
2678     break;
2679   case GL_T2F_C3F_V3F:
2680     if (stride == 0)
2681       stride = 2*F + 3*F + 3*F;
2682     jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2683     glTexCoordPointer (2, GL_FLOAT, stride, c);
2684     CHECK("glTexCoordPointer");
2685     c += 2*F;
2686     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2687     glColorPointer  (3, GL_FLOAT, stride, c);
2688     CHECK("glColorPointer");
2689     c += 3*F;
2690     glVertexPointer (3, GL_FLOAT, stride, c);
2691     CHECK("glVertexPointer");
2692     break;
2693   case GL_T2F_N3F_V3F:
2694     if (stride == 0)
2695       stride = 2*F + 3*F + 3*F;
2696     jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2697     glTexCoordPointer (2, GL_FLOAT, stride, c);
2698     CHECK("glTexCoordPointer");
2699     c += 2*F;
2700     jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
2701     glNormalPointer (GL_FLOAT, stride, c);
2702     CHECK("glNormalPointer");
2703     c += 3*F;
2704     glVertexPointer (3, GL_FLOAT, stride, c);
2705     CHECK("glVertexPointer");
2706     break;
2707   case GL_T2F_C4F_N3F_V3F:
2708     if (stride == 0)
2709       stride = 2*F + 4*F + 3*F + 3*F;
2710     jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2711     glTexCoordPointer (2, GL_FLOAT, stride, c);
2712     CHECK("glTexCoordPointer");
2713     c += 2*F;
2714     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2715     glColorPointer  (3, GL_FLOAT, stride, c);
2716     CHECK("glColorPointer");
2717     c += 3*F;
2718     jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
2719     glNormalPointer (GL_FLOAT, stride, c);
2720     CHECK("glNormalPointer");
2721     c += 3*F;
2722     glVertexPointer (3, GL_FLOAT, stride, c);
2723     CHECK("glVertexPointer");
2724     break;
2725   case GL_T4F_C4F_N3F_V4F:
2726     if (stride == 0)
2727       stride = 4*F + 4*F + 3*F + 4*F;
2728     jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2729     glTexCoordPointer (4, GL_FLOAT, stride, c);
2730     CHECK("glTexCoordPointer");
2731     c += 4*F;
2732     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2733     glColorPointer  (4, GL_FLOAT, stride, c);
2734     CHECK("glColorPointer");
2735     c += 4*F;
2736     jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
2737     glNormalPointer (GL_FLOAT, stride, c);
2738     CHECK("glNormalPointer");
2739     c += 3*F;
2740     glVertexPointer (3, GL_FLOAT, stride, c);
2741     CHECK("glVertexPointer");
2742     break;
2743   default:
2744     Assert (0, "glInterleavedArrays: bogus format");
2745     break;
2746   }
2747
2748 # undef B
2749 # undef F
2750 }
2751
2752
2753
2754 void
2755 jwzgles_glEnableClientState (GLuint cap)
2756 {
2757   if (state->compiling_list)
2758     {
2759       void_int vv[1];
2760       vv[0].i = cap;
2761       list_push ("glEnableClientState", 
2762                  (list_fn_cb) &jwzgles_glEnableClientState,
2763                  PROTO_I, vv);
2764     }
2765   else
2766     {
2767       if (! state->replaying_list)
2768         LOG2 ("direct %-12s %s", "glEnableClientState", mode_desc(cap));
2769       glEnableClientState (cap);  /* the real one */
2770       CHECK("glEnableClientState");
2771     }
2772
2773   switch (cap) {
2774   case GL_VERTEX_ARRAY:
2775     state->enabled |= ISENABLED_VERT_ARRAY;
2776     break;
2777   case GL_NORMAL_ARRAY:
2778     if (! state->compiling_verts)
2779       state->set.ncount += 2;
2780     state->enabled |= ISENABLED_NORM_ARRAY;
2781     break;
2782   case GL_TEXTURE_COORD_ARRAY:
2783     if (! state->compiling_verts)
2784       state->set.tcount += 2;
2785     state->enabled |= ISENABLED_TEX_ARRAY;
2786     break;
2787   case GL_COLOR_ARRAY:
2788     if (! state->compiling_verts)
2789       state->set.ccount += 2;
2790     state->enabled |= ISENABLED_COLOR_ARRAY;
2791     break;
2792   default: break;
2793   }
2794 }
2795
2796
2797 void
2798 jwzgles_glDisableClientState (GLuint cap)
2799 {
2800   if (state->compiling_list)
2801     {
2802       void_int vv[1];
2803       vv[0].i = cap;
2804       list_push ("glDisableClientState", 
2805                  (list_fn_cb) &jwzgles_glDisableClientState,
2806                  PROTO_I, vv);
2807     }
2808   else
2809     {
2810       if (! state->replaying_list)
2811         LOG2 ("direct %-12s %s", "glDisableClientState", mode_desc(cap));
2812       glDisableClientState (cap);  /* the real one */
2813       CHECK("glDisableClientState");
2814     }
2815
2816   switch (cap) {
2817   case GL_VERTEX_ARRAY:
2818     state->enabled &= ~ISENABLED_VERT_ARRAY;
2819     break;
2820   case GL_NORMAL_ARRAY:
2821     if (! state->compiling_verts)
2822       state->set.ncount = 0;
2823     state->enabled &= ~ISENABLED_NORM_ARRAY;
2824     break;
2825   case GL_TEXTURE_COORD_ARRAY:
2826     if (! state->compiling_verts)
2827       state->set.tcount = 0;
2828     state->enabled &= ~ISENABLED_TEX_ARRAY;
2829     break;
2830   case GL_COLOR_ARRAY:
2831     if (! state->compiling_verts)
2832       state->set.ccount = 0;
2833     state->enabled &= ~ISENABLED_COLOR_ARRAY;
2834     break;
2835   default:
2836     break;
2837   }
2838 }
2839
2840
2841 void
2842 jwzgles_glMultMatrixf (const GLfloat *m)
2843 {
2844   Assert (!state->compiling_verts,
2845           "glMultMatrixf not allowed inside glBegin");
2846   if (state->compiling_list)
2847     {
2848       void_int vv[16];
2849       int i;
2850       for (i = 0; i < countof(vv); i++)
2851         vv[i].f = m[i];
2852       list_push ("glMultMatrixf", (list_fn_cb) &jwzgles_glMultMatrixf,
2853                  PROTO_FV16, vv);
2854     }
2855   else
2856     {
2857       if (! state->replaying_list)
2858         LOG1 ("direct %-12s", "glMultMatrixf");
2859       glMultMatrixf (m);  /* the real one */
2860       CHECK("glMultMatrixf");
2861     }
2862 }
2863
2864
2865 void
2866 jwzgles_glClearIndex(GLfloat c)
2867 {
2868   /* Does GLES even do indexed color? */
2869   Assert (0, "glClearIndex unimplemented");
2870 }
2871
2872
2873 void
2874 jwzgles_glBitmap (GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig,
2875                   GLfloat xmove, GLfloat ymove, const GLubyte *bitmap)
2876 {
2877   Assert (0, "glBitmap unimplemented");
2878 }
2879
2880 void
2881 jwzgles_glPushAttrib(int flags)
2882 {
2883   Assert (0, "glPushAttrib unimplemented");
2884 }
2885
2886 void
2887 jwzgles_glPopAttrib(void)
2888 {
2889   Assert (0, "glPopAttrib unimplemented");
2890 }
2891
2892
2893 /* These are needed for object hit detection in pinion.
2894    Might need to rewrite that code entirely.  Punt for now.
2895  */
2896 void
2897 jwzgles_glInitNames (void)
2898 {
2899 /*  Assert (0, "glInitNames unimplemented");*/
2900 }
2901
2902 void
2903 jwzgles_glPushName (GLuint name)
2904 {
2905 /*  Assert (0, "glPushName unimplemented");*/
2906 }
2907
2908 GLuint
2909 jwzgles_glPopName (void)
2910 {
2911 /*  Assert (0, "glPopName unimplemented");*/
2912   return 0;
2913 }
2914
2915 GLuint
2916 jwzgles_glRenderMode (GLuint mode)
2917 {
2918 /*  Assert (0, "glRenderMode unimplemented");*/
2919   return 0;
2920 }
2921
2922 void
2923 jwzgles_glSelectBuffer (GLsizei size, GLuint *buf)
2924 {
2925 /*  Assert (0, "glSelectBuffer unimplemented");*/
2926 }
2927
2928
2929 void
2930 jwzgles_glGenTextures (GLuint n, GLuint *ret)
2931 {
2932   Assert (!state->compiling_verts,
2933           "glGenTextures not allowed inside glBegin");
2934   /* technically legal, but stupid! */
2935   Assert (!state->compiling_list,
2936           "glGenTextures not allowed inside glNewList");
2937   if (! state->replaying_list)
2938     LOG1 ("direct %-12s", "glGenTextures");
2939   glGenTextures (n, ret);  /* the real one */
2940   CHECK("glGenTextures");
2941 }
2942
2943
2944 /* return the next larger power of 2. */
2945 static int
2946 to_pow2 (int value)
2947 {
2948   int i = 1;
2949   while (i < value) i <<= 1;
2950   return i;
2951 }
2952
2953 void
2954 jwzgles_glTexImage1D (GLenum target, GLint level,
2955                       GLint internalFormat,
2956                       GLsizei width, GLint border,
2957                       GLenum format, GLenum type,
2958                       const GLvoid *data)
2959 {
2960   Assert (!state->compiling_verts, "glTexImage1D not allowed inside glBegin");
2961   /* technically legal, but stupid! */
2962   Assert (!state->compiling_list, "glTexImage1D inside glNewList");
2963   Assert (width  == to_pow2(width), "width must be a power of 2");
2964
2965   if (target == GL_TEXTURE_1D) target = GL_TEXTURE_2D;
2966   jwzgles_glTexImage2D (target, level, internalFormat, width, 1,
2967                         border, format, type, data);
2968 }
2969
2970 void
2971 jwzgles_glTexImage2D (GLenum target,
2972                       GLint     level,
2973                       GLint     internalFormat,
2974                       GLsizei   width,
2975                       GLsizei   height,
2976                       GLint     border,
2977                       GLenum    format,
2978                       GLenum    type,
2979                       const GLvoid *data)
2980 {
2981   GLvoid *d2 = (GLvoid *) data;
2982   Assert (!state->compiling_verts, "glTexImage2D not allowed inside glBegin");
2983   Assert (!state->compiling_list,  /* technically legal, but stupid! */
2984           "glTexImage2D not allowed inside glNewList");
2985
2986   Assert (width  == to_pow2(width),   "width must be a power of 2");
2987   Assert (height == to_pow2(height), "height must be a power of 2");
2988
2989   /* OpenGLES no longer supports "4" as a synonym for "RGBA". */
2990   switch (internalFormat) {
2991   case 1: internalFormat = GL_LUMINANCE; break;
2992   case 2: internalFormat = GL_LUMINANCE_ALPHA; break;
2993   case 3: internalFormat = GL_RGB; break;
2994   case 4: internalFormat = GL_RGBA; break;
2995   }
2996
2997   /* GLES does not let us omit the data pointer to create a blank texture. */
2998   if (! data)
2999     {
3000       d2 = (GLvoid *) calloc (1, width * height * sizeof(GLfloat) * 4);
3001       Assert (d2, "out of memory");
3002     }
3003
3004   if (internalFormat == GL_RGB && format == GL_RGBA)
3005     internalFormat = GL_RGBA;  /* WTF */
3006   if (type == GL_UNSIGNED_INT_8_8_8_8_REV)
3007     type = GL_UNSIGNED_BYTE;
3008
3009   if (! state->replaying_list)
3010     LOG10 ("direct %-12s %s %d %s %d %d %d %s %s 0x%lX", "glTexImage2D", 
3011            mode_desc(target), level, mode_desc(internalFormat),
3012            width, height, border, mode_desc(format), mode_desc(type),
3013            (unsigned long) d2);
3014   glTexImage2D (target, level, internalFormat, width, height, border,
3015                 format, type, d2);  /* the real one */
3016   CHECK("glTexImage2D");
3017
3018   if (d2 != data) free (d2);
3019 }
3020
3021 void
3022 jwzgles_glTexSubImage2D (GLenum target, GLint level,
3023                          GLint xoffset, GLint yoffset,
3024                          GLsizei width, GLsizei height,
3025                          GLenum format, GLenum type,
3026                          const GLvoid *pixels)
3027 {
3028   Assert (!state->compiling_verts,
3029           "glTexSubImage2D not allowed inside glBegin");
3030   Assert (!state->compiling_list,   /* technically legal, but stupid! */
3031           "glTexSubImage2D not allowed inside glNewList");
3032
3033   if (! state->replaying_list)
3034     LOG10 ("direct %-12s %s %d %d %d %d %d %s %s 0x%lX", "glTexSubImage2D", 
3035            mode_desc(target), level, xoffset, yoffset, width, height,
3036            mode_desc (format), mode_desc (type), (unsigned long) pixels);
3037   glTexSubImage2D (target, level, xoffset, yoffset, width, height,
3038                    format, type, pixels);  /* the real one */
3039   CHECK("glTexSubImage2D");
3040 }
3041
3042 void
3043 jwzgles_glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat,
3044                           GLint x, GLint y, GLsizei width, GLsizei height,
3045                           GLint border)
3046 {
3047   Assert (!state->compiling_verts, 
3048           "glCopyTexImage2D not allowed inside glBegin");
3049   Assert (!state->compiling_list,    /* technically legal, but stupid! */
3050           "glCopyTexImage2D not allowed inside glNewList");
3051   if (! state->replaying_list)
3052     LOG9 ("direct %-12s %s %d %s %d %d %d %d %d", "glCopyTexImage2D", 
3053           mode_desc(target), level, mode_desc(internalformat),
3054           x, y, width, height, border);
3055   glCopyTexImage2D (target, level, internalformat, x, y, width, height,
3056                     border);  /* the real one */
3057   CHECK("glCopyTexImage2D");
3058 }
3059
3060
3061 void
3062 jwzgles_glTexGenfv (GLenum coord, GLenum pname, const GLfloat *params)
3063 {
3064   /* OpenGLES doesn't have this at all!
3065      "Oh, just rewrite that code to use GPU shaders", they say.
3066      How fucking convenient.
3067
3068      So, when this is enabled, we could emit a GL_TEXTURE_COORD_ARRAY
3069      and compute coords for each vertex in the current GL_VERTEX_ARRAY
3070      as per http://www.opengl.org/wiki/Mathematics_of_glTexGen
3071      but holy shit, what a pain in the ass!
3072
3073      For GL_OBJECT_LINEAR, we can just re-use the vertex array as
3074      the texture array, using a proper stride.  That's hardly worth
3075      the effort, though, because bouncingcow is the only hack that
3076      uses that, and not even by default.
3077    */
3078   Assert (coord == GL_S || coord == GL_T, "glTexGenfv: unimplemented coord");
3079
3080   /* This is probably default-ish, so do nothing. */
3081   if (pname == GL_EYE_PLANE) return;
3082
3083   Assert (pname == GL_TEXTURE_GEN_MODE, "glTexGenfv: unimplemented name");
3084   Assert (params[0] == GL_EYE_LINEAR, "glTexGenfv: unimplemented mode");
3085 }
3086
3087 void
3088 jwzgles_glTexGeni (GLenum coord, GLenum pname, GLint param)
3089 {
3090   GLfloat v = param;
3091   jwzgles_glTexGenfv (coord, pname, &v);
3092 }
3093
3094
3095 int
3096 jwzgles_gluBuild2DMipmaps (GLenum target,
3097                            GLint        internalFormat,
3098                            GLsizei      width,
3099                            GLsizei      height,
3100                            GLenum       format,
3101                            GLenum       type,
3102                            const GLvoid *data)
3103 {
3104   /* Not really bothering with mipmapping; only making one level.
3105      Note that this required a corresponding hack in glTexParameterf().
3106    */
3107
3108   int w2 = to_pow2(width);
3109   int h2 = to_pow2(height);
3110
3111   void *d2 = (void *) data;
3112
3113   /* OpenGLES no longer supports "4" as a synonym for "RGBA". */
3114   switch (internalFormat) {
3115   case 1: internalFormat = GL_LUMINANCE; break;
3116   case 2: internalFormat = GL_LUMINANCE_ALPHA; break;
3117   case 3: internalFormat = GL_RGB; break;
3118   case 4: internalFormat = GL_RGBA; break;
3119   }
3120
3121 /*  if (w2 < h2) w2 = h2;
3122   if (h2 < w2) h2 = w2;*/
3123
3124   if (w2 != width || h2 != height)
3125     {
3126       /* Scale up the image bits to fit the power-of-2 texture.
3127          We have to do this because the mipmap API assumes that
3128          the texture bits go to texture coordinates 1.0 x 1.0.
3129          This could be more efficient, but it doesn't happen often.
3130       */
3131       int istride = (format == GL_RGBA ? 4 : 3);
3132       int ostride = 4;
3133       int ibpl = istride * width;
3134       int obpl = ostride * w2;
3135       int oy;
3136       const unsigned char *in = (unsigned char *) data;
3137       unsigned char *out = (void *) malloc (h2 * obpl);
3138       Assert (out, "out of memory");
3139       d2 = out;
3140
3141       for (oy = 0; oy < h2; oy++)
3142         {
3143           int iy = oy * height / h2;
3144           const unsigned char *iline = in  + (iy * ibpl);
3145           unsigned char       *oline = out + (oy * obpl);
3146           int ox;
3147           for (ox = 0; ox < w2; ox++)
3148             {
3149               int ix = ox * width / w2;
3150               const unsigned char *i = iline + (ix * istride);
3151               unsigned char       *o = oline + (ox * ostride);
3152               *o++ = *i++;  /* R */
3153               *o++ = *i++;  /* G */
3154               *o++ = *i++;  /* B */
3155               *o++ = (istride == 4 ? *i : 0xFF); /* A */
3156             }
3157         }
3158       width  = w2;
3159       height = h2;
3160       internalFormat = GL_RGBA;
3161       format = GL_RGBA;
3162     }
3163
3164   jwzgles_glTexImage2D (target, 0, internalFormat, w2, h2, 0, 
3165                         format, type, d2);
3166   if (d2 != data) free (d2);
3167
3168   return 0;
3169 }
3170
3171
3172 void
3173 jwzgles_glRectf (GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
3174 {
3175   jwzgles_glBegin (GL_POLYGON);
3176   jwzgles_glVertex2f (x1, y1);
3177   jwzgles_glVertex2f (x2, y1);
3178   jwzgles_glVertex2f (x2, y2);
3179   jwzgles_glVertex2f (x1, y2);
3180   jwzgles_glEnd ();
3181 }
3182
3183 void
3184 jwzgles_glRecti (GLint x1, GLint y1, GLint x2, GLint y2)
3185 {
3186   jwzgles_glRectf (x1, y1, x2, y2);
3187 }
3188
3189 void
3190 jwzgles_glClearDepth (GLfloat d)
3191 {
3192   /* Not sure what to do here */
3193   Assert (d == 1.0, "glClearDepth unimplemented");
3194 }
3195
3196
3197 void
3198 jwzgles_glEnable (GLuint bit)
3199 {
3200   Assert (!state->compiling_verts, "glEnable not allowed inside glBegin");
3201   if (state->compiling_list)
3202     {
3203       void_int vv[1];
3204       vv[0].i = bit;
3205       list_push ("glEnable", (list_fn_cb) &jwzgles_glEnable, PROTO_I, vv);
3206     }
3207   else
3208     {
3209       /* We implement 1D textures as 2D textures. */
3210       if (bit == GL_TEXTURE_1D) bit = GL_TEXTURE_2D;
3211
3212       if (! state->replaying_list)
3213         LOG2 ("direct %-12s %s", "glEnable", mode_desc(bit));
3214       glEnable (bit);  /* the real one */
3215       CHECK("glEnable");
3216
3217       switch (bit) {
3218       case GL_TEXTURE_2D: state->enabled |= ISENABLED_TEXTURE_2D; break;
3219       case GL_TEXTURE_GEN_S: state->enabled |= ISENABLED_TEXTURE_GEN_S; break;
3220       case GL_TEXTURE_GEN_T: state->enabled |= ISENABLED_TEXTURE_GEN_T; break;
3221       case GL_LIGHTING: state->enabled |= ISENABLED_LIGHTING; break;
3222       case GL_BLEND: state->enabled |= ISENABLED_BLEND; break;
3223       case GL_DEPTH_TEST: state->enabled |= ISENABLED_DEPTH_TEST; break;
3224       case GL_CULL_FACE: state->enabled |= ISENABLED_CULL_FACE; break;
3225       case GL_NORMALIZE: state->enabled |= ISENABLED_NORMALIZE; break;
3226       case GL_FOG: state->enabled |= ISENABLED_FOG; break;
3227       case GL_COLOR_MATERIAL: state->enabled |= ISENABLED_COLMAT; break;
3228
3229       /* Do these work with glEnable or only with glEnableClientState? */
3230       case GL_VERTEX_ARRAY: state->enabled |= ISENABLED_VERT_ARRAY; break;
3231       case GL_NORMAL_ARRAY: state->enabled |= ISENABLED_NORM_ARRAY; break;
3232       case GL_TEXTURE_COORD_ARRAY: state->enabled |= ISENABLED_TEX_ARRAY;break;
3233       case GL_COLOR_ARRAY:  state->enabled |= ISENABLED_COLOR_ARRAY; break;
3234
3235       default: break;
3236       }
3237     }
3238 }
3239
3240
3241 void
3242 jwzgles_glDisable (GLuint bit)
3243 {
3244   Assert (!state->compiling_verts, "glDisable not allowed inside glBegin");
3245   if (state->compiling_list)
3246     {
3247       void_int vv[1];
3248       vv[0].i = bit;
3249       list_push ("glDisable", (list_fn_cb) &jwzgles_glDisable, PROTO_I, vv);
3250     }
3251   else
3252     {
3253       /* We implement 1D textures as 2D textures. */
3254       if (bit == GL_TEXTURE_1D) bit = GL_TEXTURE_2D;
3255
3256       if (! state->replaying_list)
3257         LOG2 ("direct %-12s %s", "glDisable", mode_desc(bit));
3258       glDisable (bit);  /* the real one */
3259       CHECK("glDisable");
3260
3261       switch (bit) {
3262       case GL_TEXTURE_2D: state->enabled &= ~ISENABLED_TEXTURE_2D; break;
3263       case GL_TEXTURE_GEN_S: state->enabled &= ~ISENABLED_TEXTURE_GEN_S; break;
3264       case GL_TEXTURE_GEN_T: state->enabled &= ~ISENABLED_TEXTURE_GEN_T; break;
3265       case GL_LIGHTING: state->enabled &= ~ISENABLED_LIGHTING; break;
3266       case GL_BLEND: state->enabled &= ~ISENABLED_BLEND; break;
3267       case GL_DEPTH_TEST: state->enabled &= ~ISENABLED_DEPTH_TEST; break;
3268       case GL_CULL_FACE: state->enabled &= ~ISENABLED_CULL_FACE; break;
3269       case GL_NORMALIZE: state->enabled &= ~ISENABLED_NORMALIZE; break;
3270       case GL_FOG: state->enabled &= ~ISENABLED_FOG; break;
3271       case GL_COLOR_MATERIAL: state->enabled &= ~ISENABLED_COLMAT; break;
3272
3273       /* Do these work with glEnable or only with glEnableClientState? */
3274       case GL_VERTEX_ARRAY: state->enabled &= ~ISENABLED_VERT_ARRAY; break;
3275       case GL_NORMAL_ARRAY: state->enabled &= ~ISENABLED_NORM_ARRAY; break;
3276       case GL_TEXTURE_COORD_ARRAY: state->enabled &= ~ISENABLED_TEX_ARRAY;break;
3277       case GL_COLOR_ARRAY:  state->enabled &= ~ISENABLED_COLOR_ARRAY; break;
3278
3279       default: break;
3280       }
3281     }
3282 }
3283
3284
3285 GLboolean
3286 jwzgles_glIsEnabled (GLuint bit)
3287 {
3288  /*
3289   Assert (!state->compiling_verts, "glIsEnabled not allowed inside glBegin");
3290   Assert (!state->compiling_list,  "glIsEnabled not allowed inside glNewList");
3291   */
3292
3293   /* We implement 1D textures as 2D textures. */
3294   if (bit == GL_TEXTURE_1D) bit = GL_TEXTURE_2D;
3295
3296   switch (bit) {
3297   case GL_TEXTURE_2D: return !!(state->enabled & ISENABLED_TEXTURE_2D);
3298   case GL_TEXTURE_GEN_S: return !!(state->enabled & ISENABLED_TEXTURE_GEN_S);
3299   case GL_TEXTURE_GEN_T: return !!(state->enabled & ISENABLED_TEXTURE_GEN_T);
3300   case GL_LIGHTING: return !!(state->enabled & ISENABLED_LIGHTING);
3301   case GL_BLEND: return !!(state->enabled & ISENABLED_BLEND);
3302   case GL_DEPTH_TEST: return !!(state->enabled & ISENABLED_DEPTH_TEST);
3303   case GL_CULL_FACE: return !!(state->enabled & ISENABLED_CULL_FACE);
3304   case GL_NORMALIZE: return !!(state->enabled & ISENABLED_NORMALIZE);
3305   case GL_FOG: return !!(state->enabled & ISENABLED_FOG);
3306   case GL_COLOR_MATERIAL: return !!(state->enabled & ISENABLED_COLMAT);
3307
3308   /* Do these work with glEnable or only with glEnableClientState?
3309      We need to query them, and there is no glIsClientStateEnabled.
3310    */
3311   case GL_VERTEX_ARRAY: return !!(state->enabled & ISENABLED_VERT_ARRAY);
3312   case GL_NORMAL_ARRAY: return !!(state->enabled & ISENABLED_NORM_ARRAY);
3313   case GL_TEXTURE_COORD_ARRAY: return !!(state->enabled & ISENABLED_TEX_ARRAY);
3314   case GL_COLOR_ARRAY: return !!(state->enabled & ISENABLED_COLOR_ARRAY);
3315   default: Assert (0, "glIsEnabled unimplemented bit"); break;
3316   }
3317 }
3318
3319
3320 /* The spec says that OpenGLES 1.x doesn't implement glGetFloatv.
3321    Were this true, it would suck, for it would mean that there was no
3322    way to retrieve the prevailing matrixes.  To implement this, we'd
3323    have to keep track of them all on the client side by combining in
3324    all the actions of glMultMatrixf, glRotatef, etc.
3325
3326    However, Apple's iOS OpenGLES *does* provide glGetFloatv!
3327  */
3328 void
3329 jwzgles_glGetFloatv (GLenum pname, GLfloat *params)
3330 {
3331   if (! state->replaying_list)
3332     LOG2 ("direct %-12s %s", "glGetFloatv", mode_desc(pname));
3333   glGetFloatv (pname, params);  /* the real one */
3334   CHECK("glGetFloatv");
3335 }
3336
3337
3338 /* Likewise: not supposed to be there, but it is. */
3339 void
3340 jwzgles_glGetPointerv (GLenum pname, GLvoid *params)
3341 {
3342   if (! state->replaying_list)
3343     LOG2 ("direct %-12s %s", "glGetPointerv", mode_desc(pname));
3344   glGetPointerv (pname, params);  /* the real one */
3345   CHECK("glGetPointerv");
3346 }
3347
3348
3349 /* How many cells are written into the *params array.
3350    We need to know this to avoid smashing the caller's stack
3351    if they asked for a single-value parameter.
3352  */
3353 static int
3354 glGet_ret_count (GLenum pname)
3355 {
3356   switch (pname) {
3357 /*case GL_COLOR_MATRIX: */
3358   case GL_MODELVIEW_MATRIX:
3359   case GL_PROJECTION_MATRIX:
3360   case GL_TEXTURE_MATRIX:
3361 /*case GL_TRANSPOSE_COLOR_MATRIX: */
3362 /*case GL_TRANSPOSE_MODELVIEW_MATRIX: */
3363 /*case GL_TRANSPOSE_PROJECTION_MATRIX: */
3364 /*case GL_TRANSPOSE_TEXTURE_MATRIX: */
3365     return 16;
3366 /*case GL_ACCUM_CLEAR_VALUE: */
3367 /*case GL_BLEND_COLOR: */
3368   case GL_COLOR_CLEAR_VALUE:
3369   case GL_COLOR_WRITEMASK:
3370   case GL_CURRENT_COLOR:
3371 /*case GL_CURRENT_RASTER_COLOR: */
3372 /*case GL_CURRENT_RASTER_POSITION: */
3373 /*case GL_CURRENT_RASTER_SECONDARY_COLOR: */
3374 /*case GL_CURRENT_RASTER_TEXTURE_COORDS: */
3375 /*case GL_CURRENT_SECONDARY_COLOR: */
3376   case GL_CURRENT_TEXTURE_COORDS:
3377   case GL_FOG_COLOR:
3378   case GL_LIGHT_MODEL_AMBIENT:
3379 /*case GL_MAP2_GRID_DOMAIN: */
3380   case GL_SCISSOR_BOX:
3381   case GL_VIEWPORT:
3382     return 4;
3383   case GL_CURRENT_NORMAL:
3384   case GL_POINT_DISTANCE_ATTENUATION:
3385     return 3;
3386   case GL_ALIASED_LINE_WIDTH_RANGE:
3387   case GL_ALIASED_POINT_SIZE_RANGE:
3388   case GL_DEPTH_RANGE:
3389 /*case GL_LINE_WIDTH_RANGE: */
3390 /*case GL_MAP1_GRID_DOMAIN: */
3391 /*case GL_MAP2_GRID_SEGMENTS: */
3392   case GL_MAX_VIEWPORT_DIMS:
3393 /*case GL_POINT_SIZE_RANGE: */
3394   case GL_POLYGON_MODE:
3395   case GL_SMOOTH_LINE_WIDTH_RANGE:
3396   case GL_SMOOTH_POINT_SIZE_RANGE:
3397     return 2;
3398   default:
3399     return 1;
3400   }
3401 }
3402
3403
3404 void
3405 jwzgles_glGetDoublev (GLenum pname, GLdouble *params)
3406 {
3407   GLfloat m[16];
3408   int i, j = glGet_ret_count (pname);
3409   jwzgles_glGetFloatv (pname, m);
3410   for (i = 0; i < j; i++)
3411     params[i] = m[i];
3412 }
3413
3414
3415 void
3416 jwzgles_glGetIntegerv (GLenum pname, GLint *params)
3417 {
3418   GLfloat m[16];
3419   int i, j = glGet_ret_count (pname);
3420   jwzgles_glGetFloatv (pname, m);
3421   for (i = 0; i < j; i++)
3422     params[i] = m[i];
3423 }
3424
3425
3426 void
3427 jwzgles_glGetBooleanv (GLenum pname, GLboolean *params)
3428 {
3429   GLfloat m[16];
3430   int i, j = glGet_ret_count (pname);
3431   jwzgles_glGetFloatv (pname, m);
3432   for (i = 0; i < j; i++)
3433     params[i] = (m[i] != 0.0);
3434 }
3435
3436
3437 const char *
3438 jwzgles_gluErrorString (GLenum error)
3439 {
3440   static char s[20];
3441   sprintf (s, "0x%lX", (unsigned long) error);
3442   return s;
3443 }
3444
3445
3446 /* These four *Pointer calls (plus glBindBuffer and glBufferData) can
3447    be included inside glNewList, but they actually execute immediately
3448    anyway, because their data is recorded in the list by the
3449    subsequently-recorded call to glDrawArrays.  This is a little weird.
3450  */
3451 void
3452 jwzgles_glVertexPointer (GLuint size, GLuint type, GLuint stride, 
3453                          const GLvoid *ptr)
3454 {
3455   if (! state->replaying_list)
3456     LOG5 ("direct %-12s %d %s %d 0x%lX", "glVertexPointer", 
3457           size, mode_desc(type), stride, (unsigned long) ptr);
3458   glVertexPointer (size, type, stride, ptr);  /* the real one */
3459   CHECK("glVertexPointer");
3460 }
3461
3462 void
3463 jwzgles_glNormalPointer (GLuint type, GLuint stride, const GLvoid *ptr)
3464 {
3465   if (! state->replaying_list)
3466     LOG4 ("direct %-12s %s %d 0x%lX", "glNormalPointer", 
3467           mode_desc(type), stride, (unsigned long) ptr);
3468   glNormalPointer (type, stride, ptr);  /* the real one */
3469   CHECK("glNormalPointer");
3470 }
3471
3472 void
3473 jwzgles_glColorPointer (GLuint size, GLuint type, GLuint stride, 
3474                         const GLvoid *ptr)
3475 {
3476   if (! state->replaying_list)
3477     LOG5 ("direct %-12s %d %s %d 0x%lX", "glColorPointer", 
3478           size, mode_desc(type), stride, (unsigned long) ptr);
3479   glColorPointer (size, type, stride, ptr);  /* the real one */
3480   CHECK("glColorPointer");
3481 }
3482
3483 void
3484 jwzgles_glTexCoordPointer (GLuint size, GLuint type, GLuint stride, 
3485                            const GLvoid *ptr)
3486 {
3487   if (! state->replaying_list)
3488     LOG5 ("direct %-12s %d %s %d 0x%lX", "glTexCoordPointer", 
3489           size, mode_desc(type), stride, (unsigned long) ptr);
3490   glTexCoordPointer (size, type, stride, ptr);  /* the real one */
3491   CHECK("glTexCoordPointer");
3492 }
3493
3494 void
3495 jwzgles_glBindBuffer (GLuint target, GLuint buffer)
3496 {
3497   if (! state->replaying_list)
3498     LOG3 ("direct %-12s %s %d", "glBindBuffer", mode_desc(target), buffer);
3499   glBindBuffer (target, buffer);  /* the real one */
3500   CHECK("glBindBuffer");
3501 }
3502
3503 void
3504 jwzgles_glBufferData (GLenum target, GLsizeiptr size, const void *data,
3505                       GLenum usage)
3506 {
3507   if (! state->replaying_list)
3508     LOG5 ("direct %-12s %s %ld 0x%lX %s", "glBufferData",
3509           mode_desc(target), size, (unsigned long) data, mode_desc(usage));
3510   glBufferData (target, size, data, usage);  /* the real one */
3511   CHECK("glBufferData");
3512 }
3513
3514
3515 void
3516 jwzgles_glTexParameterf (GLuint target, GLuint pname, GLfloat param)
3517 {
3518   Assert (!state->compiling_verts,
3519           "glTexParameterf not allowed inside glBegin");
3520
3521   /* We don't *really* implement mipmaps, so just turn this off. */
3522   if (param == GL_LINEAR_MIPMAP_LINEAR)   param = GL_LINEAR;
3523   if (param == GL_NEAREST_MIPMAP_LINEAR)  param = GL_LINEAR;
3524   if (param == GL_LINEAR_MIPMAP_NEAREST)  param = GL_NEAREST;
3525   if (param == GL_NEAREST_MIPMAP_NEAREST) param = GL_NEAREST;
3526
3527   /* We implement 1D textures as 2D textures. */
3528   if (target == GL_TEXTURE_1D) target = GL_TEXTURE_2D;
3529
3530   /* Apparently this is another invalid enum. Just ignore it. */
3531   if ((pname == GL_TEXTURE_WRAP_S || pname == GL_TEXTURE_WRAP_T) &&
3532       param == GL_CLAMP)
3533     return;
3534
3535   if (state->compiling_list)
3536     {
3537       void_int vv[3];
3538       vv[0].i = target;
3539       vv[1].i = pname;
3540       vv[2].f = param;
3541       list_push ("glTexParameterf", (list_fn_cb) &jwzgles_glTexParameterf,
3542                  PROTO_IIF, vv);
3543     }
3544   else
3545     {
3546       if (! state->replaying_list)
3547         LOG4 ("direct %-12s %s %s %7.3f", "glTexParameterf", 
3548               mode_desc(target), mode_desc(pname), param);
3549       glTexParameterf (target, pname, param);  /* the real one */
3550       CHECK("glTexParameterf");
3551     }
3552 }
3553
3554 void
3555 jwzgles_glTexParameteri (GLuint target, GLuint pname, GLuint param)
3556 {
3557   jwzgles_glTexParameterf (target, pname, param);
3558 }
3559
3560
3561 void
3562 jwzgles_glBindTexture (GLuint target, GLuint texture)
3563 {
3564   Assert (!state->compiling_verts,
3565           "glBindTexture not allowed inside glBegin");
3566
3567   /* We implement 1D textures as 2D textures. */
3568   if (target == GL_TEXTURE_1D) target = GL_TEXTURE_2D;
3569
3570   if (state->compiling_list)
3571     {
3572       void_int vv[2];
3573       vv[0].i = target;
3574       vv[1].i = texture;
3575       list_push ("glBindTexture", (list_fn_cb) &jwzgles_glBindTexture,
3576                  PROTO_II, vv);
3577     }
3578   else
3579     {
3580       if (! state->replaying_list)
3581         LOG3 ("direct %-12s %s %d", "glBindTexture", 
3582               mode_desc(target), texture);
3583       glBindTexture (target, texture);  /* the real one */
3584       CHECK("glBindTexture");
3585     }
3586 }
3587
3588
3589
3590 /* Matrix functions, mostly cribbed from Mesa.
3591  */
3592
3593 void
3594 jwzgles_glFrustum (GLfloat left,   GLfloat right,
3595                    GLfloat bottom, GLfloat top,
3596                    GLfloat near,   GLfloat far)
3597 {
3598   GLfloat m[16];
3599   GLfloat x = (2 * near)        / (right-left);
3600   GLfloat y = (2 * near)        / (top - bottom);
3601   GLfloat a = (right + left)    / (right - left);
3602   GLfloat b = (top + bottom)    / (top - bottom);
3603   GLfloat c = -(far + near)     / (far - near);
3604   GLfloat d = -(2 * far * near) / (far - near);
3605
3606 # define M(X,Y)  m[Y * 4 + X]
3607   M(0,0) = x; M(0,1) = 0; M(0,2) =  a; M(0,3) = 0;
3608   M(1,0) = 0; M(1,1) = y; M(1,2) =  b; M(1,3) = 0;
3609   M(2,0) = 0; M(2,1) = 0; M(2,2) =  c; M(2,3) = d;
3610   M(3,0) = 0; M(3,1) = 0; M(3,2) = -1; M(3,3) = 0;
3611 # undef M
3612
3613   jwzgles_glMultMatrixf (m);
3614 }
3615
3616
3617 void
3618 jwzgles_glOrtho (GLfloat left,   GLfloat right,
3619                  GLfloat bottom, GLfloat top,
3620                  GLfloat near,   GLfloat far)
3621 {
3622   GLfloat m[16];
3623   GLfloat a = 2 / (right - left);
3624   GLfloat b = -(right + left) / (right - left);
3625   GLfloat c = 2 / (top - bottom);
3626   GLfloat d = -(top + bottom) / (top - bottom);
3627   GLfloat e = -2 / (far - near);
3628   GLfloat f = -(far + near) / (far - near);
3629
3630 # define M(X,Y)  m[Y * 4 + X]
3631   M(0,0) = a; M(0,1) = 0; M(0,2) = 0; M(0,3) = b;
3632   M(1,0) = 0; M(1,1) = c; M(1,2) = 0; M(1,3) = d;
3633   M(2,0) = 0; M(2,1) = 0; M(2,2) = e; M(2,3) = f;
3634   M(3,0) = 0; M(3,1) = 0; M(3,2) = 0; M(3,3) = 1;
3635 # undef M
3636
3637   jwzgles_glMultMatrixf (m);
3638 }
3639
3640
3641 void
3642 jwzgles_gluPerspective (GLdouble fovy, GLdouble aspect, 
3643                         GLdouble near, GLdouble far)
3644 {
3645   GLfloat m[16];
3646   double si, co, dz;
3647   double rad = fovy / 2 * M_PI / 180;
3648   double a, b, c, d;
3649
3650   dz = far - near;
3651   si = sin(rad);
3652   if (dz == 0 || si == 0 || aspect == 0)
3653     return;
3654   co = cos(rad) / si;
3655
3656   a = co / aspect;
3657   b = co;
3658   c = -(far + near) / dz;
3659   d = -2 * near * far / dz;
3660
3661 # define M(X,Y)  m[Y * 4 + X]
3662   M(0,0) = a; M(0,1) = 0; M(0,2) = 0;  M(0,3) = 0;
3663   M(1,0) = 0; M(1,1) = b; M(1,2) = 0;  M(1,3) = 0;
3664   M(2,0) = 0; M(2,1) = 0; M(2,2) = c;  M(2,3) = d;
3665   M(3,0) = 0; M(3,1) = 0; M(3,2) = -1; M(3,3) = 0;
3666 # undef M
3667
3668   jwzgles_glMultMatrixf (m);
3669 }
3670
3671
3672 void
3673 jwzgles_gluLookAt (GLfloat eyex, GLfloat eyey, GLfloat eyez,
3674                    GLfloat centerx, GLfloat centery, GLfloat centerz,
3675                    GLfloat upx, GLfloat upy, GLfloat upz)
3676 {
3677   GLfloat m[16];
3678   GLfloat x[3], y[3], z[3];
3679   GLfloat mag;
3680     
3681   /* Make rotation matrix */
3682     
3683   /* Z vector */
3684   z[0] = eyex - centerx;
3685   z[1] = eyey - centery;
3686   z[2] = eyez - centerz;
3687   mag = sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]);
3688   if (mag) {          /* mpichler, 19950515 */
3689     z[0] /= mag;
3690     z[1] /= mag;
3691     z[2] /= mag;
3692   }
3693     
3694   /* Y vector */
3695   y[0] = upx;
3696   y[1] = upy;
3697   y[2] = upz;
3698     
3699   /* X vector = Y cross Z */
3700   x[0] = y[1] * z[2] - y[2] * z[1];
3701   x[1] = -y[0] * z[2] + y[2] * z[0];
3702   x[2] = y[0] * z[1] - y[1] * z[0];
3703     
3704   /* Recompute Y = Z cross X */
3705   y[0] = z[1] * x[2] - z[2] * x[1];
3706   y[1] = -z[0] * x[2] + z[2] * x[0];
3707   y[2] = z[0] * x[1] - z[1] * x[0];
3708     
3709   /* mpichler, 19950515 */
3710   /* cross product gives area of parallelogram, which is < 1.0 for
3711    * non-perpendicular unit-length vectors; so normalize x, y here
3712    */
3713     
3714   mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
3715   if (mag) {
3716     x[0] /= mag;
3717     x[1] /= mag;
3718     x[2] /= mag;
3719   }
3720     
3721   mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
3722   if (mag) {
3723     y[0] /= mag;
3724     y[1] /= mag;
3725     y[2] /= mag;
3726   }
3727     
3728 #define M(row,col)  m[col*4+row]
3729   M(0, 0) = x[0]; M(0, 1) = x[1]; M(0, 2) = x[2]; M(0, 3) = 0.0;
3730   M(1, 0) = y[0]; M(1, 1) = y[1]; M(1, 2) = y[2]; M(1, 3) = 0.0;
3731   M(2, 0) = z[0]; M(2, 1) = z[1]; M(2, 2) = z[2]; M(2, 3) = 0.0;
3732   M(3, 0) = 0.0;  M(3, 1) = 0.0;  M(3, 2) = 0.0;  M(3, 3) = 1.0;
3733 #undef M
3734
3735   jwzgles_glMultMatrixf(m);
3736     
3737   /* Translate Eye to Origin */
3738   jwzgles_glTranslatef(-eyex, -eyey, -eyez);
3739 }
3740
3741
3742 static void __gluMultMatrixVecd (const GLdouble matrix[16],
3743                                  const GLdouble in[4],
3744                                  GLdouble out[4])
3745 {
3746   int i;
3747
3748   for (i=0; i<4; i++) {
3749     out[i] = 
3750       in[0] * matrix[0*4+i] +
3751       in[1] * matrix[1*4+i] +
3752       in[2] * matrix[2*4+i] +
3753       in[3] * matrix[3*4+i];
3754   }
3755 }
3756
3757 GLint
3758 jwzgles_gluProject (GLdouble objx, GLdouble objy, GLdouble objz, 
3759                     const GLdouble modelMatrix[16], 
3760                     const GLdouble projMatrix[16],
3761                     const GLint viewport[4],
3762                     GLdouble *winx, GLdouble *winy, GLdouble *winz)
3763 {
3764   GLdouble in[4];
3765   GLdouble out[4];
3766
3767   /* #### I suspect this is not working right.  I was seeing crazy values
3768      in lament.c.  Maybe there's some float-vs-double confusion going on?
3769    */
3770
3771   in[0]=objx;
3772   in[1]=objy;
3773   in[2]=objz;
3774   in[3]=1.0;
3775   __gluMultMatrixVecd(modelMatrix, in, out);
3776   __gluMultMatrixVecd(projMatrix, out, in);
3777   if (in[3] == 0.0) return(GL_FALSE);
3778   in[0] /= in[3];
3779   in[1] /= in[3];
3780   in[2] /= in[3];
3781   /* Map x, y and z to range 0-1 */
3782   in[0] = in[0] * 0.5 + 0.5;
3783   in[1] = in[1] * 0.5 + 0.5;
3784   in[2] = in[2] * 0.5 + 0.5;
3785
3786   /* Map x,y to viewport */
3787   in[0] = in[0] * viewport[2] + viewport[0];
3788   in[1] = in[1] * viewport[3] + viewport[1];
3789
3790   *winx=in[0];
3791   *winy=in[1];
3792   *winz=in[2];
3793   return(GL_TRUE);
3794 }
3795
3796
3797 /* The following functions are present in both OpenGL 1.1 and in OpenGLES 1,
3798    but are allowed within glNewList/glEndList, so we must wrap them to allow
3799    them to either be recorded in lists, or run directly.
3800
3801    All this CPP obscenity is me screaming in rage at all the ways that C is
3802    not Lisp, as all I want to do here is DEFADVICE.
3803  */
3804
3805 #define PROTO_V   PROTO_VOID
3806 #define TYPE_V    GLuint
3807 #define ARGS_V    void
3808 #define VARS_V    /* */
3809 #define LOGS_V    "\n"
3810 #define FILL_V    /* */
3811
3812 #define TYPE_I    GLuint
3813 #define TYPE_II   TYPE_I
3814 #define TYPE_III  TYPE_I
3815 #define TYPE_IIII TYPE_I
3816 #define ARGS_I    TYPE_I a
3817 #define ARGS_II   TYPE_I a, TYPE_I b
3818 #define ARGS_III  TYPE_I a, TYPE_I b, TYPE_I c
3819 #define ARGS_IIII TYPE_I a, TYPE_I b, TYPE_I c, TYPE_I d
3820 #define LOGS_I    "%s\n", mode_desc(a)
3821 #define LOGS_II   "%s %d\n", mode_desc(a), b
3822 #define LOGS_III  "%s %s %s\n", mode_desc(a), mode_desc(b), mode_desc(c)
3823 #define LOGS_IIII "%d %d %d %d\n", a, b, c, d
3824 #define VARS_I    a
3825 #define VARS_II   a, b
3826 #define VARS_III  a, b, c
3827 #define VARS_IIII a, b, c, d
3828 #define FILL_I    vv[0].i = a;
3829 #define FILL_II   vv[0].i = a; vv[1].i = b;
3830 #define FILL_III  vv[0].i = a; vv[1].i = b; vv[2].i = c;
3831 #define FILL_IIII vv[0].i = a; vv[1].i = b; vv[2].i = c; vv[3].i = d;
3832
3833 #define TYPE_F    GLfloat
3834 #define TYPE_FF   TYPE_F
3835 #define TYPE_FFF  TYPE_F
3836 #define TYPE_FFFF TYPE_F
3837 #define ARGS_F    TYPE_F a
3838 #define ARGS_FF   TYPE_F a, TYPE_F b
3839 #define ARGS_FFF  TYPE_F a, TYPE_F b, TYPE_F c
3840 #define ARGS_FFFF TYPE_F a, TYPE_F b, TYPE_F c, TYPE_F d
3841 #define LOGS_F    "%7.3f\n", a
3842 #define LOGS_FF   "%7.3f %7.3f\n", a, b
3843 #define LOGS_FFF  "%7.3f %7.3f %7.3f\n", a, b, c
3844 #define LOGS_FFFF "%7.3f %7.3f %7.3f %7.3f\n", a, b, c, d
3845 #define VARS_F    VARS_I
3846 #define VARS_FF   VARS_II
3847 #define VARS_FFF  VARS_III
3848 #define VARS_FFFF VARS_IIII
3849 #define FILL_F    vv[0].f = a;
3850 #define FILL_FF   vv[0].f = a; vv[1].f = b;
3851 #define FILL_FFF  vv[0].f = a; vv[1].f = b; vv[2].f = c;
3852 #define FILL_FFFF vv[0].f = a; vv[1].f = b; vv[2].f = c; vv[3].f = d;
3853
3854 #define ARGS_IF   TYPE_I a, TYPE_F b
3855 #define VARS_IF   VARS_II
3856 #define LOGS_IF   "%s %7.3f\n", mode_desc(a), b
3857 #define FILL_IF   vv[0].i = a; vv[1].f = b;
3858
3859 #define ARGS_IIF  TYPE_I a, TYPE_I b, TYPE_F c
3860 #define VARS_IIF  VARS_III
3861 #define LOGS_IIF  "%s %s %7.3f\n", mode_desc(a), mode_desc(b), c
3862 #define FILL_IIF  vv[0].i = a; vv[1].i = b; vv[2].f = c;
3863
3864 #define TYPE_IV   GLint
3865 #define ARGS_IIV  TYPE_I a, const TYPE_IV *b
3866 #define VARS_IIV  VARS_II
3867 #define LOGS_IIV  "%s %d %d %d %d\n", mode_desc(a), b[0], b[1], b[2], b[3]
3868 #define FILL_IIV  vv[0].i = a; \
3869                   vv[1].i = b[0]; vv[2].i = b[1]; \
3870                   vv[3].i = b[2]; vv[4].i = b[3];
3871
3872 #define ARGS_IFV  TYPE_I a, const TYPE_F *b
3873 #define VARS_IFV  VARS_II
3874 #define LOGS_IFV  "%s %7.3f %7.3f %7.3f %7.3f\n", mode_desc(a), \
3875                   b[0], b[1], b[2], b[3]
3876 #define FILL_IFV  vv[0].i = a; \
3877                   vv[1].f = b[0]; vv[2].f = b[1]; \
3878                   vv[3].f = b[2]; vv[4].f = b[3];
3879
3880 #define ARGS_IIIV TYPE_I a, TYPE_I b, const TYPE_IV *c
3881 #define VARS_IIIV VARS_III
3882 #define LOGS_IIIV "%s %-8s %3d %3d %3d %3d\n", mode_desc(a), mode_desc(b), \
3883                   c[0], c[1], c[2], c[3]
3884 #define FILL_IIIV vv[0].i = a; vv[1].i = b; \
3885                   vv[2].i = c[0]; vv[3].i = c[1]; \
3886                   vv[4].i = c[2]; vv[5].i = c[3];
3887
3888 #define ARGS_IIFV TYPE_I a, TYPE_I b, const TYPE_F *c
3889 #define VARS_IIFV VARS_III
3890 #define LOGS_IIFV "%s %-8s %7.3f %7.3f %7.3f %7.3f\n", \
3891                   mode_desc(a), mode_desc(b), \
3892                   c[0], c[1], c[2], c[3]
3893 #define FILL_IIFV vv[0].i = a; vv[1].i = b; \
3894                   vv[2].f = c[0]; vv[3].f = c[1]; \
3895                   vv[4].f = c[2]; vv[5].f = c[3];
3896
3897 #ifdef DEBUG
3898 # define WLOG(NAME,ARGS) \
3899   fprintf (stderr, "jwzgles: direct %-12s ", NAME); \
3900   fprintf (stderr, ARGS)
3901 #else
3902 # define WLOG(NAME,ARGS) /* */
3903 #endif
3904
3905 #define WRAP(NAME,SIG) \
3906 void jwzgles_##NAME (ARGS_##SIG)                                        \
3907 {                                                                       \
3908   Assert (!state->compiling_verts,                                      \
3909           STRINGIFY(NAME) " not allowed inside glBegin");               \
3910   if (state->compiling_list) {                                          \
3911     void_int vv[10];                                                    \
3912     FILL_##SIG                                                          \
3913     list_push (STRINGIFY(NAME), (list_fn_cb) &jwzgles_##NAME,           \
3914                PROTO_##SIG, vv);                                        \
3915   } else {                                                              \
3916     if (! state->replaying_list) {                                      \
3917       WLOG (STRINGIFY(NAME), LOGS_##SIG);                               \
3918     }                                                                   \
3919     NAME (VARS_##SIG);                                                  \
3920     CHECK(STRINGIFY(NAME));                                             \
3921   }                                                                     \
3922 }
3923
3924 WRAP (glActiveTexture,  I)
3925 WRAP (glAlphaFunc,      IF)
3926 WRAP (glBlendFunc,      II)
3927 WRAP (glClear,          I)
3928 WRAP (glClearColor,     FFFF)
3929 WRAP (glClearStencil,   I)
3930 WRAP (glColorMask,      IIII)
3931 WRAP (glCullFace,       I)
3932 WRAP (glDepthFunc,      I)
3933 WRAP (glDepthMask,      I)
3934 WRAP (glFinish,         V)
3935 WRAP (glFlush,          V)
3936 WRAP (glFogf,           IF)
3937 WRAP (glFogfv,          IFV)
3938 WRAP (glFrontFace,      I)
3939 WRAP (glHint,           II)
3940 WRAP (glLightModelf,    IF)
3941 WRAP (glLightModelfv,   IFV)
3942 WRAP (glLightf,         IIF)
3943 WRAP (glLightfv,        IIFV)
3944 WRAP (glLineWidth,      F)
3945 WRAP (glLoadIdentity,   V)
3946 WRAP (glLogicOp,        I)
3947 WRAP (glMatrixMode,     I)
3948 WRAP (glPixelStorei,    II)
3949 WRAP (glPointSize,      F)
3950 WRAP (glPolygonOffset,  FF)
3951 WRAP (glPopMatrix,      V)
3952 WRAP (glPushMatrix,     V)
3953 WRAP (glRotatef,        FFFF)
3954 WRAP (glScalef,         FFF)
3955 WRAP (glScissor,        IIII)
3956 WRAP (glShadeModel,     I)
3957 WRAP (glStencilFunc,    III)
3958 WRAP (glStencilMask,    I)
3959 WRAP (glStencilOp,      III)
3960 WRAP (glTexEnvf,        IIF)
3961 WRAP (glTexEnvi,        III)
3962 WRAP (glTranslatef,     FFF)
3963 WRAP (glViewport,       IIII)
3964 #undef  TYPE_IV
3965 #define TYPE_IV GLuint
3966 WRAP (glDeleteTextures, IIV)
3967
3968
3969 #endif /* HAVE_JWZGLES - whole file */