summaryrefslogtreecommitdiff
path: root/model.cpp
diff options
context:
space:
mode:
authorquou <quou@disroot.org>2025-01-02 14:55:23 +1100
committerquou <quou@disroot.org>2025-01-02 14:55:23 +1100
commit6d4b56258b89ba12bec5e329b81de62284c47ce1 (patch)
tree4888c607aac9ea542c8413988f6ce4f66641607b /model.cpp
parentcb111c1a73fa0b2168b2003120a002bc207bdeed (diff)
model instance system
Diffstat (limited to 'model.cpp')
-rw-r--r--model.cpp240
1 files changed, 162 insertions, 78 deletions
diff --git a/model.cpp b/model.cpp
index d911ac7..6aa6510 100644
--- a/model.cpp
+++ b/model.cpp
@@ -150,24 +150,13 @@ Asset* Model_Loader::load(
Buffer_Flags::copy_dst |
Buffer_Flags::index_buffer
);
- r->mvp = dev->create_buffer(
- filename,
- sizeof(MVP_Cbuffer) * node_count,
- Buffer_Flags::constant_buffer |
- Buffer_Flags::cpu_readwrite
- );
- r->mat = dev->create_buffer(
- filename,
- sizeof(Mat_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);
dev->submit(*ctx);
dev->destroy_bufferi(stage_verts);
dev->destroy_bufferi(stage_indices);
+ r->update_transforms();
return r;
}
@@ -175,8 +164,6 @@ 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);
- dev->destroy_buffer(m->mat);
}
const m4f& Mesh::get_world(Model& m) {
@@ -199,28 +186,124 @@ void Model::update_transforms() {
meshes[i].get_world(*this);
}
-void Model::update_cbuffers(
+void Material_Loader::init(
+ Asset_Arena* texture_arena,
+ Texture_Id dt
+) {
+ default_tex = dt;
+ textures = texture_arena;
+}
+
+Asset* Material_Loader::load(
+ Arena* a,
+ Arena* s,
+ const char* filename,
+ Pack_File* f
+) {
+ Material_File mf;
+ Material* m = (Material*)arena_alloc(a, sizeof *m);
+ auto read_name = [&](int len) {
+ char* r = (char*)arena_alloc(s, len + 1);
+ r[pack_read(f, r, len)] = 0;
+ return r;
+ };
+ auto read_tex = [&](int len) {
+ if (!len) return default_tex;
+ const char* name = read_name(len);
+ auto t = (Texture*)textures->load(name);
+ if (!t)
+ return default_tex;
+ return t->id;
+ };
+ (void)filename;
+ pack_read(f, &mf, sizeof mf);
+ if (
+ mf.magic[0] != 'M' ||
+ mf.magic[1] != 'T' ||
+ mf.magic[2] != 'R' ||
+ mf.magic[3] != 'L'
+ ) return 0;
+ m->metalness = mf.metalness;
+ m->roughness = mf.roughness;
+ m->ao = mf.ao;
+ m->albedo = v3f(
+ (float)((mf.albedo >> 16) & 0xff) / 255.0f,
+ (float)((mf.albedo >> 8) & 0xff) / 255.0f,
+ (float)((mf.albedo) & 0xff) / 255.0f
+ );
+ m->tex.albedo = read_tex(mf.albedo_tex_len);
+ m->tex.ao = read_tex(mf.ao_tex_len);
+ m->tex.metal = read_tex(mf.metal_tex_len);
+ m->tex.rough = read_tex(mf.rough_tex_len);
+ m->tex.normal = read_tex(mf.normal_tex_len);
+ return m;
+}
+
+void Material_Loader::unload(Asset* a) {
+ (void)a;
+}
+
+void Camera::init(float vfov, const v3f& f, const v3f& p) {
+ fov = vfov;
+ forward = f;
+ position = p;
+ near = 0.1f;
+ far = 1000.0f;
+ asp = 1.0f;
+}
+
+m4f Camera::get_view() const {
+ v3f up(0.0f, 1.0f, 0.0f);
+ return m4f::lookat(position, position + forward, up);
+}
+
+m4f Camera::get_proj() const {
+ return m4f::pers(fov, asp, near, far);
+}
+
+void Model_Instance::init(Device* dev, Model* model) {
+ m = model;
+ mvp = dev->create_buffer(
+ "Model instance MVP",
+ sizeof(MVP_Cbuffer) * m->mesh_count,
+ Buffer_Flags::constant_buffer |
+ Buffer_Flags::cpu_readwrite
+ );
+ mat = dev->create_buffer(
+ "Model instance material",
+ sizeof(Mat_Cbuffer) * m->mesh_count,
+ Buffer_Flags::constant_buffer |
+ Buffer_Flags::cpu_readwrite
+ );
+}
+
+void Model_Instance::destroy(Device* dev) {
+ dev->destroy_buffer(mat);
+ dev->destroy_buffer(mvp);
+}
+
+void Model_Instance::update_cbuffers(
Device* dev,
- const m4f& transform,
- const m4f& view_projection
+ const Camera& cam
) {
- int i, c = mesh_count;
- Mesh* meshes = get_meshes();
- MVP_Cbuffer* cbuffers = (MVP_Cbuffer*)dev->map_buffer(
+ int i, c = m->mesh_count;
+ Mesh* meshes = m->get_meshes();
+ MVP_Cbuffer* mvps = (MVP_Cbuffer*)dev->map_buffer(
mvp,
0,
- c * sizeof *cbuffers
+ c * sizeof *mvps
);
Mat_Cbuffer* mats = (Mat_Cbuffer*)dev->map_buffer(
mat,
0,
- c * sizeof *cbuffers
+ c * sizeof *mats
);
+ m4f view_projection = cam.get_proj();
for (i = 0; i < c; i++) {
Mat_Cbuffer& mat = mats[i];
Material& sm = *meshes[i].material;
- cbuffers[i].view_projection = view_projection;
- cbuffers[i].model = transform * meshes[i].world;
+ mvps[i].view_projection = view_projection;
+ mvps[i].model = transform * meshes[i].world;
mat.albedo[0] = sm.albedo.x;
mat.albedo[1] = sm.albedo.y;
mat.albedo[2] = sm.albedo.z;
@@ -232,26 +315,26 @@ void Model::update_cbuffers(
dev->unmap_buffer(mat);
}
-void Model::render(
+void Model_Instance::render(
Device* dev,
Arena* a,
Render_Pass& pass,
Sampler_Id sampler
) {
- int i, c = mesh_count;
- Mesh* meshes = get_meshes();
+ int i, c = m->mesh_count;
+ Mesh* meshes = m->get_meshes();
Context& ctx = dev->get_ctx();
bool depth_only = !pass.colour_count;
for (i = 0; i < c; i++) {
Mesh& mesh = meshes[i];
Shader& shader = dev->get_shader(mesh.shader);
Vertex_Buffer_Binding vbb[] = {{
- .id = vbo,
+ .id = m->vbo,
.offset = 0,
.target = mesh.mesh_binding
}, {}};
Index_Buffer_Binding ibb = {
- .id = ibo,
+ .id = m->ibo,
.offset = 0
};
Draw draw{};
@@ -288,59 +371,60 @@ void Model::render(
}
}
-void Material_Loader::init(
- Asset_Arena* texture_arena,
- Texture_Id dt
+void Model_Scene::init(
+ Arena* arena,
+ int max_instances,
+ Sampler_Id s
) {
- default_tex = dt;
- textures = texture_arena;
+ instances = (Model_Instance*)arena_alloc(arena, max_instances);
+ count = 0;
+ max = max_instances;
+ sampler = s;
}
-Asset* Material_Loader::load(
- Arena* a,
- Arena* s,
- const char* filename,
- Pack_File* f
+Model_Instance* Model_Scene::instantiate(
+ Device* dev,
+ Model* model
) {
- Material_File mf;
- Material* m = (Material*)arena_alloc(a, sizeof *m);
- auto read_name = [&](int len) {
- char* r = (char*)arena_alloc(s, len + 1);
- r[pack_read(f, r, len)] = 0;
- return r;
- };
- auto read_tex = [&](int len) {
- if (!len) return default_tex;
- const char* name = read_name(len);
- auto t = (Texture*)textures->load(name);
- if (!t)
- return default_tex;
- return t->id;
- };
- (void)filename;
- pack_read(f, &mf, sizeof mf);
- if (
- mf.magic[0] != 'M' ||
- mf.magic[1] != 'T' ||
- mf.magic[2] != 'R' ||
- mf.magic[3] != 'L'
- ) return 0;
- m->metalness = mf.metalness;
- m->roughness = mf.roughness;
- m->ao = mf.ao;
- m->albedo = v3f(
- (float)((mf.albedo >> 16) & 0xff) / 255.0f,
- (float)((mf.albedo >> 8) & 0xff) / 255.0f,
- (float)((mf.albedo) & 0xff) / 255.0f
- );
- m->tex.albedo = read_tex(mf.albedo_tex_len);
- m->tex.ao = read_tex(mf.ao_tex_len);
- m->tex.metal = read_tex(mf.metal_tex_len);
- m->tex.rough = read_tex(mf.rough_tex_len);
- m->tex.normal = read_tex(mf.normal_tex_len);
- return m;
+ Model_Instance* instance = &instances[count++];
+ assert(count <= max);
+ instance->init(dev, model);
+ return instance;
}
-void Material_Loader::unload(Asset* a) {
- (void)a;
+void Model_Scene::uninstantiate(
+ Device* dev,
+ Model_Instance* model
+) {
+ int idx = model - instances;
+ int last = count - 1;
+ model->destroy(dev);
+ instances[idx] = instances[last];
+ count = last;
+}
+
+void Model_Scene::update(const Camera& cam, Device* dev) {
+ int i;
+ Model_Instance* instance = instances;
+ for (i = 0; i < count; i++, instance++)
+ instance->update_cbuffers(dev, cam);
+}
+
+void Model_Scene::render(
+ Device* dev,
+ Arena* a,
+ Render_Pass& pass,
+ Sampler_Id sampler
+) {
+ int i;
+ Model_Instance* instance = instances;
+ for (i = 0; i < count; i++, instance++)
+ instance->render(dev, a, pass, sampler);
+}
+
+void Model_Scene::destroy(Device* dev) {
+ int i;
+ Model_Instance* instance = instances;
+ for (i = 0; i < count; i++, instance++)
+ instance->destroy(dev);
}