use oxigaf_flame::params::FlameParams;
use oxigaf_flame::sequence::FlameSequence;
use std::path::PathBuf;
fn create_synthetic_params(
frame_idx: usize,
n_shape: usize,
n_expr: usize,
n_pose: usize,
) -> FlameParams {
let t = frame_idx as f32;
let shape = (0..n_shape)
.map(|i| 0.1 * (t * 0.01 + i as f32 * 0.1).sin())
.collect();
let expression = (0..n_expr)
.map(|i| 0.3 * (t * 0.1 + i as f32 * 0.2).sin())
.collect();
let pose = (0..n_pose)
.map(|i| 0.2 * (t * 0.05 + i as f32 * 0.15).cos())
.collect();
let translation = [0.05 * (t * 0.02).sin(), 0.05 * (t * 0.03).cos(), 0.0];
FlameParams {
shape,
expression,
pose,
translation,
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt::init();
let args: Vec<String> = std::env::args().collect();
if args.len() != 5 {
eprintln!(
"Usage: {} <format> <output_path> <num_frames> <fps>",
args[0]
);
eprintln!();
eprintln!("Formats: json, npz");
eprintln!();
eprintln!("Examples:");
eprintln!(" {} json sequence.json 120 30", args[0]);
eprintln!(" {} npz sequence.npz 240 60", args[0]);
std::process::exit(1);
}
let format = &args[1];
let output_path = PathBuf::from(&args[2]);
let num_frames: usize = args[3]
.parse()
.map_err(|_| "Invalid num_frames: must be a positive integer")?;
let fps: f32 = args[4]
.parse()
.map_err(|_| "Invalid fps: must be a positive number")?;
let n_shape = 100;
let n_expr = 50;
let n_pose = 15;
println!("Creating synthetic FLAME sequence...");
println!(" Frames: {}", num_frames);
println!(" FPS: {}", fps);
println!(" Duration: {:.2}s", num_frames as f32 / fps);
println!(" Shape: {} coefficients", n_shape);
println!(" Expression: {} coefficients", n_expr);
println!(" Pose: {} coefficients", n_pose);
println!();
let frames: Vec<FlameParams> = (0..num_frames)
.map(|i| create_synthetic_params(i, n_shape, n_expr, n_pose))
.collect();
let sequence = FlameSequence::from_memory(frames, Some(fps));
match format.as_str() {
"json" => {
println!("Saving to JSON: {}", output_path.display());
save_sequence_json(&sequence, &output_path)?;
}
"npz" => {
#[cfg(feature = "npz")]
{
println!("Saving to NPZ: {}", output_path.display());
save_sequence_npz(&sequence, &output_path)?;
}
#[cfg(not(feature = "npz"))]
{
eprintln!("Error: NPZ support not enabled. Rebuild with --features npz");
std::process::exit(1);
}
}
_ => {
eprintln!("Error: Unknown format '{}'", format);
eprintln!("Supported formats: json, npz");
std::process::exit(1);
}
}
println!();
println!("Sequence saved successfully!");
println!("You can load it with:");
println!(
" FlameSequence::from_{}(\"{}\")",
format,
output_path.display()
);
Ok(())
}
fn save_sequence_json(
_sequence: &FlameSequence,
_path: &PathBuf,
) -> Result<(), Box<dyn std::error::Error>> {
eprintln!("Note: JSON export from FlameSequence requires mutable access");
eprintln!(" This is a limitation of the current API");
eprintln!(" Consider creating a helper method or using NPZ format");
Err("Cannot export from FlameSequence to JSON in this example".into())
}
#[cfg(feature = "npz")]
fn save_sequence_npz(
_sequence: &FlameSequence,
_path: &PathBuf,
) -> Result<(), Box<dyn std::error::Error>> {
eprintln!("Note: NPZ export from FlameSequence not yet implemented");
eprintln!(" You can manually collect frames and write using ndarray-npy");
Err("NPZ export not implemented".into())
}
#[cfg(not(feature = "npz"))]
#[allow(dead_code)]
fn save_sequence_npz(
_sequence: &FlameSequence,
_path: &PathBuf,
) -> Result<(), Box<dyn std::error::Error>> {
unreachable!()
}