1 /* xscreensaver, Copyright (c) 2012-2013 Jamie Zawinski <jwz@jwz.org>
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
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
16 There are two major operations going on here:
18 - Converting calls to glBegin + glVertex3f + glEnd to glDrawArrays
19 - Implementing display lists.
22 From an API point of view, OpenGL 1.3 and earlier code looks like this:
24 glLightfv (GL_LIGHT0, GL_POSITION, ...);
25 glLightfv (GL_LIGHT0, GL_AMBIENT, ...);
27 glMatrixMode (GL_PROJECTION);
31 glMatrixMode (GL_MODELVIEW);
41 glBegin (GL_TRIANGLES);
53 OpenGLES broke that model by eliminating glBegin(). Instead of
54 iterating a sequence of vertexes, you need to pack your points into
63 glDrawArrays (GL_TRIANGLES, 0, 3);
65 The projection model (glRotatef, etc.) works the same, but glColor()
66 is missing. You're expected to encode that into your arrays.
68 Also, OpenGLES doesn't support display lists at all.
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.
74 Likewise, it shadows all of the functions that are allowed within
75 glNewList and records those calls for later playback.
78 This code only handles OpenGLES 1.x, not 2.x.
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.
90 Incidentally, the OpenGL numbering scheme goes something like this:
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)
105 Some things that are missing:
107 - glTexGeni, meaning no spherical environment-mapping textures.
109 - gluNewTess, meaning no tesselation of complex objects.
111 - glMap2f mesh evaluators, meaning no Utah Teapot.
113 - glPolygonMode with GL_LINE or GL_POINT, meaning no wireframe modes
114 that do hidden-surface removal.
116 - glSelectBuffer, meaning no mouse-hit detection on rendered objects.
118 - gluNewQuadric, gluCylinder, etc: rewrite your code to use tube.c, etc.
120 - Putting verts in a display list without a wrapping glBegin.
121 (I didn't realize that even worked!)
123 - Not every function is implemented; just the ones that I needed for
124 xscreensaver. However, the trivial ones are trivial to enable
125 as they come up. Harder ones will be harder.
127 As a result of that, these savers look wrong:
129 blocktube Uses SPHERE_MAP.
130 bouncingcow Uses OBJECT_LINEAR (when run with -texture)
131 dnalogo Uses GLUtesselator.
132 extrusion Uses all kinds of GLUT crap.
133 flyingtoasters Uses SPHERE_MAP and OBJECT_LINEAR.
134 jigglypuff Uses SPHERE_MAP (in chrome mode), GL_LINE (in wireframe)
135 jigsaw Uses GLUtesselator.
136 lockward Puts verts in lists without glBegin!
137 pinion Uses glSelectBuffer and gluPickMatrix for mouse-clicks.
138 pipes Uses glMap2f for the Utah Teapot.
139 polyhedra Uses GLUtesselator (concave objects); also Utah Teapot.
140 skytentacles Uses GL_LINE in -cel mode.
141 timetunnel Uses GL_CONSTANT_ALPHA and all kinds of other stuff.
151 #endif /* HAVE_CONFIG_H */
153 #ifdef HAVE_JWZGLES /* whole file */
162 #endif /* HAVE_UNISTD_H */
164 #if defined(USE_IPHONE)
165 # include <OpenGLES/ES1/gl.h>
166 # include <OpenGLES/ES1/glext.h>
167 #elif defined(HAVE_COCOA)
168 # include <OpenGL/gl.h>
169 # include <OpenGL/glu.h>
171 # ifndef GL_GLEXT_PROTOTYPES
172 # define GL_GLEXT_PROTOTYPES /* for glBindBuffer */
178 #include "jwzglesI.h"
180 #define STRINGIFY(X) #X
183 #define countof(x) (sizeof((x))/sizeof((*x)))
188 extern void jwxyz_abort (const char *fmt, ...) __dead2;
189 # define Assert(C,S) do { if (!(C)) { jwxyz_abort ("%s",S); }} while(0)
191 # define Assert(C,S) do { \
193 fprintf (stderr, "jwzgles: %s\n", S); \
199 typedef struct { GLfloat x, y, z; } XYZ;
200 typedef struct { GLfloat x, y, z, w; } XYZW;
201 typedef struct { GLfloat s, t, r, q; } STRQ;
202 typedef struct { GLfloat r, g, b, a; } RGBA;
205 /* Used to record all calls to glVertex3f, glNormal3f, etc.
206 while inside glBegin / glEnd so that we can convert that
207 to a single call to glDrawArrays.
211 int count, size; /* size of each array */
213 XYZW *verts; /* Arrays being built */
218 int ncount; /* How many normals, tex coords and colors were */
219 int tcount; /* used. We optimize based on "0, 1, or many". */
221 int materialistic; /* Whether glMaterial was called inside glBegin */
223 XYZ cnorm; /* Prevailing normal/texture/color while building */
230 typedef void (*list_fn_cb) (void);
233 /* We need this nonsense because you can't cast a double to a void*
234 or vice versa. They tend to be passed in different registers,
235 and you need to know about that because it's still 1972 here.
237 typedef union { const void *v; GLfloat f; GLuint i; } void_int;
239 typedef struct { /* saved args for glDrawArrays */
240 int binding, size, type, stride, bytes;
244 typedef enum { /* shorthand describing arglist signature */
245 PROTO_VOID, /* no args */
246 PROTO_I, /* 1 int arg */
247 PROTO_F, /* 1 float arg */
248 PROTO_II, /* int, int */
249 PROTO_FF, /* float, float */
250 PROTO_IF, /* int, float */
251 PROTO_III, /* int, int, int */
252 PROTO_FFF, /* float, float, float */
253 PROTO_IIF, /* int, int, float */
254 PROTO_IIII, /* int, int, int, int */
255 PROTO_FFFF, /* float, float, float, float */
256 PROTO_IIV, /* int, int[4] */
257 PROTO_IFV, /* int, float[4] */
258 PROTO_IIIV, /* int, int, int[4] */
259 PROTO_IIFV, /* int, int, float[4] */
260 PROTO_FV16, /* float[16] */
261 PROTO_ARRAYS /* glDrawArrays */
264 typedef struct { /* A single element of a display list */
266 list_fn_cb fn; /* saved function pointer */
267 fn_proto proto; /* arglist prototype */
268 draw_array *arrays; /* args for glDrawArrays */
269 void_int argv[16]; /* args for everything else */
273 typedef struct { /* a display list: saved activity within glNewList */
278 /* Named buffer that should be freed when this display list is deleted. */
284 typedef struct { /* All display lists */
290 #define ISENABLED_TEXTURE_2D (1<<0)
291 #define ISENABLED_TEXTURE_GEN_S (1<<1)
292 #define ISENABLED_TEXTURE_GEN_T (1<<2)
293 #define ISENABLED_LIGHTING (1<<3)
294 #define ISENABLED_BLEND (1<<4)
295 #define ISENABLED_DEPTH_TEST (1<<5)
296 #define ISENABLED_CULL_FACE (1<<6)
297 #define ISENABLED_NORMALIZE (1<<7)
298 #define ISENABLED_FOG (1<<8)
299 #define ISENABLED_COLMAT (1<<9)
300 #define ISENABLED_VERT_ARRAY (1<<10)
301 #define ISENABLED_NORM_ARRAY (1<<11)
302 #define ISENABLED_TEX_ARRAY (1<<12)
303 #define ISENABLED_COLOR_ARRAY (1<<13)
306 typedef struct { /* global state */
308 vert_set set; /* set being built */
310 int compiling_list; /* list id if inside glNewList; 0 means immediate */
311 int replaying_list; /* depth of call stack to glCallList */
312 int compiling_verts; /* inside glBegin */
314 list_set lists; /* saved lists */
315 unsigned long enabled;
320 static jwzgles_state global_state = { { 0, }, 0, 0, 0, { 0, }, 0, };
321 static jwzgles_state *state = &global_state;
325 # define LOG(A) fprintf(stderr,"jwzgles: " A "\n")
326 # define LOG1(A,B) fprintf(stderr,"jwzgles: " A "\n",B)
327 # define LOG2(A,B,C) fprintf(stderr,"jwzgles: " A "\n",B,C)
328 # define LOG3(A,B,C,D) fprintf(stderr,"jwzgles: " A "\n",B,C,D)
329 # define LOG4(A,B,C,D,E) fprintf(stderr,"jwzgles: " A "\n",B,C,D,E)
330 # define LOG5(A,B,C,D,E,F) fprintf(stderr,"jwzgles: " A "\n",B,C,D,E,F)
331 # define LOG6(A,B,C,D,E,F,G) fprintf(stderr,"jwzgles: " A "\n",B,C,D,E,F,G)
332 # define LOG7(A,B,C,D,E,F,G,H) fprintf(stderr,"jwzgles: " A "\n",B,C,D,E,F,G,H)
333 # define LOG8(A,B,C,D,E,F,G,H,I)\
334 fprintf(stderr,"jwzgles: "A "\n",B,C,D,E,F,G,H,I)
335 # define LOG9(A,B,C,D,E,F,G,H,I,J)\
336 fprintf(stderr,"jwzgles: "A "\n",B,C,D,E,F,G,H,I,J)
337 # define LOG10(A,B,C,D,E,F,G,H,I,J,K)\
338 fprintf(stderr,"jwzgles: "A "\n",B,C,D,E,F,G,H,I,J,K)
339 # define LOG17(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R)\
340 fprintf(stderr,"jwzgles: "A "\n",B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R)
341 # define CHECK(S) check_gl_error(S)
343 # define LOG(A) /* */
344 # define LOG1(A,B) /* */
345 # define LOG2(A,B,C) /* */
346 # define LOG3(A,B,C,D) /* */
347 # define LOG4(A,B,C,D,E) /* */
348 # define LOG5(A,B,C,D,E,F) /* */
349 # define LOG6(A,B,C,D,E,F,G) /* */
350 # define LOG7(A,B,C,D,E,F,G,H) /* */
351 # define LOG8(A,B,C,D,E,F,G,H,I) /* */
352 # define LOG9(A,B,C,D,E,F,G,H,I,J) /* */
353 # define LOG10(A,B,C,D,E,F,G,H,I,J,K) /* */
354 # define LOG17(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R) /* */
355 # define CHECK(S) /* */
360 mode_desc (int mode) /* for debugging messages */
363 # define SS(X) case GL_##X: return STRINGIFY(X);
367 SS(AMBIENT_AND_DIFFUSE)
383 SS(COLOR_ARRAY_BUFFER_BINDING);
385 SS(COLOR_MATERIAL_FACE)
386 SS(COLOR_MATERIAL_PARAMETER)
398 SS(ELEMENT_ARRAY_BUFFER)
411 SS(INVALID_OPERATION)
419 SS(LIGHT_MODEL_AMBIENT)
420 SS(LIGHT_MODEL_COLOR_CONTROL)
421 SS(LIGHT_MODEL_LOCAL_VIEWER)
422 SS(LIGHT_MODEL_TWO_SIDE)
425 SS(LINEAR_MIPMAP_LINEAR)
426 SS(LINEAR_MIPMAP_NEAREST)
437 SS(NEAREST_MIPMAP_LINEAR)
438 SS(NEAREST_MIPMAP_NEAREST)
441 SS(NORMAL_ARRAY_BUFFER_BINDING);
444 SS(ONE_MINUS_DST_ALPHA)
445 SS(ONE_MINUS_DST_COLOR)
446 SS(ONE_MINUS_SRC_ALPHA)
447 SS(ONE_MINUS_SRC_COLOR)
452 SS(POLYGON_OFFSET_FILL)
468 SS(SEPARATE_SPECULAR_COLOR)
477 SS(SRC_ALPHA_SATURATE)
482 SS(STENCIL_BUFFER_BIT)
494 SS(TEXTURE_ALPHA_SIZE)
495 SS(TEXTURE_BINDING_2D)
496 SS(TEXTURE_BLUE_SIZE)
498 SS(TEXTURE_BORDER_COLOR)
499 SS(TEXTURE_COMPONENTS)
500 SS(TEXTURE_COORD_ARRAY)
501 SS(TEXTURE_COORD_ARRAY_BUFFER_BINDING);
503 SS(TEXTURE_ENV_COLOR)
510 SS(TEXTURE_GREEN_SIZE)
512 SS(TEXTURE_INTENSITY_SIZE)
513 SS(TEXTURE_LUMINANCE_SIZE)
514 SS(TEXTURE_MAG_FILTER)
515 SS(TEXTURE_MIN_FILTER)
523 SS(UNPACK_ROW_LENGTH)
525 SS(UNSIGNED_INT_8_8_8_8_REV)
530 SS(VERTEX_ARRAY_BUFFER_BINDING);
531 /*SS(COLOR_BUFFER_BIT) -- same value as GL_LIGHT0 */
533 case (GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT):
534 return "DEPTH_BUFFER_BIT | COLOR_BUFFER_BIT";
535 /* Oops, same as INVALID_ENUM.
536 case (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT):
537 return "DEPTH_BUFFER_BIT | STENCIL_BUFFER_BIT";
539 case (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT):
540 return "COLOR_BUFFER_BIT | STENCIL_BUFFER_BIT";
541 case (GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT):
542 return "DEPTH_BUFFER_BIT | COLOR_BUFFER_BIT | STENCIL_BUFFER_BIT";
545 static char buf[255];
546 sprintf (buf, "0x%04X", mode);
553 check_gl_error (const char *s)
555 GLenum i = glGetError();
556 if (i == GL_NO_ERROR) return;
557 fprintf (stderr, "jwzgles: GL ERROR: %s: %s\n", s, mode_desc(i));
564 make_room (const char *name, void **array, int span, int *count, int *size)
566 if (*count + 1 >= *size)
568 int new_size = (*count + 20) * 1.2; /* mildly exponential */
569 *array = realloc (*array, new_size * span);
570 Assert (*array, "out of memory");
571 /* LOG3("%s: grew %d -> %d", name, *size, new_size); */
578 jwzgles_glGenLists (int n)
583 Assert (!state->compiling_verts, "glGenLists not allowed inside glBegin");
585 /* Ensure space in state->lists, clear the one at the end, and tick counter
586 Note that lists are never really deleted, and we can never re-use elements
587 of this array. glDeleteLists zeroes out the contents of the list, but
588 the list ID is still valid for use with glNewList forever.
589 #### So maybe this should be a linked list instead of an array.
591 for (i = 0; i < n; i++)
595 make_room ("glGenLists",
596 (void **) &state->lists.lists,
597 sizeof (*state->lists.lists),
598 &state->lists.count, &state->lists.size);
599 state->lists.count++;
600 id = state->lists.count;
601 L = &state->lists.lists[id-1];
603 memset (L, 0, sizeof (*L));
605 if (ret == 0) ret = id;
606 LOG1("glGenLists -> %d", L->id);
609 /* Return the ID of the first list allocated */
616 jwzgles_glNewList (int id, int mode)
619 Assert (id > 0 && id <= state->lists.count, "glNewList: bogus ID");
620 Assert (mode == GL_COMPILE, "glNewList: bad mode");
621 Assert (!state->compiling_verts, "glNewList not allowed inside glBegin");
622 Assert (!state->compiling_list, "nested glNewList");
623 Assert (state->set.count == 0, "missing glEnd");
625 L = &state->lists.lists[id-1];
626 Assert (L->id == id, "glNewList corrupted");
628 if (L->count != 0) jwzgles_glDeleteLists (L->id, 1); /* Overwriting */
629 Assert (L->count == 0, "glNewList corrupted");
631 state->compiling_list = id;
633 LOG1("glNewList -> %d", id);
637 static void save_arrays (list_fn *, int);
638 static void restore_arrays (list_fn *, int);
639 static void copy_array_data (draw_array *, int, const char *);
640 static void optimize_arrays (void);
643 jwzgles_glEndList (void)
645 Assert (state->compiling_list, "extra glEndList");
646 Assert (state->set.count == 0, "missing glEnd");
647 Assert (!state->compiling_verts, "glEndList not allowed inside glBegin");
648 LOG1("glEndList %d", state->compiling_list);
650 state->compiling_list = 0;
655 list_push (const char * const name,
656 list_fn_cb fn, fn_proto proto, void_int *av)
662 Assert (state->compiling_list > 0, "not inside glNewList");
663 Assert (state->compiling_list <= state->lists.count, "glNewList corrupted");
665 L = &state->lists.lists[state->compiling_list-1];
666 Assert (L, "glNewList: no list");
668 make_room ("glNewLists",
669 (void **) &L->fns, sizeof (*L->fns),
670 &L->count, &L->size);
671 memset (&L->fns[L->count], 0, sizeof (*L->fns));
672 F = L->fns + L->count;
677 if (proto != PROTO_VOID)
678 for (i = 0; i < countof(F->argv); i++)
684 LOG1 (" push %-12s", name);
687 if (fn == (list_fn_cb) &jwzgles_glBegin ||
688 fn == (list_fn_cb) &jwzgles_glFrontFace ||
689 fn == (list_fn_cb) &jwzgles_glEnable ||
690 fn == (list_fn_cb) &jwzgles_glDisable ||
691 fn == (list_fn_cb) &jwzgles_glEnableClientState ||
692 fn == (list_fn_cb) &jwzgles_glDisableClientState ||
693 fn == (list_fn_cb) &jwzgles_glShadeModel ||
694 fn == (list_fn_cb) &jwzgles_glMatrixMode)
695 LOG2 (" push %-12s %s", name, mode_desc (av[0].i));
697 LOG2 (" push %-12s %d", name, av[0].i);
700 LOG2 (" push %-12s %7.3f", name, av[0].f);
703 if (fn == (list_fn_cb) &jwzgles_glBindTexture ||
704 fn == (list_fn_cb) &jwzgles_glBindBuffer)
705 LOG3 (" push %-12s %s %d", name, mode_desc (av[0].i), av[1].i);
707 LOG3 (" push %-12s %d %d", name, av[0].i, av[1].i);
710 LOG3 (" push %-12s %7.3f %7.3f", name, av[0].f, av[1].f);
713 LOG3 (" push %-12s %s %7.3f", name, mode_desc (av[0].i), av[1].f);
717 if (fn == (list_fn_cb) &jwzgles_glDrawArrays ||
718 fn == (list_fn_cb) &jwzgles_glTexParameteri)
719 LOG4 (" push %-12s %s %d %d", name, mode_desc (av[0].i),
722 LOG4 (" push %-12s %d %d %d", name, av[0].i, av[1].i, av[2].i);
725 LOG4 (" push %-12s %7.3f %7.3f %7.3f", name, av[0].f, av[1].f, av[2].f);
728 LOG4 (" push %-12s %s %s %7.3f", name,
729 mode_desc(av[0].i), mode_desc(av[1].i), av[2].f);
732 LOG5 (" push %-12s %d %d %d %d", name,
733 av[0].i, av[1].i, av[2].i, av[3].i);
736 LOG5 (" push %-12s %7.3f %7.3f %7.3f %7.3f", name,
737 av[0].f, av[1].f, av[2].f, av[3].f);
740 LOG6 (" push %-12s %s %3.1f %3.1f %3.1f %3.1f", name, mode_desc (av[0].i),
741 av[1].f, av[2].f, av[3].f, av[4].f);
744 LOG6 (" push %-12s %s %d %d %d %d", name, mode_desc (av[0].i),
745 av[1].i, av[2].i, av[3].i, av[4].i);
748 LOG7 (" push %-12s %s %-8s %3.1f %3.1f %3.1f %3.1f", name,
749 mode_desc (av[0].i), mode_desc (av[1].i),
750 av[2].f, av[3].f, av[4].f, av[5].f);
753 LOG7 (" push %-12s %s %-8s %3d %3d %3d %3d", name,
754 mode_desc (av[0].i), mode_desc (av[1].i),
755 av[2].i, av[3].i, av[4].i, av[5].i);
758 LOG17 (" push %-12s ["
759 "%8.3f %8.3f %8.3f %8.3f " "\n\t\t\t "
760 "%8.3f %8.3f %8.3f %8.3f " "\n\t\t\t "
761 "%8.3f %8.3f %8.3f %8.3f " "\n\t\t\t "
762 "%8.3f %8.3f %8.3f %8.3f ]",
764 av[0].f, av[1].f, av[2].f, av[3].f,
765 av[4].f, av[5].f, av[6].f, av[7].f,
766 av[8].f, av[9].f, av[10].f, av[11].f,
767 av[12].f, av[13].f, av[14].f, av[15].f);
770 Assert (0, "bogus prototype");
775 if (proto == PROTO_ARRAYS) /* glDrawArrays */
776 save_arrays (F, av[1].i + av[2].i);
783 jwzgles_glBegin (int mode)
785 Assert (!state->compiling_verts, "nested glBegin");
786 state->compiling_verts++;
788 /* Only these commands are allowed inside glBegin:
790 glVertex -- not allowed outside
801 glArrayElement -- not allowed outside
808 if (!state->replaying_list)
809 LOG2 ("%sglBegin %s",
810 (state->compiling_list || state->replaying_list ? " " : ""),
813 Assert (state->set.count == 0, "glBegin corrupted");
814 state->set.mode = mode;
815 state->set.count = 0;
816 state->set.ncount = 0;
817 state->set.tcount = 0;
818 state->set.ccount = 0;
823 jwzgles_glDeleteLists (int id0, int range)
825 Assert (!state->compiling_verts, "glDeleteLists not allowed inside glBegin");
827 if (state->compiling_list)
832 list_push ("glDeleteLists", (list_fn_cb) &jwzgles_glDeleteLists,
839 if (!state->replaying_list)
840 LOG2 ("glDeleteLists %d %d", id0, range);
842 for (id = id0 + range - 1; id >= id0; id--)
846 if (id == 0) continue; /* People do this stupid thing */
847 if (id > state->lists.count) break; /* this too */
848 Assert (id > 0 && id <= state->lists.count,
849 "glDeleteLists: bogus ID");
850 L = &state->lists.lists[id-1];
851 Assert (L->id == id, "glDeleteLists corrupted");
853 for (i = 0; i < L->count; i++)
855 list_fn *lf = &L->fns[i];
859 for (j = 0; j < 4; j++)
860 /* If there's a binding, 'data' is an index, not a ptr. */
861 if (!lf->arrays[j].binding &&
863 free (lf->arrays[j].data);
870 glDeleteBuffers (1, &L->buffer);
872 memset (L, 0, sizeof (*L));
880 jwzgles_glIsList (GLuint id)
882 return (id > 0 && id < state->lists.count);
888 jwzgles_glNormal3fv (const GLfloat *v)
890 if (state->compiling_list && !state->compiling_verts)
896 list_push ("glNormal3f", (list_fn_cb) &jwzgles_glNormal3f,
901 if (!state->replaying_list)
902 LOG5 ("%s%sglNormal3f %7.3f %7.3f %7.3f",
903 (state->compiling_list || state->replaying_list ? " " : ""),
904 (state->compiling_verts ? " rec " : ""),
907 if (state->compiling_verts) /* inside glBegin */
909 state->set.cnorm.x = v[0];
910 state->set.cnorm.y = v[1];
911 state->set.cnorm.z = v[2];
913 if (state->set.count > 0 && state->set.ncount == 1) /* not first! */
916 else /* outside glBegin */
918 glNormal3f (v[0], v[1], v[2]);
926 jwzgles_glNormal3f (GLfloat x, GLfloat y, GLfloat z)
932 jwzgles_glNormal3fv (v);
937 jwzgles_glTexCoord4fv (const GLfloat *v)
939 if (state->compiling_list && !state->compiling_verts)
946 list_push ("glTexCoord4f", (list_fn_cb) &jwzgles_glTexCoord4f,
951 if (!state->replaying_list)
952 LOG6 ("%s%sglTexCoord4f %7.3f %7.3f %7.3f %7.3f",
953 (state->compiling_list || state->replaying_list ? " " : ""),
954 (state->compiling_verts ? " rec " : ""),
955 v[0], v[1], v[2], v[3]);
957 Assert (state->compiling_verts, "glTexCoord4fv outside glBegin");
959 if (state->compiling_verts) /* inside glBegin */
961 state->set.ctex.s = v[0];
962 state->set.ctex.t = v[1];
963 state->set.ctex.r = v[2];
964 state->set.ctex.q = v[3];
966 if (state->set.count > 0 && state->set.tcount == 1) /* not first! */
974 jwzgles_glTexCoord4f (GLfloat s, GLfloat t, GLfloat r, GLfloat q)
981 jwzgles_glTexCoord4fv (v);
986 jwzgles_glTexCoord3fv (const GLfloat *v)
993 jwzgles_glTexCoord4fv (vv);
998 jwzgles_glTexCoord2fv (const GLfloat *v)
1005 jwzgles_glTexCoord4fv (vv);
1010 jwzgles_glTexCoord3f (GLfloat s, GLfloat t, GLfloat r)
1012 jwzgles_glTexCoord4f (s, t, r, 1);
1017 jwzgles_glTexCoord2f (GLfloat s, GLfloat t)
1019 jwzgles_glTexCoord4f (s, t, 0, 1);
1024 jwzgles_glTexCoord1f (GLfloat s)
1026 jwzgles_glTexCoord4f (s, 0, 0, 1);
1030 /* glColor: GLfloat */
1033 jwzgles_glColor4fv (const GLfloat *v)
1035 if (state->compiling_list && !state->compiling_verts)
1042 list_push ("glColor4f", (list_fn_cb) &jwzgles_glColor4f,
1047 if (!state->replaying_list)
1048 LOG6 ("%s%sglColor4f %7.3f %7.3f %7.3f %7.3f",
1049 (state->compiling_list || state->replaying_list ? " " : ""),
1050 (state->compiling_verts ? " rec " : ""),
1051 v[0], v[1], v[2], v[3]);
1053 if (state->compiling_verts) /* inside glBegin */
1055 state->set.ccolor.r = v[0];
1056 state->set.ccolor.g = v[1];
1057 state->set.ccolor.b = v[2];
1058 state->set.ccolor.a = v[3];
1059 state->set.ccount++;
1060 if (state->set.count > 0 && state->set.ccount == 1) /* not first! */
1061 state->set.ccount++;
1063 else /* outside glBegin */
1065 glColor4f (v[0], v[1], v[2], v[3]);
1073 jwzgles_glColor4f (GLfloat r, GLfloat g, GLfloat b, GLfloat a)
1080 jwzgles_glColor4fv (v);
1084 jwzgles_glColor3f (GLfloat r, GLfloat g, GLfloat b)
1086 jwzgles_glColor4f (r, g, b, 1);
1090 jwzgles_glColor3fv (const GLfloat *v)
1092 jwzgles_glColor3f (v[0], v[1], v[2]);
1096 /* glColor: GLdouble */
1099 jwzgles_glColor4d (GLdouble r, GLdouble g, GLdouble b, GLdouble a)
1101 jwzgles_glColor4f (r, g, b, a);
1105 jwzgles_glColor4dv (const GLdouble *v)
1107 jwzgles_glColor4d (v[0], v[1], v[2], v[3]);
1111 jwzgles_glColor3d (GLdouble r, GLdouble g, GLdouble b)
1113 jwzgles_glColor4d (r, g, b, 1.0);
1117 jwzgles_glColor3dv (const GLdouble *v)
1119 jwzgles_glColor3d (v[0], v[1], v[2]);
1123 /* glColor: GLint (INT_MIN - INT_MAX) */
1126 jwzgles_glColor4i (GLint r, GLint g, GLint b, GLint a)
1128 /* -0x8000000 - 0x7FFFFFFF => 0.0 - 1.0 */
1129 jwzgles_glColor4f (0.5 + (GLfloat) r / 0xFFFFFFFF,
1130 0.5 + (GLfloat) g / 0xFFFFFFFF,
1131 0.5 + (GLfloat) b / 0xFFFFFFFF,
1132 0.5 + (GLfloat) a / 0xFFFFFFFF);
1136 jwzgles_glColor4iv (const GLint *v)
1138 jwzgles_glColor4i (v[0], v[1], v[2], v[3]);
1143 jwzgles_glColor3i (GLint r, GLint g, GLint b)
1145 jwzgles_glColor4i (r, g, b, 0x7FFFFFFF);
1149 jwzgles_glColor3iv (const GLint *v)
1151 jwzgles_glColor3i (v[0], v[1], v[2]);
1155 /* glColor: GLuint (0 - UINT_MAX) */
1158 jwzgles_glColor4ui (GLuint r, GLuint g, GLuint b, GLuint a)
1160 /* 0 - 0xFFFFFFFF => 0.0 - 1.0 */
1161 jwzgles_glColor4f ((GLfloat) r / 0xFFFFFFFF,
1162 (GLfloat) g / 0xFFFFFFFF,
1163 (GLfloat) b / 0xFFFFFFFF,
1164 (GLfloat) a / 0xFFFFFFFF);
1168 jwzgles_glColor4uiv (const GLuint *v)
1170 jwzgles_glColor4ui (v[0], v[1], v[2], v[3]);
1174 jwzgles_glColor3ui (GLuint r, GLuint g, GLuint b)
1176 jwzgles_glColor4ui (r, g, b, 0xFFFFFFFF);
1180 jwzgles_glColor3uiv (const GLuint *v)
1182 jwzgles_glColor3ui (v[0], v[1], v[2]);
1186 /* glColor: GLshort (SHRT_MIN - SHRT_MAX) */
1189 jwzgles_glColor4s (GLshort r, GLshort g, GLshort b, GLshort a)
1191 /* -0x8000 - 0x7FFF => 0.0 - 1.0 */
1192 jwzgles_glColor4f (0.5 + (GLfloat) r / 0xFFFF,
1193 0.5 + (GLfloat) g / 0xFFFF,
1194 0.5 + (GLfloat) b / 0xFFFF,
1195 0.5 + (GLfloat) a / 0xFFFF);
1199 jwzgles_glColor4sv (const GLshort *v)
1201 jwzgles_glColor4s (v[0], v[1], v[2], v[3]);
1205 jwzgles_glColor3s (GLshort r, GLshort g, GLshort b)
1207 jwzgles_glColor4s (r, g, b, 0x7FFF);
1211 jwzgles_glColor3sv (const GLshort *v)
1213 jwzgles_glColor3s (v[0], v[1], v[2]);
1217 /* glColor: GLushort (0 - USHRT_MAX) */
1220 jwzgles_glColor4us (GLushort r, GLushort g, GLushort b, GLushort a)
1222 /* 0 - 0xFFFF => 0.0 - 1.0 */
1223 jwzgles_glColor4f ((GLfloat) r / 0xFFFF,
1224 (GLfloat) g / 0xFFFF,
1225 (GLfloat) b / 0xFFFF,
1226 (GLfloat) a / 0xFFFF);
1230 jwzgles_glColor4usv (const GLushort *v)
1232 jwzgles_glColor4us (v[0], v[1], v[2], v[3]);
1236 jwzgles_glColor3us (GLushort r, GLushort g, GLushort b)
1238 jwzgles_glColor4us (r, g, b, 0xFFFF);
1242 jwzgles_glColor3usv (const GLushort *v)
1244 jwzgles_glColor3us (v[0], v[1], v[2]);
1248 /* glColor: GLbyte (-128 - 127) */
1251 jwzgles_glColor4b (GLbyte r, GLbyte g, GLbyte b, GLbyte a)
1253 /* -128 - 127 => 0.0 - 1.0 */
1254 jwzgles_glColor4f (0.5 + (GLfloat) r / 255,
1255 0.5 + (GLfloat) g / 255,
1256 0.5 + (GLfloat) b / 255,
1257 0.5 + (GLfloat) a / 255);
1261 jwzgles_glColor4bv (const GLbyte *v)
1263 jwzgles_glColor4b (v[0], v[1], v[2], v[3]);
1267 jwzgles_glColor3b (GLbyte r, GLbyte g, GLbyte b)
1269 jwzgles_glColor4b (r, g, b, 127);
1273 jwzgles_glColor3bv (const GLbyte *v)
1275 jwzgles_glColor3b (v[0], v[1], v[2]);
1279 /* glColor: GLubyte (0 - 255) */
1282 jwzgles_glColor4ub (GLubyte r, GLubyte g, GLubyte b, GLubyte a)
1284 /* 0 - 255 => 0.0 - 1.0 */
1285 jwzgles_glColor4f (r / 255.0, g / 255.0, b / 255.0, a / 255.0);
1289 jwzgles_glColor4ubv (const GLubyte *v)
1291 jwzgles_glColor4ub (v[0], v[1], v[2], v[3]);
1295 jwzgles_glColor3ub (GLubyte r, GLubyte g, GLubyte b)
1297 jwzgles_glColor4ub (r, g, b, 255);
1301 jwzgles_glColor3ubv (const GLubyte *v)
1303 jwzgles_glColor3ub (v[0], v[1], v[2]);
1309 jwzgles_glMaterialfv (GLenum face, GLenum pname, const GLfloat *color)
1311 /* If this is called inside glBegin/glEnd with a front ambient color,
1312 then treat it the same as glColor: set the color of the upcoming
1315 Other faces or lighting types within glBegin are ignored.
1318 if (state->compiling_verts)
1320 if ((face == GL_FRONT ||
1321 face == GL_FRONT_AND_BACK) &&
1322 (pname == GL_AMBIENT ||
1323 pname == GL_DIFFUSE ||
1324 pname == GL_AMBIENT_AND_DIFFUSE))
1326 jwzgles_glColor4f (color[0], color[1], color[2], color[3]);
1327 state->set.materialistic++;
1330 LOG2 (" IGNORING glMaterialfv %s %s",
1331 mode_desc(face), mode_desc(pname));
1333 else if (state->compiling_list)
1342 list_push ("glMaterialfv", (list_fn_cb) &jwzgles_glMaterialfv,
1347 /* If this is called outside of glBegin/glEnd with a front
1348 ambient color, then the intent is presumably for that color
1349 to apply to the upcoming vertexes (which may be played back
1350 from a list that does not have vertex colors in it). In that
1351 case, the only way to make the colors show up is to call
1352 glColor() with GL_COLOR_MATERIAL enabled.
1354 I'm not sure if this will have other inappropriate side effects...
1356 if ((face == GL_FRONT ||
1357 face == GL_FRONT_AND_BACK) &&
1358 (pname == GL_AMBIENT ||
1359 pname == GL_DIFFUSE ||
1360 pname == GL_AMBIENT_AND_DIFFUSE))
1362 jwzgles_glEnable (GL_COLOR_MATERIAL);
1363 jwzgles_glColor4f (color[0], color[1], color[2], color[3]);
1366 /* OpenGLES seems to throw "invalid enum" for GL_FRONT -- but it
1367 goes ahead and sets the material anyway! No error if we just
1368 always use GL_FRONT_AND_BACK.
1370 if (face == GL_FRONT)
1371 face = GL_FRONT_AND_BACK;
1372 if (! state->replaying_list)
1373 LOG7 ("direct %-12s %s %s %7.3f %7.3f %7.3f %7.3f", "glMaterialfv",
1374 mode_desc(face), mode_desc(pname),
1375 color[0], color[1], color[2], color[3]);
1376 glMaterialfv (face, pname, color); /* the real one */
1377 CHECK("glMaterialfv");
1383 jwzgles_glMaterialiv (GLenum face, GLenum pname, const GLint *v)
1390 jwzgles_glMaterialfv (face, pname, vv);
1394 jwzgles_glMaterialf (GLenum face, GLenum pname, const GLfloat c)
1401 jwzgles_glMaterialfv (face, pname, vv);
1406 jwzgles_glMateriali (GLenum face, GLenum pname, const GLuint c)
1408 jwzgles_glMaterialf (face, pname, c);
1413 jwzgles_glColorMaterial (GLenum face, GLenum mode)
1415 Assert (!state->compiling_verts,
1416 "glColorMaterial not allowed inside glBegin");
1418 if (state->compiling_list)
1423 list_push ("glColorMaterial", (list_fn_cb) &jwzgles_glColorMaterial,
1428 /* No real analog to this distinction in OpenGLES, since color
1429 arrays don't distinguish between "color" and "material", */
1430 Assert (0, "glColorMaterial: unimplemented mode");
1439 jwzgles_glVertex4fv (const GLfloat *v)
1441 vert_set *s = &state->set;
1442 int count = s->count;
1444 Assert (state->compiling_verts, "glVertex4fv not inside glBegin");
1446 LOG5("%s rec glVertex4f %7.3f %7.3f %7.3f %7.3f",
1447 (state->compiling_list || state->replaying_list ? " " : ""),
1448 v[0], v[1], v[2], v[3]);
1450 if (count >= s->size - 1)
1452 int new_size = 20 + (s->size * 1.2);
1454 /* 4 arrays, different element sizes...
1455 We allocate all 4 arrays just in case we need them,
1456 but we might not end up using them all at the end.
1459 s->verts = (XYZW *) realloc (s->verts, new_size * sizeof (*s->verts));
1460 Assert (s->verts, "out of memory");
1462 s->norms = (XYZ *) realloc (s->norms, new_size * sizeof (*s->norms));
1463 Assert (s->norms, "out of memory");
1465 s->tex = (STRQ *) realloc (s->tex, new_size * sizeof (*s->tex));
1466 Assert (s->tex, "out of memory");
1468 s->color = (RGBA *) realloc (s->color, new_size * sizeof (*s->color));
1469 Assert (s->color, "out of memory");
1474 s->verts [count].x = v[0];
1475 s->verts [count].y = v[1];
1476 s->verts [count].z = v[2];
1477 s->verts [count].w = v[3];
1478 s->norms [count] = s->cnorm;
1479 s->tex [count] = s->ctex;
1480 s->color [count] = s->ccolor;
1486 jwzgles_glVertex4f (GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1493 jwzgles_glVertex4fv (v);
1497 jwzgles_glVertex4i (GLint x, GLint y, GLint z, GLint w)
1499 jwzgles_glVertex4f (x, y, z, w);
1503 jwzgles_glVertex3f (GLfloat x, GLfloat y, GLfloat z)
1510 jwzgles_glVertex4fv (v);
1514 jwzgles_glVertex3i (GLint x, GLint y, GLint z)
1516 jwzgles_glVertex3f (x, y, z);
1520 jwzgles_glVertex3fv (const GLfloat *v)
1522 jwzgles_glVertex3f (v[0], v[1], v[2]);
1526 jwzgles_glVertex3dv (const GLdouble *v)
1528 jwzgles_glVertex3f (v[0], v[1], v[2]);
1533 jwzgles_glVertex2f (GLfloat x, GLfloat y)
1539 jwzgles_glVertex3fv (v);
1543 jwzgles_glVertex2fv (const GLfloat *v)
1545 jwzgles_glVertex2f (v[0], v[1]);
1549 jwzgles_glVertex2i (GLint x, GLint y)
1551 jwzgles_glVertex2f (x, y);
1556 jwzgles_glLightiv (GLenum light, GLenum pname, const GLint *params)
1563 jwzgles_glLightfv (light, pname, v);
1567 jwzgles_glLightModeliv (GLenum pname, const GLint *params)
1574 jwzgles_glLightModelfv (pname, v);
1578 jwzgles_glFogiv (GLenum pname, const GLint *params)
1585 jwzgles_glFogfv (pname, v);
1589 jwzgles_glLighti (GLenum light, GLenum pname, GLint param)
1591 jwzgles_glLightf (light, pname, param);
1595 jwzgles_glLightModeli (GLenum pname, GLint param)
1597 jwzgles_glLightModelf (pname, param);
1601 jwzgles_glFogi (GLenum pname, GLint param)
1603 jwzgles_glFogf (pname, param);
1608 jwzgles_glRotated (GLdouble angle, GLdouble x, GLdouble y, GLdouble z)
1610 jwzgles_glRotatef (angle, x, y, z);
1615 jwzgles_glClipPlane (GLenum plane, const GLdouble *equation)
1617 Assert (state->compiling_verts, "glClipPlane not inside glBegin");
1618 Assert (0, "glClipPlane unimplemented"); /* no GLES equivalent... */
1623 jwzgles_glPolygonMode (GLenum face, GLenum mode)
1625 Assert (!state->compiling_verts, "not inside glBegin");
1626 if (state->compiling_list)
1631 list_push ("glPolygonMode", (list_fn_cb) &jwzgles_glPolygonMode,
1636 /* POINT and LINE don't exist in GLES */
1637 Assert (mode == GL_FILL, "glPolygonMode: unimplemented mode");
1643 jwzgles_glDrawBuffer (GLenum buf)
1645 Assert (!state->compiling_verts, "not inside glBegin");
1646 if (state->compiling_list)
1650 list_push ("glDrawBuffer", (list_fn_cb) &jwzgles_glDrawBuffer,
1655 /* Assert (buf == GL_BACK, "glDrawBuffer: back buffer only"); */
1656 # ifndef GL_VERSION_ES_CM_1_0 /* not compiling against OpenGLES 1.x */
1657 if (! state->replaying_list)
1658 LOG1 ("direct %-12s", "glDrawBuffer");
1659 glDrawBuffer (buf); /* the real one */
1660 CHECK("glDrawBuffer");
1666 /* Given an array of sets of 4 elements of arbitrary size, convert it
1667 to an array of sets of 6 elements instead: ABCD becomes ABC BCD.
1670 cq2t (unsigned char **arrayP, int stride, int count)
1672 int count2 = count * 6 / 4;
1673 int size = stride * count;
1674 int size2 = stride * count2;
1675 const unsigned char *oarray, *in;
1676 unsigned char *array2, *oarray2, *out;
1680 if (!oarray || count == 0)
1683 array2 = (unsigned char *) malloc (size2);
1684 Assert (array2, "out of memory");
1689 for (i = 0; i < count / 4; i++)
1691 const unsigned char *a, *b, *c, *d; /* the 4 corners */
1692 a = in; in += stride;
1693 b = in; in += stride;
1694 c = in; in += stride;
1695 d = in; in += stride;
1697 # define PUSH(IN) do { \
1698 const unsigned char *ii = IN; \
1700 for (j = 0; j < stride; j++) { \
1704 PUSH (a); PUSH (b); PUSH (d); /* the 2 triangles */
1705 PUSH (b); PUSH (c); PUSH (d);
1709 Assert (in == oarray + size, "convert_quads corrupted");
1710 Assert (out == oarray2 + size2, "convert_quads corrupted");
1718 /* Convert all coordinates in a GL_QUADS vert_set to GL_TRIANGLES.
1721 convert_quads_to_triangles (vert_set *s)
1724 Assert (s->mode == GL_QUADS, "convert_quads bad mode");
1726 cq2t ((unsigned char **) &s->verts, sizeof(*s->verts), s->count);
1727 cq2t ((unsigned char **) &s->norms, sizeof(*s->norms), s->count);
1728 cq2t ((unsigned char **) &s->tex, sizeof(*s->tex), s->count);
1729 cq2t ((unsigned char **) &s->color, sizeof(*s->color), s->count);
1732 s->mode = GL_TRIANGLES;
1737 jwzgles_glEnd (void)
1739 vert_set *s = &state->set;
1740 int was_norm, was_tex, was_color, was_mat;
1741 int is_norm, is_tex, is_color, is_mat;
1743 Assert (state->compiling_verts == 1, "missing glBegin");
1744 state->compiling_verts--;
1746 Assert (!state->replaying_list, "how did glEnd get into a display list?");
1748 if (!state->replaying_list)
1750 LOG5 ("%s [V = %d, N = %d, T = %d, C = %d]",
1751 (state->compiling_list || state->replaying_list ? " " : ""),
1752 s->count, s->ncount, s->tcount, s->ccount);
1754 (state->compiling_list || state->replaying_list ? " " : ""));
1757 if (s->count == 0) return;
1759 if (s->mode == GL_QUADS)
1760 convert_quads_to_triangles (s);
1761 else if (s->mode == GL_QUAD_STRIP)
1762 s->mode = GL_TRIANGLE_STRIP; /* They do the same thing! */
1763 else if (s->mode == GL_POLYGON)
1764 s->mode = GL_TRIANGLE_FAN; /* They do the same thing! */
1766 glVertexPointer (4, GL_FLOAT, sizeof(*s->verts), s->verts); /* XYZW */
1767 glNormalPointer ( GL_FLOAT, sizeof(*s->norms), s->norms); /* XYZ */
1768 glTexCoordPointer (4, GL_FLOAT, sizeof(*s->tex), s->tex); /* STRQ */
1769 glColorPointer (4, GL_FLOAT, sizeof(*s->color), s->color); /* RGBA */
1770 CHECK("glColorPointer");
1772 /* If there were no calls to glNormal3f inside of glBegin/glEnd,
1773 don't bother enabling the normals array.
1775 If there was exactly *one* call to glNormal3f inside of glBegin/glEnd,
1776 and it was before the first glVertex3f, then also don't enable the
1777 normals array, but do emit that call to glNormal3f before calling
1780 Likewise for texture coordinates and colors.
1782 Be careful to leave the arrays' enabled/disabled state the same as
1783 before, or a later caller might end up using one of our arrays by
1784 mistake. #### Actually this isn't quite right: if glEnd is in a
1785 list, it saves the trailing enable/disable calls in the list, instead
1786 if restoring them to what their state was before the list was run.
1788 was_norm = jwzgles_glIsEnabled (GL_NORMAL_ARRAY);
1789 was_tex = jwzgles_glIsEnabled (GL_TEXTURE_COORD_ARRAY);
1790 was_color = jwzgles_glIsEnabled (GL_COLOR_ARRAY);
1791 was_mat = jwzgles_glIsEnabled (GL_COLOR_MATERIAL);
1793 /* If we're executing glEnd in immediate mode, not from inside a display
1794 list (which is the only way it happens, because glEnd doesn't go into
1795 display lists), make sure we're not stomping on a saved buffer list:
1796 in immediate mode, vertexes are client-side only.
1798 if (! state->compiling_list)
1799 jwzgles_glBindBuffer (GL_ARRAY_BUFFER, 0);
1804 jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
1810 jwzgles_glNormal3f (s->cnorm.x, s->cnorm.y, s->cnorm.z);
1811 jwzgles_glDisableClientState (GL_NORMAL_ARRAY);
1817 jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
1823 jwzgles_glTexCoord4f (s->ctex.s, s->ctex.t, s->ctex.r, s->ctex.q);
1824 jwzgles_glDisableClientState (GL_TEXTURE_COORD_ARRAY);
1830 jwzgles_glEnableClientState (GL_COLOR_ARRAY);
1836 jwzgles_glColor4f (s->ccolor.r, s->ccolor.g, s->ccolor.b, s->ccolor.a);
1837 jwzgles_glDisableClientState (GL_COLOR_ARRAY);
1840 jwzgles_glEnableClientState (GL_VERTEX_ARRAY);
1842 /* We translated the glMaterial calls to per-vertex colors, which are
1843 of the glColor sort, not the glMaterial sort, so automatically
1844 turn on material mapping. Maybe this is a bad idea.
1846 if (s->materialistic && !jwzgles_glIsEnabled (GL_COLOR_MATERIAL))
1849 jwzgles_glEnable (GL_COLOR_MATERIAL);
1854 glBindBuffer (GL_ARRAY_BUFFER, 0); /* This comes later. */
1855 jwzgles_glDrawArrays (s->mode, 0, s->count);
1856 glBindBuffer (GL_ARRAY_BUFFER, 0); /* Keep out of others' hands */
1858 # define RESET(VAR,FN,ARG) do { \
1859 if (is_##VAR != was_##VAR) { \
1860 if (was_##VAR) jwzgles_glEnable##FN (ARG); \
1861 else jwzgles_glDisable##FN (ARG); \
1863 RESET (norm, ClientState, GL_NORMAL_ARRAY);
1864 RESET (tex, ClientState, GL_TEXTURE_COORD_ARRAY);
1865 RESET (color, ClientState, GL_COLOR_ARRAY);
1866 RESET (mat, , GL_COLOR_MATERIAL);
1873 s->materialistic = 0;
1877 /* The display list is full of calls to glDrawArrays(), plus saved arrays
1878 of the values we need to restore before calling it. "Restore" means
1879 "ship them off to the GPU before each call".
1881 So instead, this function walks through the display list and
1882 combines all of those vertex, normal, texture and color values into
1883 a single VBO array; ships those values off to the GPU *once* at the
1884 time of glEndList; and when running the list with glCallList, the
1885 values are already on the GPU and don't need to be sent over again.
1887 The VBO persists in the GPU until the display list is deleted.
1890 optimize_arrays (void)
1892 list *L = &state->lists.lists[state->compiling_list-1];
1895 int combo_count = 0;
1897 GLuint buf_name = 0;
1899 Assert (state->compiling_list, "not compiling a list");
1900 Assert (L, "no list");
1901 Assert (!L->buffer, "list already has a buffer");
1903 glGenBuffers (1, &buf_name);
1904 CHECK("glGenBuffers");
1905 if (! buf_name) return;
1907 L->buffer = buf_name;
1909 /* Go through the list and dump the contents of the various saved arrays
1910 into one large array.
1912 for (i = 0; i < L->count; i++)
1914 list_fn *F = &L->fns[i];
1918 /* count = F->argv[2].i;*/ /* 3rd arg to glDrawArrays */
1920 for (j = 0; j < 4; j++)
1922 draw_array *A = &F->arrays[j];
1923 int ocount = combo_count;
1925 /* If some caller is using arrays that don't have floats in them,
1926 we just leave them as-is and ship them over at each call.
1927 Doubt this ever really happens.
1929 if (A->type != GL_FLOAT)
1932 if (! A->data) /* No array. */
1935 Assert (A->bytes > 0, "no bytes in draw_array");
1936 Assert (((unsigned long) A->data > 0xFFFF),
1937 "buffer data not a pointer");
1939 combo_count += A->bytes / sizeof(*combo);
1940 make_room ("optimize_arrays",
1941 (void **) &combo, sizeof(*combo),
1942 &combo_count, &combo_size);
1943 memcpy (combo + ocount, A->data, A->bytes);
1944 A->binding = buf_name;
1946 /* 'data' is now the byte offset into the VBO. */
1947 A->data = (void *) (ocount * sizeof(*combo));
1948 /* LOG3(" loaded %lu floats to pos %d of buffer %d",
1949 A->bytes / sizeof(*combo), ocount, buf_name); */
1953 if (combo_count == 0) /* Nothing to do! */
1955 if (combo) free (combo);
1956 glDeleteBuffers (1, &buf_name);
1961 glBindBuffer (GL_ARRAY_BUFFER, buf_name);
1962 glBufferData (GL_ARRAY_BUFFER,
1963 combo_count * sizeof (*combo),
1966 glBindBuffer (GL_ARRAY_BUFFER, 0); /* Keep out of others' hands */
1968 LOG3(" loaded %d floats of list %d into VBO %d",
1969 combo_count, state->compiling_list, buf_name);
1973 for (i = 0; i < combo_count; i++)
1976 fprintf (stderr, "\njwzgles: %4d: ", i);
1977 fprintf (stderr, " %7.3f", combo[i]);
1979 fprintf (stderr, "\n");
1983 if (combo) free (combo);
1988 jwzgles_glCallList (int id)
1990 if (state->compiling_list)
1992 /* Yes, you can call lists inside of lists.
1993 Yes, recursion would be a mistake. */
1996 list_push ("glCallList", (list_fn_cb) &jwzgles_glCallList, PROTO_I, vv);
2003 state->replaying_list++;
2006 fprintf (stderr, "\n");
2007 LOG1 ("glCallList %d", id);
2010 Assert (id > 0 && id <= state->lists.count, "glCallList: bogus ID");
2011 L = &state->lists.lists[id-1];
2012 Assert (id == L->id, "glCallList corrupted");
2014 for (i = 0; i < L->count; i++)
2016 list_fn *F = &L->fns[i];
2017 list_fn_cb fn = F->fn;
2018 void_int *av = F->argv;
2022 LOG1 (" call %-12s", F->name);
2023 ((void (*) (void)) fn) ();
2027 if (fn == (list_fn_cb) &jwzgles_glBegin ||
2028 fn == (list_fn_cb) &jwzgles_glFrontFace ||
2029 fn == (list_fn_cb) &jwzgles_glEnable ||
2030 fn == (list_fn_cb) &jwzgles_glDisable ||
2031 fn == (list_fn_cb) &jwzgles_glEnableClientState ||
2032 fn == (list_fn_cb) &jwzgles_glDisableClientState ||
2033 fn == (list_fn_cb) &jwzgles_glShadeModel ||
2034 fn == (list_fn_cb) &jwzgles_glMatrixMode)
2035 LOG2 (" call %-12s %s", F->name, mode_desc (av[0].i));
2037 LOG2 (" call %-12s %d", F->name, av[0].i);
2038 ((void (*) (int)) fn) (av[0].i);
2042 LOG2 (" call %-12s %7.3f", F->name, av[0].f);
2043 ((void (*) (GLfloat)) fn) (av[0].f);
2047 if (fn == (list_fn_cb) &jwzgles_glBindTexture ||
2048 fn == (list_fn_cb) &jwzgles_glBindBuffer)
2049 LOG3 (" call %-12s %s %d", F->name,
2050 mode_desc (av[0].i), av[1].i);
2052 LOG3 (" call %-12s %d %d", F->name, av[0].i, av[1].i);
2053 ((void (*) (int, int)) fn) (av[0].i, av[1].i);
2057 LOG3 (" call %-12s %7.3f %7.3f", F->name, av[0].f, av[1].f);
2058 ((void (*) (GLfloat, GLfloat)) fn) (av[0].f, av[1].f);
2062 LOG3 (" call %-12s %s %7.3f", F->name,
2063 mode_desc (av[0].f), av[1].f);
2064 ((void (*) (GLint, GLfloat)) fn) (av[0].i, av[1].f);
2067 case PROTO_III: III:
2068 if (fn == (list_fn_cb) &jwzgles_glDrawArrays ||
2069 fn == (list_fn_cb) &jwzgles_glTexParameteri)
2070 LOG4 (" call %-12s %s %d %d", F->name,
2071 mode_desc (av[0].i), av[1].i, av[2].i);
2073 LOG4 (" call %-12s %d %d %d", F->name,
2074 av[0].i, av[1].i, av[2].i);
2075 ((void (*) (int, int, int)) fn) (av[0].i, av[1].i, av[2].i);
2079 LOG4 (" call %-12s %7.3f %7.3f %7.3f", F->name,
2080 av[0].f, av[1].f, av[2].f);
2081 ((void (*) (GLfloat, GLfloat, GLfloat)) fn)
2082 (av[0].f, av[1].f, av[2].f);
2086 LOG4 (" call %-12s %s %s %7.3f", F->name,
2087 mode_desc (av[0].i), mode_desc (av[1].i), av[2].f);
2088 ((void (*) (int, int, GLfloat)) fn) (av[0].i, av[1].i, av[2].f);
2092 LOG5 (" call %-12s %d %d %d %d", F->name,
2093 av[0].i, av[1].i, av[2].i, av[3].i);
2094 ((void (*) (int, int, int, int)) fn)
2095 (av[0].i, av[1].i, av[2].i, av[3].i);
2099 LOG5 (" call %-12s %7.3f %7.3f %7.3f %7.3f", F->name,
2100 av[0].f, av[1].f, av[2].f, av[3].f);
2101 ((void (*) (GLfloat, GLfloat, GLfloat, GLfloat)) fn)
2102 (av[0].f, av[1].f, av[2].f, av[3].f);
2112 LOG6 (" call %-12s %s %3.1f %3.1f %3.1f %3.1f", F->name,
2113 mode_desc (av[0].i),
2114 av[1].f, av[2].f, av[3].f, av[4].f);
2115 ((void (*) (int, const GLfloat *)) fn) (av[0].i, v);
2126 LOG7 (" call %-12s %s %-8s %3.1f %3.1f %3.1f %3.1f", F->name,
2127 mode_desc (av[0].i), mode_desc (av[1].i),
2128 av[2].f, av[3].f, av[4].f, av[5].f);
2129 ((void (*) (int, int, const GLfloat *)) fn)
2130 (av[0].i, av[1].i, v);
2141 LOG6 (" call %-12s %s %3d %3d %3d %3d", F->name,
2142 mode_desc (av[0].i),
2143 av[1].i, av[2].i, av[3].i, av[4].i);
2144 ((void (*) (int, const int *)) fn) (av[0].i, v);
2155 LOG7 (" call %-12s %s %-8s %3d %3d %3d %3d", F->name,
2156 mode_desc (av[0].i), mode_desc (av[1].i),
2157 av[2].i, av[3].i, av[4].i, av[5].i);
2158 ((void (*) (int, int, const int *)) fn)
2159 (av[0].i, av[1].i, v);
2164 restore_arrays (F, av[1].i + av[2].i);
2172 for (i = 0; i < countof(m); i++)
2174 LOG17 (" call %-12s ["
2175 "%8.3f %8.3f %8.3f %8.3f " "\n\t\t\t "
2176 "%8.3f %8.3f %8.3f %8.3f " "\n\t\t\t "
2177 "%8.3f %8.3f %8.3f %8.3f " "\n\t\t\t "
2178 "%8.3f %8.3f %8.3f %8.3f ]",
2180 m[0], m[1], m[2], m[3],
2181 m[4], m[5], m[6], m[7],
2182 m[8], m[9], m[10], m[11],
2183 m[12], m[13], m[14], m[15]);
2184 ((void (*) (GLfloat *)) fn) (m);
2189 Assert (0, "bogus prototype");
2194 LOG1 ("glCallList %d done\n", id);
2196 state->replaying_list--;
2197 Assert (state->replaying_list >= 0, "glCallList corrupted");
2202 /* When we save a call to glDrawArrays into a display list, we also need to
2203 save the prevailing copy of the arrays that it will use, and restore them
2207 save_arrays (list_fn *F, int count)
2210 draw_array *A = (draw_array *) calloc (4, sizeof (*A));
2211 Assert (A, "out of memory");
2213 /* if (state->set.count > 0) */
2215 glGetIntegerv (GL_VERTEX_ARRAY_BUFFER_BINDING, &A[i].binding);
2216 glGetIntegerv (GL_VERTEX_ARRAY_SIZE, &A[i].size);
2217 glGetIntegerv (GL_VERTEX_ARRAY_TYPE, &A[i].type);
2218 glGetIntegerv (GL_VERTEX_ARRAY_STRIDE, &A[i].stride);
2219 glGetPointerv (GL_VERTEX_ARRAY_POINTER, &A[i].data);
2220 CHECK("glGetPointerv");
2221 copy_array_data (&A[i], count, "vert");
2225 if (state->set.ncount > 1)
2228 glGetIntegerv (GL_NORMAL_ARRAY_BUFFER_BINDING, &A[i].binding);
2229 glGetIntegerv (GL_NORMAL_ARRAY_TYPE, &A[i].type);
2230 glGetIntegerv (GL_NORMAL_ARRAY_STRIDE, &A[i].stride);
2231 glGetPointerv (GL_NORMAL_ARRAY_POINTER, &A[i].data);
2232 CHECK("glGetPointerv");
2233 copy_array_data (&A[i], count, "norm");
2237 if (state->set.tcount > 1)
2239 glGetIntegerv (GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING, &A[i].binding);
2240 glGetIntegerv (GL_TEXTURE_COORD_ARRAY_SIZE, &A[i].size);
2241 glGetIntegerv (GL_TEXTURE_COORD_ARRAY_TYPE, &A[i].type);
2242 glGetIntegerv (GL_TEXTURE_COORD_ARRAY_STRIDE, &A[i].stride);
2243 glGetPointerv (GL_TEXTURE_COORD_ARRAY_POINTER, &A[i].data);
2244 CHECK("glGetPointerv");
2245 copy_array_data (&A[i], count, "tex ");
2249 if (state->set.ccount > 1)
2251 glGetIntegerv (GL_COLOR_ARRAY_BUFFER_BINDING, &A[i].binding);
2252 glGetIntegerv (GL_COLOR_ARRAY_SIZE, &A[i].size);
2253 glGetIntegerv (GL_COLOR_ARRAY_TYPE, &A[i].type);
2254 glGetIntegerv (GL_COLOR_ARRAY_STRIDE, &A[i].stride);
2255 glGetPointerv (GL_COLOR_ARRAY_POINTER, &A[i].data);
2256 CHECK("glGetPointerv");
2257 copy_array_data (&A[i], count, "col ");
2260 /* Freed by glDeleteLists. */
2262 Assert (!F->arrays, "save_arrays corrupted");
2270 dump_array_data (draw_array *A, int count,
2271 const char *action, const char *name, const void *old)
2273 int bytes = count * A->stride;
2278 "jwzgles: %s %s %d %s %2d, %4d = %5d bind %d @ %d\n",
2280 A->size, mode_desc(A->type), A->stride,
2281 count, bytes, A->binding, (int) A->data);
2285 Assert (bytes == A->bytes, "array data corrupted");
2287 fprintf (stderr, "jwzgles: %s %s %d %s %2d, %4d = %5d @ %lX",
2289 A->size, mode_desc(A->type), A->stride,
2290 count, bytes, (unsigned long) A->data);
2292 fprintf (stderr, " / %lX", (unsigned long) old);
2293 fprintf (stderr, "\n");
2298 Assert (((unsigned long) A->data < 0xFFFF),
2299 "buffer binding should be a numeric index,"
2300 " but looks like a pointer");
2303 /* glGetBufferSubData doesn't actually exist in OpenGLES, but this
2304 was helpful for debugging on real OpenGL... */
2307 fprintf (stderr, "jwzgles: read back:\n");
2308 d = (GLfloat *) malloc (A->bytes);
2309 glGetBufferSubData (GL_ARRAY_BUFFER, (int) A->data,
2310 count * A->stride, (void *) d);
2311 CHECK("glGetBufferSubData");
2312 for (i = 0; i < count * A->size; i++)
2315 fprintf (stderr, "\njwzgles: %4d: ",
2316 i + (int) A->data / sizeof(GLfloat));
2317 fprintf (stderr, " %7.3f", d[i]);
2319 fprintf (stderr, "\n");
2326 unsigned char *b = (unsigned char *) A->data;
2328 if ((unsigned long) A->data < 0xFFFF)
2330 Assert (0, "buffer data not a pointer");
2333 for (i = 0; i < count; i++)
2336 GLfloat *f = (GLfloat *) b;
2338 if (s == 0) s = 3; /* normals */
2339 fprintf (stderr, "jwzgles: ");
2340 for (j = 0; j < s; j++)
2341 fprintf (stderr, " %7.3f", f[j]);
2342 fprintf (stderr, "\n");
2350 dump_direct_array_data (int count)
2352 draw_array A = { 0, };
2354 if (jwzgles_glIsEnabled (GL_VERTEX_ARRAY))
2356 glGetIntegerv (GL_VERTEX_ARRAY_BUFFER_BINDING, &A.binding);
2357 glGetIntegerv (GL_VERTEX_ARRAY_SIZE, &A.size);
2358 glGetIntegerv (GL_VERTEX_ARRAY_TYPE, &A.type);
2359 glGetIntegerv (GL_VERTEX_ARRAY_STRIDE, &A.stride);
2360 glGetPointerv (GL_VERTEX_ARRAY_POINTER, &A.data);
2361 A.bytes = count * A.stride;
2362 dump_array_data (&A, count, "direct", "vertex ", 0);
2364 if (jwzgles_glIsEnabled (GL_NORMAL_ARRAY))
2367 glGetIntegerv (GL_NORMAL_ARRAY_BUFFER_BINDING, &A.binding);
2368 glGetIntegerv (GL_NORMAL_ARRAY_TYPE, &A.type);
2369 glGetIntegerv (GL_NORMAL_ARRAY_STRIDE, &A.stride);
2370 glGetPointerv (GL_NORMAL_ARRAY_POINTER, &A.data);
2371 A.bytes = count * A.stride;
2372 dump_array_data (&A, count, "direct", "normal ", 0);
2374 if (jwzgles_glIsEnabled (GL_TEXTURE_COORD_ARRAY))
2376 glGetIntegerv (GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING, &A.binding);
2377 glGetIntegerv (GL_TEXTURE_COORD_ARRAY_SIZE, &A.size);
2378 glGetIntegerv (GL_TEXTURE_COORD_ARRAY_TYPE, &A.type);
2379 glGetIntegerv (GL_TEXTURE_COORD_ARRAY_STRIDE, &A.stride);
2380 glGetPointerv (GL_TEXTURE_COORD_ARRAY_POINTER, &A.data);
2381 A.bytes = count * A.stride;
2382 dump_array_data (&A, count, "direct", "texture", 0);
2384 if (jwzgles_glIsEnabled (GL_COLOR_ARRAY))
2386 glGetIntegerv (GL_COLOR_ARRAY_BUFFER_BINDING, &A.binding);
2387 glGetIntegerv (GL_COLOR_ARRAY_SIZE, &A.size);
2388 glGetIntegerv (GL_COLOR_ARRAY_TYPE, &A.type);
2389 glGetIntegerv (GL_COLOR_ARRAY_STRIDE, &A.stride);
2390 glGetPointerv (GL_COLOR_ARRAY_POINTER, &A.data);
2391 A.bytes = count * A.stride;
2392 dump_array_data (&A, count, "direct", "color ", 0);
2400 copy_array_data (draw_array *A, int count, const char *name)
2402 /* Instead of just memcopy'ing the whole array and obeying its previous
2403 'stride' value, we make up a more compact array. This is because if
2404 the same array data is being used with multiple component types,
2405 e.g. with glInterleavedArrays, we don't want to copy all of the
2406 data multiple times.
2408 int stride2, bytes, i, j;
2412 const unsigned char *IB;
2415 if (((unsigned long) A->data) < 0xFFFF)
2417 Assert (0, "buffer data not a pointer");
2421 Assert (A->size >= 2 && A->size <= 4, "bogus array size");
2424 case GL_FLOAT: stride2 = A->size * sizeof(GLfloat); break;
2425 case GL_UNSIGNED_BYTE: stride2 = A->size; break;
2426 default: Assert (0, "bogus array type"); break;
2429 bytes = count * stride2;
2430 Assert (bytes > 0, "bogus array count or stride");
2431 Assert (A->data, "missing array data");
2432 data2 = (void *) malloc (bytes);
2433 Assert (data2, "out of memory");
2435 IB = (const unsigned char *) A->data;
2436 OB = (unsigned char *) data2;
2437 IF = (const GLfloat *) A->data;
2438 OF = (GLfloat *) data2;
2442 for (i = 0; i < count; i++)
2444 for (j = 0; j < A->size; j++)
2446 IF = (const GLfloat *) (((const unsigned char *) IF) + A->stride);
2449 case GL_UNSIGNED_BYTE:
2450 for (i = 0; i < count; i++)
2452 for (j = 0; j < A->size; j++)
2458 Assert (0, "bogus array type");
2464 A->stride = stride2;
2467 dump_array_data (A, count, "saved", name, old);
2473 restore_arrays (list_fn *F, int count)
2476 draw_array *A = F->arrays;
2477 Assert (A, "missing array");
2479 for (i = 0; i < 4; i++)
2481 const char *name = 0;
2486 Assert ((A[i].binding || A[i].data),
2487 "array has neither buffer binding nor data");
2489 glBindBuffer (GL_ARRAY_BUFFER, A[i].binding);
2490 CHECK("glBindBuffer");
2493 case 0: glVertexPointer (A[i].size, A[i].type, A[i].stride, A[i].data);
2495 CHECK("glVertexPointer");
2497 case 1: glNormalPointer ( A[i].type, A[i].stride, A[i].data);
2499 CHECK("glNormalPointer");
2501 case 2: glTexCoordPointer(A[i].size, A[i].type, A[i].stride, A[i].data);
2503 CHECK("glTexCoordPointer");
2505 case 3: glColorPointer (A[i].size, A[i].type, A[i].stride, A[i].data);
2507 CHECK("glColorPointer");
2509 default: Assert (0, "wat"); break;
2513 dump_array_data (&A[i], count, "restored", name, 0);
2517 glBindBuffer (GL_ARRAY_BUFFER, 0); /* Keep out of others' hands */
2522 jwzgles_glDrawArrays (GLuint mode, GLuint first, GLuint count)
2524 if (state->compiling_list)
2530 list_push ("glDrawArrays", (list_fn_cb) &jwzgles_glDrawArrays,
2536 if (! state->replaying_list) {
2537 LOG4("direct %-12s %d %d %d", "glDrawArrays", mode, first, count);
2538 dump_direct_array_data (first + count);
2541 glDrawArrays (mode, first, count); /* the real one */
2542 CHECK("glDrawArrays");
2548 jwzgles_glInterleavedArrays (GLenum format, GLsizei stride, const void *data)
2550 /* We can implement this by calling the various *Pointer functions
2551 with offsets into the same data, taking advantage of stride.
2553 const unsigned char *c = (const unsigned char *) data;
2555 # define F sizeof(GLfloat)
2557 Assert (!state->compiling_verts,
2558 "glInterleavedArrays not allowed inside glBegin");
2560 jwzgles_glEnableClientState (GL_VERTEX_ARRAY);
2562 if (!state->replaying_list)
2563 LOG4 ("%sglInterleavedArrays %s %d %lX",
2564 (state->compiling_list || state->replaying_list ? " " : ""),
2565 mode_desc (format), stride, (unsigned long) data);
2569 glVertexPointer (2, GL_FLOAT, stride, c);
2570 CHECK("glVertexPointer");
2571 if (!state->replaying_list)
2572 LOG3 ("%s -> glVertexPointer 2 FLOAT %d %lX",
2573 (state->compiling_list || state->replaying_list ? " " : ""),
2574 stride, (unsigned long) c);
2577 glVertexPointer (3, GL_FLOAT, stride, c);
2578 CHECK("glVertexPointer");
2579 if (!state->replaying_list)
2580 LOG3 ("%s -> glVertexPointer 3 FLOAT %d %lX",
2581 (state->compiling_list || state->replaying_list ? " " : ""),
2582 stride, (unsigned long) c);
2587 jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2588 glColorPointer (4, GL_UNSIGNED_BYTE, stride, c);
2589 CHECK("glColorPointer");
2590 c += 4*B; /* #### might be incorrect float-aligned address */
2591 glVertexPointer (2, GL_FLOAT, stride, c);
2596 jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2597 glColorPointer (4, GL_UNSIGNED_BYTE, stride, c);
2598 CHECK("glColorPointer");
2600 glVertexPointer (3, GL_FLOAT, stride, c);
2601 CHECK("glVertexPointer");
2606 jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2607 glColorPointer (3, GL_FLOAT, stride, c);
2608 CHECK("glColorPointer");
2610 glVertexPointer (3, GL_FLOAT, stride, c);
2611 CHECK("glVertexPointer");
2616 jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
2617 glNormalPointer (GL_FLOAT, stride, c);
2618 CHECK("glNormalPointer");
2619 if (!state->replaying_list)
2620 LOG3 ("%s -> glNormalPointer FLOAT %d %lX",
2621 (state->compiling_list || state->replaying_list ? " " : ""),
2622 stride, (unsigned long) c);
2624 glVertexPointer (3, GL_FLOAT, stride, c);
2625 CHECK("glVertexPointer");
2626 if (!state->replaying_list)
2627 LOG3 ("%s -> glVertexPointer 3 FLOAT %d %lX",
2628 (state->compiling_list || state->replaying_list ? " " : ""),
2629 stride, (unsigned long) c);
2631 case GL_C4F_N3F_V3F:
2633 stride = 4*F + 3*F + 3*F;
2634 jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2635 glColorPointer (4, GL_FLOAT, stride, c);
2636 CHECK("glColorPointer");
2638 jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
2639 glNormalPointer (GL_FLOAT, stride, c);
2640 CHECK("glNormalPointer");
2642 glVertexPointer (3, GL_FLOAT, stride, c);
2643 CHECK("glVertexPointer");
2648 jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2649 glTexCoordPointer (2, GL_FLOAT, stride, c);
2650 CHECK("glTexCoordPointer");
2652 glVertexPointer (3, GL_FLOAT, stride, c);
2653 CHECK("glVertexPointer");
2658 jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2659 glTexCoordPointer (4, GL_FLOAT, stride, c);
2660 CHECK("glTexCoordPointer");
2662 glVertexPointer (4, GL_FLOAT, stride, c);
2663 CHECK("glVertexPointer");
2665 case GL_T2F_C4UB_V3F:
2667 stride = 2*F + 4*B + 3*F;
2668 jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2669 glTexCoordPointer (2, GL_FLOAT, stride, c);
2670 CHECK("glTexCoordPointer");
2672 jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2673 glColorPointer (4, GL_UNSIGNED_BYTE, stride, c);
2674 CHECK("glColorPointer");
2676 glVertexPointer (3, GL_FLOAT, stride, c);
2677 CHECK("glVertexPointer");
2679 case GL_T2F_C3F_V3F:
2681 stride = 2*F + 3*F + 3*F;
2682 jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2683 glTexCoordPointer (2, GL_FLOAT, stride, c);
2684 CHECK("glTexCoordPointer");
2686 jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2687 glColorPointer (3, GL_FLOAT, stride, c);
2688 CHECK("glColorPointer");
2690 glVertexPointer (3, GL_FLOAT, stride, c);
2691 CHECK("glVertexPointer");
2693 case GL_T2F_N3F_V3F:
2695 stride = 2*F + 3*F + 3*F;
2696 jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2697 glTexCoordPointer (2, GL_FLOAT, stride, c);
2698 CHECK("glTexCoordPointer");
2700 jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
2701 glNormalPointer (GL_FLOAT, stride, c);
2702 CHECK("glNormalPointer");
2704 glVertexPointer (3, GL_FLOAT, stride, c);
2705 CHECK("glVertexPointer");
2707 case GL_T2F_C4F_N3F_V3F:
2709 stride = 2*F + 4*F + 3*F + 3*F;
2710 jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2711 glTexCoordPointer (2, GL_FLOAT, stride, c);
2712 CHECK("glTexCoordPointer");
2714 jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2715 glColorPointer (3, GL_FLOAT, stride, c);
2716 CHECK("glColorPointer");
2718 jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
2719 glNormalPointer (GL_FLOAT, stride, c);
2720 CHECK("glNormalPointer");
2722 glVertexPointer (3, GL_FLOAT, stride, c);
2723 CHECK("glVertexPointer");
2725 case GL_T4F_C4F_N3F_V4F:
2727 stride = 4*F + 4*F + 3*F + 4*F;
2728 jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2729 glTexCoordPointer (4, GL_FLOAT, stride, c);
2730 CHECK("glTexCoordPointer");
2732 jwzgles_glEnableClientState (GL_COLOR_ARRAY);
2733 glColorPointer (4, GL_FLOAT, stride, c);
2734 CHECK("glColorPointer");
2736 jwzgles_glEnableClientState (GL_NORMAL_ARRAY);
2737 glNormalPointer (GL_FLOAT, stride, c);
2738 CHECK("glNormalPointer");
2740 glVertexPointer (3, GL_FLOAT, stride, c);
2741 CHECK("glVertexPointer");
2744 Assert (0, "glInterleavedArrays: bogus format");
2755 jwzgles_glEnableClientState (GLuint cap)
2757 if (state->compiling_list)
2761 list_push ("glEnableClientState",
2762 (list_fn_cb) &jwzgles_glEnableClientState,
2767 if (! state->replaying_list)
2768 LOG2 ("direct %-12s %s", "glEnableClientState", mode_desc(cap));
2769 glEnableClientState (cap); /* the real one */
2770 CHECK("glEnableClientState");
2774 case GL_VERTEX_ARRAY:
2775 state->enabled |= ISENABLED_VERT_ARRAY;
2777 case GL_NORMAL_ARRAY:
2778 if (! state->compiling_verts)
2779 state->set.ncount += 2;
2780 state->enabled |= ISENABLED_NORM_ARRAY;
2782 case GL_TEXTURE_COORD_ARRAY:
2783 if (! state->compiling_verts)
2784 state->set.tcount += 2;
2785 state->enabled |= ISENABLED_TEX_ARRAY;
2787 case GL_COLOR_ARRAY:
2788 if (! state->compiling_verts)
2789 state->set.ccount += 2;
2790 state->enabled |= ISENABLED_COLOR_ARRAY;
2798 jwzgles_glDisableClientState (GLuint cap)
2800 if (state->compiling_list)
2804 list_push ("glDisableClientState",
2805 (list_fn_cb) &jwzgles_glDisableClientState,
2810 if (! state->replaying_list)
2811 LOG2 ("direct %-12s %s", "glDisableClientState", mode_desc(cap));
2812 glDisableClientState (cap); /* the real one */
2813 CHECK("glDisableClientState");
2817 case GL_VERTEX_ARRAY:
2818 state->enabled &= ~ISENABLED_VERT_ARRAY;
2820 case GL_NORMAL_ARRAY:
2821 if (! state->compiling_verts)
2822 state->set.ncount = 0;
2823 state->enabled &= ~ISENABLED_NORM_ARRAY;
2825 case GL_TEXTURE_COORD_ARRAY:
2826 if (! state->compiling_verts)
2827 state->set.tcount = 0;
2828 state->enabled &= ~ISENABLED_TEX_ARRAY;
2830 case GL_COLOR_ARRAY:
2831 if (! state->compiling_verts)
2832 state->set.ccount = 0;
2833 state->enabled &= ~ISENABLED_COLOR_ARRAY;
2842 jwzgles_glMultMatrixf (const GLfloat *m)
2844 Assert (!state->compiling_verts,
2845 "glMultMatrixf not allowed inside glBegin");
2846 if (state->compiling_list)
2850 for (i = 0; i < countof(vv); i++)
2852 list_push ("glMultMatrixf", (list_fn_cb) &jwzgles_glMultMatrixf,
2857 if (! state->replaying_list)
2858 LOG1 ("direct %-12s", "glMultMatrixf");
2859 glMultMatrixf (m); /* the real one */
2860 CHECK("glMultMatrixf");
2866 jwzgles_glClearIndex(GLfloat c)
2868 /* Does GLES even do indexed color? */
2869 Assert (0, "glClearIndex unimplemented");
2874 jwzgles_glBitmap (GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig,
2875 GLfloat xmove, GLfloat ymove, const GLubyte *bitmap)
2877 Assert (0, "glBitmap unimplemented");
2881 jwzgles_glPushAttrib(int flags)
2883 Assert (0, "glPushAttrib unimplemented");
2887 jwzgles_glPopAttrib(void)
2889 Assert (0, "glPopAttrib unimplemented");
2893 /* These are needed for object hit detection in pinion.
2894 Might need to rewrite that code entirely. Punt for now.
2897 jwzgles_glInitNames (void)
2899 /* Assert (0, "glInitNames unimplemented");*/
2903 jwzgles_glPushName (GLuint name)
2905 /* Assert (0, "glPushName unimplemented");*/
2909 jwzgles_glPopName (void)
2911 /* Assert (0, "glPopName unimplemented");*/
2916 jwzgles_glRenderMode (GLuint mode)
2918 /* Assert (0, "glRenderMode unimplemented");*/
2923 jwzgles_glSelectBuffer (GLsizei size, GLuint *buf)
2925 /* Assert (0, "glSelectBuffer unimplemented");*/
2930 jwzgles_glGenTextures (GLuint n, GLuint *ret)
2932 Assert (!state->compiling_verts,
2933 "glGenTextures not allowed inside glBegin");
2934 /* technically legal, but stupid! */
2935 Assert (!state->compiling_list,
2936 "glGenTextures not allowed inside glNewList");
2937 if (! state->replaying_list)
2938 LOG1 ("direct %-12s", "glGenTextures");
2939 glGenTextures (n, ret); /* the real one */
2940 CHECK("glGenTextures");
2944 /* return the next larger power of 2. */
2949 while (i < value) i <<= 1;
2954 jwzgles_glTexImage1D (GLenum target, GLint level,
2955 GLint internalFormat,
2956 GLsizei width, GLint border,
2957 GLenum format, GLenum type,
2960 Assert (!state->compiling_verts, "glTexImage1D not allowed inside glBegin");
2961 /* technically legal, but stupid! */
2962 Assert (!state->compiling_list, "glTexImage1D inside glNewList");
2963 Assert (width == to_pow2(width), "width must be a power of 2");
2965 if (target == GL_TEXTURE_1D) target = GL_TEXTURE_2D;
2966 jwzgles_glTexImage2D (target, level, internalFormat, width, 1,
2967 border, format, type, data);
2971 jwzgles_glTexImage2D (GLenum target,
2973 GLint internalFormat,
2981 GLvoid *d2 = (GLvoid *) data;
2982 Assert (!state->compiling_verts, "glTexImage2D not allowed inside glBegin");
2983 Assert (!state->compiling_list, /* technically legal, but stupid! */
2984 "glTexImage2D not allowed inside glNewList");
2986 Assert (width == to_pow2(width), "width must be a power of 2");
2987 Assert (height == to_pow2(height), "height must be a power of 2");
2989 /* OpenGLES no longer supports "4" as a synonym for "RGBA". */
2990 switch (internalFormat) {
2991 case 1: internalFormat = GL_LUMINANCE; break;
2992 case 2: internalFormat = GL_LUMINANCE_ALPHA; break;
2993 case 3: internalFormat = GL_RGB; break;
2994 case 4: internalFormat = GL_RGBA; break;
2997 /* GLES does not let us omit the data pointer to create a blank texture. */
3000 d2 = (GLvoid *) calloc (1, width * height * sizeof(GLfloat) * 4);
3001 Assert (d2, "out of memory");
3004 if (internalFormat == GL_RGB && format == GL_RGBA)
3005 internalFormat = GL_RGBA; /* WTF */
3006 if (type == GL_UNSIGNED_INT_8_8_8_8_REV)
3007 type = GL_UNSIGNED_BYTE;
3009 if (! state->replaying_list)
3010 LOG10 ("direct %-12s %s %d %s %d %d %d %s %s 0x%lX", "glTexImage2D",
3011 mode_desc(target), level, mode_desc(internalFormat),
3012 width, height, border, mode_desc(format), mode_desc(type),
3013 (unsigned long) d2);
3014 glTexImage2D (target, level, internalFormat, width, height, border,
3015 format, type, d2); /* the real one */
3016 CHECK("glTexImage2D");
3018 if (d2 != data) free (d2);
3022 jwzgles_glTexSubImage2D (GLenum target, GLint level,
3023 GLint xoffset, GLint yoffset,
3024 GLsizei width, GLsizei height,
3025 GLenum format, GLenum type,
3026 const GLvoid *pixels)
3028 Assert (!state->compiling_verts,
3029 "glTexSubImage2D not allowed inside glBegin");
3030 Assert (!state->compiling_list, /* technically legal, but stupid! */
3031 "glTexSubImage2D not allowed inside glNewList");
3033 if (! state->replaying_list)
3034 LOG10 ("direct %-12s %s %d %d %d %d %d %s %s 0x%lX", "glTexSubImage2D",
3035 mode_desc(target), level, xoffset, yoffset, width, height,
3036 mode_desc (format), mode_desc (type), (unsigned long) pixels);
3037 glTexSubImage2D (target, level, xoffset, yoffset, width, height,
3038 format, type, pixels); /* the real one */
3039 CHECK("glTexSubImage2D");
3043 jwzgles_glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat,
3044 GLint x, GLint y, GLsizei width, GLsizei height,
3047 Assert (!state->compiling_verts,
3048 "glCopyTexImage2D not allowed inside glBegin");
3049 Assert (!state->compiling_list, /* technically legal, but stupid! */
3050 "glCopyTexImage2D not allowed inside glNewList");
3051 if (! state->replaying_list)
3052 LOG9 ("direct %-12s %s %d %s %d %d %d %d %d", "glCopyTexImage2D",
3053 mode_desc(target), level, mode_desc(internalformat),
3054 x, y, width, height, border);
3055 glCopyTexImage2D (target, level, internalformat, x, y, width, height,
3056 border); /* the real one */
3057 CHECK("glCopyTexImage2D");
3062 jwzgles_glTexGenfv (GLenum coord, GLenum pname, const GLfloat *params)
3064 /* OpenGLES doesn't have this at all!
3065 "Oh, just rewrite that code to use GPU shaders", they say.
3066 How fucking convenient.
3068 So, when this is enabled, we could emit a GL_TEXTURE_COORD_ARRAY
3069 and compute coords for each vertex in the current GL_VERTEX_ARRAY
3070 as per http://www.opengl.org/wiki/Mathematics_of_glTexGen
3071 but holy shit, what a pain in the ass!
3073 For GL_OBJECT_LINEAR, we can just re-use the vertex array as
3074 the texture array, using a proper stride. That's hardly worth
3075 the effort, though, because bouncingcow is the only hack that
3076 uses that, and not even by default.
3078 Assert (coord == GL_S || coord == GL_T, "glTexGenfv: unimplemented coord");
3080 /* This is probably default-ish, so do nothing. */
3081 if (pname == GL_EYE_PLANE) return;
3083 Assert (pname == GL_TEXTURE_GEN_MODE, "glTexGenfv: unimplemented name");
3084 Assert (params[0] == GL_EYE_LINEAR, "glTexGenfv: unimplemented mode");
3088 jwzgles_glTexGeni (GLenum coord, GLenum pname, GLint param)
3091 jwzgles_glTexGenfv (coord, pname, &v);
3096 jwzgles_gluBuild2DMipmaps (GLenum target,
3097 GLint internalFormat,
3104 /* Not really bothering with mipmapping; only making one level.
3105 Note that this required a corresponding hack in glTexParameterf().
3108 int w2 = to_pow2(width);
3109 int h2 = to_pow2(height);
3111 void *d2 = (void *) data;
3113 /* OpenGLES no longer supports "4" as a synonym for "RGBA". */
3114 switch (internalFormat) {
3115 case 1: internalFormat = GL_LUMINANCE; break;
3116 case 2: internalFormat = GL_LUMINANCE_ALPHA; break;
3117 case 3: internalFormat = GL_RGB; break;
3118 case 4: internalFormat = GL_RGBA; break;
3121 /* if (w2 < h2) w2 = h2;
3122 if (h2 < w2) h2 = w2;*/
3124 if (w2 != width || h2 != height)
3126 /* Scale up the image bits to fit the power-of-2 texture.
3127 We have to do this because the mipmap API assumes that
3128 the texture bits go to texture coordinates 1.0 x 1.0.
3129 This could be more efficient, but it doesn't happen often.
3131 int istride = (format == GL_RGBA ? 4 : 3);
3133 int ibpl = istride * width;
3134 int obpl = ostride * w2;
3136 const unsigned char *in = (unsigned char *) data;
3137 unsigned char *out = (void *) malloc (h2 * obpl);
3138 Assert (out, "out of memory");
3141 for (oy = 0; oy < h2; oy++)
3143 int iy = oy * height / h2;
3144 const unsigned char *iline = in + (iy * ibpl);
3145 unsigned char *oline = out + (oy * obpl);
3147 for (ox = 0; ox < w2; ox++)
3149 int ix = ox * width / w2;
3150 const unsigned char *i = iline + (ix * istride);
3151 unsigned char *o = oline + (ox * ostride);
3152 *o++ = *i++; /* R */
3153 *o++ = *i++; /* G */
3154 *o++ = *i++; /* B */
3155 *o++ = (istride == 4 ? *i : 0xFF); /* A */
3160 internalFormat = GL_RGBA;
3164 jwzgles_glTexImage2D (target, 0, internalFormat, w2, h2, 0,
3166 if (d2 != data) free (d2);
3173 jwzgles_glRectf (GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
3175 jwzgles_glBegin (GL_POLYGON);
3176 jwzgles_glVertex2f (x1, y1);
3177 jwzgles_glVertex2f (x2, y1);
3178 jwzgles_glVertex2f (x2, y2);
3179 jwzgles_glVertex2f (x1, y2);
3184 jwzgles_glRecti (GLint x1, GLint y1, GLint x2, GLint y2)
3186 jwzgles_glRectf (x1, y1, x2, y2);
3190 jwzgles_glClearDepth (GLfloat d)
3192 /* Not sure what to do here */
3193 Assert (d == 1.0, "glClearDepth unimplemented");
3198 jwzgles_glEnable (GLuint bit)
3200 Assert (!state->compiling_verts, "glEnable not allowed inside glBegin");
3201 if (state->compiling_list)
3205 list_push ("glEnable", (list_fn_cb) &jwzgles_glEnable, PROTO_I, vv);
3209 /* We implement 1D textures as 2D textures. */
3210 if (bit == GL_TEXTURE_1D) bit = GL_TEXTURE_2D;
3212 if (! state->replaying_list)
3213 LOG2 ("direct %-12s %s", "glEnable", mode_desc(bit));
3214 glEnable (bit); /* the real one */
3218 case GL_TEXTURE_2D: state->enabled |= ISENABLED_TEXTURE_2D; break;
3219 case GL_TEXTURE_GEN_S: state->enabled |= ISENABLED_TEXTURE_GEN_S; break;
3220 case GL_TEXTURE_GEN_T: state->enabled |= ISENABLED_TEXTURE_GEN_T; break;
3221 case GL_LIGHTING: state->enabled |= ISENABLED_LIGHTING; break;
3222 case GL_BLEND: state->enabled |= ISENABLED_BLEND; break;
3223 case GL_DEPTH_TEST: state->enabled |= ISENABLED_DEPTH_TEST; break;
3224 case GL_CULL_FACE: state->enabled |= ISENABLED_CULL_FACE; break;
3225 case GL_NORMALIZE: state->enabled |= ISENABLED_NORMALIZE; break;
3226 case GL_FOG: state->enabled |= ISENABLED_FOG; break;
3227 case GL_COLOR_MATERIAL: state->enabled |= ISENABLED_COLMAT; break;
3229 /* Do these work with glEnable or only with glEnableClientState? */
3230 case GL_VERTEX_ARRAY: state->enabled |= ISENABLED_VERT_ARRAY; break;
3231 case GL_NORMAL_ARRAY: state->enabled |= ISENABLED_NORM_ARRAY; break;
3232 case GL_TEXTURE_COORD_ARRAY: state->enabled |= ISENABLED_TEX_ARRAY;break;
3233 case GL_COLOR_ARRAY: state->enabled |= ISENABLED_COLOR_ARRAY; break;
3242 jwzgles_glDisable (GLuint bit)
3244 Assert (!state->compiling_verts, "glDisable not allowed inside glBegin");
3245 if (state->compiling_list)
3249 list_push ("glDisable", (list_fn_cb) &jwzgles_glDisable, PROTO_I, vv);
3253 /* We implement 1D textures as 2D textures. */
3254 if (bit == GL_TEXTURE_1D) bit = GL_TEXTURE_2D;
3256 if (! state->replaying_list)
3257 LOG2 ("direct %-12s %s", "glDisable", mode_desc(bit));
3258 glDisable (bit); /* the real one */
3262 case GL_TEXTURE_2D: state->enabled &= ~ISENABLED_TEXTURE_2D; break;
3263 case GL_TEXTURE_GEN_S: state->enabled &= ~ISENABLED_TEXTURE_GEN_S; break;
3264 case GL_TEXTURE_GEN_T: state->enabled &= ~ISENABLED_TEXTURE_GEN_T; break;
3265 case GL_LIGHTING: state->enabled &= ~ISENABLED_LIGHTING; break;
3266 case GL_BLEND: state->enabled &= ~ISENABLED_BLEND; break;
3267 case GL_DEPTH_TEST: state->enabled &= ~ISENABLED_DEPTH_TEST; break;
3268 case GL_CULL_FACE: state->enabled &= ~ISENABLED_CULL_FACE; break;
3269 case GL_NORMALIZE: state->enabled &= ~ISENABLED_NORMALIZE; break;
3270 case GL_FOG: state->enabled &= ~ISENABLED_FOG; break;
3271 case GL_COLOR_MATERIAL: state->enabled &= ~ISENABLED_COLMAT; break;
3273 /* Do these work with glEnable or only with glEnableClientState? */
3274 case GL_VERTEX_ARRAY: state->enabled &= ~ISENABLED_VERT_ARRAY; break;
3275 case GL_NORMAL_ARRAY: state->enabled &= ~ISENABLED_NORM_ARRAY; break;
3276 case GL_TEXTURE_COORD_ARRAY: state->enabled &= ~ISENABLED_TEX_ARRAY;break;
3277 case GL_COLOR_ARRAY: state->enabled &= ~ISENABLED_COLOR_ARRAY; break;
3286 jwzgles_glIsEnabled (GLuint bit)
3289 Assert (!state->compiling_verts, "glIsEnabled not allowed inside glBegin");
3290 Assert (!state->compiling_list, "glIsEnabled not allowed inside glNewList");
3293 /* We implement 1D textures as 2D textures. */
3294 if (bit == GL_TEXTURE_1D) bit = GL_TEXTURE_2D;
3297 case GL_TEXTURE_2D: return !!(state->enabled & ISENABLED_TEXTURE_2D);
3298 case GL_TEXTURE_GEN_S: return !!(state->enabled & ISENABLED_TEXTURE_GEN_S);
3299 case GL_TEXTURE_GEN_T: return !!(state->enabled & ISENABLED_TEXTURE_GEN_T);
3300 case GL_LIGHTING: return !!(state->enabled & ISENABLED_LIGHTING);
3301 case GL_BLEND: return !!(state->enabled & ISENABLED_BLEND);
3302 case GL_DEPTH_TEST: return !!(state->enabled & ISENABLED_DEPTH_TEST);
3303 case GL_CULL_FACE: return !!(state->enabled & ISENABLED_CULL_FACE);
3304 case GL_NORMALIZE: return !!(state->enabled & ISENABLED_NORMALIZE);
3305 case GL_FOG: return !!(state->enabled & ISENABLED_FOG);
3306 case GL_COLOR_MATERIAL: return !!(state->enabled & ISENABLED_COLMAT);
3308 /* Do these work with glEnable or only with glEnableClientState?
3309 We need to query them, and there is no glIsClientStateEnabled.
3311 case GL_VERTEX_ARRAY: return !!(state->enabled & ISENABLED_VERT_ARRAY);
3312 case GL_NORMAL_ARRAY: return !!(state->enabled & ISENABLED_NORM_ARRAY);
3313 case GL_TEXTURE_COORD_ARRAY: return !!(state->enabled & ISENABLED_TEX_ARRAY);
3314 case GL_COLOR_ARRAY: return !!(state->enabled & ISENABLED_COLOR_ARRAY);
3315 default: Assert (0, "glIsEnabled unimplemented bit"); break;
3320 /* The spec says that OpenGLES 1.x doesn't implement glGetFloatv.
3321 Were this true, it would suck, for it would mean that there was no
3322 way to retrieve the prevailing matrixes. To implement this, we'd
3323 have to keep track of them all on the client side by combining in
3324 all the actions of glMultMatrixf, glRotatef, etc.
3326 However, Apple's iOS OpenGLES *does* provide glGetFloatv!
3329 jwzgles_glGetFloatv (GLenum pname, GLfloat *params)
3331 if (! state->replaying_list)
3332 LOG2 ("direct %-12s %s", "glGetFloatv", mode_desc(pname));
3333 glGetFloatv (pname, params); /* the real one */
3334 CHECK("glGetFloatv");
3338 /* Likewise: not supposed to be there, but it is. */
3340 jwzgles_glGetPointerv (GLenum pname, GLvoid *params)
3342 if (! state->replaying_list)
3343 LOG2 ("direct %-12s %s", "glGetPointerv", mode_desc(pname));
3344 glGetPointerv (pname, params); /* the real one */
3345 CHECK("glGetPointerv");
3349 /* How many cells are written into the *params array.
3350 We need to know this to avoid smashing the caller's stack
3351 if they asked for a single-value parameter.
3354 glGet_ret_count (GLenum pname)
3357 /*case GL_COLOR_MATRIX: */
3358 case GL_MODELVIEW_MATRIX:
3359 case GL_PROJECTION_MATRIX:
3360 case GL_TEXTURE_MATRIX:
3361 /*case GL_TRANSPOSE_COLOR_MATRIX: */
3362 /*case GL_TRANSPOSE_MODELVIEW_MATRIX: */
3363 /*case GL_TRANSPOSE_PROJECTION_MATRIX: */
3364 /*case GL_TRANSPOSE_TEXTURE_MATRIX: */
3366 /*case GL_ACCUM_CLEAR_VALUE: */
3367 /*case GL_BLEND_COLOR: */
3368 case GL_COLOR_CLEAR_VALUE:
3369 case GL_COLOR_WRITEMASK:
3370 case GL_CURRENT_COLOR:
3371 /*case GL_CURRENT_RASTER_COLOR: */
3372 /*case GL_CURRENT_RASTER_POSITION: */
3373 /*case GL_CURRENT_RASTER_SECONDARY_COLOR: */
3374 /*case GL_CURRENT_RASTER_TEXTURE_COORDS: */
3375 /*case GL_CURRENT_SECONDARY_COLOR: */
3376 case GL_CURRENT_TEXTURE_COORDS:
3378 case GL_LIGHT_MODEL_AMBIENT:
3379 /*case GL_MAP2_GRID_DOMAIN: */
3380 case GL_SCISSOR_BOX:
3383 case GL_CURRENT_NORMAL:
3384 case GL_POINT_DISTANCE_ATTENUATION:
3386 case GL_ALIASED_LINE_WIDTH_RANGE:
3387 case GL_ALIASED_POINT_SIZE_RANGE:
3388 case GL_DEPTH_RANGE:
3389 /*case GL_LINE_WIDTH_RANGE: */
3390 /*case GL_MAP1_GRID_DOMAIN: */
3391 /*case GL_MAP2_GRID_SEGMENTS: */
3392 case GL_MAX_VIEWPORT_DIMS:
3393 /*case GL_POINT_SIZE_RANGE: */
3394 case GL_POLYGON_MODE:
3395 case GL_SMOOTH_LINE_WIDTH_RANGE:
3396 case GL_SMOOTH_POINT_SIZE_RANGE:
3405 jwzgles_glGetDoublev (GLenum pname, GLdouble *params)
3408 int i, j = glGet_ret_count (pname);
3409 jwzgles_glGetFloatv (pname, m);
3410 for (i = 0; i < j; i++)
3416 jwzgles_glGetIntegerv (GLenum pname, GLint *params)
3419 int i, j = glGet_ret_count (pname);
3420 jwzgles_glGetFloatv (pname, m);
3421 for (i = 0; i < j; i++)
3427 jwzgles_glGetBooleanv (GLenum pname, GLboolean *params)
3430 int i, j = glGet_ret_count (pname);
3431 jwzgles_glGetFloatv (pname, m);
3432 for (i = 0; i < j; i++)
3433 params[i] = (m[i] != 0.0);
3438 jwzgles_gluErrorString (GLenum error)
3441 sprintf (s, "0x%lX", (unsigned long) error);
3446 /* These four *Pointer calls (plus glBindBuffer and glBufferData) can
3447 be included inside glNewList, but they actually execute immediately
3448 anyway, because their data is recorded in the list by the
3449 subsequently-recorded call to glDrawArrays. This is a little weird.
3452 jwzgles_glVertexPointer (GLuint size, GLuint type, GLuint stride,
3455 if (! state->replaying_list)
3456 LOG5 ("direct %-12s %d %s %d 0x%lX", "glVertexPointer",
3457 size, mode_desc(type), stride, (unsigned long) ptr);
3458 glVertexPointer (size, type, stride, ptr); /* the real one */
3459 CHECK("glVertexPointer");
3463 jwzgles_glNormalPointer (GLuint type, GLuint stride, const GLvoid *ptr)
3465 if (! state->replaying_list)
3466 LOG4 ("direct %-12s %s %d 0x%lX", "glNormalPointer",
3467 mode_desc(type), stride, (unsigned long) ptr);
3468 glNormalPointer (type, stride, ptr); /* the real one */
3469 CHECK("glNormalPointer");
3473 jwzgles_glColorPointer (GLuint size, GLuint type, GLuint stride,
3476 if (! state->replaying_list)
3477 LOG5 ("direct %-12s %d %s %d 0x%lX", "glColorPointer",
3478 size, mode_desc(type), stride, (unsigned long) ptr);
3479 glColorPointer (size, type, stride, ptr); /* the real one */
3480 CHECK("glColorPointer");
3484 jwzgles_glTexCoordPointer (GLuint size, GLuint type, GLuint stride,
3487 if (! state->replaying_list)
3488 LOG5 ("direct %-12s %d %s %d 0x%lX", "glTexCoordPointer",
3489 size, mode_desc(type), stride, (unsigned long) ptr);
3490 glTexCoordPointer (size, type, stride, ptr); /* the real one */
3491 CHECK("glTexCoordPointer");
3495 jwzgles_glBindBuffer (GLuint target, GLuint buffer)
3497 if (! state->replaying_list)
3498 LOG3 ("direct %-12s %s %d", "glBindBuffer", mode_desc(target), buffer);
3499 glBindBuffer (target, buffer); /* the real one */
3500 CHECK("glBindBuffer");
3504 jwzgles_glBufferData (GLenum target, GLsizeiptr size, const void *data,
3507 if (! state->replaying_list)
3508 LOG5 ("direct %-12s %s %ld 0x%lX %s", "glBufferData",
3509 mode_desc(target), size, (unsigned long) data, mode_desc(usage));
3510 glBufferData (target, size, data, usage); /* the real one */
3511 CHECK("glBufferData");
3516 jwzgles_glTexParameterf (GLuint target, GLuint pname, GLfloat param)
3518 Assert (!state->compiling_verts,
3519 "glTexParameterf not allowed inside glBegin");
3521 /* We don't *really* implement mipmaps, so just turn this off. */
3522 if (param == GL_LINEAR_MIPMAP_LINEAR) param = GL_LINEAR;
3523 if (param == GL_NEAREST_MIPMAP_LINEAR) param = GL_LINEAR;
3524 if (param == GL_LINEAR_MIPMAP_NEAREST) param = GL_NEAREST;
3525 if (param == GL_NEAREST_MIPMAP_NEAREST) param = GL_NEAREST;
3527 /* We implement 1D textures as 2D textures. */
3528 if (target == GL_TEXTURE_1D) target = GL_TEXTURE_2D;
3530 /* Apparently this is another invalid enum. Just ignore it. */
3531 if ((pname == GL_TEXTURE_WRAP_S || pname == GL_TEXTURE_WRAP_T) &&
3535 if (state->compiling_list)
3541 list_push ("glTexParameterf", (list_fn_cb) &jwzgles_glTexParameterf,
3546 if (! state->replaying_list)
3547 LOG4 ("direct %-12s %s %s %7.3f", "glTexParameterf",
3548 mode_desc(target), mode_desc(pname), param);
3549 glTexParameterf (target, pname, param); /* the real one */
3550 CHECK("glTexParameterf");
3555 jwzgles_glTexParameteri (GLuint target, GLuint pname, GLuint param)
3557 jwzgles_glTexParameterf (target, pname, param);
3562 jwzgles_glBindTexture (GLuint target, GLuint texture)
3564 Assert (!state->compiling_verts,
3565 "glBindTexture not allowed inside glBegin");
3567 /* We implement 1D textures as 2D textures. */
3568 if (target == GL_TEXTURE_1D) target = GL_TEXTURE_2D;
3570 if (state->compiling_list)
3575 list_push ("glBindTexture", (list_fn_cb) &jwzgles_glBindTexture,
3580 if (! state->replaying_list)
3581 LOG3 ("direct %-12s %s %d", "glBindTexture",
3582 mode_desc(target), texture);
3583 glBindTexture (target, texture); /* the real one */
3584 CHECK("glBindTexture");
3590 /* Matrix functions, mostly cribbed from Mesa.
3594 jwzgles_glFrustum (GLfloat left, GLfloat right,
3595 GLfloat bottom, GLfloat top,
3596 GLfloat near, GLfloat far)
3599 GLfloat x = (2 * near) / (right-left);
3600 GLfloat y = (2 * near) / (top - bottom);
3601 GLfloat a = (right + left) / (right - left);
3602 GLfloat b = (top + bottom) / (top - bottom);
3603 GLfloat c = -(far + near) / (far - near);
3604 GLfloat d = -(2 * far * near) / (far - near);
3606 # define M(X,Y) m[Y * 4 + X]
3607 M(0,0) = x; M(0,1) = 0; M(0,2) = a; M(0,3) = 0;
3608 M(1,0) = 0; M(1,1) = y; M(1,2) = b; M(1,3) = 0;
3609 M(2,0) = 0; M(2,1) = 0; M(2,2) = c; M(2,3) = d;
3610 M(3,0) = 0; M(3,1) = 0; M(3,2) = -1; M(3,3) = 0;
3613 jwzgles_glMultMatrixf (m);
3618 jwzgles_glOrtho (GLfloat left, GLfloat right,
3619 GLfloat bottom, GLfloat top,
3620 GLfloat near, GLfloat far)
3623 GLfloat a = 2 / (right - left);
3624 GLfloat b = -(right + left) / (right - left);
3625 GLfloat c = 2 / (top - bottom);
3626 GLfloat d = -(top + bottom) / (top - bottom);
3627 GLfloat e = -2 / (far - near);
3628 GLfloat f = -(far + near) / (far - near);
3630 # define M(X,Y) m[Y * 4 + X]
3631 M(0,0) = a; M(0,1) = 0; M(0,2) = 0; M(0,3) = b;
3632 M(1,0) = 0; M(1,1) = c; M(1,2) = 0; M(1,3) = d;
3633 M(2,0) = 0; M(2,1) = 0; M(2,2) = e; M(2,3) = f;
3634 M(3,0) = 0; M(3,1) = 0; M(3,2) = 0; M(3,3) = 1;
3637 jwzgles_glMultMatrixf (m);
3642 jwzgles_gluPerspective (GLdouble fovy, GLdouble aspect,
3643 GLdouble near, GLdouble far)
3647 double rad = fovy / 2 * M_PI / 180;
3652 if (dz == 0 || si == 0 || aspect == 0)
3658 c = -(far + near) / dz;
3659 d = -2 * near * far / dz;
3661 # define M(X,Y) m[Y * 4 + X]
3662 M(0,0) = a; M(0,1) = 0; M(0,2) = 0; M(0,3) = 0;
3663 M(1,0) = 0; M(1,1) = b; M(1,2) = 0; M(1,3) = 0;
3664 M(2,0) = 0; M(2,1) = 0; M(2,2) = c; M(2,3) = d;
3665 M(3,0) = 0; M(3,1) = 0; M(3,2) = -1; M(3,3) = 0;
3668 jwzgles_glMultMatrixf (m);
3673 jwzgles_gluLookAt (GLfloat eyex, GLfloat eyey, GLfloat eyez,
3674 GLfloat centerx, GLfloat centery, GLfloat centerz,
3675 GLfloat upx, GLfloat upy, GLfloat upz)
3678 GLfloat x[3], y[3], z[3];
3681 /* Make rotation matrix */
3684 z[0] = eyex - centerx;
3685 z[1] = eyey - centery;
3686 z[2] = eyez - centerz;
3687 mag = sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]);
3688 if (mag) { /* mpichler, 19950515 */
3699 /* X vector = Y cross Z */
3700 x[0] = y[1] * z[2] - y[2] * z[1];
3701 x[1] = -y[0] * z[2] + y[2] * z[0];
3702 x[2] = y[0] * z[1] - y[1] * z[0];
3704 /* Recompute Y = Z cross X */
3705 y[0] = z[1] * x[2] - z[2] * x[1];
3706 y[1] = -z[0] * x[2] + z[2] * x[0];
3707 y[2] = z[0] * x[1] - z[1] * x[0];
3709 /* mpichler, 19950515 */
3710 /* cross product gives area of parallelogram, which is < 1.0 for
3711 * non-perpendicular unit-length vectors; so normalize x, y here
3714 mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
3721 mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
3728 #define M(row,col) m[col*4+row]
3729 M(0, 0) = x[0]; M(0, 1) = x[1]; M(0, 2) = x[2]; M(0, 3) = 0.0;
3730 M(1, 0) = y[0]; M(1, 1) = y[1]; M(1, 2) = y[2]; M(1, 3) = 0.0;
3731 M(2, 0) = z[0]; M(2, 1) = z[1]; M(2, 2) = z[2]; M(2, 3) = 0.0;
3732 M(3, 0) = 0.0; M(3, 1) = 0.0; M(3, 2) = 0.0; M(3, 3) = 1.0;
3735 jwzgles_glMultMatrixf(m);
3737 /* Translate Eye to Origin */
3738 jwzgles_glTranslatef(-eyex, -eyey, -eyez);
3742 static void __gluMultMatrixVecd (const GLdouble matrix[16],
3743 const GLdouble in[4],
3748 for (i=0; i<4; i++) {
3750 in[0] * matrix[0*4+i] +
3751 in[1] * matrix[1*4+i] +
3752 in[2] * matrix[2*4+i] +
3753 in[3] * matrix[3*4+i];
3758 jwzgles_gluProject (GLdouble objx, GLdouble objy, GLdouble objz,
3759 const GLdouble modelMatrix[16],
3760 const GLdouble projMatrix[16],
3761 const GLint viewport[4],
3762 GLdouble *winx, GLdouble *winy, GLdouble *winz)
3767 /* #### I suspect this is not working right. I was seeing crazy values
3768 in lament.c. Maybe there's some float-vs-double confusion going on?
3775 __gluMultMatrixVecd(modelMatrix, in, out);
3776 __gluMultMatrixVecd(projMatrix, out, in);
3777 if (in[3] == 0.0) return(GL_FALSE);
3781 /* Map x, y and z to range 0-1 */
3782 in[0] = in[0] * 0.5 + 0.5;
3783 in[1] = in[1] * 0.5 + 0.5;
3784 in[2] = in[2] * 0.5 + 0.5;
3786 /* Map x,y to viewport */
3787 in[0] = in[0] * viewport[2] + viewport[0];
3788 in[1] = in[1] * viewport[3] + viewport[1];
3797 /* The following functions are present in both OpenGL 1.1 and in OpenGLES 1,
3798 but are allowed within glNewList/glEndList, so we must wrap them to allow
3799 them to either be recorded in lists, or run directly.
3801 All this CPP obscenity is me screaming in rage at all the ways that C is
3802 not Lisp, as all I want to do here is DEFADVICE.
3805 #define PROTO_V PROTO_VOID
3806 #define TYPE_V GLuint
3808 #define VARS_V /* */
3810 #define FILL_V /* */
3812 #define TYPE_I GLuint
3813 #define TYPE_II TYPE_I
3814 #define TYPE_III TYPE_I
3815 #define TYPE_IIII TYPE_I
3816 #define ARGS_I TYPE_I a
3817 #define ARGS_II TYPE_I a, TYPE_I b
3818 #define ARGS_III TYPE_I a, TYPE_I b, TYPE_I c
3819 #define ARGS_IIII TYPE_I a, TYPE_I b, TYPE_I c, TYPE_I d
3820 #define LOGS_I "%s\n", mode_desc(a)
3821 #define LOGS_II "%s %d\n", mode_desc(a), b
3822 #define LOGS_III "%s %s %s\n", mode_desc(a), mode_desc(b), mode_desc(c)
3823 #define LOGS_IIII "%d %d %d %d\n", a, b, c, d
3825 #define VARS_II a, b
3826 #define VARS_III a, b, c
3827 #define VARS_IIII a, b, c, d
3828 #define FILL_I vv[0].i = a;
3829 #define FILL_II vv[0].i = a; vv[1].i = b;
3830 #define FILL_III vv[0].i = a; vv[1].i = b; vv[2].i = c;
3831 #define FILL_IIII vv[0].i = a; vv[1].i = b; vv[2].i = c; vv[3].i = d;
3833 #define TYPE_F GLfloat
3834 #define TYPE_FF TYPE_F
3835 #define TYPE_FFF TYPE_F
3836 #define TYPE_FFFF TYPE_F
3837 #define ARGS_F TYPE_F a
3838 #define ARGS_FF TYPE_F a, TYPE_F b
3839 #define ARGS_FFF TYPE_F a, TYPE_F b, TYPE_F c
3840 #define ARGS_FFFF TYPE_F a, TYPE_F b, TYPE_F c, TYPE_F d
3841 #define LOGS_F "%7.3f\n", a
3842 #define LOGS_FF "%7.3f %7.3f\n", a, b
3843 #define LOGS_FFF "%7.3f %7.3f %7.3f\n", a, b, c
3844 #define LOGS_FFFF "%7.3f %7.3f %7.3f %7.3f\n", a, b, c, d
3845 #define VARS_F VARS_I
3846 #define VARS_FF VARS_II
3847 #define VARS_FFF VARS_III
3848 #define VARS_FFFF VARS_IIII
3849 #define FILL_F vv[0].f = a;
3850 #define FILL_FF vv[0].f = a; vv[1].f = b;
3851 #define FILL_FFF vv[0].f = a; vv[1].f = b; vv[2].f = c;
3852 #define FILL_FFFF vv[0].f = a; vv[1].f = b; vv[2].f = c; vv[3].f = d;
3854 #define ARGS_IF TYPE_I a, TYPE_F b
3855 #define VARS_IF VARS_II
3856 #define LOGS_IF "%s %7.3f\n", mode_desc(a), b
3857 #define FILL_IF vv[0].i = a; vv[1].f = b;
3859 #define ARGS_IIF TYPE_I a, TYPE_I b, TYPE_F c
3860 #define VARS_IIF VARS_III
3861 #define LOGS_IIF "%s %s %7.3f\n", mode_desc(a), mode_desc(b), c
3862 #define FILL_IIF vv[0].i = a; vv[1].i = b; vv[2].f = c;
3864 #define TYPE_IV GLint
3865 #define ARGS_IIV TYPE_I a, const TYPE_IV *b
3866 #define VARS_IIV VARS_II
3867 #define LOGS_IIV "%s %d %d %d %d\n", mode_desc(a), b[0], b[1], b[2], b[3]
3868 #define FILL_IIV vv[0].i = a; \
3869 vv[1].i = b[0]; vv[2].i = b[1]; \
3870 vv[3].i = b[2]; vv[4].i = b[3];
3872 #define ARGS_IFV TYPE_I a, const TYPE_F *b
3873 #define VARS_IFV VARS_II
3874 #define LOGS_IFV "%s %7.3f %7.3f %7.3f %7.3f\n", mode_desc(a), \
3875 b[0], b[1], b[2], b[3]
3876 #define FILL_IFV vv[0].i = a; \
3877 vv[1].f = b[0]; vv[2].f = b[1]; \
3878 vv[3].f = b[2]; vv[4].f = b[3];
3880 #define ARGS_IIIV TYPE_I a, TYPE_I b, const TYPE_IV *c
3881 #define VARS_IIIV VARS_III
3882 #define LOGS_IIIV "%s %-8s %3d %3d %3d %3d\n", mode_desc(a), mode_desc(b), \
3883 c[0], c[1], c[2], c[3]
3884 #define FILL_IIIV vv[0].i = a; vv[1].i = b; \
3885 vv[2].i = c[0]; vv[3].i = c[1]; \
3886 vv[4].i = c[2]; vv[5].i = c[3];
3888 #define ARGS_IIFV TYPE_I a, TYPE_I b, const TYPE_F *c
3889 #define VARS_IIFV VARS_III
3890 #define LOGS_IIFV "%s %-8s %7.3f %7.3f %7.3f %7.3f\n", \
3891 mode_desc(a), mode_desc(b), \
3892 c[0], c[1], c[2], c[3]
3893 #define FILL_IIFV vv[0].i = a; vv[1].i = b; \
3894 vv[2].f = c[0]; vv[3].f = c[1]; \
3895 vv[4].f = c[2]; vv[5].f = c[3];
3898 # define WLOG(NAME,ARGS) \
3899 fprintf (stderr, "jwzgles: direct %-12s ", NAME); \
3900 fprintf (stderr, ARGS)
3902 # define WLOG(NAME,ARGS) /* */
3905 #define WRAP(NAME,SIG) \
3906 void jwzgles_##NAME (ARGS_##SIG) \
3908 Assert (!state->compiling_verts, \
3909 STRINGIFY(NAME) " not allowed inside glBegin"); \
3910 if (state->compiling_list) { \
3913 list_push (STRINGIFY(NAME), (list_fn_cb) &jwzgles_##NAME, \
3916 if (! state->replaying_list) { \
3917 WLOG (STRINGIFY(NAME), LOGS_##SIG); \
3919 NAME (VARS_##SIG); \
3920 CHECK(STRINGIFY(NAME)); \
3924 WRAP (glActiveTexture, I)
3925 WRAP (glAlphaFunc, IF)
3926 WRAP (glBlendFunc, II)
3928 WRAP (glClearColor, FFFF)
3929 WRAP (glClearStencil, I)
3930 WRAP (glColorMask, IIII)
3931 WRAP (glCullFace, I)
3932 WRAP (glDepthFunc, I)
3933 WRAP (glDepthMask, I)
3938 WRAP (glFrontFace, I)
3940 WRAP (glLightModelf, IF)
3941 WRAP (glLightModelfv, IFV)
3942 WRAP (glLightf, IIF)
3943 WRAP (glLightfv, IIFV)
3944 WRAP (glLineWidth, F)
3945 WRAP (glLoadIdentity, V)
3947 WRAP (glMatrixMode, I)
3948 WRAP (glPixelStorei, II)
3949 WRAP (glPointSize, F)
3950 WRAP (glPolygonOffset, FF)
3951 WRAP (glPopMatrix, V)
3952 WRAP (glPushMatrix, V)
3953 WRAP (glRotatef, FFFF)
3954 WRAP (glScalef, FFF)
3955 WRAP (glScissor, IIII)
3956 WRAP (glShadeModel, I)
3957 WRAP (glStencilFunc, III)
3958 WRAP (glStencilMask, I)
3959 WRAP (glStencilOp, III)
3960 WRAP (glTexEnvf, IIF)
3961 WRAP (glTexEnvi, III)
3962 WRAP (glTranslatef, FFF)
3963 WRAP (glViewport, IIII)
3965 #define TYPE_IV GLuint
3966 WRAP (glDeleteTextures, IIV)
3969 #endif /* HAVE_JWZGLES - whole file */