fmod/studio/command_replay/
callback.rs1use crate::{FmodResultExt, Result};
8use fmod_sys::*;
9use lanyard::Utf8CStr;
10use std::ffi::{c_char, c_float, c_int, c_uint, c_void};
11
12use crate::{
13 Guid, panic_wrapper,
14 studio::{Bank, CommandReplay, EventDescription, EventInstance, LoadBankFlags},
15};
16
17pub trait CreateInstanceCallback {
21 fn create_instance_callback(
23 replay: CommandReplay,
24 command_index: c_int,
25 description: EventDescription,
26 userdata: *mut c_void,
27 ) -> Result<Option<EventInstance>>;
28}
29
30unsafe extern "C" fn create_instance_impl<C: CreateInstanceCallback>(
31 replay: *mut FMOD_STUDIO_COMMANDREPLAY,
32 command_index: c_int,
33 event_description: *mut FMOD_STUDIO_EVENTDESCRIPTION,
34 event_instance: *mut *mut FMOD_STUDIO_EVENTINSTANCE,
35 userdata: *mut c_void,
36) -> FMOD_RESULT {
37 panic_wrapper(|| unsafe {
38 let replay = CommandReplay::from_ffi(replay);
39 let description = EventDescription::from_ffi(event_description);
40 let result = C::create_instance_callback(replay, command_index, description, userdata);
41 match result {
42 Ok(Some(instance)) => {
43 std::ptr::write(event_instance, instance.into());
44 FMOD_RESULT::FMOD_OK
45 }
46 Ok(None) => FMOD_RESULT::FMOD_OK,
47 Err(e) => e.into(),
48 }
49 })
50}
51
52pub trait FrameCallback {
56 fn frame_callback(
58 replay: CommandReplay,
59 command_index: c_int,
60 current_time: c_float,
61 userdata: *mut c_void,
62 ) -> Result<()>;
63}
64
65unsafe extern "C" fn frame_impl<C: FrameCallback>(
66 replay: *mut FMOD_STUDIO_COMMANDREPLAY,
67 command_index: c_int,
68 current_time: c_float,
69 userdata: *mut c_void,
70) -> FMOD_RESULT {
71 panic_wrapper(|| {
72 let replay = unsafe { CommandReplay::from_ffi(replay) };
73 let result = C::frame_callback(replay, command_index, current_time, userdata);
74 FMOD_RESULT::from_result(result)
75 })
76}
77
78pub trait LoadBankCallback {
82 fn load_bank_callback(
84 replay: CommandReplay,
85 command_index: c_int,
86 guid: Option<Guid>,
87 filename: Option<&Utf8CStr>,
88 flags: LoadBankFlags,
89 userdata: *mut c_void,
90 ) -> Result<Option<Bank>>;
91}
92
93unsafe extern "C" fn load_bank_impl<C: LoadBankCallback>(
94 replay: *mut FMOD_STUDIO_COMMANDREPLAY,
95 command_index: c_int,
96 guid: *const FMOD_GUID,
97 filename: *const c_char,
98 flags: c_uint,
99 bank_ptr: *mut *mut FMOD_STUDIO_BANK,
100 userdata: *mut c_void,
101) -> FMOD_RESULT {
102 panic_wrapper(|| {
103 let replay = unsafe { CommandReplay::from_ffi(replay) };
104 let flags = LoadBankFlags::from(flags);
105 let guid = if guid.is_null() {
106 None
107 } else {
108 Some(unsafe { std::ptr::read(guid.cast()) })
109 };
110 let filename = if filename.is_null() {
111 None
112 } else {
113 Some(unsafe { Utf8CStr::from_ptr_unchecked(filename) })
114 };
115 let result = C::load_bank_callback(replay, command_index, guid, filename, flags, userdata);
116 match result {
117 Ok(Some(bank)) => {
118 unsafe {
119 std::ptr::write(bank_ptr, bank.into());
120 }
121 FMOD_RESULT::FMOD_OK
122 }
123 Ok(None) => FMOD_RESULT::FMOD_OK,
124 Err(e) => e.into(),
125 }
126 })
127}
128
129impl CommandReplay {
130 #[allow(clippy::not_unsafe_ptr_arg_deref)] pub fn set_userdata(&self, userdata: *mut c_void) -> Result<()> {
133 unsafe { FMOD_Studio_CommandReplay_SetUserData(self.inner.as_ptr(), userdata).to_result() }
134 }
135
136 pub fn get_userdata(&self) -> Result<*mut c_void> {
138 let mut userdata = std::ptr::null_mut();
139 unsafe {
140 FMOD_Studio_CommandReplay_GetUserData(self.inner.as_ptr(), &raw mut userdata)
141 .to_result()?;
142 }
143 Ok(userdata)
144 }
145
146 pub fn set_create_instance_callback<C: CreateInstanceCallback>(&self) -> Result<()> {
155 unsafe {
156 FMOD_Studio_CommandReplay_SetCreateInstanceCallback(
157 self.inner.as_ptr(),
158 Some(create_instance_impl::<C>),
159 )
160 .to_result()
161 }
162 }
163
164 pub fn set_frame_callback<C: FrameCallback>(&self) -> Result<()> {
166 unsafe {
167 FMOD_Studio_CommandReplay_SetFrameCallback(self.inner.as_ptr(), Some(frame_impl::<C>))
168 .to_result()
169 }
170 }
171
172 pub fn set_load_bank_callback<C: LoadBankCallback>(&self) -> Result<()> {
184 unsafe {
185 FMOD_Studio_CommandReplay_SetLoadBankCallback(
186 self.inner.as_ptr(),
187 Some(load_bank_impl::<C>),
188 )
189 .to_result()
190 }
191 }
192}