Skip to main content

esoc_scene/
node.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2//! Scene graph node types.
3
4use crate::mark::{Mark, MarkBatch, MarkKey};
5use crate::transform::Affine2D;
6
7/// A handle to a node in the scene graph.
8#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
9pub struct NodeId {
10    /// Slot index in the arena.
11    pub index: u32,
12    /// Generation counter for ABA safety.
13    pub generation: u32,
14}
15
16/// What a node contains.
17pub enum NodeContent {
18    /// A grouping container (no visual output).
19    Container,
20    /// A single visual mark.
21    Mark(Mark),
22    /// A batch of homogeneous marks (for instanced rendering).
23    Batch(MarkBatch),
24}
25
26/// A node in the scene graph.
27pub struct Node {
28    /// Parent node.
29    pub parent: Option<NodeId>,
30    /// Child nodes.
31    pub children: Vec<NodeId>,
32    /// Local transform.
33    pub transform: Affine2D,
34    /// Whether this node clips its children to its bounds.
35    pub clip: bool,
36    /// Z-order for sibling sorting.
37    pub z_order: i32,
38    /// Opacity multiplier `[0, 1]`.
39    pub opacity: f32,
40    /// The visual content of this node.
41    pub content: NodeContent,
42    /// Optional key for scene diffing (transitions).
43    pub key: Option<MarkKey>,
44}
45
46impl Node {
47    /// Create a container node.
48    pub fn container() -> Self {
49        Self {
50            parent: None,
51            children: Vec::new(),
52            transform: Affine2D::IDENTITY,
53            clip: false,
54            z_order: 0,
55            opacity: 1.0,
56            content: NodeContent::Container,
57            key: None,
58        }
59    }
60
61    /// Create a node wrapping a single mark.
62    pub fn with_mark(mark: Mark) -> Self {
63        Self {
64            parent: None,
65            children: Vec::new(),
66            transform: Affine2D::IDENTITY,
67            clip: false,
68            z_order: 0,
69            opacity: 1.0,
70            content: NodeContent::Mark(mark),
71            key: None,
72        }
73    }
74
75    /// Create a node wrapping a mark batch.
76    pub fn with_batch(batch: MarkBatch) -> Self {
77        Self {
78            parent: None,
79            children: Vec::new(),
80            transform: Affine2D::IDENTITY,
81            clip: false,
82            z_order: 0,
83            opacity: 1.0,
84            content: NodeContent::Batch(batch),
85            key: None,
86        }
87    }
88
89    /// Set the transform and return self.
90    pub fn transform(mut self, t: Affine2D) -> Self {
91        self.transform = t;
92        self
93    }
94
95    /// Set `z_order` and return self.
96    pub fn z_order(mut self, z: i32) -> Self {
97        self.z_order = z;
98        self
99    }
100
101    /// Set the key and return self.
102    pub fn key(mut self, k: MarkKey) -> Self {
103        self.key = Some(k);
104        self
105    }
106}