fmod/core/system/geometry.rs
1// Copyright (c) 2024 Lily Lyons
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
7use fmod_sys::*;
8use std::ffi::{c_float, c_int};
9
10use crate::{Geometry, System, Vector};
11
12impl System {
13 /// [`Geometry`] creation function. This function will create a base geometry object which can then have polygons added to it.
14 ///
15 /// Polygons can be added to a geometry object using [`Geometry::add_polygon`]. For best efficiency, avoid overlapping of polygons and long thin polygons.
16 ///
17 /// A geometry object stores its polygons in a group to allow optimization for line testing, insertion and updating of geometry in real-time.
18 /// Geometry objects also allow for efficient rotation, scaling and translation of groups of polygons.
19 ///
20 /// It is important to set the value of maxworldsize to an appropriate value using [`System::set_geometry_settings`].
21 pub fn create_geometry(&self, max_polygons: c_int, max_vertices: c_int) -> Result<Geometry> {
22 let mut geometry = std::ptr::null_mut();
23 unsafe {
24 FMOD_System_CreateGeometry(self.inner, max_polygons, max_vertices, &mut geometry)
25 .to_result()?;
26 }
27 Ok(geometry.into())
28 }
29
30 /// Sets the maximum world size for the geometry engine for performance / precision reasons.
31 ///
32 /// FMOD uses an efficient spatial partitioning system to store polygons for ray casting purposes.
33 /// The maximum size of the world should (`max_world_size`) be set to allow processing within a known range.
34 /// Outside of this range, objects and polygons will not be processed as efficiently.
35 /// Excessive world size settings can also cause loss of precision and efficiency.
36 ///
37 /// Setting `max_world_size` should be done first before creating any geometry.
38 /// It can be done any time afterwards but may be slow in this case.
39 pub fn set_geometry_settings(&self, max_world_size: c_float) -> Result<()> {
40 unsafe { FMOD_System_SetGeometrySettings(self.inner, max_world_size).to_result() }
41 }
42
43 /// Retrieves the maximum world size for the geometry engine.
44 ///
45 /// FMOD uses an efficient spatial partitioning system to store polygons for ray casting purposes.
46 /// The maximum size of the world should (`max_world_size`) be set to allow processing within a known range.
47 /// Outside of this range, objects and polygons will not be processed as efficiently.
48 /// Excessive world size settings can also cause loss of precision and efficiency.
49 pub fn get_geometry_settings(&self) -> Result<c_float> {
50 let mut max_world_size = 0.0;
51 unsafe {
52 FMOD_System_GetGeometrySettings(self.inner, &mut max_world_size).to_result()?;
53 }
54 Ok(max_world_size)
55 }
56
57 /// Creates a geometry object from a block of memory which contains pre-saved geometry data.
58 ///
59 /// This function avoids the need to manually create and add geometry for faster start time.
60 pub fn load_geometry(&self, data: &[u8]) -> Result<Geometry> {
61 let mut geometry = std::ptr::null_mut();
62 unsafe {
63 FMOD_System_LoadGeometry(
64 self.inner,
65 data.as_ptr().cast(),
66 data.len() as c_int,
67 &mut geometry,
68 )
69 .to_result()?;
70 }
71 Ok(geometry.into())
72 }
73
74 /// Calculates geometry occlusion between a listener and a sound source.
75 ///
76 /// If single sided polygons have been created, it is important to get the source and listener positions around the right way,
77 /// as the occlusion from point A to point B may not be the same as the occlusion from point B to point A.
78 pub fn get_geometry_occlusion(
79 &self,
80 listener: Vector,
81 source: Vector,
82 ) -> Result<(c_float, c_float)> {
83 let mut direct = 0.0;
84 let mut reverb = 0.0;
85 unsafe {
86 FMOD_System_GetGeometryOcclusion(
87 self.inner,
88 std::ptr::from_ref(&listener).cast(),
89 std::ptr::from_ref(&source).cast(),
90 &mut direct,
91 &mut reverb,
92 )
93 .to_result()?;
94 }
95 Ok((direct, reverb))
96 }
97}