1use crate::info;
5use crate::FFGLData;
6
7use crate::ffi::ffgl2::*;
8
9use crate::handler::{FFGLHandler, FFGLInstance};
10use crate::log::try_init_default_subscriber;
11use crate::parameters::ParamInfo;
12
13use core::slice;
14
15use std::{any::Any, ffi::CString};
16
17use crate::conversions::*;
18
19use crate::handler;
20use anyhow::{Context, Error};
21
22fn param<H: FFGLHandler>(handler: &'static H, index: FFGLVal) -> &'static dyn ParamInfo {
23 handler.param_info(unsafe { index.num as usize })
24}
25
26static mut INITIALIZED: bool = false;
27static mut INFO: Option<info::PluginInfo> = None;
28static mut INFO_STRUCT: Option<PluginInfoStruct> = None;
29static mut ABOUT: Option<CString> = None;
30static mut DESCRIPTION: Option<CString> = None;
31static mut INFO_STRUCT_EXTENDED: Option<PluginExtendedInfoStruct> = None;
32static mut HANDLER: Option<Box<dyn Any>> = None;
33
34use tracing::{debug, info, trace};
35
36macro_rules! e {
38 ($($arg:tt)*) => {{
39 format!("{orig}\nSOURCE {file}:{line}:{column}", orig=format!($($arg)*),
40 file = file!(),
41 line = line!(),
42 column = column!(),)
43 }}
44}
45
46pub fn default_ffgl_entry<H: FFGLHandler + 'static>(
47 function: Op,
48 mut input_value: FFGLVal,
49 instance: Option<&mut handler::Instance<H::Instance>>,
50) -> Result<FFGLVal, Error> {
51 let noisy_op = match function {
52 Op::ProcessOpenGL
53 | Op::SetBeatInfo
54 | Op::SetTime
55 | Op::GetParameterEvents
56 | Op::SetParameter
57 | Op::GetParameterDisplay
58 | Op::GetParameterType => true,
59 _ => false,
60 };
61
62 if !noisy_op {
63 debug!("Op::{function:?}({})", unsafe { input_value.num });
64 } else {
65 trace!("Op::{function:?}({})", unsafe { input_value.num });
66 }
67
68 unsafe {
69 if !INITIALIZED {
70 INITIALIZED = true;
71
72 HANDLER = Some(Box::new(H::init()));
73
74 let _ = try_init_default_subscriber();
75
76 let handler = &*HANDLER
77 .as_ref()
78 .context(e!("No handler"))?
79 .downcast_ref::<H>()
80 .context(e!("Handler incorrect type"))?;
81
82 INFO = Some(handler.plugin_info());
83 let info = INFO.as_ref().context(e!("No info"))?;
84 ABOUT = Some(CString::new(info.about.clone())?);
85 DESCRIPTION = Some(CString::new(info.description.clone())?);
86
87 INFO_STRUCT = Some(info::plugin_info(
88 std::mem::transmute(&info.unique_id),
89 std::mem::transmute(&info.name),
90 info.ty,
91 ));
92
93 INFO_STRUCT_EXTENDED = Some(info::plugin_info_extended(
94 ABOUT.as_ref().context(e!("ABOUT not initialized"))?,
95 DESCRIPTION
96 .as_ref()
97 .context(e!("DESCRIPTION not initialized"))?,
98 ));
99
100 info!(
101 "INITIALIZED PLUGIN '{id:?}' '{name}'",
102 name = std::str::from_utf8(&info.name)?,
103 id = info.unique_id
104 );
105 }
106 }
107
108 let info = unsafe { INFO.as_ref().context(e!("No info"))? };
109
110 let handler = unsafe { &HANDLER }
111 .as_ref()
112 .context(e!("Handler not initialized"))?
113 .downcast_ref::<H>()
114 .context(e!("Handler type mismatch"))?;
115
116 let resp = match function {
117 Op::GetPluginCaps => {
118 let cap_num = unsafe { input_value.num };
119 let cap = num::FromPrimitive::from_u32(cap_num).expect("Unexpected cap n{cap_num}");
120
121 let result = match cap {
122 PluginCapacity::MinInputFrames => FFGLVal { num: 0 },
123 PluginCapacity::MaxInputFrames => FFGLVal { num: 1 },
124
125 PluginCapacity::ProcessOpenGl => SupportVal::Supported.into(),
126 PluginCapacity::SetTime => SupportVal::Supported.into(),
127
128 PluginCapacity::TopLeftTextureOrientation => SupportVal::Supported.into(),
129
130 _ => SupportVal::Unsupported.into(),
131 };
132
133 debug!("{cap:?} => {}", unsafe { result.num });
134
135 result
136 }
137
138 Op::EnablePluginCap => {
139 let cap_num = unsafe { input_value.num };
140 let cap = num::FromPrimitive::from_u32(cap_num).expect("Unexpected cap n{cap_num}");
141
142 let result: FFGLVal = match cap {
143 PluginCapacity::TopLeftTextureOrientation => SuccessVal::Success.into(),
144 _ => SuccessVal::Fail.into(),
145 };
146
147 debug!("{cap:?} => {}", unsafe { result.num });
148
149 result
150 }
151
152 Op::GetNumParameters => FFGLVal {
153 num: handler.num_params() as u32,
154 },
155
156 Op::GetParameterDefault => param(handler, input_value).default_val().into(),
157 Op::GetParameterGroup => {
158 let input: &GetStringStructTag = unsafe { input_value.as_ref() };
159 let buffer = input.stringBuffer;
160
161 let group = H::param_info(handler, input.parameterNumber as usize).group();
162
163 let string_target: &mut [char] = unsafe {
164 slice::from_raw_parts_mut(buffer.address as *mut char, buffer.maxToWrite as usize)
165 };
166
167 let copied_chars = std::cmp::min(group.len(), buffer.maxToWrite as usize);
168
169 string_target[..copied_chars]
170 .copy_from_slice(&group[..copied_chars].chars().collect::<Vec<_>>());
171
172 debug!("GET PARAM GROUP {group:?}");
173
174 SuccessVal::Success.into()
175 }
176 Op::GetParameterDisplay => param(handler, input_value).display_name().into(),
177 Op::GetParameterName => param(handler, input_value).name().into(),
178 Op::GetParameterType => param(handler, input_value).param_type().into(),
179
180 Op::GetParameter => instance
181 .context(e!("No instance"))?
182 .renderer
183 .get_param(unsafe { input_value.num } as usize)
184 .into(),
185
186 Op::SetParameter => {
187 let input: &SetParameterStruct = unsafe { input_value.as_ref() };
188 let index = input.ParameterNumber;
189
190 let index_usize = index as usize;
192
193 let new_value =
195 unsafe { std::mem::transmute::<u32, f32>(input.NewParameterValue.UIntValue) };
196
197 instance
198 .context(e!("No instance"))?
199 .renderer
200 .set_param(index_usize, new_value);
201
202 SuccessVal::Success.into()
203 }
204 Op::GetParameterRange => {
205 let input: &mut GetRangeStruct = unsafe { (input_value).as_mut() };
206
207 let index = input.parameterNumber;
208 let param = handler.param_info(index as usize);
209
210 input.range = RangeStruct {
211 min: param.min(),
212 max: param.max(),
213 };
214
215 SuccessVal::Success.into()
216 }
217 Op::GetInfo => unsafe { INFO_STRUCT.as_ref().context(e!("No info"))?.into() },
219
220 Op::GetExtendedInfo => unsafe {
221 INFO_STRUCT_EXTENDED
222 .as_ref()
223 .context(e!("No extended info"))?
224 .into()
225 },
226
227 Op::InstantiateGL => {
228 let viewport: &FFGLViewportStruct = unsafe { input_value.as_ref() };
229
230 let data = FFGLData::new(viewport);
231 let renderer = H::new_instance(handler, &data)
232 .context("Failed to instantiate renderer")
233 .context(format!("For {}", std::str::from_utf8(&info.name).unwrap()))?;
234
235 let instance = handler::Instance { data, renderer };
236
237 info!(
238 "Created INSTANCE \n{instance:#?} of ({id:?}, '{name:?}')",
239 id = info.unique_id,
240 name = String::from_utf8_lossy(&info.name),
241 );
242
243 FFGLVal::from_static(Box::leak(Box::<handler::Instance<H::Instance>>::new(
244 instance,
245 )))
246 }
247
248 Op::DeinstantiateGL => {
249 let inst = instance.context(e!("No instance"))?;
250
251 debug!("DEINSTGL\n{inst:#?}");
252 unsafe {
253 drop(Box::from_raw(inst as *mut handler::Instance<H::Instance>));
254 }
255
256 SuccessVal::Success.into()
257 }
258
259 Op::ProcessOpenGL => {
260 let gl_process_info: &ProcessOpenGLStruct = unsafe { input_value.as_ref() };
261
262 let handler::Instance { data, renderer } = instance.context(e!("No instance"))?;
263 let gl_input = gl_process_info.into();
264
265 renderer.draw(&data, gl_input);
266
267 SuccessVal::Success.into()
268 }
269
270 Op::SetTime => {
271 let seconds: f64 = *unsafe { input_value.as_ref() };
272 instance.context(e!("No instance"))?.data.set_time(seconds);
273 SuccessVal::Success.into()
274 }
275
276 Op::SetBeatInfo => {
278 let beat_info: &SetBeatinfoStruct = unsafe { input_value.as_ref() };
279 if let Some(inst) = instance {
280 inst.data.set_beat(*beat_info);
281 SuccessVal::Success.into()
282 } else {
283 SuccessVal::Fail.into()
284 }
285 }
286
287 Op::Resize => {
288 let viewport: &FFGLViewportStruct = unsafe { input_value.as_ref() };
289 debug!("RESIZE\n{viewport:#?}");
290 SuccessVal::Success.into()
291 }
292
293 Op::Connect => SuccessVal::Success.into(),
294
295 Op::Instantiate | Op::Deinstantiate | Op::ProcessFrame | Op::ProcessFrameCopy => {
296 SuccessVal::Fail.into()
297 }
298
299 Op::InitialiseV2 => SuccessVal::Success.into(),
300 Op::Initialise => SuccessVal::Success.into(),
301 Op::Deinitialise => SuccessVal::Success.into(),
302
303 _ => SuccessVal::Fail.into(),
304 };
305
306 if !noisy_op {
307 debug!("=> {}", unsafe { resp.num });
308 } else {
309 trace!("=> {}", unsafe { resp.num });
310 }
311
312 Ok(resp)
313}