use alloc::vec::Vec;
use crate::components::{File, FileKind, Material, ProceduralMesh, VoxelChunk, validate};
use crate::ecs::asset_id::AssetId;
use crate::ecs::{EnvironmentMapHandle, MaterialHandle, MeshHandle, PipelineContext};
use super::{EnvironmentMapTable, MaterialTable, MeshTable, ResourceEntry, RuntimeMeshPayloads};
pub fn append_mesh(ctx: &mut PipelineContext, id: AssetId, payload: Vec<u8>) -> MeshHandle {
let handle = build_assigned(ctx) + runtime_count(ctx);
if ctx.resource::<RuntimeMeshPayloads>().is_none() {
ctx.insert_resource(RuntimeMeshPayloads::default());
}
if let Some(payloads) = ctx.resource_mut::<RuntimeMeshPayloads>() {
payloads.push(id, payload);
}
MeshHandle(handle as u32)
}
pub fn append_material(ctx: &mut PipelineContext, material: Material) -> MaterialHandle {
let bytes = postcard::to_allocvec(&validate::material(material))
.expect("a Material is a plain struct; postcard cannot fail on one");
if ctx.resource::<MaterialTable>().is_none() {
ctx.insert_resource(MaterialTable::default());
}
let table = ctx
.resource_mut::<MaterialTable>()
.expect("the table was just ensured");
MaterialHandle(table.append(ResourceEntry {
payload: None,
data_bytes: bytes,
}))
}
pub fn append_environment_map(ctx: &mut PipelineContext, payload: Vec<u8>) -> EnvironmentMapHandle {
if ctx.resource::<EnvironmentMapTable>().is_none() {
ctx.insert_resource(EnvironmentMapTable::default());
}
let table = ctx
.resource_mut::<EnvironmentMapTable>()
.expect("the table was just ensured");
EnvironmentMapHandle(table.append(ResourceEntry::baked(payload)))
}
fn build_assigned(ctx: &PipelineContext) -> usize {
let meshes = ctx.resource::<MeshTable>().map_or(0, MeshTable::len);
let procedural = ctx
.query::<ProceduralMesh>()
.filter(|m| m.locator.is_some())
.count();
let voxels = ctx.query::<VoxelChunk>().count();
let files = ctx
.query::<File>()
.filter(|f| f.kind.as_ref().is_some_and(FileKind::is_mesh))
.count();
meshes + procedural + voxels + files
}
fn runtime_count(ctx: &PipelineContext) -> usize {
ctx.resource::<RuntimeMeshPayloads>()
.map_or(0, RuntimeMeshPayloads::len)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ecs::World;
use alloc::vec;
#[test]
fn installed_resources_take_dense_handles_in_call_order() {
let mut world = World::default();
let mut ctx = world.context();
let first = append_material(&mut ctx, Material::default());
let second = append_material(&mut ctx, Material::default());
assert_eq!((first.0, second.0), (0, 1));
let map = append_environment_map(&mut ctx, vec![1, 2, 3]);
assert_eq!(map.0, 0);
let table = ctx
.resource::<EnvironmentMapTable>()
.expect("the table exists");
assert_eq!(table.0[0].baked_bytes(), Some(&[1u8, 2, 3][..]));
}
#[test]
fn an_installed_mesh_trails_the_builds_blocks() {
let mut world = World::default();
let mut ctx = world.context();
let first = append_mesh(&mut ctx, AssetId(7), vec![1]);
let second = append_mesh(&mut ctx, AssetId(8), vec![2]);
assert_eq!((first.0, second.0), (0, 1));
let payloads = ctx
.resource::<RuntimeMeshPayloads>()
.expect("the payload store exists");
assert_eq!(payloads.len(), 2);
}
}