use {
super::ShaderType,
crate::{
IntoSfResult, SfResult,
cpp::FBox,
ffi::graphics as ffi,
graphics::{Texture, glsl},
system::InputStream,
},
std::{
ffi::CString,
io::{Read, Seek},
marker::PhantomData,
ptr::{self},
},
};
#[repr(C)]
pub struct Shader<'texture> {
_opaque: [u8; 0],
_texture: PhantomData<&'texture Texture>,
}
impl std::fmt::Debug for Shader<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Shader(<opaque> @ {self:p})")
}
}
impl<'texture> Shader<'texture> {
fn new() -> SfResult<FBox<Self>> {
FBox::new(unsafe { ffi::sfShader_new() }.cast()).into_sf_result()
}
pub fn from_file(path: &str, type_: ShaderType) -> SfResult<FBox<Self>> {
let path = CString::new(path)?;
let mut new = Self::new()?;
unsafe { ffi::sfShader_loadFromFile_1(new.raw_mut(), path.as_ptr(), type_) }
.into_sf_result()?;
Ok(new)
}
pub fn from_file_vert_frag(vert: &str, frag: &str) -> SfResult<FBox<Self>> {
let vert = CString::new(vert)?;
let frag = CString::new(frag)?;
let mut new = Self::new()?;
unsafe {
ffi::sfShader_loadFromFile_vert_frag(new.raw_mut(), vert.as_ptr(), frag.as_ptr())
}
.into_sf_result()?;
Ok(new)
}
pub fn from_file_all(vert: &str, geom: &str, frag: &str) -> SfResult<FBox<Self>> {
let vert = CString::new(vert)?;
let geom = CString::new(geom)?;
let frag = CString::new(frag)?;
let mut new = Self::new()?;
unsafe {
ffi::sfShader_loadFromFile_all(
new.raw_mut(),
vert.as_ptr(),
geom.as_ptr(),
frag.as_ptr(),
)
}
.into_sf_result()?;
Ok(new)
}
pub fn from_memory(contents: &str, type_: ShaderType) -> SfResult<FBox<Self>> {
let contents = CString::new(contents)?;
let mut new = Self::new()?;
unsafe { ffi::sfShader_loadFromMemory_1(new.raw_mut(), contents.as_ptr(), type_) }
.into_sf_result()?;
Ok(new)
}
pub fn from_memory_vert_frag(vert: &str, frag: &str) -> SfResult<FBox<Self>> {
let vert = CString::new(vert)?;
let frag = CString::new(frag)?;
let mut new = Self::new()?;
unsafe {
ffi::sfShader_loadFromMemory_vert_frag(new.raw_mut(), vert.as_ptr(), frag.as_ptr())
}
.into_sf_result()?;
Ok(new)
}
pub fn from_memory_all(vert: &str, geom: &str, frag: &str) -> SfResult<FBox<Self>> {
let vert = CString::new(vert)?;
let geom = CString::new(geom)?;
let frag = CString::new(frag)?;
let mut new = Self::new()?;
unsafe {
ffi::sfShader_loadFromMemory_all(
new.raw_mut(),
vert.as_ptr(),
geom.as_ptr(),
frag.as_ptr(),
)
}
.into_sf_result()?;
Ok(new)
}
pub fn from_stream<T: Read + Seek>(mut source: T, type_: ShaderType) -> SfResult<FBox<Self>> {
let source = InputStream::new(&mut source);
let mut new = Self::new()?;
unsafe { ffi::sfShader_loadFromStream_1(new.raw_mut(), source.stream.0.as_ptr(), type_) }
.into_sf_result()?;
Ok(new)
}
pub fn from_stream_vert_frag<T, U>(mut vert: T, mut frag: U) -> SfResult<FBox<Self>>
where
T: Read + Seek,
U: Read + Seek,
{
let vert = InputStream::new(&mut vert);
let frag = InputStream::new(&mut frag);
let mut new = Self::new()?;
unsafe {
ffi::sfShader_loadFromStream_vert_frag(
new.raw_mut(),
vert.stream.0.as_ptr(),
frag.stream.0.as_ptr(),
)
}
.into_sf_result()?;
Ok(new)
}
pub fn from_stream_all<T, U, V>(mut vert: T, mut geom: U, mut frag: V) -> SfResult<FBox<Self>>
where
T: Read + Seek,
U: Read + Seek,
V: Read + Seek,
{
let vert = InputStream::new(&mut vert);
let geom = InputStream::new(&mut geom);
let frag = InputStream::new(&mut frag);
let mut new = Self::new()?;
unsafe {
ffi::sfShader_loadFromStream_all(
new.raw_mut(),
vert.stream.0.as_ptr(),
geom.stream.0.as_ptr(),
frag.stream.0.as_ptr(),
)
}
.into_sf_result()?;
Ok(new)
}
pub fn bind(shader: Option<&Self>) {
unsafe { ffi::sfShader_bind(shader.map_or(ptr::null(), |s| s.raw())) }
}
#[must_use]
pub fn is_available() -> bool {
unsafe { ffi::sfShader_isAvailable() }
}
#[must_use]
pub fn is_geometry_available() -> bool {
unsafe { ffi::sfShader_isGeometryAvailable() }
}
pub fn set_uniform_float(&mut self, name: &str, value: f32) -> SfResult<()> {
let cstring = CString::new(name)?;
let name = cstring.as_ptr();
unsafe {
ffi::sfShader_setFloatUniform(self.raw_mut(), name, value);
}
Ok(())
}
pub fn set_uniform_vec2(&mut self, name: &str, value: glsl::Vec2) -> SfResult<()> {
let cstring = CString::new(name)?;
let name = cstring.as_ptr();
unsafe {
ffi::sfShader_setVec2Uniform(self.raw_mut(), name, value);
}
Ok(())
}
pub fn set_uniform_vec3(&mut self, name: &str, value: glsl::Vec3) -> SfResult<()> {
let cstring = CString::new(name)?;
let name = cstring.as_ptr();
unsafe {
ffi::sfShader_setVec3Uniform(self.raw_mut(), name, value);
}
Ok(())
}
pub fn set_uniform_vec4<V>(&mut self, name: &str, value: V) -> SfResult<()>
where
V: Into<glsl::Vec4>,
{
let cstring = CString::new(name)?;
let name = cstring.as_ptr();
unsafe {
ffi::sfShader_setVec4Uniform(self.raw_mut(), name, value.into().raw());
}
Ok(())
}
pub fn set_uniform_int(&mut self, name: &str, value: i32) -> SfResult<()> {
let cstring = CString::new(name)?;
let name = cstring.as_ptr();
unsafe {
ffi::sfShader_setIntUniform(self.raw_mut(), name, value);
}
Ok(())
}
pub fn set_uniform_ivec2(&mut self, name: &str, value: glsl::IVec2) -> SfResult<()> {
let cstring = CString::new(name)?;
let name = cstring.as_ptr();
unsafe {
ffi::sfShader_setIvec2Uniform(self.raw_mut(), name, value);
}
Ok(())
}
pub fn set_uniform_ivec3(&mut self, name: &str, value: glsl::IVec3) -> SfResult<()> {
let cstring = CString::new(name)?;
let name = cstring.as_ptr();
unsafe {
ffi::sfShader_setIvec3Uniform(self.raw_mut(), name, value.into());
}
Ok(())
}
pub fn set_uniform_ivec4<V>(&mut self, name: &str, value: V) -> SfResult<()>
where
V: Into<glsl::IVec4>,
{
let cstring = CString::new(name)?;
let name = cstring.as_ptr();
unsafe {
ffi::sfShader_setIvec4Uniform(self.raw_mut(), name, value.into().raw());
}
Ok(())
}
pub fn set_uniform_bool(&mut self, name: &str, value: bool) -> SfResult<()> {
let cstring = CString::new(name)?;
let name = cstring.as_ptr();
unsafe {
ffi::sfShader_setBoolUniform(self.raw_mut(), name, value);
}
Ok(())
}
pub fn set_uniform_bvec2(&mut self, name: &str, value: glsl::BVec2) -> SfResult<()> {
let cstring = CString::new(name)?;
let name = cstring.as_ptr();
unsafe {
ffi::sfShader_setBvec2Uniform(self.raw_mut(), name, value.into());
}
Ok(())
}
pub fn set_uniform_bvec3(&mut self, name: &str, value: glsl::BVec3) -> SfResult<()> {
let cstring = CString::new(name)?;
let name = cstring.as_ptr();
unsafe {
ffi::sfShader_setBvec3Uniform(self.raw_mut(), name, value.into());
}
Ok(())
}
pub fn set_uniform_bvec4(&mut self, name: &str, value: glsl::BVec4) -> SfResult<()> {
let cstring = CString::new(name)?;
let name = cstring.as_ptr();
unsafe {
ffi::sfShader_setBvec4Uniform(self.raw_mut(), name, value.into());
}
Ok(())
}
pub fn set_uniform_mat3<V>(&mut self, name: &str, value: V) -> SfResult<()>
where
V: Into<glsl::Mat3>,
{
let cstring = CString::new(name)?;
let name = cstring.as_ptr();
let value = value.into();
let ptr: *const _ = &value.0;
unsafe {
ffi::sfShader_setMat3Uniform(self.raw_mut(), name, ptr.cast());
}
Ok(())
}
pub fn set_uniform_mat4<V>(&mut self, name: &str, value: V) -> SfResult<()>
where
V: Into<glsl::Mat4>,
{
let cstring = CString::new(name)?;
let name = cstring.as_ptr();
let value = value.into();
let ptr: *const _ = &value.0;
unsafe {
ffi::sfShader_setMat4Uniform(self.raw_mut(), name, ptr.cast());
}
Ok(())
}
pub fn set_uniform_texture(&mut self, name: &str, value: &'texture Texture) -> SfResult<()> {
let cstring = CString::new(name)?;
let name = cstring.as_ptr();
unsafe {
ffi::sfShader_setTextureUniform(self.raw_mut(), name, value);
}
Ok(())
}
pub fn set_uniform_current_texture(&mut self, name: &str) -> SfResult<()> {
let cstring = CString::new(name)?;
let name = cstring.as_ptr();
unsafe {
ffi::sfShader_setCurrentTextureUniform(self.raw_mut(), name);
}
Ok(())
}
pub fn set_uniform_array_float(&mut self, name: &str, array: &[f32]) -> SfResult<()> {
let cstring = CString::new(name)?;
let name = cstring.as_ptr();
let len = array.len();
unsafe {
ffi::sfShader_setFloatUniformArray(self.raw_mut(), name, array.as_ptr(), len);
}
Ok(())
}
pub fn set_uniform_array_vec2(&mut self, name: &str, array: &[glsl::Vec2]) -> SfResult<()> {
let cstring = CString::new(name)?;
let name = cstring.as_ptr();
let len = array.len();
let ptr = array.as_ptr();
unsafe {
ffi::sfShader_setVec2UniformArray(self.raw_mut(), name, ptr, len);
}
Ok(())
}
pub fn set_uniform_array_vec3(&mut self, name: &str, array: &[glsl::Vec3]) -> SfResult<()> {
let cstring = CString::new(name)?;
let name = cstring.as_ptr();
let len = array.len();
let ptr = array.as_ptr();
unsafe {
ffi::sfShader_setVec3UniformArray(self.raw_mut(), name, ptr, len);
}
Ok(())
}
pub fn set_uniform_array_vec4(&mut self, name: &str, array: &[glsl::Vec4]) -> SfResult<()> {
let cstring = CString::new(name)?;
unsafe {
ffi::sfShader_setVec4UniformArray(
self.raw_mut(),
cstring.as_ptr(),
array.as_ptr().cast(),
array.len(),
);
}
Ok(())
}
pub fn set_uniform_array_mat3(&mut self, name: &str, array: &[glsl::Mat3]) -> SfResult<()> {
let cstring = CString::new(name)?;
unsafe {
ffi::sfShader_setMat3UniformArray(
self.raw_mut(),
cstring.as_ptr(),
array.as_ptr().cast(),
array.len(),
);
}
Ok(())
}
pub fn set_uniform_array_mat4(&mut self, name: &str, array: &[glsl::Mat4]) -> SfResult<()> {
let cstring = CString::new(name)?;
unsafe {
ffi::sfShader_setMat4UniformArray(
self.raw_mut(),
cstring.as_ptr(),
array.as_ptr().cast(),
array.len(),
);
}
Ok(())
}
#[must_use]
pub fn native_handle(&self) -> u32 {
unsafe { ffi::sfShader_getNativeHandle(self.raw()) }
}
pub(super) fn raw(&self) -> *const ffi::sfShader {
let ptr: *const Self = self;
ptr.cast()
}
fn raw_mut(&mut self) -> *mut ffi::sfShader {
let ptr: *mut Self = self;
ptr.cast()
}
}
impl Drop for Shader<'_> {
fn drop(&mut self) {
unsafe { ffi::sfShader_del(self.raw_mut()) }
}
}