oxihuman_export/
camera_rig_export.rs1#![allow(dead_code)]
4
5#[allow(dead_code)]
9#[derive(Debug, Clone)]
10pub struct CameraRigKeyframe {
11 pub time: f32,
12 pub position: [f32; 3],
13 pub target: [f32; 3],
14 pub fov: f32,
15}
16
17#[allow(dead_code)]
19#[derive(Debug, Clone)]
20pub struct CameraRigExport {
21 pub name: String,
22 pub keyframes: Vec<CameraRigKeyframe>,
23}
24
25#[allow(dead_code)]
27pub fn new_camera_rig_export(name: &str) -> CameraRigExport {
28 CameraRigExport {
29 name: name.to_string(),
30 keyframes: Vec::new(),
31 }
32}
33
34#[allow(dead_code)]
36pub fn rig_add_keyframe(
37 rig: &mut CameraRigExport,
38 time: f32,
39 position: [f32; 3],
40 target: [f32; 3],
41 fov: f32,
42) {
43 rig.keyframes.push(CameraRigKeyframe {
44 time,
45 position,
46 target,
47 fov,
48 });
49}
50
51#[allow(dead_code)]
53pub fn rig_keyframe_count(rig: &CameraRigExport) -> usize {
54 rig.keyframes.len()
55}
56
57#[allow(dead_code)]
59pub fn rig_duration(rig: &CameraRigExport) -> f32 {
60 if rig.keyframes.len() < 2 {
61 return 0.0;
62 }
63 rig.keyframes.last().map_or(0.0, |k| k.time) - rig.keyframes.first().map_or(0.0, |k| k.time)
64}
65
66#[allow(dead_code)]
68pub fn rig_keyframe_at(rig: &CameraRigExport, idx: usize) -> Option<&CameraRigKeyframe> {
69 rig.keyframes.get(idx)
70}
71
72#[allow(dead_code)]
74pub fn rig_clear(rig: &mut CameraRigExport) {
75 rig.keyframes.clear();
76}
77
78#[allow(dead_code)]
80pub fn camera_rig_to_json(rig: &CameraRigExport) -> String {
81 format!(
82 "{{\"name\":\"{}\",\"keyframes\":{},\"duration\":{:.6}}}",
83 rig.name,
84 rig.keyframes.len(),
85 rig_duration(rig),
86 )
87}
88
89#[allow(dead_code)]
91pub fn rig_validate(rig: &CameraRigExport) -> bool {
92 rig.keyframes.windows(2).all(|w| w[0].time <= w[1].time)
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn test_new() {
101 let r = new_camera_rig_export("main");
102 assert_eq!(rig_keyframe_count(&r), 0);
103 }
104
105 #[test]
106 fn test_add_keyframe() {
107 let mut r = new_camera_rig_export("cam");
108 rig_add_keyframe(&mut r, 0.0, [0.0; 3], [0.0, 0.0, -1.0], 60.0);
109 assert_eq!(rig_keyframe_count(&r), 1);
110 }
111
112 #[test]
113 fn test_duration() {
114 let mut r = new_camera_rig_export("cam");
115 rig_add_keyframe(&mut r, 0.0, [0.0; 3], [0.0; 3], 60.0);
116 rig_add_keyframe(&mut r, 2.5, [1.0; 3], [0.0; 3], 60.0);
117 assert!((rig_duration(&r) - 2.5).abs() < 1e-6);
118 }
119
120 #[test]
121 fn test_duration_single() {
122 let mut r = new_camera_rig_export("cam");
123 rig_add_keyframe(&mut r, 1.0, [0.0; 3], [0.0; 3], 60.0);
124 assert!((rig_duration(&r)).abs() < 1e-6);
125 }
126
127 #[test]
128 fn test_keyframe_at() {
129 let mut r = new_camera_rig_export("cam");
130 rig_add_keyframe(&mut r, 0.0, [1.0, 2.0, 3.0], [0.0; 3], 45.0);
131 let kf = rig_keyframe_at(&r, 0).expect("should succeed");
132 assert!((kf.fov - 45.0).abs() < 1e-6);
133 }
134
135 #[test]
136 fn test_clear() {
137 let mut r = new_camera_rig_export("cam");
138 rig_add_keyframe(&mut r, 0.0, [0.0; 3], [0.0; 3], 60.0);
139 rig_clear(&mut r);
140 assert_eq!(rig_keyframe_count(&r), 0);
141 }
142
143 #[test]
144 fn test_to_json() {
145 let r = new_camera_rig_export("test");
146 assert!(camera_rig_to_json(&r).contains("\"name\":\"test\""));
147 }
148
149 #[test]
150 fn test_validate_sorted() {
151 let mut r = new_camera_rig_export("cam");
152 rig_add_keyframe(&mut r, 0.0, [0.0; 3], [0.0; 3], 60.0);
153 rig_add_keyframe(&mut r, 1.0, [0.0; 3], [0.0; 3], 60.0);
154 assert!(rig_validate(&r));
155 }
156
157 #[test]
158 fn test_validate_unsorted() {
159 let mut r = new_camera_rig_export("cam");
160 rig_add_keyframe(&mut r, 2.0, [0.0; 3], [0.0; 3], 60.0);
161 rig_add_keyframe(&mut r, 1.0, [0.0; 3], [0.0; 3], 60.0);
162 assert!(!rig_validate(&r));
163 }
164
165 #[test]
166 fn test_keyframe_at_oob() {
167 let r = new_camera_rig_export("cam");
168 assert!(rig_keyframe_at(&r, 0).is_none());
169 }
170}