Commit: b2a678ea2cb8f0ded3db53cf9c34a8843a1506d9
Parent: af4c8ec39796779c9fd0b93b87f8b31d216a0037
Author: Randy Palamar
Date:   Sat, 24 May 2025 22:39:20 -0600
textured cube with drawn bounding box
Diffstat:
5 files changed, 113 insertions(+), 43 deletions(-)
diff --git a/common.c b/common.c
@@ -3,6 +3,9 @@
 #include "glad/gl.h"
 #include "GLFW/glfw3.h"
 
+#include <stdio.h>
+#include <stdarg.h>
+
 #define BG_CLEAR_COLOUR    (v4){{0.12, 0.1, 0.1, 1}}
 #define RENDER_TARGET_SIZE 1024, 1024
 
@@ -12,7 +15,10 @@
  * the specified frame rate */
 #define OUTPUT_TIME_SECONDS     8.0f
 #define OUTPUT_FRAME_RATE      30.0f
-#define OUTPUT_BG_CLEAR_COLOUR (v4){{0.0, 0.2, 0.0, 1}}
+#define OUTPUT_BG_CLEAR_COLOUR (v4){{0.0, 0.0, 0.0, 1}}
+
+#define BOUNDING_BOX_COLOUR    0.78, 0.07, 0.20, 1
+#define BOUNDING_BOX_FRACTION  0.005f
 
 #define MODEL_RENDER_MODEL_MATRIX_LOC  (0)
 #define MODEL_RENDER_VIEW_MATRIX_LOC   (1)
@@ -21,14 +27,8 @@
 #define MODEL_RENDER_DYNAMIC_RANGE_LOC (4)
 #define MODEL_RENDER_THRESHOLD_LOC     (5)
 #define MODEL_RENDER_GAMMA_LOC         (6)
