commit 05ba29dbd5abf2277521f1f00b80786a007e8e2a
parent f9d49901707dafcfc5ffe680b3b6631e6851d116
Author: Samdal <samdal@protonmail.com>
Date: Tue, 25 Mar 2025 15:29:50 +0100
idraw2d updated
Diffstat:
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, ©_from[0]);
- rv_vertex_cache_push(&ctx->vertex, ©_from[1]);
- rv_vertex_cache_push(&ctx->vertex, ©_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, ©_from[0]);
+ rv_bump_cache_push(&ctx->vertex, ©_from[1]);
+ rv_bump_cache_push(&ctx->vertex, ©_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