revolver

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit 05ba29dbd5abf2277521f1f00b80786a007e8e2a
parent f9d49901707dafcfc5ffe680b3b6631e6851d116
Author: Samdal <samdal@protonmail.com>
Date:   Tue, 25 Mar 2025 15:29:50 +0100

idraw2d updated

Diffstat:
Mbuild.sh | 2+-
Aexamples/bump_cache.c | 198+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mexamples/idraw2d.c | 2--
Dexamples/vertex_cache.c | 196-------------------------------------------------------------------------------
Msrc/render/render.h | 9++++++++-
Dsrc/render/render_idraw2d.c | 264-------------------------------------------------------------------------------
Dsrc/render/render_idraw2d.h | 91-------------------------------------------------------------------------------
Msrc/render/render_inc.c | 2--
Msrc/render/render_inc.h | 2--
Dsrc/render/render_vertex_cache.c | 76----------------------------------------------------------------------------
Dsrc/render/render_vertex_cache.h | 26--------------------------
Msrc/revolver_inc.c | 1+
Msrc/revolver_inc.h | 1+
Asrc/util/util_bump_cache.c | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/util/util_bump_cache.h | 25+++++++++++++++++++++++++
Asrc/util/util_idraw2d.c | 305++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/util/util_idraw2d.h | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/util/util_inc.c | 8++++++++
Asrc/util/util_inc.h | 8++++++++
19 files changed, 720 insertions(+), 661 deletions(-)

