use super::{Matrix, Scene};
use crate::error::{SteamAudioError, to_option_error};
use crate::ray_tracing::{DefaultRayTracer, RayTracer};
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
#[derive(Debug)]
pub struct InstancedMesh<T: RayTracer = DefaultRayTracer> {
inner: audionimbus_sys::IPLInstancedMesh,
pub(crate) sub_scene: Scene<T>,
_marker: PhantomData<T>,
}
impl<T: RayTracer> InstancedMesh<T> {
pub fn try_new(
scene: &Scene<T>,
settings: &InstancedMeshSettings<T>,
) -> Result<Self, SteamAudioError> {
let mut inner = std::ptr::null_mut();
let mut instanced_mesh_settings_ffi = audionimbus_sys::IPLInstancedMeshSettings {
subScene: settings.sub_scene.raw_ptr(),
transform: settings.transform.into(),
};
let status = unsafe {
audionimbus_sys::iplInstancedMeshCreate(
scene.raw_ptr(),
&raw mut instanced_mesh_settings_ffi,
&raw mut inner,
)
};
if let Some(error) = to_option_error(status) {
return Err(error);
}
let instanced_mesh = Self {
inner,
sub_scene: settings.sub_scene.clone(),
_marker: PhantomData,
};
Ok(instanced_mesh)
}
pub const fn raw_ptr(&self) -> audionimbus_sys::IPLInstancedMesh {
self.inner
}
pub const fn raw_ptr_mut(&mut self) -> &mut audionimbus_sys::IPLInstancedMesh {
&mut self.inner
}
}
impl<T: RayTracer> Drop for InstancedMesh<T> {
fn drop(&mut self) {
unsafe { audionimbus_sys::iplInstancedMeshRelease(&raw mut self.inner) }
}
}
unsafe impl<T: RayTracer> Send for InstancedMesh<T> {}
unsafe impl<T: RayTracer> Sync for InstancedMesh<T> {}
impl<T: RayTracer> Clone for InstancedMesh<T> {
fn clone(&self) -> Self {
Self {
inner: unsafe { audionimbus_sys::iplInstancedMeshRetain(self.inner) },
sub_scene: self.sub_scene.clone(),
_marker: PhantomData,
}
}
}
impl<T: RayTracer> PartialEq for InstancedMesh<T> {
fn eq(&self, other: &Self) -> bool {
self.raw_ptr() == other.raw_ptr()
}
}
impl<T: RayTracer> Eq for InstancedMesh<T> {}
impl<T: RayTracer> Hash for InstancedMesh<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
std::ptr::hash(self.raw_ptr(), state);
}
}
#[derive(Debug, Clone)]
pub struct InstancedMeshSettings<T: RayTracer = DefaultRayTracer> {
pub sub_scene: Scene<T>,
pub transform: Matrix<f32, 4, 4>,
}
#[cfg(test)]
mod tests {
use crate::*;
#[test]
fn test_instanced_mesh_clone() {
let context = Context::default();
let main_scene = Scene::try_new(&context).unwrap();
let sub_scene = Scene::try_new(&context).unwrap();
let transform = Matrix::new([
[1.0, 0.0, 0.0, 5.0],
[0.0, 1.0, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0],
]);
let instanced_mesh_settings = geometry::InstancedMeshSettings {
sub_scene,
transform,
};
let instanced_mesh = InstancedMesh::try_new(&main_scene, &instanced_mesh_settings).unwrap();
let clone = instanced_mesh.clone();
assert_eq!(instanced_mesh.raw_ptr(), clone.raw_ptr());
drop(instanced_mesh);
assert!(!clone.raw_ptr().is_null());
}
}