-
-typedef struct {
-	v3  normal;
-	v3  position;
-	v3  colour;
-	v3  texture_coordinate;
-	u32 flags;
-} Vertex;
+#define MODEL_RENDER_BB_COLOUR_LOC     (7)
+#define MODEL_RENDER_BB_FRACTION_LOC   (8)
 
 struct gl_debug_ctx {
 	Stream  stream;
@@ -56,6 +56,21 @@ gl_debug_logger(u32 src, u32 type, u32 id, u32 lvl, s32 len, const char *msg, co
 	stream_reset(e, 0);
 }
 
+function void
+stream_printf(Stream *s, const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+	s32 length = vsnprintf(0, 0, format, ap);
+	s->errors |= (s->cap - s->widx) < (length + 1);
+	if (!s->errors) {
+		vsnprintf((char *)(s->data + s->widx), s->cap - s->widx, format, ap);
+		s->widx += length;
+	}
+	va_end(ap);
+}
+
 function u32
 compile_shader(OS *os, Arena a, u32 type, str8 shader, str8 name)
 {
@@ -148,6 +163,33 @@ function FILE_WATCH_CALLBACK_FN(reload_shader)
 	return 1;
 }
 
+function Texture
+load_complex_texture(Arena arena, c8 *file_path, b32 multi_file, u32 width, u32 height, u32 depth)
+{
+	Texture result = {0};
+	glCreateTextures(GL_TEXTURE_3D, 1, &result.texture);
+	glTextureStorage3D(result.texture, 1, GL_RG32F, width, height, depth);
+	glTextureParameteri(result.texture, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
+	glTextureParameteri(result.texture, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
+
+	if (multi_file) {
+		/* NOTE(rnp): assumes single plane */
+		for (u32 i = 0; i < depth; i++) {
+			Stream spath = arena_stream(arena);
+			stream_printf(&spath, file_path, i);
+			str8 path = arena_stream_commit_zero(&arena, &spath);
+			str8 raw  = os_read_whole_file(&arena, (char *)path.data);
+			glTextureSubImage3D(result.texture, 0, 0, 0, i, width, height, 1, GL_RG,
+			                    GL_FLOAT, raw.data);
+		}
+	} else {
+		str8 raw = os_read_whole_file(&arena, file_path);
+		glTextureSubImage3D(result.texture, 0, 0, 0, 0, width, height, depth, GL_RG,
+		                    GL_FLOAT, raw.data);
+	}
+	return result;
+}
+
 function RenderModel
 load_render_model(Arena arena, c8 *positions_file_name, c8 *indices_file_name, c8 *normals_file_name)
 {
@@ -217,7 +259,7 @@ init_viewer(ViewerContext *ctx)
 {
 	ctx->window_size   = (sv2){.w = 640, .h = 640};
 	ctx->camera_radius = 5;
-	ctx->camera_angle  = CAMERA_ELEVATION_ANGLE * PI / 180.0f;
+	ctx->camera_angle  = -CAMERA_ELEVATION_ANGLE * PI / 180.0f;
 
 	if (!glfwInit()) os_fatal(str8("failed to start glfw\n"));
 
@@ -246,6 +288,8 @@ init_viewer(ViewerContext *ctx)
 #endif
 
 	glEnable(GL_DEPTH_TEST);
+	glEnable(GL_BLEND);
+	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
 	RenderContext *rc = &ctx->model_render_context;
 
@@ -268,6 +312,7 @@ init_viewer(ViewerContext *ctx)
 	"layout(location = 1) in vec3 v_normal;\n"
 	"\n"
 	"layout(location = 0) out vec3 f_normal;\n"
+	"layout(location = 1) out vec3 f_texture_coordinate;\n"
 	"\n"
 	"layout(location = " str(MODEL_RENDER_MODEL_MATRIX_LOC) ") uniform mat4 u_model;\n"
 	"layout(location = " str(MODEL_RENDER_VIEW_MATRIX_LOC)  ") uniform mat4 u_view;\n"
@@ -276,6 +321,7 @@ init_viewer(ViewerContext *ctx)
 	"\n"
 	"void main()\n"
 	"{\n"
+	"\tf_texture_coordinate = (v_position + 1) / 2;\n"
 	//"\tf_normal    = normalize(mat3(u_model) * v_normal);\n"
 	"\tf_normal    = v_normal;\n"
 	"\tgl_Position = u_projection * u_view * u_model * vec4(v_position, 1);\n"
@@ -283,30 +329,22 @@ init_viewer(ViewerContext *ctx)
 
 	model_rc->fragment_header = str8(""
 	"#version 460 core\n\n"
-	"layout(location = 0) in  vec3 normal;\n\n"
+	"layout(location = 0) in  vec3 normal;\n"
+	"layout(location = 1) in  vec3 texture_coordinate;\n\n"
 	"layout(location = 0) out vec4 out_colour;\n\n"
 	"layout(location = " str(MODEL_RENDER_DYNAMIC_RANGE_LOC) ") uniform float u_db_cutoff = 60;\n"
 	"layout(location = " str(MODEL_RENDER_THRESHOLD_LOC)     ") uniform float u_threshold = 40;\n"
 	"layout(location = " str(MODEL_RENDER_GAMMA_LOC)         ") uniform float u_gamma     = 1;\n"
 	"layout(location = " str(MODEL_RENDER_LOG_SCALE_LOC)     ") uniform bool  u_log_scale;\n"
+	"layout(location = " str(MODEL_RENDER_BB_COLOUR_LOC)     ") uniform vec4  u_bb_colour   = vec4(" str(BOUNDING_BOX_COLOUR) ");\n"
+	"layout(location = " str(MODEL_RENDER_BB_FRACTION_LOC)   ") uniform float u_bb_fraction = " str(BOUNDING_BOX_FRACTION) ";\n\n"
+	"layout(binding = 0) uniform sampler3D u_texture;\n"
 	"\n#line 1\n");
 
 	str8 render_model = str8("render_model.frag.glsl");
 	reload_shader(&ctx->os, render_model, (sptr)model_rc, ctx->arena);
 	os_add_file_watch(&ctx->os, &ctx->arena, render_model, reload_shader, (sptr)model_rc);
 
-	/* TODO(rnp): think about a reasonable region (probably min_coord -> max_coord + 10%) */
-	f32 n = 1;
-	f32 f = 20;
-	f32 a = -f / (f - n);
-	f32 b = -f * n / (f - n);
-	m4 projection;
-	projection.c[0] = (v4){{1, 0, 0,  0}};
-	projection.c[1] = (v4){{0, 1, 0,  0}};
-	projection.c[2] = (v4){{0, 0, a, -1}};
-	projection.c[3] = (v4){{0, 0, b,  0}};
-	glProgramUniformMatrix4fv(rc->shader, MODEL_RENDER_PROJ_MATRIX_LOC, 1, 0, projection.E);
-
 	rc = &ctx->overlay_render_context;
 	ShaderReloadContext *overlay_rc = push_struct(&ctx->arena, ShaderReloadContext);
 	overlay_rc->render_context = rc;
@@ -326,7 +364,7 @@ init_viewer(ViewerContext *ctx)
 	"\n"
 	"void main()\n"
 	"{\n"
-	"\tf_texture_coordinate = 1 - v_texture_coordinate;\n"
+	"\tf_texture_coordinate = v_texture_coordinate;\n"
 	"\tf_colour             = v_colour;\n"
 	"\tf_flags              = v_flags;\n"
 	"\tgl_Position = vec4(v_position, 0, 1);\n"
@@ -365,6 +403,9 @@ init_viewer(ViewerContext *ctx)
 
 	ctx->unit_cube = load_render_model(ctx->arena, "unit_cube_positions.bin",
 	                                   "unit_cube_indices.bin", "unit_cube_normals.bin");
+
+	c8 *walking_cysts = "./data/test/frame_%02u.bin";
+	ctx->view_texture = load_complex_texture(ctx->arena, walking_cysts, 1, 512, 1024, 64);
 }
 
 function void
@@ -408,6 +449,20 @@ viewer_frame_step(ViewerContext *ctx, f32 dt)
 
 	glUseProgram(ctx->model_render_context.shader);
 
+	/* TODO(rnp): this needs to be set on hot reload */
+	/* TODO(rnp): think about a reasonable region (probably min_coord -> max_coord + 10%) */
+	f32 n = 1;
+	f32 f = 20;
+	f32 a = -f / (f - n);
+	f32 b = -f * n / (f - n);
+	m4 projection;
+	projection.c[0] = (v4){{1, 0, 0,  0}};
+	projection.c[1] = (v4){{0, 1, 0,  0}};
+	projection.c[2] = (v4){{0, 0, a, -1}};
+	projection.c[3] = (v4){{0, 0, b,  0}};
+	glProgramUniformMatrix4fv(ctx->model_render_context.shader, MODEL_RENDER_PROJ_MATRIX_LOC,
+	                          1, 0, projection.E);
+
 	v3 camera = ctx->camera_position;
 	set_camera(ctx->model_render_context.shader, MODEL_RENDER_VIEW_MATRIX_LOC,
 	           camera, v3_normalize(v3_sub(camera, (v3){0})), (v3){{0, 1, 0}});
@@ -421,6 +476,7 @@ viewer_frame_step(ViewerContext *ctx, f32 dt)
 	glProgramUniformMatrix4fv(ctx->model_render_context.shader, MODEL_RENDER_MODEL_MATRIX_LOC,
 	                          1, 0, model_transform.E);
 
+	glBindTextureUnit(0, ctx->view_texture.texture);
 	glBindVertexArray(ctx->unit_cube.vao);
 	glDrawElements(GL_TRIANGLES, ctx->unit_cube.elements, GL_UNSIGNED_SHORT,
 	               (void *)ctx->unit_cube.elements_offset);
diff --git a/main_linux.c b/main_linux.c
@@ -47,7 +47,7 @@ dispatch_file_watch_events(OS *os, Arena arena)
 extern s32
 main(void)
 {
-	Arena memory       = os_alloc_arena(MB(16));
+	Arena memory       = os_alloc_arena(GB(1));
 	ViewerContext *ctx = push_struct(&memory, ViewerContext);
 	ctx->arena         = memory;
 
diff --git a/main_w32.c b/main_w32.c
@@ -77,7 +77,7 @@ clear_io_queue(OS *os, Arena arena)
 extern i32
 main(void)
 {
-	Arena memory       = os_alloc_arena(MB(16));
+	Arena memory       = os_alloc_arena(GB(1));
 	ViewerContext *ctx = push_struct(&memory, ViewerContext);
 	ctx->arena         = memory;
 
diff --git a/render_model.frag.glsl b/render_model.frag.glsl
@@ -1,5 +1,4 @@
 /* See LICENSE for license details. */
-//layout(binding = 0) uniform sampler3D u_out_data_tex;
 
 /* input:  h [0,360] | s,v [0, 1] *
  * output: rgb [0,1]              */
@@ -10,19 +9,19 @@ vec3 hsv2rgb(vec3 hsv)
 	return hsv.z - hsv.z * hsv.y * k;
 }
 
-void main()
+bool bounding_box_test(vec3 coord, float p)
 {
-	#if 0
-	ivec3 out_data_dim = textureSize(u_out_data_tex, 0);
-
-	//vec2 min_max = texelFetch(u_out_data_tex, ivec3(0), textureQueryLevels(u_out_data_tex) - 1).xy;
-
-	/* TODO(rnp): select between x and y and specify slice */
-	ivec2 coord     = ivec2(fragment_texture_coordinate * vec2(out_data_dim.xz));
-	ivec3 smp_coord = ivec3(coord.x, out_data_dim.y / 2, coord.y);
-	float smp       = length(texelFetch(u_out_data_tex, smp_coord, 0).xy);
+	bool result = false;
+	bvec3 tests = bvec3(1 - step(vec3(p), coord) * step(coord, vec3(1 - p)));
+	if ((tests.x && tests.y) || (tests.x && tests.z) || (tests.y && tests.z))
+		result = true;
+	return result;
+}
 
-	float threshold_val = pow(10.0f, u_threshold / 20.0f);
+void main()
+{
+	float smp = length(texture(u_texture, texture_coordinate).xy);
+	float threshold_val = pow(10.0f, (u_threshold + 13) / 20.0f);
 	smp = clamp(smp, 0.0f, threshold_val);
 	smp = smp / threshold_val;
 	smp = pow(smp, u_gamma);
@@ -33,8 +32,13 @@ void main()
 		smp = 1 - smp;
 	}
 
-	//v_out_colour = vec4(hsv2rgb(vec3(360 * smp, 0.8, 0.95)), 1);
-	#endif
+	//out_colour = vec4(abs(normal), 1);
+	//out_colour = vec4(1, 1, 1, smp);
+	//out_colour = vec4(smp * abs(normal), 1);
 
-	out_colour = vec4(abs(normal), 1);
+	if (bounding_box_test(texture_coordinate, u_bb_fraction)) {
+		out_colour = u_bb_colour;
+	} else {
+		out_colour = vec4(smp, smp, smp, 1);
+	}
 }
diff --git a/util.h b/util.h
@@ -72,8 +72,8 @@
 #define static_assert _Static_assert
 
 /* NOTE: garbage to get the prepocessor to properly stringize the value of a macro */
-#define str_(x) #x
-#define str(x) str_(x)
+#define str_(...) #__VA_ARGS__
+#define str(...) str_(__VA_ARGS__)
 
 #define countof(a)       (sizeof(a) / sizeof(*a))
 #define ARRAY_COUNT(a)   (sizeof(a) / sizeof(*a))
@@ -269,6 +269,13 @@ struct OS {
 };
 
 typedef struct {
+	u32 texture;
+	u32 width;
+	u32 height;
+	u32 depth;
+} Texture;
+
+typedef struct {
 	u32 shader;
 	u32 vao;
 	u32 vbo;
@@ -303,6 +310,9 @@ typedef struct {
 	f32 camera_angle;
 	f32 camera_radius;
 	v3  camera_position;
+
+	Texture view_texture;
+
 	b32 should_exit;
 
 	void *window;