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