concinnity_core/components/
model.rs1use crate::ecs::MaterialHandle;
4use crate::ecs::MeshHandle;
5use crate::ecs::asset_id::AssetId;
6use crate::ecs::de_opt_material_handle;
7use crate::ecs::de_opt_mesh_handle;
8use alloc::vec::Vec;
9
10#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
12pub struct SubMeshRef {
13 #[serde(default, deserialize_with = "de_opt_mesh_handle")]
15 pub mesh: Option<MeshHandle>,
16 #[serde(default, deserialize_with = "de_opt_material_handle")]
18 pub material: Option<MaterialHandle>,
19}
20
21#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
30#[serde(default)]
31pub struct Model {
32 #[serde(skip)]
34 pub asset_id: AssetId,
35 pub meshes: Vec<SubMeshRef>,
37}
38
39#[cfg(test)]
40mod tests {
41 use super::*;
42
43 #[test]
44 fn a_blank_model_has_no_sub_meshes() {
45 let m = Model::default();
46 assert!(m.meshes.is_empty());
47 assert_eq!(m.asset_id, AssetId::default());
48 }
49
50 #[test]
51 fn a_sub_mesh_may_declare_geometry_without_a_material() {
52 crate::test_support::install_resolvers();
53 let s: SubMeshRef = serde_json::from_str(r#"{"mesh":"body"}"#).unwrap();
54 assert_eq!(s.mesh, Some(MeshHandle(4)));
55 assert_eq!(s.material, None);
57 let s: SubMeshRef = serde_json::from_str("{}").unwrap();
58 assert_eq!(s.mesh, None);
59 assert_eq!(s.material, None);
60 }
61
62 #[test]
63 fn an_imported_model_keeps_its_sub_mesh_order_through_postcard() {
64 crate::test_support::install_resolvers();
65 let m: Model = serde_json::from_str(
66 r#"{"meshes":[{"mesh":"body","material":"skin"},
67 {"mesh":"trim","material":"metal"}]}"#,
68 )
69 .unwrap();
70 assert_eq!(m.meshes.len(), 2);
71
72 let bytes = postcard::to_allocvec(&m).unwrap();
73 let back: Model = postcard::from_bytes(&bytes).unwrap();
74 assert_eq!(back.meshes[0].mesh, Some(MeshHandle(4)));
75 assert_eq!(back.meshes[0].material, Some(MaterialHandle(4)));
76 assert_eq!(back.meshes[1].mesh, Some(MeshHandle(4)));
77 assert_eq!(back.meshes[1].material, Some(MaterialHandle(5)));
78 assert_eq!(back.asset_id, AssetId::default());
79 }
80}