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