diff options
author | quou <quou@disroot.org> | 2025-01-02 14:55:23 +1100 |
---|---|---|
committer | quou <quou@disroot.org> | 2025-01-02 14:55:23 +1100 |
commit | 6d4b56258b89ba12bec5e329b81de62284c47ce1 (patch) | |
tree | 4888c607aac9ea542c8413988f6ce4f66641607b | |
parent | cb111c1a73fa0b2168b2003120a002bc207bdeed (diff) |
model instance system
-rw-r--r-- | c2.cpp | 62 | ||||
-rw-r--r-- | model.cpp | 240 | ||||
-rw-r--r-- | model.hpp | 54 |
3 files changed, 239 insertions, 117 deletions
@@ -110,7 +110,9 @@ extern "C" int entrypoint() { Texture* texture; Texture* texture2; Texture_Id default_texture; - Model* monkey; + Model_Instance* monkey, * monkey2; + Model_Scene scene; + Camera camera; Buffer_Id vbo, cbuf; Sampler_Id clamped_linear; C2* app = App::create<C2>("c2"); @@ -140,7 +142,6 @@ extern "C" int entrypoint() { mat_loader.init(&assets, default_texture); register_asset_loader("MODL", &model_loader); register_asset_loader("MTRL", &mat_loader); - monkey = (Model*)assets.load("monkey.mdl"); app->dev = dev; shader = (Shader*)assets.load("triangle.csh"); ui_shader = (Shader*)assets.load("ui.csh"); @@ -166,6 +167,20 @@ extern "C" int entrypoint() { vbo = upload_verts(dev); ui->layout(app->w, app->h); auto fps_label = ui->create_element<UI::Label>(ui->root, ""); + scene.init(app->arena, 32, clamped_linear); + monkey = scene.instantiate( + dev, + (Model*)assets.load("monkey.mdl") + ); + monkey2 = scene.instantiate( + dev, + (Model*)assets.load("monkey.mdl") + ); + camera.init( + 90.0f, + v3f(0.0f, 0.0f, 1.0f), + v3f(0.0f, 0.0f, 0.0f) + ); while (app->running) { Arena frame_arena; init_arena(&frame_arena, per_frame, per_frame_memory_size); @@ -239,13 +254,7 @@ extern "C" int entrypoint() { Render_Pass& pass2 = pb.build_rp(); 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( + monkey->transform = (m4f::translate( m4f::identity(), v3f(0.0f, 0.0f, -5.0f) ) * m4f::rotate( @@ -253,27 +262,19 @@ extern "C" int entrypoint() { rot, raxis )); - monkey->update_transforms(); - monkey->update_cbuffers( - dev, - transform, - projection - ); - ctx.debug_push("depth prepass"); - monkey->render( - dev, - &frame_arena, - depth_prepass, - clamped_linear - ); - ctx.debug_pop(); - ctx.debug_push("forward"); - monkey->render( - dev, - &frame_arena, - pass2, - clamped_linear - ); + monkey2->transform = (m4f::translate( + m4f::identity(), + v3f(2.0f, 0.0f, -7.0f) + ) * m4f::rotate( + m4f::identity(), + rot * 2.0f, + v3f(1.0f, 0.0f, 0.0f) + )); + camera.asp = (float)bb.w / (float)bb.h; + scene.update(camera, dev); + ctx.debug_push("scene"); + scene.render(dev, &frame_arena, depth_prepass, clamped_linear); + scene.render(dev, &frame_arena, pass2, clamped_linear); ctx.debug_pop(); ctx.debug_push("ui"); @@ -286,6 +287,7 @@ extern "C" int entrypoint() { dev->present(); app->end(); } + scene.destroy(dev); ui->destroy(); assets.destroy(); dev->destroy_texture(default_texture); @@ -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); } @@ -27,7 +27,7 @@ struct Mesh { int offset, vbo_offset, count; int parent, mesh_binding, mvp_binding, mat_binding; bool world_dirty; - m4f local, world; + m4f world, local; Shader_Id shader; Material* material; const m4f& get_world(Model& m); @@ -36,8 +36,6 @@ struct Mesh { struct Model : public Asset { Buffer_Id vbo; Buffer_Id ibo; - Buffer_Id mvp; - Buffer_Id mat; int mesh_count; Mesh* get_meshes() { @@ -51,12 +49,6 @@ struct Model : public Asset { const m4f& transform, const m4f& view_projection ); - void render( - Device* dev, - Arena* a, - Render_Pass& pass, - Sampler_Id sampler - ); }; struct Model_Loader : public Asset_Loader { @@ -85,4 +77,48 @@ struct Material_Loader : public Asset_Loader { void unload(Asset* a) override; }; +struct Camera { + float fov, near, far, asp; + v3f forward, position; + void init(float vfov, const v3f& f, const v3f& p); + m4f get_view() const; + m4f get_proj() const; +}; + +struct Model_Instance { + Buffer_Id mvp; + Buffer_Id mat; + m4f transform; + Model* m; + + void init(Device* dev, Model* model); + void destroy(Device* dev); + void update_cbuffers(Device* dev, const Camera& cam); + void render( + Device* dev, + Arena* a, + Render_Pass& pass, + Sampler_Id sampler + ); +}; + +struct Model_Scene { + Model_Instance* instances; + int count, max; + Sampler_Id sampler; + + Model_Instance* instantiate(Device* dev, Model* model); + void uninstantiate(Device* dev, Model_Instance* model); + void destroy(Device* dev); + + void init(Arena* arena, int max_instances, Sampler_Id s); + void update(const Camera& cam, Device* dev); + void render( + Device* dev, + Arena* a, + Render_Pass& pass, + Sampler_Id sampler + ); +}; + #endif |