use haply::{
device_model::{
EasingType,
Inverse3Configure,
Linear3D,
SdfHfxObject,
SdfOutputConfigure,
SdfPrimitive,
SymmetryMode,
TransformPatch,
},
http::InverseHttpClient,
HaplyDevice,
};
use std::io::Write;
use std::{ env, time::Duration };
use tokio::time::{ interval, sleep };
const USE_HTTP: bool = false;
const HTTP_BASE: &str = "http://localhost:10001";
const WS_URL: &str = "ws://localhost:10001/";
const SESSION: &str = ":-1";
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let args: Vec<String> = env::args().skip(1).collect();
let use_cube = args.iter().any(|a| a == "--cube");
let (effect_id, shape, label) = if use_cube {
(
"cube1",
SdfPrimitive::Box {
b: Linear3D { x: 0.03, y: 0.03, z: 0.03 },
},
"Cube",
)
} else {
("sphere1", SdfPrimitive::Sphere { r: 0.05 }, "Sphere")
};
println!("WARNING: sdf_demo is experimental/internal-only and not a stable public API.");
println!("SDF Demo: {} effect", label);
let mut device = HaplyDevice::new(HTTP_BASE, WS_URL).await?;
let http = InverseHttpClient::new(HTTP_BASE);
sleep(Duration::from_millis(300)).await;
let state = device.read_state().await?;
let inv = state.inverse3.first().ok_or("No Inverse3 device connected")?;
let id = inv.device_id.clone();
println!("Using Inverse3 device: {}", id);
let sdf_obj = SdfHfxObject {
id: effect_id.to_string(),
shape: Some(shape),
transform: Some(TransformPatch {
position: Some(Linear3D { x: 0.0, y: -0.1, z: 0.18 }),
rotation: None,
scale: None,
}),
force_scale: Some(-2.0),
range: Some(0.02),
ease: Some(EasingType::CubicInOut),
reverse_easing: Some(false),
symmetry: Some(SymmetryMode::Single),
};
if USE_HTTP {
println!("Creating {} SDF via HTTP...", label);
http.set_sdf_by_id("inverse3", &id, effect_id, Some(SESSION), &sdf_obj).await?;
} else {
println!("Enabling SDF output via WS...");
device.configure_inverse3(
&id,
Inverse3Configure {
sdf: Some(SdfOutputConfigure { state_output: true }),
..Default::default()
},
Some(true)
).await?;
println!("Creating {} SDF via WS...", label);
device.sdf_set(&id, vec![sdf_obj], Some("application".to_string()), Some(true)).await?;
}
println!("SDF active -- streaming state (Ctrl+C to stop)");
let mut ticker = interval(Duration::from_millis(10));
loop {
ticker.tick().await;
device.send_ping().await?;
let state = device.read_state().await?;
if let Some(inv) = state.inverse3.first() {
let pos = inv.state.cursor_position.unwrap_or_default();
let force = inv.state.current_cursor_force.unwrap_or_default();
print!(
"\rPos: ({:.4},{:.4},{:.4}) Force: ({:.4},{:.4},{:.4}) ",
pos.x,
pos.y,
pos.z,
force.x,
force.y,
force.z
);
std::io::stdout().flush().unwrap();
}
}
}