use std::os::raw::*;
use xplm_sys;
pub trait DrawCallback: 'static {
fn draw(&mut self);
}
impl<F> DrawCallback for F
where
F: 'static + FnMut(),
{
fn draw(&mut self) {
self()
}
}
pub struct Draw {
_callback: Box<dyn DrawCallback>,
phase: Phase,
callback_ptr: *mut c_void,
c_callback: xplm_sys::XPLMDrawCallback_f,
}
impl Draw {
pub fn new<C: DrawCallback>(phase: Phase, callback: C) -> Result<Self, Error> {
let xplm_phase = phase.to_xplm();
let callback_box = Box::new(callback);
let callback_ptr: *const _ = &*callback_box;
let status = unsafe {
xplm_sys::XPLMRegisterDrawCallback(
Some(draw_callback::<C>),
xplm_phase,
0,
callback_ptr as *mut _,
)
};
if status == 1 {
Ok(Draw {
_callback: callback_box,
phase,
callback_ptr: callback_ptr as *mut _,
c_callback: Some(draw_callback::<C>),
})
} else {
Err(Error::UnsupportedPhase(phase))
}
}
}
impl Drop for Draw {
fn drop(&mut self) {
let phase = self.phase.to_xplm();
unsafe {
xplm_sys::XPLMUnregisterDrawCallback(self.c_callback, phase, 0, self.callback_ptr);
}
}
}
unsafe extern "C" fn draw_callback<C: DrawCallback>(
_phase: xplm_sys::XPLMDrawingPhase,
_before: c_int,
refcon: *mut c_void,
) -> c_int {
let callback_ptr = refcon as *mut C;
(*callback_ptr).draw();
1
}
#[derive(Debug, Copy, Clone)]
pub enum Phase {
AfterPanel,
AfterGauges,
AfterWindows,
AfterLocalMap3D,
AfterLocalMap2D,
AfterLocalMapProfile,
}
impl Phase {
fn to_xplm(&self) -> xplm_sys::XPLMDrawingPhase {
use self::Phase::*;
let phase = match *self {
AfterPanel => xplm_sys::xplm_Phase_Panel,
AfterGauges => xplm_sys::xplm_Phase_Gauges,
AfterWindows => xplm_sys::xplm_Phase_Window,
AfterLocalMap2D => xplm_sys::xplm_Phase_LocalMap2D,
AfterLocalMap3D => xplm_sys::xplm_Phase_LocalMap3D,
AfterLocalMapProfile => xplm_sys::xplm_Phase_LocalMapProfile,
};
phase as xplm_sys::XPLMDrawingPhase
}
}
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("Unsupported draw phase: {0:?}")]
UnsupportedPhase(Phase),
}
#[derive(Debug, Clone)]
pub struct GraphicsState {
pub fog: bool,
pub lighting: bool,
pub alpha_testing: bool,
pub alpha_blending: bool,
pub depth_testing: bool,
pub depth_writing: bool,
pub textures: i32,
}
pub fn set_state(state: &GraphicsState) {
unsafe {
xplm_sys::XPLMSetGraphicsState(
state.fog as i32,
state.textures,
state.lighting as i32,
state.alpha_testing as i32,
state.alpha_blending as i32,
state.depth_testing as i32,
state.depth_writing as i32,
);
}
}
pub fn bind_texture(texture_number: i32, texture_id: i32) {
unsafe {
xplm_sys::XPLMBindTexture2d(texture_number, texture_id);
}
}
pub fn generate_texture_numbers(numbers: &mut [i32]) {
let count = if numbers.len() < (i32::max_value() as usize) {
numbers.len() as i32
} else {
i32::max_value()
};
unsafe {
xplm_sys::XPLMGenerateTextureNumbers(numbers.as_mut_ptr(), count);
}
}
pub fn generate_texture_number() -> i32 {
let number = 0;
generate_texture_numbers(&mut [number]);
number
}