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