oxihuman_morph/
gpu_morph_target.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone, Copy, PartialEq)]
9pub enum GpuUploadState {
10 Pending,
11 Uploaded,
12 Dirty,
13 Failed,
14}
15
16#[derive(Debug, Clone)]
18pub struct GpuMorphTarget {
19 pub name: String,
20 pub vertex_count: usize,
21 pub gpu_buffer_id: u64,
22 pub upload_state: GpuUploadState,
23 pub weight: f32,
24 pub enabled: bool,
25}
26
27impl GpuMorphTarget {
28 pub fn new(name: impl Into<String>, vertex_count: usize) -> Self {
29 GpuMorphTarget {
30 name: name.into(),
31 vertex_count,
32 gpu_buffer_id: 0,
33 upload_state: GpuUploadState::Pending,
34 weight: 0.0,
35 enabled: true,
36 }
37 }
38}
39
40pub fn new_gpu_morph_target(name: impl Into<String>, vertex_count: usize) -> GpuMorphTarget {
42 GpuMorphTarget::new(name, vertex_count)
43}
44
45pub fn gmt_upload(target: &mut GpuMorphTarget, _data: &[[f32; 3]]) {
47 target.upload_state = GpuUploadState::Uploaded;
49 target.gpu_buffer_id = target.vertex_count as u64 * 7919;
50}
51
52pub fn gmt_mark_dirty(target: &mut GpuMorphTarget) {
54 target.upload_state = GpuUploadState::Dirty;
55}
56
57pub fn gmt_set_weight(target: &mut GpuMorphTarget, weight: f32) {
59 target.weight = weight.clamp(0.0, 1.0);
60}
61
62pub fn gmt_set_enabled(target: &mut GpuMorphTarget, enabled: bool) {
64 target.enabled = enabled;
65}
66
67pub fn gmt_to_json(target: &GpuMorphTarget) -> String {
69 let state = match target.upload_state {
70 GpuUploadState::Pending => "pending",
71 GpuUploadState::Uploaded => "uploaded",
72 GpuUploadState::Dirty => "dirty",
73 GpuUploadState::Failed => "failed",
74 };
75 format!(
76 r#"{{"name":"{}","vertex_count":{},"state":"{}","weight":{},"enabled":{}}}"#,
77 target.name, target.vertex_count, state, target.weight, target.enabled
78 )
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn test_initial_state_pending() {
87 let t = new_gpu_morph_target("mouth_open", 256);
88 assert_eq!(
89 t.upload_state,
90 GpuUploadState::Pending, );
92 }
93
94 #[test]
95 fn test_upload_changes_state() {
96 let mut t = new_gpu_morph_target("x", 4);
97 gmt_upload(&mut t, &[[0.0; 3]; 4]);
98 assert_eq!(
99 t.upload_state,
100 GpuUploadState::Uploaded, );
102 }
103
104 #[test]
105 fn test_upload_sets_buffer_id() {
106 let mut t = new_gpu_morph_target("x", 4);
107 gmt_upload(&mut t, &[[0.0; 3]; 4]);
108 assert_ne!(
109 t.gpu_buffer_id,
110 0, );
112 }
113
114 #[test]
115 fn test_mark_dirty() {
116 let mut t = new_gpu_morph_target("x", 4);
117 gmt_upload(&mut t, &[[0.0; 3]; 4]);
118 gmt_mark_dirty(&mut t);
119 assert_eq!(
120 t.upload_state,
121 GpuUploadState::Dirty, );
123 }
124
125 #[test]
126 fn test_set_weight_clamped() {
127 let mut t = new_gpu_morph_target("x", 2);
128 gmt_set_weight(&mut t, 1.5);
129 assert!((t.weight - 1.0).abs() < 1e-6, );
130 }
131
132 #[test]
133 fn test_set_weight_zero() {
134 let mut t = new_gpu_morph_target("x", 2);
135 gmt_set_weight(&mut t, -0.5);
136 assert!((t.weight).abs() < 1e-6, );
137 }
138
139 #[test]
140 fn test_set_enabled() {
141 let mut t = new_gpu_morph_target("x", 2);
142 gmt_set_enabled(&mut t, false);
143 assert!(!t.enabled ,);
144 }
145
146 #[test]
147 fn test_to_json_contains_state() {
148 let t = new_gpu_morph_target("brow", 10);
149 let j = gmt_to_json(&t);
150 assert!(j.contains("\"state\"") ,);
151 }
152
153 #[test]
154 fn test_vertex_count_stored() {
155 let t = new_gpu_morph_target("v", 512);
156 assert_eq!(t.vertex_count, 512 ,);
157 }
158
159 #[test]
160 fn test_enabled_default() {
161 let t = new_gpu_morph_target("v", 1);
162 assert!(t.enabled ,);
163 }
164}