revolver

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

commit 166d4efb81c22007037c4a37c4882ecb1d75d7f3
parent d8c6245060d253eec65cb1b599f96c252a51027c
Author: Samdal <samdal@protonmail.com>
Date:   Tue, 25 Mar 2025 19:42:12 +0100

tex_load

Diffstat:
Mbuild.sh | 5+++--
Aexamples/chad.jpeg | 0
Mexamples/simple_texture.c | 4++--
Aexamples/tex_load.c | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/platform/gfx/glfw.c | 17+++++++++++------
Msrc/platform/gfx/platform_gfx.h | 1+
Msrc/platform/gfx/xcb_impl.c | 23++++++++++++++---------
Msrc/platform/platform_arena.h | 1+
Msrc/platform/platform_core.c | 2+-
Msrc/platform/platform_core.h | 4+++-
Msrc/platform/platform_string.c | 3+++
Msrc/render/impl/opengl.c | 16++--------------
Msrc/render/render.h | 7++-----
Msrc/render/render_helpers.c | 25+++++++++++++++++++++++++
Msrc/util/util_inc.c | 1+
Msrc/util/util_inc.h | 1+
Asrc/util/util_tex_load.c | 35+++++++++++++++++++++++++++++++++++
Asrc/util/util_tex_load.h | 5+++++
18 files changed, 187 insertions(+), 40 deletions(-)

