5b0b51a5dfc2a6506a92c2f1f0da7147385d08c4
[xscreensaver] / hacks / glx / jwzgles.c
1 /* xscreensaver, Copyright (c) 2012-2015 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_glVertex2dv (const GLdouble *v)
1593 {
1594   jwzgles_glVertex2f (v[0], v[1]);
1595 }
1596
1597 void
1598 jwzgles_glVertex2fv (const GLfloat *v)
1599 {
1600   jwzgles_glVertex2f (v[0], v[1]);
1601 }
1602
1603 void
1604 jwzgles_glVertex2i (GLint x, GLint y)
1605 {
1606   jwzgles_glVertex2f (x, y);
1607 }
1608
1609
1610 void
1611 jwzgles_glLightiv (GLenum light, GLenum pname, const GLint *params)
1612 {
1613   GLfloat v[4];
1614   v[0] = params[0];
1615   v[1] = params[1];
1616   v[2] = params[2];
1617   v[3] = params[3];
1618   jwzgles_glLightfv (light, pname, v);
1619 }
1620
1621 void
1622 jwzgles_glLightModeliv (GLenum pname, const GLint *params)
1623 {
1624   GLfloat v[4];
1625   v[0] = params[0];
1626   v[1] = params[1];
1627   v[2] = params[2];
1628   v[3] = params[3];
1629   jwzgles_glLightModelfv (pname, v);
1630 }
1631
1632 void
1633 jwzgles_glFogiv (GLenum pname, const GLint *params)
1634 {
1635   GLfloat v[4];
1636   v[0] = params[0];
1637   v[1] = params[1];
1638   v[2] = params[2];
1639   v[3] = params[3];
1640   jwzgles_glFogfv (pname, v);
1641 }
1642
1643 void
1644 jwzgles_glLighti (GLenum light, GLenum pname, GLint param)
1645 {
1646   jwzgles_glLightf (light, pname, param);
1647 }
1648
1649 void
1650 jwzgles_glLightModeli (GLenum pname, GLint param)
1651 {
1652   jwzgles_glLightModelf (pname, param);
1653 }
1654
1655 void
1656 jwzgles_glFogi (GLenum pname, GLint param)
1657 {
1658   jwzgles_glFogf (pname, param);
1659 }
1660
1661
1662 void
1663 jwzgles_glRotated (GLdouble angle, GLdouble x, GLdouble y, GLdouble z)
1664 {
1665   jwzgles_glRotatef (angle, x, y, z);
1666 }
1667
1668
1669 void
1670 jwzgles_glClipPlane (GLenum plane, const GLdouble *equation)
1671 {
1672   Assert (state->compiling_verts, "glClipPlane not inside glBegin");
1673   Assert (0, "glClipPlane unimplemented");  /* no GLES equivalent... */
1674 }
1675
1676
1677 void
1678 jwzgles_glPolygonMode (GLenum face, GLenum mode)
1679 {
1680   Assert (!state->compiling_verts, "not inside glBegin");
1681   if (state->compiling_list)
1682     {
1683       void_int vv[2];
1684       vv[0].i = face;
1685       vv[1].i = mode;
1686       list_push ("glPolygonMode", (list_fn_cb) &jwzgles_glPolygonMode, 
1687                  PROTO_II, vv);
1688     }
1689   else
1690     {
1691       /* POINT and LINE don't exist in GLES */
1692       Assert (mode == GL_FILL, "glPolygonMode: unimplemented mode");
1693     }
1694 }
1695
1696
1697 void
1698 jwzgles_glDrawBuffer (GLenum buf)
1699 {
1700   Assert (!state->compiling_verts, "not inside glBegin");
1701   if (state->compiling_list)
1702     {
1703       void_int vv[1];
1704       vv[0].i = buf;
1705       list_push ("glDrawBuffer", (list_fn_cb) &jwzgles_glDrawBuffer, 
1706                  PROTO_I, vv);
1707     }
1708   else
1709     {
1710 /*      Assert (buf == GL_BACK, "glDrawBuffer: back buffer only"); */
1711 # ifndef GL_VERSION_ES_CM_1_0  /* not compiling against OpenGLES 1.x */
1712       if (! state->replaying_list)
1713         LOG1 ("direct %-12s", "glDrawBuffer");
1714       glDrawBuffer (buf);      /* the real one */
1715       CHECK("glDrawBuffer");
1716 # endif
1717     }
1718 }
1719
1720
1721 /* Given an array of sets of 4 elements of arbitrary size, convert it
1722    to an array of sets of 6 elements instead: ABCD becomes ABC BCD.
1723  */
1724 static int
1725 cq2t (unsigned char **arrayP, int stride, int count)
1726 {
1727   int count2 = count * 6 / 4;
1728   int size  = stride * count;
1729   int size2 = stride * count2;
1730   const unsigned char    *oarray,  *in;
1731   unsigned char *array2, *oarray2, *out;
1732   int i;
1733
1734   oarray = *arrayP;
1735   if (!oarray || count == 0)
1736     return count2;
1737
1738   array2 = (unsigned char *) malloc (size2);
1739   Assert (array2, "out of memory");
1740   oarray2 = array2;
1741
1742   in =  oarray;
1743   out = oarray2;
1744   for (i = 0; i < count / 4; i++)
1745     {
1746       const unsigned char *a, *b, *c, *d;       /* the 4 corners */
1747       a = in; in += stride;
1748       b = in; in += stride;
1749       c = in; in += stride;
1750       d = in; in += stride;
1751
1752 # define PUSH(IN) do {                  \
1753          const unsigned char *ii = IN;  \
1754          int j;                         \
1755          for (j = 0; j < stride; j++) { \
1756            *out++ = *ii++;              \
1757          }} while(0)
1758
1759       PUSH (a); PUSH (b); PUSH (d);             /* the 2 triangles */
1760       PUSH (b); PUSH (c); PUSH (d);
1761 # undef PUSH
1762     }
1763
1764   Assert (in  == oarray  + size,  "convert_quads corrupted");
1765   Assert (out == oarray2 + size2, "convert_quads corrupted");
1766
1767   free (*arrayP);
1768   *arrayP = oarray2;
1769   return count2;
1770 }
1771                               
1772
1773 /* Convert all coordinates in a GL_QUADS vert_set to GL_TRIANGLES.
1774  */
1775 static void
1776 convert_quads_to_triangles (vert_set *s)
1777 {
1778   int count2;
1779   Assert (s->mode == GL_QUADS, "convert_quads bad mode");
1780   count2 =
1781    cq2t ((unsigned char **) &s->verts, sizeof(*s->verts), s->count);
1782    cq2t ((unsigned char **) &s->norms, sizeof(*s->norms), s->count);
1783    cq2t ((unsigned char **) &s->tex,   sizeof(*s->tex),   s->count);
1784    cq2t ((unsigned char **) &s->color, sizeof(*s->color), s->count);
1785   s->count = count2;
1786   s->size  = count2;
1787   s->mode = GL_TRIANGLES;
1788 }
1789
1790
1791 void
1792 jwzgles_glEnd (void)
1793 {
1794   vert_set *s = &state->set;
1795   int was_norm, was_tex, was_color, was_mat;
1796   int  is_norm,  is_tex,  is_color,  is_mat;
1797
1798   Assert (state->compiling_verts == 1, "missing glBegin");
1799   state->compiling_verts--;
1800
1801   Assert (!state->replaying_list, "how did glEnd get into a display list?");
1802
1803   if (!state->replaying_list)
1804     {
1805       LOG5 ("%s  [V = %d, N = %d, T = %d, C = %d]",
1806             (state->compiling_list || state->replaying_list ? "  " : ""),
1807             s->count, s->ncount, s->tcount, s->ccount);
1808       LOG1 ("%sglEnd",
1809             (state->compiling_list || state->replaying_list ? "  " : ""));
1810     }
1811
1812   if (s->count == 0) return;
1813
1814   if (s->mode == GL_QUADS)
1815     convert_quads_to_triangles (s);
1816   else if (s->mode == GL_QUAD_STRIP)
1817     s->mode = GL_TRIANGLE_STRIP;        /* They do the same thing! */
1818   else if (s->mode == GL_POLYGON)
1819     s->mode = GL_TRIANGLE_FAN;          /* They do the same thing! */
1820
1821   jwzgles_glColorPointer   (4,GL_FLOAT, sizeof(*s->color),s->color); /* RGBA */
1822   jwzgles_glNormalPointer  (  GL_FLOAT, sizeof(*s->norms),s->norms); /* XYZ  */
1823   jwzgles_glTexCoordPointer(4,GL_FLOAT, sizeof(*s->tex),  s->tex);   /* STRQ */
1824   jwzgles_glVertexPointer  (4,GL_FLOAT, sizeof(*s->verts),s->verts); /* XYZW */
1825   /* glVertexPointer must come after glTexCoordPointer */
1826
1827   /* If there were no calls to glNormal3f inside of glBegin/glEnd,
1828      don't bother enabling the normals array.
1829
1830      If there was exactly *one* call to glNormal3f inside of glBegin/glEnd,
1831      and it was before the first glVertex3f, then also don't enable the
1832      normals array, but do emit that call to glNormal3f before calling
1833      glDrawArrays.
1834
1835      Likewise for texture coordinates and colors.
1836
1837      Be careful to leave the arrays' enabled/disabled state the same as
1838      before, or a later caller might end up using one of our arrays by
1839      mistake.  (Remember that jwzgles_glIsEnabled() tracks the enablement
1840      of the list-in-progress as well as the global state.)
1841   */
1842   was_norm  = jwzgles_glIsEnabled (GL_NORMAL_ARRAY);
1843   was_tex   = jwzgles_glIsEnabled (GL_TEXTURE_COORD_ARRAY);
1844   was_color = jwzgles_glIsEnabled (GL_COLOR_ARRAY);
1845   was_mat   = jwzgles_glIsEnabled (GL_COLOR_MATERIAL);
1846
1847   /* If we're executing glEnd in immediate mode, not from inside a display
1848      list (which is the only way it happens, because glEnd doesn't go into
1849      display lists), make sure we're not stomping on a saved buffer list:
1850      in immediate mode, vertexes are client-side only.
1851    */
1852   if (! state->compiling_list)
1853     jwzgles_glBindBuffer (GL_ARRAY_BUFFER, 0);
1854
1855   if (s->ncount > 1)
1856     {
1857       is_norm = 1;
1858       jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
1859     }
1860   else
1861     {
1862       is_norm = 0;
1863       if (s->ncount == 1)
1864         jwzgles_glNormal3f (s->cnorm.x, s->cnorm.y, s->cnorm.z);
1865       jwzgles_glDisableClientState (GL_NORMAL_ARRAY);
1866     }
1867
1868   if (s->tcount > 1 ||
1869       ((state->compiling_list ? state->list_enabled : state->enabled)
1870        & (ISENABLED_TEXTURE_GEN_S | ISENABLED_TEXTURE_GEN_T |
1871           ISENABLED_TEXTURE_GEN_R | ISENABLED_TEXTURE_GEN_Q)))
1872     {
1873       /* Enable texture coords if any were specified; or if generation
1874          is on in immediate mode; or if this list turned on generation. */
1875       is_tex = 1;
1876       jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
1877     }
1878   else
1879     {
1880       is_tex = 0;
1881       if (s->tcount == 1)
1882         jwzgles_glTexCoord4f (s->ctex.s, s->ctex.t, s->ctex.r, s->ctex.q);
1883       jwzgles_glDisableClientState (GL_TEXTURE_COORD_ARRAY);
1884     }
1885
1886   if (s->ccount > 1)
1887     {
1888       is_color = 1;
1889       jwzgles_glEnableClientState (GL_COLOR_ARRAY);
1890     }
1891   else
1892     {
1893       is_color = 0;
1894       if (s->ccount == 1)
1895         jwzgles_glColor4f (s->ccolor.r, s->ccolor.g, s->ccolor.b, s->ccolor.a);
1896       jwzgles_glDisableClientState (GL_COLOR_ARRAY);
1897     }
1898
1899   jwzgles_glEnableClientState (GL_VERTEX_ARRAY);
1900
1901   /* We translated the glMaterial calls to per-vertex colors, which are
1902      of the glColor sort, not the glMaterial sort, so automatically
1903      turn on material mapping.  Maybe this is a bad idea.
1904    */
1905   if (s->materialistic && !jwzgles_glIsEnabled (GL_COLOR_MATERIAL))
1906     {
1907       is_mat = 1;
1908       jwzgles_glEnable (GL_COLOR_MATERIAL);
1909     }
1910   else
1911     is_mat = 0;
1912
1913   glBindBuffer (GL_ARRAY_BUFFER, 0);    /* This comes later. */
1914   jwzgles_glDrawArrays (s->mode, 0, s->count);
1915   glBindBuffer (GL_ARRAY_BUFFER, 0);    /* Keep out of others' hands */
1916
1917 # define RESET(VAR,FN,ARG) do { \
1918          if (is_##VAR != was_##VAR) { \
1919             if (was_##VAR) jwzgles_glEnable##FN (ARG); \
1920             else jwzgles_glDisable##FN (ARG); \
1921          }} while(0)
1922   RESET (norm,  ClientState, GL_NORMAL_ARRAY);
1923   RESET (tex,   ClientState, GL_TEXTURE_COORD_ARRAY);
1924   RESET (color, ClientState, GL_COLOR_ARRAY);
1925   RESET (mat,   ,            GL_COLOR_MATERIAL);
1926 # undef RESET
1927
1928   s->count  = 0;
1929   s->ncount = 0;
1930   s->tcount = 0;
1931   s->ccount = 0;
1932   s->materialistic = 0;
1933 }
1934
1935
1936 /* The display list is full of calls to glDrawArrays(), plus saved arrays
1937    of the values we need to restore before calling it.  "Restore" means
1938    "ship them off to the GPU before each call".
1939
1940    So instead, this function walks through the display list and
1941    combines all of those vertex, normal, texture and color values into
1942    a single VBO array; ships those values off to the GPU *once* at the
1943    time of glEndList; and when running the list with glCallList, the
1944    values are already on the GPU and don't need to be sent over again.
1945
1946    The VBO persists in the GPU until the display list is deleted.
1947  */
1948 static void
1949 optimize_arrays (void)
1950 {
1951   list *L = &state->lists.lists[state->compiling_list-1];
1952   int i, j;
1953   GLfloat *combo = 0;
1954   int combo_count = 0;
1955   int combo_size = 0;
1956   GLuint buf_name = 0;
1957
1958   Assert (state->compiling_list, "not compiling a list");
1959   Assert (L, "no list");
1960   Assert (!L->buffer, "list already has a buffer");
1961
1962   glGenBuffers (1, &buf_name);
1963   CHECK("glGenBuffers");
1964   if (! buf_name) return;
1965
1966   L->buffer = buf_name;
1967
1968   /* Go through the list and dump the contents of the various saved arrays
1969      into one large array.
1970    */
1971   for (i = 0; i < L->count; i++)
1972     {
1973       list_fn *F = &L->fns[i];
1974 /*      int count; */
1975       if (! F->arrays)
1976         continue;
1977 /*      count = F->argv[2].i;*/  /* 3rd arg to glDrawArrays */
1978
1979       for (j = 0; j < 4; j++)
1980         {
1981           draw_array *A = &F->arrays[j];
1982           int ocount = combo_count;
1983
1984           /* If some caller is using arrays that don't have floats in them,
1985              we just leave them as-is and ship them over at each call.
1986              Doubt this ever really happens.
1987            */
1988           if (A->type != GL_FLOAT)
1989             continue;
1990
1991           if (! A->data)        /* No array. */
1992             continue;
1993
1994           Assert (A->bytes > 0, "no bytes in draw_array");
1995           Assert (((unsigned long) A->data > 0xFFFF),
1996                   "buffer data not a pointer");
1997
1998           combo_count += A->bytes / sizeof(*combo);
1999           make_room ("optimize_arrays",
2000                      (void **) &combo, sizeof(*combo),
2001                      &combo_count, &combo_size);
2002           memcpy (combo + ocount, A->data, A->bytes);
2003           A->binding = buf_name;
2004           free (A->data);
2005           /* 'data' is now the byte offset into the VBO. */
2006           A->data = (void *) (ocount * sizeof(*combo));
2007           /* LOG3("    loaded %lu floats to pos %d of buffer %d",
2008                A->bytes / sizeof(*combo), ocount, buf_name); */
2009         }
2010     }
2011
2012   if (combo_count == 0)         /* Nothing to do! */
2013     {
2014       if (combo) free (combo);
2015       glDeleteBuffers (1, &buf_name);
2016       L->buffer = 0;
2017       return;
2018     }
2019
2020   glBindBuffer (GL_ARRAY_BUFFER, buf_name);
2021   glBufferData (GL_ARRAY_BUFFER, 
2022                 combo_count * sizeof (*combo),
2023                 combo,
2024                 GL_STATIC_DRAW);
2025   glBindBuffer (GL_ARRAY_BUFFER, 0);    /* Keep out of others' hands */
2026
2027   LOG3("  loaded %d floats of list %d into VBO %d",
2028        combo_count, state->compiling_list, buf_name);
2029
2030 # ifdef DEBUG
2031 #  if 0
2032   for (i = 0; i < combo_count; i++)
2033     {
2034       if (i % 4 == 0)
2035         fprintf (stderr, "\njwzgles:    %4d: ", i);
2036       fprintf (stderr, " %7.3f", combo[i]);
2037     }
2038   fprintf (stderr, "\n");
2039 #  endif
2040 # endif /* DEBUG */
2041
2042   if (combo) free (combo);
2043 }
2044
2045
2046 void
2047 jwzgles_glCallList (int id)
2048 {
2049   if (state->compiling_list)
2050     {
2051       /* Yes, you can call lists inside of lists.
2052          Yes, recursion would be a mistake. */
2053       void_int vv[1];
2054       vv[0].i = id;
2055       list_push ("glCallList", (list_fn_cb) &jwzgles_glCallList, PROTO_I, vv);
2056     }
2057   else
2058     {
2059       list *L;
2060       int i;
2061
2062       state->replaying_list++;
2063
2064 # ifdef DEBUG
2065       fprintf (stderr, "\n");
2066       LOG1 ("glCallList %d", id);
2067 # endif
2068
2069       Assert (id > 0 && id <= state->lists.count, "glCallList: bogus ID");
2070       L = &state->lists.lists[id-1];
2071       Assert (id == L->id, "glCallList corrupted");
2072
2073       for (i = 0; i < L->count; i++)
2074         {
2075           list_fn *F = &L->fns[i];
2076           list_fn_cb fn = F->fn;
2077           void_int *av = F->argv;
2078
2079           switch (F->proto) {
2080           case PROTO_VOID:
2081             LOG1 ("  call %-12s", F->name);
2082             ((void (*) (void)) fn) ();
2083             break;
2084
2085           case PROTO_I:
2086             if (fn == (list_fn_cb) &jwzgles_glBegin ||
2087                 fn == (list_fn_cb) &jwzgles_glFrontFace ||
2088                 fn == (list_fn_cb) &jwzgles_glEnable ||
2089                 fn == (list_fn_cb) &jwzgles_glDisable ||
2090                 fn == (list_fn_cb) &jwzgles_glEnableClientState ||
2091                 fn == (list_fn_cb) &jwzgles_glDisableClientState ||
2092                 fn == (list_fn_cb) &jwzgles_glShadeModel ||
2093                 fn == (list_fn_cb) &jwzgles_glMatrixMode)
2094               LOG2 ("  call %-12s %s", F->name, mode_desc (av[0].i));
2095             else
2096               LOG2 ("  call %-12s %d", F->name, av[0].i);
2097             ((void (*) (int)) fn) (av[0].i);
2098             break;
2099
2100           case PROTO_F:
2101             LOG2 ("  call %-12s %7.3f", F->name, av[0].f);
2102             ((void (*) (GLfloat)) fn) (av[0].f);
2103             break;
2104
2105           case PROTO_II:
2106             if (fn == (list_fn_cb) &jwzgles_glBindTexture ||
2107                 fn == (list_fn_cb) &jwzgles_glBindBuffer)
2108               LOG3 ("  call %-12s %s %d", F->name, 
2109                     mode_desc (av[0].i), av[1].i);
2110             else
2111               LOG3 ("  call %-12s %d %d", F->name, av[0].i, av[1].i);
2112             ((void (*) (int, int)) fn) (av[0].i, av[1].i);
2113             break;
2114
2115           case PROTO_FF:
2116             LOG3 ("  call %-12s %7.3f %7.3f", F->name, av[0].f, av[1].f);
2117             ((void (*) (GLfloat, GLfloat)) fn) (av[0].f, av[1].f);
2118             break;
2119
2120           case PROTO_IF:
2121             LOG3 ("  call %-12s %s %7.3f", F->name, 
2122                   mode_desc (av[0].f), av[1].f);
2123             ((void (*) (GLint, GLfloat)) fn) (av[0].i, av[1].f);
2124             break;
2125
2126           case PROTO_III: III:
2127             if (fn == (list_fn_cb) &jwzgles_glDrawArrays ||
2128                 fn == (list_fn_cb) &jwzgles_glTexParameteri)
2129               LOG4 ("  call %-12s %s %d %d", F->name, 
2130                     mode_desc (av[0].i), av[1].i, av[2].i);
2131             else
2132               LOG4 ("  call %-12s %d %d %d", F->name, 
2133                     av[0].i, av[1].i, av[2].i);
2134             ((void (*) (int, int, int)) fn) (av[0].i, av[1].i, av[2].i);
2135             break;
2136
2137           case PROTO_FFF:
2138             LOG4 ("  call %-12s %7.3f %7.3f %7.3f", F->name,
2139                   av[0].f, av[1].f, av[2].f);
2140             ((void (*) (GLfloat, GLfloat, GLfloat)) fn)
2141               (av[0].f, av[1].f, av[2].f);
2142             break;
2143
2144           case PROTO_IIF:
2145             LOG4 ("  call %-12s %s %s %7.3f", F->name,
2146                   mode_desc (av[0].i), mode_desc (av[1].i), av[2].f);
2147             ((void (*) (int, int, GLfloat)) fn) (av[0].i, av[1].i, av[2].f);
2148             break;
2149
2150           case PROTO_IIII:
2151             LOG5 ("  call %-12s %d %d %d %d", F->name,
2152                   av[0].i, av[1].i, av[2].i, av[3].i);
2153             ((void (*) (int, int, int, int)) fn) 
2154               (av[0].i, av[1].i, av[2].i, av[3].i);
2155             break;
2156
2157           case PROTO_FFFF:
2158             LOG5 ("  call %-12s %7.3f %7.3f %7.3f %7.3f", F->name,
2159                   av[0].f, av[1].f, av[2].f, av[3].f);
2160             ((void (*) (GLfloat, GLfloat, GLfloat, GLfloat)) fn)
2161               (av[0].f, av[1].f, av[2].f, av[3].f);
2162             break;
2163
2164           case PROTO_IFV:
2165             {
2166               GLfloat v[4];
2167               v[0] = av[1].f;
2168               v[1] = av[2].f;
2169               v[2] = av[3].f;
2170               v[3] = av[4].f;
2171               LOG6 ("  call %-12s %s %3.1f %3.1f %3.1f %3.1f", F->name,
2172                     mode_desc (av[0].i),
2173                     av[1].f, av[2].f, av[3].f, av[4].f);
2174               ((void (*) (int, const GLfloat *)) fn) (av[0].i, v);
2175             }
2176             break;
2177
2178           case PROTO_IIFV:
2179             {
2180               GLfloat v[4];
2181               v[0] = av[2].f;
2182               v[1] = av[3].f;
2183               v[2] = av[4].f;
2184               v[3] = av[5].f;
2185               LOG7 ("  call %-12s %s %-8s %3.1f %3.1f %3.1f %3.1f", F->name,
2186                     mode_desc (av[0].i), mode_desc (av[1].i), 
2187                     av[2].f, av[3].f, av[4].f, av[5].f);
2188               ((void (*) (int, int, const GLfloat *)) fn) 
2189                 (av[0].i, av[1].i, v);
2190             }
2191             break;
2192
2193           case PROTO_IIV:
2194             {
2195               int v[4];
2196               v[0] = av[1].i;
2197               v[1] = av[2].i;
2198               v[2] = av[3].i;
2199               v[3] = av[4].i;
2200               LOG6 ("  call %-12s %s %3d %3d %3d %3d", F->name, 
2201                     mode_desc (av[0].i),
2202                     av[1].i, av[2].i, av[3].i, av[4].i);
2203               ((void (*) (int, const int *)) fn) (av[0].i, v);
2204             }
2205             break;
2206
2207           case PROTO_IIIV:
2208             {
2209               int v[4];
2210               v[0] = av[2].i;
2211               v[1] = av[3].i;
2212               v[2] = av[4].i;
2213               v[3] = av[5].i;
2214               LOG7 ("  call %-12s %s %-8s %3d %3d %3d %3d", F->name,
2215                     mode_desc (av[0].i), mode_desc (av[1].i), 
2216                     av[2].i, av[3].i, av[4].i, av[5].i);
2217               ((void (*) (int, int, const int *)) fn) 
2218                 (av[0].i, av[1].i, v);
2219             }
2220             break;
2221
2222           case PROTO_ARRAYS:
2223             restore_arrays (F, av[1].i + av[2].i);
2224             goto III;
2225             break;
2226
2227           case PROTO_FV16:
2228             {
2229               GLfloat m[16];
2230               int i;
2231               for (i = 0; i < countof(m); i++)
2232                 m[i] = av[i].f;
2233               LOG17 ("  call %-12s ["
2234                      "%8.3f %8.3f %8.3f %8.3f " "\n\t\t\t       "
2235                      "%8.3f %8.3f %8.3f %8.3f " "\n\t\t\t       "
2236                      "%8.3f %8.3f %8.3f %8.3f " "\n\t\t\t       "
2237                      "%8.3f %8.3f %8.3f %8.3f ]",
2238                      F->name,
2239                      m[0],  m[1],  m[2],  m[3],
2240                      m[4],  m[5],  m[6],  m[7],
2241                      m[8],  m[9],  m[10], m[11],
2242                      m[12], m[13], m[14], m[15]);
2243               ((void (*) (GLfloat *)) fn) (m);
2244             }
2245             break;
2246
2247           default:
2248             Assert (0, "bogus prototype");
2249             break;
2250           }
2251         }
2252
2253       LOG1 ("glCallList %d done\n", id);
2254
2255       state->replaying_list--;
2256       Assert (state->replaying_list >= 0, "glCallList corrupted");
2257     }
2258 }
2259
2260
2261 /* When we save a call to glDrawArrays into a display list, we also need to
2262    save the prevailing copy of the arrays that it will use, and restore them
2263    later.
2264  */
2265 static void
2266 save_arrays (list_fn *F, int count)
2267 {
2268   int i = 0;
2269   draw_array *A = (draw_array *) calloc (4, sizeof (*A));
2270   Assert (A, "out of memory");
2271
2272 /*  if (state->set.count > 0) */
2273     {
2274       glGetIntegerv (GL_VERTEX_ARRAY_BUFFER_BINDING, &A[i].binding);
2275       glGetIntegerv (GL_VERTEX_ARRAY_SIZE,    &A[i].size);
2276       glGetIntegerv (GL_VERTEX_ARRAY_TYPE,    &A[i].type);
2277       glGetIntegerv (GL_VERTEX_ARRAY_STRIDE,  &A[i].stride);
2278       glGetPointerv (GL_VERTEX_ARRAY_POINTER, &A[i].data);
2279       CHECK("glGetPointerv");
2280       copy_array_data (&A[i], count, "vert");
2281     }
2282
2283   i++;
2284   if (state->set.ncount > 1)
2285     {
2286       A[i].size = 3;
2287       glGetIntegerv (GL_NORMAL_ARRAY_BUFFER_BINDING, &A[i].binding);
2288       glGetIntegerv (GL_NORMAL_ARRAY_TYPE,    &A[i].type);
2289       glGetIntegerv (GL_NORMAL_ARRAY_STRIDE,  &A[i].stride);
2290       glGetPointerv (GL_NORMAL_ARRAY_POINTER, &A[i].data);
2291       CHECK("glGetPointerv");
2292       copy_array_data (&A[i], count, "norm");
2293     }
2294
2295   i++;
2296   if (state->set.tcount > 1)
2297     {
2298       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING, &A[i].binding);
2299       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_SIZE,    &A[i].size);
2300       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_TYPE,    &A[i].type);
2301       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_STRIDE,  &A[i].stride);
2302       glGetPointerv (GL_TEXTURE_COORD_ARRAY_POINTER, &A[i].data);
2303       CHECK("glGetPointerv");
2304       copy_array_data (&A[i], count, "tex ");
2305     }
2306
2307   i++;
2308   if (state->set.ccount > 1)
2309     {
2310       glGetIntegerv (GL_COLOR_ARRAY_BUFFER_BINDING, &A[i].binding);
2311       glGetIntegerv (GL_COLOR_ARRAY_SIZE,    &A[i].size);
2312       glGetIntegerv (GL_COLOR_ARRAY_TYPE,    &A[i].type);
2313       glGetIntegerv (GL_COLOR_ARRAY_STRIDE,  &A[i].stride);
2314       glGetPointerv (GL_COLOR_ARRAY_POINTER, &A[i].data);
2315       CHECK("glGetPointerv");
2316       copy_array_data (&A[i], count, "col ");
2317     }
2318
2319   /* Freed by glDeleteLists. */
2320
2321   Assert (!F->arrays, "save_arrays corrupted");
2322   F->arrays = A;
2323 }
2324
2325
2326 #ifdef DEBUG
2327
2328 static void
2329 dump_array_data (draw_array *A, int count,
2330                  const char *action, const char *name, const void *old)
2331 {
2332   int bytes = count * A->stride;
2333
2334   if (A->binding)
2335     {
2336       fprintf (stderr, 
2337                "jwzgles:     %s %s %d %s %2d, %4d = %5d   bind %d @ %d\n", 
2338                action, name,
2339                A->size, mode_desc(A->type), A->stride, 
2340                count, bytes, A->binding, (int) A->data);
2341     }
2342   else
2343     {
2344       Assert (bytes == A->bytes, "array data corrupted");
2345
2346       fprintf (stderr, "jwzgles:     %s %s %d %s %2d, %4d = %5d @ %lX", 
2347                action, name,
2348                A->size, mode_desc(A->type), A->stride, 
2349                count, bytes, (unsigned long) A->data);
2350       if (old)
2351         fprintf (stderr, " / %lX", (unsigned long) old);
2352       fprintf (stderr, "\n");
2353     }
2354
2355   if (A->binding)
2356     {
2357       Assert (((unsigned long) A->data < 0xFFFF),
2358               "buffer binding should be a numeric index,"
2359               " but looks like a pointer");
2360
2361 # if 0
2362       /* glGetBufferSubData doesn't actually exist in OpenGLES, but this
2363          was helpful for debugging on real OpenGL... */
2364       GLfloat *d;
2365       int i;
2366       fprintf (stderr, "jwzgles: read back:\n");
2367       d = (GLfloat *) malloc (A->bytes);
2368       glGetBufferSubData (GL_ARRAY_BUFFER, (int) A->data,
2369                           count * A->stride, (void *) d);
2370       CHECK("glGetBufferSubData");
2371       for (i = 0; i < count * A->size; i++)
2372         {
2373           if (i % 4 == 0)
2374             fprintf (stderr, "\njwzgles:    %4d: ", 
2375                      i + (int) A->data / sizeof(GLfloat));
2376           fprintf (stderr, " %7.3f", d[i]);
2377         }
2378       fprintf (stderr, "\n");
2379       free (d);
2380 # endif
2381     }
2382 # if 0
2383   else
2384     {
2385       unsigned char *b = (unsigned char *) A->data;
2386       int i;
2387       if ((unsigned long) A->data < 0xFFFF)
2388         {
2389           Assert (0, "buffer data not a pointer");
2390           return;
2391         }
2392       for (i = 0; i < count; i++)
2393         {
2394           int j;
2395           GLfloat *f = (GLfloat *) b;
2396           int s = A->size;
2397           if (s == 0) s = 3;  /* normals */
2398           fprintf (stderr, "jwzgles:    ");
2399           for (j = 0; j < s; j++)
2400             fprintf (stderr, " %7.3f", f[j]);
2401           fprintf (stderr, "\n");
2402           b += A->stride;
2403         }
2404     }
2405 # endif
2406 }
2407
2408 static void
2409 dump_direct_array_data (int count)
2410 {
2411   draw_array A = { 0, };
2412
2413   if (jwzgles_glIsEnabled (GL_VERTEX_ARRAY))
2414     {
2415       glGetIntegerv (GL_VERTEX_ARRAY_BUFFER_BINDING, &A.binding);
2416       glGetIntegerv (GL_VERTEX_ARRAY_SIZE,    &A.size);
2417       glGetIntegerv (GL_VERTEX_ARRAY_TYPE,    &A.type);
2418       glGetIntegerv (GL_VERTEX_ARRAY_STRIDE,  &A.stride);
2419       glGetPointerv (GL_VERTEX_ARRAY_POINTER, &A.data);
2420       A.bytes = count * A.stride;
2421       dump_array_data (&A, count, "direct", "vertex ", 0);
2422     }
2423   if (jwzgles_glIsEnabled (GL_NORMAL_ARRAY))
2424     {
2425       A.size = 0;
2426       glGetIntegerv (GL_NORMAL_ARRAY_BUFFER_BINDING, &A.binding);
2427       glGetIntegerv (GL_NORMAL_ARRAY_TYPE,    &A.type);
2428       glGetIntegerv (GL_NORMAL_ARRAY_STRIDE,  &A.stride);
2429       glGetPointerv (GL_NORMAL_ARRAY_POINTER, &A.data);
2430       A.bytes = count * A.stride;
2431       dump_array_data (&A, count, "direct", "normal ", 0);
2432     }
2433   if (jwzgles_glIsEnabled (GL_TEXTURE_COORD_ARRAY))
2434     {
2435       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING, &A.binding);
2436       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_SIZE,    &A.size);
2437       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_TYPE,    &A.type);
2438       glGetIntegerv (GL_TEXTURE_COORD_ARRAY_STRIDE,  &A.stride);
2439       glGetPointerv (GL_TEXTURE_COORD_ARRAY_POINTER, &A.data);
2440       A.bytes = count * A.stride;
2441       dump_array_data (&A, count, "direct", "texture", 0);
2442     }
2443   if (jwzgles_glIsEnabled (GL_COLOR_ARRAY))
2444     {
2445       glGetIntegerv (GL_COLOR_ARRAY_BUFFER_BINDING, &A.binding);
2446       glGetIntegerv (GL_COLOR_ARRAY_SIZE,    &A.size);
2447       glGetIntegerv (GL_COLOR_ARRAY_TYPE,    &A.type);
2448       glGetIntegerv (GL_COLOR_ARRAY_STRIDE,  &A.stride);
2449       glGetPointerv (GL_COLOR_ARRAY_POINTER, &A.data);
2450       A.bytes = count * A.stride;
2451       dump_array_data (&A, count, "direct", "color ", 0);
2452     }
2453 }
2454
2455 #endif /* DEBUG */
2456
2457
2458 static void
2459 copy_array_data (draw_array *A, int count, const char *name)
2460 {
2461   /* Instead of just memcopy'ing the whole array and obeying its previous
2462      'stride' value, we make up a more compact array.  This is because if
2463      the same array data is being used with multiple component types,
2464      e.g. with glInterleavedArrays, we don't want to copy all of the
2465      data multiple times.
2466    */
2467   int stride2, bytes, i, j;
2468   void *data2;
2469   const GLfloat *IF;
2470   GLfloat *OF;
2471   const unsigned char *IB;
2472   unsigned char *OB;
2473
2474   if (((unsigned long) A->data) < 0xFFFF)
2475     {
2476       Assert (0, "buffer data not a pointer");
2477       return;
2478     }
2479
2480   Assert (A->size >= 2 && A->size <= 4, "bogus array size");
2481
2482   switch (A->type) {
2483   case GL_FLOAT:         stride2 = A->size * sizeof(GLfloat); break;
2484   case GL_UNSIGNED_BYTE: stride2 = A->size; break;
2485   default: Assert (0, "bogus array type"); break;
2486   }
2487
2488   bytes = count * stride2;
2489   Assert (bytes > 0, "bogus array count or stride");
2490   Assert (A->data, "missing array data");
2491   data2 = (void *) malloc (bytes);
2492   Assert (data2, "out of memory");
2493
2494   IB = (const unsigned char *) A->data;
2495   OB = (unsigned char *) data2;
2496   IF = (const GLfloat *) A->data;
2497   OF = (GLfloat *) data2;
2498
2499   switch (A->type) {
2500   case GL_FLOAT:
2501     for (i = 0; i < count; i++)
2502       {
2503         for (j = 0; j < A->size; j++)
2504           *OF++ = IF[j];
2505         IF = (const GLfloat *) (((const unsigned char *) IF) + A->stride);
2506       }
2507     break;
2508   case GL_UNSIGNED_BYTE:
2509     for (i = 0; i < count; i++)
2510       {
2511         for (j = 0; j < A->size; j++)
2512           *OB++ = IB[j];
2513         IB += A->stride;
2514       }
2515     break;
2516   default:
2517     Assert (0, "bogus array type");
2518     break;
2519   }
2520
2521   A->data = data2;
2522   A->bytes = bytes;
2523   A->stride = stride2;
2524
2525 # ifdef DEBUG
2526   dump_array_data (A, count, "saved", name, 0);
2527 # endif
2528 }
2529
2530
2531 static void
2532 restore_arrays (list_fn *F, int count)
2533 {
2534   int i = 0;
2535   draw_array *A = F->arrays;
2536   Assert (A, "missing array");
2537
2538   for (i = 0; i < 4; i++)
2539     {
2540       const char *name = 0;
2541
2542       if (!A[i].size)
2543         continue;
2544
2545       Assert ((A[i].binding || A[i].data),
2546               "array has neither buffer binding nor data");
2547
2548       glBindBuffer (GL_ARRAY_BUFFER, A[i].binding);
2549       CHECK("glBindBuffer");
2550
2551       switch (i) {
2552       case 0: glVertexPointer  (A[i].size, A[i].type, A[i].stride, A[i].data);
2553         name = "vertex ";
2554         CHECK("glVertexPointer");
2555         break;
2556       case 1: glNormalPointer  (           A[i].type, A[i].stride, A[i].data);
2557         name = "normal ";
2558         CHECK("glNormalPointer");
2559         break;
2560       case 2: glTexCoordPointer(A[i].size, A[i].type, A[i].stride, A[i].data);
2561         name = "texture";
2562         CHECK("glTexCoordPointer");
2563         break;
2564       case 3: glColorPointer   (A[i].size, A[i].type, A[i].stride, A[i].data);
2565         name = "color  ";
2566         CHECK("glColorPointer");
2567         break;
2568       default: Assert (0, "wat"); break;
2569       }
2570
2571 # ifdef DEBUG
2572       dump_array_data (&A[i], count, "restored", name, 0);
2573 # endif
2574     }
2575
2576   glBindBuffer (GL_ARRAY_BUFFER, 0);    /* Keep out of others' hands */
2577 }
2578
2579
2580 void
2581 jwzgles_glDrawArrays (GLuint mode, GLuint first, GLuint count)
2582 {
2583   /* If we are auto-generating texture coordinates, do that now, after
2584      the vertex array was installed, but before drawing, This happens
2585      when recording into a list, or in direct mode.  It must happen
2586      before calling optimize_arrays() from glEndList().
2587    */
2588   if (! state->replaying_list &&
2589       ((state->compiling_list ? state->list_enabled : state->enabled)
2590        & (ISENABLED_TEXTURE_GEN_S | ISENABLED_TEXTURE_GEN_T |
2591           ISENABLED_TEXTURE_GEN_R | ISENABLED_TEXTURE_GEN_Q)))
2592     generate_texture_coords (first, count);
2593
2594   if (state->compiling_list)
2595     {
2596       void_int vv[3];
2597       vv[0].i = mode;
2598       vv[1].i = first;
2599       vv[2].i = count;
2600       list_push ("glDrawArrays", (list_fn_cb) &jwzgles_glDrawArrays,
2601                  PROTO_ARRAYS, vv);
2602     }
2603   else
2604     {
2605 # ifdef DEBUG
2606       if (! state->replaying_list) {
2607         LOG4("direct %-12s %d %d %d", "glDrawArrays", mode, first, count);
2608         dump_direct_array_data (first + count);
2609       }
2610 # endif
2611       glDrawArrays (mode, first, count);  /* the real one */
2612       CHECK("glDrawArrays");
2613     }
2614 }
2615
2616
2617 void
2618 jwzgles_glInterleavedArrays (GLenum format, GLsizei stride, const void *data)
2619 {
2620   /* We can implement this by calling the various *Pointer functions
2621      with offsets into the same data, taking advantage of stride.
2622    */
2623   const unsigned char *c = (const unsigned char *) data;
2624 # define B 1
2625 # define F sizeof(GLfloat)
2626
2627   Assert (!state->compiling_verts,
2628           "glInterleavedArrays not allowed inside glBegin");
2629
2630   jwzgles_glEnableClientState (GL_VERTEX_ARRAY);
2631
2632   if (!state->replaying_list)
2633     LOG4 ("%sglInterleavedArrays %s %d %lX", 
2634           (state->compiling_list || state->replaying_list ? "  " : ""),
2635           mode_desc (format), stride, (unsigned long) data);
2636
2637   switch (format) {
2638   case GL_V2F:
2639     glVertexPointer (2, GL_FLOAT, stride, c);
2640     CHECK("glVertexPointer");
2641     if (!state->replaying_list)
2642       LOG3 ("%s  -> glVertexPointer 2 FLOAT %d %lX", 
2643             (state->compiling_list || state->replaying_list ? "  " : ""),
2644             stride, (unsigned long) c);
2645     break;
2646   case GL_V3F:
2647     glVertexPointer (3, GL_FLOAT, stride, c);
2648     CHECK("glVertexPointer");
2649     if (!state->replaying_list)
2650       LOG3 ("%s  -> glVertexPointer 3 FLOAT %d %lX", 
2651             (state->compiling_list || state->replaying_list ? "  " : ""),
2652             stride, (unsigned long) c);
2653     break;
2654   case GL_C4UB_V2F:     
2655     if (stride == 0)
2656       stride = 4*B + 2*F;
2657     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2658     glColorPointer (4, GL_UNSIGNED_BYTE, stride, c);
2659     CHECK("glColorPointer");
2660     c += 4*B;   /* #### might be incorrect float-aligned address */
2661     glVertexPointer (2, GL_FLOAT, stride, c);
2662     break;
2663   case GL_C4UB_V3F:
2664     if (stride == 0)
2665       stride = 4*B + 3*F;
2666     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2667     glColorPointer (4, GL_UNSIGNED_BYTE, stride, c);
2668     CHECK("glColorPointer");
2669     c += 4*B;
2670     glVertexPointer (3, GL_FLOAT, stride, c);
2671     CHECK("glVertexPointer");
2672     break;
2673   case GL_C3F_V3F:
2674     if (stride == 0)
2675       stride = 3*F + 3*F;
2676     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2677     glColorPointer (3, GL_FLOAT, stride, c);
2678     CHECK("glColorPointer");
2679     c += 3*F;
2680     glVertexPointer (3, GL_FLOAT, stride, c);
2681     CHECK("glVertexPointer");
2682     break;
2683   case GL_N3F_V3F:
2684     if (stride == 0)
2685       stride = 3*F + 3*F;
2686     jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
2687     glNormalPointer (GL_FLOAT, stride, c);
2688     CHECK("glNormalPointer");
2689     if (!state->replaying_list)
2690       LOG3 ("%s  -> glNormalPointer   FLOAT %d %lX", 
2691             (state->compiling_list || state->replaying_list ? "  " : ""),
2692             stride, (unsigned long) c);
2693     c += 3*F;
2694     glVertexPointer (3, GL_FLOAT, stride, c);
2695     CHECK("glVertexPointer");
2696     if (!state->replaying_list)
2697       LOG3 ("%s  -> glVertexPointer 3 FLOAT %d %lX", 
2698             (state->compiling_list || state->replaying_list ? "  " : ""),
2699             stride, (unsigned long) c);
2700     break;
2701   case GL_C4F_N3F_V3F:
2702     if (stride == 0)
2703       stride = 4*F + 3*F + 3*F;
2704     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2705     glColorPointer (4, GL_FLOAT, stride, c);
2706     CHECK("glColorPointer");
2707     c += 4*F;
2708     jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
2709     glNormalPointer (GL_FLOAT, stride, c);
2710     CHECK("glNormalPointer");
2711     c += 3*F;
2712     glVertexPointer (3, GL_FLOAT, stride, c);
2713     CHECK("glVertexPointer");
2714     break;
2715   case GL_T2F_V3F:
2716     if (stride == 0)
2717       stride = 2*F + 3*F;
2718     jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2719     glTexCoordPointer (2, GL_FLOAT, stride, c);
2720     CHECK("glTexCoordPointer");
2721     c += 2*F;
2722     glVertexPointer (3, GL_FLOAT, stride, c);
2723     CHECK("glVertexPointer");
2724     break;
2725   case GL_T4F_V4F:
2726     if (stride == 0)
2727       stride = 4*F + 4*F;
2728     jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2729     glTexCoordPointer (4, GL_FLOAT, stride, c);
2730     CHECK("glTexCoordPointer");
2731     c += 4*F;
2732     glVertexPointer (4, GL_FLOAT, stride, c);
2733     CHECK("glVertexPointer");
2734     break;
2735   case GL_T2F_C4UB_V3F:
2736     if (stride == 0)
2737       stride = 2*F + 4*B + 3*F;
2738     jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2739     glTexCoordPointer (2, GL_FLOAT, stride, c);
2740     CHECK("glTexCoordPointer");
2741     c += 2*F;
2742     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2743     glColorPointer  (4, GL_UNSIGNED_BYTE, stride, c);
2744     CHECK("glColorPointer");
2745     c += 4*B;
2746     glVertexPointer (3, GL_FLOAT, stride, c);
2747     CHECK("glVertexPointer");
2748     break;
2749   case GL_T2F_C3F_V3F:
2750     if (stride == 0)
2751       stride = 2*F + 3*F + 3*F;
2752     jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2753     glTexCoordPointer (2, GL_FLOAT, stride, c);
2754     CHECK("glTexCoordPointer");
2755     c += 2*F;
2756     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2757     glColorPointer  (3, GL_FLOAT, stride, c);
2758     CHECK("glColorPointer");
2759     c += 3*F;
2760     glVertexPointer (3, GL_FLOAT, stride, c);
2761     CHECK("glVertexPointer");
2762     break;
2763   case GL_T2F_N3F_V3F:
2764     if (stride == 0)
2765       stride = 2*F + 3*F + 3*F;
2766     jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2767     glTexCoordPointer (2, GL_FLOAT, stride, c);
2768     CHECK("glTexCoordPointer");
2769     c += 2*F;
2770     jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
2771     glNormalPointer (GL_FLOAT, stride, c);
2772     CHECK("glNormalPointer");
2773     c += 3*F;
2774     glVertexPointer (3, GL_FLOAT, stride, c);
2775     CHECK("glVertexPointer");
2776     break;
2777   case GL_T2F_C4F_N3F_V3F:
2778     if (stride == 0)
2779       stride = 2*F + 4*F + 3*F + 3*F;
2780     jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2781     glTexCoordPointer (2, GL_FLOAT, stride, c);
2782     CHECK("glTexCoordPointer");
2783     c += 2*F;
2784     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2785     glColorPointer  (3, GL_FLOAT, stride, c);
2786     CHECK("glColorPointer");
2787     c += 3*F;
2788     jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
2789     glNormalPointer (GL_FLOAT, stride, c);
2790     CHECK("glNormalPointer");
2791     c += 3*F;
2792     glVertexPointer (3, GL_FLOAT, stride, c);
2793     CHECK("glVertexPointer");
2794     break;
2795   case GL_T4F_C4F_N3F_V4F:
2796     if (stride == 0)
2797       stride = 4*F + 4*F + 3*F + 4*F;
2798     jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2799     glTexCoordPointer (4, GL_FLOAT, stride, c);
2800     CHECK("glTexCoordPointer");
2801     c += 4*F;
2802     jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2803     glColorPointer  (4, GL_FLOAT, stride, c);
2804     CHECK("glColorPointer");
2805     c += 4*F;
2806     jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
2807     glNormalPointer (GL_FLOAT, stride, c);
2808     CHECK("glNormalPointer");
2809     c += 3*F;
2810     glVertexPointer (3, GL_FLOAT, stride, c);
2811     CHECK("glVertexPointer");
2812     break;
2813   default:
2814     Assert (0, "glInterleavedArrays: bogus format");
2815     break;
2816   }
2817
2818 # undef B
2819 # undef F
2820 }
2821
2822
2823
2824 void
2825 jwzgles_glMultMatrixf (const GLfloat *m)
2826 {
2827   Assert (!state->compiling_verts,
2828           "glMultMatrixf not allowed inside glBegin");
2829   if (state->compiling_list)
2830     {
2831       void_int vv[16];
2832       int i;
2833       for (i = 0; i < countof(vv); i++)
2834         vv[i].f = m[i];
2835       list_push ("glMultMatrixf", (list_fn_cb) &jwzgles_glMultMatrixf,
2836                  PROTO_FV16, vv);
2837     }
2838   else
2839     {
2840       if (! state->replaying_list)
2841         LOG1 ("direct %-12s", "glMultMatrixf");
2842       glMultMatrixf (m);  /* the real one */
2843       CHECK("glMultMatrixf");
2844     }
2845 }
2846
2847
2848 void
2849 jwzgles_glClearIndex(GLfloat c)
2850 {
2851   /* Does GLES even do indexed color? */
2852   Assert (0, "glClearIndex unimplemented");
2853 }
2854
2855
2856 void
2857 jwzgles_glBitmap (GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig,
2858                   GLfloat xmove, GLfloat ymove, const GLubyte *bitmap)
2859 {
2860   Assert (0, "glBitmap unimplemented");
2861 }
2862
2863 void
2864 jwzgles_glPushAttrib(int flags)
2865 {
2866   Assert (0, "glPushAttrib unimplemented");
2867 }
2868
2869 void
2870 jwzgles_glPopAttrib(void)
2871 {
2872   Assert (0, "glPopAttrib unimplemented");
2873 }
2874
2875
2876 /* These are needed for object hit detection in pinion.
2877    Might need to rewrite that code entirely.  Punt for now.
2878  */
2879 void
2880 jwzgles_glInitNames (void)
2881 {
2882 /*  Assert (0, "glInitNames unimplemented");*/
2883 }
2884
2885 void
2886 jwzgles_glPushName (GLuint name)
2887 {
2888 /*  Assert (0, "glPushName unimplemented");*/
2889 }
2890
2891 GLuint
2892 jwzgles_glPopName (void)
2893 {
2894 /*  Assert (0, "glPopName unimplemented");*/
2895   return 0;
2896 }
2897
2898 GLuint
2899 jwzgles_glRenderMode (GLuint mode)
2900 {
2901 /*  Assert (0, "glRenderMode unimplemented");*/
2902   return 0;
2903 }
2904
2905 void
2906 jwzgles_glSelectBuffer (GLsizei size, GLuint *buf)
2907 {
2908 /*  Assert (0, "glSelectBuffer unimplemented");*/
2909 }
2910
2911
2912 void
2913 jwzgles_glGenTextures (GLuint n, GLuint *ret)
2914 {
2915   Assert (!state->compiling_verts,
2916           "glGenTextures not allowed inside glBegin");
2917   /* technically legal, but stupid! */
2918   Assert (!state->compiling_list,
2919           "glGenTextures not allowed inside glNewList");
2920   if (! state->replaying_list)
2921     LOG1 ("direct %-12s", "glGenTextures");
2922   glGenTextures (n, ret);  /* the real one */
2923   CHECK("glGenTextures");
2924 }
2925
2926
2927 /* return the next larger power of 2. */
2928 static int
2929 to_pow2 (int value)
2930 {
2931   int i = 1;
2932   while (i < value) i <<= 1;
2933   return i;
2934 }
2935
2936 void
2937 jwzgles_glTexImage1D (GLenum target, GLint level,
2938                       GLint internalFormat,
2939                       GLsizei width, GLint border,
2940                       GLenum format, GLenum type,
2941                       const GLvoid *data)
2942 {
2943   Assert (!state->compiling_verts, "glTexImage1D not allowed inside glBegin");
2944   /* technically legal, but stupid! */
2945   Assert (!state->compiling_list, "glTexImage1D inside glNewList");
2946   Assert (width  == to_pow2(width), "width must be a power of 2");
2947
2948   if (target == GL_TEXTURE_1D) target = GL_TEXTURE_2D;
2949   jwzgles_glTexImage2D (target, level, internalFormat, width, 1,
2950                         border, format, type, data);
2951 }
2952
2953 void
2954 jwzgles_glTexImage2D (GLenum target,
2955                       GLint     level,
2956                       GLint     internalFormat,
2957                       GLsizei   width,
2958                       GLsizei   height,
2959                       GLint     border,
2960                       GLenum    format,
2961                       GLenum    type,
2962                       const GLvoid *data)
2963 {
2964   GLvoid *d2 = (GLvoid *) data;
2965   Assert (!state->compiling_verts, "glTexImage2D not allowed inside glBegin");
2966   Assert (!state->compiling_list,  /* technically legal, but stupid! */
2967           "glTexImage2D not allowed inside glNewList");
2968
2969   Assert (width  == to_pow2(width),   "width must be a power of 2");
2970   Assert (height == to_pow2(height), "height must be a power of 2");
2971
2972   /* OpenGLES no longer supports "4" as a synonym for "RGBA". */
2973   switch (internalFormat) {
2974   case 1: internalFormat = GL_LUMINANCE; break;
2975   case 2: internalFormat = GL_LUMINANCE_ALPHA; break;
2976   case 3: internalFormat = GL_RGB; break;
2977   case 4: internalFormat = GL_RGBA; break;
2978   }
2979
2980   /* GLES does not let us omit the data pointer to create a blank texture. */
2981   if (! data)
2982     {
2983       d2 = (GLvoid *) calloc (1, width * height * sizeof(GLfloat) * 4);
2984       Assert (d2, "out of memory");
2985     }
2986
2987   if (internalFormat == GL_RGB && format == GL_RGBA)
2988     internalFormat = GL_RGBA;  /* WTF */
2989   if (type == GL_UNSIGNED_INT_8_8_8_8_REV)
2990     type = GL_UNSIGNED_BYTE;
2991
2992   if (! state->replaying_list)
2993     LOG10 ("direct %-12s %s %d %s %d %d %d %s %s 0x%lX", "glTexImage2D", 
2994            mode_desc(target), level, mode_desc(internalFormat),
2995            width, height, border, mode_desc(format), mode_desc(type),
2996            (unsigned long) d2);
2997   glTexImage2D (target, level, internalFormat, width, height, border,
2998                 format, type, d2);  /* the real one */
2999   CHECK("glTexImage2D");
3000
3001   if (d2 != data) free (d2);
3002 }
3003
3004 void
3005 jwzgles_glTexSubImage2D (GLenum target, GLint level,
3006                          GLint xoffset, GLint yoffset,
3007                          GLsizei width, GLsizei height,
3008                          GLenum format, GLenum type,
3009                          const GLvoid *pixels)
3010 {
3011   Assert (!state->compiling_verts,
3012           "glTexSubImage2D not allowed inside glBegin");
3013   Assert (!state->compiling_list,   /* technically legal, but stupid! */
3014           "glTexSubImage2D not allowed inside glNewList");
3015
3016   if (! state->replaying_list)
3017     LOG10 ("direct %-12s %s %d %d %d %d %d %s %s 0x%lX", "glTexSubImage2D", 
3018            mode_desc(target), level, xoffset, yoffset, width, height,
3019            mode_desc (format), mode_desc (type), (unsigned long) pixels);
3020   glTexSubImage2D (target, level, xoffset, yoffset, width, height,
3021                    format, type, pixels);  /* the real one */
3022   CHECK("glTexSubImage2D");
3023 }
3024
3025 void
3026 jwzgles_glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat,
3027                           GLint x, GLint y, GLsizei width, GLsizei height,
3028                           GLint border)
3029 {
3030   Assert (!state->compiling_verts, 
3031           "glCopyTexImage2D not allowed inside glBegin");
3032   Assert (!state->compiling_list,    /* technically legal, but stupid! */
3033           "glCopyTexImage2D not allowed inside glNewList");
3034   if (! state->replaying_list)
3035     LOG9 ("direct %-12s %s %d %s %d %d %d %d %d", "glCopyTexImage2D", 
3036           mode_desc(target), level, mode_desc(internalformat),
3037           x, y, width, height, border);
3038   glCopyTexImage2D (target, level, internalformat, x, y, width, height,
3039                     border);  /* the real one */
3040   CHECK("glCopyTexImage2D");
3041 }
3042
3043
3044 /* OpenGLES doesn't have auto texture-generation at all!
3045    "Oh, just rewrite that code to use GPU shaders", they say.
3046    How fucking convenient.
3047  */
3048 void
3049 jwzgles_glTexGenfv (GLenum coord, GLenum pname, const GLfloat *params)
3050 {
3051   texgen_state *s;
3052
3053   if (pname == GL_TEXTURE_GEN_MODE)
3054     LOG5 ("%sdirect %-12s %s %s %s", 
3055           (state->compiling_list || state->replaying_list ? "  " : ""),
3056           "glTexGenfv",
3057           mode_desc(coord), mode_desc(pname), mode_desc(params[0]));
3058   else
3059     LOG8 ("%sdirect %-12s %s %s %3.1f %3.1f %3.1f %3.1f",
3060           (state->compiling_list || state->replaying_list ? "  " : ""),
3061           "glTexGenfv",
3062           mode_desc(coord), mode_desc(pname),
3063           params[0], params[1], params[2], params[3]);
3064
3065   switch (coord) {
3066   case GL_S: s = &state->s; break;
3067   case GL_T: s = &state->t; break;
3068   case GL_R: s = &state->r; break;
3069   case GL_Q: s = &state->q; break;
3070   default: Assert (0, "glGetTexGenfv: unknown coord"); break;
3071   }
3072
3073   switch (pname) {
3074   case GL_TEXTURE_GEN_MODE: s->mode = params[0]; break;
3075   case GL_OBJECT_PLANE:     memcpy (s->obj, params, sizeof(s->obj)); break;
3076   case GL_EYE_PLANE:        memcpy (s->eye, params, sizeof(s->eye)); break;
3077   default: Assert (0, "glTexGenfv: unknown pname"); break;
3078   }
3079 }
3080
3081 void
3082 jwzgles_glTexGeni (GLenum coord, GLenum pname, GLint param)
3083 {
3084   GLfloat v = param;
3085   jwzgles_glTexGenfv (coord, pname, &v);
3086 }
3087
3088 void
3089 jwzgles_glGetTexGenfv (GLenum coord, GLenum pname, GLfloat *params)
3090 {
3091   texgen_state *s;
3092
3093   switch (coord) {
3094   case GL_S: s = &state->s; break;
3095   case GL_T: s = &state->t; break;
3096   case GL_R: s = &state->r; break;
3097   case GL_Q: s = &state->q; break;
3098   default: Assert (0, "glGetTexGenfv: unknown coord"); break;
3099   }
3100
3101   switch (pname) {
3102   case GL_TEXTURE_GEN_MODE: params[0] = s->mode; break;
3103   case GL_OBJECT_PLANE:     memcpy (params, s->obj, sizeof(s->obj)); break;
3104   case GL_EYE_PLANE:        memcpy (params, s->eye, sizeof(s->eye)); break;
3105   default: Assert (0, "glGetTexGenfv: unknown pname"); break;
3106   }
3107
3108   if (pname == GL_TEXTURE_GEN_MODE)
3109     LOG5 ("%sdirect %-12s %s %s -> %s", 
3110           (state->compiling_list || state->replaying_list ? "  " : ""),
3111           "glGetTexGenfv",
3112           mode_desc(coord), mode_desc(pname), mode_desc(params[0]));
3113   else
3114     LOG8 ("%sdirect %-12s %s %s -> %3.1f %3.1f %3.1f %3.1f",
3115           (state->compiling_list || state->replaying_list ? "  " : ""),
3116           "glGetTexGenfv",
3117           mode_desc(coord), mode_desc(pname),
3118           params[0], params[1], params[2], params[3]);
3119 }
3120
3121
3122 static GLfloat
3123 dot_product (int rank, GLfloat *a, GLfloat *b)
3124 {
3125   /* A dot B  =>  (A[1] * B[1]) + ... + (A[n] * B[n]) */
3126   GLfloat ret = 0;
3127   int i;
3128   for (i = 0; i < rank; i++) 
3129     ret += a[i] * b[i];
3130   return ret;
3131 }
3132
3133
3134
3135 /* Compute the texture coordinates of the prevailing list of verts as per
3136    http://www.opengl.org/wiki/Mathematics_of_glTexGen
3137  */
3138 static void
3139 generate_texture_coords (GLuint first, GLuint count)
3140 {
3141   GLfloat *tex_out, *tex_array;
3142   GLsizei tex_stride;
3143   GLuint i;
3144   draw_array A = { 0, };
3145   char *verts_in;
3146
3147   struct { GLuint which, flag, mode; GLfloat plane[4]; } tg[4] = {
3148     { GL_S, ISENABLED_TEXTURE_GEN_S, 0, { 0, } },
3149     { GL_T, ISENABLED_TEXTURE_GEN_T, 0, { 0, } },
3150     { GL_R, ISENABLED_TEXTURE_GEN_R, 0, { 0, } },
3151     { GL_Q, ISENABLED_TEXTURE_GEN_Q, 0, { 0, }}};
3152                                                     
3153   int tcoords = 0;
3154
3155   /* Read the texture plane configs that were stored with glTexGen.
3156    */
3157   for (i = 0; i < countof(tg); i++)
3158     {
3159       GLfloat mode = 0;
3160       if (! ((state->compiling_list ? state->list_enabled : state->enabled)
3161              & tg[i].flag))
3162         continue;
3163       jwzgles_glGetTexGenfv (tg[i].which, GL_TEXTURE_GEN_MODE, &mode);
3164       jwzgles_glGetTexGenfv (tg[i].which, GL_OBJECT_PLANE, tg[i].plane);
3165       tg[i].mode = mode;
3166       tcoords++;
3167     }
3168
3169   if (tcoords == 0) return;  /* Nothing to do! */
3170
3171
3172   /* Make the array to store our texture coords in. */
3173
3174   tex_stride = tcoords * sizeof(GLfloat);
3175   tex_array = (GLfloat *) calloc (first + count, tex_stride);
3176   tex_out = tex_array;
3177
3178
3179   /* Read the prevailing vertex array, that was stored with
3180      glVertexPointer or glInterleavedArrays.
3181    */
3182   glGetIntegerv (GL_VERTEX_ARRAY_BUFFER_BINDING, &A.binding);
3183   glGetIntegerv (GL_VERTEX_ARRAY_SIZE,    &A.size);
3184   glGetIntegerv (GL_VERTEX_ARRAY_TYPE,    &A.type);
3185   glGetIntegerv (GL_VERTEX_ARRAY_STRIDE,  &A.stride);
3186   glGetPointerv (GL_VERTEX_ARRAY_POINTER, &A.data);
3187   A.bytes = count * A.stride;
3188
3189   verts_in = (char *) A.data;
3190
3191   /* Iterate over each vertex we're drawing.
3192      We just skip the ones < start, but the tex array has
3193      left room for zeroes there anyway.
3194    */
3195   for (i = first; i < first + count; i++)
3196     {
3197       GLfloat vert[4] = { 0, };
3198       int j, k;
3199
3200       /* Extract this vertex into `vert' as a float, whatever its type was. */
3201       for (j = 0; j < A.size; j++)
3202         {
3203           switch (A.type) {
3204           case GL_SHORT:  vert[j] = ((GLshort *)  verts_in)[j]; break;
3205           case GL_INT:    vert[j] = ((GLint *)    verts_in)[j]; break;
3206           case GL_FLOAT:  vert[j] = ((GLfloat *)  verts_in)[j]; break;
3207           case GL_DOUBLE: vert[j] = ((GLdouble *) verts_in)[j]; break;
3208           default: Assert (0, "unknown vertex type"); break;
3209           }
3210         }
3211
3212       /* Compute the texture coordinate for this vertex.
3213          For GL_OBJECT_LINEAR, these coordinates are static, and can go
3214          into the display list.  But for GL_EYE_LINEAR, GL_SPHERE_MAP and
3215          GL_REFLECTION_MAP, they depend on the prevailing ModelView matrix,
3216          and so need to be computed afresh each time glDrawArrays is called.
3217          Unfortunately, our verts and norms are gone by then, dumped down
3218          into the VBO and discarded from CPU RAM.  Bleh.
3219        */
3220       for (j = 0, k = 0; j < countof(tg); j++)
3221         {
3222           if (! ((state->compiling_list ? state->list_enabled : state->enabled)
3223                  & tg[j].flag))
3224             continue;
3225           switch (tg[j].mode) {
3226           case GL_OBJECT_LINEAR:
3227             tex_out[k] = dot_product (4, vert, tg[j].plane);
3228             break;
3229           default:
3230             Assert (0, "unimplemented texture mode");
3231             break;
3232           }
3233           k++;
3234         }
3235
3236       /* fprintf (stderr, "%4d: V %-5.1f %-5.1f %-5.1f  T %-5.1f %-5.1f\n",
3237                i, vert[0], vert[1], vert[2], tex_out[0], tex_out[1]); */
3238
3239       /* Move verts_in and tex_out forward to the next vertex by stride. */
3240       verts_in += A.stride;
3241       tex_out = (GLfloat *) (((char *) tex_out) + tex_stride);
3242     }
3243
3244   jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
3245   jwzgles_glTexCoordPointer (tcoords, GL_FLOAT, tex_stride,
3246                              (GLvoid *) tex_array);
3247   free (tex_array);
3248 }
3249
3250
3251 int
3252 jwzgles_gluBuild2DMipmaps (GLenum target,
3253                            GLint        internalFormat,
3254                            GLsizei      width,
3255                            GLsizei      height,
3256                            GLenum       format,
3257                            GLenum       type,
3258                            const GLvoid *data)
3259 {
3260   /* Not really bothering with mipmapping; only making one level.
3261      Note that this required a corresponding hack in glTexParameterf().
3262    */
3263
3264   int w2 = to_pow2(width);
3265   int h2 = to_pow2(height);
3266
3267   void *d2 = (void *) data;
3268
3269   /* OpenGLES no longer supports "4" as a synonym for "RGBA". */
3270   switch (internalFormat) {
3271   case 1: internalFormat = GL_LUMINANCE; break;
3272   case 2: internalFormat = GL_LUMINANCE_ALPHA; break;
3273   case 3: internalFormat = GL_RGB; break;
3274   case 4: internalFormat = GL_RGBA; break;
3275   }
3276
3277 /*  if (w2 < h2) w2 = h2;
3278   if (h2 < w2) h2 = w2;*/
3279
3280   if (w2 != width || h2 != height)
3281     {
3282       /* Scale up the image bits to fit the power-of-2 texture.
3283          We have to do this because the mipmap API assumes that
3284          the texture bits go to texture coordinates 1.0 x 1.0.
3285          This could be more efficient, but it doesn't happen often.
3286       */
3287       int istride = (format == GL_RGBA ? 4 : 3);
3288       int ostride = 4;
3289       int ibpl = istride * width;
3290       int obpl = ostride * w2;
3291       int oy;
3292       const unsigned char *in = (unsigned char *) data;
3293       unsigned char *out = (void *) malloc (h2 * obpl);
3294       Assert (out, "out of memory");
3295       d2 = out;
3296
3297       for (oy = 0; oy < h2; oy++)
3298         {
3299           int iy = oy * height / h2;
3300           const unsigned char *iline = in  + (iy * ibpl);
3301           unsigned char       *oline = out + (oy * obpl);
3302           int ox;
3303           for (ox = 0; ox < w2; ox++)
3304             {
3305               int ix = ox * width / w2;
3306               const unsigned char *i = iline + (ix * istride);
3307               unsigned char       *o = oline + (ox * ostride);
3308               *o++ = *i++;  /* R */
3309               *o++ = *i++;  /* G */
3310               *o++ = *i++;  /* B */
3311               *o++ = (istride == 4 ? *i : 0xFF); /* A */
3312             }
3313         }
3314       width  = w2;
3315       height = h2;
3316       internalFormat = GL_RGBA;
3317       format = GL_RGBA;
3318     }
3319
3320   jwzgles_glTexImage2D (target, 0, internalFormat, w2, h2, 0, 
3321                         format, type, d2);
3322   if (d2 != data) free (d2);
3323
3324   return 0;
3325 }
3326
3327
3328 void
3329 jwzgles_glRectf (GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
3330 {
3331   jwzgles_glBegin (GL_POLYGON);
3332   jwzgles_glVertex2f (x1, y1);
3333   jwzgles_glVertex2f (x2, y1);
3334   jwzgles_glVertex2f (x2, y2);
3335   jwzgles_glVertex2f (x1, y2);
3336   jwzgles_glEnd ();
3337 }
3338
3339 void
3340 jwzgles_glRecti (GLint x1, GLint y1, GLint x2, GLint y2)
3341 {
3342   jwzgles_glRectf (x1, y1, x2, y2);
3343 }
3344
3345 void
3346 jwzgles_glClearDepth (GLfloat d)
3347 {
3348   /* Not sure what to do here */
3349   Assert (d == 1.0, "glClearDepth unimplemented");
3350 }
3351
3352
3353 /* When in immediate mode, we store a bit into state->enabled, and also
3354    call the real glEnable() / glDisable().
3355
3356    When recording a list, we store a bit into state->list_enabled instead,
3357    so that we can see what the prevailing enablement state will be when
3358    the list is run.
3359
3360    set: 1 = set, -1 = clear, 0 = query.
3361 */
3362 static int
3363 enable_disable (GLuint bit, int set)
3364 {
3365   int result = (set > 0);
3366   int omitp = 0;
3367   int csp = 0;
3368   unsigned long flag = 0;
3369
3370   switch (bit) {
3371   case GL_TEXTURE_1D:     /* We implement 1D textures as 2D textures. */
3372   case GL_TEXTURE_2D:     flag = ISENABLED_TEXTURE_2D;               break;
3373   case GL_TEXTURE_GEN_S:  flag = ISENABLED_TEXTURE_GEN_S; omitp = 1; break;
3374   case GL_TEXTURE_GEN_T:  flag = ISENABLED_TEXTURE_GEN_T; omitp = 1; break;
3375   case GL_TEXTURE_GEN_R:  flag = ISENABLED_TEXTURE_GEN_R; omitp = 1; break;
3376   case GL_TEXTURE_GEN_Q:  flag = ISENABLED_TEXTURE_GEN_Q; omitp = 1; break;
3377   case GL_LIGHTING:       flag = ISENABLED_LIGHTING;                 break;
3378   case GL_BLEND:          flag = ISENABLED_BLEND;                    break;
3379   case GL_DEPTH_TEST:     flag = ISENABLED_DEPTH_TEST;               break;
3380   case GL_ALPHA_TEST:     flag = ISENABLED_ALPHA_TEST;               break;
3381   case GL_CULL_FACE:      flag = ISENABLED_CULL_FACE;                break;
3382   case GL_NORMALIZE:      flag = ISENABLED_NORMALIZE;                break;
3383   case GL_FOG:            flag = ISENABLED_FOG;                      break;
3384   case GL_COLOR_MATERIAL: flag = ISENABLED_COLMAT;                   break;
3385
3386   /* Maybe technically these only work with glEnableClientState,
3387      but we treat that as synonymous with glEnable. */
3388   case GL_VERTEX_ARRAY:   flag = ISENABLED_VERT_ARRAY;     csp = 1;  break;
3389   case GL_NORMAL_ARRAY:   flag = ISENABLED_NORM_ARRAY;     csp = 1;  break;
3390   case GL_COLOR_ARRAY:    flag = ISENABLED_COLOR_ARRAY;    csp = 1;  break;
3391   case GL_TEXTURE_COORD_ARRAY: flag = ISENABLED_TEX_ARRAY; csp = 1;  break;
3392
3393   default:
3394     Assert (set != 0, "glIsEnabled unimplemented bit");
3395     break;
3396   }
3397
3398   if (set)  /* setting or unsetting, not querying */
3399     {
3400       const char *fns[4] = { "glEnable", "glDisable",
3401                              "glEnableClientState", "glDisableClientState" };
3402       list_fn_cb fs[4] = { (list_fn_cb) &jwzgles_glEnable,
3403                            (list_fn_cb) &jwzgles_glDisable,
3404                            (list_fn_cb) &jwzgles_glEnableClientState,
3405                            (list_fn_cb) &jwzgles_glDisableClientState };
3406       const char *fn = fns[(csp ? 2 : 0) + (set < 0 ? 1 : 0)];
3407       list_fn_cb  f  =  fs[(csp ? 2 : 0) + (set < 0 ? 1 : 0)];
3408
3409       Assert (!state->compiling_verts,
3410               "glEnable/glDisable not allowed inside glBegin");
3411
3412       if (state->compiling_list)
3413         {
3414           void_int vv[1];
3415           vv[0].i = bit;
3416           list_push (fn, f,PROTO_I, vv);
3417         }
3418
3419       if (! state->replaying_list &&
3420           ! state->compiling_list)
3421         LOG2 ("direct %-12s %s", fn, mode_desc(bit));
3422
3423       if (csp && !state->compiling_verts)
3424         {
3425           if (set > 0)
3426             switch (bit) {
3427             case GL_NORMAL_ARRAY: state->set.ncount        += 2; break;
3428             case GL_TEXTURE_COORD_ARRAY: state->set.tcount += 2; break;
3429             case GL_COLOR_ARRAY: state->set.ccount         += 2; break;
3430             default: break;
3431             }
3432           else
3433             switch (bit) {
3434             case GL_NORMAL_ARRAY: state->set.ncount        = 0; break;
3435             case GL_TEXTURE_COORD_ARRAY: state->set.tcount = 0; break;
3436             case GL_COLOR_ARRAY: state->set.ccount         = 0; break;
3437             default: break;
3438             }
3439         }
3440
3441       if (omitp || state->compiling_list)
3442         ;
3443       else if (set > 0 && csp)
3444         glEnableClientState (bit);      /* the real one */
3445       else if (set < 0 && csp)
3446         glDisableClientState (bit);     /* the real one */
3447       else if (set > 0)
3448         glEnable (bit);                 /* the real one */
3449       else
3450         glDisable (bit);                /* the real one */
3451
3452       CHECK(fn);
3453     }
3454
3455   /* Store the bit in our state as well, or query it.
3456    */
3457   if (flag)
3458     {
3459       unsigned long *enabled = (state->compiling_list
3460                                 ? &state->list_enabled
3461                                 : &state->enabled);
3462       if (set > 0)
3463         *enabled |= flag;
3464       else if (set < 0)
3465         *enabled &= ~flag;
3466       else
3467         result = !!(*enabled & flag);
3468     }
3469
3470   return result;
3471 }
3472
3473
3474 void
3475 jwzgles_glEnable (GLuint bit)
3476 {
3477   enable_disable (bit, 1);
3478 }
3479
3480 void
3481 jwzgles_glDisable (GLuint bit)
3482 {
3483   enable_disable (bit, -1);
3484 }
3485
3486 GLboolean
3487 jwzgles_glIsEnabled (GLuint bit)
3488 {
3489   return enable_disable (bit, 0);
3490 }
3491
3492 void
3493 jwzgles_glEnableClientState (GLuint cap)
3494 {
3495   enable_disable (cap, 1);
3496 }
3497
3498 void
3499 jwzgles_glDisableClientState (GLuint cap)
3500 {
3501   enable_disable (cap, -1);
3502 }
3503
3504
3505
3506 /* The spec says that OpenGLES 1.x doesn't implement glGetFloatv.
3507    Were this true, it would suck, for it would mean that there was no
3508    way to retrieve the prevailing matrixes.  To implement this, we'd
3509    have to keep track of them all on the client side by combining in
3510    all the actions of glMultMatrixf, glRotatef, etc.
3511
3512    However, Apple's iOS OpenGLES *does* provide glGetFloatv!
3513  */
3514 void
3515 jwzgles_glGetFloatv (GLenum pname, GLfloat *params)
3516 {
3517   if (! state->replaying_list)
3518     LOG2 ("direct %-12s %s", "glGetFloatv", mode_desc(pname));
3519   glGetFloatv (pname, params);  /* the real one */
3520   CHECK("glGetFloatv");
3521 }
3522
3523
3524 /* Likewise: not supposed to be there, but it is. */
3525 void
3526 jwzgles_glGetPointerv (GLenum pname, GLvoid *params)
3527 {
3528   if (! state->replaying_list)
3529     LOG2 ("direct %-12s %s", "glGetPointerv", mode_desc(pname));
3530   glGetPointerv (pname, params);  /* the real one */
3531   CHECK("glGetPointerv");
3532 }
3533
3534
3535 /* How many cells are written into the *params array.
3536    We need to know this to avoid smashing the caller's stack
3537    if they asked for a single-value parameter.
3538  */
3539 static int
3540 glGet_ret_count (GLenum pname)
3541 {
3542   switch (pname) {
3543 /*case GL_COLOR_MATRIX: */
3544   case GL_MODELVIEW_MATRIX:
3545   case GL_PROJECTION_MATRIX:
3546   case GL_TEXTURE_MATRIX:
3547 /*case GL_TRANSPOSE_COLOR_MATRIX: */
3548 /*case GL_TRANSPOSE_MODELVIEW_MATRIX: */
3549 /*case GL_TRANSPOSE_PROJECTION_MATRIX: */
3550 /*case GL_TRANSPOSE_TEXTURE_MATRIX: */
3551     return 16;
3552 /*case GL_ACCUM_CLEAR_VALUE: */
3553 /*case GL_BLEND_COLOR: */
3554   case GL_COLOR_CLEAR_VALUE:
3555   case GL_COLOR_WRITEMASK:
3556   case GL_CURRENT_COLOR:
3557 /*case GL_CURRENT_RASTER_COLOR: */
3558 /*case GL_CURRENT_RASTER_POSITION: */
3559 /*case GL_CURRENT_RASTER_SECONDARY_COLOR: */
3560 /*case GL_CURRENT_RASTER_TEXTURE_COORDS: */
3561 /*case GL_CURRENT_SECONDARY_COLOR: */
3562   case GL_CURRENT_TEXTURE_COORDS:
3563   case GL_FOG_COLOR:
3564   case GL_LIGHT_MODEL_AMBIENT:
3565 /*case GL_MAP2_GRID_DOMAIN: */
3566   case GL_SCISSOR_BOX:
3567   case GL_VIEWPORT:
3568     return 4;
3569   case GL_CURRENT_NORMAL:
3570   case GL_POINT_DISTANCE_ATTENUATION:
3571     return 3;
3572   case GL_ALIASED_LINE_WIDTH_RANGE:
3573   case GL_ALIASED_POINT_SIZE_RANGE:
3574   case GL_DEPTH_RANGE:
3575 /*case GL_LINE_WIDTH_RANGE: */
3576 /*case GL_MAP1_GRID_DOMAIN: */
3577 /*case GL_MAP2_GRID_SEGMENTS: */
3578   case GL_MAX_VIEWPORT_DIMS:
3579 /*case GL_POINT_SIZE_RANGE: */
3580   case GL_POLYGON_MODE:
3581   case GL_SMOOTH_LINE_WIDTH_RANGE:
3582   case GL_SMOOTH_POINT_SIZE_RANGE:
3583     return 2;
3584   default:
3585     return 1;
3586   }
3587 }
3588
3589
3590 void
3591 jwzgles_glGetDoublev (GLenum pname, GLdouble *params)
3592 {
3593   GLfloat m[16];
3594   int i, j = glGet_ret_count (pname);
3595   jwzgles_glGetFloatv (pname, m);
3596   for (i = 0; i < j; i++)
3597     params[i] = m[i];
3598 }
3599
3600
3601 void
3602 jwzgles_glGetIntegerv (GLenum pname, GLint *params)
3603 {
3604   GLfloat m[16];
3605   int i, j = glGet_ret_count (pname);
3606   jwzgles_glGetFloatv (pname, m);
3607   for (i = 0; i < j; i++)
3608     params[i] = m[i];
3609 }
3610
3611
3612 void
3613 jwzgles_glGetBooleanv (GLenum pname, GLboolean *params)
3614 {
3615   GLfloat m[16];
3616   int i, j = glGet_ret_count (pname);
3617   jwzgles_glGetFloatv (pname, m);
3618   for (i = 0; i < j; i++)
3619     params[i] = (m[i] != 0.0);
3620 }
3621
3622
3623 const char *
3624 jwzgles_gluErrorString (GLenum error)
3625 {
3626   static char s[20];
3627   sprintf (s, "0x%lX", (unsigned long) error);
3628   return s;
3629 }
3630
3631
3632 /* These four *Pointer calls (plus glBindBuffer and glBufferData) can
3633    be included inside glNewList, but they actually execute immediately
3634    anyway, because their data is recorded in the list by the
3635    subsequently-recorded call to glDrawArrays.  This is a little weird.
3636  */
3637 void
3638 jwzgles_glVertexPointer (GLuint size, GLuint type, GLuint stride, 
3639                          const GLvoid *ptr)
3640 {
3641   if (! state->replaying_list)
3642     LOG5 ("direct %-12s %d %s %d 0x%lX", "glVertexPointer", 
3643           size, mode_desc(type), stride, (unsigned long) ptr);
3644   glVertexPointer (size, type, stride, ptr);  /* the real one */
3645   CHECK("glVertexPointer");
3646 }
3647
3648
3649 void
3650 jwzgles_glNormalPointer (GLuint type, GLuint stride, const GLvoid *ptr)
3651 {
3652   if (! state->replaying_list)
3653     LOG4 ("direct %-12s %s %d 0x%lX", "glNormalPointer", 
3654           mode_desc(type), stride, (unsigned long) ptr);
3655   glNormalPointer (type, stride, ptr);  /* the real one */
3656   CHECK("glNormalPointer");
3657 }
3658
3659 void
3660 jwzgles_glColorPointer (GLuint size, GLuint type, GLuint stride, 
3661                         const GLvoid *ptr)
3662 {
3663   if (! state->replaying_list)
3664     LOG5 ("direct %-12s %d %s %d 0x%lX", "glColorPointer", 
3665           size, mode_desc(type), stride, (unsigned long) ptr);
3666   glColorPointer (size, type, stride, ptr);  /* the real one */
3667   CHECK("glColorPointer");
3668 }
3669
3670 void
3671 jwzgles_glTexCoordPointer (GLuint size, GLuint type, GLuint stride, 
3672                            const GLvoid *ptr)
3673 {
3674   if (! state->replaying_list)
3675     LOG5 ("direct %-12s %d %s %d 0x%lX", "glTexCoordPointer", 
3676           size, mode_desc(type), stride, (unsigned long) ptr);
3677   glTexCoordPointer (size, type, stride, ptr);  /* the real one */
3678   CHECK("glTexCoordPointer");
3679 }
3680
3681 void
3682 jwzgles_glBindBuffer (GLuint target, GLuint buffer)
3683 {
3684   if (! state->replaying_list)
3685     LOG3 ("direct %-12s %s %d", "glBindBuffer", mode_desc(target), buffer);
3686   glBindBuffer (target, buffer);  /* the real one */
3687   CHECK("glBindBuffer");
3688 }
3689
3690 void
3691 jwzgles_glBufferData (GLenum target, GLsizeiptr size, const void *data,
3692                       GLenum usage)
3693 {
3694   if (! state->replaying_list)
3695     LOG5 ("direct %-12s %s %ld 0x%lX %s", "glBufferData",
3696           mode_desc(target), size, (unsigned long) data, mode_desc(usage));
3697   glBufferData (target, size, data, usage);  /* the real one */
3698   CHECK("glBufferData");
3699 }
3700
3701
3702 void
3703 jwzgles_glTexParameterf (GLuint target, GLuint pname, GLfloat param)
3704 {
3705   Assert (!state->compiling_verts,
3706           "glTexParameterf not allowed inside glBegin");
3707
3708   /* We don't *really* implement mipmaps, so just turn this off. */
3709   if (param == GL_LINEAR_MIPMAP_LINEAR)   param = GL_LINEAR;
3710   if (param == GL_NEAREST_MIPMAP_LINEAR)  param = GL_LINEAR;
3711   if (param == GL_LINEAR_MIPMAP_NEAREST)  param = GL_NEAREST;
3712   if (param == GL_NEAREST_MIPMAP_NEAREST) param = GL_NEAREST;
3713
3714   /* We implement 1D textures as 2D textures. */
3715   if (target == GL_TEXTURE_1D) target = GL_TEXTURE_2D;
3716
3717   /* Apparently this is another invalid enum. Just ignore it. */
3718   if ((pname == GL_TEXTURE_WRAP_S || pname == GL_TEXTURE_WRAP_T) &&
3719       param == GL_CLAMP)
3720     return;
3721
3722   if (state->compiling_list)
3723     {
3724       void_int vv[3];
3725       vv[0].i = target;
3726       vv[1].i = pname;
3727       vv[2].f = param;
3728       list_push ("glTexParameterf", (list_fn_cb) &jwzgles_glTexParameterf,
3729                  PROTO_IIF, vv);
3730     }
3731   else
3732     {
3733       if (! state->replaying_list)
3734         LOG4 ("direct %-12s %s %s %7.3f", "glTexParameterf", 
3735               mode_desc(target), mode_desc(pname), param);
3736       glTexParameterf (target, pname, param);  /* the real one */
3737       CHECK("glTexParameterf");
3738     }
3739 }
3740
3741 void
3742 jwzgles_glTexParameteri (GLuint target, GLuint pname, GLuint param)
3743 {
3744   jwzgles_glTexParameterf (target, pname, param);
3745 }
3746
3747
3748 void
3749 jwzgles_glBindTexture (GLuint target, GLuint texture)
3750 {
3751   Assert (!state->compiling_verts,
3752           "glBindTexture not allowed inside glBegin");
3753
3754   /* We implement 1D textures as 2D textures. */
3755   if (target == GL_TEXTURE_1D) target = GL_TEXTURE_2D;
3756
3757   if (state->compiling_list)
3758     {
3759       void_int vv[2];
3760       vv[0].i = target;
3761       vv[1].i = texture;
3762       list_push ("glBindTexture", (list_fn_cb) &jwzgles_glBindTexture,
3763                  PROTO_II, vv);
3764     }
3765
3766   /* Do it immediately as well, for generate_texture_coords */
3767   /* else */
3768     {
3769       if (! state->replaying_list)
3770         LOG3 ("direct %-12s %s %d", "glBindTexture", 
3771               mode_desc(target), texture);
3772       glBindTexture (target, texture);  /* the real one */
3773       CHECK("glBindTexture");
3774     }
3775 }
3776
3777
3778
3779 /* Matrix functions, mostly cribbed from Mesa.
3780  */
3781
3782 void
3783 jwzgles_glFrustum (GLfloat left,   GLfloat right,
3784                    GLfloat bottom, GLfloat top,
3785                    GLfloat near,   GLfloat far)
3786 {
3787   GLfloat m[16];
3788   GLfloat x = (2 * near)        / (right-left);
3789   GLfloat y = (2 * near)        / (top - bottom);
3790   GLfloat a = (right + left)    / (right - left);
3791   GLfloat b = (top + bottom)    / (top - bottom);
3792   GLfloat c = -(far + near)     / (far - near);
3793   GLfloat d = -(2 * far * near) / (far - near);
3794
3795 # define M(X,Y)  m[Y * 4 + X]
3796   M(0,0) = x; M(0,1) = 0; M(0,2) =  a; M(0,3) = 0;
3797   M(1,0) = 0; M(1,1) = y; M(1,2) =  b; M(1,3) = 0;
3798   M(2,0) = 0; M(2,1) = 0; M(2,2) =  c; M(2,3) = d;
3799   M(3,0) = 0; M(3,1) = 0; M(3,2) = -1; M(3,3) = 0;
3800 # undef M
3801
3802   jwzgles_glMultMatrixf (m);
3803 }
3804
3805
3806 void
3807 jwzgles_glOrtho (GLfloat left,   GLfloat right,
3808                  GLfloat bottom, GLfloat top,
3809                  GLfloat near,   GLfloat far)
3810 {
3811   GLfloat m[16];
3812   GLfloat a = 2 / (right - left);
3813   GLfloat b = -(right + left) / (right - left);
3814   GLfloat c = 2 / (top - bottom);
3815   GLfloat d = -(top + bottom) / (top - bottom);
3816   GLfloat e = -2 / (far - near);
3817   GLfloat f = -(far + near) / (far - near);
3818
3819 # define M(X,Y)  m[Y * 4 + X]
3820   M(0,0) = a; M(0,1) = 0; M(0,2) = 0; M(0,3) = b;
3821   M(1,0) = 0; M(1,1) = c; M(1,2) = 0; M(1,3) = d;
3822   M(2,0) = 0; M(2,1) = 0; M(2,2) = e; M(2,3) = f;
3823   M(3,0) = 0; M(3,1) = 0; M(3,2) = 0; M(3,3) = 1;
3824 # undef M
3825
3826   jwzgles_glMultMatrixf (m);
3827 }
3828
3829
3830 void
3831 jwzgles_gluPerspective (GLdouble fovy, GLdouble aspect, 
3832                         GLdouble near, GLdouble far)
3833 {
3834   GLfloat m[16];
3835   double si, co, dz;
3836   double rad = fovy / 2 * M_PI / 180;
3837   double a, b, c, d;
3838
3839   dz = far - near;
3840   si = sin(rad);
3841   if (dz == 0 || si == 0 || aspect == 0)
3842     return;
3843   co = cos(rad) / si;
3844
3845   a = co / aspect;
3846   b = co;
3847   c = -(far + near) / dz;
3848   d = -2 * near * far / dz;
3849
3850 # define M(X,Y)  m[Y * 4 + X]
3851   M(0,0) = a; M(0,1) = 0; M(0,2) = 0;  M(0,3) = 0;
3852   M(1,0) = 0; M(1,1) = b; M(1,2) = 0;  M(1,3) = 0;
3853   M(2,0) = 0; M(2,1) = 0; M(2,2) = c;  M(2,3) = d;
3854   M(3,0) = 0; M(3,1) = 0; M(3,2) = -1; M(3,3) = 0;
3855 # undef M
3856
3857   jwzgles_glMultMatrixf (m);
3858 }
3859
3860
3861 void
3862 jwzgles_gluLookAt (GLfloat eyex, GLfloat eyey, GLfloat eyez,
3863                    GLfloat centerx, GLfloat centery, GLfloat centerz,
3864                    GLfloat upx, GLfloat upy, GLfloat upz)
3865 {
3866   GLfloat m[16];
3867   GLfloat x[3], y[3], z[3];
3868   GLfloat mag;
3869     
3870   /* Make rotation matrix */
3871     
3872   /* Z vector */
3873   z[0] = eyex - centerx;
3874   z[1] = eyey - centery;
3875   z[2] = eyez - centerz;
3876   mag = sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]);
3877   if (mag) {          /* mpichler, 19950515 */
3878     z[0] /= mag;
3879     z[1] /= mag;
3880     z[2] /= mag;
3881   }
3882     
3883   /* Y vector */
3884   y[0] = upx;
3885   y[1] = upy;
3886   y[2] = upz;
3887     
3888   /* X vector = Y cross Z */
3889   x[0] = y[1] * z[2] - y[2] * z[1];
3890   x[1] = -y[0] * z[2] + y[2] * z[0];
3891   x[2] = y[0] * z[1] - y[1] * z[0];
3892     
3893   /* Recompute Y = Z cross X */
3894   y[0] = z[1] * x[2] - z[2] * x[1];
3895   y[1] = -z[0] * x[2] + z[2] * x[0];
3896   y[2] = z[0] * x[1] - z[1] * x[0];
3897     
3898   /* mpichler, 19950515 */
3899   /* cross product gives area of parallelogram, which is < 1.0 for
3900    * non-perpendicular unit-length vectors; so normalize x, y here
3901    */
3902     
3903   mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
3904   if (mag) {
3905     x[0] /= mag;
3906     x[1] /= mag;
3907     x[2] /= mag;
3908   }
3909     
3910   mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
3911   if (mag) {
3912     y[0] /= mag;
3913     y[1] /= mag;
3914     y[2] /= mag;
3915   }
3916     
3917 #define M(row,col)  m[col*4+row]
3918   M(0, 0) = x[0]; M(0, 1) = x[1]; M(0, 2) = x[2]; M(0, 3) = 0.0;
3919   M(1, 0) = y[0]; M(1, 1) = y[1]; M(1, 2) = y[2]; M(1, 3) = 0.0;
3920   M(2, 0) = z[0]; M(2, 1) = z[1]; M(2, 2) = z[2]; M(2, 3) = 0.0;
3921   M(3, 0) = 0.0;  M(3, 1) = 0.0;  M(3, 2) = 0.0;  M(3, 3) = 1.0;
3922 #undef M
3923
3924   jwzgles_glMultMatrixf(m);
3925     
3926   /* Translate Eye to Origin */
3927   jwzgles_glTranslatef(-eyex, -eyey, -eyez);
3928 }
3929
3930
3931 static void __gluMultMatrixVecd (const GLdouble matrix[16],
3932                                  const GLdouble in[4],
3933                                  GLdouble out[4])
3934 {
3935   int i;
3936
3937   for (i=0; i<4; i++) {
3938     out[i] = 
3939       in[0] * matrix[0*4+i] +
3940       in[1] * matrix[1*4+i] +
3941       in[2] * matrix[2*4+i] +
3942       in[3] * matrix[3*4+i];
3943   }
3944 }
3945
3946 GLint
3947 jwzgles_gluProject (GLdouble objx, GLdouble objy, GLdouble objz, 
3948                     const GLdouble modelMatrix[16], 
3949                     const GLdouble projMatrix[16],
3950                     const GLint viewport[4],
3951                     GLdouble *winx, GLdouble *winy, GLdouble *winz)
3952 {
3953   GLdouble in[4];
3954   GLdouble out[4];
3955
3956   /* #### I suspect this is not working right.  I was seeing crazy values
3957      in lament.c.  Maybe there's some float-vs-double confusion going on?
3958    */
3959
3960   in[0]=objx;
3961   in[1]=objy;
3962   in[2]=objz;
3963   in[3]=1.0;
3964   __gluMultMatrixVecd(modelMatrix, in, out);
3965   __gluMultMatrixVecd(projMatrix, out, in);
3966   if (in[3] == 0.0) return(GL_FALSE);
3967   in[0] /= in[3];
3968   in[1] /= in[3];
3969   in[2] /= in[3];
3970   /* Map x, y and z to range 0-1 */
3971   in[0] = in[0] * 0.5 + 0.5;
3972   in[1] = in[1] * 0.5 + 0.5;
3973   in[2] = in[2] * 0.5 + 0.5;
3974
3975   /* Map x,y to viewport */
3976   in[0] = in[0] * viewport[2] + viewport[0];
3977   in[1] = in[1] * viewport[3] + viewport[1];
3978
3979   *winx=in[0];
3980   *winy=in[1];
3981   *winz=in[2];
3982   return(GL_TRUE);
3983 }
3984
3985
3986 void jwzgles_glViewport (GLuint x, GLuint y, GLuint w, GLuint h)
3987 {
3988 # if TARGET_IPHONE_SIMULATOR
3989 /*  fprintf (stderr, "glViewport %dx%d\n", w, h); */
3990 # endif
3991   glViewport (x, y, w, h);  /* the real one */
3992 }
3993
3994
3995 /* The following functions are present in both OpenGL 1.1 and in OpenGLES 1,
3996    but are allowed within glNewList/glEndList, so we must wrap them to allow
3997    them to either be recorded in lists, or run directly.
3998
3999    All this CPP obscenity is me screaming in rage at all the ways that C is
4000    not Lisp, as all I want to do here is DEFADVICE.
4001  */
4002
4003 #define PROTO_V   PROTO_VOID
4004 #define TYPE_V    GLuint
4005 #define ARGS_V    void
4006 #define VARS_V    /* */
4007 #define LOGS_V    "\n"
4008 #define FILL_V    /* */
4009
4010 #define TYPE_I    GLuint
4011 #define TYPE_II   TYPE_I
4012 #define TYPE_III  TYPE_I
4013 #define TYPE_IIII TYPE_I
4014 #define ARGS_I    TYPE_I a
4015 #define ARGS_II   TYPE_I a, TYPE_I b
4016 #define ARGS_III  TYPE_I a, TYPE_I b, TYPE_I c
4017 #define ARGS_IIII TYPE_I a, TYPE_I b, TYPE_I c, TYPE_I d
4018 #define LOGS_I    "%s\n", mode_desc(a)
4019 #define LOGS_II   "%s %d\n", mode_desc(a), b
4020 #define LOGS_III  "%s %s %s\n", mode_desc(a), mode_desc(b), mode_desc(c)
4021 #define LOGS_IIII "%d %d %d %d\n", a, b, c, d
4022 #define VARS_I    a
4023 #define VARS_II   a, b
4024 #define VARS_III  a, b, c
4025 #define VARS_IIII a, b, c, d
4026 #define FILL_I    vv[0].i = a;
4027 #define FILL_II   vv[0].i = a; vv[1].i = b;
4028 #define FILL_III  vv[0].i = a; vv[1].i = b; vv[2].i = c;
4029 #define FILL_IIII vv[0].i = a; vv[1].i = b; vv[2].i = c; vv[3].i = d;
4030
4031 #define TYPE_F    GLfloat
4032 #define TYPE_FF   TYPE_F
4033 #define TYPE_FFF  TYPE_F
4034 #define TYPE_FFFF TYPE_F
4035 #define ARGS_F    TYPE_F a
4036 #define ARGS_FF   TYPE_F a, TYPE_F b
4037 #define ARGS_FFF  TYPE_F a, TYPE_F b, TYPE_F c
4038 #define ARGS_FFFF TYPE_F a, TYPE_F b, TYPE_F c, TYPE_F d
4039 #define LOGS_F    "%7.3f\n", a
4040 #define LOGS_FF   "%7.3f %7.3f\n", a, b
4041 #define LOGS_FFF  "%7.3f %7.3f %7.3f\n", a, b, c
4042 #define LOGS_FFFF "%7.3f %7.3f %7.3f %7.3f\n", a, b, c, d
4043 #define VARS_F    VARS_I
4044 #define VARS_FF   VARS_II
4045 #define VARS_FFF  VARS_III
4046 #define VARS_FFFF VARS_IIII
4047 #define FILL_F    vv[0].f = a;
4048 #define FILL_FF   vv[0].f = a; vv[1].f = b;
4049 #define FILL_FFF  vv[0].f = a; vv[1].f = b; vv[2].f = c;
4050 #define FILL_FFFF vv[0].f = a; vv[1].f = b; vv[2].f = c; vv[3].f = d;
4051
4052 #define ARGS_IF   TYPE_I a, TYPE_F b
4053 #define VARS_IF   VARS_II
4054 #define LOGS_IF   "%s %7.3f\n", mode_desc(a), b
4055 #define FILL_IF   vv[0].i = a; vv[1].f = b;
4056
4057 #define ARGS_IIF  TYPE_I a, TYPE_I b, TYPE_F c
4058 #define VARS_IIF  VARS_III
4059 #define LOGS_IIF  "%s %s %7.3f\n", mode_desc(a), mode_desc(b), c
4060 #define FILL_IIF  vv[0].i = a; vv[1].i = b; vv[2].f = c;
4061
4062 #define TYPE_IV   GLint
4063 #define ARGS_IIV  TYPE_I a, const TYPE_IV *b
4064 #define VARS_IIV  VARS_II
4065 #define LOGS_IIV  "%s %d %d %d %d\n", mode_desc(a), b[0], b[1], b[2], b[3]
4066 #define FILL_IIV  vv[0].i = a; \
4067                   vv[1].i = b[0]; vv[2].i = b[1]; \
4068                   vv[3].i = b[2]; vv[4].i = b[3];
4069
4070 #define ARGS_IFV  TYPE_I a, const TYPE_F *b
4071 #define VARS_IFV  VARS_II
4072 #define LOGS_IFV  "%s %7.3f %7.3f %7.3f %7.3f\n", mode_desc(a), \
4073                   b[0], b[1], b[2], b[3]
4074 #define FILL_IFV  vv[0].i = a; \
4075                   vv[1].f = b[0]; vv[2].f = b[1]; \
4076                   vv[3].f = b[2]; vv[4].f = b[3];
4077
4078 #define ARGS_IIIV TYPE_I a, TYPE_I b, const TYPE_IV *c
4079 #define VARS_IIIV VARS_III
4080 #define LOGS_IIIV "%s %-8s %3d %3d %3d %3d\n", mode_desc(a), mode_desc(b), \
4081                   c[0], c[1], c[2], c[3]
4082 #define FILL_IIIV vv[0].i = a; vv[1].i = b; \
4083                   vv[2].i = c[0]; vv[3].i = c[1]; \
4084                   vv[4].i = c[2]; vv[5].i = c[3];
4085
4086 #define ARGS_IIFV TYPE_I a, TYPE_I b, const TYPE_F *c
4087 #define VARS_IIFV VARS_III
4088 #define LOGS_IIFV "%s %-8s %7.3f %7.3f %7.3f %7.3f\n", \
4089                   mode_desc(a), mode_desc(b), \
4090                   c[0], c[1], c[2], c[3]
4091 #define FILL_IIFV vv[0].i = a; vv[1].i = b; \
4092                   vv[2].f = c[0]; vv[3].f = c[1]; \
4093                   vv[4].f = c[2]; vv[5].f = c[3];
4094
4095 #ifdef DEBUG
4096 # define WLOG(NAME,ARGS) \
4097   fprintf (stderr, "jwzgles: direct %-12s ", NAME); \
4098   fprintf (stderr, ARGS)
4099 #else
4100 # define WLOG(NAME,ARGS) /* */
4101 #endif
4102
4103 #define WRAP(NAME,SIG) \
4104 void jwzgles_##NAME (ARGS_##SIG)                                        \
4105 {                                                                       \
4106   Assert (!state->compiling_verts,                                      \
4107           STRINGIFY(NAME) " not allowed inside glBegin");               \
4108   if (state->compiling_list) {                                          \
4109     void_int vv[10];                                                    \
4110     FILL_##SIG                                                          \
4111     list_push (STRINGIFY(NAME), (list_fn_cb) &jwzgles_##NAME,           \
4112                PROTO_##SIG, vv);                                        \
4113   } else {                                                              \
4114     if (! state->replaying_list) {                                      \
4115       WLOG (STRINGIFY(NAME), LOGS_##SIG);                               \
4116     }                                                                   \
4117     NAME (VARS_##SIG);                                                  \
4118     CHECK(STRINGIFY(NAME));                                             \
4119   }                                                                     \
4120 }
4121
4122 WRAP (glActiveTexture,  I)
4123 WRAP (glAlphaFunc,      IF)
4124 WRAP (glBlendFunc,      II)
4125 WRAP (glClear,          I)
4126 WRAP (glClearColor,     FFFF)
4127 WRAP (glClearStencil,   I)
4128 WRAP (glColorMask,      IIII)
4129 WRAP (glCullFace,       I)
4130 WRAP (glDepthFunc,      I)
4131 WRAP (glDepthMask,      I)
4132 WRAP (glFinish,         V)
4133 WRAP (glFlush,          V)
4134 WRAP (glFogf,           IF)
4135 WRAP (glFogfv,          IFV)
4136 WRAP (glFrontFace,      I)
4137 WRAP (glHint,           II)
4138 WRAP (glLightModelf,    IF)
4139 WRAP (glLightModelfv,   IFV)
4140 WRAP (glLightf,         IIF)
4141 WRAP (glLightfv,        IIFV)
4142 WRAP (glLineWidth,      F)
4143 WRAP (glLoadIdentity,   V)
4144 WRAP (glLogicOp,        I)
4145 WRAP (glMatrixMode,     I)
4146 WRAP (glPixelStorei,    II)
4147 WRAP (glPointSize,      F)
4148 WRAP (glPolygonOffset,  FF)
4149 WRAP (glPopMatrix,      V)
4150 WRAP (glPushMatrix,     V)
4151 WRAP (glRotatef,        FFFF)
4152 WRAP (glScalef,         FFF)
4153 WRAP (glScissor,        IIII)
4154 WRAP (glShadeModel,     I)
4155 WRAP (glStencilFunc,    III)
4156 WRAP (glStencilMask,    I)
4157 WRAP (glStencilOp,      III)
4158 WRAP (glTexEnvf,        IIF)
4159 WRAP (glTexEnvi,        III)
4160 WRAP (glTranslatef,     FFF)
4161 #undef  TYPE_IV
4162 #define TYPE_IV GLuint
4163 WRAP (glDeleteTextures, IIV)
4164
4165
4166 #endif /* HAVE_JWZGLES - whole file */