From 33471b4c469890a6d0284d001c47ed78fad3e62b Mon Sep 17 00:00:00 2001 From: veclavtalica Date: Fri, 3 Jan 2025 21:01:26 +0300 Subject: [PATCH] generalization of deferred commands and any_gl rendering where appropriate --- src/rendering/twn_deferred_commands.h | 3 + src/rendering/twn_draw.c | 125 +++++++ src/rendering/twn_draw_c.h | 21 +- src/rendering/twn_fog.c | 20 +- src/rendering/twn_gl_15_rendering.c | 436 +++++++------------------ src/rendering/twn_gl_any_rendering.c | 36 ++ src/rendering/twn_gl_any_rendering_c.h | 16 + src/rendering/twn_skybox.c | 11 +- 8 files changed, 347 insertions(+), 321 deletions(-) create mode 100644 src/rendering/twn_gl_any_rendering_c.h diff --git a/src/rendering/twn_deferred_commands.h b/src/rendering/twn_deferred_commands.h index b5837c9..0616f2d 100644 --- a/src/rendering/twn_deferred_commands.h +++ b/src/rendering/twn_deferred_commands.h @@ -109,4 +109,7 @@ typedef struct { }; } DeferredCommand; + +extern DeferredCommand *deferred_commands; + #endif diff --git a/src/rendering/twn_draw.c b/src/rendering/twn_draw.c index 9403189..a234686 100644 --- a/src/rendering/twn_draw.c +++ b/src/rendering/twn_draw.c @@ -4,6 +4,7 @@ #include "twn_camera_c.h" #include "twn_types.h" #include "twn_vec.h" +#include "twn_deferred_commands.h" #include #include @@ -18,6 +19,8 @@ #include +DeferredCommand *deferred_commands; + /* TODO: have a default initialized one */ Matrix4 camera_projection_matrix; Matrix4 camera_look_at_matrix; @@ -401,3 +404,125 @@ DrawCameraFromPrincipalAxesResult draw_camera_from_principal_axes(Vec3 position, .up = camera.up, }; } + + +void set_depth_range(double low, double high) { + DeferredCommand const command = { + .type = DEFERRED_COMMAND_TYPE_DEPTH_RANGE, + .depth_range = { + .low = low, + .high = high + } + }; + + arrpush(deferred_commands, command); +} + + +void clear_draw_buffer(void) { + /* TODO: we can optimize a rectangle drawn over whole window to a clear color call*/ + + DeferredCommand command = { + .type = DEFERRED_COMMAND_TYPE_CLEAR, + .clear = (DeferredCommandClear) { + .clear_color = true, + .clear_depth = true, + .clear_stencil = true, + .color = (Color) { 230, 230, 230, 1 } + } + }; + + arrpush(deferred_commands, command); +} + + +void use_texture_mode(TextureMode mode) { + DeferredCommand const command = { + .type = DEFERRED_COMMAND_TYPE_USE_TEXTURE_MODE, + .use_texture_mode = { mode } + }; + + arrpush(deferred_commands, command); +} + + +void use_2d_pipeline(void) { + DeferredCommand const command = { + .type = DEFERRED_COMMAND_TYPE_USE_PIPIELINE, + .use_pipeline = { PIPELINE_2D } + }; + + arrpush(deferred_commands, command); +} + + +void use_space_pipeline(void) { + DeferredCommand const command = { + .type = DEFERRED_COMMAND_TYPE_USE_PIPIELINE, + .use_pipeline = { PIPELINE_SPACE } + }; + + arrpush(deferred_commands, command); +} + + +void issue_deferred_draw_commands(void) { + for (size_t i = 0; i < arrlenu(deferred_commands); ++i) { + switch (deferred_commands[i].type) { + case DEFERRED_COMMAND_TYPE_DEPTH_RANGE: { + finally_set_depth_range(deferred_commands[i].depth_range); + break; + } + + case DEFERRED_COMMAND_TYPE_CLEAR: { + finally_clear_draw_buffer(deferred_commands[i].clear); + break; + } + + case DEFERRED_COMMAND_TYPE_DRAW: { + finally_draw_command(deferred_commands[i].draw); + break; + } + + case DEFERRED_COMMAND_TYPE_DRAW_SKYBOX: { + finally_render_skybox(deferred_commands[i].draw_skybox); + break; + } + + case DEFERRED_COMMAND_TYPE_USE_PIPIELINE: { + switch (deferred_commands[i].use_pipeline.pipeline) { + case PIPELINE_2D: + finally_use_2d_pipeline(); + break; + case PIPELINE_SPACE: + finally_use_space_pipeline(); + break; + case PIPELINE_NO: + default: + SDL_assert(false); + } + + break; + } + + case DEFERRED_COMMAND_TYPE_USE_TEXTURE_MODE: { + finally_use_texture_mode(deferred_commands[i].use_texture_mode.mode); + break; + } + + case DEFERRED_COMMAND_TYPE_APPLY_FOG: { + finally_apply_fog(deferred_commands[i].apply_fog); + break; + } + + case DEFERRED_COMMAND_TYPE_POP_FOG: { + finally_pop_fog(); + break; + } + + default: + SDL_assert(false); + } + } +} + diff --git a/src/rendering/twn_draw_c.h b/src/rendering/twn_draw_c.h index fccde14..66447e0 100644 --- a/src/rendering/twn_draw_c.h +++ b/src/rendering/twn_draw_c.h @@ -1,9 +1,12 @@ #ifndef TWN_DRAW_C_H #define TWN_DRAW_C_H +/* TODO: structure more categorically */ + #include "twn_textures_c.h" #include "twn_text_c.h" #include "twn_option.h" +#include "twn_deferred_commands.h" #include #include @@ -173,10 +176,12 @@ bool push_to_vertex_buffer_builder(VertexBufferBuilder *builder, void setup_viewport(int x, int y, int width, int height); void clear_draw_buffer(void); +void finally_clear_draw_buffer(DeferredCommandClear command); void swap_buffers(void); void set_depth_range(double low, double high); +void finally_set_depth_range(DeferredCommandDepthRange command); VertexBuffer get_quad_element_buffer(void); @@ -187,10 +192,13 @@ void render_circle(const CirclePrimitive *circle); void render_rectangle(const RectPrimitive *rectangle); void use_space_pipeline(void); +void finally_use_space_pipeline(void); void use_2d_pipeline(void); +void finally_use_2d_pipeline(void); void use_texture_mode(TextureMode mode); +void finally_use_texture_mode(TextureMode mode); void finally_render_quads(Primitive2D const primitives[], struct QuadBatch batch, @@ -220,19 +228,18 @@ void finally_draw_text(FontData const *font_data, VertexBuffer buffer); void render_skybox(void); - -void finally_render_skybox(char *paths_in_use); +void finally_render_skybox(DeferredCommandDrawSkybox); void apply_fog(void); - -void finally_apply_fog(float start, float end, float density, Color color); - +void finally_apply_fog(DeferredCommandApplyFog); void pop_fog(void); - void finally_pop_fog(void); void start_render_frame(void); - void end_render_frame(void); +void finally_draw_command(DeferredCommandDraw command); + +void issue_deferred_draw_commands(void); + #endif diff --git a/src/rendering/twn_fog.c b/src/rendering/twn_fog.c index 2b27756..1d4c4a5 100644 --- a/src/rendering/twn_fog.c +++ b/src/rendering/twn_fog.c @@ -1,6 +1,8 @@ #include "twn_draw.h" #include "twn_draw_c.h" +#include + #include static float start_cache, end_cache, density_cache; @@ -21,7 +23,17 @@ void apply_fog(void) { if (!fog_used) return; - finally_apply_fog(start_cache, end_cache, density_cache, color_cache); + DeferredCommand command = { + .type = DEFERRED_COMMAND_TYPE_APPLY_FOG, + .apply_fog = (DeferredCommandApplyFog){ + .start = start_cache, + .end = end_cache, + .density = density_cache, + .color = color_cache + } + }; + + arrpush(deferred_commands, command); } @@ -29,5 +41,9 @@ void pop_fog(void) { if (!fog_used) return; - finally_pop_fog(); + DeferredCommand command = { + .type = DEFERRED_COMMAND_TYPE_POP_FOG, + }; + + arrpush(deferred_commands, command); } diff --git a/src/rendering/twn_gl_15_rendering.c b/src/rendering/twn_gl_15_rendering.c index 94f923f..6f089ba 100644 --- a/src/rendering/twn_gl_15_rendering.c +++ b/src/rendering/twn_gl_15_rendering.c @@ -5,6 +5,7 @@ #include "twn_text_c.h" #include "twn_types.h" #include "twn_deferred_commands.h" +#include "twn_gl_any_rendering_c.h" #include #include @@ -81,219 +82,6 @@ static TextureMode texture_mode_last_used = TEXTURE_MODE_UNKNOWN; static Pipeline pipeline_last_used = PIPELINE_NO; -/* potentially double buffered array of vertex array handles */ -/* we assume they will be refilled fully each frame */ -static size_t scratch_va_front_used, scratch_va_back_used; -static GLuint *front_scratch_vertex_arrays, *back_scratch_vertex_arrays; -static GLuint **current_scratch_vertex_array = &front_scratch_vertex_arrays; - -static void restart_scratch_vertex_arrays(void) { - scratch_va_front_used = 0; - scratch_va_back_used = 0; - - if (ctx.render_double_buffered) { - current_scratch_vertex_array = current_scratch_vertex_array == &front_scratch_vertex_arrays ? - &back_scratch_vertex_arrays : &front_scratch_vertex_arrays; - } -} - - -GLuint get_scratch_vertex_array(void) { - size_t *used = current_scratch_vertex_array == &front_scratch_vertex_arrays ? - &scratch_va_front_used : &scratch_va_back_used; - - if (arrlenu(*current_scratch_vertex_array) <= *used) { - GLuint handle; - glGenBuffers(1, &handle); - arrpush(*current_scratch_vertex_array, handle); - } - - (*used)++; - return (*current_scratch_vertex_array)[*used - 1]; -} - - -static void finally_use_2d_pipeline(void); -static void finally_use_space_pipeline(void); -static void finally_use_texture_mode(TextureMode mode); -static void deferred_render_skybox(char *paths); -static void deferred_apply_fog(float start, float end, float density, Color color); -static void deferred_pop_fog(void); - -static DeferredCommand *deferred_commands; - -static void issue_deferred_draw_commands(void) { - for (size_t i = 0; i < arrlenu(deferred_commands); ++i) { - switch (deferred_commands[i].type) { - case DEFERRED_COMMAND_TYPE_DEPTH_RANGE: { - glDepthRange(deferred_commands[i].depth_range.low, deferred_commands[i].depth_range.high); - break; - } - case DEFERRED_COMMAND_TYPE_CLEAR: { - glClearColor((1.0f / 255) * deferred_commands[i].clear.color.r, - (1.0f / 255) * deferred_commands[i].clear.color.g, - (1.0f / 255) * deferred_commands[i].clear.color.b, - (1.0f / 255) * deferred_commands[i].clear.color.a); - - /* needed as we might mess with it */ - glDepthRange(0.0, 1.0); - glDepthMask(GL_TRUE); - - glClear((deferred_commands[i].clear.clear_color ? GL_COLOR_BUFFER_BIT : 0) | - (deferred_commands[i].clear.clear_depth ? GL_DEPTH_BUFFER_BIT : 0) | - (deferred_commands[i].clear.clear_stencil ? GL_STENCIL_BUFFER_BIT : 0) ); - break; - } - - case DEFERRED_COMMAND_TYPE_DRAW: { - DeferredCommandDraw const command = deferred_commands[i].draw; - - /* TODO: don't assume a single vertex array ? */ - SDL_assert(command.vertices.arity != 0); - SDL_assert(command.vertices.buffer); - SDL_assert((command.element_buffer && command.element_count != 0) || command.primitive_count != 0); - - glBindBuffer(GL_ARRAY_BUFFER, command.vertices.buffer); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, command.element_buffer); - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(command.vertices.arity, - command.vertices.type, - command.vertices.stride, - (void *)command.vertices.offset); - - if (command.texcoords.arity != 0) { - SDL_assert(command.texcoords.buffer == command.vertices.buffer); - - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTexture(GL_TEXTURE0); - glTexCoordPointer(command.texcoords.arity, - command.texcoords.type, - command.texcoords.stride, - (void *)command.texcoords.offset); - } - - if (command.colors.arity != 0) { - SDL_assert(command.colors.buffer == command.vertices.buffer); - - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(command.colors.arity, - command.colors.type, - command.colors.stride, - (void *)command.colors.offset); - } else if (command.constant_colored) - glColor4ub(command.color.r, - command.color.g, - command.color.b, - command.color.a); - - if (command.textured) { - if (command.uses_gpu_key) - glBindTexture(GL_TEXTURE_2D, command.gpu_texture); - else if (command.texture_repeat) - textures_bind_repeating(&ctx.texture_cache, command.texture_key); - else - textures_bind(&ctx.texture_cache, command.texture_key); - } - - if (command.element_buffer) { - SDL_assert(command.element_count != 0); - if (command.range_start == command.range_end) - glDrawElements(GL_TRIANGLES, command.element_count, GL_UNSIGNED_SHORT, NULL); - else - glDrawRangeElements(GL_TRIANGLES, - command.range_start, - command.range_end, - command.element_count, - GL_UNSIGNED_SHORT, - NULL); - } else { - SDL_assert(command.primitive_count != 0); - glDrawArrays(GL_TRIANGLES, 0, command.primitive_count); - } - - /* state clearing */ - - if (command.textured) - glBindTexture(GL_TEXTURE_2D, 0); - - if (command.colors.arity != 0) - glDisableClientState(GL_COLOR_ARRAY); - - if (command.texcoords.arity != 0) - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - - glDisableClientState(GL_VERTEX_ARRAY); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - break; - } - - case DEFERRED_COMMAND_TYPE_DRAW_SKYBOX: { - deferred_render_skybox(deferred_commands[i].draw_skybox.paths); - break; - } - - case DEFERRED_COMMAND_TYPE_USE_PIPIELINE: { - switch (deferred_commands[i].use_pipeline.pipeline) { - case PIPELINE_2D: - finally_use_2d_pipeline(); - break; - case PIPELINE_SPACE: - finally_use_space_pipeline(); - break; - case PIPELINE_NO: - default: - SDL_assert(false); - } - - break; - } - - case DEFERRED_COMMAND_TYPE_USE_TEXTURE_MODE: { - finally_use_texture_mode(deferred_commands[i].use_texture_mode.mode); - break; - } - - case DEFERRED_COMMAND_TYPE_APPLY_FOG: { - deferred_apply_fog(deferred_commands[i].apply_fog.start, - deferred_commands[i].apply_fog.end, - deferred_commands[i].apply_fog.density, - deferred_commands[i].apply_fog.color); - break; - } - - case DEFERRED_COMMAND_TYPE_POP_FOG: { - deferred_pop_fog(); - break; - } - - default: - SDL_assert(false); - } - } -} - - -void clear_draw_buffer(void) { - /* TODO: we can optimize a rectangle drawn over whole window to a clear color call*/ - - DeferredCommand command = { - .type = DEFERRED_COMMAND_TYPE_CLEAR, - .clear = (DeferredCommandClear) { - .clear_color = true, - .clear_depth = true, - .clear_stencil = true, - .color = (Color) { 230, 230, 230, 1 } - } - }; - - arrpush(deferred_commands, command); -} - - void start_render_frame(void) { clear_draw_buffer(); } @@ -318,17 +106,7 @@ void end_render_frame(void) { } -void use_space_pipeline(void) { - DeferredCommand const command = { - .type = DEFERRED_COMMAND_TYPE_USE_PIPIELINE, - .use_pipeline = { PIPELINE_SPACE } - }; - - arrpush(deferred_commands, command); -} - - -static void finally_use_space_pipeline(void) { +void finally_use_space_pipeline(void) { if (pipeline_last_used == PIPELINE_SPACE) return; @@ -366,17 +144,7 @@ static void finally_use_space_pipeline(void) { } -void use_2d_pipeline(void) { - DeferredCommand const command = { - .type = DEFERRED_COMMAND_TYPE_USE_PIPIELINE, - .use_pipeline = { PIPELINE_2D } - }; - - arrpush(deferred_commands, command); -} - - -static void finally_use_2d_pipeline(void) { +void finally_use_2d_pipeline(void) { if (pipeline_last_used == PIPELINE_SPACE) { glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glFlush(); @@ -418,17 +186,7 @@ static void finally_use_2d_pipeline(void) { } -void use_texture_mode(TextureMode mode) { - DeferredCommand const command = { - .type = DEFERRED_COMMAND_TYPE_USE_TEXTURE_MODE, - .use_texture_mode = { mode } - }; - - arrpush(deferred_commands, command); -} - - -static void finally_use_texture_mode(TextureMode mode) { +void finally_use_texture_mode(TextureMode mode) { if (texture_mode_last_used == mode) return; @@ -815,6 +573,7 @@ size_t get_text_payload_size(void) { return sizeof (ElementIndexedQuadWithoutColor); } + static void load_cubemap_side(const char *path, GLenum target) { SDL_Surface *surface = textures_load_surface(path); /* TODO: sanity check whether all of them have same dimensions? */ @@ -891,35 +650,23 @@ void render_circle(const CirclePrimitive *circle) { } -void finally_render_skybox(char *paths) { - DeferredCommand command = { - .type = DEFERRED_COMMAND_TYPE_DRAW_SKYBOX, - .draw_skybox = (DeferredCommandDrawSkybox){ - .paths = paths - } - }; - - arrpush(deferred_commands, command); -} - - -static void deferred_render_skybox(char *paths) { +void finally_render_skybox(DeferredCommandDrawSkybox command) { static GLuint cubemap = 0; static char *paths_cache = NULL; bool loading_needed = false; /* drop it */ - if (!paths_cache || (SDL_strcmp(paths_cache, paths) != 0)) { + if (!paths_cache || (SDL_strcmp(paths_cache, command.paths) != 0)) { if (cubemap) glDeleteTextures(1, &cubemap); glGenTextures(1, &cubemap); if (paths_cache) SDL_free(paths_cache); - paths_cache = paths; + paths_cache = command.paths; loading_needed = true; } else - SDL_free(paths); + SDL_free(command.paths); Matrix4 camera_look_at_matrix_solipsist = camera_look_at_matrix; camera_look_at_matrix_solipsist.row[3].x = 0; @@ -935,27 +682,27 @@ static void deferred_render_skybox(char *paths) { if (loading_needed) { /* load all the sides */ - char *expanded = expand_asterisk(paths, "up"); + char *expanded = expand_asterisk(command.paths, "up"); load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_POSITIVE_Y); SDL_free(expanded); - expanded = expand_asterisk(paths, "down"); + expanded = expand_asterisk(command.paths, "down"); load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y); SDL_free(expanded); - expanded = expand_asterisk(paths, "east"); + expanded = expand_asterisk(command.paths, "east"); load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_POSITIVE_X); SDL_free(expanded); - expanded = expand_asterisk(paths, "north"); + expanded = expand_asterisk(command.paths, "north"); load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_POSITIVE_Z); SDL_free(expanded); - expanded = expand_asterisk(paths, "west"); + expanded = expand_asterisk(command.paths, "west"); load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_NEGATIVE_X); SDL_free(expanded); - expanded = expand_asterisk(paths, "south"); + expanded = expand_asterisk(command.paths, "south"); load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z); SDL_free(expanded); } @@ -1051,65 +798,132 @@ static void deferred_render_skybox(char *paths) { } -void finally_apply_fog(float start, float end, float density, Color color) { - DeferredCommand command = { - .type = DEFERRED_COMMAND_TYPE_APPLY_FOG, - .apply_fog = (DeferredCommandApplyFog){ - .start = start, - .end = end, - .density = density, - .color = color - } - }; - - arrpush(deferred_commands, command); -} - - -static void deferred_apply_fog(float start, float end, float density, Color color) { - if (density < 0.0f || density > 1.0f) +void finally_apply_fog(DeferredCommandApplyFog command) { + if (command.density < 0.0f || command.density > 1.0f) log_warn("Invalid fog density given, should be in range [0..1]"); /* TODO: cache it for constant parameters, which is a common case */ glEnable(GL_FOG); - glFogf(GL_FOG_DENSITY, density); - glFogf(GL_FOG_START, start); - glFogf(GL_FOG_END, end); + glFogf(GL_FOG_DENSITY, command.density); + glFogf(GL_FOG_START, command.start); + glFogf(GL_FOG_END, command.end); float color_conv[4]; - color_conv[0] = (float)color.r / UINT8_MAX; - color_conv[1] = (float)color.g / UINT8_MAX; - color_conv[2] = (float)color.b / UINT8_MAX; - color_conv[3] = (float)color.a / UINT8_MAX; + color_conv[0] = (float)command.color.r / UINT8_MAX; + color_conv[1] = (float)command.color.g / UINT8_MAX; + color_conv[2] = (float)command.color.b / UINT8_MAX; + color_conv[3] = (float)command.color.a / UINT8_MAX; glFogfv(GL_FOG_COLOR, color_conv); } void finally_pop_fog(void) { - DeferredCommand command = { - .type = DEFERRED_COMMAND_TYPE_POP_FOG, - }; - - arrpush(deferred_commands, command); -} - - -static void deferred_pop_fog(void) { glDisable(GL_FOG); } -void set_depth_range(double low, double high) { - DeferredCommand const command = { - .type = DEFERRED_COMMAND_TYPE_DEPTH_RANGE, - .depth_range = { - .low = low, - .high = high - } - }; - - arrpush(deferred_commands, command); +void finally_set_depth_range(DeferredCommandDepthRange command) { + glDepthRange(command.low, command.high); +} + + +void finally_clear_draw_buffer(DeferredCommandClear command) { + glClearColor((1.0f / 255) * command.color.r, + (1.0f / 255) * command.color.g, + (1.0f / 255) * command.color.b, + (1.0f / 255) * command.color.a); + + /* needed as we might mess with it */ + glDepthRange(0.0, 1.0); + glDepthMask(GL_TRUE); + + glClear((command.clear_color ? GL_COLOR_BUFFER_BIT : 0) | + (command.clear_depth ? GL_DEPTH_BUFFER_BIT : 0) | + (command.clear_stencil ? GL_STENCIL_BUFFER_BIT : 0) ); +} + + +void finally_draw_command(DeferredCommandDraw command) { + /* TODO: don't assume a single vertex array ? */ + SDL_assert(command.vertices.arity != 0); + SDL_assert(command.vertices.buffer); + SDL_assert((command.element_buffer && command.element_count != 0) || command.primitive_count != 0); + + glBindBuffer(GL_ARRAY_BUFFER, command.vertices.buffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, command.element_buffer); + + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(command.vertices.arity, + command.vertices.type, + command.vertices.stride, + (void *)command.vertices.offset); + + if (command.texcoords.arity != 0) { + SDL_assert(command.texcoords.buffer == command.vertices.buffer); + + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTexture(GL_TEXTURE0); + glTexCoordPointer(command.texcoords.arity, + command.texcoords.type, + command.texcoords.stride, + (void *)command.texcoords.offset); + } + + if (command.colors.arity != 0) { + SDL_assert(command.colors.buffer == command.vertices.buffer); + + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(command.colors.arity, + command.colors.type, + command.colors.stride, + (void *)command.colors.offset); + } else if (command.constant_colored) + glColor4ub(command.color.r, + command.color.g, + command.color.b, + command.color.a); + + if (command.textured) { + if (command.uses_gpu_key) + glBindTexture(GL_TEXTURE_2D, command.gpu_texture); + else if (command.texture_repeat) + textures_bind_repeating(&ctx.texture_cache, command.texture_key); + else + textures_bind(&ctx.texture_cache, command.texture_key); + } + + if (command.element_buffer) { + SDL_assert(command.element_count != 0); + if (command.range_start == command.range_end) + glDrawElements(GL_TRIANGLES, command.element_count, GL_UNSIGNED_SHORT, NULL); + else + glDrawRangeElements(GL_TRIANGLES, + command.range_start, + command.range_end, + command.element_count, + GL_UNSIGNED_SHORT, + NULL); + } else { + SDL_assert(command.primitive_count != 0); + glDrawArrays(GL_TRIANGLES, 0, command.primitive_count); + } + + /* state clearing */ + + if (command.textured) + glBindTexture(GL_TEXTURE_2D, 0); + + if (command.colors.arity != 0) + glDisableClientState(GL_COLOR_ARRAY); + + if (command.texcoords.arity != 0) + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + glDisableClientState(GL_VERTEX_ARRAY); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } diff --git a/src/rendering/twn_gl_any_rendering.c b/src/rendering/twn_gl_any_rendering.c index fc9817a..f228995 100644 --- a/src/rendering/twn_gl_any_rendering.c +++ b/src/rendering/twn_gl_any_rendering.c @@ -1,4 +1,8 @@ +#include "twn_gl_any_rendering_c.h" #include "twn_draw_c.h" +#include "twn_engine_context_c.h" + +#include #ifdef EMSCRIPTEN #include @@ -84,3 +88,35 @@ VertexBuffer get_circle_element_buffer(void) { return buffer; } + + +/* potentially double buffered array of vertex array handles */ +/* we assume they will be refilled fully each frame */ +static size_t scratch_va_front_used, scratch_va_back_used; +static GLuint *front_scratch_vertex_arrays, *back_scratch_vertex_arrays; +static GLuint **current_scratch_vertex_array = &front_scratch_vertex_arrays; + +void restart_scratch_vertex_arrays(void) { + scratch_va_front_used = 0; + scratch_va_back_used = 0; + + if (ctx.render_double_buffered) { + current_scratch_vertex_array = current_scratch_vertex_array == &front_scratch_vertex_arrays ? + &back_scratch_vertex_arrays : &front_scratch_vertex_arrays; + } +} + + +GLuint get_scratch_vertex_array(void) { + size_t *used = current_scratch_vertex_array == &front_scratch_vertex_arrays ? + &scratch_va_front_used : &scratch_va_back_used; + + if (arrlenu(*current_scratch_vertex_array) <= *used) { + GLuint handle; + glGenBuffers(1, &handle); + arrpush(*current_scratch_vertex_array, handle); + } + + (*used)++; + return (*current_scratch_vertex_array)[*used - 1]; +} diff --git a/src/rendering/twn_gl_any_rendering_c.h b/src/rendering/twn_gl_any_rendering_c.h new file mode 100644 index 0000000..74ec20e --- /dev/null +++ b/src/rendering/twn_gl_any_rendering_c.h @@ -0,0 +1,16 @@ +#ifndef TWN_GL_ANY_RENDERING_C_H +#define TWN_GL_ANY_RENDERING_C_H + +#ifdef EMSCRIPTEN +#include +#else +#include +#endif + +#include + +void restart_scratch_vertex_arrays(void); + +GLuint get_scratch_vertex_array(void); + +#endif diff --git a/src/rendering/twn_skybox.c b/src/rendering/twn_skybox.c index 8361c7b..590edc2 100644 --- a/src/rendering/twn_skybox.c +++ b/src/rendering/twn_skybox.c @@ -2,6 +2,7 @@ #include "twn_draw_c.h" #include +#include static char *paths_in_use; @@ -21,6 +22,14 @@ void render_skybox(void) { return; /* note: ownership of 'paths_in_use' goes there */ - finally_render_skybox(paths_in_use); + DeferredCommand command = { + .type = DEFERRED_COMMAND_TYPE_DRAW_SKYBOX, + .draw_skybox = (DeferredCommandDrawSkybox){ + .paths = paths_in_use + } + }; + + arrpush(deferred_commands, command); + paths_in_use = NULL; }