use concinnity_core::ecs::ResourceRecord;
pub use concinnity_core::resource::{
AudioClipTable, ColorLutTable, EnvironmentMapTable, FontTable, MaterialTable, MeshTable,
ResourceEntry, SkinnedMeshTable, TextureTable,
};
#[derive(Debug, Clone, Default)]
pub struct TextureSource {
pub name_id: u32,
pub source: String,
pub image_index: u32,
}
#[derive(Debug, Clone, Default)]
pub struct TextureSources(pub Vec<TextureSource>);
#[derive(Debug, Clone, Default)]
pub struct ColorLutSources(pub Option<String>);
#[derive(Debug, Clone, Default)]
pub struct EnvironmentMapSourceInfo {
pub source: String,
pub prefilter_face_size: u32,
pub irradiance_face_size: u32,
pub prefilter_samples: u32,
pub prefilter_clamp: f32,
}
#[derive(Debug, Clone, Default)]
pub struct EnvironmentMapSources(pub Option<EnvironmentMapSourceInfo>);
#[derive(Debug, Clone, Default)]
pub struct MeshSource {
pub source: String,
pub primitive_index: u32,
pub lod_levels: u32,
pub lod_distances: Vec<f32>,
}
#[derive(Debug, Clone, Default)]
pub struct MeshSources(pub Vec<MeshSource>);
#[derive(Debug, Clone, Default)]
pub struct MaterialNames(pub Vec<u32>);
pub fn install_resource_tables(world: &mut crate::ecs::World, records: &mut [ResourceRecord]) {
log_resource_footprint(records);
world.insert_resource(AudioClipTable::from_records(records));
world.insert_resource(TextureTable::from_records(records));
world.insert_resource(ColorLutTable::from_records(records));
world.insert_resource(EnvironmentMapTable::from_records(records));
world.insert_resource(FontTable::from_records(records));
world.insert_resource(MaterialTable::from_records(records));
world.insert_resource(MeshTable::from_records(records));
world.insert_resource(SkinnedMeshTable::from_records(records));
}
fn log_resource_footprint(records: &[ResourceRecord]) {
if records.is_empty() {
return;
}
let total: u64 = records
.iter()
.map(|r| r.data_bytes.len() as u64 + r.payload.as_ref().map_or(0, |p| p.len))
.sum();
tracing::info!(
"Resource tables: {} record(s), {} MiB compiled",
records.len(),
total / (1024 * 1024)
);
}
#[cfg(test)]
mod tests {
use super::*;
use concinnity_core::ecs::{PayloadLocator, ResourceKind};
const KIND_COUNTS: [(ResourceKind, u32); 8] = [
(ResourceKind::AudioClip, 1),
(ResourceKind::Texture, 2),
(ResourceKind::ColorLut, 3),
(ResourceKind::EnvironmentMap, 4),
(ResourceKind::Font, 5),
(ResourceKind::Material, 6),
(ResourceKind::Mesh, 7),
(ResourceKind::SkinnedMesh, 8),
];
fn record(kind: ResourceKind, handle: u32) -> ResourceRecord {
ResourceRecord {
resource_kind: kind as u8,
handle,
payload: Some(PayloadLocator {
blob_index: 0,
offset: handle as u64 * 16,
len: 16,
}),
data_bytes: vec![handle as u8; 4],
}
}
fn records() -> Vec<ResourceRecord> {
KIND_COUNTS
.iter()
.flat_map(|&(kind, count)| (0..count).map(move |h| record(kind, h)))
.collect()
}
fn table_lens(world: &crate::ecs::World) -> [usize; 8] {
[
world.resource::<AudioClipTable>().expect("audio").0.len(),
world.resource::<TextureTable>().expect("texture").0.len(),
world
.resource::<ColorLutTable>()
.expect("color lut")
.0
.len(),
world
.resource::<EnvironmentMapTable>()
.expect("env map")
.0
.len(),
world.resource::<FontTable>().expect("font").0.len(),
world.resource::<MaterialTable>().expect("material").0.len(),
world.resource::<MeshTable>().expect("mesh").0.len(),
world
.resource::<SkinnedMeshTable>()
.expect("skinned")
.0
.len(),
]
}
#[test]
fn install_wires_every_kind_table_into_the_world() {
let mut world = crate::ecs::World::new();
install_resource_tables(&mut world, &mut records());
assert_eq!(table_lens(&world), [1, 2, 3, 4, 5, 6, 7, 8]);
let mesh = world.resource::<MeshTable>().expect("mesh table installed");
assert_eq!(mesh.0[6].data_bytes, vec![6; 4]);
assert_eq!(mesh.0[6].payload.as_ref().expect("payload kept").offset, 96);
}
#[test]
fn install_with_no_records_installs_empty_tables() {
let mut world = crate::ecs::World::new();
install_resource_tables(&mut world, &mut []);
assert_eq!(table_lens(&world), [0; 8]);
}
}