revolver

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

commit ea52e2799ae8a1b1382f498d9a57d19443ff028f
parent f047c7e95a5f9ad9902a90ac6b1e9e1a03ad172d
Author: Samdal <samdal@protonmail.com>
Date:   Sat, 22 Mar 2025 19:45:31 +0100

pipeline, improved, mouse buttons, hello_window

Diffstat:
Mbuild.sh | 3++-
Mexamples/events.c | 33++++++++++++++++++++++-----------
Aexamples/hello_window.c | 27+++++++++++++++++++++++++++
Mexamples/simple_texture.c | 94++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Mexamples/simple_triangle.c | 81++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Mexamples/test.c | 130++++++++++++++++++++++++++++++++++++++-----------------------------------------
Mexamples/uniform.c | 102+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Msrc/platform/gfx/platform_gfx.c | 87++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Msrc/platform/gfx/platform_gfx.h | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/platform/gfx/xcb_impl.c | 68++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/platform/platform_arena.c | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/platform/platform_cracker.h | 3+++
Msrc/render/impl/opengl.c | 386++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Msrc/render/render.h | 127++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/render/render_helpers.c | 101+++++++++++++++++++++++++++++++++++++++++++------------------------------------
15 files changed, 862 insertions(+), 496 deletions(-)

diff --git a/build.sh b/build.sh @@ -12,6 +12,7 @@ do "uniform") sources=(./examples/uniform.c) ;; "simple_triangle") sources=(./examples/simple_triangle.c) ;; "simple_texture") sources=(./examples/simple_texture.c) ;; + "hello_window") sources=(./examples/hello_window.c) ;; esac done @@ -36,7 +37,7 @@ compiler_flags=( -D_GNU_SOURCE=1 ) common_flags=( - #-fsanitize=address,float-divide-by-zero,float-cast-overflow -fno-sanitize=null,alignment -fno-sanitize-recover=all -fno-omit-frame-pointer + -fsanitize=address,float-divide-by-zero,float-cast-overflow -fno-sanitize=null,alignment -fno-sanitize-recover=all -fno-omit-frame-pointer ) linker_flags=( -lm -lxcb -lxcb-xkb -lEGL -lGL diff --git a/examples/events.c b/examples/events.c @@ -8,21 +8,28 @@ int main(void) { rv_window_desc_t desc = {.name = S("App"), .attach_render = true}; rv_window_handle_t* window = rv_create_window(desc); - while(1) { + while (1) { rv_temp_arena scratch = rv_scratch_begin(0, 0); - for(rv_event_t* e = rv_get_events(scratch.arena, 0); e; e = e->next) { - switch(e->type) { + f64 t = rv_time(); + for (rv_event_t* e = rv_get_events(scratch.arena, 0); e; e = e->next) { + printf("%4.4lf : ", t); + switch (e->type) { case RV_EVENT_INVALID: { - rv_assert(false); + rv_unreachable(); } break; case RV_EVENT_BUTTON_PRESS: { - //rv_destroy_window(&window); + rv_vec2 mpos = rv_window_mouse_pos(window); + printf("button %d pressed (state: %lu) at <x:%.0f, y:%.0f>", e->button_press.button, rv_keyboard_context.current_mouse_state, mpos.x, mpos.y); + } break; + case RV_EVENT_BUTTON_RELEASE: { + rv_vec2 mpos = rv_window_mouse_pos(window); + printf("button %d released (state: %lu) at <x:%.0f, y:%.0f>", e->button_release.button, rv_keyboard_context.current_mouse_state, mpos.x, mpos.y); } break; case RV_EVENT_KEY_PRESS: { - printf("pressed key %d '%.*s' (mods: %d) on window %p\n", e->key_press.keycode, rv_s8v(e->key_press.string), e->key_press.mods, e->key_press.window); + printf("pressed key %d '%.*s' (mods: %d) on window %p", e->key_press.keycode, rv_s8v(e->key_press.string), e->key_press.mods, e->key_press.window); } break; case RV_EVENT_KEY_RELEASE: { - printf("pressed key %d '%.*s' (mods: %d) on window %p\n", e->key_release.keycode, rv_s8v(e->key_release.string), e->key_release.mods, e->key_release.window); + printf("released key %d '%.*s' (mods: %d) on window %p", e->key_release.keycode, rv_s8v(e->key_release.string), e->key_release.mods, e->key_release.window); } break; case RV_EVENT_WINDOW_CLOSE: { if (e->window_close == window) { @@ -31,13 +38,17 @@ int main(void) { } break; case RV_EVENT_WINDOW_RESIZE: { rv_vec2 size = rv_window_size(window); - printf("size: <w:%f, h:%f> on window %p\n", size.x, size.y, e->window_resize); + printf("size: <w:%f, h:%f> on window %p", size.x, size.y, e->window_resize); + } break; + case RV_EVENT_WINDOW_ENTER: { + printf("window entered %p", e->window_enter); + } break; + case RV_EVENT_WINDOW_LEAVE: { + printf("window leaved %p", e->window_leave); } break; - default: break; } + printf("\n"); } - rv_vec2 ptr = rv_mouse_pos(window); - //printf("ptr: <w:%f, h:%f>\n", ptr.x, ptr.y); rv_scratch_end(scratch); } diff --git a/examples/hello_window.c b/examples/hello_window.c @@ -0,0 +1,27 @@ +////////////////////////////////////////////////////////////////// +// simple_triangle.c + +#include "revolver_inc.h" +#include "revolver_inc.c" + +int main(void) { + rv_window_desc_t desc = {.name = S("App"), .attach_render = true}; + rv_window_handle_t* window = rv_create_window(desc); + + rv_render_pass_list_t rpass_list = {0}; + + while(1) { + rv_temp_arena scratch = rv_scratch_begin(0, 0); + 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; + } + } + } + rv_scratch_end(scratch); + } +exit_program: + + return 0; +} diff --git a/examples/simple_texture.c b/examples/simple_texture.c @@ -71,69 +71,85 @@ int main(void) { } } + // make render objects rv_texture_t* tex = rv_push_compound(arena, rv_texture_t, {.data = pixels, .size = rv_v2s(ROW_COL_CT)}); - rv_vbo_t* vbo = rv_push_compound(arena, rv_vbo_t, {.data = v_data, .size = sizeof(v_data)}); - rv_vbo_t* ibo = rv_push_compound(arena, rv_ibo_t, {.data = i_data, .size = sizeof(i_data), .elem_size = sizeof(i_data[0])}); - 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_program_t* prog = rv_push(arena, rv_program_t); - - rv_render_push_shader_to_prog(arena, prog, vertex); - rv_render_push_shader_to_prog(arena, prog, fragment); - rv_uniform_t* u_tex = rv_render_push_uniform_to_prog_texture(arena, prog, S("u_tex"), tex); - rv_render_push_vattr_to_prog(arena, prog, RV_VATTR_TYPE_FLOAT2); - rv_render_push_vattr_to_prog(arena, prog, RV_VATTR_TYPE_FLOAT2); - - rv_render_command_list_t create_shader_instructions = {0}; - rv_render_push_obj_command(arena, &create_shader_instructions, RV_RENDER_COMMAND_OBJ_TEXTURE, RV_RENDER_OBJ_OP_CREATE, tex); - rv_render_push_obj_command(arena, &create_shader_instructions, RV_RENDER_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_CREATE, vbo); - rv_render_push_obj_command(arena, &create_shader_instructions, RV_RENDER_COMMAND_OBJ_INDEX, RV_RENDER_OBJ_OP_CREATE, ibo); - rv_render_push_obj_command(arena, &create_shader_instructions, RV_RENDER_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, vertex); - rv_render_push_obj_command(arena, &create_shader_instructions, RV_RENDER_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, fragment); - rv_render_push_obj_command(arena, &create_shader_instructions, RV_RENDER_COMMAND_OBJ_PROGRAM, RV_RENDER_OBJ_OP_CREATE, prog); - - rv_render_command_list_t render_shader_instructions = {0}; - rv_render_push_obj_command(arena, &render_shader_instructions, RV_RENDER_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_BIND, vbo); - rv_render_push_obj_command(arena, &render_shader_instructions, RV_RENDER_COMMAND_OBJ_INDEX, RV_RENDER_OBJ_OP_BIND, ibo); - rv_render_push_obj_command(arena, &render_shader_instructions, RV_RENDER_COMMAND_OBJ_PROGRAM, RV_RENDER_OBJ_OP_BIND, prog); - rv_render_push_command_compound(arena, &render_shader_instructions, RV_RENDER_COMMAND_DRAW, { .draw = {.count = 6 } }); + rv_vbo_t* vbo = rv_push_compound(arena, rv_vbo_t, {.data = v_data, .size = sizeof(v_data)}); + rv_vbo_t* ibo = rv_push_compound(arena, rv_ibo_t, {.data = i_data, .size = sizeof(i_data), .elem_size = sizeof(i_data[0])}); + 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); + rv_pipeline_push_vattr(arena, pip, RV_VATTR_TYPE_FLOAT2); + rv_uniform_t* u_tex = rv_pipeline_push_uniform(arena, pip, S("u_tex"), RV_UNIFORM_TEX); + + // instructions to create render objects + rv_command_list_t create_instructions = {0}; + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_TEXTURE, RV_RENDER_OBJ_OP_CREATE, tex); + 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_INDEX, RV_RENDER_OBJ_OP_CREATE, ibo); + 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); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, pip); + rv_cmd_push_uniform_update(arena, &create_instructions, u_tex, {.v_tex = tex}); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, NULL); + + // instructions to render + rv_command_list_t render_instructions = {0}; + rv_cmd_push_obj(arena, &render_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, pip); + rv_cmd_push_obj(arena, &render_instructions, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_BIND, vbo); + rv_cmd_push_obj(arena, &render_instructions, RV_COMMAND_OBJ_INDEX, RV_RENDER_OBJ_OP_BIND, ibo); + rv_cmd_push_type(arena, &render_instructions, RV_COMMAND_DRAW)->draw.count = 6; + rv_cmd_push_obj(arena, &render_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, NULL); // 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_shader_instructions); + rv_render_copy_commands(arena, &create_rpass->commands, &create_instructions); while(1) { + rv_temp_arena scratch = rv_scratch_begin(0, 0); - if (window) { // render screen - - 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); - // pick renderpass - rv_render_pass_t* rpass = rv_render_push_render_pass(scratch.arena, &rpass_list); - - { // set viewport - rv_render_command_t* viewport = rv_render_push_command(scratch.arena, &rpass->commands, RV_RENDER_COMMAND_SET_VIEWPORT); + // 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)); } + } + + if (window) { // render screen { // clear - rv_render_command_t* clear = rv_render_push_command(scratch.arena, &rpass->commands, RV_RENDER_COMMAND_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, 0.1); } { // draw custom shader // copy render commands - rv_render_copy_commands(scratch.arena, &rpass->commands, &render_shader_instructions); + rv_render_copy_commands(scratch.arena, &rpass->commands, &render_instructions); } rv_window_render_commit(window, &rpass_list); - rpass_list = (rv_render_pass_list_t){0}; - - rv_scratch_end(scratch); } + rv_scratch_end(scratch); + rpass_list = (rv_render_pass_list_t){0}; } +exit_program: return 0; } diff --git a/examples/simple_triangle.c b/examples/simple_triangle.c @@ -44,62 +44,75 @@ int main(void) { rv_arena* arena = rv_arena_alloc(); rv_render_pass_list_t rpass_list = {0}; - rv_vbo_t* vbo = rv_push_compound(arena, rv_vbo_t, {.data = v_data, .size = sizeof(v_data)}); - 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_program_t* prog = rv_push(arena, rv_program_t); - - rv_render_push_shader_to_prog(arena, prog, vertex); - rv_render_push_shader_to_prog(arena, prog, fragment); - rv_render_push_vattr_to_prog(arena, prog, RV_VATTR_TYPE_FLOAT2); - rv_render_push_vattr_to_prog(arena, prog, RV_VATTR_TYPE_FLOAT3); - - rv_render_command_list_t create_shader_instructions = {0}; - rv_render_push_obj_command(arena, &create_shader_instructions, RV_RENDER_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_CREATE, vbo); - rv_render_push_obj_command(arena, &create_shader_instructions, RV_RENDER_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, vertex); - rv_render_push_obj_command(arena, &create_shader_instructions, RV_RENDER_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, fragment); - rv_render_push_obj_command(arena, &create_shader_instructions, RV_RENDER_COMMAND_OBJ_PROGRAM, RV_RENDER_OBJ_OP_CREATE, prog); - - rv_render_command_list_t render_shader_instructions = {0}; - rv_render_push_obj_command(arena, &render_shader_instructions, RV_RENDER_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_BIND, vbo); - rv_render_push_obj_command(arena, &render_shader_instructions, RV_RENDER_COMMAND_OBJ_PROGRAM, RV_RENDER_OBJ_OP_BIND, prog); - rv_render_push_command_compound(arena, &render_shader_instructions, RV_RENDER_COMMAND_DRAW, { .draw = {.count = 3 } }); + // make render objects + rv_vbo_t* vbo = rv_push_compound(arena, rv_vbo_t, {.data = v_data, .size = sizeof(v_data)}); + 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); + rv_pipeline_push_vattr(arena, pip, RV_VATTR_TYPE_FLOAT3); + + // 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_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); + + // instructions to render + rv_command_list_t render_instructions = {0}; + rv_cmd_push_obj(arena, &render_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, pip); + rv_cmd_push_obj(arena, &render_instructions, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_BIND, vbo); + rv_cmd_push_type(arena, &render_instructions, RV_COMMAND_DRAW)->draw.count = 3; + rv_cmd_push_obj(arena, &render_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, NULL); // 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_shader_instructions); + rv_render_copy_commands(arena, &create_rpass->commands, &create_instructions); while(1) { + rv_temp_arena scratch = rv_scratch_begin(0, 0); - if (window) { // render screen - - 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); - // pick renderpass - rv_render_pass_t* rpass = rv_render_push_render_pass(scratch.arena, &rpass_list); - - { // set viewport - rv_render_command_t* viewport = rv_render_push_command(scratch.arena, &rpass->commands, RV_RENDER_COMMAND_SET_VIEWPORT); + // 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)); } + } + + if (window) { // render screen { // clear - rv_render_command_t* clear = rv_render_push_command(scratch.arena, &rpass->commands, RV_RENDER_COMMAND_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, 0.1); } { // draw custom shader // copy render commands - rv_render_copy_commands(scratch.arena, &rpass->commands, &render_shader_instructions); + rv_render_copy_commands(scratch.arena, &rpass->commands, &render_instructions); } rv_window_render_commit(window, &rpass_list); - rpass_list = (rv_render_pass_list_t){0}; - - rv_scratch_end(scratch); } + rv_scratch_end(scratch); + rpass_list = (rv_render_pass_list_t){0}; } +exit_program: return 0; } diff --git a/examples/test.c b/examples/test.c @@ -1,8 +1,15 @@ + +////////////////////////////////////////////////////////////////// +// simple_texture.c + #include "revolver_inc.h" #include "revolver_inc.c" #define ROW_COL_CT 10 +////////////////////////////////////////////////////////////////// +// data + // Vertex data for quad f32 v_data[] = { // Positions UVs @@ -41,6 +48,8 @@ rv_str8 f_src = S("#version 330 core\n" rv_strify( } )); +////////////////////////////////////////////////////////////////// + int main(void) { rv_window_desc_t desc = {.name = S("App"), .attach_render = true}; @@ -63,100 +72,85 @@ int main(void) { } } + // make render objects rv_texture_t* tex = rv_push_compound(arena, rv_texture_t, {.data = pixels, .size = rv_v2s(ROW_COL_CT)}); - rv_vbo_t* vbo = rv_push_compound(arena, rv_vbo_t, {.data = v_data, .size = sizeof(v_data)}); - rv_vbo_t* ibo = rv_push_compound(arena, rv_ibo_t, {.data = i_data, .size = sizeof(i_data), .elem_size = sizeof(i_data[0])}); - 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_program_t* prog = rv_push(arena, rv_program_t); - rv_render_push_shader_to_prog(arena, prog, vertex); - rv_render_push_shader_to_prog(arena, prog, fragment); - rv_uniform_t* u_tex = rv_render_push_uniform_to_prog_texture(arena, prog, S("u_tex"), tex); - rv_render_push_vattr_to_prog(arena, prog, RV_VATTR_TYPE_FLOAT2); - rv_render_push_vattr_to_prog(arena, prog, RV_VATTR_TYPE_FLOAT2); - - rv_render_command_list_t create_shader_instructions = {0}; - rv_render_push_obj_command(arena, &create_shader_instructions, RV_RENDER_COMMAND_OBJ_TEXTURE, RV_RENDER_OBJ_OP_CREATE, tex); - rv_render_push_obj_command(arena, &create_shader_instructions, RV_RENDER_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_CREATE, vbo); - rv_render_push_obj_command(arena, &create_shader_instructions, RV_RENDER_COMMAND_OBJ_INDEX, RV_RENDER_OBJ_OP_CREATE, ibo); - rv_render_push_obj_command(arena, &create_shader_instructions, RV_RENDER_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, vertex); - rv_render_push_obj_command(arena, &create_shader_instructions, RV_RENDER_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, fragment); - rv_render_push_obj_command(arena, &create_shader_instructions, RV_RENDER_COMMAND_OBJ_PROGRAM, RV_RENDER_OBJ_OP_CREATE, prog); - - rv_render_command_list_t render_shader_instructions = {0}; - rv_render_push_obj_command(arena, &render_shader_instructions, RV_RENDER_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_BIND, vbo); - rv_render_push_obj_command(arena, &render_shader_instructions, RV_RENDER_COMMAND_OBJ_INDEX, RV_RENDER_OBJ_OP_BIND, ibo); - rv_render_push_obj_command(arena, &render_shader_instructions, RV_RENDER_COMMAND_OBJ_PROGRAM, RV_RENDER_OBJ_OP_BIND, prog); - rv_render_push_command_compound(arena, &render_shader_instructions, RV_RENDER_COMMAND_DRAW, { .draw = {.count = 6 } }); + rv_vbo_t* vbo = rv_push_compound(arena, rv_vbo_t, {.data = v_data, .size = sizeof(v_data)}); + rv_vbo_t* ibo = rv_push_compound(arena, rv_ibo_t, {.data = i_data, .size = sizeof(i_data), .elem_size = sizeof(i_data[0])}); + 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); + rv_pipeline_push_vattr(arena, pip, RV_VATTR_TYPE_FLOAT2); + rv_uniform_t* u_tex = rv_pipeline_push_uniform(arena, pip, S("u_tex"), RV_UNIFORM_TEX); + + // instructions to create render objects + rv_command_list_t create_instructions = {0}; + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_TEXTURE, RV_RENDER_OBJ_OP_CREATE, tex); + 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_INDEX, RV_RENDER_OBJ_OP_CREATE, ibo); + 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); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, pip); + rv_cmd_push_uniform_update(arena, &create_instructions, u_tex, {.v_tex = tex}); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, NULL); + + // instructions to render + rv_command_list_t render_instructions = {0}; + rv_cmd_push_obj(arena, &render_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, pip); + rv_cmd_push_obj(arena, &render_instructions, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_BIND, vbo); + rv_cmd_push_obj(arena, &render_instructions, RV_COMMAND_OBJ_INDEX, RV_RENDER_OBJ_OP_BIND, ibo); + rv_cmd_push_type(arena, &render_instructions, RV_COMMAND_DRAW)->draw.count = 6; + rv_cmd_push_obj(arena, &render_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, NULL); // 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_shader_instructions); + rv_render_copy_commands(arena, &create_rpass->commands, &create_instructions); while(1) { + rv_temp_arena scratch = rv_scratch_begin(0, 0); - { // process events - rv_temp_arena scratch = rv_scratch_begin(0, 0); - for(rv_event_t* e = rv_get_events(scratch.arena, 0); e; e = e->next) { - switch(e->type) { - case RV_EVENT_INVALID: { - rv_assert(false); - } break; - case RV_EVENT_BUTTON_PRESS: { - //rv_destroy_window(&window); - } break; - case RV_EVENT_KEY_PRESS: { - printf("pressed key %d '%.*s' (mods: %d) on window %p\n", e->key_press.keycode, rv_s8v(e->key_press.string), e->key_press.mods, e->key_press.window); - } break; - case RV_EVENT_KEY_RELEASE: { - printf("pressed key %d '%.*s' (mods: %d) on window %p\n", e->key_release.keycode, rv_s8v(e->key_release.string), e->key_release.mods, e->key_release.window); - } break; - case RV_EVENT_WINDOW_CLOSE: { - if (e->window_close == window) { - rv_abort_msg(0, "close request"); - } - } break; - case RV_EVENT_WINDOW_RESIZE: { - puts("move"); - } break; - default: break; + // 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; } } - rv_scratch_end(scratch); + 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)); + } } - if (window) { // render screen - 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); - - { // set viewport - rv_render_command_t* viewport = rv_render_push_command(scratch.arena, &rpass->commands, RV_RENDER_COMMAND_SET_VIEWPORT); - viewport->viewport = rv_v4(.xy = {0, 0}, .zw = rv_window_size(window)); - } - { // clear - rv_render_command_t* clear = rv_render_push_command(scratch.arena, &rpass->commands, RV_RENDER_COMMAND_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, 0.1); } { // draw custom shader // copy render commands - rv_render_copy_commands(scratch.arena, &rpass->commands, &render_shader_instructions); + rv_render_copy_commands(scratch.arena, &rpass->commands, &render_instructions); } rv_window_render_commit(window, &rpass_list); - rpass_list = (rv_render_pass_list_t){0}; - - rv_scratch_end(scratch); } + rv_scratch_end(scratch); + rpass_list = (rv_render_pass_list_t){0}; } +exit_program: return 0; } diff --git a/examples/uniform.c b/examples/uniform.c @@ -46,50 +46,63 @@ int main(void) { rv_arena* arena = rv_arena_alloc(); rv_render_pass_list_t rpass_list = {0}; - rv_vbo_t* vbo = rv_push_compound(arena, rv_vbo_t, {.data = v_data, .size = sizeof(v_data)}); - 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_program_t* prog = rv_push(arena, rv_program_t); - - rv_render_push_shader_to_prog(arena, prog, vertex); - rv_render_push_shader_to_prog(arena, prog, fragment); - rv_uniform_t* u_color = rv_render_push_uniform_to_prog(arena, prog, S("u_color"), RV_UNIFORM_VEC3); - rv_uniform_t* u_model = rv_render_push_uniform_to_prog(arena, prog, S("u_model"), RV_UNIFORM_MAT4); - rv_render_push_vattr_to_prog(arena, prog, RV_VATTR_TYPE_FLOAT2); - rv_render_push_vattr_to_prog(arena, prog, RV_VATTR_TYPE_FLOAT3); - - rv_render_command_list_t create_shader_instructions = {0}; - rv_render_push_obj_command(arena, &create_shader_instructions, RV_RENDER_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_CREATE, vbo); - rv_render_push_obj_command(arena, &create_shader_instructions, RV_RENDER_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, vertex); - rv_render_push_obj_command(arena, &create_shader_instructions, RV_RENDER_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, fragment); - rv_render_push_obj_command(arena, &create_shader_instructions, RV_RENDER_COMMAND_OBJ_PROGRAM, RV_RENDER_OBJ_OP_CREATE, prog); - - rv_render_command_list_t render_shader_instructions = {0}; - rv_render_push_obj_command(arena, &render_shader_instructions, RV_RENDER_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_BIND, vbo); - rv_render_push_obj_command(arena, &render_shader_instructions, RV_RENDER_COMMAND_OBJ_PROGRAM, RV_RENDER_OBJ_OP_BIND, prog); - rv_render_push_command_compound(arena, &render_shader_instructions, RV_RENDER_COMMAND_DRAW, { .draw = {.count = 3 } }); + // make render objects + rv_vbo_t* vbo = rv_push_compound(arena, rv_vbo_t, {.data = v_data, .size = sizeof(v_data)}); + 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); + rv_pipeline_push_vattr(arena, pip, RV_VATTR_TYPE_FLOAT3); + rv_uniform_t* u_color = rv_pipeline_push_uniform(arena, pip, S("u_color"), RV_UNIFORM_VEC3); + rv_uniform_t* u_model = rv_pipeline_push_uniform(arena, pip, S("u_model"), RV_UNIFORM_MAT4); + + // 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_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); + + // instructions to render + rv_command_list_t render_instructions = {0}; + rv_cmd_push_obj(arena, &render_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, pip); + rv_cmd_push_obj(arena, &render_instructions, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_BIND, vbo); + rv_cmd_push_type(arena, &render_instructions, RV_COMMAND_DRAW)->draw.count = 3; + rv_cmd_push_obj(arena, &render_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, NULL); // 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_shader_instructions); + rv_render_copy_commands(arena, &create_rpass->commands, &create_instructions); while(1) { + rv_temp_arena scratch = rv_scratch_begin(0, 0); - if (window) { // render screen - - 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); + // pick renderpass + rv_render_pass_t* rpass = rv_render_push_render_pass(scratch.arena, &rpass_list); - { // set viewport - rv_render_command_t* viewport = rv_render_push_command(scratch.arena, &rpass->commands, RV_RENDER_COMMAND_SET_VIEWPORT); + // 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)); } + } + + if (window) { // render screen { // clear - rv_render_command_t* clear = rv_render_push_command(scratch.arena, &rpass->commands, RV_RENDER_COMMAND_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, 0.1); } @@ -97,37 +110,38 @@ int main(void) { { // draw custom shader // copy render commands - rv_render_command_t* rcmd = rv_render_copy_commands(scratch.arena, &rpass->commands, &render_shader_instructions); + rv_command_t* rcmd = rv_render_copy_commands(scratch.arena, &rpass->commands, &render_instructions); - // find the program command - rv_render_command_t* prog_cmd = rcmd; - for (; prog_cmd; prog_cmd = prog_cmd->next) { - if (rv_render_command_has_program(prog_cmd, prog)) break; + // find the pipeline command + rv_command_t* pipeline_cmd = rcmd; + for (; pipeline_cmd; pipeline_cmd = pipeline_cmd->next) { + if (rv_command_has_pipeline(pipeline_cmd, pip)) break; } - if (prog_cmd) { + if (pipeline_cmd) { // add uniform updates const f64 t = rv_time(); const f32 r = sinf(t) * 0.5f + 0.5f; const f32 g = cosf(t * 6.f) * 0.5f + 0.5f; const f32 b = sinf(t * 3.f) * 0.5f + 0.5f; - rv_render_update_uniform_compound(scratch.arena, prog_cmd, u_color, {.v_vec3 = rv_v3(r, g, b)}); + rv_cmd_insert_uniform_update(scratch.arena, &rpass->commands, pipeline_cmd, u_color, {.v_vec3 = rv_v3(r, g, b)}); const f32 st = sin(t); rv_mat4 rot = rv_mat4_rotatev(t, RV_ZAXIS); rv_mat4 scl = rv_mat4_scalev(rv_v3(st, st, st)); rv_mat4 model = rv_mat4_mul_list(2, scl, rot); - rv_render_update_uniform_compound(scratch.arena, prog_cmd, u_model, {.v_mat4 = model}); - + rv_command_t* update_u_model = rv_cmd_insert_type(scratch.arena, &rpass->commands, pipeline_cmd, RV_COMMAND_UNIFORM_UPDATE); + update_u_model->uniform_update.desc = u_model; + update_u_model->uniform_update.value.v_mat4 = model; } } rv_window_render_commit(window, &rpass_list); - rpass_list = (rv_render_pass_list_t){0}; - - rv_scratch_end(scratch); } + rv_scratch_end(scratch); + rpass_list = (rv_render_pass_list_t){0}; } +exit_program: return 0; } diff --git a/src/platform/gfx/platform_gfx.c b/src/platform/gfx/platform_gfx.c @@ -3,46 +3,87 @@ RV_GLOBAL bool32 rv_key_pressed(rv_keycode_t keycode) { - return rv_keyboard_context.current_state[keycode] && !rv_keyboard_context.last_state[keycode]; + return rv_keyboard_context.current_state[keycode] && !rv_keyboard_context.last_state[keycode]; } RV_GLOBAL bool32 rv_key_down(rv_keycode_t keycode) { - return rv_keyboard_context.current_state[keycode]; + return rv_keyboard_context.current_state[keycode]; } RV_GLOBAL bool32 rv_key_released(rv_keycode_t keycode) { - return !rv_keyboard_context.current_state[keycode] && rv_keyboard_context.last_state[keycode]; + return !rv_keyboard_context.current_state[keycode] && rv_keyboard_context.last_state[keycode]; } RV_GLOBAL bool32 rv_key_changed(rv_keycode_t keycode) { - return rv_keyboard_context.current_state[keycode] != rv_keyboard_context.last_state[keycode]; + return rv_keyboard_context.current_state[keycode] != rv_keyboard_context.last_state[keycode]; } -RV_GLOBAL bool32 rv_key_mod(rv_keycode_t keycode, u8 mask) +RV_GLOBAL bool32 rv_key_mod(u8 mask) { - return (rv_keyboard_context.mods & mask) != 0; + return (rv_keyboard_context.mods & mask) != 0; +} + +RV_GLOBAL bool32 rv_mouse_pressed(u32 mask) +{ + for (u32 i = 0; i < 32; i++) { + if (((rv_keyboard_context.current_mouse_state >> i) & 1) == ((mask >> i) & 1)) { + if (((rv_keyboard_context.last_mouse_state >> i) & 1) != ((mask >> i) & 1)) { + return true; + } + } + } + return false; +} + +RV_GLOBAL bool32 rv_mouse_down(u32 mask) +{ + return (rv_keyboard_context.current_mouse_state & mask) != 0; +} + +RV_GLOBAL bool32 rv_mouse_released(u32 mask) +{ + for (u32 i = 0; i < 32; i++) { + if (((rv_keyboard_context.current_mouse_state >> i) & 1) != ((mask >> i) & 1)) { + if (((rv_keyboard_context.last_mouse_state >> i) & 1) == ((mask >> i) & 1)) { + return true; + } + } + } + return false; +} + +RV_GLOBAL bool32 rv_mouse_changed(u32 mask) +{ + return ((rv_keyboard_context.current_mouse_state & mask) ^ (rv_keyboard_context.last_mouse_state & mask)) != 0; } RV_GLOBAL void rv_keyboard_context_update(rv_keyboard_context_t* kbd_ctx, rv_event_t* events) { - rv_mem_copy(kbd_ctx->last_state, kbd_ctx->current_state, sizeof(kbd_ctx->current_state)); - - for (rv_event_t* e = events; e; e = e->next) { - if (e->key_press.keycode == RV_KEYCODE_INVALID) continue; - switch(e->type) { - case RV_EVENT_KEY_PRESS: { - kbd_ctx->current_state[e->key_press.keycode] = true; - kbd_ctx->mods = e->key_press.mods; - kbd_ctx->group = e->key_press.group; - } break; - case RV_EVENT_KEY_RELEASE: { - kbd_ctx->current_state[e->key_release.keycode] = false; - kbd_ctx->group = e->key_press.group; - } break; - default: break; - } - } + kbd_ctx->last_mouse_state = kbd_ctx->current_mouse_state; + rv_mem_copy(kbd_ctx->last_state, kbd_ctx->current_state, sizeof(kbd_ctx->current_state)); + + for (rv_event_t* e = events; e; e = e->next) { + if (e->key_press.keycode == RV_KEYCODE_INVALID) continue; + switch(e->type) { + case RV_EVENT_KEY_PRESS: { + kbd_ctx->current_state[e->key_press.keycode] = true; + kbd_ctx->mods = e->key_press.mods; + kbd_ctx->group = e->key_press.group; + } break; + case RV_EVENT_KEY_RELEASE: { + kbd_ctx->current_state[e->key_release.keycode] = false; + kbd_ctx->group = e->key_press.group; + } break; + case RV_EVENT_BUTTON_PRESS: { + kbd_ctx->current_mouse_state |= 1 << e->button_press.button; + } break; + case RV_EVENT_BUTTON_RELEASE: { + kbd_ctx->current_mouse_state &= ~(1 << e->button_release.button); + } break; + default: break; + } + } } diff --git a/src/platform/gfx/platform_gfx.h b/src/platform/gfx/platform_gfx.h @@ -173,11 +173,57 @@ typedef enum { RV_KEY_MOD_ALTGR = RV_KEY_MOD_8, } rv_key_mods_t; +typedef enum { + // NOTE(Samdal): RV_MOUSE_0 does not exist for simplicity... + RV_MOUSE_1 = (1 << 1), + RV_MOUSE_2 = (1 << 2), + RV_MOUSE_3 = (1 << 3), + RV_MOUSE_4 = (1 << 4), + RV_MOUSE_5 = (1 << 5), + RV_MOUSE_6 = (1 << 6), + RV_MOUSE_7 = (1 << 7), + RV_MOUSE_8 = (1 << 8), + RV_MOUSE_9 = (1 << 9), + RV_MOUSE_10 = (1 << 10), + RV_MOUSE_11 = (1 << 11), + RV_MOUSE_12 = (1 << 12), + RV_MOUSE_13 = (1 << 13), + RV_MOUSE_14 = (1 << 14), + RV_MOUSE_15 = (1 << 15), + RV_MOUSE_16 = (1 << 16), + RV_MOUSE_17 = (1 << 17), + RV_MOUSE_18 = (1 << 18), + RV_MOUSE_19 = (1 << 19), + RV_MOUSE_20 = (1 << 20), + RV_MOUSE_21 = (1 << 21), + RV_MOUSE_22 = (1 << 22), + RV_MOUSE_23 = (1 << 23), + RV_MOUSE_24 = (1 << 24), + RV_MOUSE_25 = (1 << 25), + RV_MOUSE_26 = (1 << 26), + RV_MOUSE_27 = (1 << 27), + RV_MOUSE_28 = (1 << 28), + RV_MOUSE_29 = (1 << 29), + RV_MOUSE_30 = (1 << 30), + RV_MOUSE_31 = (1 << 31), + + RV_MOUSE_PRIMARY = RV_MOUSE_1, + RV_MOUSE_SECONDARY = RV_MOUSE_3, + RV_MOUSE_LEFT = RV_MOUSE_1, + RV_MOUSE_RIGHT = RV_MOUSE_3, + RV_MOUSE_MIDDLE = RV_MOUSE_2, + RV_MOUSE_SCROLL_UP = RV_MOUSE_4, + RV_MOUSE_SCROLL_DOWN = RV_MOUSE_5, +} rv_mouse_mask_t; + typedef struct { bool8 last_state[RV_KEYCODE_COUNT]; bool8 current_state[RV_KEYCODE_COUNT]; u8 mods; u8 group; + + u64 last_mouse_state; + u64 current_mouse_state; } rv_keyboard_context_t; // updated when rv_get_events() is called @@ -190,7 +236,12 @@ RV_GLOBAL bool32 rv_key_down(rv_keycode_t keycode); RV_GLOBAL bool32 rv_key_released(rv_keycode_t keycode); RV_GLOBAL bool32 rv_key_changed(rv_keycode_t keycode); -RV_GLOBAL bool32 rv_key_mod(rv_keycode_t keycode, u8 mask); +RV_GLOBAL bool32 rv_key_mod(u8 mask); + +RV_GLOBAL bool32 rv_mouse_pressed(u32 mask); // any button pressed +RV_GLOBAL bool32 rv_mouse_down(u32 mask); // any button down +RV_GLOBAL bool32 rv_mouse_released(u32 mask); // any button released +RV_GLOBAL bool32 rv_mouse_changed(u32 mask); // any button changed ////////////////////////////////////////////////////////////////// @@ -223,9 +274,16 @@ struct rv_event_t { rv_str8 string; u8 mods; u8 group; + u8 native_keycode; // non-layout-sensetive, only for custom logic } key_press; struct _rv_key_press_releaase key_release; + struct _rv_button_press_releaase { + u32 button; // 1, 2, 3, 4... + rv_window_handle_t* window; + } button_press; + struct _rv_button_press_releaase button_release; + rv_window_handle_t* window_resize; rv_window_handle_t* window_close; rv_window_handle_t* window_enter; @@ -246,7 +304,7 @@ RV_GLOBAL rv_event_t* rv_get_events(rv_arena* arena, rv_event_flags_t flags); // // if NULL, will get the last created window RV_GLOBAL rv_vec2 rv_window_size(rv_window_handle_t* window); -RV_GLOBAL rv_vec2 rv_mouse_pos(rv_window_handle_t* window); +RV_GLOBAL rv_vec2 rv_widnow_mouse_pos(rv_window_handle_t* window); ////////////////////////////////////////////////////////////////// // Rendering diff --git a/src/platform/gfx/xcb_impl.c b/src/platform/gfx/xcb_impl.c @@ -18,6 +18,7 @@ struct rv_window_handle_t { rv_vec2 last_size; xcb_intern_atom_reply_t* close_reply; void* render; + bool32 sent_initial_events; }; ////////////////////////////////////////////////////////////////// @@ -471,6 +472,7 @@ RV_GLOBAL rv_window_handle_t* rv_create_window(rv_window_desc_t desc) mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; + values[0] = screen->black_pixel; values[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | @@ -481,7 +483,7 @@ RV_GLOBAL rv_window_handle_t* rv_create_window(rv_window_desc_t desc) if (size.x == 0) size.x = 150; if (size.y == 0) size.y = 150; - xcb_create_window(xcb_context.connection, // xcb_context.connection + xcb_create_window(xcb_context.connection, // connection XCB_COPY_FROM_PARENT, // depth res->window_id, // window Id screen->root, // parent window @@ -538,6 +540,8 @@ RV_GLOBAL rv_window_handle_t* rv_create_window(rv_window_desc_t desc) if (done) break; } + res->last_size = rv_window_size(res); + rv_llist_stack_push(xcb_context.window_list, res); return res; @@ -546,7 +550,7 @@ RV_GLOBAL rv_window_handle_t* rv_create_window(rv_window_desc_t desc) RV_GLOBAL void rv_destroy_window(rv_window_handle_t** handle) { if (!*handle) { - rv_assert(false); + rv_unreachable(); return; } @@ -590,14 +594,29 @@ rv_window_handle_t* xcb_get_window(xcb_window_t window) { RV_GLOBAL rv_event_t* rv_get_events(rv_arena* arena, rv_event_flags_t flags) { - rv_event_t* res = NULL; + rv_event_t* res_first = NULL; + rv_event_t* res_last = NULL; + + // force send initial events... + for (rv_window_handle_t* w = xcb_context.window_list; w; w = w->next) { + if (!w->sent_initial_events) { + w->sent_initial_events = true; + rv_event_t* n; + + n = rv_push_compound(arena, rv_event_t, {.type = RV_EVENT_WINDOW_RESIZE, .window_resize = w}); + rv_llist_queue_push(res_first, res_last, n); + + n = rv_push_compound(arena, rv_event_t, {.type = RV_EVENT_KEY_PRESS, .key_press.mods = xcb_context.mods, .key_press.group = xcb_context.group}); + rv_llist_queue_push(res_first, res_last, n); + } + } xcb_generic_event_t *event; while ((event = xcb_poll_for_event(xcb_context.connection))) { rv_event_t new_ev = {0}; - bool32 key_is_press = false; + bool32 is_press = false; switch (event->response_type & ~0x80) { case XCB_EXPOSE: { @@ -618,11 +637,11 @@ RV_GLOBAL rv_event_t* rv_get_events(rv_arena* arena, rv_event_flags_t flags) case XCB_KEY_PRESS: { _Static_assert(sizeof(xcb_key_release_event_t) == sizeof(xcb_key_press_event_t), "press/release were not the same"); - key_is_press = true; + is_press = true; case XCB_KEY_RELEASE:; - if (key_is_press) new_ev.type = RV_EVENT_KEY_PRESS; - else new_ev.type = RV_EVENT_KEY_RELEASE; + if (is_press) new_ev.type = RV_EVENT_KEY_PRESS; + else new_ev.type = RV_EVENT_KEY_RELEASE; xcb_key_press_event_t* key_event = (xcb_key_press_event_t*)event; @@ -823,6 +842,7 @@ RV_GLOBAL rv_event_t* rv_get_events(rv_arena* arena, rv_event_flags_t flags) new_ev.key_press.keycode = kc; new_ev.key_press.mods = xcb_context.mods; new_ev.key_press.group = xcb_context.group; + new_ev.key_press.native_keycode = keycode; { char buf[XKB_KEYSYM_UTF8_MAX_SIZE]; @@ -843,8 +863,15 @@ RV_GLOBAL rv_event_t* rv_get_events(rv_arena* arena, rv_event_flags_t flags) new_ev.type = RV_EVENT_INVALID; } } break; - case XCB_BUTTON_PRESS: { new_ev.type = RV_EVENT_BUTTON_PRESS; } break; - case XCB_BUTTON_RELEASE: { new_ev.type = RV_EVENT_BUTTON_RELEASE; } break; + case XCB_BUTTON_PRESS: { + is_press = true; + case XCB_BUTTON_RELEASE: + if (is_press) new_ev.type = RV_EVENT_BUTTON_PRESS; + else new_ev.type = RV_EVENT_BUTTON_RELEASE; + xcb_button_press_event_t* button_event = (xcb_button_press_event_t*)event; + new_ev.button_press.button = button_event->detail; + new_ev.button_press.window = xcb_get_window(button_event->event); + } break; case XCB_CONFIGURE_NOTIFY: { xcb_configure_notify_event_t* conf_event = (xcb_configure_notify_event_t*)event; new_ev.window_resize = xcb_get_window(conf_event->event); @@ -882,30 +909,15 @@ RV_GLOBAL rv_event_t* rv_get_events(rv_arena* arena, rv_event_flags_t flags) if (new_ev.type != RV_EVENT_INVALID) { rv_event_t* n = rv_push_no_zero(arena, rv_event_t); *n = new_ev; - rv_llist_stack_push(res, n); + rv_llist_queue_push(res_first, res_last, n); } free(event); } - // make a resize event if it's not up to date - for (rv_window_handle_t* w = xcb_context.window_list; w; w = w->next) { - rv_event_t new_ev = {0}; - new_ev.window_resize = w; - - rv_vec2 size = rv_window_size(w); - if (new_ev.window_resize->last_size.x != size.x || new_ev.window_resize->last_size.y != size.y) { - new_ev.type = RV_EVENT_WINDOW_RESIZE; - new_ev.window_resize->last_size = rv_v2(size.x, size.y); - - rv_event_t* n = rv_push_copy(arena, rv_event_t, &new_ev); - rv_llist_stack_push(res, n); - } - } + rv_keyboard_context_update(&rv_keyboard_context, res_first); - rv_keyboard_context_update(&rv_keyboard_context, res); - - return res; + return res_first; } ////////////////////////////////////////////////////////////////// @@ -926,7 +938,7 @@ RV_GLOBAL rv_vec2 rv_window_size(rv_window_handle_t* window) return ret; } -RV_GLOBAL rv_vec2 rv_mouse_pos(rv_window_handle_t* window) +RV_GLOBAL rv_vec2 rv_window_mouse_pos(rv_window_handle_t* window) { rv_vec2 ret = {0}; xcb_query_pointer_cookie_t cookie = xcb_query_pointer(xcb_context.connection, xcb_maybe_window(window)->window_id); diff --git a/src/platform/platform_arena.c b/src/platform/platform_arena.c @@ -1,6 +1,58 @@ ////////////////////////////////////////////////////////////////// // platform_arena.c +#if RV_USE_DEBUG_MALLOC_ARENA + +// TODO(Samdal): make a malloc chained variant + +// Arena Creation/Destruction +RV_INTERNAL rv_arena* rv_arena_alloc_(rv_arena_params* params) { + return NULL; +} +RV_INTERNAL void rv_arena_release(rv_arena* arena) +{ + +} + +// Arena Push/Pop/Pos Core Functions +RV_INTERNAL void* rv_arena_push(rv_arena* arena, u64 size, u64 align) +{ + return malloc(size); +} +RV_INTERNAL u64 rv_arena_pos(rv_arena* arena) +{ + return 0; +} +RV_INTERNAL void rv_arena_pop_to(rv_arena* arena, u64 pos) { + +} + +// Arena Push/Pop Helpers +RV_INTERNAL void arena_clear(rv_arena* arena) +{ + +} +RV_INTERNAL void arena_pop(rv_arena* arena, u64 amt) +{ +} + +// Temporary Arena Scopes +RV_INTERNAL rv_temp_arena rv_temp_begin(rv_arena* arena) +{ + return (rv_temp_arena){0}; +} +RV_INTERNAL void rv_temp_end(rv_temp_arena temp) +{ + +} + +RV_GLOBAL rv_arena* rv_scratch_begin_(rv_arena **conflicts, u64 count) +{ + return NULL; +} + +#else // RV_USE_DEBUG_MALLOC_ARENA + // Arena Creation/Destruction RV_INTERNAL rv_arena* @@ -234,3 +286,5 @@ RV_GLOBAL rv_arena* rv_scratch_begin_(rv_arena **conflicts, u64 count) return result; } + +#endif // !RV_USE_DEBUG_MALLOC_ARENA diff --git a/src/platform/platform_cracker.h b/src/platform/platform_cracker.h @@ -21,6 +21,7 @@ // RV_FORCE_INLINE // RV_READ_ONLY // rv_assert(...) +// rv_unreachable() = rv_assert(false) // rv_alignof(T) // true=1, false=0 (C only, optional) // @@ -400,6 +401,8 @@ #define rv_assert(...) #endif +#define rv_unreachable() rv_assert(false) + #if RV_ASAN_ENABLED #include <sanitizer/asan_interface.h> #define RV_ASAN_POISOIN(ptr, sz) ASAN_POISON_MEMORY_REGION(ptr, sz) diff --git a/src/render/impl/opengl.c b/src/render/impl/opengl.c @@ -1,6 +1,8 @@ ////////////////////////////////////////////////////////////////// // opengl.c +#define ogl_safe_set(ptr, hndl_arg) ((ptr) ? ((ptr)->hndl_arg.u) : (0)) + struct { GLuint vao; bool32 is_init; @@ -12,7 +14,7 @@ struct { RV_INTERNAL GLenum rv_usage_to_gl(rv_buffer_usage_t usage) { GLenum mode = GL_STATIC_DRAW; switch (usage) { - default: + default: rv_unreachable(); case RV_BUFFER_USAGE_STATIC: mode = GL_STATIC_DRAW; break; case RV_BUFFER_USAGE_DYNAMIC: mode = GL_DYNAMIC_DRAW; break; case RV_BUFFER_USAGE_STREAM: mode = GL_STREAM_DRAW; break; @@ -23,7 +25,7 @@ RV_INTERNAL GLenum rv_usage_to_gl(rv_buffer_usage_t usage) { RV_INTERNAL GLenum rv_shader_to_gl(rv_shader_type_t type) { GLenum mode = 0; switch (type) { - default: + default: rv_unreachable(); case RV_SHADER_TYPE_VERTEX: mode = GL_VERTEX_SHADER; break; case RV_SHADER_TYPE_FRAGMENT: mode = GL_FRAGMENT_SHADER; break; } @@ -33,7 +35,7 @@ RV_INTERNAL GLenum rv_shader_to_gl(rv_shader_type_t type) { RV_INTERNAL GLenum rv_primitive_to_gl(rv_primitive_type_t type) { GLenum res = 0; switch (type) { - default: + default: rv_unreachable(); case RV_PRIMITIVE_TYPE_TRIANGLES: res = GL_TRIANGLES; break; } return res; @@ -60,9 +62,9 @@ RV_INTERNAL s64 rv_vattr_type_size(rv_vattr_type_t type) { RV_INTERNAL GLenum rv_tex_wrap_to_gl(rv_texture_wrap_t type) { - uint32_t wrap = GL_REPEAT; + GLenum wrap = GL_REPEAT; switch (type) { - default: + default: rv_unreachable(); case RV_TEXTURE_WRAP_REPEAT: wrap = GL_REPEAT; break; case RV_TEXTURE_WRAP_MIRRORED_REPEAT: wrap = GL_MIRRORED_REPEAT; break; case RV_TEXTURE_WRAP_CLAMP_TO_EDGE: wrap = GL_CLAMP_TO_EDGE; break; @@ -71,6 +73,12 @@ RV_INTERNAL GLenum rv_tex_wrap_to_gl(rv_texture_wrap_t type) { return wrap; } +struct { + rv_ibo_t* bound_ibo; + rv_vbo_t* bound_vbo; + rv_pipeline_t* bound_pip; +} ogl_state; + RV_GLOBAL void rv_window_render_commit(rv_window_handle_t* window, rv_render_pass_list_t* passes) { @@ -83,25 +91,21 @@ RV_GLOBAL void rv_window_render_commit(rv_window_handle_t* window, rv_render_pas glBindVertexArray(ogl_ctx.vao); } - struct { - rv_ibo_t* bound_ibo; - rv_vbo_t* bound_vbo; - } state = {0}; - for (rv_render_pass_t* p = passes->first; p; p = p->next) { - for (rv_render_command_t* c = p->commands.first; c; c = c->next) { + for (rv_command_t* c = p->commands.first; c; c = c->next) { switch (c->type) { - case RV_RENDER_COMMAND_INVALID: { + case RV_COMMAND_INVALID: { + rv_unreachable(); } break; - case RV_RENDER_COMMAND_CUSTOM: { + case RV_COMMAND_CUSTOM: { rv_assert(c->custom.func); if (c->custom.func) { c->custom.func(c->custom.data); } } break; - case RV_RENDER_COMMAND_CLEAR: { + case RV_COMMAND_CLEAR: { for (rv_render_clear_desc_t* clear = c->clear.first; clear; clear = clear->next) { if (clear->flags == RV_RENDER_CLEAR_FLAG_NONE) continue; @@ -117,74 +121,79 @@ RV_GLOBAL void rv_window_render_commit(rv_window_handle_t* window, rv_render_pas } } break; - case RV_RENDER_COMMAND_SET_VIEWPORT: { + case RV_COMMAND_SET_VIEWPORT: { glViewport(c->viewport.x, c->viewport.y, c->viewport.z, c->viewport.w); } break; - case RV_RENDER_COMMAND_OBJ_VERTEX: { + case RV_COMMAND_OBJ_VERTEX: { rv_vbo_t* vbo = c->obj.vbo; switch (c->obj.operation) { case RV_RENDER_OBJ_OP_CREATE: { glGenBuffers(1, &vbo->handle.u); glBindBuffer(GL_ARRAY_BUFFER, vbo->handle.u); glBufferData(GL_ARRAY_BUFFER, vbo->size, vbo->data, rv_usage_to_gl(vbo->usage)); - glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, ogl_safe_set(ogl_state.bound_vbo, handle)); } break; + case RV_RENDER_OBJ_OP_UPDATE: { glBindBuffer(GL_ARRAY_BUFFER, vbo->handle.u); glBufferData(GL_ARRAY_BUFFER, c->obj.vbo_update.size, c->obj.vbo_update.data, rv_usage_to_gl(vbo->usage)); - if (state.bound_vbo) { - glBindBuffer(GL_ARRAY_BUFFER, state.bound_vbo->handle.u); - } + + glBindBuffer(GL_ARRAY_BUFFER, ogl_safe_set(ogl_state.bound_vbo, handle)); } break; + case RV_RENDER_OBJ_OP_BIND: { - if (vbo) { - glBindBuffer(GL_ARRAY_BUFFER, vbo->handle.u); - } else { - glBindBuffer(GL_ARRAY_BUFFER, vbo->handle.u); - } - state.bound_vbo = vbo; + ogl_state.bound_vbo = vbo; + glBindBuffer(GL_ARRAY_BUFFER, ogl_safe_set(ogl_state.bound_vbo, handle)); } break; + case RV_RENDER_OBJ_OP_DELETE: { glDeleteBuffers(1, &vbo->handle.u); vbo->handle.u = 0; + if (ogl_state.bound_vbo == vbo) { + ogl_state.bound_vbo = NULL; + glBindBuffer(GL_ARRAY_BUFFER, 0); + } } break; } } break; - case RV_RENDER_COMMAND_OBJ_INDEX: { + case RV_COMMAND_OBJ_INDEX: { rv_ibo_t* ibo = c->obj.ibo; switch (c->obj.operation) { case RV_RENDER_OBJ_OP_CREATE: { glGenBuffers(1, &ibo->handle.u); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo->handle.u); glBufferData(GL_ELEMENT_ARRAY_BUFFER, ibo->size, ibo->data, rv_usage_to_gl(ibo->usage)); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ogl_safe_set(ogl_state.bound_ibo, handle)); } break; + case RV_RENDER_OBJ_OP_UPDATE: { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo->handle.u); glBufferData(GL_ELEMENT_ARRAY_BUFFER, c->obj.ibo_update.size, c->obj.ibo_update.data, rv_usage_to_gl(ibo->usage)); - if (state.bound_ibo) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, state.bound_ibo->handle.u); - } + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ogl_safe_set(ogl_state.bound_ibo, handle)); } break; + case RV_RENDER_OBJ_OP_BIND: { - if (ibo) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo->handle.u); - } else { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - state.bound_ibo = ibo; + ogl_state.bound_ibo = ibo; + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ogl_safe_set(ogl_state.bound_ibo, handle)); } break; + case RV_RENDER_OBJ_OP_DELETE: { glDeleteBuffers(1, &ibo->handle.u); ibo->handle.u = 0; + if (ogl_state.bound_ibo == ibo) { + ogl_state.bound_ibo = NULL; + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } } break; } } break; - case RV_RENDER_COMMAND_OBJ_SHADER: { + case RV_COMMAND_OBJ_SHADER: { rv_shader_t* shader = c->obj.shader; switch (c->obj.operation) { case RV_RENDER_OBJ_OP_CREATE: { @@ -208,12 +217,15 @@ RV_GLOBAL void rv_window_render_commit(rv_window_handle_t* window, rv_render_pas } } } break; + case RV_RENDER_OBJ_OP_UPDATE: { - rv_assert(false); + rv_unreachable(); } break; + case RV_RENDER_OBJ_OP_BIND: { - rv_assert(false); + rv_unreachable(); } break; + case RV_RENDER_OBJ_OP_DELETE: { glDeleteShader(shader->handle.u); shader->handle.u = 0; @@ -221,118 +233,130 @@ RV_GLOBAL void rv_window_render_commit(rv_window_handle_t* window, rv_render_pas } } break; - case RV_RENDER_COMMAND_OBJ_PROGRAM: { - rv_program_t* program = c->obj.program; + case RV_COMMAND_OBJ_PIPELINE: { + rv_pipeline_t* pipeline = c->obj.pipeline; switch (c->obj.operation) { case RV_RENDER_OBJ_OP_CREATE: { - program->handle.u = glCreateProgram(); - for (rv_shader_node_t* s = program->shader_first; s; s = s->next) { - glAttachShader(program->handle.u, s->shader->handle.u); + pipeline->handle.u = glCreateProgram(); + for (rv_shader_node_t* s = pipeline->shader_first; s; s = s->next) { + glAttachShader(pipeline->handle.u, s->shader->handle.u); } - glLinkProgram(program->handle.u); + glLinkProgram(pipeline->handle.u); { int program_link_success; - glGetProgramiv(program->handle.u, GL_LINK_STATUS, &program_link_success); + glGetProgramiv(pipeline->handle.u, GL_LINK_STATUS, &program_link_success); if (!program_link_success) { char info_log[512]; - glGetProgramInfoLog(program->handle.u, 512, NULL, info_log); + glGetProgramInfoLog(pipeline->handle.u, 512, NULL, info_log); fprintf(stderr, "-------------ERROR------------\n" - "::OpenGL Failed to link program::\n%s\n", info_log); + "::OpenGL Failed to link shader program::\n%s\n", info_log); rv_assert(program_link_success); } } // find uniform locations - for (rv_uniform_t* u = program->uniform_desc_first; u; u = u->next) { - u->program_uniform_handle.u = glGetUniformLocation(program->handle.u, (const char*)u->name_null_terminated.str); + for (rv_uniform_t* u = pipeline->uniform_desc_first; u; u = u->next) { + u->pipeline_uniform_handle.u = glGetUniformLocation(pipeline->handle.u, (const char*)u->name_null_terminated.str); } - } break; - case RV_RENDER_OBJ_OP_UPDATE: { - rv_assert(false); - } break; - case RV_RENDER_OBJ_OP_BIND: { - rv_uniform_update_node_t* committed_uniforms = c->obj.program_bind.committed_uniforms; - glUseProgram(program->handle.u); - s32 sampler_channel; - // update last type - for (rv_uniform_update_node_t* u = committed_uniforms; u; u = u->next) { - u->desc->last_val = u->value; - } + glUseProgram(pipeline->handle.u); - // activate textures and sample2d, if any - sampler_channel = 0; - for (rv_uniform_t* u = program->uniform_desc_first; u; u = u->next) { + // set up sampler channels + s32 sampler_channel = 0; + for (rv_uniform_t* u = pipeline->uniform_desc_first; u; u = u->next) { if (u->type == RV_UNIFORM_TEX) { - glActiveTexture(GL_TEXTURE0 + sampler_channel); - glBindTexture(GL_TEXTURE_2D, u->last_val.v_tex->handle.u); - if (!u->has_been_set) { - glUniform1i(u->program_uniform_handle.u, sampler_channel); - u->has_been_set = true; - } - u->last_val.v_tex->last_sampler_channel = sampler_channel; + glUniform1i(u->pipeline_uniform_handle.u, sampler_channel); sampler_channel++; } } + // turn back to previous state + glUseProgram(ogl_safe_set(ogl_state.bound_pip, handle)); + } break; - for (rv_uniform_update_node_t* u = committed_uniforms; u; u = u->next) { - switch (u->desc->type) { - case RV_UNIFORM_F32: glUniform1fv(u->desc->program_uniform_handle.u, 1, &u->value.v_f32); break; - case RV_UNIFORM_VEC2: glUniform2fv(u->desc->program_uniform_handle.u, 1, u->value.v_vec2.xy); break; - case RV_UNIFORM_VEC3: glUniform3fv(u->desc->program_uniform_handle.u, 1, u->value.v_vec3.xyz); break; - case RV_UNIFORM_VEC4: glUniform4fv(u->desc->program_uniform_handle.u, 1, u->value.v_vec4.xyzw); break; - case RV_UNIFORM_MAT4: glUniformMatrix4fv(u->desc->program_uniform_handle.u, 1, GL_FALSE, u->value.v_mat4.elements); break; - case RV_UNIFORM_TEX: break; // handled above - case RV_UNIFORM_INVALID: break; - } - u->desc->has_been_set = true; - } + case RV_RENDER_OBJ_OP_UPDATE: { + rv_unreachable(); + } break; - s64 stride = 0; - for (rv_vattr_t* v = program->vattr_first; v; v = v->next) { - stride += rv_vattr_type_size(v->type); - } - s64 offset = 0; - s64 i = 0; - for (rv_vattr_t* v = program->vattr_first; v; v = v->next, i++) { - glEnableVertexAttribArray(i); - switch (v->type) { - case RV_VATTR_TYPE_FLOAT4: glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, stride, (void*)offset); break; - case RV_VATTR_TYPE_FLOAT3: glVertexAttribPointer(i, 3, GL_FLOAT, GL_FALSE, stride, (void*)offset); break; - case RV_VATTR_TYPE_FLOAT2: glVertexAttribPointer(i, 2, GL_FLOAT, GL_FALSE, stride, (void*)offset); break; - case RV_VATTR_TYPE_FLOAT: glVertexAttribPointer(i, 1, GL_FLOAT, GL_FALSE, stride, (void*)offset); break; - case RV_VATTR_TYPE_UINT4: glVertexAttribIPointer(i, 4, GL_UNSIGNED_INT, stride, (void*)offset); break; - case RV_VATTR_TYPE_UINT3: glVertexAttribIPointer(i, 3, GL_UNSIGNED_INT, stride, (void*)offset); break; - case RV_VATTR_TYPE_UINT2: glVertexAttribIPointer(i, 2, GL_UNSIGNED_INT, stride, (void*)offset); break; - case RV_VATTR_TYPE_UINT: glVertexAttribIPointer(i, 1, GL_UNSIGNED_INT, stride, (void*)offset); break; - case RV_VATTR_TYPE_BYTE: glVertexAttribPointer(i, 1, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void*)offset); break; - case RV_VATTR_TYPE_BYTE2: glVertexAttribPointer(i, 2, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void*)offset); break; - case RV_VATTR_TYPE_BYTE3: glVertexAttribPointer(i, 3, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void*)offset); break; - case RV_VATTR_TYPE_BYTE4: glVertexAttribPointer(i, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void*)offset); break; - default: rv_assert(false); break; + case RV_RENDER_OBJ_OP_BIND: { + ogl_state.bound_pip = pipeline; + if (pipeline) { + glUseProgram(pipeline->handle.u); + + // activate textures and sample2d, if any + s32 sampler_channel = 0; + for (rv_uniform_t* u = pipeline->uniform_desc_first; u; u = u->next) { + if (u->type == RV_UNIFORM_TEX) { + bool32 has_queued_update = false; + { + for (rv_command_t* c_future = c->next; c_future; c_future = c_future->next) { + if (c_future->type == RV_COMMAND_DRAW || c_future->type == RV_COMMAND_OBJ_PIPELINE) { + // reached end... + break; + } + if (c_future->type == RV_COMMAND_UNIFORM_UPDATE) { + if (c_future->uniform_update.desc == u) { + // found something that updates this uniform + has_queued_update = true; + break; + } + } + } + } + if (!has_queued_update) { + if (u->last_val.v_tex) { + glActiveTexture(GL_TEXTURE0 + sampler_channel); + glBindTexture(GL_TEXTURE_2D, u->last_val.v_tex->handle.u); + } else { + // Texture was null, cannot bind + // TODO(Samdal): bind default texture? + rv_unreachable(); + } + } + sampler_channel++; + } } - - offset += rv_vattr_type_size(v->type); + } else { + glUseProgram(0); } } break; + case RV_RENDER_OBJ_OP_DELETE: { - glDeleteProgram(program->handle.u); - program->handle.u = 0; - for (rv_uniform_t* u = program->uniform_desc_first; u; u = u->next) { - u->program_uniform_handle.u = 0; + glDeleteProgram(pipeline->handle.u); + pipeline->handle.u = 0; + for (rv_uniform_t* u = pipeline->uniform_desc_first; u; u = u->next) { + u->pipeline_uniform_handle.u = 0; + } + if (ogl_state.bound_pip == pipeline) { + ogl_state.bound_pip = NULL; + glUseProgram(0); } } break; } } break; - case RV_RENDER_COMMAND_OBJ_TEXTURE: { + case RV_COMMAND_OBJ_TEXTURE: { rv_texture_t* tex = c->obj.tex; switch (c->obj.operation) { case RV_RENDER_OBJ_OP_CREATE: { glGenTextures(1, &tex->handle.u); - glActiveTexture(GL_TEXTURE0 + tex->last_sampler_channel); + + s32 sampler_channel = 0; + if (ogl_state.bound_pip) { + // need to update the existing bound sampler + // ... or make sure we don't override a bound one + for (rv_uniform_t* u = ogl_state.bound_pip->uniform_desc_first; u; u = u->next) { + if (u->type == RV_UNIFORM_TEX) { + if (u->last_val.v_tex == tex) { + // found our texture + break; + } + sampler_channel++; + } + } + } + glActiveTexture(GL_TEXTURE0 + sampler_channel); glBindTexture(GL_TEXTURE_2D, tex->handle.u); switch(tex->format) @@ -349,11 +373,11 @@ RV_GLOBAL void rv_window_render_commit(rv_window_handle_t* window, rv_render_pas case RV_TEXTURE_FORMAT_DEPTH32F: glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, tex->size.x, tex->size.y, 0, GL_DEPTH_COMPONENT, GL_FLOAT, tex->data); break; case RV_TEXTURE_FORMAT_DEPTH24_STENCIL8: glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, tex->size.x, tex->size.y, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, tex->data); break; case RV_TEXTURE_FORMAT_DEPTH32F_STENCIL8: glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH32F_STENCIL8, tex->size.x, tex->size.y, 0, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, tex->data); break; - default: break; + default: rv_unreachable(); break; } - int32_t mag_filter = tex->mag_filter == RV_TEXTURE_FILTER_NEAREST ? GL_NEAREST : GL_LINEAR; - int32_t min_filter = tex->min_filter == RV_TEXTURE_FILTER_NEAREST ? GL_NEAREST : GL_LINEAR; + GLenum mag_filter = tex->mag_filter == RV_TEXTURE_FILTER_NEAREST ? GL_NEAREST : GL_LINEAR; + GLenum min_filter = tex->min_filter == RV_TEXTURE_FILTER_NEAREST ? GL_NEAREST : GL_LINEAR; if (tex->num_mips) { if (tex->min_filter == RV_TEXTURE_FILTER_NEAREST) { @@ -366,8 +390,8 @@ RV_GLOBAL void rv_window_render_commit(rv_window_handle_t* window, rv_render_pas } } - uint32_t texture_wrap_s = rv_tex_wrap_to_gl(tex->wrap_s); - uint32_t texture_wrap_t = rv_tex_wrap_to_gl(tex->wrap_t); + GLenum texture_wrap_s = rv_tex_wrap_to_gl(tex->wrap_s); + GLenum texture_wrap_t = rv_tex_wrap_to_gl(tex->wrap_t); if (tex->num_mips) { glGenerateMipmap(GL_TEXTURE_2D); @@ -378,11 +402,25 @@ RV_GLOBAL void rv_window_render_commit(rv_window_handle_t* window, rv_render_pas glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter); - glBindTexture(GL_TEXTURE_2D, 0); - } break; + case RV_RENDER_OBJ_OP_UPDATE: { - glActiveTexture(GL_TEXTURE0 + tex->last_sampler_channel); + + s32 sampler_channel = 0; + if (ogl_state.bound_pip) { + // need to update the existing bound sampler + // ... or make sure we don't override a bound one + for (rv_uniform_t* u = ogl_state.bound_pip->uniform_desc_first; u; u = u->next) { + if (u->type == RV_UNIFORM_TEX) { + if (u ->last_val.v_tex == tex) { + // found our texture + break; + } + sampler_channel++; + } + } + } + glActiveTexture(GL_TEXTURE0 + sampler_channel); glBindTexture(GL_TEXTURE_2D, tex->handle.u); switch(tex->format) @@ -399,15 +437,14 @@ RV_GLOBAL void rv_window_render_commit(rv_window_handle_t* window, rv_render_pas case RV_TEXTURE_FORMAT_DEPTH32F: glTexSubImage2D(GL_TEXTURE_2D, 0, c->obj.tex_update.sub_part.x, c->obj.tex_update.sub_part.y, c->obj.tex_update.sub_part.w, c->obj.tex_update.sub_part.h, GL_DEPTH_COMPONENT, GL_FLOAT, c->obj.tex_update.data); break; case RV_TEXTURE_FORMAT_DEPTH24_STENCIL8: glTexSubImage2D(GL_TEXTURE_2D, 0, c->obj.tex_update.sub_part.x, c->obj.tex_update.sub_part.y, c->obj.tex_update.sub_part.w, c->obj.tex_update.sub_part.h, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, c->obj.tex_update.data); break; case RV_TEXTURE_FORMAT_DEPTH32F_STENCIL8: glTexSubImage2D(GL_TEXTURE_2D, 0, c->obj.tex_update.sub_part.x, c->obj.tex_update.sub_part.y, c->obj.tex_update.sub_part.w, c->obj.tex_update.sub_part.h, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, c->obj.tex_update.data); break; - default: break; + default: rv_unreachable(); break; } } break; + case RV_RENDER_OBJ_OP_BIND: { - // uniforms bind textures automatically - // so you don't have to do this every time - glActiveTexture(GL_TEXTURE0 + c->obj.tex_bind.sampler_index); - glBindTexture(GL_TEXTURE_2D, tex->handle.u); + rv_unreachable(); // textures are bound automatically by uniforms } break; + case RV_RENDER_OBJ_OP_DELETE: { glDeleteTextures(1, &tex->handle.u); tex->handle.u = 0; @@ -415,21 +452,88 @@ RV_GLOBAL void rv_window_render_commit(rv_window_handle_t* window, rv_render_pas } } break; - case RV_RENDER_COMMAND_DRAW: { - GLenum prim = rv_primitive_to_gl(c->draw.primitive); - // TODO(Samdal): instancing... - if (state.bound_ibo) { - - GLenum itype = GL_UNSIGNED_INT; - switch (state.bound_ibo->elem_size) { - default: - case 4: itype = GL_UNSIGNED_INT; break; - case 2: itype = GL_UNSIGNED_SHORT; break; - case 1: itype = GL_UNSIGNED_BYTE; break; + case RV_COMMAND_UNIFORM_UPDATE: { + if (ogl_state.bound_pip) { + rv_uniform_t* desc = c->uniform_update.desc; + rv_uniform_variant_t* val = &c->uniform_update.value; + if (desc) { + desc->last_val = *val; + + switch (desc->type) { + case RV_UNIFORM_F32: glUniform1fv(desc->pipeline_uniform_handle.u, 1, &val->v_f32); break; + case RV_UNIFORM_VEC2: glUniform2fv(desc->pipeline_uniform_handle.u, 1, val->v_vec2.xy); break; + case RV_UNIFORM_VEC3: glUniform3fv(desc->pipeline_uniform_handle.u, 1, val->v_vec3.xyz); break; + case RV_UNIFORM_VEC4: glUniform4fv(desc->pipeline_uniform_handle.u, 1, val->v_vec4.xyzw); break; + case RV_UNIFORM_MAT4: glUniformMatrix4fv(desc->pipeline_uniform_handle.u, 1, GL_FALSE, val->v_mat4.elements); break; + case RV_UNIFORM_TEX: { + s32 sampler_channel = 0; + for (rv_uniform_t* u = ogl_state.bound_pip->uniform_desc_first; u; u = u->next) { + if (u->type == RV_UNIFORM_TEX) { + if (u == desc) { + // found our uniform + glActiveTexture(GL_TEXTURE0 + sampler_channel); + glBindTexture(GL_TEXTURE_2D, u->last_val.v_tex->handle.u); + break; + } + sampler_channel++; + } + } + + } break; + case RV_UNIFORM_INVALID: rv_unreachable(); break; + } + } else { + rv_unreachable(); + } + } else { + rv_unreachable(); + } + } break; + + case RV_COMMAND_DRAW: { + if (ogl_state.bound_pip) { + s64 stride = 0; + for (rv_vattr_t* v = ogl_state.bound_pip->vattr_first; v; v = v->next) { + stride += rv_vattr_type_size(v->type); + } + s64 offset = 0; + s64 i = 0; + for (rv_vattr_t* v = ogl_state.bound_pip->vattr_first; v; v = v->next, i++) { + glEnableVertexAttribArray(i); + switch (v->type) { + case RV_VATTR_TYPE_FLOAT4: glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, stride, (void*)offset); break; + case RV_VATTR_TYPE_FLOAT3: glVertexAttribPointer(i, 3, GL_FLOAT, GL_FALSE, stride, (void*)offset); break; + case RV_VATTR_TYPE_FLOAT2: glVertexAttribPointer(i, 2, GL_FLOAT, GL_FALSE, stride, (void*)offset); break; + case RV_VATTR_TYPE_FLOAT: glVertexAttribPointer(i, 1, GL_FLOAT, GL_FALSE, stride, (void*)offset); break; + case RV_VATTR_TYPE_UINT4: glVertexAttribIPointer(i, 4, GL_UNSIGNED_INT, stride, (void*)offset); break; + case RV_VATTR_TYPE_UINT3: glVertexAttribIPointer(i, 3, GL_UNSIGNED_INT, stride, (void*)offset); break; + case RV_VATTR_TYPE_UINT2: glVertexAttribIPointer(i, 2, GL_UNSIGNED_INT, stride, (void*)offset); break; + case RV_VATTR_TYPE_UINT: glVertexAttribIPointer(i, 1, GL_UNSIGNED_INT, stride, (void*)offset); break; + case RV_VATTR_TYPE_BYTE: glVertexAttribPointer(i, 1, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void*)offset); break; + case RV_VATTR_TYPE_BYTE2: glVertexAttribPointer(i, 2, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void*)offset); break; + case RV_VATTR_TYPE_BYTE3: glVertexAttribPointer(i, 3, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void*)offset); break; + case RV_VATTR_TYPE_BYTE4: glVertexAttribPointer(i, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void*)offset); break; + default: rv_unreachable(); break; + } + offset += rv_vattr_type_size(v->type); + } + GLenum prim = rv_primitive_to_gl(c->draw.primitive); + // TODO(Samdal): instancing... + if (ogl_state.bound_ibo) { + + GLenum itype = GL_UNSIGNED_INT; + switch (ogl_state.bound_ibo->elem_size) { + default: rv_unreachable(); + case 4: itype = GL_UNSIGNED_INT; break; + case 2: itype = GL_UNSIGNED_SHORT; break; + case 1: itype = GL_UNSIGNED_BYTE; break; + } + glDrawElements(prim, c->draw.count, itype, (void*)(s64)c->draw.first); + } else { + glDrawArrays(prim, c->draw.first, c->draw.count); } - glDrawElements(prim, c->draw.count, itype, (void*)(s64)c->draw.first); } else { - glDrawArrays(prim, c->draw.first, c->draw.count); + rv_unreachable(); } } break; diff --git a/src/render/render.h b/src/render/render.h @@ -45,8 +45,6 @@ typedef struct { void* data; rv_render_handle_t handle; - - s32 last_sampler_channel; } rv_texture_t; typedef struct { @@ -73,25 +71,17 @@ typedef union { typedef struct rv_uniform_t rv_uniform_t; struct rv_uniform_t { - // NOTE(Samdal): uniforms are specific to their corresponding program + // NOTE(Samdal): uniforms are specific to their corresponding pipeline rv_uniform_t* next; // create info - // uniforms are created when it's program is created + // uniforms are created when it's pipeline is created rv_str8 name_null_terminated; // MUST be null terminated rv_uniform_type_t type; - rv_render_handle_t program_uniform_handle; + rv_render_handle_t pipeline_uniform_handle; rv_uniform_variant_t last_val; - bool32 has_been_set; -}; - -typedef struct rv_uniform_update_node_t rv_uniform_update_node_t; -struct rv_uniform_update_node_t { - rv_uniform_update_node_t* next; - rv_uniform_variant_t value; - rv_uniform_t* desc; }; typedef enum { @@ -102,7 +92,6 @@ typedef enum { typedef struct rv_vbo_t rv_vbo_t; struct rv_vbo_t { - rv_vbo_t* next; void* data; s32 size; rv_buffer_usage_t usage; @@ -111,7 +100,6 @@ struct rv_vbo_t { typedef struct rv_ibo_t rv_ibo_t; struct rv_ibo_t { - rv_ibo_t* next; void* data; s32 size; s32 elem_size; @@ -165,7 +153,7 @@ typedef struct { rv_vattr_t* vattr_first; rv_vattr_t* vattr_last; rv_render_handle_t handle; -} rv_program_t; +} rv_pipeline_t; typedef enum { RV_PRIMITIVE_TYPE_TRIANGLES, @@ -200,30 +188,33 @@ typedef enum { RV_RENDER_OBJ_OP_UPDATE, RV_RENDER_OBJ_OP_BIND, RV_RENDER_OBJ_OP_DELETE, -} rv_render_command_obj_operation_t; +} rv_command_obj_operation_t; typedef enum { - RV_RENDER_COMMAND_INVALID, + RV_COMMAND_INVALID, + + RV_COMMAND_CUSTOM, - RV_RENDER_COMMAND_CUSTOM, + RV_COMMAND_OBJ_VERTEX, + RV_COMMAND_OBJ_INDEX, + RV_COMMAND_OBJ_SHADER, + RV_COMMAND_OBJ_PIPELINE, + RV_COMMAND_OBJ_TEXTURE, - RV_RENDER_COMMAND_OBJ_VERTEX, - RV_RENDER_COMMAND_OBJ_INDEX, - RV_RENDER_COMMAND_OBJ_SHADER, - RV_RENDER_COMMAND_OBJ_PROGRAM, - RV_RENDER_COMMAND_OBJ_TEXTURE, + RV_COMMAND_UNIFORM_UPDATE, // only allowed during pipeline bind - RV_RENDER_COMMAND_DRAW, + RV_COMMAND_DRAW, // only allowed during pipeline bind - RV_RENDER_COMMAND_CLEAR, - RV_RENDER_COMMAND_SET_VIEWPORT, -} rv_render_command_type_t; + RV_COMMAND_CLEAR, + RV_COMMAND_SET_VIEWPORT, +} rv_command_type_t; -typedef struct rv_render_command_t rv_render_command_t; -struct rv_render_command_t { - rv_render_command_t* next; +typedef struct rv_command_t rv_command_t; +struct rv_command_t { + rv_command_t* next; + rv_command_t* prev; - rv_render_command_type_t type; + rv_command_type_t type; union { struct { @@ -236,14 +227,10 @@ struct rv_render_command_t { void* data; } custom; struct { - rv_render_command_obj_operation_t operation; + rv_command_obj_operation_t operation; // parameters union { - struct { - rv_uniform_update_node_t* committed_uniforms; - } program_bind; - // TODO(Samdal): make these named structs and // add ability to switch between different // update methods @@ -264,7 +251,7 @@ struct rv_render_command_t { // desc reference union { - rv_program_t* program; + rv_pipeline_t* pipeline; rv_shader_t* shader; rv_vbo_t* vbo; rv_ibo_t* ibo; @@ -277,18 +264,23 @@ struct rv_render_command_t { s32 first; s64 count; } draw; + + struct { + rv_uniform_t* desc; + rv_uniform_variant_t value; + } uniform_update; }; }; typedef struct { - rv_render_command_t* first; - rv_render_command_t* last; -} rv_render_command_list_t; + rv_command_t* first; + rv_command_t* last; +} rv_command_list_t; typedef struct rv_render_pass_t rv_render_pass_t; struct rv_render_pass_t { rv_render_pass_t* next; - rv_render_command_list_t commands; + rv_command_list_t commands; rv_render_framebuffer_t* framebuffer; }; @@ -301,25 +293,42 @@ typedef struct { ////////////////////////////////////////////////////////////////// // Helpers -// core command buffer helpers -RV_GLOBAL rv_render_pass_t* rv_render_push_render_pass(rv_arena* arena, rv_render_pass_list_t* rpass_list); -RV_GLOBAL rv_render_command_t* rv_render_push_command(rv_arena* arena, rv_render_command_list_t* commands, rv_render_command_type_t type); -RV_GLOBAL rv_render_command_t* rv_render_push_command_copy(rv_arena* arena, rv_render_command_list_t* commands, rv_render_command_t* source); -RV_GLOBAL rv_render_command_t* rv_render_push_obj_command(rv_arena* arena, rv_render_command_list_t* commands, rv_render_command_type_t type, rv_render_command_obj_operation_t operation, void* obj); -#define rv_render_push_command_compound(arnea, commands, _type, ...) rv_render_push_command_copy(arena, commands, &(rv_render_command_t){.type = _type, __VA_ARGS__}) -RV_GLOBAL rv_render_command_t* rv_render_copy_commands(rv_arena* arena, rv_render_command_list_t* dest, rv_render_command_list_t* source); // reurns the first command addded +// render pass +RV_GLOBAL rv_render_pass_t* rv_render_push_render_pass(rv_arena* arena, rv_render_pass_list_t* rpass_list); + +// command list +RV_GLOBAL rv_command_t* rv_cmd_copy(rv_command_t* dest, rv_command_t source); // returns dest, does not modify next/prev +RV_GLOBAL rv_command_t* rv_cmd_push(rv_arena* arena, rv_command_list_t* commands); +RV_GLOBAL rv_command_t* rv_cmd_insert(rv_arena* arena, rv_command_list_t* commands, rv_command_t* after); +RV_GLOBAL rv_command_t* rv_render_copy_commands(rv_arena* arena, rv_command_list_t* dest, rv_command_list_t* source); // reurns the first command addded + + +// ctors +#define rv_cmd(_type, ...) (rv_command_t){.type = _type, __VA_ARGS__} +RV_GLOBAL rv_command_t rv_cmd_type(rv_command_type_t type); +RV_GLOBAL rv_command_t rv_cmd_obj(rv_command_type_t type, rv_command_obj_operation_t operation, void* obj); +RV_GLOBAL rv_command_t rv_cmd_uniform_update(rv_uniform_t* uniform, rv_uniform_variant_t value); + +#define rv_cmd_push_type(arena, commands, _type) rv_cmd_copy(rv_cmd_push(arena, commands), rv_cmd_type(_type)) +#define rv_cmd_insert_type(arena, commands, after, _type) rv_cmd_copy(rv_cmd_insert(arena, commands, after), rv_cmd_type(_type)) + +#define rv_cmd_push_compound(arena, commands, _type, ...) rv_cmd_copy(rv_cmd_push(arena, commands), rv_cmd(_type, __VA_ARGS__)) +#define rv_cmd_insert_compound(arena, commands, after, _type, ...) rv_cmd_copy(rv_cmd_insert(arena, commands, after), rv_cmd(_type, __VA_ARGS__)) + +#define rv_cmd_push_obj(arena, commands, _type, op, obj) rv_cmd_copy(rv_cmd_push(arena, commands), rv_cmd_obj(_type, op, obj)) +#define rv_cmd_insert_obj(arena, commands, after, _type, op, obj) rv_cmd_copy(rv_cmd_insert(arena, commands, after), rv_cmd_obj(_type, op, obj)) + +#define rv_cmd_push_uniform_update(arena, commands, uniform, ...) rv_cmd_copy(rv_cmd_push(arena, commands), rv_cmd_uniform_update(uniform, (rv_uniform_variant_t)__VA_ARGS__)) +#define rv_cmd_insert_uniform_update(arena, commands, after, uniform, ...) rv_cmd_copy(rv_cmd_insert(arena, commands, after), rv_cmd_uniform_update(uniform, (rv_uniform_variant_t)__VA_ARGS__)) // command modification helpers -RV_GLOBAL rv_render_clear_desc_t* rv_render_push_clear_desc(rv_arena* arena, rv_render_command_t* clear, rv_graphics_clear_flag_t flags); -RV_GLOBAL rv_uniform_update_node_t* rv_render_update_uniform(rv_arena* arena, rv_render_command_t* program, rv_uniform_t* uniform, rv_uniform_variant_t value); -#define rv_render_update_uniform_compound(arena, prog, uniform, ...) rv_render_update_uniform(arena, prog, uniform, (rv_uniform_variant_t)__VA_ARGS__); -RV_GLOBAL bool32 rv_render_command_has_program(rv_render_command_t* command, rv_program_t* prog); - -// shader modificatoin helpers -RV_GLOBAL rv_shader_node_t* rv_render_push_shader_to_prog(rv_arena* arena, rv_program_t* prog, rv_shader_t* shader); -RV_GLOBAL rv_uniform_t* rv_render_push_uniform_to_prog(rv_arena* arena, rv_program_t* prog, rv_str8 name, rv_uniform_type_t type); -RV_GLOBAL rv_uniform_t* rv_render_push_uniform_to_prog_texture(rv_arena* arena, rv_program_t* prog, rv_str8 name, rv_texture_t* tex); -RV_GLOBAL rv_vattr_t* rv_render_push_vattr_to_prog(rv_arena* arena, rv_program_t* prog, rv_vattr_type_t type); +RV_GLOBAL rv_render_clear_desc_t* rv_render_push_clear_desc(rv_arena* arena, rv_command_t* clear, rv_graphics_clear_flag_t flags); +RV_GLOBAL bool32 rv_command_has_pipeline(rv_command_t* command, rv_pipeline_t* prog); + +// pipeline modificatoin helpers +RV_GLOBAL rv_shader_node_t* rv_pipeline_push_shader(rv_arena* arena, rv_pipeline_t* pipeline, rv_shader_t* shader); +RV_GLOBAL rv_uniform_t* rv_pipeline_push_uniform(rv_arena* arena, rv_pipeline_t* pipeline, rv_str8 name, rv_uniform_type_t type); +RV_GLOBAL rv_vattr_t* rv_pipeline_push_vattr(rv_arena* arena, rv_pipeline_t* pipeline, rv_vattr_type_t type); ////////////////////////////////////////////////////////////////// // Submit diff --git a/src/render/render_helpers.c b/src/render/render_helpers.c @@ -1,7 +1,6 @@ ////////////////////////////////////////////////////////////////// // render_helpers.c - RV_GLOBAL rv_render_pass_t* rv_render_push_render_pass(rv_arena* arena, rv_render_pass_list_t* rpass_list) { rv_render_pass_t* res = rv_push(arena, rv_render_pass_t); @@ -9,87 +8,97 @@ RV_GLOBAL rv_render_pass_t* rv_render_push_render_pass(rv_arena* arena, rv_rende return res; } -RV_GLOBAL rv_render_command_t* rv_render_push_command(rv_arena* arena, rv_render_command_list_t* commands, rv_render_command_type_t type) -{ - rv_render_command_t* res = rv_push_compound(arena, rv_render_command_t, {.type = type}); - rv_llist_queue_push(commands->first, commands->last, res); - return res; +RV_GLOBAL rv_command_t* rv_cmd_copy(rv_command_t* dest, rv_command_t source) { + rv_command_t* next = dest->next; + rv_command_t* prev = dest->prev; + + *dest = source; + + dest->next = next; + dest->prev = prev; + + return dest; } -RV_GLOBAL rv_render_command_t* rv_render_push_command_copy(rv_arena* arena, rv_render_command_list_t* commands, rv_render_command_t* source) +RV_GLOBAL rv_command_t* rv_cmd_push(rv_arena* arena, rv_command_list_t* commands) { - rv_render_command_t* res = rv_push(arena, rv_render_command_t); - *res = *source; - rv_llist_queue_push(commands->first, commands->last, res); + rv_command_t* res = rv_push(arena, rv_command_t); + rv_dll_push_back(commands->first, commands->last, res); return res; } -RV_GLOBAL rv_render_command_t* rv_render_push_obj_command(rv_arena* arena, rv_render_command_list_t* commands, rv_render_command_type_t type, rv_render_command_obj_operation_t operation, void* obj) +RV_GLOBAL rv_command_t* rv_cmd_insert(rv_arena* arena, rv_command_list_t* commands, rv_command_t* after) { - rv_assert(type >= RV_RENDER_COMMAND_OBJ_VERTEX && type <= RV_RENDER_COMMAND_OBJ_TEXTURE); - - rv_render_command_t* res = rv_render_push_command(arena, commands, type); - res->obj.operation = operation; - res->obj.generic = obj; - + rv_command_t* res = rv_push(arena, rv_command_t); + rv_dll_insert(commands->first, commands->last, after, res); return res; } -RV_GLOBAL rv_render_command_t* rv_render_copy_commands(rv_arena* arena, rv_render_command_list_t* dest, rv_render_command_list_t* source) +RV_GLOBAL rv_command_t* rv_render_copy_commands(rv_arena* arena, rv_command_list_t* dest, rv_command_list_t* source) { - rv_render_command_t* res = NULL; - for (rv_render_command_t* c = source->first; c; c = c->next) { - if (!res) res = rv_render_push_command_copy(arena, dest, c); - else rv_render_push_command_copy(arena, dest, c); + rv_command_t* res = NULL; + for (rv_command_t* c = source->first; c; c = c->next) { + if (!res) res = rv_cmd_copy(rv_cmd_push(arena, dest), *c); + else rv_cmd_copy(rv_cmd_push(arena, dest), *c); } return res; } -RV_GLOBAL rv_render_clear_desc_t* rv_render_push_clear_desc(rv_arena* arena, rv_render_command_t* clear, rv_graphics_clear_flag_t flags) +RV_GLOBAL rv_command_t rv_cmd_type(rv_command_type_t type) { - rv_assert(clear->type == RV_RENDER_COMMAND_CLEAR); - rv_render_clear_desc_t* res = rv_push_compound(arena, rv_render_clear_desc_t, {.flags = flags}); - rv_llist_queue_push(clear->clear.first, clear->clear.last, res); - return res; + return (rv_command_t){.type = type}; } -RV_GLOBAL rv_uniform_update_node_t* rv_render_update_uniform(rv_arena* arena, rv_render_command_t* program, rv_uniform_t* uniform, rv_uniform_variant_t value) +RV_GLOBAL rv_command_t rv_cmd_obj(rv_command_type_t type, rv_command_obj_operation_t operation, void* obj) { - rv_assert(program->type == RV_RENDER_COMMAND_OBJ_PROGRAM); - rv_uniform_update_node_t* res = rv_push_compound(arena, rv_uniform_update_node_t, {.desc = uniform, .value = value}); - rv_llist_stack_push(program->obj.program_bind.committed_uniforms, res); - return res; + rv_assert(type >= RV_COMMAND_OBJ_VERTEX && type <= RV_COMMAND_OBJ_TEXTURE); + + return (rv_command_t) { + .type = type, + .obj.operation = operation, + .obj.generic = obj, + }; } -RV_GLOBAL bool32 rv_render_command_has_program(rv_render_command_t* command, rv_program_t* prog) +RV_GLOBAL rv_command_t rv_cmd_uniform_update(rv_uniform_t* uniform, rv_uniform_variant_t value) { - return command->type == RV_RENDER_COMMAND_OBJ_PROGRAM && command->obj.program == prog; + return (rv_command_t) { + .type = RV_COMMAND_UNIFORM_UPDATE, + .uniform_update.desc = uniform, + .uniform_update.value = value, + }; } -RV_GLOBAL rv_shader_node_t* rv_render_push_shader_to_prog(rv_arena* arena, rv_program_t* prog, rv_shader_t* shader) +RV_GLOBAL rv_render_clear_desc_t* rv_render_push_clear_desc(rv_arena* arena, rv_command_t* clear, rv_graphics_clear_flag_t flags) { - rv_shader_node_t* res = rv_push_compound(arena, rv_shader_node_t, {.shader = shader}); - rv_llist_stack_push(prog->shader_first, res); + rv_assert(clear->type == RV_COMMAND_CLEAR); + rv_render_clear_desc_t* res = rv_push_compound(arena, rv_render_clear_desc_t, {.flags = flags}); + rv_llist_queue_push(clear->clear.first, clear->clear.last, res); return res; } -RV_GLOBAL rv_uniform_t* rv_render_push_uniform_to_prog(rv_arena* arena, rv_program_t* prog, rv_str8 name, rv_uniform_type_t type) +RV_GLOBAL bool32 rv_command_has_pipeline(rv_command_t* command, rv_pipeline_t* pipeline) { - rv_uniform_t* res = rv_push_compound(arena, rv_uniform_t, {.name_null_terminated = rv_str8_copy(arena, name) , .type = type}); - rv_llist_stack_push(prog->uniform_desc_first, res); - return res; + return command->type == RV_COMMAND_OBJ_PIPELINE && command->obj.pipeline == pipeline; } -RV_GLOBAL rv_uniform_t* rv_render_push_uniform_to_prog_texture(rv_arena* arena, rv_program_t* prog, rv_str8 name, rv_texture_t* tex) + +RV_GLOBAL rv_shader_node_t* rv_pipeline_push_shader(rv_arena* arena, rv_pipeline_t* pipeline, rv_shader_t* shader) { - rv_uniform_t* res = rv_push_compound(arena, rv_uniform_t, {.name_null_terminated = rv_str8_copy(arena, name) , .type = RV_UNIFORM_TEX, .last_val.v_tex = tex}); - rv_llist_stack_push(prog->uniform_desc_first, res); + rv_shader_node_t* res = rv_push_compound(arena, rv_shader_node_t, {.shader = shader}); + rv_llist_stack_push(pipeline->shader_first, res); return res; +} +RV_GLOBAL rv_uniform_t* rv_pipeline_push_uniform(rv_arena* arena, rv_pipeline_t* pipeline, rv_str8 name, rv_uniform_type_t type) +{ + rv_uniform_t* res = rv_push_compound(arena, rv_uniform_t, {.name_null_terminated = rv_str8_copy(arena, name) , .type = type}); + rv_llist_stack_push(pipeline->uniform_desc_first, res); + return res; } -RV_GLOBAL rv_vattr_t* rv_render_push_vattr_to_prog(rv_arena* arena, rv_program_t* prog, rv_vattr_type_t type) +RV_GLOBAL rv_vattr_t* rv_pipeline_push_vattr(rv_arena* arena, rv_pipeline_t* pipeline, rv_vattr_type_t type) { rv_vattr_t* res = rv_push_compound(arena, rv_vattr_t, {.type = type}); - rv_llist_queue_push(prog->vattr_first, prog->vattr_last, res); + rv_llist_queue_push(pipeline->vattr_first, pipeline->vattr_last, res); return res; }