Skip to main content

ling_graphics/
scene.rs

1use std::sync::Arc;
2use glam::{Vec3, Quat, Mat4};
3use crate::geometry::Mesh;
4use crate::material::Material;
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 { Self { translation: t, ..Self::IDENTITY } }
23    pub fn from_rotation(r: Quat) -> Self    { Self { rotation: r, ..Self::IDENTITY } }
24    pub fn from_scale(s: Vec3) -> Self       { Self { scale: s, ..Self::IDENTITY } }
25
26    pub fn from_trs(translation: Vec3, rotation: Quat, scale: Vec3) -> Self {
27        Self { translation, rotation, scale }
28    }
29
30    pub fn matrix(&self) -> Mat4 {
31        Mat4::from_scale_rotation_translation(self.scale, self.rotation, self.translation)
32    }
33
34    pub fn global_matrix(&self, parent: &Mat4) -> Mat4 {
35        *parent * self.matrix()
36    }
37
38    pub fn forward(&self) -> Vec3 { self.rotation * -Vec3::Z }
39    pub fn right(&self)   -> Vec3 { self.rotation *  Vec3::X }
40    pub fn up(&self)      -> Vec3 { self.rotation *  Vec3::Y }
41
42    pub fn look_at(&mut self, target: Vec3, world_up: Vec3) {
43        let dir = (target - self.translation).normalize();
44        if dir.length_squared() < 1e-8 { return; }
45        let mat = Mat4::look_at_rh(self.translation, target, world_up);
46        let (_, rot, _) = mat.inverse().to_scale_rotation_translation();
47        self.rotation = rot;
48    }
49
50    pub fn lerp(&self, other: &Self, t: f32) -> Self {
51        Self {
52            translation: self.translation.lerp(other.translation, t),
53            rotation: self.rotation.slerp(other.rotation, t),
54            scale: self.scale.lerp(other.scale, t),
55        }
56    }
57}
58
59impl Default for Transform {
60    fn default() -> Self { Self::IDENTITY }
61}
62
63// ── Scene graph ───────────────────────────────────────────────────────────────
64
65pub type NodeId = usize;
66
67#[derive(Debug, Clone)]
68pub struct SceneNode {
69    pub name: String,
70    pub transform: Transform,
71    pub mesh: Option<Arc<Mesh>>,
72    pub material: Option<Arc<Material>>,
73    pub visible: bool,
74    pub children: Vec<NodeId>,
75    pub parent: Option<NodeId>,
76}
77
78impl SceneNode {
79    pub fn new(name: impl Into<String>) -> Self {
80        Self {
81            name: name.into(),
82            transform: Transform::IDENTITY,
83            mesh: None,
84            material: None,
85            visible: true,
86            children: Vec::new(),
87            parent: None,
88        }
89    }
90
91    pub fn with_mesh(mut self, mesh: Arc<Mesh>) -> Self { self.mesh = Some(mesh); self }
92    pub fn with_material(mut self, mat: Arc<Material>) -> Self { self.material = Some(mat); self }
93    pub fn with_transform(mut self, t: Transform) -> Self { self.transform = t; self }
94}
95
96#[derive(Debug, Default)]
97pub struct Scene {
98    nodes: Vec<SceneNode>,
99    roots: Vec<NodeId>,
100}
101
102impl Scene {
103    pub fn new() -> Self { Self::default() }
104
105    pub fn add_node(&mut self, node: SceneNode) -> NodeId {
106        let id = self.nodes.len();
107        self.nodes.push(node);
108        id
109    }
110
111    pub fn add_root(&mut self, id: NodeId) { self.roots.push(id); }
112
113    pub fn add_child(&mut self, parent: NodeId, child: NodeId) {
114        self.nodes[child].parent = Some(parent);
115        self.nodes[parent].children.push(child);
116    }
117
118    pub fn node(&self, id: NodeId) -> &SceneNode { &self.nodes[id] }
119    pub fn node_mut(&mut self, id: NodeId) -> &mut SceneNode { &mut self.nodes[id] }
120
121    pub fn roots(&self) -> &[NodeId] { &self.roots }
122
123    pub fn global_transform(&self, id: NodeId) -> Mat4 {
124        let node = &self.nodes[id];
125        match node.parent {
126            None => node.transform.matrix(),
127            Some(parent_id) => self.global_transform(parent_id) * node.transform.matrix(),
128        }
129    }
130
131    /// Collect all visible (node, global_matrix) pairs in DFS order.
132    pub fn collect_render_items(&self) -> Vec<(NodeId, Mat4)> {
133        let mut out = Vec::new();
134        for &root in &self.roots {
135            self.collect_recursive(root, Mat4::IDENTITY, &mut out);
136        }
137        out
138    }
139
140    fn collect_recursive(&self, id: NodeId, parent_mat: Mat4, out: &mut Vec<(NodeId, Mat4)>) {
141        let node = &self.nodes[id];
142        if !node.visible { return; }
143        let mat = parent_mat * node.transform.matrix();
144        if node.mesh.is_some() {
145            out.push((id, mat));
146        }
147        for &child in &node.children {
148            self.collect_recursive(child, mat, out);
149        }
150    }
151
152    /// Convenience: create a mesh node, add it as a root, and return its id.
153    pub fn spawn_mesh(&mut self, name: impl Into<String>, mesh: Arc<Mesh>, material: Arc<Material>, transform: Transform) -> NodeId {
154        let node = SceneNode::new(name)
155            .with_mesh(mesh)
156            .with_material(material)
157            .with_transform(transform);
158        let id = self.add_node(node);
159        self.add_root(id);
160        id
161    }
162}