use crate::{StereoKitError, system::IAsset};
use std::{
ffi::{CStr, CString, c_void},
path::Path,
ptr::NonNull,
};
#[repr(C)]
#[derive(Debug, PartialEq)]
pub struct Shader(pub NonNull<_ShaderT>);
impl Drop for Shader {
fn drop(&mut self) {
unsafe { shader_release(self.0.as_ptr()) };
}
}
impl AsRef<Shader> for Shader {
fn as_ref(&self) -> &Shader {
self
}
}
#[repr(C)]
#[derive(Debug)]
pub struct _ShaderT {
_unused: [u8; 0],
}
pub type ShaderT = *mut _ShaderT;
unsafe extern "C" {
pub fn shader_find(id: *const ::std::os::raw::c_char) -> ShaderT;
pub fn shader_create_file(filename_utf8: *const ::std::os::raw::c_char) -> ShaderT;
pub fn shader_create_mem(data: *mut ::std::os::raw::c_void, data_size: usize) -> ShaderT;
pub fn shader_set_id(shader: ShaderT, id: *const ::std::os::raw::c_char);
pub fn shader_get_id(shader: ShaderT) -> *const ::std::os::raw::c_char;
pub fn shader_get_name(shader: ShaderT) -> *const ::std::os::raw::c_char;
pub fn shader_addref(shader: ShaderT);
pub fn shader_release(shader: ShaderT);
}
impl IAsset for Shader {
fn get_id(&self) -> &str {
self.get_id()
}
}
impl Default for Shader {
fn default() -> Self {
Self::find("default/shader").unwrap()
}
}
impl Shader {
pub fn from_memory(data: &[u8]) -> Result<Shader, StereoKitError> {
Ok(Shader(
NonNull::new(unsafe { shader_create_mem(data.as_ptr() as *mut c_void, data.len()) })
.ok_or(StereoKitError::ShaderMem)?,
))
}
pub fn from_file(file_utf8: impl AsRef<Path>) -> Result<Shader, StereoKitError> {
let path_buf = file_utf8.as_ref().to_path_buf();
let c_str = CString::new(
path_buf
.clone()
.to_str()
.ok_or(StereoKitError::ShaderFile(path_buf.clone(), "CString conversion".to_string()))?,
)?;
Ok(Shader(
NonNull::new(unsafe { shader_create_file(c_str.as_ptr()) })
.ok_or(StereoKitError::ShaderFile(path_buf.clone(), "shader_create_file failed".to_string()))?,
))
}
pub fn find<S: AsRef<str>>(id: S) -> Result<Shader, StereoKitError> {
let c_str = CString::new(id.as_ref())
.map_err(|_| StereoKitError::ShaderFind(id.as_ref().into(), "CString conversion".to_string()))?;
Ok(Shader(
NonNull::new(unsafe { shader_find(c_str.as_ptr()) })
.ok_or(StereoKitError::ShaderFind(id.as_ref().into(), "shader_find failed".to_string()))?,
))
}
pub fn clone_ref(&self) -> Shader {
Shader(
NonNull::new(unsafe { shader_find(shader_get_id(self.0.as_ptr())) }).expect("<asset>::clone_ref failed!"),
)
}
pub fn id<S: AsRef<str>>(&mut self, id: S) -> &mut Self {
let c_str = CString::new(id.as_ref()).unwrap();
unsafe { shader_set_id(self.0.as_ptr(), c_str.as_ptr()) };
self
}
pub fn get_id(&self) -> &str {
unsafe { CStr::from_ptr(shader_get_id(self.0.as_ptr())) }.to_str().unwrap()
}
pub fn get_name(&self) -> &str {
unsafe { CStr::from_ptr(shader_get_name(self.0.as_ptr())) }.to_str().unwrap()
}
pub fn blit() -> Self {
Self::find("default/shader_blit").unwrap()
}
pub fn light_map() -> Self {
Self::find("default/shader_lightmap").unwrap()
}
pub fn unlit() -> Self {
Self::find("default/shader_unlit").unwrap()
}
pub fn unlit_clip() -> Self {
Self::find("default/shader_unlit_clip").unwrap()
}
pub fn font() -> Self {
Self::find("default/shader_font").unwrap()
}
pub fn equirect() -> Self {
Self::find("default/shader_equirect").unwrap()
}
pub fn ui() -> Self {
Self::find("default/shader_ui").unwrap()
}
pub fn ui_box() -> Self {
Self::find("default/shader_ui_box").unwrap()
}
pub fn ui_quadrant() -> Self {
Self::find("default/shader_ui_quadrant").unwrap()
}
pub fn sky() -> Self {
Self::find("default/shader_sky").unwrap()
}
pub fn pbr() -> Self {
Self::find("default/shader_pbr").unwrap()
}
pub fn pbr_clip() -> Self {
Self::find("default/shader_pbr_clip").unwrap()
}
}