1use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11pub struct VertexData {
12 pub vertex_count: u32,
13 pub channels: Vec<ChannelInfo>,
14 pub data_size: Vec<u8>,
15}
16
17#[derive(Debug, Clone, Default, Serialize, Deserialize)]
21pub struct ChannelInfo {
22 pub stream: u8,
23 pub offset: u8,
24 pub format: u8,
25 pub dimension: u8,
26}
27
28#[derive(Debug, Clone, Default, Serialize, Deserialize)]
32pub struct SubMesh {
33 pub first_byte: u32,
34 pub index_count: u32,
35 pub topology: i32,
36 pub triangle_count: u32,
37 pub base_vertex: u32,
38 pub first_vertex: u32,
39 pub vertex_count: u32,
40 pub local_aabb: Option<AABB>,
41}
42
43#[derive(Debug, Clone, Default, Serialize, Deserialize)]
47pub struct AABB {
48 pub center_x: f32,
49 pub center_y: f32,
50 pub center_z: f32,
51 pub extent_x: f32,
52 pub extent_y: f32,
53 pub extent_z: f32,
54}
55
56#[derive(Debug, Clone, Default, Serialize, Deserialize)]
60pub struct BlendShapeData {
61 pub vertices: Vec<BlendShapeVertex>,
62 pub shapes: Vec<BlendShape>,
63 pub channels: Vec<BlendShapeChannel>,
64 pub full_weights: Vec<f32>,
65}
66
67#[derive(Debug, Clone, Default, Serialize, Deserialize)]
71pub struct BlendShapeVertex {
72 pub vertex: [f32; 3],
73 pub normal: [f32; 3],
74 pub tangent: [f32; 3],
75 pub index: u32,
76}
77
78#[derive(Debug, Clone, Default, Serialize, Deserialize)]
82pub struct BlendShape {
83 pub first_vertex: u32,
84 pub vertex_count: u32,
85 pub has_normals: bool,
86 pub has_tangents: bool,
87}
88
89#[derive(Debug, Clone, Default, Serialize, Deserialize)]
93pub struct BlendShapeChannel {
94 pub name: String,
95 pub name_hash: u32,
96 pub frame_index: i32,
97 pub frame_count: i32,
98}
99
100#[derive(Debug, Clone, Default, Serialize, Deserialize)]
104pub struct StreamingInfo {
105 pub offset: u64,
106 pub size: u32,
107 pub path: String,
108}
109
110#[derive(Debug, Clone, Default, Serialize, Deserialize)]
114pub struct CompressedMesh {
115 pub vertices: PackedFloatVector,
116 pub uv: PackedFloatVector,
117 pub normals: PackedFloatVector,
118 pub tangents: PackedFloatVector,
119 pub weights: PackedIntVector,
120 pub normal_signs: PackedIntVector,
121 pub tangent_signs: PackedIntVector,
122 pub float_colors: Option<PackedFloatVector>,
123 pub bone_indices: PackedIntVector,
124 pub triangles: PackedIntVector,
125 pub colors: Option<PackedIntVector>,
126 pub uv_info: u32,
127}
128
129#[derive(Debug, Clone, Default, Serialize, Deserialize)]
133pub struct PackedFloatVector {
134 pub num_items: u32,
135 pub range: f32,
136 pub start: f32,
137 pub data: Vec<u8>,
138 pub bit_size: u8,
139}
140
141#[derive(Debug, Clone, Default, Serialize, Deserialize)]
145pub struct PackedIntVector {
146 pub num_items: u32,
147 pub data: Vec<u8>,
148 pub bit_size: u8,
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize)]
155pub struct Mesh {
156 pub name: String,
157 pub sub_meshes: Vec<SubMesh>,
158 pub blend_shape_data: Option<BlendShapeData>,
159 pub bind_pose: Vec<[f32; 16]>, pub bone_name_hashes: Vec<u32>,
161 pub root_bone_name_hash: u32,
162 pub mesh_compression: u8,
163 pub is_readable: bool,
164 pub keep_vertices: bool,
165 pub keep_indices: bool,
166 pub index_format: i32,
167 pub index_buffer: Vec<u8>,
168 pub vertex_data: VertexData,
169 pub compressed_mesh: Option<CompressedMesh>,
170 pub local_aabb: AABB,
171 pub mesh_usage_flags: i32,
172 pub baked_convex_collision_mesh: Vec<u8>,
173 pub baked_triangle_collision_mesh: Vec<u8>,
174 pub mesh_metrics: [f32; 2],
175 pub stream_data: Option<StreamingInfo>,
176}
177
178impl Default for Mesh {
179 fn default() -> Self {
180 Self {
181 name: String::new(),
182 sub_meshes: Vec::new(),
183 blend_shape_data: None,
184 bind_pose: Vec::new(),
185 bone_name_hashes: Vec::new(),
186 root_bone_name_hash: 0,
187 mesh_compression: 0,
188 is_readable: true,
189 keep_vertices: true,
190 keep_indices: true,
191 index_format: 0,
192 index_buffer: Vec::new(),
193 vertex_data: VertexData::default(),
194 compressed_mesh: None,
195 local_aabb: AABB::default(),
196 mesh_usage_flags: 0,
197 baked_convex_collision_mesh: Vec::new(),
198 baked_triangle_collision_mesh: Vec::new(),
199 mesh_metrics: [0.0, 0.0],
200 stream_data: None,
201 }
202 }
203}
204
205#[derive(Debug, Clone)]
207pub struct MeshConfig {
208 pub extract_vertices: bool,
210 pub extract_indices: bool,
212 pub process_blend_shapes: bool,
214 pub decompress_meshes: bool,
216 pub max_vertex_count: Option<u32>,
218}
219
220impl Default for MeshConfig {
221 fn default() -> Self {
222 Self {
223 extract_vertices: true,
224 extract_indices: true,
225 process_blend_shapes: true,
226 decompress_meshes: true,
227 max_vertex_count: None,
228 }
229 }
230}
231
232#[derive(Debug, Clone)]
234pub struct MeshResult {
235 pub mesh: Mesh,
236 pub warnings: Vec<String>,
237 pub errors: Vec<String>,
238}
239
240impl MeshResult {
241 pub fn new(mesh: Mesh) -> Self {
242 Self {
243 mesh,
244 warnings: Vec::new(),
245 errors: Vec::new(),
246 }
247 }
248
249 pub fn add_warning(&mut self, warning: String) {
250 self.warnings.push(warning);
251 }
252
253 pub fn add_error(&mut self, error: String) {
254 self.errors.push(error);
255 }
256
257 pub fn has_warnings(&self) -> bool {
258 !self.warnings.is_empty()
259 }
260
261 pub fn has_errors(&self) -> bool {
262 !self.errors.is_empty()
263 }
264}
265
266#[derive(Debug, Clone, Serialize, Deserialize)]
268pub struct MeshInfo {
269 pub name: String,
270 pub vertex_count: u32,
271 pub sub_mesh_count: u32,
272 pub triangle_count: u32,
273 pub has_blend_shapes: bool,
274 pub is_readable: bool,
275 pub is_compressed: bool,
276 pub has_streaming_data: bool,
277}
278
279impl Mesh {
281 pub fn vertex_count(&self) -> u32 {
283 self.vertex_data.vertex_count
284 }
285
286 pub fn triangle_count(&self) -> u32 {
288 self.sub_meshes.iter().map(|sm| sm.triangle_count).sum()
289 }
290
291 pub fn has_blend_shapes(&self) -> bool {
293 self.blend_shape_data.is_some()
294 }
295
296 pub fn is_compressed(&self) -> bool {
298 self.compressed_mesh.is_some()
299 }
300
301 pub fn has_streaming_data(&self) -> bool {
303 self.stream_data.is_some()
304 }
305
306 pub fn bounds(&self) -> &AABB {
308 &self.local_aabb
309 }
310
311 pub fn get_info(&self) -> MeshInfo {
313 MeshInfo {
314 name: self.name.clone(),
315 vertex_count: self.vertex_count(),
316 sub_mesh_count: self.sub_meshes.len() as u32,
317 triangle_count: self.triangle_count(),
318 has_blend_shapes: self.has_blend_shapes(),
319 is_readable: self.is_readable,
320 is_compressed: self.is_compressed(),
321 has_streaming_data: self.has_streaming_data(),
322 }
323 }
324}
325
326impl AABB {
327 pub fn new(center: [f32; 3], extent: [f32; 3]) -> Self {
329 Self {
330 center_x: center[0],
331 center_y: center[1],
332 center_z: center[2],
333 extent_x: extent[0],
334 extent_y: extent[1],
335 extent_z: extent[2],
336 }
337 }
338
339 pub fn center(&self) -> [f32; 3] {
341 [self.center_x, self.center_y, self.center_z]
342 }
343
344 pub fn extent(&self) -> [f32; 3] {
346 [self.extent_x, self.extent_y, self.extent_z]
347 }
348
349 pub fn min(&self) -> [f32; 3] {
351 [
352 self.center_x - self.extent_x,
353 self.center_y - self.extent_y,
354 self.center_z - self.extent_z,
355 ]
356 }
357
358 pub fn max(&self) -> [f32; 3] {
360 [
361 self.center_x + self.extent_x,
362 self.center_y + self.extent_y,
363 self.center_z + self.extent_z,
364 ]
365 }
366
367 pub fn volume(&self) -> f32 {
369 8.0 * self.extent_x * self.extent_y * self.extent_z
370 }
371}
372
373impl SubMesh {
374 pub fn is_valid(&self) -> bool {
376 self.vertex_count > 0 && self.index_count > 0
377 }
378
379 pub fn topology_name(&self) -> &'static str {
381 match self.topology {
382 0 => "Triangles",
383 1 => "Quads",
384 2 => "Lines",
385 3 => "LineStrip",
386 4 => "Points",
387 _ => "Unknown",
388 }
389 }
390}