+/* The display list is full of calls to glDrawArrays(), plus saved arrays
+ of the values we need to restore before calling it. "Restore" means
+ "ship them off to the GPU before each call".
+
+ So instead, this function walks through the display list and
+ combines all of those vertex, normal, texture and color values into
+ a single VBO array; ships those values off to the GPU *once* at the
+ time of glEndList; and when running the list with glCallList, the
+ values are already on the GPU and don't need to be sent over again.
+
+ The VBO persists in the GPU until the display list is deleted.
+ */
+static void
+optimize_arrays (void)
+{
+ list *L = &state->lists.lists[state->compiling_list-1];
+ int i, j;
+ GLfloat *combo = 0;
+ int combo_count = 0;
+ int combo_size = 0;
+ GLuint buf_name = 0;
+
+ Assert (state->compiling_list, "not compiling a list");
+ Assert (L, "no list");
+ Assert (!L->buffer, "list already has a buffer");
+
+ glGenBuffers (1, &buf_name);
+ CHECK("glGenBuffers");
+ if (! buf_name) return;
+
+ L->buffer = buf_name;
+
+ /* Go through the list and dump the contents of the various saved arrays
+ into one large array.
+ */
+ for (i = 0; i < L->count; i++)
+ {
+ list_fn *F = &L->fns[i];
+ int count;
+ if (! F->arrays)
+ continue;
+ count = F->argv[2].i; /* 3rd arg to glDrawArrays */
+
+ for (j = 0; j < 4; j++)
+ {
+ draw_array *A = &F->arrays[j];
+ int ocount = combo_count;
+
+ /* If some caller is using arrays that don't have floats in them,
+ we just leave them as-is and ship them over at each call.
+ Doubt this ever really happens.
+ */
+ if (A->type != GL_FLOAT)
+ continue;
+
+ if (! A->data) /* No array. */
+ continue;
+
+ Assert (A->bytes > 0, "no bytes in draw_array");
+ Assert (((unsigned long) A->data > 0xFFFF),
+ "buffer data not a pointer");
+
+ combo_count += A->bytes / sizeof(*combo);
+ make_room ("optimize_arrays",
+ (void **) &combo, sizeof(*combo),
+ &combo_count, &combo_size);
+ memcpy (combo + ocount, A->data, A->bytes);
+ A->binding = buf_name;
+ free (A->data);
+ /* 'data' is now the byte offset into the VBO. */
+ A->data = (void *) (ocount * sizeof(*combo));
+ /* LOG3(" loaded %lu floats to pos %d of buffer %d",
+ A->bytes / sizeof(*combo), ocount, buf_name); */
+ }
+ }
+
+ if (combo_count == 0) /* Nothing to do! */
+ {
+ if (combo) free (combo);
+ glDeleteBuffers (1, &buf_name);
+ L->buffer = 0;
+ return;
+ }
+
+ glBindBuffer (GL_ARRAY_BUFFER, buf_name);
+ glBufferData (GL_ARRAY_BUFFER,
+ combo_count * sizeof (*combo),
+ combo,
+ GL_STATIC_DRAW);
+ glBindBuffer (GL_ARRAY_BUFFER, 0); /* Keep out of others' hands */
+
+ LOG3(" loaded %d floats of list %d into VBO %d",
+ combo_count, state->compiling_list, buf_name);
+
+# ifdef DEBUG
+# if 0
+ for (i = 0; i < combo_count; i++)
+ {
+ if (i % 4 == 0)
+ fprintf (stderr, "\njwzgles: %4d: ", i);
+ fprintf (stderr, " %7.3f", combo[i]);
+ }
+ fprintf (stderr, "\n");
+# endif
+# endif /* DEBUG */
+
+ if (combo) free (combo);
+}
+
+