use super::BakedDataIdentifier;
use super::{BakeError, BAKE_LOCK};
use crate::callback::ProgressCallback;
use crate::context::Context;
use crate::geometry::Scene;
use crate::probe::ProbeBatch;
use crate::ray_tracing::RayTracer;
use std::marker::PhantomData;
#[cfg(doc)]
use super::BakedDataVariation;
#[derive(Default)]
pub struct PathBaker<T: RayTracer> {
_marker: PhantomData<T>,
}
impl<T: RayTracer> PathBaker<T> {
pub const fn new() -> Self {
Self {
_marker: PhantomData,
}
}
pub fn bake(
&self,
context: &Context,
probe_batch: &mut ProbeBatch,
scene: &Scene<T>,
params: PathBakeParams,
) -> Result<(), BakeError> {
self.bake_with_optional_progress_callback(context, probe_batch, scene, params, None)
}
pub fn bake_with_progress_callback(
&self,
context: &Context,
probe_batch: &mut ProbeBatch,
scene: &Scene<T>,
params: PathBakeParams,
progress_callback: ProgressCallback,
) -> Result<(), BakeError> {
self.bake_with_optional_progress_callback(
context,
probe_batch,
scene,
params,
Some(progress_callback),
)
}
fn bake_with_optional_progress_callback(
&self,
context: &Context,
probe_batch: &mut ProbeBatch,
scene: &Scene<T>,
params: PathBakeParams,
progress_callback: Option<ProgressCallback>,
) -> Result<(), BakeError> {
unsafe extern "C" fn noop(_: f32, _: *mut std::ffi::c_void) {}
let _guard = BAKE_LOCK
.try_lock()
.map_err(|_| BakeError::BakeInProgress)?;
let (callback, user_data) = progress_callback.as_ref().map_or(
(noop as _, std::ptr::null_mut()),
ProgressCallback::as_raw_parts,
);
let mut ffi_params = audionimbus_sys::IPLPathBakeParams {
scene: scene.raw_ptr(),
probeBatch: probe_batch.raw_ptr(),
identifier: params.identifier.into(),
numSamples: params.num_samples as i32,
radius: params.radius,
threshold: params.threshold,
visRange: params.visibility_range,
pathRange: params.path_range,
numThreads: params.num_threads as i32,
};
unsafe {
audionimbus_sys::iplPathBakerBake(
context.raw_ptr(),
&raw mut ffi_params,
Some(callback),
user_data,
);
}
Ok(())
}
pub fn cancel_bake(&self, context: &Context) {
unsafe { audionimbus_sys::iplPathBakerCancelBake(context.raw_ptr()) }
}
}
#[derive(Debug, Copy, Clone)]
pub struct PathBakeParams {
pub identifier: BakedDataIdentifier,
pub num_samples: u32,
pub radius: f32,
pub threshold: f32,
pub visibility_range: f32,
pub path_range: f32,
pub num_threads: u32,
}
#[cfg(test)]
pub mod tests {
use crate::*;
fn test_scene(context: &Context) -> Scene<'_, DefaultRayTracer> {
let mut scene = Scene::try_new(context).unwrap();
let vertices = vec![
Vector3::new(-5.0, 0.0, -5.0),
Vector3::new(5.0, 0.0, -5.0),
Vector3::new(5.0, 0.0, 5.0),
Vector3::new(-5.0, 0.0, 5.0),
Vector3::new(-5.0, 3.0, -5.0),
Vector3::new(5.0, 3.0, -5.0),
Vector3::new(5.0, 3.0, 5.0),
Vector3::new(-5.0, 3.0, 5.0),
];
let triangles = [
[0, 1, 2],
[0, 2, 3],
[4, 6, 5],
[4, 7, 6],
[0, 4, 5],
[0, 5, 1],
[1, 5, 6],
[1, 6, 2],
[2, 6, 7],
[2, 7, 3],
[3, 7, 4],
[3, 4, 0],
]
.iter()
.map(|indices| Triangle::new(indices[0], indices[1], indices[2]))
.collect::<Vec<_>>();
let material_indices = vec![0; triangles.len()];
let materials = vec![Material::default()];
let settings = StaticMeshSettings {
vertices: &vertices,
triangles: &triangles,
material_indices: &material_indices,
materials: &materials,
};
let static_mesh = StaticMesh::try_new(&scene, &settings).unwrap();
scene.add_static_mesh(static_mesh);
scene.commit();
scene
}
fn test_probe_batch(context: &Context, scene: &Scene) -> ProbeBatch {
let mut probe_batch = ProbeBatch::try_new(context).unwrap();
let params = ProbeGenerationParams::Centroid {
transform: Matrix4::new([
[1.0, 0.0, 0.0, 0.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 mut probe_array = ProbeArray::try_new(context).unwrap();
probe_array.generate_probes(scene, ¶ms);
probe_batch.add_probe_array(&probe_array);
probe_batch.commit();
probe_batch
}
pub fn test_bake() {
{
let context = Context::default();
let scene = test_scene(&context);
let mut probe_batch = test_probe_batch(&context, &scene);
let baker = PathBaker::<DefaultRayTracer>::new();
let params = PathBakeParams {
identifier: BakedDataIdentifier::Pathing {
variation: BakedDataVariation::Dynamic,
},
num_samples: 4,
radius: 0.5,
threshold: 0.3,
visibility_range: 5.0,
path_range: 10.0,
num_threads: 1,
};
assert!(baker
.bake(&context, &mut probe_batch, &scene, params)
.is_ok());
}
{
let context = Context::default();
let scene = test_scene(&context);
let mut probe_batch = test_probe_batch(&context, &scene);
let baker = PathBaker::<DefaultRayTracer>::new();
let params = PathBakeParams {
identifier: BakedDataIdentifier::Pathing {
variation: BakedDataVariation::Dynamic,
},
num_samples: 4,
radius: 0.5,
threshold: 0.3,
visibility_range: 5.0,
path_range: 10.0,
num_threads: 1,
};
assert!(baker
.bake_with_progress_callback(
&context,
&mut probe_batch,
&scene,
params,
ProgressCallback::new(|progress| {
println!("pathing bake progress: {:.1}%", progress * 100.0);
}),
)
.is_ok());
}
}
}