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