Commit: ff39ae97d3787079e0a78305cfb2b90fc4e0b72d
Parent: 719cb1e490abf88c1acd38bbc08ca540a9dd60ca
Author: Randy Palamar
Date:   Fri, 23 May 2025 23:05:21 -0600
basic model loading and drawing
Diffstat:
7 files changed, 94 insertions(+), 69 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,3 +1,5 @@
+*.bin
 *.exe
+*.gltf
 build
 volviewer
diff --git a/common.c b/common.c
@@ -47,7 +47,7 @@ gl_debug_logger(u32 src, u32 type, u32 id, u32 lvl, s32 len, const char *msg, co
 	}
 	stream_append(e, (char *)msg, len);
 	stream_append_byte(e, '\n');
-	ctx->os->write_file(ctx->os->error_handle, stream_to_str8(e));
+	os_write_file(ctx->os->error_handle, stream_to_str8(e));
 	stream_reset(e, 0);
 }
 
@@ -70,7 +70,7 @@ compile_shader(OS *os, Arena a, u32 type, str8 shader, str8 name)
 		glGetShaderInfoLog(sid, len, &out_len, (char *)(buf.data + buf.widx));
 		stream_commit(&buf, out_len);
 		glDeleteShader(sid);
-		os->write_file(os->error_handle, stream_to_str8(&buf));
+		os_write_file(os->error_handle, stream_to_str8(&buf));
 
 		sid = 0;
 	}
@@ -94,7 +94,7 @@ link_program(OS *os, Arena a, u32 *shader_ids, u32 shader_id_count)
 		glGetProgramInfoLog(result, buf.cap - buf.widx, &len, (c8 *)(buf.data + buf.widx));
 		stream_reset(&buf, len);
 		stream_append_byte(&buf, '\n');
-		os->write_file(os->error_handle, stream_to_str8(&buf));
+		os_write_file(os->error_handle, stream_to_str8(&buf));
 		glDeleteProgram(result);
 		result = 0;
 	}