diff --git a/build.sh b/build.sh @@ -14,7 +14,7 @@ do "simple_texture") sources=(./examples/simple_texture.c) ;; "hello_window") sources=(./examples/hello_window.c) ;; "instancing") sources=(./examples/instancing.c) ;; - "vertex_cache") sources=(./examples/vertex_cache.c) ;; + "bump_cache") sources=(./examples/bump_cache.c) ;; "idraw2d") sources=(./examples/idraw2d.c) ;; esac done diff --git a/examples/bump_cache.c b/examples/bump_cache.c @@ -0,0 +1,198 @@ +////////////////////////////////////////////////////////////////// +// bump_cache.c + +#include "revolver_inc.h" +#include "revolver_inc.c" + +////////////////////////////////////////////////////////////////// +// data + +f32 v_data[] = { + 0.00, 0.05, 1, 0, 0, + -0.05, -0.05, 0, 1, 0, + 0.05, -0.05, 0, 0, 1, +}; + +rv_str8 v_src = S("#version 330 core\n" rv_strify( + layout(location = 0) in vec2 a_pos; + layout(location = 1) in vec3 a_color; + layout(location = 2) in vec2 a_offset; + precision mediump float; + out vec3 f_color; + void main() + { + gl_Position = vec4(a_pos + a_offset, 0.0, 1.0); + f_color = a_color; + } +)); + +rv_str8 f_src = S("#version 330 core\n" rv_strify( + precision mediump float; + in vec3 f_color; + out vec4 frag_color; + void main() + { + frag_color = vec4(f_color, 1.0); + } +)); + +////////////////////////////////////////////////////////////////// + +int main(void) { + rv_window_desc_t desc = {.name = S("App"), .attach_render = true}; + rv_window_handle_t* window = rv_create_window(desc); + + rv_arena* arena = rv_arena_alloc(); + rv_render_pass_list_t rpass_list = {0}; + + // make render objects + rv_vbo_t* vbo = rv_push_compound(arena, rv_vbo_t, {.data = v_data, .size = sizeof(v_data)}); + rv_vbo_t* vboi = rv_push_compound(arena, rv_vbo_t, {.usage = RV_BUFFER_USAGE_DYNAMIC}); + rv_shader_t* vertex = rv_push_compound(arena, rv_shader_t, {.source = v_src, .type = RV_SHADER_TYPE_VERTEX}); + rv_shader_t* fragment = rv_push_compound(arena, rv_shader_t, {.source = f_src, .type = RV_SHADER_TYPE_FRAGMENT}); + rv_pipeline_t* pip = rv_push(arena, rv_pipeline_t); + + // construct pipeline + rv_pipeline_push_shader(arena, pip, vertex); + rv_pipeline_push_shader(arena, pip, fragment); + rv_pipeline_push_vattr(arena, pip, RV_VATTR_TYPE_FLOAT2, 0, 0); + rv_pipeline_push_vattr(arena, pip, RV_VATTR_TYPE_FLOAT3, 0, 0); + rv_pipeline_push_vattr(arena, pip, RV_VATTR_TYPE_FLOAT2, 1, 1); + + // instructions to create render objects + rv_command_list_t create_instructions = {0}; + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_CREATE, vbo); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_CREATE, vboi); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, vertex); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, fragment); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_CREATE, pip); + + // copy over create commands + rv_render_pass_t* create_rpass = rv_render_push_render_pass(arena, &rpass_list); + rv_render_copy_commands(arena, &create_rpass->commands, &create_instructions); + + // create vertex cache + rv_bump_cache_ctx_t bc = {0}; + rv_bump_cache_create(&bc, sizeof(rv_vec2)); + + while(1) { + rv_temp_arena scratch = rv_scratch_begin(0, 0); + + // pick renderpass + rv_render_pass_t* rpass = rv_render_push_render_pass(scratch.arena, &rpass_list); + + // process events + for (rv_event_t* e = rv_get_events(scratch.arena, 0); e; e = e->next) { + if (e->type == RV_EVENT_WINDOW_CLOSE) { + if (e->window_close == window) { + goto exit_program; + } + } + if (e->type == RV_EVENT_WINDOW_RESIZE) { + // set viewport + rv_command_t* viewport = rv_cmd_push_type(scratch.arena, &rpass->commands, RV_COMMAND_SET_VIEWPORT); + viewport->viewport = rv_v4(.xy = {0, 0}, .zw = rv_window_size(window)); + } + } + + + { // clear + rv_command_t* clear = rv_cmd_push_type(scratch.arena, &rpass->commands, RV_COMMAND_CLEAR); + rv_render_clear_desc_t* clear_desc = rv_render_push_clear_desc(scratch.arena, clear, RV_RENDER_CLEAR_FLAG_COLOR); + clear_desc->color_v = rv_v4(0.1, 0.1, 0.1, 1.0); + } + + { // draw using vertex cache + // bind pipeline + rv_cmd_push_obj(arena, &rpass->commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, pip); + rv_cmd_push_obj(arena, &rpass->commands, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_BIND, vbo); + + { // draw custom shader first time + { // Translation data + int32_t index = 0; + float offset = 0.1f; + s32 peak_to_peak = 10.0; + for (int32_t y = -peak_to_peak; y < peak_to_peak; y += 2) { + if (sinf(rv_time()*5) * 9.0f < y) + break; + for (int32_t x = -peak_to_peak; x < peak_to_peak; x += 2) { + if (cosf(rv_time()*5) * 9.0f < x) + break; + rv_vec2 vertex = {0}; + vertex.x = (float)x / 10.0f + offset; + vertex.y = (float)y / 10.0f + offset; + rv_bump_cache_push(&bc, &vertex); + index++; + } + } + } + + // insert break, push draw command + s64 offset, instances; + rv_bump_cache_break(&bc, &offset, &instances); + + rv_command_t bind_command = rv_cmd_obj(RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_BIND, vboi); + bind_command.obj.vbo_bind.bind_index = 1; + bind_command.obj.vbo_bind.base_offset = offset * bc.element_size; + rv_command_t draw_command = rv_cmd(RV_COMMAND_DRAW, {.draw.count = 3, .draw.instances = instances}); + + if (instances) { + rv_cmd_push_copy(scratch.arena, &rpass->commands, bind_command); + rv_cmd_push_copy(scratch.arena, &rpass->commands, draw_command); + } + } + + { // draw custom shader second time + { // Translation data + rv_vec2 extra_offset = rv_v2(sinf(rv_time()*10) * 0.05, cosf(rv_time()*10) * 0.05); + int32_t index = 0; + float offset = 0.1f; + s32 peak_to_peak = 10; + for (int32_t y = -peak_to_peak; y < peak_to_peak; y += 2) { + for (int32_t x = -peak_to_peak; x < peak_to_peak; x += 2) { + rv_vec2 vertex = {0}; + vertex.x = (float)x / 10.0f + offset + extra_offset.x; + vertex.y = (float)y / 10.0f + offset + extra_offset.y; + rv_bump_cache_push(&bc, &vertex); + index++; + } + } + } + + // insert break, push draw command + s64 offset, instances; + rv_bump_cache_break(&bc, &offset, &instances); + + rv_command_t bind_command = rv_cmd_obj(RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_BIND, vboi); + bind_command.obj.vbo_bind.bind_index = 1; + bind_command.obj.vbo_bind.base_offset = offset * bc.element_size; + rv_command_t draw_command = rv_cmd(RV_COMMAND_DRAW, {.draw.count = 3, .draw.instances = instances}); + + if (instances) { + rv_cmd_push_copy(scratch.arena, &rpass->commands, bind_command); + rv_cmd_push_copy(scratch.arena, &rpass->commands, draw_command); + } + } + + // unbind pipeline + rv_cmd_push_obj(arena, &rpass->commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, NULL); + + { + // when done, upload all the data + // must be done before render commands of course + rv_command_t change_command = rv_cmd_obj(RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_UPDATE, vboi); + rv_bump_cache_upload_and_reset(&bc, scratch.arena, &change_command.obj.vbo_update.data, &change_command.obj.vbo_update.size); + rv_cmd_insert_copy(scratch.arena, &rpass->commands, rpass->commands.first, change_command); + } + } + + if (window) { // render screen + rv_window_render_commit(window, &rpass_list); + } + rv_scratch_end(scratch); + rpass_list = (rv_render_pass_list_t){0}; + } +exit_program: + + return 0; +} diff --git a/examples/idraw2d.c b/examples/idraw2d.c @@ -20,8 +20,6 @@ int main(void) { while(1) { rv_temp_arena scratch = rv_scratch_begin(0, 0); - rvi2d_break_and_insert_default_bindings(&rvi); - // pick renderpass rv_render_pass_t* rpass = rv_render_push_render_pass(scratch.arena, &rpass_list); diff --git a/examples/vertex_cache.c b/examples/vertex_cache.c @@ -1,196 +0,0 @@ -////////////////////////////////////////////////////////////////// -// vertex_cache.c - -#include "revolver_inc.h" -#include "revolver_inc.c" - -////////////////////////////////////////////////////////////////// -// data - -f32 v_data[] = { - 0.00, 0.05, 1, 0, 0, - -0.05, -0.05, 0, 1, 0, - 0.05, -0.05, 0, 0, 1, -}; - -rv_str8 v_src = S("#version 330 core\n" rv_strify( - layout(location = 0) in vec2 a_pos; - layout(location = 1) in vec3 a_color; - layout(location = 2) in vec2 a_offset; - precision mediump float; - out vec3 f_color; - void main() - { - gl_Position = vec4(a_pos + a_offset, 0.0, 1.0); - f_color = a_color; - } -)); - -rv_str8 f_src = S("#version 330 core\n" rv_strify( - precision mediump float; - in vec3 f_color; - out vec4 frag_color; - void main() - { - frag_color = vec4(f_color, 1.0); - } -)); - -////////////////////////////////////////////////////////////////// - -int main(void) { - rv_window_desc_t desc = {.name = S("App"), .attach_render = true}; - rv_window_handle_t* window = rv_create_window(desc); - - rv_arena* arena = rv_arena_alloc(); - rv_render_pass_list_t rpass_list = {0}; - - // make render objects - rv_vbo_t* vbo = rv_push_compound(arena, rv_vbo_t, {.data = v_data, .size = sizeof(v_data)}); - rv_vbo_t* vboi = rv_push_compound(arena, rv_vbo_t, {.usage = RV_BUFFER_USAGE_DYNAMIC}); - rv_shader_t* vertex = rv_push_compound(arena, rv_shader_t, {.source = v_src, .type = RV_SHADER_TYPE_VERTEX}); - rv_shader_t* fragment = rv_push_compound(arena, rv_shader_t, {.source = f_src, .type = RV_SHADER_TYPE_FRAGMENT}); - rv_pipeline_t* pip = rv_push(arena, rv_pipeline_t); - - // construct pipeline - rv_pipeline_push_shader(arena, pip, vertex); - rv_pipeline_push_shader(arena, pip, fragment); - rv_pipeline_push_vattr(arena, pip, RV_VATTR_TYPE_FLOAT2, 0, 0); - rv_pipeline_push_vattr(arena, pip, RV_VATTR_TYPE_FLOAT3, 0, 0); - rv_pipeline_push_vattr(arena, pip, RV_VATTR_TYPE_FLOAT2, 1, 1); - - // instructions to create render objects - rv_command_list_t create_instructions = {0}; - rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_CREATE, vbo); - rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_CREATE, vboi); - rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, vertex); - rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, fragment); - rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_CREATE, pip); - - // copy over create commands - rv_render_pass_t* create_rpass = rv_render_push_render_pass(arena, &rpass_list); - rv_render_copy_commands(arena, &create_rpass->commands, &create_instructions); - - // create vertex cache - rv_vertex_cache_ctx_t vc = {0}; - rv_vertex_cache_create(&vc, // vertex cache context - vboi, // vertex buffer to change and bind - sizeof(rv_vec2) // element size - ); - - while(1) { - rv_temp_arena scratch = rv_scratch_begin(0, 0); - - // pick renderpass - rv_render_pass_t* rpass = rv_render_push_render_pass(scratch.arena, &rpass_list); - - // process events - for (rv_event_t* e = rv_get_events(scratch.arena, 0); e; e = e->next) { - if (e->type == RV_EVENT_WINDOW_CLOSE) { - if (e->window_close == window) { - goto exit_program; - } - } - if (e->type == RV_EVENT_WINDOW_RESIZE) { - // set viewport - rv_command_t* viewport = rv_cmd_push_type(scratch.arena, &rpass->commands, RV_COMMAND_SET_VIEWPORT); - viewport->viewport = rv_v4(.xy = {0, 0}, .zw = rv_window_size(window)); - } - } - - - { // clear - rv_command_t* clear = rv_cmd_push_type(scratch.arena, &rpass->commands, RV_COMMAND_CLEAR); - rv_render_clear_desc_t* clear_desc = rv_render_push_clear_desc(scratch.arena, clear, RV_RENDER_CLEAR_FLAG_COLOR); - clear_desc->color_v = rv_v4(0.1, 0.1, 0.1, 1.0); - } - - { // draw using vertex cache - // bind pipeline - rv_cmd_push_obj(arena, &rpass->commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, pip); - rv_cmd_push_obj(arena, &rpass->commands, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_BIND, vbo); - - { // draw custom shader first time - { // Translation data - int32_t index = 0; - float offset = 0.1f; - s32 peak_to_peak = 9.0; - for (int32_t y = -peak_to_peak; y < peak_to_peak; y += 2) { - if (sinf(rv_time()*5) * 9.0f < y) - break; - for (int32_t x = -peak_to_peak; x < peak_to_peak; x += 2) { - if (cosf(rv_time()*5) * 9.0f < x) - break; - rv_vec2 vertex = {0}; - vertex.x = (float)x / 10.0f + offset; - vertex.y = (float)y / 10.0f + offset; - rv_vertex_cache_push(&vc, &vertex); - index++; - } - } - } - - // insert break, push draw command - rv_command_t bind_command; - rv_command_t draw_command = rv_cmd(RV_COMMAND_DRAW, {.draw.count = 3}); - - rv_vertex_cache_break(&vc, &bind_command, &draw_command.draw.instances); - bind_command.obj.vbo_bind.bind_index = 1; - - if (draw_command.draw.instances) { - rv_cmd_push_copy(scratch.arena, &rpass->commands, bind_command); - rv_cmd_push_copy(scratch.arena, &rpass->commands, draw_command); - } - } - - { // draw custom shader second time - { // Translation data - rv_vec2 extra_offset = rv_v2(sinf(rv_time()*10) * 0.05, cosf(rv_time()*10) * 0.05); - int32_t index = 0; - float offset = 0.1f; - s32 peak_to_peak = 10; - for (int32_t y = -peak_to_peak; y < peak_to_peak; y += 2) { - for (int32_t x = -peak_to_peak; x < peak_to_peak; x += 2) { - rv_vec2 vertex = {0}; - vertex.x = (float)x / 10.0f + offset + extra_offset.x; - vertex.y = (float)y / 10.0f + offset + extra_offset.y; - rv_vertex_cache_push(&vc, &vertex); - index++; - } - } - } - - // insert break, push draw command - rv_command_t bind_command; - rv_command_t draw_command = rv_cmd(RV_COMMAND_DRAW, {.draw.count = 3}); - - rv_vertex_cache_break(&vc, &bind_command, &draw_command.draw.instances); - bind_command.obj.vbo_bind.bind_index = 1; - - if (draw_command.draw.instances) { - rv_cmd_push_copy(scratch.arena, &rpass->commands, bind_command); - rv_cmd_push_copy(scratch.arena, &rpass->commands, draw_command); - } - } - - // unbind pipeline - rv_cmd_push_obj(arena, &rpass->commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, NULL); - - { - // when done, upload all the data - // must be done before render commands of course - rv_command_t change_command = rv_vetex_cache_upload_and_reset(&vc, scratch.arena); - rv_cmd_insert_copy(scratch.arena, &rpass->commands, rpass->commands.first, change_command); - } - } - - if (window) { // render screen - rv_window_render_commit(window, &rpass_list); - } - rv_scratch_end(scratch); - rpass_list = (rv_render_pass_list_t){0}; - } -exit_program: - - return 0; -} diff --git a/src/render/render.h b/src/render/render.h @@ -238,7 +238,6 @@ typedef struct { rv_command_t* last; } rv_command_list_t; - struct rv_command_t { rv_command_t* next; rv_command_t* prev; @@ -319,6 +318,14 @@ struct rv_render_pass_t { rv_framebuffer_t* framebuffer; // auto bind framebuffer }; +// non-framebuffer command list node +typedef struct rv_command_list_node_t rv_command_list_node_t; +struct rv_command_list_node_t { + rv_command_list_node_t* next; + rv_command_list_t commands; +}; + + typedef struct { rv_render_pass_t* first; rv_render_pass_t* last; diff --git a/src/render/render_idraw2d.c b/src/render/render_idraw2d.c @@ -1,264 +0,0 @@ -////////////////////////////////////////////////////////////////// -// render_idraw2d.c - -////////////////////////////////////////////////////////////////// -// data - -RV_INTERNAL rv_str8 rv_idraw2d_v_src = S("#version 330 core\n" rv_strify( - layout(location = 0) in vec2 a_pos; - layout(location = 1) in vec2 a_uv; - layout(location = 2) in vec4 a_color; - precision mediump float; - - uniform vec2 u_resolution; - - out vec4 f_color; - out vec2 f_uv; - - void main() - { - vec2 xy_pos = a_pos/u_resolution * 2.0; - xy_pos.y = -xy_pos.y; - xy_pos += vec2(-1.0, 1.0); - gl_Position = vec4(xy_pos, 0.0, 1.0); - f_color = a_color; - f_uv = a_uv; - } -)); - -RV_INTERNAL rv_str8 rv_idraw2d_f_src = S("#version 330 core\n" rv_strify( - precision mediump float; - in vec4 f_color; - in vec2 f_uv; - out vec4 frag_color; - uniform sampler2D u_tex; - uniform float u_omit_tex; - void main() - { - vec4 color = f_color; - if (u_omit_tex < 1.0) { - color *= texture(u_tex, f_uv); - } - frag_color = color; - } -)); - -// init - -RV_GLOBAL void rvi2d_create(rv_idraw2d_ctx* ctx, rv_arena* arena, rv_command_list_t* create_commands) -{ - rvi2d_destroy(ctx, arena, create_commands); - - ctx->arena = rv_arena_alloc(); - ctx->permanent_arena = rv_arena_alloc(.commit_size = KB(4), .reserve_size = KB(4)); - - // make render objects - ctx->vbo_vertex = rv_push_compound(ctx->permanent_arena, rv_vbo_t, {.usage = RV_BUFFER_USAGE_DYNAMIC}); - rv_shader_t* vert = rv_push_compound(ctx->permanent_arena, rv_shader_t, {.source = rv_idraw2d_v_src, .type = RV_SHADER_TYPE_VERTEX}); - rv_shader_t* frag = rv_push_compound(ctx->permanent_arena, rv_shader_t, {.source = rv_idraw2d_f_src, .type = RV_SHADER_TYPE_FRAGMENT}); - ctx->pip = rv_push(ctx->permanent_arena, rv_pipeline_t); - - // construct pipeline - rv_pipeline_push_shader(arena, ctx->pip, vert); - rv_pipeline_push_shader(arena, ctx->pip, frag); - rv_pipeline_push_vattr(arena, ctx->pip, RV_VATTR_TYPE_FLOAT2, 0, 0); - rv_pipeline_push_vattr(arena, ctx->pip, RV_VATTR_TYPE_FLOAT2, 0, 0); - rv_pipeline_push_vattr(arena, ctx->pip, RV_VATTR_TYPE_FLOAT4, 0, 0); - ctx->u_tex = rv_pipeline_push_uniform(ctx->permanent_arena, ctx->pip, S("u_tex"), RV_UNIFORM_TEX); - ctx->u_omit_tex = rv_pipeline_push_uniform(ctx->permanent_arena, ctx->pip, S("u_omit_tex"), RV_UNIFORM_F32); - ctx->u_resolution = rv_pipeline_push_uniform(ctx->permanent_arena, ctx->pip, S("u_resolution"), RV_UNIFORM_VEC2); - - // add creation commands - rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_CREATE, ctx->vbo_vertex); - rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, vert); - rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, frag); - rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_CREATE, ctx->pip); - rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_DESTROY, frag); // don't need anymore - rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_DESTROY, vert); // don't need anymore - rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, ctx->pip); - rv_cmd_push_uniform_update(arena, create_commands, ctx->u_omit_tex, {.v_f32 = 1.0f}); - rv_cmd_push_uniform_update(arena, create_commands, ctx->u_resolution, {.v_vec2 = rv_v2(1,1)}); - rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, NULL); - - rv_vertex_cache_create(&ctx->vertex, ctx->vbo_vertex, sizeof(rv_vec2) + sizeof(rv_vec2) + sizeof(rv_vec4)); -} - -RV_GLOBAL void rvi2d_destroy(rv_idraw2d_ctx* ctx, rv_arena* arena, rv_command_list_t* destroy_commands) -{ - // just use something to check if we're already destroyed - if (ctx->pip) { - // make copies, the memory will be invalid otherwise - rv_vbo_t* vbo_vertex_copy = rv_push_copy(arena, rv_vbo_t, ctx->vbo_vertex); - rv_ibo_t* ibo_copy = rv_push_copy(arena, rv_ibo_t, ctx->ibo); - rv_pipeline_t* pip_copy = rv_push_copy(arena, rv_pipeline_t, ctx->ibo); - - rv_cmd_push_obj(arena, destroy_commands, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_DESTROY, vbo_vertex_copy); - rv_cmd_push_obj(arena, destroy_commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_DESTROY, pip_copy); - - rv_arena_release(ctx->arena); - rv_arena_release(ctx->permanent_arena); - rv_vertex_cache_destroy(&ctx->vertex); - - *ctx = (rv_idraw2d_ctx){0}; - } -} - -////////////////////////////////////////////////////////////////// -// draw - -RV_GLOBAL rv_command_t* rvi2d_draw_and_reset(rv_idraw2d_ctx* ctx, rv_arena* arena, rv_command_list_t* render_commands) -{ - rv_command_t* res = rvi2d_break(ctx); - - rv_command_t update_vertex = rv_vetex_cache_upload_and_reset(&ctx->vertex, arena); - rv_cmd_push_copy(arena, render_commands, update_vertex); - - rv_render_copy_commands(arena, render_commands, &ctx->commands); - - ctx->commands = (rv_command_list_t){0}; - ctx->last_commited_command = NULL; - rv_arena_clear(ctx->arena); - - return res; -} - -////////////////////////////////////////////////////////////////// -// core update functions - - -RV_GLOBAL rv_command_t* rvi2d_break(rv_idraw2d_ctx* ctx) -{ - if (ctx->vertex.current_count == 0) { - // nothing has been pushed since last break - return NULL; - } - - s64 vertex_count; - rv_command_t vertex_bind; - rv_vertex_cache_break(&ctx->vertex, &vertex_bind, &vertex_count); - - rv_command_t draw_command = { - .type = RV_COMMAND_DRAW, - .draw = { - .count = vertex_count * ctx->vertex.vertex_element_size, - }}; - - rv_cmd_push_copy(ctx->arena, &ctx->commands, vertex_bind); - rv_cmd_push_copy(ctx->arena, &ctx->commands, draw_command); - - rv_command_t* first; - if (ctx->last_commited_command == NULL) { - first = ctx->commands.first; - } else { - first = ctx->last_commited_command->next; - } - ctx->last_commited_command = ctx->commands.last; - - return first; -} - -RV_GLOBAL rv_command_t* rvi2d_camera(rv_idraw2d_ctx* ctx, rv_vec2 screen_size) -{ - rv_command_t* res = rvi2d_break(ctx); - rv_cmd_push_uniform_update(ctx->arena, &ctx->commands, ctx->u_resolution, {.v_vec2 = screen_size}); - return res; -} - -RV_GLOBAL rv_command_t* rvi2d_tex(rv_idraw2d_ctx* ctx, rv_texture_t* tex) -{ - rv_command_t* res = NULL; - if (!ctx->has_tex && !tex) { - // nothing to change - } else { - res = rvi2d_break(ctx); - - rv_cmd_push_uniform_update(ctx->arena, &ctx->commands, ctx->u_tex, {.v_tex = tex}); - - if (!ctx->has_tex && tex) { - rv_cmd_push_uniform_update(ctx->arena, &ctx->commands, ctx->u_omit_tex, {.v_f32 = 0.0f}); - } else if (ctx->has_tex && !tex) { - rv_cmd_push_uniform_update(ctx->arena, &ctx->commands, ctx->u_omit_tex, {.v_f32 = 1.0f}); - } - - ctx->has_tex = tex != NULL; - } - - return res; -} - -RV_GLOBAL rv_command_t* rvi2d_break_and_begin_custom_bindings(rv_idraw2d_ctx* ctx, rv_command_list_t* copy_binds) -{ - rv_command_t* res = rvi2d_break(ctx); - rv_render_copy_commands(ctx->arena, &ctx->commands, copy_binds); - return res; - -} - -RV_GLOBAL rv_command_t* rvi2d_break_and_insert_default_bindings(rv_idraw2d_ctx* ctx) -{ - rv_command_t* res = rvi2d_break(ctx); - rv_cmd_push_obj(ctx->arena, &ctx->commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, ctx->pip); - return res; -} - -RV_GLOBAL void rvi2d_triangle(rv_idraw2d_ctx* ctx, - rv_vec2 pos_a, rv_vec2 pos_b, rv_vec2 pos_c, - rv_vec2 uv_a, rv_vec2 uv_b, rv_vec2 uv_c, - rv_color_t color) -{ - rv_vec4 c = rv_vec4_from_color(color); - struct { - rv_vec2 pos, uv; - rv_vec4 color; - } copy_from[3] = { - {.pos = pos_a, .uv = uv_a, .color = c}, - {.pos = pos_b, .uv = uv_b, .color = c}, - {.pos = pos_c, .uv = uv_c, .color = c}, - }; - rv_vertex_cache_push(&ctx->vertex, &copy_from[0]); - rv_vertex_cache_push(&ctx->vertex, &copy_from[1]); - rv_vertex_cache_push(&ctx->vertex, &copy_from[2]); -} - -RV_GLOBAL void rvi2d_quad(rv_idraw2d_ctx* ctx, - rv_vec2 pos_tl, rv_vec2 pos_tr, rv_vec2 pos_bl, rv_vec2 pos_br, - rv_vec2 uv_tl, rv_vec2 uv_tr, rv_vec2 uv_bl, rv_vec2 uv_br, - rv_color_t color) -{ - rvi2d_triangle(ctx, pos_tl, pos_tr, pos_bl, - uv_tl, uv_tr, uv_bl, color); - rvi2d_triangle(ctx, pos_tr, pos_bl, pos_br, - uv_tr, uv_bl, uv_br, color); -} - -////////////////////////////////////////////////////////////////// -// helpers functions - -#define rvi2d_triangle_no_uv(ctx, pos_a, pos_b, pos_c, color) \ - rvi2d_triangle(ctx, pos_a, pos_b, pos_c, rv_v2s(0,0), rv_v2s(0,0), rv_v2s(0,0), color) -#define rvi2d_quad_default_uv(ctx, pos_tl, pos_tr, pos_bl, pos_br, color)\ - rvi2d_quad(ctx, pos_tl, pos_tr, pos_bl, pos_br,\ - rv_v2s(1,0), rv_v2s(1,1), rv_v2s(0,0), rv_v2s(0,1),\ - color) -#define rvi2d_quad_yflipped_uv(ctx, pos_tl, pos_tr, pos_bl, pos_br, color)\ - rvi2d_quad(ctx, pos_tl, pos_tr, pos_bl, pos_br,\ - rv_v2s(0,0), rv_v2s(0,1), rv_v2s(1,0), rv_v2s(1,1),\ - color) - -RV_GLOBAL void rvi2d_rect(rv_idraw2d_ctx* ctx, rv_rect rect, rv_color_t color) -{ - rvi2d_quad(ctx, - rv_vec2_add(rect.xy, rv_v2(0, 0)), - rv_vec2_add(rect.xy, rv_v2(rect.w, 0)), - rv_vec2_add(rect.xy, rv_v2(0, rect.h)), - rv_vec2_add(rect.xy, rv_v2(rect.w, rect.h)), - rv_v2(0,0), rv_v2(1,0), rv_v2(0,1), rv_v2(1,1), color); -} -RV_GLOBAL void rvi2d_line(rv_idraw2d_ctx* ctx, rv_vec2 a, rv_vec2 b, f32 thickness, rv_color_t color) -{ - rv_unreachable(); // not implemented -} -RV_GLOBAL void rvi2d_circle(rv_idraw2d_ctx* ctx, rv_vec2 center, f32 radius, s32 segments) -{ - rv_unreachable(); // not implemented -} diff --git a/src/render/render_idraw2d.h b/src/render/render_idraw2d.h @@ -1,91 +0,0 @@ -////////////////////////////////////////////////////////////////// -// render_idraw2d.h -// -// TODO(Samdal): -// Make a stack for custom bindings, this would make it easy to auto-bind pipelines -// rvid_push_custom_binds() -// rvid_pop_custom_binds() -// Use an index buffer (?) -// Implement line drawing -// Implement circle drawing - -////////////////////////////////////////////////////////////////// -// types - -typedef struct { - rv_arena* permanent_arena; - rv_arena* arena; - - // gpu objects - rv_vbo_t* vbo_vertex; - rv_ibo_t* ibo; - rv_pipeline_t* pip; - rv_uniform_t* u_resolution; - rv_uniform_t* u_tex; - rv_uniform_t* u_omit_tex; - - // state - rv_vertex_cache_ctx_t vertex; - rv_command_list_t commands; - rv_command_t* last_commited_command; - bool32 has_tex; -} rv_idraw2d_ctx; - -////////////////////////////////////////////////////////////////// -// init - -RV_GLOBAL void rvi2d_create(rv_idraw2d_ctx* ctx, rv_arena* arena, rv_command_list_t* create_commands); -RV_GLOBAL void rvi2d_destroy(rv_idraw2d_ctx* ctx, rv_arena* arena, rv_command_list_t* destroy_commands); - -////////////////////////////////////////////////////////////////// -// draw - -RV_GLOBAL rv_command_t* rvi2d_draw_and_reset(rv_idraw2d_ctx* ctx, rv_arena* arena, rv_command_list_t* render_commands); - -////////////////////////////////////////////////////////////////// -// core update functions -// -// NOTE(Samdal): -// rvi2d_camera, rvi2d_tex and rvi2d_custom_bind(_clear) invalidates instancing -// -// NOTE(Samdal): -// fixed vertex layout ( you can add more binds if you want ): -// layout(location = 0) in vec2 a_pos; (bind index 0) -// layout(location = 1) in vec2 a_uv; (bind index 0) -// layout(location = 2) in vec4 a_color; (bind index 1) -// -// NOTE(Samdal): -// These functions return the first command if there was a break in the instancing. -// Otherwise they return NULL. - -RV_GLOBAL rv_command_t* rvi2d_break(rv_idraw2d_ctx* ctx); -RV_GLOBAL rv_command_t* rvi2d_camera(rv_idraw2d_ctx* ctx, rv_vec2 screen_size); -RV_GLOBAL rv_command_t* rvi2d_tex(rv_idraw2d_ctx* ctx, rv_texture_t* tex); -RV_GLOBAL rv_command_t* rvi2d_break_and_begin_custom_bindings(rv_idraw2d_ctx* ctx, rv_command_list_t* copy_binds); -RV_GLOBAL rv_command_t* rvi2d_break_and_begin_default_bindings(rv_idraw2d_ctx* ctx); -RV_GLOBAL void rvi2d_triangle(rv_idraw2d_ctx* ctx, - rv_vec2 pos_a, rv_vec2 pos_b, rv_vec2 pos_c, - rv_vec2 uv_a, rv_vec2 uv_b, rv_vec2 uv_c, - rv_color_t color); -RV_GLOBAL void rvi2d_quad(rv_idraw2d_ctx* ctx, - rv_vec2 pos_tl, rv_vec2 pos_tr, rv_vec2 pos_bl, rv_vec2 pos_br, - rv_vec2 uv_tl, rv_vec2 uv_tr, rv_vec2 uv_bl, rv_vec2 uv_br, - rv_color_t color); - -////////////////////////////////////////////////////////////////// -// helpers functions - -#define rvi2d_triangle_no_uv(ctx, pos_a, pos_b, pos_c, color) \ - rvi2d_triangle(ctx, pos_a, pos_b, pos_c, rv_v2s(0,0), rv_v2s(0,0), rv_v2s(0,0), color) -#define rvi2d_quad_default_uv(ctx, pos_tl, pos_tr, pos_bl, pos_br, color)\ - rvi2d_quad(ctx, pos_tl, pos_tr, pos_bl, pos_br,\ - rv_v2s(1,0), rv_v2s(1,1), rv_v2s(0,0), rv_v2s(0,1),\ - color) -#define rvi2d_quad_yflipped_uv(ctx, pos_tl, pos_tr, pos_bl, pos_br, color)\ - rvi2d_quad(ctx, pos_tl, pos_tr, pos_bl, pos_br,\ - rv_v2s(0,0), rv_v2s(0,1), rv_v2s(1,0), rv_v2s(1,1),\ - color) - -RV_GLOBAL void rvi2d_rect(rv_idraw2d_ctx* ctx, rv_rect rect, rv_color_t color); -RV_GLOBAL void rvi2d_line(rv_idraw2d_ctx* ctx, rv_vec2 a, rv_vec2 b, f32 thickness, rv_color_t color); -RV_GLOBAL void rvi2d_circle(rv_idraw2d_ctx* ctx, rv_vec2 center, f32 radius, s32 segments); diff --git a/src/render/render_inc.c b/src/render/render_inc.c @@ -3,8 +3,6 @@ #if RV_WIN_ENABLED #include "render_helpers.c" - #include "render_vertex_cache.c" - #include "render_idraw2d.c" #if RV_RENDER_OPENGL #include "impl/opengl.c" diff --git a/src/render/render_inc.h b/src/render/render_inc.h @@ -3,6 +3,4 @@ #if RV_WIN_ENABLED #include "render.h" - #include "render_vertex_cache.h" - #include "render_idraw2d.h" #endif // RV_WIN_ENABLED diff --git a/src/render/render_vertex_cache.c b/src/render/render_vertex_cache.c @@ -1,76 +0,0 @@ -////////////////////////////////////////////////////////////////// -// render_vertex_cache.c - -RV_GLOBAL void rv_vertex_cache_create(rv_vertex_cache_ctx_t* vc, rv_vbo_t* vbo, s64 vertex_element_size) -{ - rv_vertex_cache_destroy(vc); - vc->vertex_element_size = vertex_element_size; - vc->vbo = vbo; - - // TODO(Samdal): - // Check if the arena implementation supports virtual paging first... - vc->vertex_arena = rv_arena_alloc(.flags = rv_arena_flag_no_chain, .reserve_size = GB(1)); -} - -RV_GLOBAL void rv_vertex_cache_destroy(rv_vertex_cache_ctx_t* vc) -{ - if (vc->vertex_arena) { - rv_arena_release(vc->vertex_arena); - } - *vc = (rv_vertex_cache_ctx_t){0}; -} - -RV_GLOBAL void* rv_vertex_cache_push(rv_vertex_cache_ctx_t* vc, const void* new) -{ - rv_assert(vc->vertex_element_size > 0); - - void* res = rv_arena_push(vc->vertex_arena, vc->vertex_element_size, 1); - rv_mem_copy(res, new, vc->vertex_element_size); - - if (!vc->vertex_begin) { - vc->vertex_begin = res; - rv_assert(vc->vertex_total_size == 0); - rv_assert(vc->committed_vertecies_so_far == 0); - } - - vc->current_count += 1; - vc->vertex_total_size += vc->vertex_element_size; - - return res; -} - -RV_GLOBAL void rv_vertex_cache_break(rv_vertex_cache_ctx_t* vc, rv_command_t* bind_out, s64* count_out) { - - *bind_out = rv_cmd_obj(RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_BIND, vc->vbo); - bind_out->obj.vbo_bind.base_offset = vc->committed_vertecies_so_far; - - *count_out = vc->current_count; - - rv_command_t res = {0}; - - vc->committed_vertecies_so_far += vc->current_count * vc->vertex_element_size; - - vc->current_count = 0; -} - -RV_GLOBAL rv_command_t rv_vetex_cache_upload_and_reset(rv_vertex_cache_ctx_t* vc, rv_arena* arena) -{ - // make and push command - rv_command_t update_cmd = rv_cmd_obj(RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_UPDATE, vc->vbo); - - // copy over data into new arena - - void* data = rv_arena_push(arena, vc->vertex_total_size, 8); - rv_mem_copy(data, vc->vertex_begin, vc->vertex_total_size); - update_cmd.obj.vbo_update.data = data; - update_cmd.obj.vbo_update.size = vc->vertex_total_size; - - // reset - rv_arena_clear(vc->vertex_arena); - vc->vertex_begin = NULL; - vc->current_count = 0; - vc->committed_vertecies_so_far = 0; - vc->vertex_total_size = 0; - - return update_cmd; -} diff --git a/src/render/render_vertex_cache.h b/src/render/render_vertex_cache.h @@ -1,26 +0,0 @@ -////////////////////////////////////////////////////////////////// -// render_vertex_cache.h - -typedef struct { - // initialization - s64 vertex_element_size; - rv_arena* vertex_arena; - rv_vbo_t* vbo; - - // construction - s64 current_count; - s64 committed_vertecies_so_far; - - // upload - void* vertex_begin; - s64 vertex_total_size; -} rv_vertex_cache_ctx_t; - -RV_GLOBAL void rv_vertex_cache_create(rv_vertex_cache_ctx_t* vc, rv_vbo_t* vbo, s64 vertex_element_size); -RV_GLOBAL void rv_vertex_cache_destroy(rv_vertex_cache_ctx_t* vc); - -RV_GLOBAL void* rv_vertex_cache_push(rv_vertex_cache_ctx_t* vc, const void* new); -RV_GLOBAL void rv_vertex_cache_break(rv_vertex_cache_ctx_t* vc, rv_command_t* bind_out, s64* count_out); -// returns draw command with filled data - -RV_GLOBAL rv_command_t rv_vetex_cache_upload_and_reset(rv_vertex_cache_ctx_t* vc, rv_arena* arena); diff --git a/src/revolver_inc.c b/src/revolver_inc.c @@ -1,2 +1,3 @@ #include "platform/platform_inc.c" #include "render/render_inc.c" +#include "util/util_inc.c" diff --git a/src/revolver_inc.h b/src/revolver_inc.h @@ -1,2 +1,3 @@ #include "platform/platform_inc.h" #include "render/render_inc.h" +#include "util/util_inc.h" diff --git a/src/util/util_bump_cache.c b/src/util/util_bump_cache.c @@ -0,0 +1,65 @@ +////////////////////////////////////////////////////////////////// +// render_vertex_cache.c + +RV_GLOBAL void rv_bump_cache_create(rv_bump_cache_ctx_t* bc, s64 element_size) +{ + rv_bump_cache_destroy(bc); + bc->element_size = element_size; + + // TODO(Samdal): + // Check if the arena implementation supports virtual paging first... + bc->bump_arena = rv_arena_alloc(.flags = rv_arena_flag_no_chain, .reserve_size = GB(1)); +} + +RV_GLOBAL void rv_bump_cache_destroy(rv_bump_cache_ctx_t* bc) +{ + if (bc->bump_arena) { + rv_arena_release(bc->bump_arena); + } + *bc = (rv_bump_cache_ctx_t){0}; +} + +RV_GLOBAL void* rv_bump_cache_push(rv_bump_cache_ctx_t* bc, const void* new) +{ + rv_assert(bc->element_size > 0); + + void* res = rv_arena_push(bc->bump_arena, bc->element_size, 1); + rv_mem_copy(res, new, bc->element_size); + + if (!bc->bump_begin) { + bc->bump_begin = res; + rv_assert(bc->bump_total_size == 0); + rv_assert(bc->committed_so_far == 0); + } + + bc->current_count += 1; + bc->bump_total_size += bc->element_size; + + return res; +} + +RV_GLOBAL void rv_bump_cache_break(rv_bump_cache_ctx_t* bc, s64* offset_out, s64* count_out) { + *offset_out = bc->committed_so_far; + *count_out = bc->current_count; + + rv_command_t res = {0}; + + bc->committed_so_far += bc->current_count; + + bc->current_count = 0; +} + +RV_GLOBAL void rv_bump_cache_upload_and_reset(rv_bump_cache_ctx_t* bc, rv_arena* arena, void** data_out, s64* size_out) +{ + // copy over data into new arena + *data_out = rv_arena_push(arena, bc->bump_total_size, 8); + rv_mem_copy(*data_out, bc->bump_begin, bc->bump_total_size); + *size_out = bc->bump_total_size; + + // reset + rv_arena_clear(bc->bump_arena); + bc->bump_begin = NULL; + bc->current_count = 0; + bc->committed_so_far = 0; + bc->bump_total_size = 0; +} diff --git a/src/util/util_bump_cache.h b/src/util/util_bump_cache.h @@ -0,0 +1,25 @@ +////////////////////////////////////////////////////////////////// +// util_bump_cache.h + +typedef struct { + // initialization + s64 element_size; + rv_arena* bump_arena; + + // construction + s64 current_count; + s64 committed_so_far; + + // upload + void* bump_begin; + s64 bump_total_size; +} rv_bump_cache_ctx_t; + +RV_GLOBAL void rv_bump_cache_create(rv_bump_cache_ctx_t* bc, s64 element_size); +RV_GLOBAL void rv_bump_cache_destroy(rv_bump_cache_ctx_t* bc); + +RV_GLOBAL void* rv_bump_cache_push(rv_bump_cache_ctx_t* bc, const void* new); +RV_GLOBAL void rv_bump_cache_break(rv_bump_cache_ctx_t* bc, s64* offset_out, s64* count_out); +// returns draw command with filled data + +RV_GLOBAL void rv_bump_cache_upload_and_reset(rv_bump_cache_ctx_t* bc, rv_arena* arena, void** data_out, s64* size_out); diff --git a/src/util/util_idraw2d.c b/src/util/util_idraw2d.c @@ -0,0 +1,305 @@ +////////////////////////////////////////////////////////////////// +// util_idraw2d.c + +////////////////////////////////////////////////////////////////// +// data + +RV_INTERNAL rv_str8 rv_idraw2d_v_src = S("#version 330 core\n" rv_strify( + layout(location = 0) in vec2 a_pos; + layout(location = 1) in vec2 a_uv; + layout(location = 2) in vec4 a_color; + precision mediump float; + + uniform vec2 u_resolution; + + out vec4 f_color; + out vec2 f_uv; + + void main() + { + vec2 xy_pos = a_pos/u_resolution * 2.0; + xy_pos.y = -xy_pos.y; + xy_pos += vec2(-1.0, 1.0); + gl_Position = vec4(xy_pos, 0.0, 1.0); + f_color = a_color; + f_uv = a_uv; + } +)); + +RV_INTERNAL rv_str8 rv_idraw2d_f_src = S("#version 330 core\n" rv_strify( + precision mediump float; + in vec4 f_color; + in vec2 f_uv; + out vec4 frag_color; + uniform sampler2D u_tex; + uniform float u_omit_tex; + void main() + { + vec4 color = f_color; + if (u_omit_tex < 1.0) { + color *= texture(u_tex, f_uv); + } + frag_color = color; + } +)); + +////////////////////////////////////////////////////////////////// +// init + +RV_GLOBAL void rvi2d_create(rv_idraw2d_ctx* ctx, rv_arena* arena, rv_command_list_t* create_commands) +{ + rvi2d_destroy(ctx, arena, create_commands); + + ctx->arena = rv_arena_alloc(); + ctx->permanent_arena = rv_arena_alloc(.commit_size = KB(4), .reserve_size = KB(4)); + + // make render objects + ctx->vbo = rv_push_compound(ctx->permanent_arena, rv_vbo_t, {.usage = RV_BUFFER_USAGE_DYNAMIC}); + rv_shader_t* vert = rv_push_compound(ctx->permanent_arena, rv_shader_t, {.source = rv_idraw2d_v_src, .type = RV_SHADER_TYPE_VERTEX}); + rv_shader_t* frag = rv_push_compound(ctx->permanent_arena, rv_shader_t, {.source = rv_idraw2d_f_src, .type = RV_SHADER_TYPE_FRAGMENT}); + ctx->pip = rv_push(ctx->permanent_arena, rv_pipeline_t); + + // construct pipeline + rv_pipeline_push_shader(arena, ctx->pip, vert); + rv_pipeline_push_shader(arena, ctx->pip, frag); + rv_pipeline_push_vattr(arena, ctx->pip, RV_VATTR_TYPE_FLOAT2, 0, 0); + rv_pipeline_push_vattr(arena, ctx->pip, RV_VATTR_TYPE_FLOAT2, 0, 0); + rv_pipeline_push_vattr(arena, ctx->pip, RV_VATTR_TYPE_FLOAT4, 0, 0); + ctx->u_tex = rv_pipeline_push_uniform(ctx->permanent_arena, ctx->pip, S("u_tex"), RV_UNIFORM_TEX); + ctx->u_omit_tex = rv_pipeline_push_uniform(ctx->permanent_arena, ctx->pip, S("u_omit_tex"), RV_UNIFORM_F32); + ctx->u_resolution = rv_pipeline_push_uniform(ctx->permanent_arena, ctx->pip, S("u_resolution"), RV_UNIFORM_VEC2); + + // add creation commands + rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_CREATE, ctx->vbo); + rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, vert); + rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, frag); + rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_CREATE, ctx->pip); + rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_DESTROY, frag); // don't need anymore + rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_DESTROY, vert); // don't need anymore + rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, ctx->pip); + rv_cmd_push_uniform_update(arena, create_commands, ctx->u_omit_tex, {.v_f32 = 1.0f}); + rv_cmd_push_uniform_update(arena, create_commands, ctx->u_resolution, {.v_vec2 = rv_v2(1,1)}); + rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, NULL); + + rv_bump_cache_create(&ctx->vertex, sizeof(rv_vec2) + sizeof(rv_vec2) + sizeof(rv_vec4)); + + ctx->default_binds = rv_push(ctx->permanent_arena, rv_command_list_node_t); + rv_cmd_push_obj(ctx->permanent_arena, &ctx->default_binds->commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, ctx->pip); + + rv_llist_stack_push(ctx->custom_binds_stack, ctx->default_binds); +} + +RV_GLOBAL void rvi2d_destroy(rv_idraw2d_ctx* ctx, rv_arena* arena, rv_command_list_t* destroy_commands) +{ + // just use something to check if we're already destroyed + if (ctx->pip) { + // make copies, the memory will be invalid otherwise + rv_vbo_t* vbo_vertex_copy = rv_push_copy(arena, rv_vbo_t, ctx->vbo); + rv_ibo_t* ibo_copy = rv_push_copy(arena, rv_ibo_t, ctx->ibo); + rv_pipeline_t* pip_copy = rv_push_copy(arena, rv_pipeline_t, ctx->ibo); + + rv_cmd_push_obj(arena, destroy_commands, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_DESTROY, vbo_vertex_copy); + rv_cmd_push_obj(arena, destroy_commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_DESTROY, pip_copy); + + rv_arena_release(ctx->arena); + rv_arena_release(ctx->permanent_arena); + rv_bump_cache_destroy(&ctx->vertex); + + *ctx = (rv_idraw2d_ctx){0}; + } +} + +////////////////////////////////////////////////////////////////// +// draw + +RV_GLOBAL rv_command_t* rvi2d_draw_and_reset(rv_idraw2d_ctx* ctx, rv_arena* arena, rv_command_list_t* render_commands) +{ + rv_command_t* res = rvi2d_break(ctx); + + rv_command_t update_cmd = rv_cmd_obj(RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_UPDATE, ctx->vbo); + + rv_bump_cache_upload_and_reset(&ctx->vertex, arena, &update_cmd.obj.vbo_update.data, &update_cmd.obj.vbo_update.size); + rv_cmd_push_copy(arena, render_commands, update_cmd); + + rv_render_copy_commands(arena, render_commands, &ctx->commands); + + if (ctx->custom_binds_stack->next) { + rv_unreachable(); + ctx->custom_binds_stack = NULL; + rv_llist_stack_push(ctx->custom_binds_stack, ctx->default_binds); + } + + ctx->commands = (rv_command_list_t){0}; + ctx->last_commited_command = NULL; + ctx->last_bind = NULL; + rv_arena_clear(ctx->arena); + + return res; +} + +////////////////////////////////////////////////////////////////// +// core update functions + + +RV_GLOBAL rv_command_t* rvi2d_break(rv_idraw2d_ctx* ctx) +{ + if (ctx->last_bind != ctx->custom_binds_stack) { + rv_render_copy_commands(ctx->arena, &ctx->commands, &ctx->custom_binds_stack->commands); + + // force rebind vbo + rv_cmd_push_obj(ctx->arena, &ctx->commands, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_BIND, ctx->vbo); + // force update all uniforms + rv_cmd_push_uniform_update(ctx->arena, &ctx->commands, ctx->u_resolution, {.v_vec2 = ctx->u_resolution_last}); + rv_cmd_push_uniform_update(ctx->arena, &ctx->commands, ctx->u_tex, {.v_tex = ctx->u_tex_last}); + rv_cmd_push_uniform_update(ctx->arena, &ctx->commands, ctx->u_omit_tex, {.v_f32 = ctx->u_omit_tex_last}); + + ctx->last_bind = ctx->custom_binds_stack; + } + + s64 first, count; + rv_bump_cache_break(&ctx->vertex, &first, &count); + + if (count > 0 ) { + rv_command_t draw_cmd = { + .type = RV_COMMAND_DRAW, + .draw = { + .first = first, + .count = count, + }}; + rv_cmd_push_copy(ctx->arena, &ctx->commands, draw_cmd); + } + + rv_command_t* first_cmd; + if (ctx->last_commited_command == NULL) { + first_cmd = ctx->commands.first; + } else { + first_cmd = ctx->last_commited_command->next; + } + ctx->last_commited_command = ctx->commands.last; + + return first_cmd; +} + +RV_GLOBAL rv_command_t* rvi2d_camera(rv_idraw2d_ctx* ctx, rv_vec2 screen_size) +{ + rv_command_t* res = rvi2d_break(ctx); + rv_cmd_push_uniform_update(ctx->arena, &ctx->commands, ctx->u_resolution, {.v_vec2 = screen_size}); + ctx->u_resolution_last = screen_size; + + return res; +} + +RV_GLOBAL rv_command_t* rvi2d_tex(rv_idraw2d_ctx* ctx, rv_texture_t* tex) +{ + rv_command_t* res = NULL; + if (!ctx->has_tex && !tex) { + // nothing to change + } else { + res = rvi2d_break(ctx); + + rv_cmd_push_uniform_update(ctx->arena, &ctx->commands, ctx->u_tex, {.v_tex = tex}); + ctx->u_tex_last = tex; + + if (!ctx->has_tex && tex) { + rv_cmd_push_uniform_update(ctx->arena, &ctx->commands, ctx->u_omit_tex, {.v_f32 = 0.0f}); + ctx->u_omit_tex_last = 0.0f; + } else if (ctx->has_tex && !tex) { + rv_cmd_push_uniform_update(ctx->arena, &ctx->commands, ctx->u_omit_tex, {.v_f32 = 1.0f}); + ctx->u_omit_tex_last = 1.0f; + } + + ctx->has_tex = tex != NULL; + } + + return res; +} + +RV_GLOBAL rv_command_t* rvi2d_custom_binds_push(rv_idraw2d_ctx* ctx, rv_command_list_t* copy_binds) +{ + rv_command_t* res = rvi2d_break(ctx); + + rv_command_list_node_t* n = rv_push(ctx->arena, rv_command_list_node_t); + rv_render_copy_commands(ctx->arena, &ctx->commands, copy_binds); + rv_llist_stack_push(ctx->custom_binds_stack, n); + + return res; + +} + +RV_GLOBAL rv_command_t* rvi2d_custom_binds_pop(rv_idraw2d_ctx* ctx) +{ + rv_command_t* res = rvi2d_break(ctx); + + rv_command_list_node_t* tmp = ctx->custom_binds_stack; + rv_llist_stack_pop(ctx->custom_binds_stack); + tmp->next = NULL; + + if (!ctx->custom_binds_stack) { + rv_unreachable(); + rv_llist_stack_push(ctx->custom_binds_stack, ctx->default_binds); + } + + return res; +} + +RV_GLOBAL void rvi2d_triangle(rv_idraw2d_ctx* ctx, + rv_vec2 pos_a, rv_vec2 pos_b, rv_vec2 pos_c, + rv_vec2 uv_a, rv_vec2 uv_b, rv_vec2 uv_c, + rv_color_t color) +{ + rv_vec4 c = rv_vec4_from_color(color); + struct { + rv_vec2 pos, uv; + rv_vec4 color; + } copy_from[3] = { + {.pos = pos_a, .uv = uv_a, .color = c}, + {.pos = pos_b, .uv = uv_b, .color = c}, + {.pos = pos_c, .uv = uv_c, .color = c}, + }; + rv_bump_cache_push(&ctx->vertex, &copy_from[0]); + rv_bump_cache_push(&ctx->vertex, &copy_from[1]); + rv_bump_cache_push(&ctx->vertex, &copy_from[2]); +} + +RV_GLOBAL void rvi2d_quad(rv_idraw2d_ctx* ctx, + rv_vec2 pos_tl, rv_vec2 pos_tr, rv_vec2 pos_bl, rv_vec2 pos_br, + rv_vec2 uv_tl, rv_vec2 uv_tr, rv_vec2 uv_bl, rv_vec2 uv_br, + rv_color_t color) +{ + rvi2d_triangle(ctx, pos_tl, pos_tr, pos_bl, + uv_tl, uv_tr, uv_bl, color); + rvi2d_triangle(ctx, pos_tr, pos_bl, pos_br, + uv_tr, uv_bl, uv_br, color); +} + +////////////////////////////////////////////////////////////////// +// helpers functions + +#define rvi2d_triangle_no_uv(ctx, pos_a, pos_b, pos_c, color) \ + rvi2d_triangle(ctx, pos_a, pos_b, pos_c, rv_v2s(0,0), rv_v2s(0,0), rv_v2s(0,0), color) +#define rvi2d_quad_default_uv(ctx, pos_tl, pos_tr, pos_bl, pos_br, color)\ + rvi2d_quad(ctx, pos_tl, pos_tr, pos_bl, pos_br,\ + rv_v2s(1,0), rv_v2s(1,1), rv_v2s(0,0), rv_v2s(0,1),\ + color) +#define rvi2d_quad_yflipped_uv(ctx, pos_tl, pos_tr, pos_bl, pos_br, color)\ + rvi2d_quad(ctx, pos_tl, pos_tr, pos_bl, pos_br,\ + rv_v2s(0,0), rv_v2s(0,1), rv_v2s(1,0), rv_v2s(1,1),\ + color) + +RV_GLOBAL void rvi2d_rect(rv_idraw2d_ctx* ctx, rv_rect rect, rv_color_t color) +{ + rvi2d_quad(ctx, + rv_vec2_add(rect.xy, rv_v2(0, 0)), + rv_vec2_add(rect.xy, rv_v2(rect.w, 0)), + rv_vec2_add(rect.xy, rv_v2(0, rect.h)), + rv_vec2_add(rect.xy, rv_v2(rect.w, rect.h)), + rv_v2(0,0), rv_v2(1,0), rv_v2(0,1), rv_v2(1,1), color); +} +RV_GLOBAL void rvi2d_line(rv_idraw2d_ctx* ctx, rv_vec2 a, rv_vec2 b, f32 thickness, rv_color_t color) +{ + rv_unreachable(); // not implemented +} +RV_GLOBAL void rvi2d_circle(rv_idraw2d_ctx* ctx, rv_vec2 center, f32 radius, s32 segments) +{ + rv_unreachable(); // not implemented +} diff --git a/src/util/util_idraw2d.h b/src/util/util_idraw2d.h @@ -0,0 +1,100 @@ +////////////////////////////////////////////////////////////////// +// util_idraw2d.h +// +// TODO(Samdal): +// Make a stack for custom bindings, this would make it easy to auto-bind pipelines +// rvid_push_custom_binds() +// rvid_pop_custom_binds() +// Use an index buffer (?) +// Implement line drawing +// Implement circle drawing + +////////////////////////////////////////////////////////////////// +// types + +typedef struct { + rv_arena* permanent_arena; + rv_arena* arena; + + // gpu objects + rv_vbo_t* vbo; + rv_ibo_t* ibo; + rv_pipeline_t* pip; + + rv_command_list_node_t* default_binds; + + rv_uniform_t* u_resolution; + rv_uniform_t* u_tex; + rv_uniform_t* u_omit_tex; + rv_vec2 u_resolution_last; + rv_texture_t* u_tex_last; + f32 u_omit_tex_last; + + // state + rv_bump_cache_ctx_t vertex; + rv_command_list_t commands; + rv_command_t* last_commited_command; + bool32 has_tex; + + rv_command_list_node_t* custom_binds_stack; + rv_command_list_node_t* last_bind; +} rv_idraw2d_ctx; + +////////////////////////////////////////////////////////////////// +// init + +RV_GLOBAL void rvi2d_create(rv_idraw2d_ctx* ctx, rv_arena* arena, rv_command_list_t* create_commands); +RV_GLOBAL void rvi2d_destroy(rv_idraw2d_ctx* ctx, rv_arena* arena, rv_command_list_t* destroy_commands); + +////////////////////////////////////////////////////////////////// +// draw + +RV_GLOBAL rv_command_t* rvi2d_draw_and_reset(rv_idraw2d_ctx* ctx, rv_arena* arena, rv_command_list_t* render_commands); + +////////////////////////////////////////////////////////////////// +// core update functions +// +// NOTE(Samdal): +// rvi2d_camera, rvi2d_tex and rvi2d_custom_bind(_clear) invalidates instancing +// +// NOTE(Samdal): +// fixed vertex layout ( you can add more binds if you want ): +// layout(location = 0) in vec2 a_pos; (bind index 0) +// layout(location = 1) in vec2 a_uv; (bind index 0) +// layout(location = 2) in vec4 a_color; (bind index 1) +// +// NOTE(Samdal): +// These functions return the first command if there was a break in the instancing. +// Otherwise they return NULL. + +RV_GLOBAL rv_command_t* rvi2d_break(rv_idraw2d_ctx* ctx); +RV_GLOBAL rv_command_t* rvi2d_camera(rv_idraw2d_ctx* ctx, rv_vec2 screen_size); +RV_GLOBAL rv_command_t* rvi2d_tex(rv_idraw2d_ctx* ctx, rv_texture_t* tex); +RV_GLOBAL rv_command_t* rvi2d_custom_binds_push(rv_idraw2d_ctx* ctx, rv_command_list_t* copy_binds); +RV_GLOBAL rv_command_t* rvi2d_custom_binds_pop(rv_idraw2d_ctx* ctx); +RV_GLOBAL void rvi2d_triangle(rv_idraw2d_ctx* ctx, + rv_vec2 pos_a, rv_vec2 pos_b, rv_vec2 pos_c, + rv_vec2 uv_a, rv_vec2 uv_b, rv_vec2 uv_c, + rv_color_t color); +RV_GLOBAL void rvi2d_quad(rv_idraw2d_ctx* ctx, + rv_vec2 pos_tl, rv_vec2 pos_tr, rv_vec2 pos_bl, rv_vec2 pos_br, + rv_vec2 uv_tl, rv_vec2 uv_tr, rv_vec2 uv_bl, rv_vec2 uv_br, + rv_color_t color); + +////////////////////////////////////////////////////////////////// +// helpers functions + +#define rvi2d_triangle_no_uv(ctx, pos_a, pos_b, pos_c, color) \ + rvi2d_triangle(ctx, pos_a, pos_b, pos_c, rv_v2s(0,0), rv_v2s(0,0), rv_v2s(0,0), color) +#define rvi2d_quad_default_uv(ctx, pos_tl, pos_tr, pos_bl, pos_br, color)\ + rvi2d_quad(ctx, pos_tl, pos_tr, pos_bl, pos_br,\ + rv_v2s(1,0), rv_v2s(1,1), rv_v2s(0,0), rv_v2s(0,1),\ + color) +#define rvi2d_quad_yflipped_uv(ctx, pos_tl, pos_tr, pos_bl, pos_br, color)\ + rvi2d_quad(ctx, pos_tl, pos_tr, pos_bl, pos_br,\ + rv_v2s(0,0), rv_v2s(0,1), rv_v2s(1,0), rv_v2s(1,1),\ + color) + +RV_GLOBAL void rvi2d_rect(rv_idraw2d_ctx* ctx, rv_rect rect, rv_color_t color); +RV_GLOBAL void rvi2d_line(rv_idraw2d_ctx* ctx, rv_vec2 a, rv_vec2 b, f32 thickness, rv_color_t color); +RV_GLOBAL void rvi2d_circle(rv_idraw2d_ctx* ctx, rv_vec2 center, f32 radius, s32 segments); diff --git a/src/util/util_inc.c b/src/util/util_inc.c @@ -0,0 +1,8 @@ +////////////////////////////////////////////////////////////////// +// util_inc.c + +#include "util_bump_cache.c" + +#if RV_WIN_ENABLED + #include "util_idraw2d.c" +#endif diff --git a/src/util/util_inc.h b/src/util/util_inc.h @@ -0,0 +1,8 @@ +////////////////////////////////////////////////////////////////// +// util_inc.h + +#include "util_bump_cache.h" + +#if RV_WIN_ENABLED + #include "util_idraw2d.h" +#endif