diff --git a/build.sh b/build.sh @@ -16,6 +16,7 @@ do "instancing") sources=(./examples/instancing.c) ;; "bump_cache") sources=(./examples/bump_cache.c) ;; "idraw2d") sources=(./examples/idraw2d.c) ;; + "tex_load") sources=(./examples/tex_load.c) ;; esac done @@ -37,7 +38,7 @@ compiler_flags=( -Isrc/ - #-DRV_WIN_X11=0 + -DRV_WIN_X11=0 -D_GNU_SOURCE=1 ) common_flags=( @@ -46,7 +47,7 @@ common_flags=( linker_flags=( -lm -lxcb -lxcb-xkb -lEGL -lGL - #-lX11 -lXi + -lX11 -lXi -fuse-ld=mold ) diff --git a/examples/chad.jpeg b/examples/chad.jpeg Binary files differ. diff --git a/examples/simple_texture.c b/examples/simple_texture.c @@ -82,8 +82,8 @@ int main(void) { // 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_pipeline_push_vattr(arena, pip, RV_VATTR_TYPE_FLOAT2, 0, 0); + rv_pipeline_push_vattr(arena, pip, RV_VATTR_TYPE_FLOAT2, 0, 0); rv_uniform_t* u_tex = rv_pipeline_push_uniform(arena, pip, S("u_tex"), RV_UNIFORM_TEX); // instructions to create render objects diff --git a/examples/tex_load.c b/examples/tex_load.c @@ -0,0 +1,77 @@ +////////////////////////////////////////////////////////////////// +// tex_load.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_arena* arena = rv_arena_alloc(); + rv_render_pass_list_t rpass_list = {0}; + + rv_texture_t* tex = rv_tex_load_from_file(arena, S("chad.jpeg"), false); + + rv_render_pass_t* create_rpass = rv_render_push_render_pass(arena, &rpass_list); + + rv_cmd_push_obj(arena, &create_rpass->commands, RV_COMMAND_OBJ_TEXTURE, RV_RENDER_OBJ_OP_CREATE, tex); + + rv_idraw2d_ctx rvi = {0}; + rvi2d_create(&rvi, arena, &create_rpass->commands); + rvi2d_camera(&rvi, rv_v2(1, 1)); + + 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); + + bool32 vsync = true; + + // 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)); + vsync = false; + } + } + + { // 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 image + f32 screen_ratio = rv_window_size(window).x / rv_window_size(window).y; + f32 image_ratio = tex->size.x / tex->size.y; + rvi2d_tex(&rvi, tex); + if (screen_ratio > image_ratio) { + rvi2d_rect(&rvi, rv_rct(0, 0, image_ratio/screen_ratio, 1), RV_COLOR_WHITE); + } else { + rvi2d_rect(&rvi, rv_rct(0, 0, 1, screen_ratio/image_ratio), RV_COLOR_WHITE); + } + rvi2d_tex(&rvi, NULL); + } + + rvi2d_draw_and_reset(&rvi, scratch.arena, &rpass->commands); + + if (window) { // render screen + rv_window_render_commit(window, &rpass_list); + } + rv_scratch_end(scratch); + rpass_list = (rv_render_pass_list_t){0}; + } +exit_program: + + return 0; +} diff --git a/src/platform/gfx/glfw.c b/src/platform/gfx/glfw.c @@ -395,9 +395,10 @@ RV_GLOBAL rv_window_handle_t* rv_create_window(rv_window_desc_t desc) glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); #endif + glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); } - { + { // make window rv_temp_arena scratch = rv_scratch_begin(0, 0); rv_str8 title = rv_str8_copy(scratch.arena, desc.name); @@ -415,11 +416,15 @@ RV_GLOBAL rv_window_handle_t* rv_create_window(rv_window_desc_t desc) glfwMakeContextCurrent(res->window); - glfwSetFramebufferSizeCallback(res->window, rv_framebuffer_size_callback); - glfwSetKeyCallback(res->window, rv_key_callback); - glfwSetCharCallback(res->window, rv_character_callback); - glfwSetMouseButtonCallback(res->window, rv_mouse_button_callback); - glfwSetCursorEnterCallback(res->window, rv_cursor_enter_callback); + glfwSwapInterval(desc.vsync ? 1 : 0); + + { // event callbacks + glfwSetFramebufferSizeCallback(res->window, rv_framebuffer_size_callback); + glfwSetKeyCallback(res->window, rv_key_callback); + glfwSetCharCallback(res->window, rv_character_callback); + glfwSetMouseButtonCallback(res->window, rv_mouse_button_callback); + glfwSetCursorEnterCallback(res->window, rv_cursor_enter_callback); + } #if RV_RENDER_OPENGL if (!glad_loaded) { diff --git a/src/platform/gfx/platform_gfx.h b/src/platform/gfx/platform_gfx.h @@ -12,6 +12,7 @@ typedef struct rv_event_t rv_event_t; typedef struct { rv_str8 name; bool32 attach_render; + bool32 vsync; rv_rect rect; } rv_window_desc_t; diff --git a/src/platform/gfx/xcb_impl.c b/src/platform/gfx/xcb_impl.c @@ -80,7 +80,7 @@ RV_INTERNAL struct { } egl_context; -RV_GLOBAL void* egl_attach(xcb_window_t window, xcb_connection_t* connection) +RV_GLOBAL void* egl_attach(xcb_window_t window, xcb_connection_t* connection, bool32 vsync) { { // make egl context if (!egl_context.is_init) { @@ -166,8 +166,6 @@ RV_GLOBAL void* egl_attach(xcb_window_t window, xcb_connection_t* connection) } } - eglSwapInterval(egl_context.egl_display, 1); - EGLint attr[] = { EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_LINEAR, // or use EGL_GL_COLORSPACE_SRGB for sRGB framebuffer EGL_RENDER_BUFFER, EGL_BACK_BUFFER, @@ -179,11 +177,17 @@ RV_GLOBAL void* egl_attach(xcb_window_t window, xcb_connection_t* connection) rv_abort_msg(1, "Cannot create EGL surface"); } + eglMakeCurrent(egl_context.egl_display, surface, surface, egl_context.egl_context); + + if (vsync) + eglSwapInterval(egl_context.egl_display, 1); + else + eglSwapInterval(egl_context.egl_display, 0); + { // load opengl functions RV_LOCAL_PERSIST bool32 glad_loaded = false; if (!glad_loaded) { glad_loaded = true; - eglMakeCurrent(egl_context.egl_display, surface, surface, egl_context.egl_context); gladLoadGLLoader((GLADloadproc)eglGetProcAddress); } } @@ -543,7 +547,7 @@ RV_GLOBAL rv_window_handle_t* rv_create_window(rv_window_desc_t desc) if (desc.attach_render) { #if RV_RENDER_OPENGL - res->render = egl_attach(res->window_id, xcb_context.connection); + res->render = egl_attach(res->window_id, xcb_context.connection, desc.vsync); #endif } @@ -919,11 +923,12 @@ RV_GLOBAL rv_event_t* rv_get_events(rv_arena* arena, rv_event_flags_t flags) } 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); - if (new_ev.window_resize) { - if (new_ev.window_resize->last_size.x != conf_event->width || new_ev.window_resize->last_size.y != conf_event->height) { + rv_window_handle_t* w = xcb_get_window(conf_event->event); + new_ev.window_resize = w; + if (w) { + if (w->last_size.x != conf_event->width || w->last_size.y != conf_event->height) { new_ev.type = RV_EVENT_WINDOW_RESIZE; - new_ev.window_resize->last_size = rv_v2(conf_event->width, conf_event->height); + w->last_size = rv_v2(conf_event->width, conf_event->height); } } } break; diff --git a/src/platform/platform_arena.h b/src/platform/platform_arena.h @@ -92,6 +92,7 @@ RV_INTERNAL void rv_temp_end(rv_temp_arena temp); #define rv_push_array(a, T, c) rv_push_array_aligned(a, T, c, rv_alignof(T)) #define rv_push_array_compound(a, T, c, ...) rv_mem_copy(rv_push_array_no_zero_aligned(a, T, c, rv_alignof(T)), (T[c])__VA_ARGS__, sizeof(T)*c) +#define rv_push_array_copy(a, T, c, v) rv_mem_copy(rv_push_array_no_zero_aligned(a, T, c, rv_alignof(T)), (T*)v, sizeof(T) * (c)) // Scratch RV_GLOBAL rv_arena* rv_scratch_begin_(rv_arena **conflicts, u64 count); diff --git a/src/platform/platform_core.c b/src/platform/platform_core.c @@ -24,7 +24,7 @@ RV_GLOBAL void rv_abort_msg_(const char* file, const char* func, s32 line_no, s3 #endif } -f64 rv_time(void) { +RV_GLOBAL f64 rv_time(void) { f64 res = 0; #if RV_OS_WINDOWS diff --git a/src/platform/platform_core.h b/src/platform/platform_core.h @@ -27,6 +27,8 @@ #endif #include <stdio.h> +#include <errno.h> +#include <string.h> #include <stdlib.h> #include <time.h> #include <stdarg.h> @@ -92,7 +94,7 @@ #define rv_abort_msg(exit_code, ...) rv_abort_msg_(__FILE__, __FUNCTION__, __LINE__, exit_code, __VA_ARGS__) RV_GLOBAL void rv_abort_msg_(const char* file, const char* func, s32 line_no, s32 exit_code, const char* message, ...); -f64 rv_time(void); +RV_GLOBAL f64 rv_time(void); ////////////////////////////////////////////////////////////////// diff --git a/src/platform/platform_string.c b/src/platform/platform_string.c @@ -309,6 +309,9 @@ RV_GLOBAL rv_str8 rv_read_file(rv_arena* arena, rv_str8 filename) fread(buffer, 1, len, fp); fclose(fp); + } else { + fprintf(stderr, "rv_read_file, unable to rad file '%.*s' (%d: %s)", rv_s8v(filename), errno, strerror(errno)); + rv_unreachable(); } return rv_s8(buffer, len); diff --git a/src/render/impl/opengl.c b/src/render/impl/opengl.c @@ -109,25 +109,13 @@ RV_GLOBAL void rv_window_render_commit(rv_window_handle_t* window, rv_render_pas glBindVertexArray(ogl_ctx.vao); - #define OGL_DEFAULT_TEX_ROW_COL_CT 6 - // Generate default texture (checkered purple/black texture) - rv_color_t c0 = RV_COLOR_BLACK; - rv_color_t c1 = RV_COLOR_PURPLE; - rv_color_t* pixels = rv_push_array(scratch.arena, rv_color_t, OGL_DEFAULT_TEX_ROW_COL_CT * OGL_DEFAULT_TEX_ROW_COL_CT); - for (uint32_t r = 0; r < OGL_DEFAULT_TEX_ROW_COL_CT; ++r) { - for (uint32_t c = 0; c < OGL_DEFAULT_TEX_ROW_COL_CT; ++c) { - const bool32 re = (r % 2) == 0; - const bool32 ce = (c % 2) == 0; - uint32_t idx = r * OGL_DEFAULT_TEX_ROW_COL_CT + c; - pixels[idx] = (re && ce) ? c0 : (re) ? c1 : (ce) ? c1 : c0; - } - } rv_render_pass_t* extra_initial_rpass = rv_push(scratch.arena, rv_render_pass_t); extra_initial_rpass->next = initial_rpass; initial_rpass = extra_initial_rpass; - ogl_ctx.default_tex = (rv_texture_t){.data = pixels, .size = rv_v2s(OGL_DEFAULT_TEX_ROW_COL_CT)}; + ogl_ctx.default_tex = (rv_texture_t){}; + rv_get_default_texture(&ogl_ctx.default_tex.data, &ogl_ctx.default_tex.size); rv_cmd_push_obj(scratch.arena, &extra_initial_rpass->commands, RV_COMMAND_OBJ_TEXTURE, RV_RENDER_OBJ_OP_CREATE, &ogl_ctx.default_tex); } diff --git a/src/render/render.h b/src/render/render.h @@ -334,6 +334,8 @@ typedef struct { ////////////////////////////////////////////////////////////////// // Helpers +RV_GLOBAL void rv_get_default_texture(void** data_out, rv_vec2* size_out); + // render pass RV_GLOBAL rv_render_pass_t* rv_render_push_render_pass(rv_arena* arena, rv_render_pass_list_t* rpass_list); @@ -381,8 +383,3 @@ RV_GLOBAL rv_vattr_t* rv_pipeline_push_vattr(rv_arena* arena, rv_pipeline_ ////////////////////////////////////////////////////////////////// // Submit RV_GLOBAL void rv_window_render_commit(rv_window_handle_t* window, rv_render_pass_list_t* passes); - -////////////////////////////////////////////////////////////////// -// Util - -RV_GLOBAL void rv_tex_load_from_file(rv_str8 filename); diff --git a/src/render/render_helpers.c b/src/render/render_helpers.c @@ -127,3 +127,28 @@ RV_GLOBAL rv_vattr_t* rv_pipeline_push_vattr(rv_arena* arena, rv_pipeline_ rv_llist_queue_push(pipeline->vattr_first, pipeline->vattr_last, res); return res; } + +RV_GLOBAL void rv_get_default_texture(void** data_out, rv_vec2* size_out) +{ +#define RV_DEFAULT_TEX_ROW_COL_CT 6 + + RV_LOCAL_PERSIST rv_color_t pixels[RV_DEFAULT_TEX_ROW_COL_CT * RV_DEFAULT_TEX_ROW_COL_CT]; + RV_LOCAL_PERSIST bool32 loaded = false; + + if (!loaded) { + // Generate default texture (checkered purple/black texture) + rv_color_t c0 = RV_COLOR_BLACK; + rv_color_t c1 = RV_COLOR_PURPLE; + for (s32 r = 0; r < RV_DEFAULT_TEX_ROW_COL_CT; ++r) { + for (s32 c = 0; c < RV_DEFAULT_TEX_ROW_COL_CT; ++c) { + const bool32 re = (r % 2) == 0; + const bool32 ce = (c % 2) == 0; + s32 idx = r * RV_DEFAULT_TEX_ROW_COL_CT + c; + pixels[idx] = (re && ce) ? c0 : (re) ? c1 : (ce) ? c1 : c0; + } + } + } + + *data_out = pixels; + *size_out = rv_v2(RV_DEFAULT_TEX_ROW_COL_CT, RV_DEFAULT_TEX_ROW_COL_CT); +} diff --git a/src/util/util_inc.c b/src/util/util_inc.c @@ -5,4 +5,5 @@ #if RV_WIN_ENABLED #include "util_idraw2d.c" + #include "util_tex_load.c" #endif diff --git a/src/util/util_inc.h b/src/util/util_inc.h @@ -5,4 +5,5 @@ #if RV_WIN_ENABLED #include "util_idraw2d.h" + #include "util_tex_load.h" #endif diff --git a/src/util/util_tex_load.c b/src/util/util_tex_load.c @@ -0,0 +1,35 @@ +////////////////////////////////////////////////////////////////// +// util_tex_load.c + +#define STB_IMAGE_IMPLEMENTATION +#include "../external/stb_image.h" + +RV_GLOBAL rv_texture_t* rv_tex_load_from_file(rv_arena* arena, rv_str8 filename, bool32 vertical_flip_on_load) +{ + rv_temp_arena scratch = rv_scratch_begin(0, 0); + rv_str8 f = rv_read_file(scratch.arena, filename); + rv_texture_t* res = rv_tex_load_from_memory(arena, f, vertical_flip_on_load); + rv_scratch_end(scratch); + + return res; +} + +RV_GLOBAL rv_texture_t* rv_tex_load_from_memory(rv_arena* arena, rv_str8 memory, bool32 vertical_flip_on_load) +{ + rv_texture_t* res = rv_push(arena, rv_texture_t); + + s32 num_comps, width, height; + stbi_set_flip_vertically_on_load(vertical_flip_on_load); + void* data = stbi_load_from_memory((const stbi_uc*)memory.str, memory.len, &width, &height, &num_comps, STBI_rgb_alpha); + + if (data) { + res->size = rv_v2(width, height); + res->data = rv_mem_copy(rv_arena_push(arena, 4 * width * height, 8), data, 4 * width * height); + } else { + // set default texture... + rv_unreachable(); + rv_get_default_texture(&res->data, &res->size); + } + + return res; +} diff --git a/src/util/util_tex_load.h b/src/util/util_tex_load.h @@ -0,0 +1,5 @@ +////////////////////////////////////////////////////////////////// +// util_tex_load.h + +RV_GLOBAL rv_texture_t* rv_tex_load_from_file(rv_arena* arena, rv_str8 filename, bool32 vertical_flip_on_load); +RV_GLOBAL rv_texture_t* rv_tex_load_from_memory(rv_arena* areana, rv_str8 memory, bool32 vertical_flip_on_load);