concinnity_core/resource/
install.rs1use 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
15pub 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
31pub 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
48pub 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
60fn 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
76fn 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}