pub type Effect = sys::mojo::MOJOSHADER_effect;
pub type EffectTechnique = sys::mojo::MOJOSHADER_effectTechnique;
pub type EffectStateChanges = sys::mojo::MOJOSHADER_effectStateChanges;
pub type EffectParam = sys::mojo::MOJOSHADER_effectParam;
use ::{
fna3d_sys as sys,
std::{
ffi::{c_void, CStr},
fmt, fs,
io::{self, prelude::*},
path::Path,
},
};
pub type Result<T> = std::result::Result<T, LoadShaderError>;
#[derive(Debug)]
pub enum LoadShaderError {
Io(io::Error),
EffectError(String),
}
impl fmt::Display for LoadShaderError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
LoadShaderError::Io(err) => write!(f, "{}", err),
LoadShaderError::EffectError(err) => write!(f, "Shader loading errors: {}", err),
}
}
}
pub fn from_file(
device: &crate::Device,
shader_path: impl AsRef<Path>,
) -> Result<(*mut crate::Effect, *mut crate::mojo::Effect)> {
let data = fs::read(shader_path).map_err(|e| LoadShaderError::Io(e))?;
self::from_bytes(device, &data)
}
pub fn from_bytes(
device: &crate::Device,
bytes: &[u8],
) -> Result<(*mut crate::Effect, *mut crate::mojo::Effect)> {
let (effect, mojo_effect) =
device.create_effect(bytes as *const _ as *mut _, bytes.len() as u32);
let techniques = unsafe { (*mojo_effect).techniques };
device.set_effect_technique(effect, techniques);
let mojo_effect: &mut crate::mojo::Effect = unsafe { &mut *mojo_effect };
if mojo_effect.error_count <= 0 {
Ok((effect, mojo_effect))
} else {
let errs = unsafe {
std::slice::from_raw_parts(mojo_effect.techniques, mojo_effect.technique_count as usize)
};
let message = format!("{:?}", errs);
Err(LoadShaderError::EffectError(message))
}
}
pub fn orthographic_off_center(
left: f32,
right: f32,
bottom: f32,
top: f32,
near: f32,
far: f32,
) -> [f32; 16] {
[
(2.0 / (right as f64 - left as f64)) as f32,
0.0,
0.0,
-((right as f64 + left as f64) / (right as f64 - left as f64)) as f32,
0.0,
(2.0 / (top as f64 - bottom as f64)) as f32,
0.0,
-((top as f64 + bottom as f64) / (top as f64 - bottom as f64)) as f32,
0.0,
0.0,
-(1.0 / (far as f64 - near as f64)) as f32,
(near as f64 / (near as f64 - far as f64)) as f32,
0.0,
0.0,
0.0,
1.0,
]
}
pub fn find_param(data: *mut Effect, name: &CStr) -> Option<*mut c_void> {
unsafe {
for i in 0..(*data).param_count as isize {
let target_name = (*(*data).params.offset(i)).value.name;
let target_name = std::ffi::CStr::from_ptr(target_name);
if target_name != name {
continue;
}
return Some((*(*data).params.offset(i)).value.__bindgen_anon_1.values);
}
None
}
}
pub unsafe fn set_param<T>(data: *mut Effect, name: &CStr, value: &T) -> bool {
let ptr = match self::find_param(data, name) {
Some(ptr) => ptr,
None => return false,
};
let n_bytes = std::mem::size_of::<T>();
let src: &[u8] = std::slice::from_raw_parts_mut(value as *const _ as *mut u8, n_bytes);
let mut dest = std::slice::from_raw_parts_mut(ptr as *mut u8, n_bytes);
dest.write(src)
.expect("failed to write universal effect data");
true
}