summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorquou <quou@disroot.org>2024-12-29 13:40:55 +1100
committerquou <quou@disroot.org>2024-12-29 13:41:56 +1100
commit928eba3845d6017d133048cf04c1f816d87941b0 (patch)
tree50f8c52b6f6eb0adbde2666c50ff10dd3920616a
parent7383cfcbe8ade4dce057608e971e8cb7d4b1feb7 (diff)
model hierarchy support
-rw-r--r--c2.cpp53
-rw-r--r--convmodel.c31
-rw-r--r--intermediate/monkey.glbbin69720 -> 80692 bytes
-rw-r--r--intermediate/surface.glsl16
-rw-r--r--model.cpp66
-rw-r--r--model.hpp12
-rw-r--r--src/monkey.blendbin522496 -> 539788 bytes
7 files changed, 135 insertions, 43 deletions
diff --git a/c2.cpp b/c2.cpp
index 573744e..29f3955 100644
--- a/c2.cpp
+++ b/c2.cpp
@@ -152,28 +152,6 @@ extern "C" int entrypoint() {
dev->unmap_buffer(cbuf);
}
- {
- Texture& bb = dev->get_texture(dev->get_backbuffer());
- void* mem;
- mem = dev->map_buffer(cbuf2, 0, sizeof(Config_Buffer2));
- Config_Buffer2* c = (Config_Buffer2*)mem;
- c->projection = m4f::pers(
- 70.0f,
- (float)bb.w / (float)bb.h,
- 0.01f,
- 100.0f
- );
- c->transform = (m4f::translate(
- m4f::identity(),
- v3f(0.0f, 0.0f, -5.0f)
- ) * m4f::rotate(
- m4f::identity(),
- rot,
- raxis
- ));
- dev->unmap_buffer(cbuf2);
- }
-
Pipeline_Builder pb(&frame_arena, dev);
pb.begin_rp();
pb.rp_target(dev->get_backbuffer(), { r, 0x00, 0xff, 0xff });
@@ -207,10 +185,37 @@ extern "C" int entrypoint() {
dev->get_ctx().submit(draw, pip, pass);
pb.begin_rp();
- pb.rp_target(dev->get_backbuffer(), Clear_Mode::restore);
pb.rp_depth_target(dev->get_depth_target(), 1.0f);
+ dev->get_ctx().submit(pb.build_rp());
+
+ pb.begin_rp();
+ pb.rp_target(dev->get_backbuffer(), Clear_Mode::restore);
+ pb.rp_depth_target(dev->get_depth_target(), Clear_Mode::restore);
Render_Pass& pass2 = pb.build_rp();
- monkey->render(dev, &frame_arena, pass2, cbuf2);
+
+ Texture& bb = dev->get_texture(dev->get_backbuffer());
+ m4f projection = m4f::pers(
+ 70.0f,
+ (float)bb.w / (float)bb.h,
+ 0.01f,
+ 100.0f
+ );
+ m4f transform = (m4f::translate(
+ m4f::identity(),
+ v3f(0.0f, 0.0f, -5.0f)
+ ) * m4f::rotate(
+ m4f::identity(),
+ rot,
+ raxis
+ ));
+ monkey->update_transforms();
+ monkey->render(
+ dev,
+ &frame_arena,
+ pass2,
+ transform,
+ projection
+ );
ui->render(&frame_arena, dev->get_backbuffer());
diff --git a/convmodel.c b/convmodel.c
index 5e57fc9..1a09f99 100644
--- a/convmodel.c
+++ b/convmodel.c
@@ -75,6 +75,13 @@ void parse_node_cfg(const cgltf_node* n, Node_Config* cfg) {
const jsmntok_t* t = &toks[i];
if (tcmp(json, "shader", t)) {
cfg->shader = read_str(json, &t[1]);
+ if (string_len(cfg->shader) > 27) {
+ print_err(
+ "Shader name %s too long (max 27 chars).\n",
+ cfg->shader
+ );
+ pbreak(3478);
+ }
i++;
}
}
@@ -216,20 +223,30 @@ void parse_prim(
}
void parse_node_mesh(
+ int parent_index,
const cgltf_node* n,
+ const Node_Config* cfg,
Shader_Attrib* desired,
FILE* outfile
) {
const cgltf_mesh* m = n->mesh;
int i, c = m->primitives_count;
+ char buf[28];
+ float matrix[16];
+ zero(buf, sizeof buf);
+ string_copy(buf, cfg->shader);
vertex_count = 0;
index_count = 0;
for (i = 0; i < c; i++)
parse_prim(&m->primitives[i], desired);
+ cgltf_node_transform_local(n, matrix);
fwrite("MESH", 4, 1, outfile);
+ fwrite(buf, 1, sizeof buf, outfile);
fwrite(&vertex_size, 4, 1, outfile);
fwrite(&index_count, 4, 1, outfile);
fwrite(&vertex_count, 4, 1, outfile);
+ fwrite(&parent_index, 4, 1, outfile);
+ fwrite(matrix, sizeof matrix, 1, outfile);
fwrite(vertex_buffer, 1, vertex_count * vertex_size, outfile);
fwrite(index_buffer, 1, index_count * sizeof *index_buffer, outfile);
}
@@ -336,7 +353,11 @@ int calc_vertex_size(Shader_Attrib* attribs) {
return s;
}
-void parse_node(const cgltf_node* n, FILE* outfile) {
+void parse_node(
+ int parent_index,
+ const cgltf_node* n,
+ FILE* outfile
+) {
Node_Config cfg = { 0 };
if (n->extras.data)
parse_node_cfg(n, &cfg);
@@ -353,7 +374,7 @@ void parse_node(const cgltf_node* n, FILE* outfile) {
vertex_size = calc_vertex_size(desired);
current_vertex = arena_alloc(&arena, vertex_size);
assert(desired != 0);
- parse_node_mesh(n, desired, outfile);
+ parse_node_mesh(parent_index, n, &cfg, desired, outfile);
}
}
@@ -376,8 +397,12 @@ int parse(const char* fname, FILE* outfile) {
c = (int)d->nodes_count;
fwrite(&c, 4, 1, outfile);
for (i = 0; i < c; i++) {
+ const cgltf_node* n = &d->nodes[i];
+ int parent_index = 0;
+ if (n->parent)
+ parent_index = n->parent - d->nodes;
clear_arena(&arena);
- parse_node(&d->nodes[i], outfile);
+ parse_node(parent_index, &d->nodes[i], outfile);
}
cgltf_free(d);
return 0;
diff --git a/intermediate/monkey.glb b/intermediate/monkey.glb
index d7b3665..d199545 100644
--- a/intermediate/monkey.glb
+++ b/intermediate/monkey.glb
Binary files differ
diff --git a/intermediate/surface.glsl b/intermediate/surface.glsl
index 681ec3f..18c13a3 100644
--- a/intermediate/surface.glsl
+++ b/intermediate/surface.glsl
@@ -25,17 +25,17 @@ name: normal
type: vec3
[struct]
-name: Config
+name: MVP
[variable]
-name: transform
+name: model
type: mat4
[variable]
-name: projection
+name: view_projection
type: mat4
[cbuffer]
-name: config_buffer
-type: Config
+name: c_mvp
+type: MVP
stage: vertex
[target]
@@ -48,10 +48,10 @@ type: vec4
void main() {
interpolator.uv = uv;
- interpolator.normal = mat3(config_buffer.transform) * normal;
+ interpolator.normal = mat3(c_mvp.model) * normal;
gl_Position =
- config_buffer.projection *
- config_buffer.transform *
+ c_mvp.view_projection *
+ c_mvp.model *
vec4(position, 1.0);
}
diff --git a/model.cpp b/model.cpp
index 4c3e40f..e8be727 100644
--- a/model.cpp
+++ b/model.cpp
@@ -9,6 +9,11 @@ extern "C" {
#include <string.h>
+struct MVP_Cbuffer {
+ m4f model;
+ m4f view_projection;
+};
+
void Model_Loader::init(Device* device, Asset_Arena* shader_arena) {
dev = device;
shaders = shader_arena;
@@ -55,6 +60,8 @@ Asset* Model_Loader::load(Arena* a, Arena* s, Pack_File* f) {
for (i = 0, coff = 0, icoff = 0, vcoff = 0; i < node_count; i++) {
Mesh& mesh = meshes[i];
int vertex_size, vertex_count;
+ char shader_name[28];
+ Shader* shader;
pack_read(f, magic, 4);
if (
magic[0] != 'M' ||
@@ -65,12 +72,20 @@ Asset* Model_Loader::load(Arena* a, Arena* s, Pack_File* f) {
print_err("Invalid mesh.\n");
return 0;
}
+ pack_read(f, shader_name, sizeof shader_name);
mesh.offset = icoff;
- mesh.parent = 0;
- mesh.shader = ((Shader*)shaders->load("surface.csh"))->id;
+ shader = (Shader*)shaders->load(shader_name);
+ assert(shader != 0);
+ mesh.shader = shader->id;
+ mesh.mvp_binding = shader->descriptor_binding("c_mvp");
+ mesh.mesh_binding = shader->binding_index("mesh");
+ assert(mesh.mvp_binding >= 0);
+ assert(mesh.mesh_binding >= 0);
pack_read(f, &vertex_size, 4);
pack_read(f, &mesh.count, 4);
pack_read(f, &vertex_count, 4);
+ pack_read(f, &mesh.parent, 4);
+ pack_read(f, &mesh.local, 64);
pack_read(f, &verts[coff], vertex_count * vertex_size);
pack_read(f, &indices[icoff], mesh.count * sizeof *indices);
mesh.vbo_offset = vcoff;
@@ -90,6 +105,11 @@ Asset* Model_Loader::load(Arena* a, Arena* s, Pack_File* f) {
Buffer_Flags::copy_dst |
Buffer_Flags::index_buffer
);
+ r->mvp = dev->create_buffer(
+ sizeof(MVP_Cbuffer) * node_count,
+ Buffer_Flags::constant_buffer |
+ Buffer_Flags::cpu_readwrite
+ );
ctx = &dev->acquire();
ctx->copy(r->vbo, stage_verts);
ctx->copy(r->ibo, stage_indices);
@@ -103,24 +123,56 @@ void Model_Loader::unload(Asset* a) {
Model* m = (Model*)a;
dev->destroy_buffer(m->vbo);
dev->destroy_buffer(m->ibo);
+ dev->destroy_buffer(m->mvp);
+}
+
+const m4f& Mesh::get_world(Model& m) {
+ if (world_dirty) {
+ if (parent)
+ world = m.get_meshes()[parent].get_world(m) * local;
+ else
+ world = local;
+ world_dirty = false;
+ }
+ return world;
+}
+
+void Model::update_transforms() {
+ int i, c = mesh_count;
+ Mesh* meshes = get_meshes();
+ for (i = 0; i < c; i++)
+ meshes[i].world_dirty = true;
+ for (i = 0; i < c; i++)
+ meshes[i].get_world(*this);
}
void Model::render(
Device* dev,
Arena* a,
Render_Pass& pass,
- Buffer_Id config
+ const m4f& transform,
+ const m4f& view_projection
) {
int i, c = mesh_count;
Mesh* meshes = get_meshes();
Context& ctx = dev->get_ctx();
+ MVP_Cbuffer* cbuffers = (MVP_Cbuffer*)dev->map_buffer(
+ mvp,
+ 0,
+ c * sizeof *cbuffers
+ );
+ for (i = 0; i < c; i++) {
+ cbuffers[i].view_projection = view_projection;
+ cbuffers[i].model = transform * meshes[i].world;
+ }
+ dev->unmap_buffer(mvp);
for (i = 0; i < c; i++) {
Mesh& mesh = meshes[i];
Shader& shader = dev->get_shader(mesh.shader);
Vertex_Buffer_Binding vbb[] = {{
.id = vbo,
.offset = 0,
- .target = shader.binding_index("mesh")
+ .target = mesh.mesh_binding
}, {}};
Index_Buffer_Binding ibb = {
.id = ibo,
@@ -138,8 +190,10 @@ void Model::render(
pb.depth(true, true, Depth_Mode::less);
pb.shader(mesh.shader);
pb.cbuffer(
- shader.descriptor_binding("config_buffer"),
- config
+ mesh.mvp_binding,
+ mvp,
+ i * sizeof(MVP_Cbuffer),
+ sizeof(MVP_Cbuffer)
);
pb.vertex_format(shader.vf);
Pipeline& pip = pb.build();
diff --git a/model.hpp b/model.hpp
index d4c4be3..0242cd0 100644
--- a/model.hpp
+++ b/model.hpp
@@ -2,17 +2,23 @@
#define model_hpp
#include "asset.hpp"
+#include "maths.hpp"
#include "video.hpp"
+struct Model;
struct Mesh {
int offset, vbo_offset, count;
- int parent;
+ int parent, mesh_binding, mvp_binding;
+ bool world_dirty;
+ m4f local, world;
Shader_Id shader;
+ const m4f& get_world(Model& m);
};
struct Model : public Asset {
Buffer_Id vbo;
Buffer_Id ibo;
+ Buffer_Id mvp;
int mesh_count;
Mesh* get_meshes() {
@@ -20,11 +26,13 @@ struct Model : public Asset {
}
void destroy(Device* dev);
+ void update_transforms();
void render(
Device* dev,
Arena* a,
Render_Pass& pass,
- Buffer_Id config
+ const m4f& transform,
+ const m4f& view_projection
);
};
diff --git a/src/monkey.blend b/src/monkey.blend
index 1c456dd..3f26c50 100644
--- a/src/monkey.blend
+++ b/src/monkey.blend
Binary files differ