commit 166d4efb81c22007037c4a37c4882ecb1d75d7f3
parent d8c6245060d253eec65cb1b599f96c252a51027c
Author: Samdal <samdal@protonmail.com>
Date: Tue, 25 Mar 2025 19:42:12 +0100
tex_load
Diffstat:
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);