Skip to main content

oxihuman_viewer/
depth_buffer_view.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan) / SPDX-License-Identifier: Apache-2.0
2#![allow(dead_code)]
3
4//! Depth buffer visualization (linear/log remapping).
5
6/// Depth remapping mode.
7#[allow(dead_code)]
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum DepthRemapMode {
10    Linear,
11    Logarithmic,
12    Reversed,
13}
14
15/// Depth buffer view configuration.
16#[allow(dead_code)]
17#[derive(Debug, Clone)]
18pub struct DepthBufferViewConfig {
19    /// Near plane distance.
20    pub near: f32,
21    /// Far plane distance.
22    pub far: f32,
23    /// Remapping mode.
24    pub mode: DepthRemapMode,
25    /// Enabled.
26    pub enabled: bool,
27    /// Contrast boost 0..=4.
28    pub contrast: f32,
29}
30
31impl Default for DepthBufferViewConfig {
32    fn default() -> Self {
33        Self {
34            near: 0.1,
35            far: 100.0,
36            mode: DepthRemapMode::Linear,
37            enabled: false,
38            contrast: 1.0,
39        }
40    }
41}
42
43/// Create default config.
44#[allow(dead_code)]
45pub fn new_depth_buffer_view_config() -> DepthBufferViewConfig {
46    DepthBufferViewConfig::default()
47}
48
49/// Remap a raw depth value [0..=1] to a display value [0..=1].
50#[allow(dead_code)]
51pub fn remap_depth(raw: f32, cfg: &DepthBufferViewConfig) -> f32 {
52    let raw = raw.clamp(0.0, 1.0);
53    let range = cfg.far - cfg.near;
54    let linear = if range > 0.0 {
55        (raw * range + cfg.near - cfg.near) / range
56    } else {
57        raw
58    };
59    let result = match cfg.mode {
60        DepthRemapMode::Linear => linear,
61        DepthRemapMode::Logarithmic => {
62            if linear > 0.0 {
63                (linear.ln() + 1.0).clamp(0.0, 1.0)
64            } else {
65                0.0
66            }
67        }
68        DepthRemapMode::Reversed => 1.0 - linear,
69    };
70    let c = cfg.contrast.clamp(0.0, 4.0);
71    ((result - 0.5) * c + 0.5).clamp(0.0, 1.0)
72}
73
74/// Enable/disable depth view.
75#[allow(dead_code)]
76pub fn dbv_enable(cfg: &mut DepthBufferViewConfig) {
77    cfg.enabled = true;
78}
79
80/// Disable depth view.
81#[allow(dead_code)]
82pub fn dbv_disable(cfg: &mut DepthBufferViewConfig) {
83    cfg.enabled = false;
84}
85
86/// Set remap mode.
87#[allow(dead_code)]
88pub fn dbv_set_mode(cfg: &mut DepthBufferViewConfig, mode: DepthRemapMode) {
89    cfg.mode = mode;
90}
91
92/// Set contrast.
93#[allow(dead_code)]
94pub fn dbv_set_contrast(cfg: &mut DepthBufferViewConfig, contrast: f32) {
95    cfg.contrast = contrast.clamp(0.0, 4.0);
96}
97
98/// Depth value to grayscale color [R, G, B, A].
99#[allow(dead_code)]
100pub fn depth_to_color(raw: f32, cfg: &DepthBufferViewConfig) -> [f32; 4] {
101    let d = remap_depth(raw, cfg);
102    [d, d, d, 1.0]
103}
104
105/// Serialize to JSON.
106#[allow(dead_code)]
107pub fn depth_buffer_view_to_json(cfg: &DepthBufferViewConfig) -> String {
108    let mode = match cfg.mode {
109        DepthRemapMode::Linear => "linear",
110        DepthRemapMode::Logarithmic => "log",
111        DepthRemapMode::Reversed => "reversed",
112    };
113    format!(
114        r#"{{"near":{:.4},"far":{:.4},"mode":"{}","enabled":{},"contrast":{:.4}}}"#,
115        cfg.near, cfg.far, mode, cfg.enabled, cfg.contrast
116    )
117}
118
119#[cfg(test)]
120mod tests {
121    use super::*;
122
123    #[test]
124    fn test_default() {
125        let c = DepthBufferViewConfig::default();
126        assert!(!c.enabled);
127    }
128
129    #[test]
130    fn test_remap_linear_pass() {
131        let c = DepthBufferViewConfig {
132            contrast: 1.0,
133            ..Default::default()
134        };
135        let d = remap_depth(0.5, &c);
136        assert!((d - 0.5).abs() < 1e-5);
137    }
138
139    #[test]
140    fn test_remap_reversed() {
141        let c = DepthBufferViewConfig {
142            mode: DepthRemapMode::Reversed,
143            contrast: 1.0,
144            ..Default::default()
145        };
146        let d = remap_depth(0.0, &c);
147        assert!((d - 1.0).abs() < 1e-5);
148    }
149
150    #[test]
151    fn test_remap_clamp() {
152        let c = DepthBufferViewConfig::default();
153        let d = remap_depth(5.0, &c);
154        assert!((0.0..=1.0).contains(&d));
155    }
156
157    #[test]
158    fn test_enable_disable() {
159        let mut c = DepthBufferViewConfig::default();
160        dbv_enable(&mut c);
161        assert!(c.enabled);
162        dbv_disable(&mut c);
163        assert!(!c.enabled);
164    }
165
166    #[test]
167    fn test_set_mode() {
168        let mut c = DepthBufferViewConfig::default();
169        dbv_set_mode(&mut c, DepthRemapMode::Logarithmic);
170        assert_eq!(c.mode, DepthRemapMode::Logarithmic);
171    }
172
173    #[test]
174    fn test_set_contrast_clamp() {
175        let mut c = DepthBufferViewConfig::default();
176        dbv_set_contrast(&mut c, 10.0);
177        assert!((c.contrast - 4.0).abs() < 1e-6);
178    }
179
180    #[test]
181    fn test_depth_to_color_channels() {
182        let c = DepthBufferViewConfig::default();
183        let col = depth_to_color(0.5, &c);
184        assert!((col[0] - col[1]).abs() < 1e-6);
185        assert!((col[3] - 1.0).abs() < 1e-6);
186    }
187
188    #[test]
189    fn test_to_json() {
190        let j = depth_buffer_view_to_json(&DepthBufferViewConfig::default());
191        assert!(j.contains("near"));
192        assert!(j.contains("mode"));
193    }
194
195    #[test]
196    fn test_log_mode_nonzero() {
197        let c = DepthBufferViewConfig {
198            mode: DepthRemapMode::Logarithmic,
199            contrast: 1.0,
200            ..Default::default()
201        };
202        let d = remap_depth(0.5, &c);
203        assert!(d >= 0.0);
204    }
205}