khora_core/asset/materials/
wireframe.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//! Defines wireframe materials for debug visualization and editor tools.
16
17use crate::{
18    asset::{Asset, Material},
19    math::LinearRgba,
20};
21
22/// A material that renders geometry as a wireframe for debugging and editor visualization.
23///
24/// Wireframe materials are essential for debug views, editor gizmos, and understanding
25/// the underlying geometry of meshes. This material will integrate with the future
26/// EditorGizmo RenderLane (issue #167) and is designed for development and debugging,
27/// not production rendering.
28///
29/// # Performance Note
30///
31/// Wireframe rendering typically requires either:
32/// - A geometry shader to generate line primitives
33/// - Barycentric coordinates in the fragment shader
34///
35/// The exact implementation will depend on the graphics backend capabilities.
36/// This material is intended for debug/editor contexts where performance is less critical.
37///
38/// # Examples
39///
40/// ```
41/// use khora_core::asset::WireframeMaterial;
42/// use khora_core::math::LinearRgba;
43///
44/// // Create a green wireframe for debug visualization
45/// let debug_wireframe = WireframeMaterial {
46///     color: LinearRgba::new(0.0, 1.0, 0.0, 1.0),
47///     line_width: 1.5,
48/// };
49///
50/// // Create a thin white wireframe for mesh inspection
51/// let mesh_inspector = WireframeMaterial {
52///     color: LinearRgba::new(1.0, 1.0, 1.0, 1.0),
53///     line_width: 1.0,
54/// };
55/// ```
56#[derive(Clone, Debug)]
57pub struct WireframeMaterial {
58    /// The color of the wireframe lines.
59    ///
60    /// This color is used for all edges of the geometry. Typically bright colors
61    /// like green, cyan, or white are used for maximum visibility against the scene.
62    pub color: LinearRgba,
63
64    /// The width of the wireframe lines in pixels.
65    ///
66    /// Note that line width support varies by platform and graphics backend:
67    /// - **Vulkan**: Limited support for line widths other than 1.0
68    /// - **Metal/DX12**: Good support for varying line widths
69    /// - **WebGPU**: Limited to 1.0 pixel lines
70    ///
71    /// For maximum compatibility, use 1.0. The rendering system may clamp this value
72    /// based on backend capabilities.
73    pub line_width: f32,
74}
75
76impl Default for WireframeMaterial {
77    fn default() -> Self {
78        Self {
79            color: LinearRgba::new(0.0, 1.0, 0.0, 1.0), // Green - common for wireframes
80            line_width: 1.0,                            // Standard 1-pixel lines
81        }
82    }
83}
84
85impl Asset for WireframeMaterial {}
86impl Material for WireframeMaterial {}
87
88#[cfg(test)]
89mod tests {
90    use super::*;
91
92    #[test]
93    fn test_wireframe_material_default() {
94        let material = WireframeMaterial::default();
95
96        assert_eq!(material.color, LinearRgba::new(0.0, 1.0, 0.0, 1.0));
97        assert_eq!(material.line_width, 1.0);
98    }
99
100    #[test]
101    fn test_wireframe_material_custom_color() {
102        let material = WireframeMaterial {
103            color: LinearRgba::new(1.0, 0.0, 0.0, 1.0),
104            ..Default::default()
105        };
106
107        assert_eq!(material.color, LinearRgba::new(1.0, 0.0, 0.0, 1.0));
108    }
109
110    #[test]
111    fn test_wireframe_material_line_widths() {
112        // Test default line width
113        let thin = WireframeMaterial {
114            line_width: 1.0,
115            ..Default::default()
116        };
117        assert_eq!(thin.line_width, 1.0);
118
119        // Test thicker line
120        let thick = WireframeMaterial {
121            line_width: 2.5,
122            ..Default::default()
123        };
124        assert_eq!(thick.line_width, 2.5);
125    }
126
127    #[test]
128    fn test_wireframe_material_clone() {
129        let original = WireframeMaterial {
130            color: LinearRgba::new(0.5, 0.5, 1.0, 1.0),
131            line_width: 1.5,
132        };
133
134        let cloned = original.clone();
135        assert_eq!(cloned.color, original.color);
136        assert_eq!(cloned.line_width, original.line_width);
137    }
138
139    #[test]
140    fn test_wireframe_material_common_colors() {
141        // Test common wireframe colors
142        let green = WireframeMaterial {
143            color: LinearRgba::new(0.0, 1.0, 0.0, 1.0),
144            ..Default::default()
145        };
146        assert_eq!(green.color.g, 1.0);
147
148        let cyan = WireframeMaterial {
149            color: LinearRgba::new(0.0, 1.0, 1.0, 1.0),
150            ..Default::default()
151        };
152        assert_eq!(cyan.color.g, 1.0);
153        assert_eq!(cyan.color.b, 1.0);
154
155        let white = WireframeMaterial {
156            color: LinearRgba::new(1.0, 1.0, 1.0, 1.0),
157            ..Default::default()
158        };
159        assert_eq!(white.color.r, 1.0);
160        assert_eq!(white.color.g, 1.0);
161        assert_eq!(white.color.b, 1.0);
162    }
163}