1use crate::context::Context;
2use crate::energy_field::EnergyField;
3use crate::error::{to_option_error, SteamAudioError};
4use crate::geometry::{Matrix, Scene, Sphere};
5use crate::serialized_object::SerializedObject;
6use crate::simulation::BakedDataIdentifier;
7
8#[derive(Debug)]
12pub struct ProbeArray(audionimbus_sys::IPLProbeArray);
13
14impl ProbeArray {
15 pub fn try_new(context: &Context) -> Result<Self, SteamAudioError> {
16 let mut probe_array = Self(std::ptr::null_mut());
17
18 let status = unsafe {
19 audionimbus_sys::iplProbeArrayCreate(context.raw_ptr(), probe_array.raw_ptr_mut())
20 };
21
22 if let Some(error) = to_option_error(status) {
23 return Err(error);
24 }
25
26 Ok(probe_array)
27 }
28
29 pub fn generate_probes(&mut self, scene: &Scene, probe_params: &ProbeGenerationParams) {
31 unsafe {
32 audionimbus_sys::iplProbeArrayGenerateProbes(
33 self.raw_ptr(),
34 scene.raw_ptr(),
35 &mut audionimbus_sys::IPLProbeGenerationParams::from(*probe_params),
36 );
37 }
38 }
39
40 pub fn num_probes(&self) -> usize {
42 unsafe { audionimbus_sys::iplProbeArrayGetNumProbes(self.raw_ptr()) as usize }
43 }
44
45 pub fn probe(&self, index: usize) -> Sphere {
47 assert!(index < self.num_probes(), "probe index out of bounds");
48
49 let ipl_sphere =
50 unsafe { audionimbus_sys::iplProbeArrayGetProbe(self.raw_ptr(), index as i32) };
51
52 Sphere::from(ipl_sphere)
53 }
54
55 pub fn raw_ptr(&self) -> audionimbus_sys::IPLProbeArray {
56 self.0
57 }
58
59 pub fn raw_ptr_mut(&mut self) -> &mut audionimbus_sys::IPLProbeArray {
60 &mut self.0
61 }
62}
63
64impl Clone for ProbeArray {
65 fn clone(&self) -> Self {
66 unsafe {
67 audionimbus_sys::iplProbeArrayRetain(self.0);
68 }
69 Self(self.0)
70 }
71}
72
73impl Drop for ProbeArray {
74 fn drop(&mut self) {
75 unsafe { audionimbus_sys::iplProbeArrayRelease(&mut self.0) }
76 }
77}
78
79unsafe impl Send for ProbeArray {}
80unsafe impl Sync for ProbeArray {}
81
82#[derive(Copy, Clone, Debug)]
84pub enum ProbeGenerationParams {
85 Centroid {
87 transform: Matrix<f32, 4, 4>,
90 },
91
92 UniformFloor {
97 spacing: f32,
99
100 height: f32,
102
103 transform: Matrix<f32, 4, 4>,
106 },
107}
108
109impl From<ProbeGenerationParams> for audionimbus_sys::IPLProbeGenerationParams {
110 fn from(probe_generation_params: ProbeGenerationParams) -> Self {
111 let (type_, spacing, height, transform) = match probe_generation_params {
112 ProbeGenerationParams::Centroid { transform } => (
113 audionimbus_sys::IPLProbeGenerationType::IPL_PROBEGENERATIONTYPE_CENTROID,
114 f32::default(),
115 f32::default(),
116 transform,
117 ),
118 ProbeGenerationParams::UniformFloor {
119 spacing,
120 height,
121 transform,
122 } => (
123 audionimbus_sys::IPLProbeGenerationType::IPL_PROBEGENERATIONTYPE_UNIFORMFLOOR,
124 spacing,
125 height,
126 transform,
127 ),
128 };
129
130 Self {
131 type_,
132 spacing,
133 height,
134 transform: transform.into(),
135 }
136 }
137}
138
139#[derive(Debug)]
144pub struct ProbeBatch(audionimbus_sys::IPLProbeBatch);
145
146impl ProbeBatch {
147 pub fn try_new(context: &Context) -> Result<Self, SteamAudioError> {
148 let mut probe_batch = Self(std::ptr::null_mut());
149
150 let status = unsafe {
151 audionimbus_sys::iplProbeBatchCreate(context.raw_ptr(), probe_batch.raw_ptr_mut())
152 };
153
154 if let Some(error) = to_option_error(status) {
155 return Err(error);
156 }
157
158 Ok(probe_batch)
159 }
160
161 pub fn num_probes(&self) -> usize {
163 unsafe { audionimbus_sys::iplProbeBatchGetNumProbes(self.raw_ptr()) as usize }
164 }
165
166 pub fn data_size(&self, identifier: BakedDataIdentifier) -> usize {
168 let mut ffi_identifier: audionimbus_sys::IPLBakedDataIdentifier = identifier.into();
169
170 unsafe {
171 audionimbus_sys::iplProbeBatchGetDataSize(self.raw_ptr(), &mut ffi_identifier as *mut _)
172 as usize
173 }
174 }
175
176 pub fn remove_data(&mut self, identifier: BakedDataIdentifier) {
177 let mut ffi_identifier: audionimbus_sys::IPLBakedDataIdentifier = identifier.into();
178
179 unsafe {
180 audionimbus_sys::iplProbeBatchRemoveData(self.raw_ptr(), &mut ffi_identifier as *mut _)
181 }
182 }
183
184 pub fn add_probe(&mut self, probe: &Sphere) {
187 unsafe {
188 audionimbus_sys::iplProbeBatchAddProbe(
189 self.raw_ptr(),
190 audionimbus_sys::IPLSphere::from(*probe),
191 );
192 }
193 }
194
195 pub fn remove_probe(&mut self, probe_index: usize) {
197 assert!(probe_index < self.num_probes(), "probe index out of bounds");
198
199 unsafe {
200 audionimbus_sys::iplProbeBatchRemoveProbe(self.raw_ptr(), probe_index as i32);
201 }
202 }
203
204 pub fn add_probe_array(&mut self, probe_array: &ProbeArray) {
207 unsafe {
208 audionimbus_sys::iplProbeBatchAddProbeArray(self.raw_ptr(), probe_array.raw_ptr());
209 }
210 }
211
212 pub fn reverb(&self, identifier: BakedDataIdentifier, probe_index: usize) -> [f32; 3] {
214 assert!(probe_index < self.num_probes(), "probe index out of bounds");
215
216 let mut ffi_identifier: audionimbus_sys::IPLBakedDataIdentifier = identifier.into();
217 let mut reverb_times: [f32; 3] = [0.0; 3];
218
219 unsafe {
220 audionimbus_sys::iplProbeBatchGetReverb(
221 self.raw_ptr(),
222 &mut ffi_identifier as *mut _,
223 probe_index as i32,
224 reverb_times.as_mut_ptr(),
225 );
226 }
227
228 reverb_times
229 }
230
231 pub fn energy_field(&self, identifier: BakedDataIdentifier, probe_index: usize) -> EnergyField {
233 assert!(probe_index < self.num_probes(), "probe index out of bounds");
234
235 let mut ffi_identifier: audionimbus_sys::IPLBakedDataIdentifier = identifier.into();
236 let energy_field = EnergyField(std::ptr::null_mut());
237
238 unsafe {
239 audionimbus_sys::iplProbeBatchGetEnergyField(
240 self.raw_ptr(),
241 &mut ffi_identifier as *mut _,
242 probe_index as i32,
243 energy_field.raw_ptr(),
244 );
245 }
246
247 energy_field
248 }
249
250 pub fn commit(&self) {
253 unsafe { audionimbus_sys::iplProbeBatchCommit(self.raw_ptr()) }
254 }
255
256 pub fn save(&self, serialized_object: &mut SerializedObject) {
259 unsafe {
260 audionimbus_sys::iplProbeBatchSave(self.raw_ptr(), serialized_object.raw_ptr());
261 }
262 }
263
264 pub fn load(
267 context: &Context,
268 serialized_object: &mut SerializedObject,
269 ) -> Result<Self, SteamAudioError> {
270 let mut probe_batch = Self(std::ptr::null_mut());
271
272 let status = unsafe {
273 audionimbus_sys::iplProbeBatchLoad(
274 context.raw_ptr(),
275 serialized_object.raw_ptr(),
276 probe_batch.raw_ptr_mut(),
277 )
278 };
279
280 if let Some(error) = to_option_error(status) {
281 return Err(error);
282 }
283
284 Ok(probe_batch)
285 }
286
287 pub fn raw_ptr(&self) -> audionimbus_sys::IPLProbeBatch {
288 self.0
289 }
290
291 pub fn raw_ptr_mut(&mut self) -> &mut audionimbus_sys::IPLProbeBatch {
292 &mut self.0
293 }
294}
295
296impl Clone for ProbeBatch {
297 fn clone(&self) -> Self {
298 unsafe {
299 audionimbus_sys::iplProbeBatchRetain(self.0);
300 }
301 Self(self.0)
302 }
303}
304
305impl Drop for ProbeBatch {
306 fn drop(&mut self) {
307 unsafe { audionimbus_sys::iplProbeBatchRelease(&mut self.0) }
308 }
309}
310
311unsafe impl Send for ProbeBatch {}
312unsafe impl Sync for ProbeBatch {}