1use std::collections::HashMap;
4use std::io::{Seek, Read};
5
6use glam::{Affine3A, Vec3A, Vec4};
7use smallvec::SmallVec;
8use thiserror::Error;
9
10use crate::pxml::{self, Value, Element};
11
12
13pub fn from_reader<R: Read + Seek>(reader: R) -> Result<Box<Visual>, DeError> {
18
19 let root_elt = pxml::from_reader(reader)?;
20
21 let root_node_value = root_elt.get_child("node").ok_or(DeError::MissingRootNode)?;
22 let root_node_elt = root_node_value.as_element().ok_or(DeError::MissingRootNode)?;
23 let root_node = read_node(root_node_elt).ok_or(DeError::InvalidNode)?;
24
25 let bb_elt = root_elt
26 .get_child("boundingBox").ok_or(DeError::MissingBoundingBox)?
27 .as_element().ok_or(DeError::MissingBoundingBox)?;
28
29 let bb_min = bb_elt
30 .get_child("min").ok_or(DeError::MissingBoundingBox)?
31 .as_vec3().ok_or(DeError::MissingBoundingBox)?;
32
33 let bb_max = bb_elt
34 .get_child("max").ok_or(DeError::MissingBoundingBox)?
35 .as_vec3().ok_or(DeError::MissingBoundingBox)?;
36
37 let geometry_size = root_elt
38 .get_child("geometrySize").ok_or(DeError::MissingGeometrySize)?
39 .as_integer().ok_or(DeError::MissingGeometrySize)? as u32;
40
41 let min_uv_density = root_elt
42 .get_child("minUVDensity").ok_or(DeError::MissingUvDensity)?
43 .as_float().ok_or(DeError::MissingUvDensity)?;
44
45 let mut render_sets = SmallVec::new();
46 for child in root_elt.iter_children("renderSet") {
47 if let Value::Element(child_elt) = child {
48 render_sets.push(read_render_set(&**&child_elt).ok_or(DeError::InvalidRenderSet)?);
49 }
50 }
51
52 Ok(Box::new(Visual {
53 root_node,
54 render_sets,
55 bb_min,
56 bb_max,
57 geometry_size,
58 min_uv_density,
59 }))
60
61}
62
63
64fn read_node(element: &Element) -> Option<Node> {
65
66 let identifier = element.get_child("identifier")?.as_string()?;
67 let transform = element.get_child("transform")?.as_affine3()?;
68
69 let mut children = Vec::new();
70 for child in element.iter_children("node") {
71 if let Value::Element(child_elt) = child {
72 children.push(read_node(&**child_elt)?);
73 }
74 }
75
76 Some(Node {
77 identifier: identifier.clone(),
78 transform,
79 children,
80 })
81
82}
83
84
85fn read_render_set(element: &Element) -> Option<RenderSet> {
86
87 let node = element.get_child("node")?.as_string()?;
88 let treat_as_world_space_object = element.get_child("treatAsWorldSpaceObject")?.as_boolean()?;
89
90 let geometry_elt = element.get_child("geometry")?.as_element()?;
91 let geometry_vertices = geometry_elt.get_child("vertices")?.as_string()?;
92 let geometry_indices = geometry_elt.get_child("primitive")?.as_string()?;
93
94 let mut primitive_groups = SmallVec::new();
95 for group_val in geometry_elt.iter_children("primitiveGroup") {
96 if let Value::Element(group_elt) = group_val {
97
98 let group_index = group_elt.value.as_integer()? as u32;
99 let group_origin = group_elt.get_child("groupOrigin")?.as_vec3()?;
100
101 let mat_elt = group_elt.get_child("material")?.as_element()?;
102 let mat_identifier = mat_elt.get_child("identifier")?.as_string()?;
103 let mat_collision_flags = mat_elt.get_child("collisionFlags")?.as_integer()? as u32;
104 let mat_kind = mat_elt.get_child("materialKind")?.as_integer()? as u32;
105 let mat_fx = mat_elt.get_child("fx")?.as_string()?;
106
107 let mut mat_properties = HashMap::new();
108 for prop_val in mat_elt.iter_children("property") {
109 if let Value::Element(prop_elt) = prop_val {
110
111 let prop_name = prop_elt.value.as_string()?;
112 let prop_value = if let Some(val) = prop_elt.get_child("Texture") {
113 MaterialProperty::Texture(val.as_string()?.clone())
114 } else if let Some(val) = prop_elt.get_child("Bool") {
115 MaterialProperty::Boolean(val.as_boolean()?)
116 } else if let Some(val) = prop_elt.get_child("Int") {
117 MaterialProperty::Integer(val.as_integer()?)
118 } else if let Some(val) = prop_elt.get_child("Float") {
119 let n = match val {
122 &Value::Integer(n) => n as f32,
123 &Value::Float(n) => n,
124 Value::String(s) => s.parse().ok()?,
125 _ => return None
126 };
127 MaterialProperty::Float(n)
128 } else if let Some(val) = prop_elt.get_child("Vector4") {
129 let mut raw = val.as_string()?
131 .splitn(4, ' ')
132 .filter_map(|s| s.parse::<f32>().ok());
133 let x = raw.next()?;
134 let y = raw.next()?;
135 let z = raw.next()?;
136 let w = raw.next()?;
137 MaterialProperty::Vec4(Vec4::new(x, y, z, w))
138 } else {
139 return None;
140 };
141
142 mat_properties.insert(prop_name.clone(), prop_value);
143
144 }
145 }
146
147 primitive_groups.push(PrimitiveGroup {
148 index: group_index,
149 origin: group_origin,
150 material: Material {
151 identifier: mat_identifier.clone(),
152 properties: mat_properties,
153 collision_flags: mat_collision_flags,
154 material_kind: mat_kind,
155 fx: mat_fx.clone(),
156 },
157 })
158
159 }
160 }
161
162 Some(RenderSet {
163 node: node.clone(),
164 geometry: Geometry {
165 vertices_section: geometry_vertices.clone(),
166 indices_section: geometry_indices.clone(),
167 primitive_groups,
168 },
169 treat_as_world_space_object,
170 })
171
172}
173
174
175#[derive(Debug)]
177pub struct Visual {
178 pub root_node: Node,
180 pub render_sets: SmallVec<[RenderSet; 4]>,
182 pub bb_min: Vec3A,
184 pub bb_max: Vec3A,
186 pub geometry_size: u32,
188 pub min_uv_density: f32,
190}
191
192#[derive(Debug)]
194pub struct Node {
195 pub identifier: String,
197 pub transform: Affine3A,
199 pub children: Vec<Node>,
201}
202
203#[derive(Debug)]
205pub struct RenderSet {
206 pub node: String,
208 pub geometry: Geometry,
210 pub treat_as_world_space_object: bool,
212}
213
214#[derive(Debug)]
216pub struct Geometry {
217 pub vertices_section: String,
219 pub indices_section: String,
221 pub primitive_groups: SmallVec<[PrimitiveGroup; 1]>,
223}
224
225#[derive(Debug)]
227pub struct PrimitiveGroup {
228 pub index: u32,
230 pub origin: Vec3A,
232 pub material: Material,
234}
235
236#[derive(Debug)]
237pub struct Material {
238 pub identifier: String,
239 pub properties: HashMap<String, MaterialProperty>,
240 pub collision_flags: u32,
241 pub material_kind: u32,
242 pub fx: String,
243}
244
245#[derive(Debug)]
246pub enum MaterialProperty {
247 Texture(String),
249 Boolean(bool),
251 Integer(i64),
253 Float(f32),
255 Vec4(Vec4),
257}
258
259#[derive(Debug, Error)]
261pub enum DeError {
262 #[error("the root node is missing")]
264 MissingRootNode,
265 #[error("a node is missing either identifier or transform")]
267 InvalidNode,
268 #[error("values are missing in a render set")]
270 InvalidRenderSet,
271 #[error("the bounding box is missing or invalid")]
273 MissingBoundingBox,
274 #[error("the geometry size is missing or invalid")]
276 MissingGeometrySize,
277 #[error("the uv density is missing or invalid")]
279 MissingUvDensity,
280 #[error("pxml error: {0}")]
282 Pxml(#[from] pxml::DeError),
283}