@@ -114,7 +114,7 @@ load_shader(OS *os, Arena arena, str8 vs_text, str8 fs_text, str8 info_name, str
 	if (result) {
 		Stream buf = arena_stream(arena);
 		stream_append_str8s(&buf, str8("loaded: "), info_name, str8("\n"));
-		os->write_file(os->error_handle, stream_to_str8(&buf));
+		os_write_file(os->error_handle, stream_to_str8(&buf));
 		LABEL_GL_OBJECT(GL_PROGRAM, result, label);
 	}
 
@@ -131,7 +131,7 @@ function FILE_WATCH_CALLBACK_FN(reload_shader)
 {
 	ShaderReloadContext *ctx = (typeof(ctx))user_data;
 	str8 header    = push_str8(&tmp, ctx->fragment_header);
-	str8 fragment  = os->read_whole_file(&tmp, (c8 *)path.data);
+	str8 fragment  = os_read_whole_file(&tmp, (c8 *)path.data);
 	fragment.data -= header.len;
 	fragment.len  += header.len;
 	assert(fragment.data == header.data);
@@ -143,6 +143,36 @@ function FILE_WATCH_CALLBACK_FN(reload_shader)
 	return 1;
 }
 
+function RenderModel
+load_render_model(Arena arena, c8 *positions_file_name, c8 *indices_file_name)
+{
+	RenderModel result = {0};
+
+	str8 positions = os_read_whole_file(&arena, positions_file_name);
+	str8 indices   = os_read_whole_file(&arena, indices_file_name);
+
+	result.elements = indices.len / sizeof(u16);
+
+	s32 buffer_size = positions.len + indices.len;
+
+	result.elements_offset = positions.len;
+
+	glCreateBuffers(1, &result.buffer);
+	glNamedBufferStorage(result.buffer, buffer_size, 0, GL_DYNAMIC_STORAGE_BIT);
+	glNamedBufferSubData(result.buffer, 0,             positions.len, positions.data);
+	glNamedBufferSubData(result.buffer, positions.len, indices.len,   indices.data);
+
+	glCreateVertexArrays(1, &result.vao);
+	glVertexArrayVertexBuffer(result.vao, 0, result.buffer, 0, 3 * sizeof(f32));
+	glVertexArrayElementBuffer(result.vao, result.buffer);
+
+	glEnableVertexArrayAttrib(result.vao, 0);
+	glVertexArrayAttribFormat(result.vao,  0, 3, GL_FLOAT, 0, 0);
+	glVertexArrayAttribBinding(result.vao, 0, 0);
+
+	return result;
+}
+
 function void
 key_callback(GLFWwindow *window, s32 key, s32 scancode, s32 action, s32 modifiers)
 {
@@ -190,29 +220,6 @@ init_viewer(ViewerContext *ctx)
 
 	RenderContext *rc = &ctx->model_render_context;
 
-	Vertex vertices[] = {
-		{.position = {{-0.5, -0.5, 0.0}}, .colour = {{1.0, 0.0, 0.0}}},
-		{.position = {{   0,  0.5, 0.0}}, .colour = {{0.0, 1.0, 0.0}}},
-		{.position = {{ 0.5, -0.5, 0.0}}, .colour = {{0.0, 0.0, 1.0}}},
-	};
-
-	glGenVertexArrays(1, &rc->vao);
-	glBindVertexArray(rc->vao);
-	glGenBuffers(1, &rc->vbo);
-	glBindBuffer(GL_ARRAY_BUFFER, rc->vbo);
-	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
-
-	glVertexAttribPointer(0, 3, GL_FLOAT, 0, sizeof(Vertex), (void *)offsetof(Vertex, normal));
-	glVertexAttribPointer(1, 3, GL_FLOAT, 0, sizeof(Vertex), (void *)offsetof(Vertex, position));
-	glVertexAttribPointer(2, 3, GL_FLOAT, 0, sizeof(Vertex), (void *)offsetof(Vertex, texture_coordinate));
-	glVertexAttribPointer(3, 3, GL_FLOAT, 0, sizeof(Vertex), (void *)offsetof(Vertex, colour));
-	glVertexAttribPointer(4, 1, GL_INT,   0, sizeof(Vertex), (void *)offsetof(Vertex, flags));
-	glEnableVertexAttribArray(0);
-	glEnableVertexAttribArray(1);
-	glEnableVertexAttribArray(2);
-	glEnableVertexAttribArray(3);
-	glEnableVertexAttribArray(4);
-
 	RenderTarget *rt = &ctx->output_target;
 	glCreateTextures(GL_TEXTURE_2D, countof(rt->textures), rt->textures);
 	rt->size = (sv2){{RENDER_TARGET_SIZE}};
@@ -228,26 +235,15 @@ init_viewer(ViewerContext *ctx)
 	model_rc->vertex_text = str8(""
 	"#version 460 core\n"
 	"\n"
-	"layout(location = 0) in vec3 v_normal;\n"
-	"layout(location = 1) in vec3 v_position;\n"
-	"layout(location = 2) in vec3 v_texture_coordinate;\n"
-	"layout(location = 3) in vec3 v_colour;\n"
-	"layout(location = 4) in uint v_flags;\n"
-	"\n"
-	"layout(location = 0) out vec3 f_texture_coordinate;\n"
-	"layout(location = 1) out vec3 f_colour;\n"
+	"layout(location = 0) in vec3 v_position;\n"
 	"\n"
 	"void main()\n"
 	"{\n"
-	"\tf_texture_coordinate = v_texture_coordinate;\n"
-	"\tf_colour             = v_colour;\n"
-	"\tgl_Position = vec4(v_position, 1);\n"
+	"\tgl_Position = vec4(0.5 * v_position, 1);\n"
 	"}\n");
 
 	model_rc->fragment_header = str8(""
 	"#version 460 core\n\n"
-	"layout(location = 0) in  vec3 texture_coordinate;\n"
-	"layout(location = 1) in  vec3 colour;\n"
 	"layout(location = 0) out vec4 out_colour;\n\n"
 	"layout(location = " str(VIEWER_RENDER_DYNAMIC_RANGE_LOC) ") uniform float u_db_cutoff = 60;\n"
 	"layout(location = " str(VIEWER_RENDER_THRESHOLD_LOC)     ") uniform float u_threshold = 40;\n"
@@ -314,6 +310,9 @@ init_viewer(ViewerContext *ctx)
 	str8 render_overlay = str8("render_overlay.frag.glsl");
 	reload_shader(&ctx->os, render_overlay, (sptr)overlay_rc, ctx->arena);
 	os_add_file_watch(&ctx->os, &ctx->arena, render_overlay, reload_shader, (sptr)overlay_rc);
+
+	ctx->unit_cube = load_render_model(ctx->arena, "unit_cube_positions.bin",
+	                                   "unit_cube_indices.bin");
 }
 
 function void
@@ -326,8 +325,9 @@ viewer_frame_step(ViewerContext *ctx)
 	glViewport(0, 0, ctx->output_target.size.w, ctx->output_target.size.h);
 
 	glUseProgram(ctx->model_render_context.shader);
-	glBindVertexArray(ctx->model_render_context.vao);
-	glDrawArrays(GL_TRIANGLES, 0, 3);
+	glBindVertexArray(ctx->unit_cube.vao);
+	glDrawElements(GL_TRIANGLES, ctx->unit_cube.elements, GL_UNSIGNED_SHORT,
+	               (void *)ctx->unit_cube.elements_offset);
 
 	////////////////
 	// UI Overlay
diff --git a/main_linux.c b/main_linux.c
@@ -51,10 +51,6 @@ main(void)
 	ViewerContext *ctx = push_struct(&memory, ViewerContext);
 	ctx->arena         = memory;
 
-	#define X(name) ctx->os.name = os_ ## name;
-	OS_FNS
-	#undef X
-
 	ctx->os.file_watch_context.handle = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
 	ctx->os.error_handle              = STDERR_FILENO;
 
diff --git a/main_w32.c b/main_w32.c
@@ -12,11 +12,10 @@ function void
 dispatch_file_watch(OS *os, FileWatchDirectory *fw_dir, u8 *buf, Arena arena)
 {
 	i64 offset = 0;
-	TempArena save_point = {0};
+	Arena start_arena = arena;
 	w32_file_notify_info *fni = (w32_file_notify_info *)buf;
 	do {
-		end_temp_arena(save_point);
-		save_point = begin_temp_arena(&arena);
+		arena = start_arena;
 
 		Stream path = {.data = arena_commit(&arena, KB(1)), .cap = KB(1)};
 
@@ -52,7 +51,7 @@ dispatch_file_watch(OS *os, FileWatchDirectory *fw_dir, u8 *buf, Arena arena)
 }
 
 function void
-clear_io_queue(OS *os, BeamformerInput *input, Arena arena)
+clear_io_queue(OS *os, Arena arena)
 {
 	w32_context *ctx = (w32_context *)os->context;
 
@@ -78,13 +77,9 @@ clear_io_queue(OS *os, BeamformerInput *input, Arena arena)
 extern i32
 main(void)
 {
-	BeamformerCtx   ctx   = {0};
-	BeamformerInput input = {.executable_reloaded = 1};
-	Arena temp_memory = os_alloc_arena((Arena){0}, MB(16));
-
-	#define X(name) ctx.os.name = os_ ## name;
-	OS_FNS
-	#undef X
+	Arena memory       = os_alloc_arena(MB(16));
+	ViewerContext *ctx = push_struct(&memory, ViewerContext);
+	ctx->arena         = memory;
 
 	w32_context w32_ctx = {0};
 	w32_ctx.io_completion_handle = CreateIoCompletionPort(INVALID_FILE, 0, 0, 0);
diff --git a/render_model.frag.glsl b/render_model.frag.glsl
@@ -36,5 +36,5 @@ void main()
 	//v_out_colour = vec4(hsv2rgb(vec3(360 * smp, 0.8, 0.95)), 1);
 	#endif
 
-	out_colour = vec4(colour, 1);
+	out_colour = vec4(1);
 }
diff --git a/repack_gltf.py b/repack_gltf.py
@@ -0,0 +1,34 @@
+import json
+
+def dump_sub_buffer_to_file(gltf, accessor, output):
+    position_attribute = gltf["accessors"][accessor]
+    buffer_view = gltf["bufferViews"][position_attribute["bufferView"]]
+    offset = buffer_view["byteOffset"]
+    length = buffer_view["byteLength"]
+    buffer = buffer_view["buffer"]
+
+    with open(gltf["buffers"][buffer]["uri"], "rb") as input:
+        input.seek(offset, 0)
+        output.write(input.read(length))
+
+def dump_sub_buffer(gltf, accessor, output_name):
+    with open(output_name, "wb") as output:
+        dump_sub_buffer_to_file(gltf, accessor, output)
+
+def main():
+    with open('unit_cube.gltf', 'r') as f:
+        unit_cube = json.load(f)
+
+    assert(len(unit_cube["meshes"]) == 1)
+    mesh = unit_cube["meshes"][0]
+
+    assert(len(mesh["primitives"]) == 1)
+    attributes = mesh["primitives"][0]["attributes"]
+    indices    = mesh["primitives"][0]["indices"]
+
+    dump_sub_buffer(unit_cube, attributes["POSITION"], "unit_cube_positions.bin")
+    dump_sub_buffer(unit_cube, attributes["NORMAL"],   "unit_cube_normals.bin")
+    dump_sub_buffer(unit_cube, indices,                "unit_cube_indices.bin")
+
+if __name__ == '__main__':
+    main()
diff --git a/util.h b/util.h
@@ -257,17 +257,7 @@ typedef OS_WRITE_NEW_FILE_FN(os_write_new_file_fn);
 #define OS_WRITE_FILE_FN(name) b32 name(sptr file, str8 raw)
 typedef OS_WRITE_FILE_FN(os_write_file_fn);
 
-#define OS_FNS \
-	X(add_file_watch)  \
-	X(alloc_arena)     \
-	X(read_whole_file) \
-	X(write_new_file)  \
-	X(write_file)
-
 struct OS {
-#define X(name) os_ ## name ## _fn *name;
-	OS_FNS
-#undef X
 	FileWatchContext file_watch_context;
 	sptr             context;
 	sptr             error_handle;
@@ -286,6 +276,13 @@ typedef struct {
 } RenderTarget;
 
 typedef struct {
+	sptr elements_offset;
+	s32  elements;
+	u32  buffer;
+	u32  vao;
+} RenderModel;
+
+typedef struct {
 	Arena arena;
 	OS    os;
 
@@ -293,6 +290,7 @@ typedef struct {
 	RenderContext overlay_render_context;
 
 	RenderTarget output_target;
+	RenderModel  unit_cube;
 
 	sv2 window_size;