Skip to main content

enigma_3d/
object.rs

1use std::collections::HashMap;
2use std::vec::Vec;
3use glium::Display;
4use glium::glutin::surface::WindowSurface;
5use crate::geometry::{BoneTransforms, BoundingBox, Vertex};
6use nalgebra::{Vector3, Matrix4, Translation3, UnitQuaternion, Point3};
7use crate::{animation, debug_geo, geometry, smart_format};
8use uuid::Uuid;
9
10
11use std::fs::File;
12use std::io::BufReader;
13use glium::uniforms::UniformBuffer;
14use nalgebra_glm::normalize;
15use obj::{load_obj, Obj};
16use serde::{Deserialize, Serialize};
17use crate::animation::{AnimationState, MAX_BONES};
18use crate::logging::{EnigmaError, EnigmaMessage};
19
20pub struct ObjectInstance {
21    pub vertex_buffers: Vec<(glium::vertex::VertexBufferAny, usize)>,
22    pub index_buffers: Vec<glium::IndexBuffer<u32>>,
23    pub instance_matrices: Vec<[[f32; 4]; 4]>,
24    pub instance_attributes: glium::VertexBuffer<geometry::InstanceAttribute>,
25}
26
27#[derive(Serialize, Deserialize, Clone)]
28pub struct ObjectSerializer {
29    pub name: String,
30    pub transform: TransformSerializer,
31    collision: bool,
32    shapes: Vec<Shape>,
33    materials: Vec<String>,
34    unique_id: String,
35    cloned_id: String,
36    animations: HashMap<String, animation::AnimationSerializer>,
37    skeleton: Option<animation::SkeletonSerializer>,
38}
39
40pub struct Object {
41    pub name: String,
42    pub transform: Transform,
43    collision: bool,
44    shapes: Vec<Shape>,
45    materials: Vec<Uuid>,
46    bounding_box: Option<geometry::BoundingBox>,
47    unique_id: Uuid,
48    cloned_id: Uuid,
49    animations: HashMap<String, animation::Animation>,
50    skeleton: Option<animation::Skeleton>,
51    current_animation: Option<AnimationState>,
52}
53
54impl Clone for Object {
55    fn clone(&self) -> Self {
56        //creating new object
57        let mut new_object = Object::new(Some(self.name.clone()));
58
59        //setting transform for new object
60        new_object.transform.set_position(self.transform.get_position().into());
61        new_object.transform.set_rotation(self.transform.get_rotation().into());
62        new_object.transform.set_scale(self.transform.get_scale().into());
63
64        //cloning shapes
65        for shape in self.shapes.iter() {
66            let mut new_shape = Shape::new();
67            new_shape.vertices = shape.vertices.clone();
68            new_shape.indices = shape.indices.clone();
69            new_shape.material_index = shape.material_index;
70            new_object.add_shape(new_shape);
71        }
72
73        //cloning materials
74        new_object.materials = self.materials.clone();
75
76        new_object.bounding_box = self.bounding_box.clone();
77        new_object.unique_id = Uuid::new_v4();
78        new_object.cloned_id = self.unique_id;
79        new_object.animations = self.animations.clone();
80        new_object.skeleton = self.skeleton.clone();
81        new_object
82    }
83}
84
85#[derive(Serialize, Deserialize)]
86pub struct Shape {
87    pub vertices: Vec<Vertex>,
88    pub indices: Vec<u32>,
89    pub material_index: usize,
90}
91
92impl Clone for Shape {
93    fn clone(&self) -> Self {
94        Shape {
95            vertices: self.vertices.clone(),
96            indices: self.indices.clone(),
97            material_index: self.material_index,
98        }
99    }
100}
101
102impl Shape {
103    pub fn new() -> Self {
104        Shape {
105            vertices: Vec::new(),
106            indices: Vec::new(),
107            material_index: 0,
108        }
109    }
110
111    pub fn from_vertices_indices(vertices: Vec<Vertex>, indices: Vec<u32>) -> Self {
112        Shape {
113            vertices,
114            indices,
115            material_index: 0,
116        }
117    }
118
119    pub fn default() -> Self {
120        let triangle = debug_geo::TRIANGLE;
121        let mut shape = Shape::new();
122        shape.vertices = triangle.to_vec();
123        for i in 0..triangle.iter().len() {
124            shape.indices.push(i as u32);
125        }
126        shape
127    }
128
129    pub fn get_vertex_buffer(&self, display: Display<WindowSurface>) -> glium::VertexBuffer<Vertex> {
130        glium::VertexBuffer::new(&display, &self.vertices).unwrap()
131    }
132
133    pub fn get_index_buffer(&self, display: Display<WindowSurface>) -> glium::IndexBuffer<u32> {
134        glium::IndexBuffer::new(&display, glium::index::PrimitiveType::TrianglesList, &self.indices).unwrap()
135    }
136
137    pub fn set_material_from_object_list(&mut self, material_index: usize) {
138        self.material_index = material_index;
139    }
140}
141
142impl ObjectInstance {
143    pub fn new(display: &Display<WindowSurface>) -> Self {
144        Self {
145            vertex_buffers: Vec::new(),
146            index_buffers: Vec::new(),
147            instance_matrices: Vec::new(),
148            instance_attributes: glium::vertex::VertexBuffer::dynamic(display, &Vec::new()).expect("Building ObjectInstance, Per Instance Attribute could not be created"),
149        }
150    }
151
152    pub fn set_vertex_buffers(&mut self, buffers: Vec<(glium::vertex::VertexBufferAny, usize)>) {
153        self.vertex_buffers = buffers;
154    }
155
156    pub fn set_index_buffers(&mut self, buffers: Vec<glium::IndexBuffer<u32>>) {
157        self.index_buffers = buffers;
158    }
159
160    pub fn add_instance(&mut self, instance: [[f32; 4]; 4]) {
161        self.instance_matrices.push(instance);
162    }
163}
164
165impl Object {
166    pub fn new(name: Option<String>) -> Self {
167        let uuid = Uuid::new_v4();
168        let mut object = Object {
169            name: name.unwrap_or_else(|| String::from("Object")),
170            transform: Transform::new(),
171            shapes: Vec::new(),
172            materials: Vec::new(),
173            bounding_box: None,
174            unique_id: uuid,
175            cloned_id: uuid,
176            collision: true,
177            animations: HashMap::new(),
178            skeleton: None,
179            current_animation: None,
180        };
181        object.calculate_bounding_box();
182        object
183    }
184
185    pub fn to_serializer(&self) -> ObjectSerializer {
186        let name = self.name.clone();
187        let transform = self.transform.to_serializer();
188        let mut animations = HashMap::new();
189        for (n, a) in &self.animations {
190            animations.insert(n.to_string(), a.to_serializer());
191        }
192        let shapes = self.shapes.clone();
193        let materials = self.materials.iter().map(|x| x.to_string()).collect();
194        let unique_id = self.unique_id.to_string();
195        let cloned_id = self.cloned_id.to_string();
196        ObjectSerializer {
197            name,
198            transform,
199            shapes,
200            materials,
201            unique_id,
202            cloned_id,
203            collision: self.collision,
204            animations,
205            skeleton: match &self.skeleton {
206                Some(skeleton) => Some(skeleton.to_serializer()),
207                None => None
208            },
209        }
210    }
211
212    pub fn from_serializer(serializer: ObjectSerializer) -> Self {
213        let mut object = Object::new(Some(serializer.name));
214        object.transform = Transform::from_serializer(serializer.transform);
215        object.shapes = serializer.shapes;
216        for mat in serializer.materials {
217            object.add_material(Uuid::parse_str(mat.as_str()).expect("failed to parse material uuid"));
218        }
219        object.unique_id = uuid::Uuid::parse_str(serializer.unique_id.as_str()).unwrap();
220        object.cloned_id = uuid::Uuid::parse_str(serializer.cloned_id.as_str()).unwrap();
221        object.collision = serializer.collision;
222        object.calculate_bounding_box();
223
224        let mut animations = HashMap::new();
225        for (n, s) in serializer.animations {
226            let anim = animation::Animation::from_serializer(s);
227            animations.insert(n, anim);
228        }
229        object.animations = animations;
230        object.skeleton = match serializer.skeleton {
231            Some(s) => Some(animation::Skeleton::from_serializer(s)),
232            None => None
233        };
234        object
235    }
236
237    pub fn set_collision(&mut self, collision: bool) {
238        self.collision = collision;
239    }
240
241    pub fn get_collision(&self) -> &bool {
242        &self.collision
243    }
244
245    pub fn get_unique_id(&self) -> Uuid {
246        self.unique_id
247    }
248
249    pub fn get_instance_id(&self) -> Uuid {
250        self.cloned_id
251    }
252
253    pub fn break_instance(&mut self) {
254        self.cloned_id = self.unique_id;
255    }
256
257    fn calculate_bounding_box(&mut self) -> BoundingBox {
258        let mut min_x = f32::INFINITY;
259        let mut min_y = f32::INFINITY;
260        let mut min_z = f32::INFINITY;
261        let mut max_x = f32::NEG_INFINITY;
262        let mut max_y = f32::NEG_INFINITY;
263        let mut max_z = f32::NEG_INFINITY;
264
265        for shape in self.get_shapes().iter() {
266            for vertex in shape.vertices.iter() {
267                min_x = min_x.min(vertex.position[0]);
268                min_y = min_y.min(vertex.position[1]);
269                min_z = min_z.min(vertex.position[2]);
270                max_x = max_x.max(vertex.position[0]);
271                max_y = max_y.max(vertex.position[1]);
272                max_z = max_z.max(vertex.position[2]);
273            }
274        }
275
276        let min_point = Point3::new(min_x, min_y, min_z);
277        let max_point = Point3::new(max_x, max_y, max_z);
278
279        let center = Point3::new(
280            (min_point.x + max_point.x) / 2.0,
281            (min_point.y + max_point.y) / 2.0,
282            (min_point.z + max_point.z) / 2.0,
283        );
284        self.transform.update();
285        let transformed_center = self.transform.matrix.transform_point(&center);
286        let transformed_width = (max_x - min_x) * self.transform.get_scale().x;
287        let transformed_height = (max_y - min_y) * self.transform.get_scale().y;
288        let transformed_depth = (max_z - min_z) * self.transform.get_scale().z;
289
290        let aabb = BoundingBox {
291            center: Vector3::from([transformed_center.x, transformed_center.y, transformed_center.z]),
292            width: transformed_width,
293            height: transformed_height,
294            depth: transformed_depth,
295        };
296        self.bounding_box = Some(aabb);
297        aabb
298    }
299
300    pub fn default() -> Self {
301        let mut object = Object::new(None);
302        object.add_shape(Shape::default());
303        object
304    }
305
306    fn update_animation_internal(&mut self, delta_time: f32) {
307        if let Some(anim_state) = &mut self.current_animation {
308            if let Some(animation) = self.animations.get(&anim_state.name) {
309                anim_state.time += delta_time * anim_state.speed;
310                if anim_state.time > animation.duration {
311                    if anim_state.looping {
312                        anim_state.time %= animation.duration;
313                    } else {
314                        anim_state.time = animation.duration;
315                    }
316                }
317            }
318        }
319    }
320
321    pub fn has_skeletal_animation(&self) -> bool {
322        self.skeleton.is_some() && !self.animations.is_empty()
323    }
324
325    pub fn get_bone_transform_buffer(&self, display: &Display<WindowSurface>) -> UniformBuffer<BoneTransforms> {
326        let identity = [[1.0f32, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]];
327        let mut bone_transform_data = BoneTransforms {
328            bone_transforms: [identity; MAX_BONES],
329        };
330
331        if let (Some(skeleton), Some(anim_state)) = (&self.skeleton, &self.current_animation) {
332            if let Some(animation) = self.animations.get(anim_state.name.as_str()) {
333                let mut global_transforms = vec![Matrix4::identity(); skeleton.bones.len()];
334
335                for (i, bone) in skeleton.bones.iter().enumerate() {
336                    let local_transform = self.interpolate_bone(animation, bone.node_index, anim_state.time);
337                    let parent_transform: Matrix4<f32> = bone.parent_id
338                        .map(|id| global_transforms[id])
339                        .unwrap_or(skeleton.root_transform);
340
341                    global_transforms[i] = parent_transform * local_transform;
342                    let final_transform: Matrix4<f32> = global_transforms[i] * bone.inverse_bind_pose;
343                    bone_transform_data.bone_transforms[i] = final_transform.into();
344                }
345            }
346        }
347
348        UniformBuffer::new(display, bone_transform_data).expect("Failed to create BoneTransform Buffer")
349    }
350
351    fn interpolate_bone(&self, animation: &animation::Animation, node_index: usize, time: f32) -> Matrix4<f32> {
352        let mut translation = Matrix4::identity();
353        let mut rotation = Matrix4::identity();
354        let mut scale = Matrix4::identity();
355
356        for channel in animation.channels.iter().filter(|c| c.bone_id == node_index) {
357            if channel.keyframes.is_empty() { continue; }
358            let m = Self::interpolate_channel(channel, time);
359            match &channel.keyframes[0].transform {
360                animation::AnimationTransform::Translation(_) => translation = m,
361                animation::AnimationTransform::Rotation(_) => rotation = m,
362                animation::AnimationTransform::Scale(_) => scale = m,
363            }
364        }
365
366        translation * rotation * scale
367    }
368
369    fn interpolate_channel(channel: &animation::AnimationChannel, time: f32) -> Matrix4<f32> {
370        let mut prev_keyframe = &channel.keyframes[0];
371        let mut next_keyframe = prev_keyframe;
372
373        for keyframe in &channel.keyframes {
374            if keyframe.time > time {
375                next_keyframe = keyframe;
376                break;
377            }
378            prev_keyframe = keyframe;
379        }
380
381        let duration = next_keyframe.time - prev_keyframe.time;
382        let t = if duration > 0.0 {
383            ((time - prev_keyframe.time) / duration).clamp(0.0, 1.0)
384        } else {
385            0.0
386        };
387
388        match (&prev_keyframe.transform, &next_keyframe.transform) {
389            (animation::AnimationTransform::Translation(prev), animation::AnimationTransform::Translation(next)) => {
390                let interpolated = Vector3::new(
391                    prev[0] + (next[0] - prev[0]) * t,
392                    prev[1] + (next[1] - prev[1]) * t,
393                    prev[2] + (next[2] - prev[2]) * t,
394                );
395                Matrix4::new_translation(&interpolated)
396            }
397            (animation::AnimationTransform::Rotation(prev), animation::AnimationTransform::Rotation(next)) => {
398                let prev_quat = UnitQuaternion::from_quaternion(nalgebra::Quaternion::new(prev[3], prev[0], prev[1], prev[2]));
399                let next_quat = UnitQuaternion::from_quaternion(nalgebra::Quaternion::new(next[3], next[0], next[1], next[2]));
400                prev_quat.slerp(&next_quat, t).to_homogeneous()
401            }
402            (animation::AnimationTransform::Scale(prev), animation::AnimationTransform::Scale(next)) => {
403                let interpolated = Vector3::new(
404                    prev[0] + (next[0] - prev[0]) * t,
405                    prev[1] + (next[1] - prev[1]) * t,
406                    prev[2] + (next[2] - prev[2]) * t,
407                );
408                Matrix4::new_nonuniform_scaling(&interpolated)
409            }
410            _ => Matrix4::identity(),
411        }
412    }
413
414    pub fn play_animation(&mut self, name: &str, looping: bool) {
415        if let Some(_) = self.animations.get(name) {
416            self.current_animation = Some(AnimationState {
417                name: name.to_string(),
418                time: 0.0,
419                speed: 1.0,
420                looping,
421            });
422        }
423    }
424
425    pub fn stop_animation(&mut self) {
426        self.current_animation = None;
427    }
428
429    pub fn get_current_animation(&self) -> &Option<AnimationState> {
430        &self.current_animation
431    }
432
433    pub fn update(&mut self, delta_time: f32) {
434        self.transform.update();
435        if self.skeleton.is_some() && self.current_animation.is_some() {
436            self.update_animation_internal(delta_time);
437        }
438    }
439
440    pub fn get_closest_lights(&self, lights: &Vec<crate::light::Light>) -> Vec<crate::light::Light> {
441        let mut closest_lights = Vec::new();
442
443        //collect the four closest lights to the object
444        for light in lights.iter() {
445            let light_pos = light.position;
446            let object_pos = self.transform.get_position();
447            let distance = (Vector3::from(light_pos) - object_pos).magnitude();
448            if closest_lights.len() < 4 {
449                closest_lights.push((light.clone(), distance));
450            } else {
451                let mut max_distance = 0.0;
452                let mut max_index = 0;
453                for (index, (_, distance)) in closest_lights.iter().enumerate() {
454                    if *distance > max_distance {
455                        max_distance = *distance;
456                        max_index = index;
457                    }
458                }
459                if distance < max_distance {
460                    closest_lights[max_index] = (light.clone(), distance.clone());
461                }
462            }
463        }
464        closest_lights.iter().map(|(light, _)| light.clone()).collect()
465    }
466
467    pub fn add_shape(&mut self, shape: Shape) {
468        self.shapes.push(shape);
469    }
470
471    pub fn get_vertex_buffers(&self, display: &Display<WindowSurface>) -> Vec<(glium::vertex::VertexBufferAny, usize)> {
472        let shapes = self.get_shapes();
473        let mut buffer = Vec::new();
474        for shape in shapes.iter() {
475            let vertex: glium::vertex::VertexBufferAny = glium::VertexBuffer::new(display, &shape.vertices).unwrap().into();
476            buffer.push((vertex, shape.material_index));
477        }
478        buffer
479    }
480
481    pub fn get_index_buffers(&self, display: &Display<WindowSurface>) -> Vec<glium::IndexBuffer<u32>> {
482        let shapes = self.get_shapes();
483        let mut buffer = Vec::new();
484        for shape in shapes.iter() {
485            let index = glium::IndexBuffer::new(display, glium::index::PrimitiveType::TrianglesList, &shape.indices).unwrap();
486            buffer.push(index);
487        }
488        buffer
489    }
490    pub fn get_bounding_box(&mut self) -> BoundingBox {
491        self.calculate_bounding_box()
492    }
493
494    pub fn get_materials(&self) -> &Vec<Uuid> {
495        &self.materials
496    }
497
498    pub fn get_materials_mut(&mut self) -> &mut Vec<Uuid> {
499        &mut self.materials
500    }
501
502    pub fn add_material(&mut self, material: Uuid) {
503        self.materials.push(material);
504    }
505
506    pub fn get_shapes(&self) -> &Vec<Shape> {
507        &self.shapes
508    }
509
510    pub fn get_shapes_mut(&mut self) -> &mut Vec<Shape> {
511        &mut self.shapes
512    }
513
514    pub fn get_name(&self) -> &String {
515        &self.name
516    }
517
518    pub fn set_name(&mut self, name: String) {
519        self.name = name;
520    }
521
522    pub fn get_animations(&self) -> &HashMap<String, animation::Animation> {
523        &self.animations
524    }
525    pub fn get_animations_mut(&mut self) -> &mut HashMap<String, animation::Animation> {
526        &mut self.animations
527    }
528
529    pub fn get_skeleton(&self) -> &Option<animation::Skeleton> {
530        &self.skeleton
531    }
532
533    pub fn get_skeleton_mut(&mut self) -> &mut Option<animation::Skeleton> {
534        &mut self.skeleton
535    }
536
537    pub fn try_fix_object(&mut self) -> Result<EnigmaMessage, EnigmaError> {
538        let mut errors = EnigmaError::new(None, true);
539        if let Some(skeleton) = &mut self.skeleton {
540            match skeleton.try_fix() {
541                Ok(_) => {},
542                Err(e) => errors.merge(e),
543            }
544        }
545
546        if !errors.is_empty() {
547            Err(errors)
548        } else {
549            Ok(EnigmaMessage::new(Some(&smart_format!("Nothing to Repair on Object {:?}", self.get_name())), true))
550        }
551    }
552
553    pub fn load_from_obj(path: &str) -> Self {
554        let input = BufReader::new(File::open(path).expect("Failed to open file"));
555        let obj: Obj = load_obj(input).unwrap();
556        let mut vertices = Vec::new();
557        let mut indices = Vec::new();
558        for vert in obj.vertices.iter() {
559            let vertex = geometry::Vertex { position: vert.position, color: [1.0, 1.0, 1.0], texcoord: [0.0, 0.0], normal: vert.normal, bone_indices: [0, 0, 0, 0], bone_weights: [0.0, 0.0, 0.0, 0.0] };
560            vertices.push(vertex);
561        }
562        for index in obj.indices.iter() {
563            indices.push((*index).into());
564        }
565
566        let shape = Shape::from_vertices_indices(vertices, indices);
567        let mut object = Object::new(obj.name);
568        object.add_shape(shape);
569        object
570    }
571
572    pub fn load_from_gltf_resource(data: &[u8], rig_scale_multiplier: Option<f32>) -> Self {
573        let (gltf, buffers, images) = gltf::import_slice(data).expect("Failed to import gltf file"); // gltf::import(path).expect("Failed to import gltf file");
574        let object = Object::new(Some(String::from("INTERNAL ENIGMA RESOURCE")));
575        Object::load_from_gltf_internal((gltf, buffers, images), object, rig_scale_multiplier.unwrap_or_else(|| 1.0f32))
576    }
577
578    pub fn load_from_gltf(path: &str, rig_scale_multiplier: Option<f32>) -> Self {
579        let (gltf, buffers, images) = gltf::import(path).expect("Failed to import gltf file");
580        let object = Object::new(Some(String::from(path)));
581        Object::load_from_gltf_internal((gltf, buffers, images), object, rig_scale_multiplier.unwrap_or_else(|| 1.0f32))
582    }
583
584    fn load_from_gltf_internal(content: (gltf::Document, Vec<gltf::buffer::Data>, Vec<gltf::image::Data>), mut object: Object, rig_scale_multiplier: f32) -> Self {
585        let (gltf, buffers, _images) = content;
586        for mesh in gltf.meshes() {
587            let mut vertices = Vec::new();
588            let mut indices = Vec::new();
589            for primitive in mesh.primitives() {
590                let reader = primitive.reader(|buffer| buffers.get(buffer.index()).map(|data| &data[..]));
591
592                let positions = reader.read_positions().unwrap();
593                let normals = reader.read_normals().unwrap();
594                let tex_coords = reader.read_tex_coords(0).unwrap().into_f32();
595                let prim_indices = reader.read_indices().unwrap().into_u32();
596
597                // Read skinning data
598                let joints = reader.read_joints(0).map(|j| j.into_u16());
599                let weights = reader.read_weights(0).map(|w| w.into_f32());
600
601                let mut flipped_tex_coords: Vec<[f32; 2]> = Vec::new();
602                for mut tex_coord in tex_coords.into_iter() {
603                    tex_coord[1] = 1.0 - tex_coord[1];
604                    flipped_tex_coords.push(tex_coord);
605                }
606
607                let mut joint_data = joints.map(|j| j.map(|arr| [arr[0] as u32, arr[1] as u32, arr[2] as u32, arr[3] as u32]));
608                let mut weight_data = weights;
609
610                for ((position, normal), tex_coord) in positions.zip(normals).zip(flipped_tex_coords) {
611                    let bone_indices = joint_data.as_mut().and_then(|j| j.next()).unwrap_or([0; 4]);
612                    let bone_weight = weight_data.as_mut().and_then(|w| w.next()).unwrap_or([0.0; 4]);
613                    let vertex = Vertex {
614                        position,
615                        texcoord: tex_coord,
616                        color: [1.0, 1.0, 1.0],
617                        normal,
618                        bone_indices,
619                        bone_weights: bone_weight,
620                    };
621                    vertices.push(vertex);
622                }
623
624                indices.extend(prim_indices);
625            }
626            let shape = Shape::from_vertices_indices(vertices, indices);
627            object.add_shape(shape);
628        }
629
630        if let Some(skin) = gltf.skins().next() {
631            let skeleton = Object::load_skeleton_internal(&gltf, &skin, &buffers, rig_scale_multiplier);
632            match skeleton.validate() {
633                Err(e) => e.log(),
634                Ok(_) => ()
635            }
636            object.skeleton = Some(skeleton)
637
638        }
639        let animations = gltf.animations();
640        for (i, animation) in animations.enumerate() {
641            let loaded_anim = Object::load_animation_internal(&animation, &buffers, i, 1.);
642            object.animations.insert(loaded_anim.name.clone(), loaded_anim);
643        }
644        object
645    }
646
647    fn load_skeleton_internal(document: &gltf::Document, skin: &gltf::Skin, buffers: &[gltf::buffer::Data], multiplier: f32) -> animation::Skeleton {
648        let reader = skin.reader(|buffer| Some(&buffers[buffer.index()]));
649
650        // Get joints from the skin
651        let joints: Vec<gltf::Node> = skin.joints().collect();
652
653        // Read inverse bind matrices
654        let mut inverse_bind_matrices: Vec<Matrix4<f32>> = reader.read_inverse_bind_matrices()
655            .map(|iter| iter.map(Matrix4::from).collect())
656            .unwrap_or_else(|| vec![Matrix4::identity(); joints.len()]);
657
658        // apply scale multiplier
659        inverse_bind_matrices = inverse_bind_matrices.iter_mut().map(|x| *x * multiplier).collect();
660
661        // Create a map of child to parent relationships
662        let mut parent_map = HashMap::new();
663        for node in document.nodes() {
664            for child in node.children() {
665                parent_map.insert(child.index(), node.index());
666            }
667        }
668
669        let joint_node_indices: Vec<usize> = joints.iter().map(|j| j.index()).collect();
670
671        let bones = joints.into_iter().enumerate().zip(inverse_bind_matrices).map(|((id, joint), ibm)| {
672            let node_idx = joint.index();
673            let parent_id = parent_map.get(&node_idx)
674                .and_then(|parent_node_idx| joint_node_indices.iter().position(|&ni| ni == *parent_node_idx));
675            animation::Bone {
676                name: joint.name().unwrap_or("").to_string(),
677                id,
678                node_index: node_idx,
679                parent_id,
680                inverse_bind_pose: ibm,
681            }
682        }).collect();
683
684        // Compute the world-space transform of the node that is the parent of the root joint(s).
685        // This is needed because IBMs are baked in world space but our hierarchy starts from
686        // the joint root, which may have an ancestor with a non-identity transform (e.g., Blender's
687        // Z-up → Y-up correction and unit scale applied to the armature node).
688        let root_joint_node_idx = joint_node_indices.first().copied().unwrap_or(0);
689        let root_transform = if let Some(&armature_idx) = parent_map.get(&root_joint_node_idx) {
690            let nodes: Vec<gltf::Node> = document.nodes().collect();
691            // Walk from armature up to the scene root, accumulating transforms.
692            let mut chain = Vec::new();
693            let mut current = armature_idx;
694            loop {
695                chain.push(Matrix4::from(nodes[current].transform().matrix()));
696                match parent_map.get(&current) {
697                    Some(&p) => current = p,
698                    None => break,
699                }
700            }
701            chain.iter().rev().fold(Matrix4::identity(), |acc, m| acc * m)
702        } else {
703            Matrix4::identity()
704        };
705
706        animation::Skeleton { bones, root_transform }
707    }
708
709    fn load_animation_internal(anim: &gltf::Animation, buffers: &[gltf::buffer::Data], padding: usize, multiplier: f32) -> animation::Animation {
710        let mut channels = Vec::new();
711        let mut duration: f32 = 0.0;
712        let name = match anim.name() {
713            Some(n) => n.to_string(),
714            None => format!("animation_{}", padding)
715        };
716        for channel in anim.channels() {
717            let reader = channel.reader(|buffer| Some(&buffers[buffer.index()]));
718            let bone_id = channel.target().node().index();
719            let mut keyframes = Vec::new();
720            if let (Some(times), Some(outputs)) = (reader.read_inputs(), reader.read_outputs()) {
721                let times: Vec<f32> = times.collect();
722                // Update max_time
723                if let Some(&channel_duration) = times.iter().max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal)) {
724                    duration = duration.max(channel_duration);
725                }
726                match outputs {
727                    gltf::animation::util::ReadOutputs::Translations(translations) => {
728                        for (i, translation) in translations.enumerate() {
729                            let translation = Vector3::from(translation);
730                            keyframes.push(animation::AnimationKeyframe {
731                                time: times[i],
732                                transform: animation::AnimationTransform::Translation((translation * multiplier).into()),
733                            });
734                        }
735                    }
736                    gltf::animation::util::ReadOutputs::Rotations(rotations) => {
737                        for (i, rotation) in rotations.into_f32().enumerate() {
738                            let rotation = UnitQuaternion::from_quaternion(
739                                nalgebra::Quaternion::new(rotation[3], rotation[0], rotation[1], rotation[2])
740                            );
741                            keyframes.push(animation::AnimationKeyframe {
742                                time: times[i],
743                                transform: animation::AnimationTransform::Rotation([rotation[0], rotation[1], rotation[2], rotation[3]]),
744                            });
745                        }
746                    }
747                    gltf::animation::util::ReadOutputs::Scales(scales) => {
748                        for (i, scale) in scales.enumerate() {
749                            let scale = Vector3::from(scale);
750                            keyframes.push(animation::AnimationKeyframe {
751                                time: times[i],
752                                transform: animation::AnimationTransform::Scale((scale * multiplier).into()),
753                            });
754                        }
755                    }
756                    gltf::animation::util::ReadOutputs::MorphTargetWeights(_) => {
757                        // Handle morph target weights if needed
758                        // For now, we'll just ignore these
759                    }
760                }
761            }
762
763            if !keyframes.is_empty() {
764                channels.push(animation::AnimationChannel { bone_id, keyframes });
765            }
766        }
767
768        animation::Animation {
769            name,
770            duration,
771            channels,
772        }
773    }
774}
775
776#[derive(Serialize, Deserialize, Clone)]
777pub struct TransformSerializer {
778    position: [f32; 3],
779    rotation: [f32; 3],
780    scale: [f32; 3],
781}
782
783#[derive(Copy, Clone)]
784pub struct Transform {
785    pub position: Vector3<f32>,
786    pub rotation: Vector3<f32>,
787    // radian angles
788    pub scale: Vector3<f32>,
789    pub matrix: Matrix4<f32>,
790}
791
792impl Transform {
793    pub fn new() -> Self {
794        Transform {
795            position: Vector3::new(0.0, 0.0, 0.0),
796            rotation: Vector3::new(0.0, 0.0, 0.0),
797            scale: Vector3::new(1.0, 1.0, 1.0),
798            matrix: Matrix4::identity(),
799        }
800    }
801
802    pub fn forward(&self) -> Vector3<f32> {
803        // return the forward vector of the transform with positive z being forward
804        let rotation = UnitQuaternion::from_euler_angles(self.rotation.x, self.rotation.y, self.rotation.z);
805        let forward = rotation * Vector3::new(0.0, 0.0, 1.0);
806        normalize(&forward)
807    }
808
809    pub fn left(&self) -> Vector3<f32> {
810        // return the left vector of the transform with positive x being left
811        let rotation = UnitQuaternion::from_euler_angles(self.rotation.x, self.rotation.y, self.rotation.z);
812        let left = rotation * Vector3::new(-1.0, 0.0, 0.0);
813        normalize(&left)
814    }
815
816    pub fn up(&self) -> Vector3<f32> {
817        // return the up vector of the transform with positive y being up
818        let rotation = UnitQuaternion::from_euler_angles(self.rotation.x, self.rotation.y, self.rotation.z);
819        let up = rotation * Vector3::new(0.0, 1.0, 0.0);
820        normalize(&up)
821    }
822
823    pub fn from_serializer(serializer: TransformSerializer) -> Self {
824        let mut t = Transform::new();
825        t.set_position(serializer.position);
826        t.set_rotation(serializer.rotation);
827        t.set_scale(serializer.scale);
828        t
829    }
830
831    pub fn to_serializer(&self) -> TransformSerializer {
832        TransformSerializer {
833            position: self.get_position().into(),
834            rotation: self.get_rotation().into(),
835            scale: self.get_scale().into(),
836        }
837    }
838
839    pub fn update(&mut self) {
840        let scale_matrix = Matrix4::new_nonuniform_scaling(&self.scale);
841        let rotation_matrix = UnitQuaternion::from_euler_angles(self.rotation.x, self.rotation.y, self.rotation.z).to_homogeneous();
842        let translation_matrix = Translation3::from(self.position).to_homogeneous();
843        // Scale, then rotate, then translate
844        self.matrix = translation_matrix * rotation_matrix * scale_matrix;
845    }
846
847
848    pub fn set_position(&mut self, position: [f32; 3]) {
849        self.position = Vector3::from(position);
850    }
851
852    pub fn get_position(&self) -> Vector3<f32> {
853        self.position.clone()
854    }
855
856    pub fn set_rotation(&mut self, rotation: [f32; 3]) {
857        let radians = rotation.iter().map(|x| x.to_radians()).collect::<Vec<f32>>();
858        self.rotation = Vector3::from([radians[0], radians[1], radians[2]]);
859    }
860
861    pub fn rotate(&mut self, rotation: [f32; 3]) {
862        let cur_r = self.get_rotation();
863        let additive_rotation = [cur_r.x + rotation[0], cur_r.y + rotation[1], cur_r.z + rotation[2]];
864        let radians = additive_rotation.iter().map(|x| x.to_radians()).collect::<Vec<f32>>();
865        self.rotation = Vector3::from([radians[0], radians[1], radians[2]]);
866    }
867
868    pub fn move_dir_array(&mut self, position: [f32; 3]) {
869        let cur_p = self.get_position();
870        let additive_position = [cur_p.x + position[0], cur_p.y + position[1], cur_p.z + position[2]];
871        self.position = Vector3::from(additive_position);
872    }
873
874    pub fn move_dir_vector(&mut self, direction: Vector3<f32>) {
875        self.position += direction;
876    }
877
878    pub fn get_rotation(&self) -> Vector3<f32> {
879        let x = self.rotation.x.to_degrees();
880        let y = self.rotation.y.to_degrees();
881        let z = self.rotation.z.to_degrees();
882        Vector3::from([x, y, z])
883    }
884
885    pub fn set_scale(&mut self, scale: [f32; 3]) {
886        self.scale = Vector3::from(scale);
887    }
888
889    pub fn get_scale(&self) -> Vector3<f32> {
890        self.scale.clone()
891    }
892
893    pub fn get_matrix(&mut self) -> [[f32; 4]; 4] {
894        self.update();
895        self.matrix.into()
896    }
897
898    pub fn get_matrix_object(&mut self) -> Matrix4<f32> {
899        self.update();
900        self.matrix
901    }
902
903    pub fn lerp(&self, other: &Self, t: f32) -> Self {
904        let position = self.get_position().lerp(&other.get_position(), t);
905        let scale = self.get_scale().lerp(&other.get_scale(), t);
906        let rotation = self.get_rotation().slerp(&other.get_rotation(), t);
907
908        let mut result = Self::new();
909        result.set_position(position.into());
910        result.set_scale(scale.into());
911        result.set_rotation(rotation.into());
912        result
913    }
914}