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:
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;
}