+void
+jwzgles_glGetTexGenfv (GLenum coord, GLenum pname, GLfloat *params)
+{
+ texgen_state *s;
+
+ switch (coord) {
+ case GL_S: s = &state->s; break;
+ case GL_T: s = &state->t; break;
+ case GL_R: s = &state->r; break;
+ case GL_Q: s = &state->q; break;
+ default: Assert (0, "glGetTexGenfv: unknown coord"); break;
+ }
+
+ switch (pname) {
+ case GL_TEXTURE_GEN_MODE: params[0] = s->mode; break;
+ case GL_OBJECT_PLANE: memcpy (params, s->obj, sizeof(s->obj)); break;
+ case GL_EYE_PLANE: memcpy (params, s->eye, sizeof(s->eye)); break;
+ default: Assert (0, "glGetTexGenfv: unknown pname"); break;
+ }
+
+ if (pname == GL_TEXTURE_GEN_MODE)
+ LOG5 ("%sdirect %-12s %s %s -> %s",
+ (state->compiling_list || state->replaying_list ? " " : ""),
+ "glGetTexGenfv",
+ mode_desc(coord), mode_desc(pname), mode_desc(params[0]));
+ else
+ LOG8 ("%sdirect %-12s %s %s -> %3.1f %3.1f %3.1f %3.1f",
+ (state->compiling_list || state->replaying_list ? " " : ""),
+ "glGetTexGenfv",
+ mode_desc(coord), mode_desc(pname),
+ params[0], params[1], params[2], params[3]);
+}
+
+
+static GLfloat
+dot_product (int rank, GLfloat *a, GLfloat *b)
+{
+ /* A dot B => (A[1] * B[1]) + ... + (A[n] * B[n]) */
+ GLfloat ret = 0;
+ int i;
+ for (i = 0; i < rank; i++)
+ ret += a[i] * b[i];
+ return ret;
+}
+
+
+
+/* Compute the texture coordinates of the prevailing list of verts as per
+ http://www.opengl.org/wiki/Mathematics_of_glTexGen
+ */
+static void
+generate_texture_coords (GLuint first, GLuint count)
+{
+ GLfloat *tex_out, *tex_array;
+ GLsizei tex_stride;
+ GLuint i;
+ draw_array A = { 0, };
+ char *verts_in;
+
+ struct { GLuint which, flag, mode; GLfloat plane[4]; } tg[4] = {
+ { GL_S, ISENABLED_TEXTURE_GEN_S, 0, { 0, } },
+ { GL_T, ISENABLED_TEXTURE_GEN_T, 0, { 0, } },
+ { GL_R, ISENABLED_TEXTURE_GEN_R, 0, { 0, } },
+ { GL_Q, ISENABLED_TEXTURE_GEN_Q, 0, { 0, }}};
+
+ int tcoords = 0;
+
+ /* Read the texture plane configs that were stored with glTexGen.
+ */
+ for (i = 0; i < countof(tg); i++)
+ {
+ GLfloat mode = 0;
+ if (! ((state->compiling_list ? state->list_enabled : state->enabled)
+ & tg[i].flag))
+ continue;
+ jwzgles_glGetTexGenfv (tg[i].which, GL_TEXTURE_GEN_MODE, &mode);
+ jwzgles_glGetTexGenfv (tg[i].which, GL_OBJECT_PLANE, tg[i].plane);
+ tg[i].mode = mode;
+ tcoords++;
+ }
+
+ if (tcoords == 0) return; /* Nothing to do! */
+
+
+ /* Make the array to store our texture coords in. */
+
+ tex_stride = tcoords * sizeof(GLfloat);
+ tex_array = (GLfloat *) calloc (first + count, tex_stride);
+ tex_out = tex_array;
+
+
+ /* Read the prevailing vertex array, that was stored with
+ glVertexPointer or glInterleavedArrays.
+ */
+ glGetIntegerv (GL_VERTEX_ARRAY_BUFFER_BINDING, &A.binding);
+ glGetIntegerv (GL_VERTEX_ARRAY_SIZE, &A.size);
+ glGetIntegerv (GL_VERTEX_ARRAY_TYPE, &A.type);
+ glGetIntegerv (GL_VERTEX_ARRAY_STRIDE, &A.stride);
+ glGetPointerv (GL_VERTEX_ARRAY_POINTER, &A.data);
+ A.bytes = count * A.stride;
+
+ verts_in = (char *) A.data;
+
+ /* Iterate over each vertex we're drawing.
+ We just skip the ones < start, but the tex array has
+ left room for zeroes there anyway.
+ */
+ for (i = first; i < first + count; i++)
+ {
+ GLfloat vert[4] = { 0, };
+ int j, k;
+
+ /* Extract this vertex into `vert' as a float, whatever its type was. */
+ for (j = 0; j < A.size; j++)
+ {
+ switch (A.type) {
+ case GL_SHORT: vert[j] = ((GLshort *) verts_in)[j]; break;
+ case GL_INT: vert[j] = ((GLint *) verts_in)[j]; break;
+ case GL_FLOAT: vert[j] = ((GLfloat *) verts_in)[j]; break;
+ case GL_DOUBLE: vert[j] = ((GLdouble *) verts_in)[j]; break;
+ default: Assert (0, "unknown vertex type"); break;
+ }
+ }
+
+ /* Compute the texture coordinate for this vertex.
+ For GL_OBJECT_LINEAR, these coordinates are static, and can go
+ into the display list. But for GL_EYE_LINEAR, GL_SPHERE_MAP and
+ GL_REFLECTION_MAP, they depend on the prevailing ModelView matrix,
+ and so need to be computed afresh each time glDrawArrays is called.
+ Unfortunately, our verts and norms are gone by then, dumped down
+ into the VBO and discarded from CPU RAM. Bleh.
+ */
+ for (j = 0, k = 0; j < countof(tg); j++)
+ {
+ if (! ((state->compiling_list ? state->list_enabled : state->enabled)
+ & tg[j].flag))
+ continue;
+ switch (tg[j].mode) {
+ case GL_OBJECT_LINEAR:
+ tex_out[k] = dot_product (4, vert, tg[j].plane);
+ break;
+ default:
+ Assert (0, "unimplemented texture mode");
+ break;
+ }
+ k++;
+ }
+
+ /* fprintf (stderr, "%4d: V %-5.1f %-5.1f %-5.1f T %-5.1f %-5.1f\n",
+ i, vert[0], vert[1], vert[2], tex_out[0], tex_out[1]); */
+
+ /* Move verts_in and tex_out forward to the next vertex by stride. */
+ verts_in += A.stride;
+ tex_out = (GLfloat *) (((char *) tex_out) + tex_stride);
+ }
+
+ jwzgles_glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+ jwzgles_glTexCoordPointer (tcoords, GL_FLOAT, tex_stride,
+ (GLvoid *) tex_array);
+ free (tex_array);
+}
+