Skip to main content

ling_graphics/
scene.rs

1use crate::geometry::Mesh;
2use crate::material::Material;
3use glam::{Mat4, Quat, Vec3};
4use std::sync::Arc;
5
6// ── Transform ─────────────────────────────────────────────────────────────────
7
8#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
9pub struct Transform {
10    pub translation: Vec3,
11    pub rotation: Quat,
12    pub scale: Vec3,
13}
14
15impl Transform {
16    pub const IDENTITY: Self = Self {
17        translation: Vec3::ZERO,
18        rotation: Quat::IDENTITY,
19        scale: Vec3::ONE,
20    };
21
22    pub fn from_translation(t: Vec3) -> Self {
23        Self { translation: t, ..Self::IDENTITY }
24    }
25
26    pub fn from_rotation(r: Quat) -> Self {
27        Self { rotation: r, ..Self::IDENTITY }
28    }
29
30    pub fn from_scale(s: Vec3) -> Self {
31        Self { scale: s, ..Self::IDENTITY }
32    }
33
34    pub fn from_trs(translation: Vec3, rotation: Quat, scale: Vec3) -> Self {
35        Self { translation, rotation, scale }
36    }
37
38    pub fn matrix(&self) -> Mat4 {
39        Mat4::from_scale_rotation_translation(self.scale, self.rotation, self.translation)
40    }
41
42    pub fn global_matrix(&self, parent: &Mat4) -> Mat4 {
43        *parent * self.matrix()
44    }
45
46    pub fn forward(&self) -> Vec3 {
47        self.rotation * -Vec3::Z
48    }
49
50    pub fn right(&self) -> Vec3 {
51        self.rotation * Vec3::X
52    }
53
54    pub fn up(&self) -> Vec3 {
55        self.rotation * Vec3::Y
56    }
57
58    pub fn look_at(&mut self, target: Vec3, world_up: Vec3) {
59        let dir = (target - self.translation).normalize();
60        if dir.length_squared() < 1e-8 {
61            return;
62        }
63        let mat = glam::camera::rh::view::look_at_mat4(self.translation, target, world_up);
64        let (_, rot, _) = mat.inverse().to_scale_rotation_translation();
65        self.rotation = rot;
66    }
67
68    pub fn lerp(&self, other: &Self, t: f32) -> Self {
69        Self {
70            translation: self.translation.lerp(other.translation, t),
71            rotation: self.rotation.slerp(other.rotation, t),
72            scale: self.scale.lerp(other.scale, t),
73        }
74    }
75}
76
77impl Default for Transform {
78    fn default() -> Self {
79        Self::IDENTITY
80    }
81}
82
83// ── Scene graph ───────────────────────────────────────────────────────────────
84
85pub type NodeId = usize;
86
87#[derive(Debug, Clone)]
88pub struct SceneNode {
89    pub name: String,
90    pub transform: Transform,
91    pub mesh: Option<Arc<Mesh>>,
92    pub material: Option<Arc<Material>>,
93    pub visible: bool,
94    pub children: Vec<NodeId>,
95    pub parent: Option<NodeId>,
96}
97
98impl SceneNode {
99    pub fn new(name: impl Into<String>) -> Self {
100        Self {
101            name: name.into(),
102            transform: Transform::IDENTITY,
103            mesh: None,
104            material: None,
105            visible: true,
106            children: Vec::new(),
107            parent: None,
108        }
109    }
110
111    pub fn with_mesh(mut self, mesh: Arc<Mesh>) -> Self {
112        self.mesh = Some(mesh);
113        self
114    }
115
116    pub fn with_material(mut self, mat: Arc<Material>) -> Self {
117        self.material = Some(mat);
118        self
119    }
120
121    pub fn with_transform(mut self, t: Transform) -> Self {
122        self.transform = t;
123        self
124    }
125}
126
127#[derive(Debug, Default)]
128pub struct Scene {
129    nodes: Vec<SceneNode>,
130    roots: Vec<NodeId>,
131}
132
133impl Scene {
134    pub fn new() -> Self {
135        Self::default()
136    }
137
138    pub fn add_node(&mut self, node: SceneNode) -> NodeId {
139        let id = self.nodes.len();
140        self.nodes.push(node);
141        id
142    }
143
144    pub fn add_root(&mut self, id: NodeId) {
145        self.roots.push(id);
146    }
147
148    pub fn add_child(&mut self, parent: NodeId, child: NodeId) {
149        self.nodes[child].parent = Some(parent);
150        self.nodes[parent].children.push(child);
151    }
152
153    pub fn node(&self, id: NodeId) -> &SceneNode {
154        &self.nodes[id]
155    }
156
157    pub fn node_mut(&mut self, id: NodeId) -> &mut SceneNode {
158        &mut self.nodes[id]
159    }
160
161    pub fn roots(&self) -> &[NodeId] {
162        &self.roots
163    }
164
165    pub fn global_transform(&self, id: NodeId) -> Mat4 {
166        let node = &self.nodes[id];
167        match node.parent {
168            None => node.transform.matrix(),
169            Some(parent_id) => self.global_transform(parent_id) * node.transform.matrix(),
170        }
171    }
172
173    /// Collect all visible (node, global_matrix) pairs in DFS order.
174    pub fn collect_render_items(&self) -> Vec<(NodeId, Mat4)> {
175        let mut out = Vec::new();
176        for &root in &self.roots {
177            self.collect_recursive(root, Mat4::IDENTITY, &mut out);
178        }
179        out
180    }
181
182    fn collect_recursive(&self, id: NodeId, parent_mat: Mat4, out: &mut Vec<(NodeId, Mat4)>) {
183        let node = &self.nodes[id];
184        if !node.visible {
185            return;
186        }
187        let mat = parent_mat * node.transform.matrix();
188        if node.mesh.is_some() {
189            out.push((id, mat));
190        }
191        for &child in &node.children {
192            self.collect_recursive(child, mat, out);
193        }
194    }
195
196    /// Convenience: create a mesh node, add it as a root, and return its id.
197    pub fn spawn_mesh(
198        &mut self,
199        name: impl Into<String>,
200        mesh: Arc<Mesh>,
201        material: Arc<Material>,
202        transform: Transform,
203    ) -> NodeId {
204        let node = SceneNode::new(name)
205            .with_mesh(mesh)
206            .with_material(material)
207            .with_transform(transform);
208        let id = self.add_node(node);
209        self.add_root(id);
210        id
211    }
212}