Skip to main content

khora_data/render/
gizmo.rs

1// Copyright 2025 eraflo
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Per-frame gizmo output slot for the
16//! [`OutputDeck`](khora_core::lane::OutputDeck).
17//!
18//! Producers (typically the editor application) push line instances
19//! into `GizmoFrame.lines`; the engine-side `GizmoLane` consumes the
20//! slot and renders the overlay. Empty by default — a frame with no
21//! gizmos triggers no GPU work.
22//!
23//! Symmetric to the [`ShadowFrame`](khora_core::renderer::api::shadow::ShadowFrame)
24//! pattern: only contract types live in `khora-data`, no GPU code.
25
26use khora_core::ui::editor::GizmoLineInstance;
27
28/// Per-frame gizmo lines published by a host application (editor,
29/// debug tooling) and consumed by the engine's `GizmoLane`.
30#[derive(Debug, Default, Clone)]
31pub struct GizmoFrame {
32    /// Line segments to draw this frame.
33    pub lines: Vec<GizmoLineInstance>,
34}
35
36impl GizmoFrame {
37    /// Returns true when no producer published any lines this frame.
38    pub fn is_empty(&self) -> bool {
39        self.lines.is_empty()
40    }
41
42    /// Returns the number of line instances queued this frame.
43    pub fn len(&self) -> usize {
44        self.lines.len()
45    }
46
47    /// Clears all queued lines.
48    pub fn clear(&mut self) {
49        self.lines.clear();
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56    use khora_core::lane::OutputDeck;
57    use khora_core::math::Vec3;
58
59    #[test]
60    fn gizmo_frame_deck_round_trip() {
61        let mut deck = OutputDeck::new();
62        {
63            let frame = deck.slot::<GizmoFrame>();
64            frame.lines.push(GizmoLineInstance::new(
65                Vec3::ZERO,
66                Vec3::new(1.0, 0.0, 0.0),
67                [1.0, 0.0, 0.0, 1.0],
68            ));
69        }
70        let taken: GizmoFrame = deck.take();
71        assert_eq!(taken.len(), 1);
72    }
73
74    #[test]
75    fn empty_by_default() {
76        let frame = GizmoFrame::default();
77        assert!(frame.is_empty());
78    }
79}