From http://www.jwz.org/xscreensaver/xscreensaver-5.16.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 glTexImage1D and 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 *pixels)
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   Assert (0, "glTexImage1D unimplemented");  /* does not exist in GLES */
2578 }
2579
2580 void
2581 jwzgles_glTexImage2D (GLenum target,
2582                       GLint     level,
2583                       GLint     internalFormat,
2584                       GLsizei   width,
2585                       GLsizei   height,
2586                       GLint     border,
2587                       GLenum    format,
2588                       GLenum    type,
2589                       const GLvoid *data)
2590 {
2591   GLvoid *d2 = (GLvoid *) data;
2592   Assert (!state->compiling_verts, "glTexImage2D not allowed inside glBegin");
2593   Assert (!state->compiling_list,  /* technically legal, but stupid! */
2594           "glTexImage2D not allowed inside glNewList");
2595
2596   Assert (width  == to_pow2(width),   "width must be a power of 2");
2597   Assert (height == to_pow2(height), "height must be a power of 2");
2598
2599   /* OpenGLES no longer supports "4" as a synonym for "RGBA". */
2600   switch (internalFormat) {
2601   case 1: internalFormat = GL_LUMINANCE; break;
2602   case 2: internalFormat = GL_LUMINANCE_ALPHA; break;
2603   case 3: internalFormat = GL_RGB; break;
2604   case 4: internalFormat = GL_RGBA; break;
2605   }
2606
2607   /* GLES does not let us omit the data pointer to create a blank texture. */
2608   if (! data)
2609     {
2610       d2 = (GLvoid *) calloc (1, width * height * sizeof(GLfloat) * 4);
2611       Assert (d2, "out of memory");
2612     }
2613
2614   if (internalFormat == GL_RGB && format == GL_RGBA)
2615     internalFormat = GL_RGBA;  /* WTF */
2616
2617   if (! state->replaying_list)
2618     LOG10 ("direct %-12s %s %d %s %d %d %d %s %s 0x%lX", "glTexImage2D", 
2619            mode_desc(target), level, mode_desc(internalFormat),
2620            width, height, border, mode_desc(format), mode_desc(type),
2621            (unsigned long) d2);
2622   glTexImage2D (target, level, internalFormat, width, height, border,
2623                 format, type, d2);  /* the real one */
2624   CHECK("glTexImage2D");
2625
2626   if (d2 != data) free (d2);
2627 }
2628
2629 void
2630 jwzgles_glTexSubImage2D (GLenum target, GLint level,
2631                          GLint xoffset, GLint yoffset,
2632                          GLsizei width, GLsizei height,
2633                          GLenum format, GLenum type,
2634                          const GLvoid *pixels)
2635 {
2636   Assert (!state->compiling_verts,
2637           "glTexSubImage2D not allowed inside glBegin");
2638   Assert (!state->compiling_list,   /* technically legal, but stupid! */
2639           "glTexSubImage2D not allowed inside glNewList");
2640
2641   if (! state->replaying_list)
2642     LOG10 ("direct %-12s %s %d %d %d %d %d %s %s 0x%lX", "glTexSubImage2D", 
2643            mode_desc(target), level, xoffset, yoffset, width, height,
2644            mode_desc (format), mode_desc (type), (unsigned long) pixels);
2645   glTexSubImage2D (target, level, xoffset, yoffset, width, height,
2646                    format, type, pixels);  /* the real one */
2647   CHECK("glTexSubImage2D");
2648 }
2649
2650 void
2651 jwzgles_glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat,
2652                           GLint x, GLint y, GLsizei width, GLsizei height,
2653                           GLint border)
2654 {
2655   Assert (!state->compiling_verts, 
2656           "glCopyTexImage2D not allowed inside glBegin");
2657   Assert (!state->compiling_list,    /* technically legal, but stupid! */
2658           "glCopyTexImage2D not allowed inside glNewList");
2659   if (! state->replaying_list)
2660     LOG9 ("direct %-12s %s %d %s %d %d %d %d %d", "glCopyTexImage2D", 
2661           mode_desc(target), level, mode_desc(internalformat),
2662           x, y, width, height, border);
2663   glCopyTexImage2D (target, level, internalformat, x, y, width, height,
2664                     border);  /* the real one */
2665   CHECK("glCopyTexImage2D");
2666 }
2667
2668
2669 void
2670 jwzgles_glTexGenfv (GLenum coord, GLenum pname, const GLfloat *params)
2671 {
2672   /* OpenGLES doesn't have this at all!
2673      "Oh, just rewrite that code to use GPU shaders", they say.
2674      How fucking convenient.
2675
2676      So, when this is enabled, we could emit a GL_TEXTURE_COORD_ARRAY
2677      and compute coords for each vertex in the current GL_VERTEX_ARRAY
2678      as per http://www.opengl.org/wiki/Mathematics_of_glTexGen
2679      but holy shit, what a pain in the ass!
2680
2681      For GL_OBJECT_LINEAR, we can just re-use the vertex array as
2682      the texture array, using a proper stride.  That's hardly worth
2683      the effort, though, because bouncingcow is the only hack that
2684      uses that, and not even by default.
2685    */
2686   Assert (coord == GL_S || coord == GL_T, "glTexGenfv: unimplemented coord");
2687
2688   /* This is probably default-ish, so do nothing. */
2689   if (pname == GL_EYE_PLANE) return;
2690
2691   Assert (pname == GL_TEXTURE_GEN_MODE, "glTexGenfv: unimplemented name");
2692   Assert (params[0] == GL_EYE_LINEAR, "glTexGenfv: unimplemented mode");
2693 }
2694
2695 void
2696 jwzgles_glTexGeni (GLenum coord, GLenum pname, GLint param)
2697 {
2698   GLfloat v = param;
2699   jwzgles_glTexGenfv (coord, pname, &v);
2700 }
2701
2702
2703 int
2704 jwzgles_gluBuild2DMipmaps (GLenum target,
2705                            GLint        internalFormat,
2706                            GLsizei      width,
2707                            GLsizei      height,
2708                            GLenum       format,
2709                            GLenum       type,
2710                            const GLvoid *data)
2711 {
2712   /* Not really bothering with mipmapping; only making one level.
2713      Note that this required a corresponding hack in glTexParameterf().
2714    */
2715
2716   int w2 = to_pow2(width);
2717   int h2 = to_pow2(height);
2718
2719   void *d2 = (void *) data;
2720
2721   /* OpenGLES no longer supports "4" as a synonym for "RGBA". */
2722   switch (internalFormat) {
2723   case 1: internalFormat = GL_LUMINANCE; break;
2724   case 2: internalFormat = GL_LUMINANCE_ALPHA; break;
2725   case 3: internalFormat = GL_RGB; break;
2726   case 4: internalFormat = GL_RGBA; break;
2727   }
2728
2729 /*  if (w2 < h2) w2 = h2;
2730   if (h2 < w2) h2 = w2;*/
2731
2732   if (w2 != width || h2 != height)
2733     {
2734       /* Scale up the image bits to fit the power-of-2 texture.
2735          We have to do this because the mipmap API assumes that
2736          the texture bits go to texture coordinates 1.0 x 1.0.
2737          This could be more efficient, but it doesn't happen often.
2738       */
2739       int istride = (format == GL_RGBA ? 4 : 3);
2740       int ostride = 4;
2741       int ibpl = istride * width;
2742       int obpl = ostride * w2;
2743       int oy;
2744       const unsigned char *in = (unsigned char *) data;
2745       unsigned char *out = (void *) malloc (h2 * obpl);
2746       Assert (out, "out of memory");
2747       d2 = out;
2748
2749       for (oy = 0; oy < h2; oy++)
2750         {
2751           int iy = oy * height / h2;
2752           const unsigned char *iline = in  + (iy * ibpl);
2753           unsigned char       *oline = out + (oy * obpl);
2754           int ox;
2755           for (ox = 0; ox < w2; ox++)
2756             {
2757               int ix = ox * width / w2;
2758               const unsigned char *i = iline + (ix * istride);
2759               unsigned char       *o = oline + (ox * ostride);
2760               *o++ = *i++;  /* R */
2761               *o++ = *i++;  /* G */
2762               *o++ = *i++;  /* B */
2763               *o++ = (istride == 4 ? *i : 0xFF); /* A */
2764             }
2765         }
2766       width  = w2;
2767       height = h2;
2768       internalFormat = GL_RGBA;
2769       format = GL_RGBA;
2770     }
2771
2772   jwzgles_glTexImage2D (target, 0, internalFormat, w2, h2, 0, 
2773                         format, type, d2);
2774   if (d2 != data) free (d2);
2775
2776   return 0;
2777 }
2778
2779
2780 void
2781 jwzgles_glRectf (GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
2782 {
2783   jwzgles_glBegin (GL_POLYGON);
2784   jwzgles_glVertex2f (x1, y1);
2785   jwzgles_glVertex2f (x2, y1);
2786   jwzgles_glVertex2f (x2, y2);
2787   jwzgles_glVertex2f (x1, y2);
2788   jwzgles_glEnd ();
2789 }
2790
2791 void
2792 jwzgles_glRecti (GLint x1, GLint y1, GLint x2, GLint y2)
2793 {
2794   jwzgles_glRectf (x1, y1, x2, y2);
2795 }
2796
2797 void
2798 jwzgles_glClearDepth (GLfloat d)
2799 {
2800   /* Not sure what to do here */
2801   Assert (d == 1.0, "glClearDepth unimplemented");
2802 }
2803
2804
2805 void
2806 jwzgles_glEnable (GLuint bit)
2807 {
2808   Assert (!state->compiling_verts, "glEnable not allowed inside glBegin");
2809   if (state->compiling_list)
2810     {
2811       void_int vv[1];
2812       vv[0].i = bit;
2813       list_push ("glEnable", (list_fn_cb) &jwzgles_glEnable, PROTO_I, vv);
2814     }
2815   else
2816     {
2817       if (! state->replaying_list)
2818         LOG2 ("direct %-12s %s", "glEnable", mode_desc(bit));
2819       glEnable (bit);  /* the real one */
2820       CHECK("glEnable");
2821
2822       switch (bit) {
2823       case GL_TEXTURE_2D: state->enabled |= ISENABLED_TEXTURE_2D; break;
2824       case GL_TEXTURE_GEN_S: state->enabled |= ISENABLED_TEXTURE_GEN_S; break;
2825       case GL_TEXTURE_GEN_T: state->enabled |= ISENABLED_TEXTURE_GEN_T; break;
2826       case GL_LIGHTING: state->enabled |= ISENABLED_LIGHTING; break;
2827       case GL_BLEND: state->enabled |= ISENABLED_BLEND; break;
2828       case GL_DEPTH_TEST: state->enabled |= ISENABLED_DEPTH_TEST; break;
2829       case GL_CULL_FACE: state->enabled |= ISENABLED_CULL_FACE; break;
2830       case GL_NORMALIZE: state->enabled |= ISENABLED_NORMALIZE; break;
2831       case GL_FOG: state->enabled |= ISENABLED_FOG; break;
2832       case GL_COLOR_MATERIAL: state->enabled |= ISENABLED_COLMAT; break;
2833
2834       /* Do these work with glEnable or only with glEnableClientState? */
2835       case GL_VERTEX_ARRAY: state->enabled |= ISENABLED_VERT_ARRAY; break;
2836       case GL_NORMAL_ARRAY: state->enabled |= ISENABLED_NORM_ARRAY; break;
2837       case GL_TEXTURE_COORD_ARRAY: state->enabled |= ISENABLED_TEX_ARRAY;break;
2838       case GL_COLOR_ARRAY:  state->enabled |= ISENABLED_COLOR_ARRAY; break;
2839
2840       default: break;
2841       }
2842     }
2843 }
2844
2845
2846 void
2847 jwzgles_glDisable (GLuint bit)
2848 {
2849   Assert (!state->compiling_verts, "glDisable not allowed inside glBegin");
2850   if (state->compiling_list)
2851     {
2852       void_int vv[1];
2853       vv[0].i = bit;
2854       list_push ("glDisable", (list_fn_cb) &jwzgles_glDisable, PROTO_I, vv);
2855     }
2856   else
2857     {
2858       if (! state->replaying_list)
2859         LOG2 ("direct %-12s %s", "glDisable", mode_desc(bit));
2860       glDisable (bit);  /* the real one */
2861       CHECK("glDisable");
2862
2863       switch (bit) {
2864       case GL_TEXTURE_2D: state->enabled &= ~ISENABLED_TEXTURE_2D; break;
2865       case GL_TEXTURE_GEN_S: state->enabled &= ~ISENABLED_TEXTURE_GEN_S; break;
2866       case GL_TEXTURE_GEN_T: state->enabled &= ~ISENABLED_TEXTURE_GEN_T; break;
2867       case GL_LIGHTING: state->enabled &= ~ISENABLED_LIGHTING; break;
2868       case GL_BLEND: state->enabled &= ~ISENABLED_BLEND; break;
2869       case GL_DEPTH_TEST: state->enabled &= ~ISENABLED_DEPTH_TEST; break;
2870       case GL_CULL_FACE: state->enabled &= ~ISENABLED_CULL_FACE; break;
2871       case GL_NORMALIZE: state->enabled &= ~ISENABLED_NORMALIZE; break;
2872       case GL_FOG: state->enabled &= ~ISENABLED_FOG; break;
2873       case GL_COLOR_MATERIAL: state->enabled &= ~ISENABLED_COLMAT; break;
2874
2875       /* Do these work with glEnable or only with glEnableClientState? */
2876       case GL_VERTEX_ARRAY: state->enabled &= ~ISENABLED_VERT_ARRAY; break;
2877       case GL_NORMAL_ARRAY: state->enabled &= ~ISENABLED_NORM_ARRAY; break;
2878       case GL_TEXTURE_COORD_ARRAY: state->enabled &= ~ISENABLED_TEX_ARRAY;break;
2879       case GL_COLOR_ARRAY:  state->enabled &= ~ISENABLED_COLOR_ARRAY; break;
2880
2881       default: break;
2882       }
2883     }
2884 }
2885
2886
2887 GLboolean
2888 jwzgles_glIsEnabled (GLuint bit)
2889 {
2890  /*
2891   Assert (!state->compiling_verts, "glIsEnabled not allowed inside glBegin");
2892   Assert (!state->compiling_list,  "glIsEnabled not allowed inside glNewList");
2893   */
2894   switch (bit) {
2895   case GL_TEXTURE_2D: return !!(state->enabled & ISENABLED_TEXTURE_2D);
2896   case GL_TEXTURE_GEN_S: return !!(state->enabled & ISENABLED_TEXTURE_GEN_S);
2897   case GL_TEXTURE_GEN_T: return !!(state->enabled & ISENABLED_TEXTURE_GEN_T);
2898   case GL_LIGHTING: return !!(state->enabled & ISENABLED_LIGHTING);
2899   case GL_BLEND: return !!(state->enabled & ISENABLED_BLEND);
2900   case GL_DEPTH_TEST: return !!(state->enabled & ISENABLED_DEPTH_TEST);
2901   case GL_CULL_FACE: return !!(state->enabled & ISENABLED_CULL_FACE);
2902   case GL_NORMALIZE: return !!(state->enabled & ISENABLED_NORMALIZE);
2903   case GL_FOG: return !!(state->enabled & ISENABLED_FOG);
2904   case GL_COLOR_MATERIAL: return !!(state->enabled & ISENABLED_COLMAT);
2905
2906   /* Do these work with glEnable or only with glEnableClientState?
2907      We need to query them, and there is no glIsClientStateEnabled.
2908    */
2909   case GL_VERTEX_ARRAY: return !!(state->enabled & ISENABLED_VERT_ARRAY);
2910   case GL_NORMAL_ARRAY: return !!(state->enabled & ISENABLED_NORM_ARRAY);
2911   case GL_TEXTURE_COORD_ARRAY: return !!(state->enabled & ISENABLED_TEX_ARRAY);
2912   case GL_COLOR_ARRAY: return !!(state->enabled & ISENABLED_COLOR_ARRAY);
2913   default: Assert (0, "glIsEnabled unimplemented bit"); break;
2914   }
2915 }
2916
2917
2918 /* The spec says that OpenGLES 1.x doesn't implement glGetFloatv.
2919    Were this true, it would suck, for it would mean that there was no
2920    way to retrieve the prevailing matrixes.  To implement this, we'd
2921    have to keep track of them all on the client side by combining in
2922    all the actions of glMultMatrixf, glRotatef, etc.
2923
2924    However, Apple's iOS OpenGLES *does* provide glGetFloatv!
2925  */
2926 void
2927 jwzgles_glGetFloatv (GLenum pname, GLfloat *params)
2928 {
2929   if (! state->replaying_list)
2930     LOG2 ("direct %-12s %s", "glGetFloatv", mode_desc(pname));
2931   glGetFloatv (pname, params);  /* the real one */
2932   CHECK("glGetFloatv");
2933 }
2934
2935
2936 /* Likewise: not supposed to be there, but it is. */
2937 void
2938 jwzgles_glGetPointerv (GLenum pname, GLvoid *params)
2939 {
2940   if (! state->replaying_list)
2941     LOG2 ("direct %-12s %s", "glGetPointerv", mode_desc(pname));
2942   glGetPointerv (pname, params);  /* the real one */
2943   CHECK("glGetPointerv");
2944 }
2945
2946
2947 /* How many cells are written into the *params array.
2948    We need to know this to avoid smashing the caller's stack
2949    if they asked for a single-value parameter.
2950  */
2951 static int
2952 glGet_ret_count (GLenum pname)
2953 {
2954   switch (pname) {
2955 /*case GL_COLOR_MATRIX: */
2956   case GL_MODELVIEW_MATRIX:
2957   case GL_PROJECTION_MATRIX:
2958   case GL_TEXTURE_MATRIX:
2959 /*case GL_TRANSPOSE_COLOR_MATRIX: */
2960 /*case GL_TRANSPOSE_MODELVIEW_MATRIX: */
2961 /*case GL_TRANSPOSE_PROJECTION_MATRIX: */
2962 /*case GL_TRANSPOSE_TEXTURE_MATRIX: */
2963     return 16;
2964 /*case GL_ACCUM_CLEAR_VALUE: */
2965 /*case GL_BLEND_COLOR: */
2966   case GL_COLOR_CLEAR_VALUE:
2967   case GL_COLOR_WRITEMASK:
2968   case GL_CURRENT_COLOR:
2969 /*case GL_CURRENT_RASTER_COLOR: */
2970 /*case GL_CURRENT_RASTER_POSITION: */
2971 /*case GL_CURRENT_RASTER_SECONDARY_COLOR: */
2972 /*case GL_CURRENT_RASTER_TEXTURE_COORDS: */
2973 /*case GL_CURRENT_SECONDARY_COLOR: */
2974   case GL_CURRENT_TEXTURE_COORDS:
2975   case GL_FOG_COLOR:
2976   case GL_LIGHT_MODEL_AMBIENT:
2977 /*case GL_MAP2_GRID_DOMAIN: */
2978   case GL_SCISSOR_BOX:
2979   case GL_VIEWPORT:
2980     return 4;
2981   case GL_CURRENT_NORMAL:
2982   case GL_POINT_DISTANCE_ATTENUATION:
2983     return 3;
2984   case GL_ALIASED_LINE_WIDTH_RANGE:
2985   case GL_ALIASED_POINT_SIZE_RANGE:
2986   case GL_DEPTH_RANGE:
2987 /*case GL_LINE_WIDTH_RANGE: */
2988 /*case GL_MAP1_GRID_DOMAIN: */
2989 /*case GL_MAP2_GRID_SEGMENTS: */
2990   case GL_MAX_VIEWPORT_DIMS:
2991 /*case GL_POINT_SIZE_RANGE: */
2992   case GL_POLYGON_MODE:
2993   case GL_SMOOTH_LINE_WIDTH_RANGE:
2994   case GL_SMOOTH_POINT_SIZE_RANGE:
2995     return 2;
2996   default:
2997     return 1;
2998   }
2999 }
3000
3001
3002 void
3003 jwzgles_glGetDoublev (GLenum pname, GLdouble *params)
3004 {
3005   GLfloat m[16];
3006   int i, j = glGet_ret_count (pname);
3007   jwzgles_glGetFloatv (pname, m);
3008   for (i = 0; i < j; i++)
3009     params[i] = m[i];
3010 }
3011
3012
3013 void
3014 jwzgles_glGetIntegerv (GLenum pname, GLint *params)
3015 {
3016   GLfloat m[16];
3017   int i, j = glGet_ret_count (pname);
3018   jwzgles_glGetFloatv (pname, m);
3019   for (i = 0; i < j; i++)
3020     params[i] = m[i];
3021 }
3022
3023
3024 void
3025 jwzgles_glGetBooleanv (GLenum pname, GLboolean *params)
3026 {
3027   GLfloat m[16];
3028   int i, j = glGet_ret_count (pname);
3029   jwzgles_glGetFloatv (pname, m);
3030   for (i = 0; i < j; i++)
3031     params[i] = (m[i] != 0.0);
3032 }
3033
3034
3035 const char *
3036 jwzgles_gluErrorString (GLenum error)
3037 {
3038   static char s[20];
3039   sprintf (s, "0x%lX", (unsigned long) error);
3040   return s;
3041 }
3042
3043
3044 /* These can be included inside glNewList, but they actually execute
3045    immediately anyway. 
3046  */
3047 void
3048 jwzgles_glVertexPointer (GLuint size, GLuint type, GLuint stride, 
3049                          const GLvoid *ptr)
3050 {
3051   if (! state->replaying_list)
3052     LOG5 ("direct %-12s %d %s %d 0x%lX", "glVertexPointer", 
3053           size, mode_desc(type), stride, (unsigned long) ptr);
3054   glVertexPointer (size, type, stride, ptr);  /* the real one */
3055   CHECK("glVertexPointer");
3056 }
3057
3058 void
3059 jwzgles_glNormalPointer (GLuint type, GLuint stride, const GLvoid *ptr)
3060 {
3061   if (! state->replaying_list)
3062     LOG4 ("direct %-12s %s %d 0x%lX", "glNormalPointer", 
3063           mode_desc(type), stride, (unsigned long) ptr);
3064   glNormalPointer (type, stride, ptr);  /* the real one */
3065   CHECK("glNormalPointer");
3066 }
3067
3068 void
3069 jwzgles_glColorPointer (GLuint size, GLuint type, GLuint stride, 
3070                         const GLvoid *ptr)
3071 {
3072   if (! state->replaying_list)
3073     LOG5 ("direct %-12s %d %s %d 0x%lX", "glColorPointer", 
3074           size, mode_desc(type), stride, (unsigned long) ptr);
3075   glColorPointer (size, type, stride, ptr);  /* the real one */
3076   CHECK("glColorPointer");
3077 }
3078
3079 void
3080 jwzgles_glTexCoordPointer (GLuint size, GLuint type, GLuint stride, 
3081                            const GLvoid *ptr)
3082 {
3083   if (! state->replaying_list)
3084     LOG5 ("direct %-12s %d %s %d 0x%lX", "glTexCoordPointer", 
3085           size, mode_desc(type), stride, (unsigned long) ptr);
3086   glTexCoordPointer (size, type, stride, ptr);  /* the real one */
3087   CHECK("glTexCoordPointer");
3088 }
3089
3090
3091 void
3092 jwzgles_glTexParameterf (GLuint target, GLuint pname, GLfloat param)
3093 {
3094   Assert (!state->compiling_verts,
3095           "glTexParameterf not allowed inside glBegin");
3096
3097   /* We don't *really* implement mipmaps, so just turn this off.
3098    */
3099   if (param == GL_LINEAR_MIPMAP_LINEAR)   param = GL_LINEAR;
3100   if (param == GL_NEAREST_MIPMAP_LINEAR)  param = GL_LINEAR;
3101   if (param == GL_LINEAR_MIPMAP_NEAREST)  param = GL_NEAREST;
3102   if (param == GL_NEAREST_MIPMAP_NEAREST) param = GL_NEAREST;
3103
3104   if (state->compiling_list)
3105     {
3106       void_int vv[3];
3107       vv[0].i = target;
3108       vv[1].i = pname;
3109       vv[2].f = param;
3110       list_push ("glTexParameterf", (list_fn_cb) &jwzgles_glTexParameterf,
3111                  PROTO_IIF, vv);
3112     }
3113   else
3114     {
3115       if (! state->replaying_list)
3116         LOG4 ("direct %-12s %s %s %7.3f", "glTexParameterf", 
3117               mode_desc(target), mode_desc(pname), param);
3118       glTexParameterf (target, pname, param);  /* the real one */
3119       CHECK("glTexParameterf");
3120     }
3121 }
3122
3123 void
3124 jwzgles_glTexParameteri (GLuint target, GLuint pname, GLuint param)
3125 {
3126   jwzgles_glTexParameterf (target, pname, param);
3127 }
3128
3129
3130 /* Matrix functions, mostly cribbed from Mesa.
3131  */
3132
3133 void
3134 jwzgles_glFrustum (GLfloat left,   GLfloat right,
3135                    GLfloat bottom, GLfloat top,
3136                    GLfloat near,   GLfloat far)
3137 {
3138   GLfloat m[16];
3139   GLfloat x = (2 * near)        / (right-left);
3140   GLfloat y = (2 * near)        / (top - bottom);
3141   GLfloat a = (right + left)    / (right - left);
3142   GLfloat b = (top + bottom)    / (top - bottom);
3143   GLfloat c = -(far + near)     / (far - near);
3144   GLfloat d = -(2 * far * near) / (far - near);
3145
3146 # define M(X,Y)  m[Y * 4 + X]
3147   M(0,0) = x; M(0,1) = 0; M(0,2) =  a; M(0,3) = 0;
3148   M(1,0) = 0; M(1,1) = y; M(1,2) =  b; M(1,3) = 0;
3149   M(2,0) = 0; M(2,1) = 0; M(2,2) =  c; M(2,3) = d;
3150   M(3,0) = 0; M(3,1) = 0; M(3,2) = -1; M(3,3) = 0;
3151 # undef M
3152
3153   jwzgles_glMultMatrixf (m);
3154 }
3155
3156
3157 void
3158 jwzgles_glOrtho (GLfloat left,   GLfloat right,
3159                  GLfloat bottom, GLfloat top,
3160                  GLfloat near,   GLfloat far)
3161 {
3162   GLfloat m[16];
3163   GLfloat a = 2 / (right - left);
3164   GLfloat b = -(right + left) / (right - left);
3165   GLfloat c = 2 / (top - bottom);
3166   GLfloat d = -(top + bottom) / (top - bottom);
3167   GLfloat e = -2 / (far - near);
3168   GLfloat f = -(far + near) / (far - near);
3169
3170 # define M(X,Y)  m[Y * 4 + X]
3171   M(0,0) = a; M(0,1) = 0; M(0,2) = 0; M(0,3) = b;
3172   M(1,0) = 0; M(1,1) = c; M(1,2) = 0; M(1,3) = d;
3173   M(2,0) = 0; M(2,1) = 0; M(2,2) = e; M(2,3) = f;
3174   M(3,0) = 0; M(3,1) = 0; M(3,2) = 0; M(3,3) = 1;
3175 # undef M
3176
3177   jwzgles_glMultMatrixf (m);
3178 }
3179
3180
3181 void
3182 jwzgles_gluPerspective (GLdouble fovy, GLdouble aspect, 
3183                         GLdouble near, GLdouble far)
3184 {
3185   GLfloat m[16];
3186   double si, co, dz;
3187   double rad = fovy / 2 * M_PI / 180;
3188   double a, b, c, d;
3189
3190   dz = far - near;
3191   si = sin(rad);
3192   if (dz == 0 || si == 0 || aspect == 0)
3193     return;
3194   co = cos(rad) / si;
3195
3196   a = co / aspect;
3197   b = co;
3198   c = -(far + near) / dz;
3199   d = -2 * near * far / dz;
3200
3201 # define M(X,Y)  m[Y * 4 + X]
3202   M(0,0) = a; M(0,1) = 0; M(0,2) = 0;  M(0,3) = 0;
3203   M(1,0) = 0; M(1,1) = b; M(1,2) = 0;  M(1,3) = 0;
3204   M(2,0) = 0; M(2,1) = 0; M(2,2) = c;  M(2,3) = d;
3205   M(3,0) = 0; M(3,1) = 0; M(3,2) = -1; M(3,3) = 0;
3206 # undef M
3207
3208   jwzgles_glMultMatrixf (m);
3209 }
3210
3211
3212 void
3213 jwzgles_gluLookAt (GLfloat eyex, GLfloat eyey, GLfloat eyez,
3214                    GLfloat centerx, GLfloat centery, GLfloat centerz,
3215                    GLfloat upx, GLfloat upy, GLfloat upz)
3216 {
3217   GLfloat m[16];
3218   GLfloat x[3], y[3], z[3];
3219   GLfloat mag;
3220     
3221   /* Make rotation matrix */
3222     
3223   /* Z vector */
3224   z[0] = eyex - centerx;
3225   z[1] = eyey - centery;
3226   z[2] = eyez - centerz;
3227   mag = sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]);
3228   if (mag) {          /* mpichler, 19950515 */
3229     z[0] /= mag;
3230     z[1] /= mag;
3231     z[2] /= mag;
3232   }
3233     
3234   /* Y vector */
3235   y[0] = upx;
3236   y[1] = upy;
3237   y[2] = upz;
3238     
3239   /* X vector = Y cross Z */
3240   x[0] = y[1] * z[2] - y[2] * z[1];
3241   x[1] = -y[0] * z[2] + y[2] * z[0];
3242   x[2] = y[0] * z[1] - y[1] * z[0];
3243     
3244   /* Recompute Y = Z cross X */
3245   y[0] = z[1] * x[2] - z[2] * x[1];
3246   y[1] = -z[0] * x[2] + z[2] * x[0];
3247   y[2] = z[0] * x[1] - z[1] * x[0];
3248     
3249   /* mpichler, 19950515 */
3250   /* cross product gives area of parallelogram, which is < 1.0 for
3251    * non-perpendicular unit-length vectors; so normalize x, y here
3252    */
3253     
3254   mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
3255   if (mag) {
3256     x[0] /= mag;
3257     x[1] /= mag;
3258     x[2] /= mag;
3259   }
3260     
3261   mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
3262   if (mag) {
3263     y[0] /= mag;
3264     y[1] /= mag;
3265     y[2] /= mag;
3266   }
3267     
3268 #define M(row,col)  m[col*4+row]
3269   M(0, 0) = x[0]; M(0, 1) = x[1]; M(0, 2) = x[2]; M(0, 3) = 0.0;
3270   M(1, 0) = y[0]; M(1, 1) = y[1]; M(1, 2) = y[2]; M(1, 3) = 0.0;
3271   M(2, 0) = z[0]; M(2, 1) = z[1]; M(2, 2) = z[2]; M(2, 3) = 0.0;
3272   M(3, 0) = 0.0;  M(3, 1) = 0.0;  M(3, 2) = 0.0;  M(3, 3) = 1.0;
3273 #undef M
3274
3275   jwzgles_glMultMatrixf(m);
3276     
3277   /* Translate Eye to Origin */
3278   jwzgles_glTranslatef(-eyex, -eyey, -eyez);
3279 }
3280
3281
3282 static void __gluMultMatrixVecd (const GLdouble matrix[16],
3283                                  const GLdouble in[4],
3284                                  GLdouble out[4])
3285 {
3286   int i;
3287
3288   for (i=0; i<4; i++) {
3289     out[i] = 
3290       in[0] * matrix[0*4+i] +
3291       in[1] * matrix[1*4+i] +
3292       in[2] * matrix[2*4+i] +
3293       in[3] * matrix[3*4+i];
3294   }
3295 }
3296
3297 GLint
3298 jwzgles_gluProject (GLdouble objx, GLdouble objy, GLdouble objz, 
3299                     const GLdouble modelMatrix[16], 
3300                     const GLdouble projMatrix[16],
3301                     const GLint viewport[4],
3302                     GLdouble *winx, GLdouble *winy, GLdouble *winz)
3303 {
3304   GLdouble in[4];
3305   GLdouble out[4];
3306
3307   /* #### I suspect this is not working right.  I was seeing crazy values
3308      in lament.c.  Maybe there's some float-vs-double confusion going on?
3309    */
3310
3311   in[0]=objx;
3312   in[1]=objy;
3313   in[2]=objz;
3314   in[3]=1.0;
3315   __gluMultMatrixVecd(modelMatrix, in, out);
3316   __gluMultMatrixVecd(projMatrix, out, in);
3317   if (in[3] == 0.0) return(GL_FALSE);
3318   in[0] /= in[3];
3319   in[1] /= in[3];
3320   in[2] /= in[3];
3321   /* Map x, y and z to range 0-1 */
3322   in[0] = in[0] * 0.5 + 0.5;
3323   in[1] = in[1] * 0.5 + 0.5;
3324   in[2] = in[2] * 0.5 + 0.5;
3325
3326   /* Map x,y to viewport */
3327   in[0] = in[0] * viewport[2] + viewport[0];
3328   in[1] = in[1] * viewport[3] + viewport[1];
3329
3330   *winx=in[0];
3331   *winy=in[1];
3332   *winz=in[2];
3333   return(GL_TRUE);
3334 }
3335
3336
3337 /* The following functions are present in both OpenGL 1.1 and in OpenGLES 1,
3338    but are allowed within glNewList/glEndList, so we must wrap them to allow
3339    them to either be recorded in lists, or run directly.
3340
3341    All this CPP obscenity is me screaming in rage at all the ways that C is
3342    not Lisp, as all I want to do here is DEFADVICE.
3343  */
3344
3345 #define PROTO_V   PROTO_VOID
3346 #define TYPE_V    GLuint
3347 #define ARGS_V    void
3348 #define VARS_V    /* */
3349 #define LOGS_V    "\n"
3350 #define FILL_V    /* */
3351
3352 #define TYPE_I    GLuint
3353 #define TYPE_II   TYPE_I
3354 #define TYPE_III  TYPE_I
3355 #define TYPE_IIII TYPE_I
3356 #define ARGS_I    TYPE_I a
3357 #define ARGS_II   TYPE_I a, TYPE_I b
3358 #define ARGS_III  TYPE_I a, TYPE_I b, TYPE_I c
3359 #define ARGS_IIII TYPE_I a, TYPE_I b, TYPE_I c, TYPE_I d
3360 #define LOGS_I    "%s\n", mode_desc(a)
3361 #define LOGS_II   "%s %d\n", mode_desc(a), b
3362 #define LOGS_III  "%s %s %s\n", mode_desc(a), mode_desc(b), mode_desc(c)
3363 #define LOGS_IIII "%d %d %d %d\n", a, b, c, d
3364 #define VARS_I    a
3365 #define VARS_II   a, b
3366 #define VARS_III  a, b, c
3367 #define VARS_IIII a, b, c, d
3368 #define FILL_I    vv[0].i = a;
3369 #define FILL_II   vv[0].i = a; vv[1].i = b;
3370 #define FILL_III  vv[0].i = a; vv[1].i = b; vv[2].i = c;
3371 #define FILL_IIII vv[0].i = a; vv[1].i = b; vv[2].i = c; vv[3].i = d;
3372
3373 #define TYPE_F    GLfloat
3374 #define TYPE_FF   TYPE_F
3375 #define TYPE_FFF  TYPE_F
3376 #define TYPE_FFFF TYPE_F
3377 #define ARGS_F    TYPE_F a
3378 #define ARGS_FF   TYPE_F a, TYPE_F b
3379 #define ARGS_FFF  TYPE_F a, TYPE_F b, TYPE_F c
3380 #define ARGS_FFFF TYPE_F a, TYPE_F b, TYPE_F c, TYPE_F d
3381 #define LOGS_F    "%7.3f\n", a
3382 #define LOGS_FF   "%7.3f %7.3f\n", a, b
3383 #define LOGS_FFF  "%7.3f %7.3f %7.3f\n", a, b, c
3384 #define LOGS_FFFF "%7.3f %7.3f %7.3f %7.3f\n", a, b, c, d
3385 #define VARS_F    VARS_I
3386 #define VARS_FF   VARS_II
3387 #define VARS_FFF  VARS_III
3388 #define VARS_FFFF VARS_IIII
3389 #define FILL_F    vv[0].f = a;
3390 #define FILL_FF   vv[0].f = a; vv[1].f = b;
3391 #define FILL_FFF  vv[0].f = a; vv[1].f = b; vv[2].f = c;
3392 #define FILL_FFFF vv[0].f = a; vv[1].f = b; vv[2].f = c; vv[3].f = d;
3393
3394 #define ARGS_IF   TYPE_I a, TYPE_F b
3395 #define VARS_IF   VARS_II
3396 #define LOGS_IF   "%s %7.3f\n", mode_desc(a), b
3397 #define FILL_IF   vv[0].i = a; vv[1].f = b;
3398
3399 #define ARGS_IIF  TYPE_I a, TYPE_I b, TYPE_F c
3400 #define VARS_IIF  VARS_III
3401 #define LOGS_IIF  "%s %s %7.3f\n", mode_desc(a), mode_desc(b), c
3402 #define FILL_IIF  vv[0].i = a; vv[1].i = b; vv[2].f = c;
3403
3404 #define TYPE_IV   GLint
3405 #define ARGS_IIV  TYPE_I a, const TYPE_IV *b
3406 #define VARS_IIV  VARS_II
3407 #define LOGS_IIV  "%s %d %d %d %d\n", mode_desc(a), b[0], b[1], b[2], b[3]
3408 #define FILL_IIV  vv[0].i = a; \
3409                   vv[1].i = b[0]; vv[2].i = b[1]; \
3410                   vv[3].i = b[2]; vv[4].i = b[3];
3411
3412 #define ARGS_IFV  TYPE_I a, const TYPE_F *b
3413 #define VARS_IFV  VARS_II
3414 #define LOGS_IFV  "%s %7.3f %7.3f %7.3f %7.3f\n", mode_desc(a), \
3415                   b[0], b[1], b[2], b[3]
3416 #define FILL_IFV  vv[0].i = a; \
3417                   vv[1].f = b[0]; vv[2].f = b[1]; \
3418                   vv[3].f = b[2]; vv[4].f = b[3];
3419
3420 #define ARGS_IIIV TYPE_I a, TYPE_I b, const TYPE_IV *c
3421 #define VARS_IIIV VARS_III
3422 #define LOGS_IIIV "%s %-8s %3d %3d %3d %3d\n", mode_desc(a), mode_desc(b), \
3423                   c[0], c[1], c[2], c[3]
3424 #define FILL_IIIV vv[0].i = a; vv[1].i = b; \
3425                   vv[2].i = c[0]; vv[3].i = c[1]; \
3426                   vv[4].i = c[2]; vv[5].i = c[3];
3427
3428 #define ARGS_IIFV TYPE_I a, TYPE_I b, const TYPE_F *c
3429 #define VARS_IIFV VARS_III
3430 #define LOGS_IIFV "%s %-8s %7.3f %7.3f %7.3f %7.3f\n", \
3431                   mode_desc(a), mode_desc(b), \
3432                   c[0], c[1], c[2], c[3]
3433 #define FILL_IIFV vv[0].i = a; vv[1].i = b; \
3434                   vv[2].f = c[0]; vv[3].f = c[1]; \
3435                   vv[4].f = c[2]; vv[5].f = c[3];
3436
3437 #ifdef DEBUG
3438 # define WLOG(NAME,ARGS) \
3439   fprintf (stderr, "jwzgles: direct %-12s ", NAME); \
3440   fprintf (stderr, ARGS)
3441 #else
3442 # define WLOG(NAME,ARGS) /* */
3443 #endif
3444
3445 #define WRAP(NAME,SIG) \
3446 void jwzgles_##NAME (ARGS_##SIG)                                        \
3447 {                                                                       \
3448   Assert (!state->compiling_verts,                                      \
3449           STRINGIFY(NAME) " not allowed inside glBegin");               \
3450   if (state->compiling_list) {                                          \
3451     void_int vv[10];                                                    \
3452     FILL_##SIG                                                          \
3453     list_push (STRINGIFY(NAME), (list_fn_cb) &jwzgles_##NAME,           \
3454                PROTO_##SIG, vv);                                        \
3455   } else {                                                              \
3456     if (! state->replaying_list) {                                      \
3457       WLOG (STRINGIFY(NAME), LOGS_##SIG);                               \
3458     }                                                                   \
3459     NAME (VARS_##SIG);                                                  \
3460     CHECK(STRINGIFY(NAME));                                             \
3461   }                                                                     \
3462 }
3463
3464 WRAP (glActiveTexture,  I)
3465 WRAP (glAlphaFunc,      IF)
3466 WRAP (glBindTexture,    II)
3467 WRAP (glBlendFunc,      II)
3468 WRAP (glClear,          I)
3469 WRAP (glClearColor,     FFFF)
3470 WRAP (glClearStencil,   I)
3471 WRAP (glColorMask,      IIII)
3472 WRAP (glCullFace,       I)
3473 WRAP (glDepthFunc,      I)
3474 WRAP (glDepthMask,      I)
3475 WRAP (glFinish,         V)
3476 WRAP (glFlush,          V)
3477 WRAP (glFogf,           IF)
3478 WRAP (glFogfv,          IFV)
3479 WRAP (glFrontFace,      I)
3480 WRAP (glHint,           II)
3481 WRAP (glLightModelf,    IF)
3482 WRAP (glLightModelfv,   IFV)
3483 WRAP (glLightf,         IIF)
3484 WRAP (glLightfv,        IIFV)
3485 WRAP (glLineWidth,      F)
3486 WRAP (glLoadIdentity,   V)
3487 WRAP (glLogicOp,        I)
3488 WRAP (glMatrixMode,     I)
3489 WRAP (glPixelStorei,    II)
3490 WRAP (glPointSize,      F)
3491 WRAP (glPolygonOffset,  FF)
3492 WRAP (glPopMatrix,      V)
3493 WRAP (glPushMatrix,     V)
3494 WRAP (glRotatef,        FFFF)
3495 WRAP (glScalef,         FFF)
3496 WRAP (glScissor,        IIII)
3497 WRAP (glShadeModel,     I)
3498 WRAP (glStencilFunc,    III)
3499 WRAP (glStencilMask,    I)
3500 WRAP (glStencilOp,      III)
3501 WRAP (glTexEnvf,        IIF)
3502 WRAP (glTexEnvi,        III)
3503 WRAP (glTranslatef,     FFF)
3504 WRAP (glViewport,       IIII)
3505 #undef  TYPE_IV
3506 #define TYPE_IV GLuint
3507 WRAP (glDeleteTextures, IIV)
3508
3509
3510 #endif /* HAVE_JWZGLES - whole file */