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