Skip to main content

oxihuman_export/
camera_export.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5//! Export camera data to JSON-compatible format.
6
7use std::f32::consts::PI;
8
9/* ── legacy API (kept) ── */
10
11#[derive(Debug, Clone)]
12pub struct CameraExport {
13    pub name: String,
14    pub position: [f32; 3],
15    pub target: [f32; 3],
16    pub up: [f32; 3],
17    pub fov_y: f32,
18    pub near: f32,
19    pub far: f32,
20    pub camera_type: u8,
21}
22
23pub fn default_camera_export(name: &str) -> CameraExport {
24    CameraExport {
25        name: name.to_string(),
26        position: [0.0, 0.0, 5.0],
27        target: [0.0, 0.0, 0.0],
28        up: [0.0, 1.0, 0.0],
29        fov_y: PI / 3.0,
30        near: 0.1,
31        far: 1000.0,
32        camera_type: 0,
33    }
34}
35
36/* ── spec functions (wave 150B) ── */
37
38/// Spec-style camera data.
39#[derive(Debug, Clone)]
40pub struct CameraData {
41    pub name: String,
42    pub fov_deg: f32,
43    pub near: f32,
44    pub far: f32,
45    pub orthographic: bool,
46    pub ortho_scale: f32,
47}
48
49/// Create a new `CameraData`.
50pub fn new_camera_data(name: &str, fov_deg: f32) -> CameraData {
51    CameraData {
52        name: name.to_string(),
53        fov_deg,
54        near: 0.1,
55        far: 1000.0,
56        orthographic: false,
57        ortho_scale: 1.0,
58    }
59}
60
61/// Serialize to JSON.
62pub fn camera_to_json(c: &CameraData) -> String {
63    format!(
64        "{{\"name\":\"{}\",\"fov_deg\":{},\"near\":{},\"far\":{},\"ortho\":{}}}",
65        c.name, c.fov_deg, c.near, c.far, c.orthographic
66    )
67}
68
69/// Column-major 4×4 perspective projection matrix (right-handed, OpenGL convention).
70pub fn camera_projection_matrix(c: &CameraData) -> [f32; 16] {
71    let fov_rad = c.fov_deg * PI / 180.0;
72    let f = 1.0 / (fov_rad / 2.0).tan();
73    let rng = c.near - c.far;
74    [
75        f,
76        0.0,
77        0.0,
78        0.0,
79        0.0,
80        f,
81        0.0,
82        0.0,
83        0.0,
84        0.0,
85        (c.far + c.near) / rng,
86        -1.0,
87        0.0,
88        0.0,
89        (2.0 * c.far * c.near) / rng,
90        0.0,
91    ]
92}
93
94/// Maximum view distance (far plane).
95pub fn camera_view_distance(c: &CameraData) -> f32 {
96    c.far
97}
98
99/// Returns true if the camera is orthographic.
100pub fn camera_is_orthographic(c: &CameraData) -> bool {
101    c.orthographic
102}
103
104#[cfg(test)]
105mod tests {
106    use super::*;
107
108    #[test]
109    fn test_new_camera_data() {
110        let c = new_camera_data("cam", 60.0);
111        assert_eq!(c.name, "cam");
112        assert!((c.fov_deg - 60.0).abs() < 1e-5);
113    }
114
115    #[test]
116    fn test_camera_to_json() {
117        let c = new_camera_data("main", 45.0);
118        let j = camera_to_json(&c);
119        assert!(j.contains("main"));
120    }
121
122    #[test]
123    fn test_camera_projection_matrix() {
124        let c = new_camera_data("c", 60.0);
125        let m = camera_projection_matrix(&c);
126        /* [0] = f component should be positive */
127        assert!(m[0] > 0.0);
128    }
129
130    #[test]
131    fn test_camera_view_distance() {
132        let c = new_camera_data("c", 60.0);
133        assert!((camera_view_distance(&c) - 1000.0).abs() < 1e-5);
134    }
135
136    #[test]
137    fn test_camera_is_orthographic_false() {
138        let c = new_camera_data("c", 60.0);
139        assert!(!camera_is_orthographic(&c));
140    }
141}