#![allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum GpuUploadState {
Pending,
Uploaded,
Dirty,
Failed,
}
#[derive(Debug, Clone)]
pub struct GpuMorphTarget {
pub name: String,
pub vertex_count: usize,
pub gpu_buffer_id: u64,
pub upload_state: GpuUploadState,
pub weight: f32,
pub enabled: bool,
}
impl GpuMorphTarget {
pub fn new(name: impl Into<String>, vertex_count: usize) -> Self {
GpuMorphTarget {
name: name.into(),
vertex_count,
gpu_buffer_id: 0,
upload_state: GpuUploadState::Pending,
weight: 0.0,
enabled: true,
}
}
}
pub fn new_gpu_morph_target(name: impl Into<String>, vertex_count: usize) -> GpuMorphTarget {
GpuMorphTarget::new(name, vertex_count)
}
pub fn gmt_upload(target: &mut GpuMorphTarget, _data: &[[f32; 3]]) {
target.upload_state = GpuUploadState::Uploaded;
target.gpu_buffer_id = target.vertex_count as u64 * 7919;
}
pub fn gmt_mark_dirty(target: &mut GpuMorphTarget) {
target.upload_state = GpuUploadState::Dirty;
}
pub fn gmt_set_weight(target: &mut GpuMorphTarget, weight: f32) {
target.weight = weight.clamp(0.0, 1.0);
}
pub fn gmt_set_enabled(target: &mut GpuMorphTarget, enabled: bool) {
target.enabled = enabled;
}
pub fn gmt_to_json(target: &GpuMorphTarget) -> String {
let state = match target.upload_state {
GpuUploadState::Pending => "pending",
GpuUploadState::Uploaded => "uploaded",
GpuUploadState::Dirty => "dirty",
GpuUploadState::Failed => "failed",
};
format!(
r#"{{"name":"{}","vertex_count":{},"state":"{}","weight":{},"enabled":{}}}"#,
target.name, target.vertex_count, state, target.weight, target.enabled
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_initial_state_pending() {
let t = new_gpu_morph_target("mouth_open", 256);
assert_eq!(
t.upload_state,
GpuUploadState::Pending,
);
}
#[test]
fn test_upload_changes_state() {
let mut t = new_gpu_morph_target("x", 4);
gmt_upload(&mut t, &[[0.0; 3]; 4]);
assert_eq!(
t.upload_state,
GpuUploadState::Uploaded,
);
}
#[test]
fn test_upload_sets_buffer_id() {
let mut t = new_gpu_morph_target("x", 4);
gmt_upload(&mut t, &[[0.0; 3]; 4]);
assert_ne!(
t.gpu_buffer_id,
0,
);
}
#[test]
fn test_mark_dirty() {
let mut t = new_gpu_morph_target("x", 4);
gmt_upload(&mut t, &[[0.0; 3]; 4]);
gmt_mark_dirty(&mut t);
assert_eq!(
t.upload_state,
GpuUploadState::Dirty,
);
}
#[test]
fn test_set_weight_clamped() {
let mut t = new_gpu_morph_target("x", 2);
gmt_set_weight(&mut t, 1.5);
assert!((t.weight - 1.0).abs() < 1e-6, );
}
#[test]
fn test_set_weight_zero() {
let mut t = new_gpu_morph_target("x", 2);
gmt_set_weight(&mut t, -0.5);
assert!((t.weight).abs() < 1e-6, );
}
#[test]
fn test_set_enabled() {
let mut t = new_gpu_morph_target("x", 2);
gmt_set_enabled(&mut t, false);
assert!(!t.enabled ,);
}
#[test]
fn test_to_json_contains_state() {
let t = new_gpu_morph_target("brow", 10);
let j = gmt_to_json(&t);
assert!(j.contains("\"state\"") ,);
}
#[test]
fn test_vertex_count_stored() {
let t = new_gpu_morph_target("v", 512);
assert_eq!(t.vertex_count, 512 ,);
}
#[test]
fn test_enabled_default() {
let t = new_gpu_morph_target("v", 1);
assert!(t.enabled ,);
}
}