use std::path::Path;
use cxx::UniquePtr;
#[cxx::bridge(namespace = "hydra_rs")]
mod ffi {
unsafe extern "C++" {
include!("hydra_bridge.h");
type SceneIndex;
type Renderer;
fn populate_from_path(usd_path: &str) -> Result<UniquePtr<SceneIndex>>;
fn list_render_delegate_ids() -> UniquePtr<CxxVector<CxxString>>;
fn create_renderer(
usd_path: &str,
render_delegate_id: &str,
) -> Result<UniquePtr<Renderer>>;
fn render_to_rgba(
usd_path: &str,
render_delegate_id: &str,
width: u32,
height: u32,
) -> Result<UniquePtr<CxxVector<u8>>>;
fn stage_root(self: &SceneIndex) -> String;
fn prim_count(self: &SceneIndex) -> usize;
fn prim_paths(self: &SceneIndex) -> UniquePtr<CxxVector<CxxString>>;
fn set_size(self: Pin<&mut Renderer>, width: u32, height: u32);
fn set_camera_matrices(
self: Pin<&mut Renderer>,
view: &[f32],
projection: &[f32],
);
fn set_time(self: Pin<&mut Renderer>, time: f64);
fn use_default_time(self: Pin<&mut Renderer>);
fn clear_lights(self: Pin<&mut Renderer>);
fn use_default_light(self: Pin<&mut Renderer>);
fn add_distant_light(
self: Pin<&mut Renderer>,
dx: f32,
dy: f32,
dz: f32,
r: f32,
g: f32,
b: f32,
intensity: f32,
);
fn add_positional_light(
self: Pin<&mut Renderer>,
px: f32,
py: f32,
pz: f32,
r: f32,
g: f32,
b: f32,
intensity: f32,
);
fn set_clear_color(self: Pin<&mut Renderer>, r: f32, g: f32, b: f32, a: f32);
fn set_scene_ambient(self: Pin<&mut Renderer>, r: f32, g: f32, b: f32, a: f32);
fn set_dome_light(
self: Pin<&mut Renderer>,
hdri_path: &str,
intensity: f32,
exposure: f32,
rotation_y_degrees: f32,
) -> Result<()>;
fn clear_dome_light(self: Pin<&mut Renderer>);
fn set_external_material(
self: Pin<&mut Renderer>,
source_usd_path: &str,
prim_path: &str,
) -> Result<()>;
fn clear_external_material(self: Pin<&mut Renderer>);
fn set_user_lights(
self: Pin<&mut Renderer>,
data: &[f32],
) -> Result<()>;
fn clear_user_lights(self: Pin<&mut Renderer>);
fn set_painted_material(
self: Pin<&mut Renderer>,
base_color_asset_path: &str,
roughness_asset_path: &str,
metallic_asset_path: &str,
normal_asset_path: &str,
) -> Result<()>;
fn clear_painted_material(self: Pin<&mut Renderer>);
fn set_show_render(self: Pin<&mut Renderer>, show: bool);
fn set_show_proxy(self: Pin<&mut Renderer>, show: bool);
fn set_show_guides(self: Pin<&mut Renderer>, show: bool);
fn current_renderer(self: &Renderer) -> String;
fn set_renderer_plugin(self: &Renderer, plugin_id: &str) -> bool;
fn render_color(self: &Renderer) -> Result<UniquePtr<CxxVector<u8>>>;
fn is_converged(self: &Renderer) -> bool;
}
}
pub struct SceneIndex {
inner: UniquePtr<ffi::SceneIndex>,
}
impl SceneIndex {
pub fn from_path(path: impl AsRef<Path>) -> Result<Self, cxx::Exception> {
let p = path.as_ref().to_string_lossy();
Ok(Self {
inner: ffi::populate_from_path(&p)?,
})
}
pub fn stage_root(&self) -> String {
self.inner.stage_root()
}
pub fn prim_count(&self) -> usize {
self.inner.prim_count()
}
pub fn prim_paths(&self) -> Vec<String> {
self.inner
.prim_paths()
.iter()
.map(|s| s.to_string())
.collect()
}
}
pub fn list_render_delegates() -> Vec<String> {
ffi::list_render_delegate_ids()
.iter()
.map(|s| s.to_string())
.collect()
}
pub struct Renderer {
inner: UniquePtr<ffi::Renderer>,
}
impl Renderer {
pub fn new(usd_path: impl AsRef<Path>) -> Result<Self, cxx::Exception> {
Self::with_delegate(usd_path, "")
}
pub fn with_delegate(
usd_path: impl AsRef<Path>,
delegate_id: &str,
) -> Result<Self, cxx::Exception> {
let p = usd_path.as_ref().to_string_lossy();
Ok(Self {
inner: ffi::create_renderer(&p, delegate_id)?,
})
}
pub fn set_size(&mut self, width: u32, height: u32) {
self.inner.pin_mut().set_size(width, height);
}
pub fn set_camera_matrices(&mut self, view: &[f32; 16], projection: &[f32; 16]) {
self.inner.pin_mut().set_camera_matrices(view, projection);
}
pub fn set_time(&mut self, time: f64) {
self.inner.pin_mut().set_time(time);
}
pub fn use_default_time(&mut self) {
self.inner.pin_mut().use_default_time();
}
pub fn clear_lights(&mut self) {
self.inner.pin_mut().clear_lights();
}
pub fn use_default_light(&mut self) {
self.inner.pin_mut().use_default_light();
}
pub fn add_distant_light(
&mut self,
direction: [f32; 3],
color: [f32; 3],
intensity: f32,
) {
self.inner.pin_mut().add_distant_light(
direction[0],
direction[1],
direction[2],
color[0],
color[1],
color[2],
intensity,
);
}
pub fn add_positional_light(
&mut self,
position: [f32; 3],
color: [f32; 3],
intensity: f32,
) {
self.inner.pin_mut().add_positional_light(
position[0],
position[1],
position[2],
color[0],
color[1],
color[2],
intensity,
);
}
pub fn set_clear_color(&mut self, color: [f32; 4]) {
self.inner
.pin_mut()
.set_clear_color(color[0], color[1], color[2], color[3]);
}
pub fn set_scene_ambient(&mut self, color: [f32; 4]) {
self.inner
.pin_mut()
.set_scene_ambient(color[0], color[1], color[2], color[3]);
}
pub fn set_dome_light(
&mut self,
path: impl AsRef<Path>,
intensity: f32,
exposure: f32,
rotation_y_degrees: f32,
) -> Result<(), cxx::Exception> {
let p = path.as_ref().to_string_lossy();
self.inner
.pin_mut()
.set_dome_light(&p, intensity, exposure, rotation_y_degrees)
}
pub fn clear_dome_light(&mut self) {
self.inner.pin_mut().clear_dome_light();
}
pub fn set_external_material(
&mut self,
source: impl AsRef<Path>,
prim_path: &str,
) -> Result<(), cxx::Exception> {
let src = source.as_ref().to_string_lossy();
self.inner
.pin_mut()
.set_external_material(&src, prim_path)
}
pub fn clear_external_material(&mut self) {
self.inner.pin_mut().clear_external_material();
}
pub fn set_painted_material(
&mut self,
base_color: impl AsRef<Path>,
roughness: impl AsRef<Path>,
metallic: impl AsRef<Path>,
normal: impl AsRef<Path>,
) -> Result<(), cxx::Exception> {
let bc = base_color.as_ref().to_string_lossy();
let ro = roughness.as_ref().to_string_lossy();
let me = metallic.as_ref().to_string_lossy();
let nm = normal.as_ref().to_string_lossy();
self.inner
.pin_mut()
.set_painted_material(&bc, &ro, &me, &nm)
}
pub fn clear_painted_material(&mut self) {
self.inner.pin_mut().clear_painted_material();
}
pub fn set_user_lights(
&mut self,
lights: &[[f32; 16]],
) -> Result<(), cxx::Exception> {
let flat: &[f32] = unsafe {
std::slice::from_raw_parts(
lights.as_ptr() as *const f32,
lights.len() * 16,
)
};
self.inner.pin_mut().set_user_lights(flat)
}
pub fn clear_user_lights(&mut self) {
self.inner.pin_mut().clear_user_lights();
}
pub fn set_show_render(&mut self, show: bool) {
self.inner.pin_mut().set_show_render(show);
}
pub fn set_show_proxy(&mut self, show: bool) {
self.inner.pin_mut().set_show_proxy(show);
}
pub fn set_show_guides(&mut self, show: bool) {
self.inner.pin_mut().set_show_guides(show);
}
pub fn current_renderer(&self) -> String {
self.inner.current_renderer()
}
pub fn set_renderer_plugin(&self, plugin_id: &str) -> bool {
self.inner.set_renderer_plugin(plugin_id)
}
pub fn render(&self) -> Result<Vec<u8>, cxx::Exception> {
Ok(self.inner.render_color()?.iter().copied().collect())
}
pub fn is_converged(&self) -> bool {
self.inner.is_converged()
}
}
pub fn render_to_rgba(
usd_path: impl AsRef<Path>,
render_delegate: &str,
width: u32,
height: u32,
) -> Result<Vec<u8>, cxx::Exception> {
let p = usd_path.as_ref().to_string_lossy();
Ok(ffi::render_to_rgba(&p, render_delegate, width, height)?
.iter()
.copied()
.collect())
}