revolver

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

commit 1e57b726b635a7df096307ec28f381cf6af0ead3
parent ea52e2799ae8a1b1382f498d9a57d19443ff028f
Author: Samdal <samdal@protonmail.com>
Date:   Sat, 22 Mar 2025 22:12:19 +0100

framebuffers

Diffstat:
Aexamples/framebuffer.c | 243+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mexamples/simple_texture.c | 33++++++++++++++++-----------------
Mexamples/simple_triangle.c | 22+++++++++++-----------
Mexamples/test.c | 221+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Mexamples/uniform.c | 60++++++++++++++++++++++++++++++------------------------------
Msrc/platform/gfx/xcb_impl.c | 33+++++++++++++++++++++++++--------
Msrc/platform/platform_core.c | 8++++----
Msrc/platform/platform_string.c | 368++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/platform/platform_string.h | 2+-
Msrc/platform/platform_types.h | 2+-
Msrc/render/impl/opengl.c | 65++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/render/render.h | 20++++++++++++++++++--
Msrc/render/render_helpers.c | 27++++++++++++++++++++++++++-
13 files changed, 777 insertions(+), 327 deletions(-)

diff --git a/examples/framebuffer.c b/examples/framebuffer.c @@ -0,0 +1,243 @@ + +////////////////////////////////////////////////////////////////// +// simple_texture.c + +#include "revolver_inc.h" +#include "revolver_inc.c" + +////////////////////////////////////////////////////////////////// +// triangle data + +f32 triangle_v_data[] = { + 0.0, 0.5, 1, 0, 0, + -0.5, -0.5, 0, 1, 0, + 0.5, -0.5, 0, 0, 1, +}; + +rv_str8 triangle_v_src = S("#version 330 core\n" rv_strify( + layout(location = 0) in vec2 a_pos; + layout(location = 1) in vec3 a_color; + precision mediump float; + out vec3 f_color; + void main() + { + gl_Position = vec4(a_pos, 0.0, 1.0); + f_color = a_color; + } +)); + +rv_str8 triangle_f_src = S("#version 330 core\n" rv_strify( + precision mediump float; + in vec3 f_color; + out vec4 frag_color; + void main() + { + frag_color = vec4(f_color, 1.0); + } +)); + +////////////////////////////////////////////////////////////////// +// post processing data + +// Vertex data for quad +f32 post_v_data[] = { + // Positions | UV + -1, -1, 0, 0, // Top Left + 1, -1, 1, 0, // Top Right + -1, 1, 0, 1, // Bottom Left + 1, 1, 1, 1, // Bottom Right +}; + +// Index data for quad +uint32_t post_i_data[] = { + 0, 3, 2, // First Triangle + 0, 1, 3 // Second Triangle +}; + +rv_str8 post_v_src = S("#version 330 core\n" rv_strify( + layout(location = 0) in vec2 a_pos; + layout(location = 1) in vec2 a_uv; + precision mediump float; + out vec2 uv; + void main() + { + gl_Position = vec4(a_pos, 0.0, 1.0); + uv = a_uv; + } +)); + +rv_str8 post_f_src = S("#version 330 core\n" rv_strify( + precision mediump float; + in vec2 uv; + uniform sampler2D u_tex; + uniform float u_time; + out vec4 frag_color; + void main() + { + frag_color = texture(u_tex, uv); + float percent = (sin(u_time) + 1.0) * 0.5; + if (uv.x > percent) { + frag_color = vec4(vec3(1.0, 1.0, 1.0) - texture(u_tex, uv).xyz, 1.0); + } + } +)); + +////////////////////////////////////////////////////////////////// + +int main(void) { + rv_window_desc_t desc = {.name = S("App"), .attach_render = true}; + rv_window_handle_t* window = rv_create_window(desc); + + rv_arena* arena = rv_arena_alloc(); + rv_render_pass_list_t rpass_list = {0}; + + rv_command_list_t create_instructions = {0}; + rv_command_list_t triangle_render_instructions = {0}; + rv_command_list_t post_render_instructions = {0}; + + + ////////////////////////////////////////////////////////////////// + // triangle + + // make render objects + rv_vbo_t* triangle_vbo = rv_push_compound(arena, rv_vbo_t, {.data = triangle_v_data, .size = sizeof(triangle_v_data)}); + rv_shader_t* triangle_vertex = rv_push_compound(arena, rv_shader_t, {.source = triangle_v_src, .type = RV_SHADER_TYPE_VERTEX}); + rv_shader_t* triangle_fragment = rv_push_compound(arena, rv_shader_t, {.source = triangle_f_src, .type = RV_SHADER_TYPE_FRAGMENT}); + rv_pipeline_t* triangle_pip = rv_push(arena, rv_pipeline_t); + + // construct pipeline + rv_pipeline_push_shader(arena, triangle_pip, triangle_vertex); + rv_pipeline_push_shader(arena, triangle_pip, triangle_fragment); + rv_pipeline_push_vattr(arena, triangle_pip, RV_VATTR_TYPE_FLOAT2); + rv_pipeline_push_vattr(arena, triangle_pip, RV_VATTR_TYPE_FLOAT3); + + // instructions to create render objects + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_CREATE, triangle_vbo); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, triangle_vertex); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, triangle_fragment); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_CREATE, triangle_pip); + + // instructions to render + rv_cmd_push_obj(arena, &triangle_render_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, triangle_pip); + rv_cmd_push_obj(arena, &triangle_render_instructions, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_BIND, triangle_vbo); + rv_cmd_push_type(arena, &triangle_render_instructions, RV_COMMAND_DRAW)->draw.count = 3; + rv_cmd_push_obj(arena, &triangle_render_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, NULL); + + ////////////////////////////////////////////////////////////////// + // post processing + + // make render objects + rv_vbo_t* post_vbo = rv_push_compound(arena, rv_vbo_t, {.data = post_v_data, .size = sizeof(post_v_data)}); + rv_vbo_t* post_ibo = rv_push_compound(arena, rv_ibo_t, {.data = post_i_data, .size = sizeof(post_i_data), .elem_size = sizeof(post_i_data[0])}); + rv_shader_t* post_vertex = rv_push_compound(arena, rv_shader_t, {.source = post_v_src, .type = RV_SHADER_TYPE_VERTEX}); + rv_shader_t* post_fragment = rv_push_compound(arena, rv_shader_t, {.source = post_f_src, .type = RV_SHADER_TYPE_FRAGMENT}); + rv_pipeline_t* post_pip = rv_push(arena, rv_pipeline_t); + + // construct pipeline + rv_pipeline_push_shader(arena, post_pip, post_vertex); + rv_pipeline_push_shader(arena, post_pip, post_fragment); + rv_pipeline_push_vattr(arena, post_pip, RV_VATTR_TYPE_FLOAT2); + rv_pipeline_push_vattr(arena, post_pip, RV_VATTR_TYPE_FLOAT2); + rv_uniform_t* u_tex = rv_pipeline_push_uniform(arena, post_pip, S("u_tex"), RV_UNIFORM_TEX); + rv_uniform_t* u_time = rv_pipeline_push_uniform(arena, post_pip, S("u_time"), RV_UNIFORM_F32); + + // instructions to create render objects + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_CREATE, post_vbo); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_INDEX, RV_RENDER_OBJ_OP_CREATE, post_ibo); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, post_vertex); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, post_fragment); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_CREATE, post_pip); + + // instructions to render + rv_cmd_push_obj(arena, &post_render_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, post_pip); + rv_cmd_push_obj(arena, &post_render_instructions, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_BIND, post_vbo); + rv_cmd_push_obj(arena, &post_render_instructions, RV_COMMAND_OBJ_INDEX, RV_RENDER_OBJ_OP_BIND, post_ibo); + rv_cmd_push_type(arena, &post_render_instructions, RV_COMMAND_DRAW)->draw.count = 6; + rv_cmd_push_obj(arena, &post_render_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, NULL); + + ////////////////////////////////////////////////////////////////// + // fbuf + + rv_framebuffer_t* fbuf = rv_framebuffer_color_simple(arena, rv_v2(1920, 1080), &create_instructions); + // set uniform texture to fbuf + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, post_pip); + rv_cmd_push_uniform_update(arena, &create_instructions, u_tex, {.v_tex = fbuf->color_attachement_first->tex}); + rv_cmd_push_obj(arena, &create_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_instructions); + + while(1) { + rv_temp_arena scratch = rv_scratch_begin(0, 0); + + // 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; + } + } + } + + { // add off-screen rendering first + rv_render_pass_t* off_screen_rpass = rv_render_push_render_pass(scratch.arena, &rpass_list); + + { // set viewport + rv_command_t* viewport = rv_cmd_push_type(scratch.arena, &off_screen_rpass->commands, RV_COMMAND_SET_VIEWPORT); + viewport->viewport = rv_v4(0, 0, 1920, 1080); + } + + { // clear + rv_command_t* clear = rv_cmd_push_type(scratch.arena, &off_screen_rpass->commands, RV_COMMAND_CLEAR); + rv_render_clear_desc_t* clear_desc = rv_render_push_clear_desc(scratch.arena, clear, RV_RENDER_CLEAR_FLAG_COLOR); + clear_desc->color_v = rv_v4(0.1, 0.1, 0.1, 1.0); + } + + off_screen_rpass->framebuffer = fbuf; + rv_render_copy_commands(scratch.arena, &off_screen_rpass->commands, &triangle_render_instructions); + } + + // main renderpass + rv_render_pass_t* rpass = rv_render_push_render_pass(scratch.arena, &rpass_list); + + { // set viewport + rv_command_t* viewport = rv_cmd_push_type(scratch.arena, &rpass->commands, RV_COMMAND_SET_VIEWPORT); + viewport->viewport = rv_v4(.xy = {0, 0}, .zw = rv_window_size(window)); + } + + { // clear + rv_command_t* clear = rv_cmd_push_type(scratch.arena, &rpass->commands, RV_COMMAND_CLEAR); + rv_render_clear_desc_t* clear_desc = rv_render_push_clear_desc(scratch.arena, clear, RV_RENDER_CLEAR_FLAG_COLOR); + clear_desc->color_v = rv_v4(0.1, 0.1, 0.1, 1.0); + } + + { // draw post processing +#if 1 + rv_command_t* rcmd = rv_render_copy_commands(scratch.arena, &rpass->commands, &post_render_instructions); + + // 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, post_pip)) break; + } + if (pipeline_cmd) { + rv_cmd_insert_uniform_update(scratch.arena, &rpass->commands, pipeline_cmd, u_time, {.v_f32 = (f32)rv_time()}); + } +#else + rv_render_copy_commands(scratch.arena, &rpass->commands, &triangle_render_instructions); +#endif + } + + if (window) { // render screen + rv_window_render_commit(window, &rpass_list); + } + rv_scratch_end(scratch); + rpass_list = (rv_render_pass_list_t){0}; + } +exit_program: + + return 0; +} diff --git a/examples/simple_texture.c b/examples/simple_texture.c @@ -72,7 +72,7 @@ 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_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}); @@ -88,11 +88,11 @@ int main(void) { // 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_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}); @@ -131,19 +131,18 @@ int main(void) { } } - if (window) { // render screen - - { // 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); - } + { // clear + rv_command_t* clear = rv_cmd_push_type(scratch.arena, &rpass->commands, RV_COMMAND_CLEAR); + rv_render_clear_desc_t* clear_desc = rv_render_push_clear_desc(scratch.arena, clear, RV_RENDER_CLEAR_FLAG_COLOR); + clear_desc->color_v = rv_v4(0.1, 0.1, 0.1, 1.0); + } - { // draw custom shader - // copy render commands - rv_render_copy_commands(scratch.arena, &rpass->commands, &render_instructions); - } + { // draw custom shader + // copy render commands + rv_render_copy_commands(scratch.arena, &rpass->commands, &render_instructions); + } + if (window) { // render screen rv_window_render_commit(window, &rpass_list); } rv_scratch_end(scratch); diff --git a/examples/simple_triangle.c b/examples/simple_triangle.c @@ -31,7 +31,7 @@ rv_str8 f_src = S("#version 330 core\n" rv_strify( out vec4 frag_color; void main() { - frag_color = vec4(f_color, 1.0); + frag_color = vec4(f_color, 1.0); } )); @@ -94,19 +94,19 @@ int main(void) { } } - if (window) { // render screen - { // 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); - } + { // clear + rv_command_t* clear = rv_cmd_push_type(scratch.arena, &rpass->commands, RV_COMMAND_CLEAR); + rv_render_clear_desc_t* clear_desc = rv_render_push_clear_desc(scratch.arena, clear, RV_RENDER_CLEAR_FLAG_COLOR); + clear_desc->color_v = rv_v4(0.1, 0.1, 0.1, 1.0); + } - { // draw custom shader - // copy render commands - rv_render_copy_commands(scratch.arena, &rpass->commands, &render_instructions); - } + { // draw custom shader + // copy render commands + rv_render_copy_commands(scratch.arena, &rpass->commands, &render_instructions); + } + if (window) { // render screen rv_window_render_commit(window, &rpass_list); } rv_scratch_end(scratch); diff --git a/examples/test.c b/examples/test.c @@ -5,27 +5,56 @@ #include "revolver_inc.h" #include "revolver_inc.c" -#define ROW_COL_CT 10 +////////////////////////////////////////////////////////////////// +// triangle data + +f32 triangle_v_data[] = { + 0.0, 0.5, 1, 0, 0, + -0.5, -0.5, 0, 1, 0, + 0.5, -0.5, 0, 0, 1, +}; + +rv_str8 triangle_v_src = S("#version 330 core\n" rv_strify( + layout(location = 0) in vec2 a_pos; + layout(location = 1) in vec3 a_color; + precision mediump float; + out vec3 f_color; + void main() + { + gl_Position = vec4(a_pos, 0.0, 1.0); + f_color = a_color; + } +)); + +rv_str8 triangle_f_src = S("#version 330 core\n" rv_strify( + precision mediump float; + in vec3 f_color; + out vec4 frag_color; + void main() + { + frag_color = vec4(f_color, 1.0); + } +)); ////////////////////////////////////////////////////////////////// -// data +// post processing data // Vertex data for quad -f32 v_data[] = { - // Positions UVs - -0.5f, -0.5f, 0.0f, 0.0f, // Top Left - 0.5f, -0.5f, 1.0f, 0.0f, // Top Right - -0.5f, 0.5f, 0.0f, 1.0f, // Bottom Left - 0.5f, 0.5f, 1.0f, 1.0f // Bottom Right +f32 post_v_data[] = { + // Positions | UV + -1, -1, 0, 0, // Top Left + 1, -1, 1, 0, // Top Right + -1, 1, 0, 1, // Bottom Left + 1, 1, 1, 1, // Bottom Right }; // Index data for quad -uint32_t i_data[] = { +uint32_t post_i_data[] = { 0, 3, 2, // First Triangle 0, 1, 3 // Second Triangle }; -rv_str8 v_src = S("#version 330 core\n" rv_strify( +rv_str8 post_v_src = S("#version 330 core\n" rv_strify( layout(location = 0) in vec2 a_pos; layout(location = 1) in vec2 a_uv; precision mediump float; @@ -37,20 +66,24 @@ rv_str8 v_src = S("#version 330 core\n" rv_strify( } )); -rv_str8 f_src = S("#version 330 core\n" rv_strify( +rv_str8 post_f_src = S("#version 330 core\n" rv_strify( precision mediump float; - uniform sampler2D u_tex; in vec2 uv; + uniform sampler2D u_tex; + uniform float u_time; out vec4 frag_color; void main() { frag_color = texture(u_tex, uv); + float percent = (sin(u_time) + 1.0) * 0.5; + if (uv.x > percent) { + frag_color = vec4(vec3(1.0, 1.0, 1.0) - texture(u_tex, uv).xyz, 1.0); + } } )); ////////////////////////////////////////////////////////////////// - int main(void) { rv_window_desc_t desc = {.name = S("App"), .attach_render = true}; rv_window_handle_t* window = rv_create_window(desc); @@ -58,66 +91,88 @@ int main(void) { rv_arena* arena = rv_arena_alloc(); rv_render_pass_list_t rpass_list = {0}; + rv_command_list_t create_instructions = {0}; + rv_command_list_t triangle_render_instructions = {0}; + rv_command_list_t post_render_instructions = {0}; - // Generate procedural texture data (checkered texture) - rv_color_t c0 = RV_COLOR_BLACK; - rv_color_t c1 = RV_COLOR_PURPLE; - rv_color_t pixels[ROW_COL_CT * ROW_COL_CT] = {0}; - for (uint32_t r = 0; r < ROW_COL_CT; ++r) { - for (uint32_t c = 0; c < ROW_COL_CT; ++c) { - const bool32 re = (r % 2) == 0; - const bool32 ce = (c % 2) == 0; - uint32_t idx = r * ROW_COL_CT + c; - pixels[idx] = (re && ce) ? c0 : (re) ? c1 : (ce) ? c1 : c0; - } - } + + ////////////////////////////////////////////////////////////////// + // triangle // 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_pipeline_t* pip = rv_push(arena, rv_pipeline_t); + rv_vbo_t* triangle_vbo = rv_push_compound(arena, rv_vbo_t, {.data = triangle_v_data, .size = sizeof(triangle_v_data)}); + rv_shader_t* triangle_vertex = rv_push_compound(arena, rv_shader_t, {.source = triangle_v_src, .type = RV_SHADER_TYPE_VERTEX}); + rv_shader_t* triangle_fragment = rv_push_compound(arena, rv_shader_t, {.source = triangle_f_src, .type = RV_SHADER_TYPE_FRAGMENT}); + rv_pipeline_t* triangle_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); + rv_pipeline_push_shader(arena, triangle_pip, triangle_vertex); + rv_pipeline_push_shader(arena, triangle_pip, triangle_fragment); + rv_pipeline_push_vattr(arena, triangle_pip, RV_VATTR_TYPE_FLOAT2); + rv_pipeline_push_vattr(arena, triangle_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_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); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_CREATE, triangle_vbo); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, triangle_vertex); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, triangle_fragment); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_CREATE, triangle_pip); + + // instructions to render + rv_cmd_push_obj(arena, &triangle_render_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, triangle_pip); + rv_cmd_push_obj(arena, &triangle_render_instructions, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_BIND, triangle_vbo); + rv_cmd_push_type(arena, &triangle_render_instructions, RV_COMMAND_DRAW)->draw.count = 3; + rv_cmd_push_obj(arena, &triangle_render_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, NULL); + + ////////////////////////////////////////////////////////////////// + // post processing + + // make render objects + rv_vbo_t* post_vbo = rv_push_compound(arena, rv_vbo_t, {.data = post_v_data, .size = sizeof(post_v_data)}); + rv_vbo_t* post_ibo = rv_push_compound(arena, rv_ibo_t, {.data = post_i_data, .size = sizeof(post_i_data), .elem_size = sizeof(post_i_data[0])}); + rv_shader_t* post_vertex = rv_push_compound(arena, rv_shader_t, {.source = post_v_src, .type = RV_SHADER_TYPE_VERTEX}); + rv_shader_t* post_fragment = rv_push_compound(arena, rv_shader_t, {.source = post_f_src, .type = RV_SHADER_TYPE_FRAGMENT}); + rv_pipeline_t* post_pip = rv_push(arena, rv_pipeline_t); + + // construct pipeline + rv_pipeline_push_shader(arena, post_pip, post_vertex); + rv_pipeline_push_shader(arena, post_pip, post_fragment); + rv_pipeline_push_vattr(arena, post_pip, RV_VATTR_TYPE_FLOAT2); + rv_pipeline_push_vattr(arena, post_pip, RV_VATTR_TYPE_FLOAT2); + rv_uniform_t* u_tex = rv_pipeline_push_uniform(arena, post_pip, S("u_tex"), RV_UNIFORM_TEX); + rv_uniform_t* u_time = rv_pipeline_push_uniform(arena, post_pip, S("u_time"), RV_UNIFORM_F32); + + // instructions to create render objects + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_CREATE, post_vbo); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_INDEX, RV_RENDER_OBJ_OP_CREATE, post_ibo); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, post_vertex); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_SHADER, RV_RENDER_OBJ_OP_CREATE, post_fragment); + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_CREATE, post_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_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); + rv_cmd_push_obj(arena, &post_render_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, post_pip); + rv_cmd_push_obj(arena, &post_render_instructions, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_BIND, post_vbo); + rv_cmd_push_obj(arena, &post_render_instructions, RV_COMMAND_OBJ_INDEX, RV_RENDER_OBJ_OP_BIND, post_ibo); + rv_cmd_push_type(arena, &post_render_instructions, RV_COMMAND_DRAW)->draw.count = 6; + rv_cmd_push_obj(arena, &post_render_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, NULL); + + ////////////////////////////////////////////////////////////////// + // fbuf + + rv_framebuffer_t* fbuf = rv_framebuffer_color_simple(arena, rv_v2(1920, 1080), &create_instructions); + // set uniform texture to fbuf + rv_cmd_push_obj(arena, &create_instructions, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, post_pip); + rv_cmd_push_uniform_update(arena, &create_instructions, u_tex, {.v_tex = fbuf->color_attachement_first->tex}); + rv_cmd_push_obj(arena, &create_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_instructions); - while(1) { rv_temp_arena scratch = rv_scratch_begin(0, 0); - // pick renderpass - rv_render_pass_t* rpass = rv_render_push_render_pass(scratch.arena, &rpass_list); - // process events for (rv_event_t* e = rv_get_events(scratch.arena, 0); e; e = e->next) { if (e->type == RV_EVENT_WINDOW_CLOSE) { @@ -125,26 +180,58 @@ int main(void) { 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 + { // add off-screen rendering first + rv_render_pass_t* off_screen_rpass = rv_render_push_render_pass(scratch.arena, &rpass_list); + + { // set viewport + rv_command_t* viewport = rv_cmd_push_type(scratch.arena, &off_screen_rpass->commands, RV_COMMAND_SET_VIEWPORT); + viewport->viewport = rv_v4(0, 0, 1920, 1080); + } { // clear - rv_command_t* clear = rv_cmd_push_type(scratch.arena, &rpass->commands, RV_COMMAND_CLEAR); + rv_command_t* clear = rv_cmd_push_type(scratch.arena, &off_screen_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); + clear_desc->color_v = rv_v4(0.1, 0.1, 0.1, 1.0); } - { // draw custom shader - // copy render commands - rv_render_copy_commands(scratch.arena, &rpass->commands, &render_instructions); + off_screen_rpass->framebuffer = fbuf; + rv_render_copy_commands(scratch.arena, &off_screen_rpass->commands, &triangle_render_instructions); + } + + // main renderpass + rv_render_pass_t* rpass = rv_render_push_render_pass(scratch.arena, &rpass_list); + + { // set viewport + rv_command_t* viewport = rv_cmd_push_type(scratch.arena, &rpass->commands, RV_COMMAND_SET_VIEWPORT); + viewport->viewport = rv_v4(.xy = {0, 0}, .zw = rv_window_size(window)); + } + + { // clear + rv_command_t* clear = rv_cmd_push_type(scratch.arena, &rpass->commands, RV_COMMAND_CLEAR); + rv_render_clear_desc_t* clear_desc = rv_render_push_clear_desc(scratch.arena, clear, RV_RENDER_CLEAR_FLAG_COLOR); + clear_desc->color_v = rv_v4(0.1, 0.1, 0.1, 1.0); + } + + { // draw post processing +#if 1 + rv_command_t* rcmd = rv_render_copy_commands(scratch.arena, &rpass->commands, &post_render_instructions); + + // 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, post_pip)) break; } + if (pipeline_cmd) { + rv_cmd_insert_uniform_update(scratch.arena, &rpass->commands, pipeline_cmd, u_time, {.v_f32 = (f32)rv_time()}); + } +#else + rv_render_copy_commands(scratch.arena, &rpass->commands, &triangle_render_instructions); +#endif + } + if (window) { // render screen rv_window_render_commit(window, &rpass_list); } rv_scratch_end(scratch); diff --git a/examples/uniform.c b/examples/uniform.c @@ -99,43 +99,43 @@ int main(void) { } } - if (window) { // render screen - { // 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); - } + { // clear + rv_command_t* clear = rv_cmd_push_type(scratch.arena, &rpass->commands, RV_COMMAND_CLEAR); + rv_render_clear_desc_t* clear_desc = rv_render_push_clear_desc(scratch.arena, clear, RV_RENDER_CLEAR_FLAG_COLOR); + clear_desc->color_v = rv_v4(0.1, 0.1, 0.1, 1.0); + } - { // draw custom shader + { // draw custom shader - // copy render commands - rv_command_t* rcmd = rv_render_copy_commands(scratch.arena, &rpass->commands, &render_instructions); + // copy render commands + rv_command_t* rcmd = rv_render_copy_commands(scratch.arena, &rpass->commands, &render_instructions); - // 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; - } + // 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 (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_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_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; - } + 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_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_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; } + } + if (window) { // render screen rv_window_render_commit(window, &rpass_list); } rv_scratch_end(scratch); diff --git a/src/platform/gfx/xcb_impl.c b/src/platform/gfx/xcb_impl.c @@ -188,18 +188,35 @@ RV_GLOBAL void* egl_attach(xcb_window_t window, xcb_connection_t* connection) RV_GLOBAL void rv_window_render_begin(rv_window_handle_t* window) { - EGLSurface* surface = xcb_maybe_window(window)->render; - eglMakeCurrent(egl_context.egl_display, surface, surface, egl_context.egl_context); + rv_window_handle_t* w = xcb_maybe_window(window); + if (w) { + EGLSurface* surface = w->render; + eglMakeCurrent(egl_context.egl_display, surface, surface, egl_context.egl_context); + } } RV_GLOBAL void rv_window_render_end(rv_window_handle_t* window) { - EGLSurface* surface = xcb_maybe_window(window)->render; - eglSwapBuffers(egl_context.egl_display, surface); + rv_window_handle_t* w = xcb_maybe_window(window); + if (w) { + EGLSurface* surface = w->render; + eglSwapBuffers(egl_context.egl_display, surface); + } +} + +#else // RV_RENDER_OPENGL + +RV_GLOBAL void rv_window_render_begin(rv_window_handle_t* window) +{ + } +RV_GLOBAL void rv_window_render_end(rv_window_handle_t* window) +{ + +} -#endif // RV_RENDER_OPENGL +#endif // !RV_RENDER_OPENGL ////////////////////////////////////////////////////////////////// @@ -506,7 +523,7 @@ RV_GLOBAL rv_window_handle_t* rv_create_window(rv_window_desc_t desc) xcb_change_property(xcb_context.connection, XCB_PROP_MODE_REPLACE, res->window_id, XCB_ATOM_WM_NAME, m_utf8_string_atom, 8, - desc.name.size, desc.name.str); + desc.name.len, desc.name.str); } { // setup close handler event @@ -850,7 +867,7 @@ RV_GLOBAL rv_event_t* rv_get_events(rv_arena* arena, rv_event_flags_t flags) if (len) { new_ev.key_press.string = rv_str8_from_cstr(buf); new_ev.key_press.string = rv_str8_copy(arena, new_ev.key_press.string); - if (new_ev.key_press.string.size == 1) { + if (new_ev.key_press.string.len == 1) { if (new_ev.key_press.string.str[0] == '\r') { new_ev.key_press.string.str[0] = '\n'; } @@ -859,7 +876,7 @@ RV_GLOBAL rv_event_t* rv_get_events(rv_arena* arena, rv_event_flags_t flags) } // invalidate event if nothing gave any results - if (new_ev.key_press.keycode == RV_KEYCODE_INVALID && new_ev.key_press.string.size == 0) { + if (new_ev.key_press.keycode == RV_KEYCODE_INVALID && new_ev.key_press.string.len == 0) { new_ev.type = RV_EVENT_INVALID; } } break; diff --git a/src/platform/platform_core.c b/src/platform/platform_core.c @@ -140,15 +140,15 @@ RV_GLOBAL s64 rv_mem_get_page_size(bool32 is_large) rv_str8 proc_meminfo = rv_str8_from_cstr(buffer); rv_str8 tag = S("Hugepagesize:"); - rv_str8 found = rv_str8_skip(proc_meminfo, rv_str8_find_needle(proc_meminfo, 0, tag, 0) + tag.size); + rv_str8 found = rv_str8_skip(proc_meminfo, rv_str8_find_needle(proc_meminfo, 0, tag, 0) + tag.len); // chop around number + byte size found = rv_str8_skip_chop_whitespace(found); found = rv_str8_prefix(found, rv_str8_find_needle(found, 0, S("\n"), 0)); - bool32 kb = rv_str8_find_needle(found, 0, S("kb"), rv_str8_match_flag_case_insensetive) < found.size; - bool32 mb = rv_str8_find_needle(found, 0, S("mb"), rv_str8_match_flag_case_insensetive) < found.size; - bool32 gb = rv_str8_find_needle(found, 0, S("gb"), rv_str8_match_flag_case_insensetive) < found.size; + bool32 kb = rv_str8_find_needle(found, 0, S("kb"), rv_str8_match_flag_case_insensetive) < found.len; + bool32 mb = rv_str8_find_needle(found, 0, S("mb"), rv_str8_match_flag_case_insensetive) < found.len; + bool32 gb = rv_str8_find_needle(found, 0, S("gb"), rv_str8_match_flag_case_insensetive) < found.len; // remove byte part found = rv_str8_prefix(found, rv_str8_find_needle(found, 0, S(" "), 0)); diff --git a/src/platform/platform_string.c b/src/platform/platform_string.c @@ -6,75 +6,75 @@ RV_READ_ONLY RV_INTERNAL u8 char_integer_symbol_reverse[128] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, }; RV_GLOBAL bool32 rv_char_is_space(u8 c) { - return c == ' ' || c == '\n' || c == '\t' || c == '\r' || c == '\f' || c == '\v'; + return c == ' ' || c == '\n' || c == '\t' || c == '\r' || c == '\f' || c == '\v'; } RV_GLOBAL bool32 rv_char_is_upper(u8 c) { - return 'A' <= c && c <= 'Z'; + return 'A' <= c && c <= 'Z'; } RV_GLOBAL bool32 rv_char_is_lower(u8 c) { - return 'a' <= c && c <= 'z'; + return 'a' <= c && c <= 'z'; } RV_GLOBAL bool32 rv_char_is_alpha(u8 c) { - return rv_char_is_upper(c) || rv_char_is_lower(c); + return rv_char_is_upper(c) || rv_char_is_lower(c); } RV_GLOBAL bool32 rv_char_is_slash(u8 c) { - return c == '/' || c == '\\'; + return c == '/' || c == '\\'; } RV_GLOBAL bool32 rv_char_is_digit(u8 c, s32 base) { - bool32 result = 0; - if (base >= 0 && base <= 16) { - u8 val = char_integer_symbol_reverse[c]; - if (val < base) { - result = 1; - } - } - return result; + bool32 result = 0; + if (base >= 0 && base <= 16) { + u8 val = char_integer_symbol_reverse[c]; + if (val < base) { + result = 1; + } + } + return result; } RV_GLOBAL u8 rv_char_to_lower(u8 c) { - if (rv_char_is_upper(c)) { - c += ('a' - 'A'); - } - return c; + if (rv_char_is_upper(c)) { + c += ('a' - 'A'); + } + return c; } RV_GLOBAL u8 rv_char_to_upper(u8 c) { - if (rv_char_is_lower(c)) { - c += ('A' - 'a'); - } - return c; + if (rv_char_is_lower(c)) { + c += ('A' - 'a'); + } + return c; } RV_GLOBAL u8 rv_char_to_correct_slash(u8 c) { - if(rv_char_is_slash(c)) { - c = '/'; - } - return c; + if(rv_char_is_slash(c)) { + c = '/'; + } + return c; } ////////////////////////////////////////////////////////////////// @@ -82,9 +82,9 @@ RV_GLOBAL u8 rv_char_to_correct_slash(u8 c) RV_GLOBAL s64 rv_cstrlen(const char* c_str) { - s64 res = 0; - while (*c_str++) res++; - return res; + s64 res = 0; + while (*c_str++) res++; + return res; } ////////////////////////////////////////////////////////////////// @@ -92,7 +92,7 @@ RV_GLOBAL s64 rv_cstrlen(const char* c_str) RV_GLOBAL rv_str8 rv_str8_range(u8* first, u8* one_past_last) { - return rv_s8(first, (s64)(one_past_last - first)); + return rv_s8(first, (s64)(one_past_last - first)); } @@ -101,45 +101,45 @@ RV_GLOBAL rv_str8 rv_str8_range(u8* first, u8* one_past_last) RV_GLOBAL s64 rv_sign_from_str8(rv_str8 string, rv_str8* string_tail) { - // count negative signs - u64 neg_count = 0; - u64 i = 0; - for (; i < string.size; i += 1) { - if (string.str[i] == '-') { - neg_count += 1; - } - else if (string.str[i] != '+') { - break; - } - } - - // output part of string after signs - *string_tail = rv_str8_skip(string, i); - - // output integer sign - s64 sign = (neg_count & 1) ? -1 : +1; - return sign; + // count negative signs + u64 neg_count = 0; + u64 i = 0; + for (; i < string.len; i += 1) { + if (string.str[i] == '-') { + neg_count += 1; + } + else if (string.str[i] != '+') { + break; + } + } + + // output part of string after signs + *string_tail = rv_str8_skip(string, i); + + // output integer sign + s64 sign = (neg_count & 1) ? -1 : +1; + return sign; } RV_GLOBAL u64 rv_u64_from_str8(rv_str8 string, u32 radix) { - u64 x = 0; - if (1 < radix && radix <= 16) { - for (u64 i = 0; i < string.size; i += 1) { - x *= radix; - x += char_integer_symbol_reverse[string.str[i]&0x7F]; - } - } - return x; + u64 x = 0; + if (1 < radix && radix <= 16) { + for (u64 i = 0; i < string.len; i += 1) { + x *= radix; + x += char_integer_symbol_reverse[string.str[i]&0x7F]; + } + } + return x; } RV_GLOBAL s64 rv_s64_from_str8(rv_str8 string, s32 radix) { - s64 sign = rv_sign_from_str8(string, &string); - s64 x = (s64)rv_u64_from_str8(string, radix) * sign; - return x; + s64 sign = rv_sign_from_str8(string, &string); + s64 x = (s64)rv_u64_from_str8(string, radix) * sign; + return x; } RV_GLOBAL rv_str8 str8_from_s64(rv_arena* arena, s64 integer, s32 radix, u8 min_digits, u8 digit_group_separator); @@ -149,68 +149,68 @@ RV_GLOBAL rv_str8 str8_from_s64(rv_arena* arena, s64 integer, s32 radix, u8 min_ RV_GLOBAL bool32 rv_str8_match(rv_str8 a, rv_str8 b, rv_str8_match_flags flags) { - bool32 result = 0; - if (a.size == b.size || (flags & rv_str8_match_flag_right_side_sloppy)){ - bool32 case_insensitive = (flags & rv_str8_match_flag_case_insensetive); - bool32 slash_insensitive = (flags & rv_str8_match_flag_slash_insensetive); - s64 size = rv_min(a.size, b.size); - result = 1; - for (s64 i = 0; i < size; i += 1){ - u8 at = a.str[i]; - u8 bt = b.str[i]; - if (case_insensitive){ - at = rv_char_to_upper(at); - bt = rv_char_to_upper(bt); - } - if (slash_insensitive){ - at = rv_char_to_correct_slash(at); - bt = rv_char_to_correct_slash(bt); - } - if (at != bt){ - result = 0; - break; - } - } - } - return result; + bool32 result = 0; + if (a.len == b.len || (flags & rv_str8_match_flag_right_side_sloppy)){ + bool32 case_insensitive = (flags & rv_str8_match_flag_case_insensetive); + bool32 slash_insensitive = (flags & rv_str8_match_flag_slash_insensetive); + s64 len = rv_min(a.len, b.len); + result = 1; + for (s64 i = 0; i < len; i += 1){ + u8 at = a.str[i]; + u8 bt = b.str[i]; + if (case_insensitive){ + at = rv_char_to_upper(at); + bt = rv_char_to_upper(bt); + } + if (slash_insensitive){ + at = rv_char_to_correct_slash(at); + bt = rv_char_to_correct_slash(bt); + } + if (at != bt){ + result = 0; + break; + } + } + } + return result; } RV_GLOBAL s64 rv_str8_find_needle(rv_str8 string, s64 start_pos, rv_str8 needle, rv_str8_match_flags flags) { - u8* p = string.str + start_pos; - s64 stop_offset = rv_max(string.size + 1, needle.size) - needle.size; - u8* stop_p = string.str + stop_offset; - - if (string.size > 0 && needle.size > 0) { - u8* string_opl = string.str + string.size; - - rv_str8 needle_tail = rv_str8_skip(needle, 1); - rv_str8_match_flags adjusted_flags = flags | rv_str8_match_flag_right_side_sloppy; - u8 needle_first_rv_char_adjusted = needle.str[0]; - - if (adjusted_flags & rv_str8_match_flag_case_insensetive) { - needle_first_rv_char_adjusted = rv_char_to_upper(needle_first_rv_char_adjusted); - } - - for (;p < stop_p; p += 1) { - u8 haystack_rv_char_adjusted = *p; - - if (adjusted_flags & rv_str8_match_flag_case_insensetive) { - haystack_rv_char_adjusted = rv_char_to_upper(haystack_rv_char_adjusted); - } - - if (haystack_rv_char_adjusted == needle_first_rv_char_adjusted) { - if (rv_str8_match(rv_str8_range(p + 1, string_opl), needle_tail, adjusted_flags)) { - break; - } - } - } - } - s64 result = string.size; - if (p < stop_p) { - result = (s64)(p - string.str); - } - return result; + u8* p = string.str + start_pos; + s64 stop_offset = rv_max(string.len + 1, needle.len) - needle.len; + u8* stop_p = string.str + stop_offset; + + if (string.len > 0 && needle.len > 0) { + u8* string_opl = string.str + string.len; + + rv_str8 needle_tail = rv_str8_skip(needle, 1); + rv_str8_match_flags adjusted_flags = flags | rv_str8_match_flag_right_side_sloppy; + u8 needle_first_rv_char_adjusted = needle.str[0]; + + if (adjusted_flags & rv_str8_match_flag_case_insensetive) { + needle_first_rv_char_adjusted = rv_char_to_upper(needle_first_rv_char_adjusted); + } + + for (;p < stop_p; p += 1) { + u8 haystack_rv_char_adjusted = *p; + + if (adjusted_flags & rv_str8_match_flag_case_insensetive) { + haystack_rv_char_adjusted = rv_char_to_upper(haystack_rv_char_adjusted); + } + + if (haystack_rv_char_adjusted == needle_first_rv_char_adjusted) { + if (rv_str8_match(rv_str8_range(p + 1, string_opl), needle_tail, adjusted_flags)) { + break; + } + } + } + } + s64 result = string.len; + if (p < stop_p) { + result = (s64)(p - string.str); + } + return result; } ////////////////////////////////////////////////////////////////// @@ -218,60 +218,60 @@ RV_GLOBAL s64 rv_str8_find_needle(rv_str8 string, s64 start_pos, rv_str8 needle, RV_GLOBAL rv_str8 rv_str8_substr(rv_str8 str, rv_range range) { - range.min = rv_min(range.min, str.size); - range.max = rv_min(range.max, str.size); - str.str += range.min; - str.size = rv_range_diff(range); - return str; + range.min = rv_min(range.min, str.len); + range.max = rv_min(range.max, str.len); + str.str += range.min; + str.len = rv_range_diff(range); + return str; } -RV_GLOBAL rv_str8 rv_str8_prefix(rv_str8 str, s64 size) +RV_GLOBAL rv_str8 rv_str8_prefix(rv_str8 str, s64 len) { - str.size = rv_min(size, str.size); - return str; + str.len = rv_min(len, str.len); + return str; } RV_GLOBAL rv_str8 rv_str8_skip(rv_str8 str, s64 amt) { - amt = rv_min(amt, str.size); - str.str += amt; - str.size -= amt; - return str; + amt = rv_min(amt, str.len); + str.str += amt; + str.len -= amt; + return str; } -RV_GLOBAL rv_str8 rv_str8_postfix(rv_str8 str, s64 size) +RV_GLOBAL rv_str8 rv_str8_postfix(rv_str8 str, s64 len) { - size = rv_min(size, str.size); - str.str = (str.str + str.size) - size; - str.size = size; - return str; + len = rv_min(len, str.len); + str.str = (str.str + str.len) - len; + str.len = len; + return str; } RV_GLOBAL rv_str8 rv_str8_chop(rv_str8 str, s64 amt) { - amt = rv_min(amt, str.size); - str.size -= amt; - return str; + amt = rv_min(amt, str.len); + str.len -= amt; + return str; } RV_GLOBAL rv_str8 rv_str8_skip_chop_whitespace(rv_str8 string) { - u8* first = string.str; - u8* opl = first + string.size; - for (;first < opl; first += 1) { - if (!rv_char_is_space(*first)) { - break; - } - } - for (;opl > first;) { - opl -= 1; - if (!rv_char_is_space(*opl)) { - opl += 1; - break; - } - } - rv_str8 result = rv_str8_range(first, opl); - return result; + u8* first = string.str; + u8* opl = first + string.len; + for (;first < opl; first += 1) { + if (!rv_char_is_space(*first)) { + break; + } + } + for (;opl > first;) { + opl -= 1; + if (!rv_char_is_space(*opl)) { + opl += 1; + break; + } + } + rv_str8 result = rv_str8_range(first, opl); + return result; } ////////////////////////////////////////////////////////////////// @@ -279,37 +279,37 @@ RV_GLOBAL rv_str8 rv_str8_skip_chop_whitespace(rv_str8 string) RV_GLOBAL rv_str8 rv_str8_copy(rv_arena* arena, rv_str8 s) { - rv_str8 str; - str.size = s.size; - str.str = rv_push_array_no_zero(arena, u8, str.size + 1); - rv_mem_copy(str.str, s.str, s.size); - str.str[str.size] = 0; - return str; + rv_str8 str; + str.len = s.len; + str.str = rv_push_array_no_zero(arena, u8, str.len + 1); + rv_mem_copy(str.str, s.str, s.len); + str.str[str.len] = 0; + return str; } RV_GLOBAL rv_str8 rv_read_file(rv_arena* arena, rv_str8 filename) { - u8* buffer = NULL; - s64 size = 0; + u8* buffer = NULL; + s64 len = 0; - FILE* fp = NULL; - { - rv_temp_arena scratch = rv_scratch_begin((rv_arena*[]){arena}, 1); - rv_str8 filename_copy = rv_str8_copy(scratch.arena, filename); - fp = fopen((char*)filename_copy.str, "rb"); - rv_scratch_end(scratch); - } + FILE* fp = NULL; + { + rv_temp_arena scratch = rv_scratch_begin((rv_arena*[]){arena}, 1); + rv_str8 filename_copy = rv_str8_copy(scratch.arena, filename); + fp = fopen((char*)filename_copy.str, "rb"); + rv_scratch_end(scratch); + } - if (fp) { - fseek(fp, 0, SEEK_END); - size = ftell(fp); - fseek(fp, 0, SEEK_SET); + if (fp) { + fseek(fp, 0, SEEK_END); + len = ftell(fp); + fseek(fp, 0, SEEK_SET); - buffer = rv_push_array_no_zero(arena, u8, size + 1); - fread(buffer, 1, size, fp); + buffer = rv_push_array_no_zero(arena, u8, len + 1); + fread(buffer, 1, len, fp); - fclose(fp); - } + fclose(fp); + } - return rv_s8(buffer, size); + return rv_s8(buffer, len); } diff --git a/src/platform/platform_string.h b/src/platform/platform_string.h @@ -36,7 +36,7 @@ RV_GLOBAL rv_str8 rv_str8_copy(rv_arena* arena, rv_str8 s); ////////////////////////////////////////////////////////////////// // conversions -#define rv_s8v(S) (int)((S).size), ((S).str) +#define rv_s8v(S) (int)((S).len), ((S).str) RV_GLOBAL s64 rv_sign_from_str8(rv_str8 string, rv_str8* string_tail); RV_GLOBAL u64 rv_u64_from_str8(rv_str8 string, u32 radix); diff --git a/src/platform/platform_types.h b/src/platform/platform_types.h @@ -150,7 +150,7 @@ typedef struct { typedef struct { u8* str; - s64 size; + s64 len; } rv_str8; typedef struct rv_str8_node_t rv_str8_node_t; diff --git a/src/render/impl/opengl.c b/src/render/impl/opengl.c @@ -77,8 +77,24 @@ struct { rv_ibo_t* bound_ibo; rv_vbo_t* bound_vbo; rv_pipeline_t* bound_pip; + rv_framebuffer_t* bound_fbuf; } ogl_state; +void ogl_bind_fbuf(rv_framebuffer_t* fbuf) { + ogl_state.bound_fbuf = fbuf; + glBindFramebuffer(GL_FRAMEBUFFER, ogl_safe_set(fbuf, handle)); + if (fbuf) { + s32 r = 0; + for (rv_texture_node_t* c = fbuf->color_attachement_first; c; c = c->next, r++) { + if (c->tex) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + r, GL_TEXTURE_2D, c->tex->handle.u, 0); + } else { + rv_unreachable(); + } + } + } +} + RV_GLOBAL void rv_window_render_commit(rv_window_handle_t* window, rv_render_pass_list_t* passes) { @@ -91,7 +107,30 @@ RV_GLOBAL void rv_window_render_commit(rv_window_handle_t* window, rv_render_pas glBindVertexArray(ogl_ctx.vao); } + for (rv_render_pass_t* p = passes->first; p; p = p->next) { + { // unbind everything + + if (ogl_state.bound_ibo) { + ogl_state.bound_ibo = NULL; + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + + if (ogl_state.bound_vbo) { + ogl_state.bound_vbo = NULL; + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + + if (ogl_state.bound_pip) { + ogl_state.bound_pip = NULL; + glUseProgram(0); + } + + if (ogl_state.bound_fbuf || p->framebuffer) { + ogl_bind_fbuf(p->framebuffer); + } + } + for (rv_command_t* c = p->commands.first; c; c = c->next) { switch (c->type) { case RV_COMMAND_INVALID: { @@ -198,7 +237,7 @@ RV_GLOBAL void rv_window_render_commit(rv_window_handle_t* window, rv_render_pas switch (c->obj.operation) { case RV_RENDER_OBJ_OP_CREATE: { shader->handle.u = glCreateShader(rv_shader_to_gl(shader->type)); - glShaderSource(shader->handle.u, 1, (const char* const*)&shader->source.str, (s32*)&shader->source.size); + glShaderSource(shader->handle.u, 1, (const char* const*)&shader->source.str, (s32*)&shader->source.len); glCompileShader(shader->handle.u); { // check for errors @@ -537,6 +576,30 @@ RV_GLOBAL void rv_window_render_commit(rv_window_handle_t* window, rv_render_pas } } break; + case RV_COMMAND_OBJ_FRAMEBUFFER: { + rv_framebuffer_t* fbuf = c->obj.framebuffer; + switch (c->obj.operation) { + case RV_RENDER_OBJ_OP_CREATE: { + glGenFramebuffers(1, &fbuf->handle.u); + } break; + + case RV_RENDER_OBJ_OP_UPDATE: { + rv_unreachable(); + } break; + + case RV_RENDER_OBJ_OP_BIND: { + ogl_bind_fbuf(fbuf); + } break; + + case RV_RENDER_OBJ_OP_DELETE: { + glDeleteFramebuffers(1, &fbuf->handle.u); + if (ogl_state.bound_fbuf == fbuf) { + ogl_state.bound_fbuf = NULL; + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + } break; + } + } break; } } } diff --git a/src/render/render.h b/src/render/render.h @@ -34,6 +34,7 @@ typedef enum { } rv_texture_filter_t; typedef struct { + // creation data rv_vec2 size; rv_texture_format_t format; rv_texture_wrap_t wrap_s; @@ -47,9 +48,18 @@ typedef struct { rv_render_handle_t handle; } rv_texture_t; +typedef struct rv_texture_node_t rv_texture_node_t; +struct rv_texture_node_t { + rv_texture_node_t* next; + rv_texture_t* tex; +}; + typedef struct { + rv_texture_node_t* color_attachement_first; + // TODO(Samdal): depth buffer + rv_render_handle_t handle; -} rv_render_framebuffer_t; +} rv_framebuffer_t; typedef enum { RV_UNIFORM_INVALID, @@ -200,6 +210,7 @@ typedef enum { RV_COMMAND_OBJ_SHADER, RV_COMMAND_OBJ_PIPELINE, RV_COMMAND_OBJ_TEXTURE, + RV_COMMAND_OBJ_FRAMEBUFFER, RV_COMMAND_UNIFORM_UPDATE, // only allowed during pipeline bind @@ -256,6 +267,7 @@ struct rv_command_t { rv_vbo_t* vbo; rv_ibo_t* ibo; rv_texture_t* tex; + rv_framebuffer_t* framebuffer; void* generic; }; } obj; @@ -282,7 +294,7 @@ struct rv_render_pass_t { rv_render_pass_t* next; rv_command_list_t commands; - rv_render_framebuffer_t* framebuffer; + rv_framebuffer_t* framebuffer; // auto bind framebuffer }; typedef struct { @@ -325,6 +337,10 @@ RV_GLOBAL rv_command_t rv_cmd_uniform_update(rv_uniform_t* uniform, rv_uniform_v 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); +// framebuffer modificatoin helpers +RV_GLOBAL void rv_framebuffer_push_texture(rv_arena* arena, rv_framebuffer_t* fbuf, rv_texture_t* tex); +RV_GLOBAL rv_framebuffer_t* rv_framebuffer_color_simple(rv_arena* arena, rv_vec2 color_size, rv_command_list_t* append_construction); + // 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); diff --git a/src/render/render_helpers.c b/src/render/render_helpers.c @@ -1,6 +1,7 @@ ////////////////////////////////////////////////////////////////// // render_helpers.c +// render pass 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); @@ -8,6 +9,7 @@ RV_GLOBAL rv_render_pass_t* rv_render_push_render_pass(rv_arena* arena, rv_rende return res; } +// command list 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; @@ -44,6 +46,7 @@ RV_GLOBAL rv_command_t* rv_render_copy_commands(rv_arena* arena, rv_command_list return res; } +// ctors RV_GLOBAL rv_command_t rv_cmd_type(rv_command_type_t type) { return (rv_command_t){.type = type}; @@ -51,7 +54,7 @@ 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_assert(type >= RV_COMMAND_OBJ_VERTEX && type <= RV_COMMAND_OBJ_TEXTURE); + rv_assert(type >= RV_COMMAND_OBJ_VERTEX && type <= RV_COMMAND_OBJ_FRAMEBUFFER); return (rv_command_t) { .type = type, @@ -69,6 +72,7 @@ RV_GLOBAL rv_command_t rv_cmd_uniform_update(rv_uniform_t* uniform, rv_uniform_v }; } +// command modification helpers 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_assert(clear->type == RV_COMMAND_CLEAR); @@ -82,6 +86,27 @@ RV_GLOBAL bool32 rv_command_has_pipeline(rv_command_t* command, rv_pipeline_t* p return command->type == RV_COMMAND_OBJ_PIPELINE && command->obj.pipeline == pipeline; } +// framebuffer modificatoin helpers +RV_GLOBAL void rv_framebuffer_push_texture(rv_arena* arena, rv_framebuffer_t* fbuf, rv_texture_t* tex) +{ + rv_texture_node_t* tnode = rv_push_compound(arena, rv_texture_node_t, {.tex = tex}); + rv_llist_stack_push(fbuf->color_attachement_first, tnode); +} + +RV_GLOBAL rv_framebuffer_t* rv_framebuffer_color_simple(rv_arena* arena, rv_vec2 color_size, rv_command_list_t* append_construction) +{ + rv_framebuffer_t* fbuf = rv_push(arena, rv_framebuffer_t); + + rv_texture_t* tex = rv_push_compound(arena, rv_texture_t, {.data = NULL, .size = color_size}); + rv_framebuffer_push_texture(arena, fbuf, tex); + + rv_cmd_push_obj(arena, append_construction, RV_COMMAND_OBJ_TEXTURE, RV_RENDER_OBJ_OP_CREATE, tex); + rv_cmd_push_obj(arena, append_construction, RV_COMMAND_OBJ_FRAMEBUFFER, RV_RENDER_OBJ_OP_CREATE, fbuf); + + return fbuf; +} + +// 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_shader_node_t* res = rv_push_compound(arena, rv_shader_node_t, {.shader = shader});