Skip to main content

concinnity_core/resource/
install.rs

1//! Installing a baked resource into a running world: the payload or bytes go
2//! where the owning system reads them, and the caller gets the dense handle a
3//! component references them by. Shared by the world-start defaults pass and
4//! by [`World`](crate::ecs::World)'s data-entry methods, so a resource the
5//! engine injects and one an application hands over land identically.
6
7use alloc::vec::Vec;
8
9use crate::components::{File, FileKind, Material, ProceduralMesh, VoxelChunk, validate};
10use crate::ecs::asset_id::AssetId;
11use crate::ecs::{EnvironmentMapHandle, MaterialHandle, MeshHandle, PipelineContext};
12
13use super::{EnvironmentMapTable, MaterialTable, MeshTable, ResourceEntry, RuntimeMeshPayloads};
14
15/// Record `payload` as `id`'s geometry and return the handle it lands on.
16///
17/// A mesh installed here trails the build's four compiled blocks (the build
18/// assigns Mesh, ProceduralMesh, VoxelChunk, and File blocks in that order),
19/// so it moves no handle a compiled world baked into a Prop.
20pub fn append_mesh(ctx: &mut PipelineContext, id: AssetId, payload: Vec<u8>) -> MeshHandle {
21    let handle = build_assigned(ctx) + runtime_count(ctx);
22    if ctx.resource::<RuntimeMeshPayloads>().is_none() {
23        ctx.insert_resource(RuntimeMeshPayloads::default());
24    }
25    if let Some(payloads) = ctx.resource_mut::<RuntimeMeshPayloads>() {
26        payloads.push(id, payload);
27    }
28    MeshHandle(handle as u32)
29}
30
31/// Install `material` into the world's material table and return its handle.
32/// A material is a data resource: its clamped parameters are the whole entry.
33pub fn append_material(ctx: &mut PipelineContext, material: Material) -> MaterialHandle {
34    let bytes = postcard::to_allocvec(&validate::material(material))
35        .expect("a Material is a plain struct; postcard cannot fail on one");
36    if ctx.resource::<MaterialTable>().is_none() {
37        ctx.insert_resource(MaterialTable::default());
38    }
39    let table = ctx
40        .resource_mut::<MaterialTable>()
41        .expect("the table was just ensured");
42    MaterialHandle(table.append(ResourceEntry {
43        payload: None,
44        data_bytes: bytes,
45    }))
46}
47
48/// Install a baked IBL `payload` into the world's environment-map table and
49/// return its handle. The renderer lights with the map at handle 0.
50pub fn append_environment_map(ctx: &mut PipelineContext, payload: Vec<u8>) -> EnvironmentMapHandle {
51    if ctx.resource::<EnvironmentMapTable>().is_none() {
52        ctx.insert_resource(EnvironmentMapTable::default());
53    }
54    let table = ctx
55        .resource_mut::<EnvironmentMapTable>()
56        .expect("the table was just ensured");
57    EnvironmentMapHandle(table.append(ResourceEntry::baked(payload)))
58}
59
60// How many mesh handles the build handed out: the four compiled blocks,
61// counted the way the renderer enumerates them.
62fn build_assigned(ctx: &PipelineContext) -> usize {
63    let meshes = ctx.resource::<MeshTable>().map_or(0, MeshTable::len);
64    let procedural = ctx
65        .query::<ProceduralMesh>()
66        .filter(|m| m.locator.is_some())
67        .count();
68    let voxels = ctx.query::<VoxelChunk>().count();
69    let files = ctx
70        .query::<File>()
71        .filter(|f| f.kind.as_ref().is_some_and(FileKind::is_mesh))
72        .count();
73    meshes + procedural + voxels + files
74}
75
76// Geometry already installed at runtime, which the trailing block counts
77// before it.
78fn runtime_count(ctx: &PipelineContext) -> usize {
79    ctx.resource::<RuntimeMeshPayloads>()
80        .map_or(0, RuntimeMeshPayloads::len)
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86    use crate::ecs::World;
87    use alloc::vec;
88
89    #[test]
90    fn installed_resources_take_dense_handles_in_call_order() {
91        let mut world = World::default();
92        let mut ctx = world.context();
93        let first = append_material(&mut ctx, Material::default());
94        let second = append_material(&mut ctx, Material::default());
95        assert_eq!((first.0, second.0), (0, 1));
96
97        let map = append_environment_map(&mut ctx, vec![1, 2, 3]);
98        assert_eq!(map.0, 0);
99        let table = ctx
100            .resource::<EnvironmentMapTable>()
101            .expect("the table exists");
102        assert_eq!(table.0[0].baked_bytes(), Some(&[1u8, 2, 3][..]));
103    }
104
105    #[test]
106    fn an_installed_mesh_trails_the_builds_blocks() {
107        let mut world = World::default();
108        let mut ctx = world.context();
109        let first = append_mesh(&mut ctx, AssetId(7), vec![1]);
110        let second = append_mesh(&mut ctx, AssetId(8), vec![2]);
111        assert_eq!((first.0, second.0), (0, 1));
112        let payloads = ctx
113            .resource::<RuntimeMeshPayloads>()
114            .expect("the payload store exists");
115        assert_eq!(payloads.len(), 2);
116    }
117}