#include #include #include #if defined(__APPLE__) #include #include #include #else #include #endif #include "plane.h" #include "plane_cloud.h" #include "shader.h" #define MAX_BATCH_SIZE 16 static int _initialize_batched_vbo_renderer( unsigned batch_size, GLuint *vertex_buffer_id, GLuint *index_buffer_id, shader_t *shader) { #if defined(__APPLE__) CGLContextObj CGL_MACRO_CONTEXT = CGLGetCurrentContext(); #endif if (!gluCheckExtension( (const GLubyte*)"GL_ARB_vertex_buffer_object", glGetString(GL_EXTENSIONS))) { return 0; } char *new_vertex_shader_text; asprintf( &new_vertex_shader_text, "#define BATCH_SIZE %d\n" "attribute float model_index;\n" "uniform mat4 model_matrices[BATCH_SIZE];\n" "uniform vec4 colors[BATCH_SIZE];\n" "void main() {\n" "int int_index = int(floor(model_index));\n" "gl_Position = gl_ModelViewProjectionMatrix *" "model_matrices[int_index] * gl_Vertex;\n" "gl_FrontColor = colors[int_index];\n" "}", batch_size); const char *vertex_shader_text = new_vertex_shader_text; const char *fragment_shader_text = "void main() {\n" "gl_FragColor = gl_Color;\n" "}"; *shader = make_shader( 1, &vertex_shader_text, 1, &fragment_shader_text); free(new_vertex_shader_text); if (*shader == NULL) { return 0; } else if (shader_error_text(*shader) != NULL) { fprintf(stderr, "batched VBO renderer: %s\n", shader_error_text(*shader)); delete_shader(*shader); return 0; } float color_array[4 * MAX_BATCH_SIZE] = { 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.5, 0.0, 0.0, 1.0, 0.0, 0.5, 0.0, 1.0, 0.0, 0.0, 0.5, 1.0, 0.5, 0.5, 0.0, 1.0, 0.5, 0.0, 0.5, 1.0, 0.0, 0.5, 0.5, 1.0, 0.25, 0.25, 0.25, 1.0, 0.75, 0.75, 0.75, 1.0, }; GLint colors_location = glGetUniformLocationARB( shader_program(*shader), "colors"); glUseProgramObjectARB(shader_program(*shader)); glUniform4fvARB( colors_location, batch_size, color_array); glUseProgramObjectARB(0); glGenBuffersARB(1, vertex_buffer_id); if (*vertex_buffer_id == 0) { return 0; } size_t vertex_buffer_size = 4 * sizeof(float) * PLANE_VERTEX_COUNT * batch_size; float *vertex_data = malloc(vertex_buffer_size); unsigned i; for (i = 0; i < PLANE_VERTEX_COUNT * batch_size; ++i) { unsigned vertex_index = i % PLANE_VERTEX_COUNT; vertex_data[i * 4 + 0] = PLANE_VERTICES[3 * vertex_index + 0]; vertex_data[i * 4 + 1] = PLANE_VERTICES[3 * vertex_index + 1]; vertex_data[i * 4 + 2] = PLANE_VERTICES[3 * vertex_index + 2]; vertex_data[i * 4 + 3] = (float)(i / PLANE_VERTEX_COUNT) + 0.5f; } glBindBufferARB(GL_ARRAY_BUFFER_ARB, *vertex_buffer_id); glBufferDataARB( GL_ARRAY_BUFFER_ARB, vertex_buffer_size, vertex_data, GL_STATIC_DRAW_ARB); glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); free(vertex_data); glGenBuffersARB(1, index_buffer_id); if (*index_buffer_id == 0) { glDeleteBuffersARB(1, vertex_buffer_id); return 0; } size_t index_buffer_size = sizeof(GLuint) * PLANE_INDEX_COUNT * batch_size; GLuint *index_data = malloc(index_buffer_size); for (i = 0; i < PLANE_INDEX_COUNT * batch_size; ++i) { unsigned index_index = i % PLANE_INDEX_COUNT; index_data[i] = PLANE_INDICES[index_index] + PLANE_VERTEX_COUNT * (i / PLANE_INDEX_COUNT); } glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, *index_buffer_id); glBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, index_buffer_size, index_data, GL_STATIC_DRAW_ARB); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); free(index_data); return 1; } static void _update_batched_vbo_rendererer( double dt, unsigned batch_size, GLuint vertex_buffer_id, GLuint index_buffer_id, shader_t shader) { #if defined(__APPLE__) CGLContextObj CGL_MACRO_CONTEXT = CGLGetCurrentContext(); #endif unsigned num_planes = plane_count(); const float *matrices = plane_matrices(); glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertex_buffer_id); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, index_buffer_id); glVertexPointer(3, GL_FLOAT, 4 * sizeof(float), 0); glEnableClientState(GL_VERTEX_ARRAY); GLint attribute_index = glGetAttribLocationARB( shader_program(shader), "model_index"); assert(attribute_index >= 0); glVertexAttribPointerARB( attribute_index, 1, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const void *)(3 * sizeof(float))); glEnableVertexAttribArrayARB(attribute_index); GLint matrices_location = glGetUniformLocationARB( shader_program(shader), "model_matrices"); assert(matrices_location >= 0); glUseProgramObjectARB(shader_program(shader)); unsigned i; const float *matrix = matrices; for (i = 0; i < num_planes; i += batch_size) { unsigned this_batch_size = num_planes - i; if (batch_size < this_batch_size) { this_batch_size = batch_size; } glUniformMatrix4fvARB( matrices_location, this_batch_size, GL_FALSE, matrix); glDrawElements( GL_TRIANGLES, PLANE_INDEX_COUNT * this_batch_size, GL_UNSIGNED_INT, 0); matrix += 16 * this_batch_size; } glUseProgramObjectARB(0); glDisableVertexAttribArrayARB(attribute_index); glDisableClientState(GL_VERTEX_ARRAY); glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); } //4--4--4--4--4--4--4--4--4--4--4--4--4--4--4--4--4--4--4--4--4--4--4--4--4--4-- static GLuint _vertex_buffer_id_4; static GLuint _index_buffer_id_4; static shader_t _shader_4; int initialize_batched_vbo_renderer_4(void) { return _initialize_batched_vbo_renderer( 4, &_vertex_buffer_id_4, &_index_buffer_id_4, &_shader_4); } void update_batched_vbo_renderer_4(double dt) { _update_batched_vbo_rendererer( dt, 4, _vertex_buffer_id_4, _index_buffer_id_4, _shader_4); } //16--16--16--16--16--16--16--16--16--16--16--16--16--16--16--16--16--16--16--16 static GLuint _vertex_buffer_id_16; static GLuint _index_buffer_id_16; static shader_t _shader_16; int initialize_batched_vbo_renderer_16(void) { return _initialize_batched_vbo_renderer( 16, &_vertex_buffer_id_16, &_index_buffer_id_16, &_shader_16); } void update_batched_vbo_renderer_16(double dt) { _update_batched_vbo_rendererer( dt, 16, _vertex_buffer_id_16, _index_buffer_id_16, _shader_16); }