typedef union { float values[12]; struct { float x, y, z, w; float a, b, c, d; float s, t, r, q; } components; } Vertex; const struct { char name; unsigned index; } INDEX_MAP[12] = { {'x', 0}, {'y', 1}, {'z', 2}, {'w', 3}, {'a', 4}, {'b', 5}, {'c', 6}, {'d', 7}, {'s', 8}, {'t', 9}, {'r', 10}, {'q', 11} }; static unsigned find_index(char name) { for (unsigned i = 0; i < 12; ++i) { if (INDEX_MAP[i].name == name) { return INDEX_MAP[i].index; } } abort(); } static void pack_vertex( const char *format, const Vertex *vertex, float *buffer) { const char *cursor = format; int buffer_index = 0; while (*cursor != '\0') { buffer[buffer_index] = vertex->values[find_index(*cursor)]; ++buffer_index; ++cursor; } } #define TESSELLATION 64 #define VERTEX_COUNT ((TESSELLATION + 1) * (TESSELLATION + 1)) Vertex VERTICES[VERTEX_COUNT]; static void create_vertices(void) { for (unsigned y = 0; y <= TESSELLATION; ++y) { for (unsigned x = 0; x <= TESSELLATION; ++x) { VERTICES[x + y * (TESSELLATION + 1)].components.x = x * 2.0f / TESSELLATION - 1.0f; VERTICES[x + y * (TESSELLATION + 1)].components.y = y * 2.0f / TESSELLATION - 1.0f; VERTICES[x + y * (TESSELLATION + 1)].components.z = 0.0f; VERTICES[x + y * (TESSELLATION + 1)].components.w = 1.0f; VERTICES[x + y * (TESSELLATION + 1)].components.a = 0.0f; VERTICES[x + y * (TESSELLATION + 1)].components.b = 0.0f; VERTICES[x + y * (TESSELLATION + 1)].components.c = 1.0f; VERTICES[x + y * (TESSELLATION + 1)].components.d = 0.0f; VERTICES[x + y * (TESSELLATION + 1)].components.s = x * 1.0f / TESSELLATION; VERTICES[x + y * (TESSELLATION + 1)].components.t = y * 1.0f / TESSELLATION; VERTICES[x + y * (TESSELLATION + 1)].components.r = 0.0f; VERTICES[x + y * (TESSELLATION + 1)].components.q = 1.0f; } } } #define INDEX_COUNT (3 * 2 * TESSELLATION * TESSELLATION) GLuint INDICES[INDEX_COUNT]; void create_indices(void) { unsigned i = 0; for (unsigned y = 0; y < TESSELLATION; ++y) { for (unsigned x = 0; x < TESSELLATION; ++x) { GLuint lower_left = x + y * (TESSELLATION + 1); GLuint lower_right = x + 1 + y * (TESSELLATION + 1); GLuint upper_right = x + 1 + (y + 1) * (TESSELLATION + 1); GLuint upper_left = x + (y + 1) * (TESSELLATION + 1); INDICES[i++] = lower_left; INDICES[i++] = lower_right; INDICES[i++] = upper_right; INDICES[i++] = upper_right; INDICES[i++] = upper_left; INDICES[i++] = lower_left; } } } GLuint create_array_buffer_object(unsigned component_count) { GLuint array_buffer; glGenBuffersARB(1, &array_buffer); glBindBufferARB(GL_ARRAY_BUFFER_ARB, array_buffer); glBufferDataARB( GL_ARRAY_BUFFER_ARB, VERTEX_COUNT * component_count * sizeof(float), NULL, GL_STATIC_DRAW_ARB); return array_buffer; } static GLuint create_index_buffer_object(void) { GLuint index_buffer; glGenBuffersARB(1, &index_buffer); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, index_buffer); glBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, INDEX_COUNT * sizeof(GLuint), INDICES, GL_STATIC_DRAW_ARB); return index_buffer; } typedef struct { GLuint array_buffer_id; GLsizei vertex_pointer_offset; GLsizei normal_pointer_offset; GLsizei texcoord_pointer_offset; GLsizei vertex_size; GLsizei texcoord_size; GLsizei vertex_stride; GLsizei normal_stride; GLsizei texcoord_stride; } ArrayFormat; static void parse_simple_format( const char *format, ArrayFormat *array_format, GLsizei offset) { unsigned stride = strlen(format); const char *p; if ((p = strstr(format, "xyzw")) != NULL) { array_format->vertex_size = 4; array_format->vertex_pointer_offset = offset + p - format; array_format->vertex_stride = stride; } else if ((p = strstr(format, "xyz")) != NULL) { array_format->vertex_size = 3; array_format->vertex_pointer_offset = offset + p - format; array_format->vertex_stride = stride; } else if (strcspn(format, "xyzw") != stride) { abort(); } if ((p = strstr(format, "abc")) != NULL) { array_format->normal_pointer_offset = offset + p - format; array_format->normal_stride = stride; } else if (strcspn(format, "abcd") != stride) { abort(); } if ((p = strstr(format, "strq")) != NULL) { array_format->texcoord_size = 4; array_format->texcoord_pointer_offset = offset + p - format; array_format->texcoord_stride = stride; } else if ((p = strstr(format, "str")) != NULL) { array_format->texcoord_size = 3; array_format->texcoord_pointer_offset = offset + p - format; array_format->texcoord_stride = stride; } else if ((p = strstr(format, "st")) != NULL) { array_format->texcoord_size = 2; array_format->texcoord_pointer_offset = offset + p - format; array_format->texcoord_stride = stride; } else if (strcspn(format, "strq") != stride) { abort(); } } static void parse_format( const char *format, ArrayFormat *array_format) { unsigned component_count = 0; for (const char *cursor = format; *cursor != '\0'; ++cursor) { if (*cursor != '|') { ++component_count; } } glDeleteBuffers(1, &(array_format->array_buffer_id)); array_format->array_buffer_id = create_array_buffer_object(component_count); glBindBufferARB(GL_ARRAY_BUFFER_ARB, array_format->array_buffer_id); float *vertex_data = glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); GLsizei offset = 0; char buffer[128]; strcpy(buffer, format); char *next = buffer; const char *simple_format; while ((simple_format = strsep(&next, "|")) != NULL) { parse_simple_format(simple_format, array_format, offset); unsigned simple_component_count = strlen(simple_format); for (unsigned i = 0; i < VERTEX_COUNT; ++i) { pack_vertex( simple_format, VERTICES + i, vertex_data + offset + (i * simple_component_count)); } offset += VERTEX_COUNT * simple_component_count; } glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); } GLuint INDEX_BUFFER_ID; ArrayFormat FORMAT; unsigned FRAME_COUNT; unsigned START_TIME; unsigned CURRENT_FORMAT; #define FORMAT_COUNT 8 const char *FORMATS[FORMAT_COUNT] = { "xyzabcst", "xyzabcstr", "xyzwabcdst", "xyzwabcdstrq", "xyz|abc|st", "xyz|abc|str", "xyzw|abc|st", "xyzw|abcd|strq" }; #define NUMBER_OF_FRAMES 10000 static void display(void) { ++FRAME_COUNT; if (FRAME_COUNT % NUMBER_OF_FRAMES == 0) { unsigned now = glutGet(GLUT_ELAPSED_TIME); printf( "%s -- %u frames in %ums\n", FORMATS[CURRENT_FORMAT], NUMBER_OF_FRAMES, now - START_TIME); CURRENT_FORMAT = (CURRENT_FORMAT + 1) % FORMAT_COUNT; parse_format(FORMATS[CURRENT_FORMAT], &FORMAT); START_TIME = glutGet(GLUT_ELAPSED_TIME); } glClear(GL_COLOR_BUFFER_BIT); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glBindBufferARB(GL_ARRAY_BUFFER_ARB, FORMAT.array_buffer_id); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, INDEX_BUFFER_ID); glVertexPointer( FORMAT.vertex_size, GL_FLOAT, FORMAT.vertex_stride * sizeof(float), (void*)(FORMAT.vertex_pointer_offset * sizeof(float))); glNormalPointer( GL_FLOAT, FORMAT.normal_stride * sizeof(float), (void*)(FORMAT.normal_pointer_offset * sizeof(float))); glTexCoordPointer( FORMAT.texcoord_size, GL_FLOAT, FORMAT.texcoord_stride * sizeof(float), (void*)(FORMAT.texcoord_pointer_offset * sizeof(float))); glDrawElements( GL_TRIANGLES, INDEX_COUNT, GL_UNSIGNED_INT, (void*)0); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glutSwapBuffers(); glutReportErrors(); } static void reshape(int width, int height) { glViewport(0, 0, width, height); } static void idle(void) { glutPostRedisplay(); } int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); glutInitWindowSize(512, 512); glutCreateWindow("VBO Speed Test"); glutDisplayFunc(display); glutReshapeFunc(reshape); glutIdleFunc(idle); create_vertices(); create_indices(); INDEX_BUFFER_ID = create_index_buffer_object(); FORMAT.array_buffer_id = 0; FRAME_COUNT = 0; START_TIME = glutGet(GLUT_ELAPSED_TIME); CURRENT_FORMAT = 0; parse_format(FORMATS[CURRENT_FORMAT], &FORMAT); glutMainLoop(); return EXIT_SUCCESS; }