use super::buffer::Buffer;
use crate::gl33::GL33;
use gl::{self, types::*};
use luminance::{
backend::shader::{Shader, ShaderData, Uniformable},
pipeline::{ShaderDataBinding, TextureBinding},
pixel::{SamplerType, Type as PixelType},
shader::{
types::{Arr, Mat22, Mat33, Mat44, Vec2, Vec3, Vec4},
ProgramError, ShaderDataError, StageError, StageType, TessellationStages, Uniform, UniformType,
UniformWarning, VertexAttribWarning,
},
texture::{Dim, Dimensionable},
vertex::Semantics,
};
use luminance_std140::{ArrElem, Std140};
use std::{
ffi::CString,
mem,
ptr::{null, null_mut},
};
#[derive(Debug)]
pub struct Stage {
handle: GLuint,
}
impl Drop for Stage {
fn drop(&mut self) {
unsafe {
gl::DeleteShader(self.handle);
}
}
}
#[derive(Debug)]
pub struct Program {
pub(crate) handle: GLuint,
}
impl Drop for Program {
fn drop(&mut self) {
unsafe {
gl::DeleteProgram(self.handle);
}
}
}
impl Program {
fn link(&self) -> Result<(), ProgramError> {
let handle = self.handle;
unsafe {
gl::LinkProgram(handle);
let mut linked: GLint = gl::FALSE.into();
gl::GetProgramiv(handle, gl::LINK_STATUS, &mut linked);
if linked == gl::TRUE.into() {
Ok(())
} else {
let mut log_len: GLint = 0;
gl::GetProgramiv(handle, gl::INFO_LOG_LENGTH, &mut log_len);
let mut log: Vec<u8> = Vec::with_capacity(log_len as usize);
gl::GetProgramInfoLog(handle, log_len, null_mut(), log.as_mut_ptr() as *mut GLchar);
log.set_len(log_len as usize);
Err(ProgramError::link_failed(String::from_utf8(log).unwrap()))
}
}
}
}
pub struct UniformBuilder {
handle: GLuint,
}
impl UniformBuilder {
fn new(program: &Program) -> Self {
UniformBuilder {
handle: program.handle,
}
}
fn ask_uniform<T>(
&self,
name: &str,
ty: UniformType,
size: usize,
) -> Result<Uniform<T>, UniformWarning>
where
GL33: for<'u> Uniformable<'u, T>,
{
let location = {
let c_name = CString::new(name.as_bytes()).unwrap();
unsafe { gl::GetUniformLocation(self.handle, c_name.as_ptr() as *const GLchar) }
};
if location < 0 {
return Err(UniformWarning::inactive(name));
}
uniform_type_match(self.handle, name, ty, size)?;
Ok(unsafe { Uniform::new(location) })
}
fn ask_uniform_block<T>(&self, name: &str) -> Result<Uniform<T>, UniformWarning>
where
GL33: for<'u> Uniformable<'u, T>,
{
let location = {
let c_name = CString::new(name.as_bytes()).unwrap();
unsafe { gl::GetUniformBlockIndex(self.handle, c_name.as_ptr() as *const GLchar) }
};
if location == gl::INVALID_INDEX {
return Err(UniformWarning::inactive(name));
}
Ok(unsafe { Uniform::new(location as _) })
}
}
unsafe impl Shader for GL33 {
type StageRepr = Stage;
type ProgramRepr = Program;
type UniformBuilderRepr = UniformBuilder;
unsafe fn new_stage(&mut self, ty: StageType, src: &str) -> Result<Self::StageRepr, StageError> {
let handle = gl::CreateShader(opengl_shader_type(ty));
if handle == 0 {
return Err(StageError::compilation_failed(
ty,
"unable to create shader stage",
));
}
let c_src = CString::new(glsl_pragma_src(src).as_bytes()).unwrap();
gl::ShaderSource(handle, 1, [c_src.as_ptr()].as_ptr(), null());
gl::CompileShader(handle);
let mut compiled: GLint = gl::FALSE.into();
gl::GetShaderiv(handle, gl::COMPILE_STATUS, &mut compiled);
if compiled == gl::TRUE.into() {
Ok(Stage { handle })
} else {
let mut log_len: GLint = 0;
gl::GetShaderiv(handle, gl::INFO_LOG_LENGTH, &mut log_len);
let mut log: Vec<u8> = Vec::with_capacity(log_len as usize);
gl::GetShaderInfoLog(handle, log_len, null_mut(), log.as_mut_ptr() as *mut GLchar);
gl::DeleteShader(handle);
log.set_len(log_len as usize);
Err(StageError::compilation_failed(
ty,
String::from_utf8(log).unwrap(),
))
}
}
unsafe fn new_program(
&mut self,
vertex: &Self::StageRepr,
tess: Option<TessellationStages<Self::StageRepr>>,
geometry: Option<&Self::StageRepr>,
fragment: &Self::StageRepr,
) -> Result<Self::ProgramRepr, ProgramError> {
let handle = gl::CreateProgram();
if let Some(TessellationStages {
control,
evaluation,
}) = tess
{
gl::AttachShader(handle, control.handle);
gl::AttachShader(handle, evaluation.handle);
}
gl::AttachShader(handle, vertex.handle);
if let Some(geometry) = geometry {
gl::AttachShader(handle, geometry.handle);
}
gl::AttachShader(handle, fragment.handle);
let program = Program { handle };
program.link().map(move |_| program)
}
unsafe fn apply_semantics<Sem>(
program: &mut Self::ProgramRepr,
) -> Result<Vec<VertexAttribWarning>, ProgramError>
where
Sem: Semantics,
{
let warnings = bind_vertex_attribs_locations::<Sem>(program);
program.link()?;
Ok(warnings)
}
unsafe fn new_uniform_builder(
program: &mut Self::ProgramRepr,
) -> Result<Self::UniformBuilderRepr, ProgramError> {
Ok(UniformBuilder::new(&program))
}
unsafe fn ask_uniform<T>(
uniform_builder: &mut Self::UniformBuilderRepr,
name: &str,
) -> Result<Uniform<T>, UniformWarning>
where
Self: for<'u> Uniformable<'u, T>,
{
let uniform = match Self::ty() {
UniformType::ShaderDataBinding => uniform_builder.ask_uniform_block(name)?,
_ => uniform_builder.ask_uniform(name, Self::ty(), Self::SIZE)?,
};
Ok(uniform)
}
unsafe fn unbound<T>(_: &mut Self::UniformBuilderRepr) -> Uniform<T>
where
Self: for<'u> Uniformable<'u, T>,
{
Uniform::new(-1)
}
}
fn opengl_shader_type(t: StageType) -> GLenum {
match t {
StageType::TessellationControlShader => gl::TESS_CONTROL_SHADER,
StageType::TessellationEvaluationShader => gl::TESS_EVALUATION_SHADER,
StageType::VertexShader => gl::VERTEX_SHADER,
StageType::GeometryShader => gl::GEOMETRY_SHADER,
StageType::FragmentShader => gl::FRAGMENT_SHADER,
}
}
#[cfg(feature = "GL_ARB_gpu_shader_fp64")]
const GLSL_PRAGMA: &str = "#version 330 core\n\
#extension GL_ARB_separate_shader_objects : require\n
#extension GL_ARB_gpu_shader_fp64 : require\n\
layout(std140) uniform;\n";
#[cfg(not(feature = "GL_ARB_gpu_shader_fp64"))]
const GLSL_PRAGMA: &str = "#version 330 core\n\
#extension GL_ARB_separate_shader_objects : require\n\
layout(std140) uniform;\n";
fn glsl_pragma_src(src: &str) -> String {
let mut pragma = String::from(GLSL_PRAGMA);
pragma.push_str(src);
pragma
}
fn uniform_type_match(
program: GLuint,
name: &str,
ty: UniformType,
size: usize,
) -> Result<(), UniformWarning> {
let mut glty: GLuint = 0;
let mut found_size: GLint = 0;
unsafe {
let mut max_len = 0;
gl::GetProgramiv(program, gl::ACTIVE_UNIFORM_MAX_LENGTH, &mut max_len);
let mut index = 0;
let c_name = CString::new(name.as_bytes()).unwrap();
gl::GetUniformIndices(
program,
1,
[c_name.as_ptr() as *const GLchar].as_ptr(),
&mut index,
);
let mut name_ = Vec::<GLchar>::with_capacity(max_len as usize);
gl::GetActiveUniform(
program,
index,
max_len,
null_mut(),
&mut found_size,
&mut glty,
name_.as_mut_ptr(),
);
}
let found_size = found_size as usize;
if size > 0 && found_size != size {
return Err(UniformWarning::size_mismatch(name, size, found_size));
}
check_uniform_type_match(name, ty, glty)
}
#[allow(clippy::cognitive_complexity)]
fn check_uniform_type_match(
name: &str,
ty: UniformType,
glty: GLuint,
) -> Result<(), UniformWarning> {
macro_rules! milkcheck {
($ty:expr, $( ( $v:tt, $t:tt ) ),* $(,)?) => {
match $ty {
$(
UniformType::$v => {
if glty == gl::$t {
Ok(())
} else {
Err(UniformWarning::type_mismatch(name, ty))
}
}
)*
_ => Err(UniformWarning::unsupported_type(name, ty))
}
}
}
milkcheck!(
ty,
(Int, INT),
(UInt, UNSIGNED_INT),
(Float, FLOAT),
(Double, DOUBLE),
(Bool, BOOL),
(IVec2, INT_VEC2),
(IVec3, INT_VEC3),
(IVec4, INT_VEC4),
(UIVec2, UNSIGNED_INT_VEC2),
(UIVec3, UNSIGNED_INT_VEC3),
(UIVec4, UNSIGNED_INT_VEC4),
(Vec2, FLOAT_VEC2),
(Vec3, FLOAT_VEC3),
(Vec4, FLOAT_VEC4),
(DVec2, DOUBLE_VEC2),
(DVec3, DOUBLE_VEC3),
(DVec4, DOUBLE_VEC4),
(BVec2, BOOL_VEC2),
(BVec3, BOOL_VEC3),
(BVec4, BOOL_VEC4),
(M22, FLOAT_MAT2),
(M33, FLOAT_MAT3),
(M44, FLOAT_MAT4),
(DM22, DOUBLE_MAT2),
(DM33, DOUBLE_MAT3),
(DM44, DOUBLE_MAT4),
(ISampler1D, INT_SAMPLER_1D),
(ISampler2D, INT_SAMPLER_2D),
(ISampler3D, INT_SAMPLER_3D),
(ISampler1DArray, INT_SAMPLER_1D_ARRAY),
(ISampler2DArray, INT_SAMPLER_2D_ARRAY),
(UISampler1D, UNSIGNED_INT_SAMPLER_1D),
(UISampler2D, UNSIGNED_INT_SAMPLER_2D),
(UISampler3D, UNSIGNED_INT_SAMPLER_3D),
(UISampler1DArray, UNSIGNED_INT_SAMPLER_1D_ARRAY),
(UISampler2DArray, UNSIGNED_INT_SAMPLER_2D_ARRAY),
(Sampler1D, SAMPLER_1D),
(Sampler2D, SAMPLER_2D),
(Sampler3D, SAMPLER_3D),
(Sampler1DArray, SAMPLER_1D_ARRAY),
(Sampler2DArray, SAMPLER_2D_ARRAY),
(ICubemap, INT_SAMPLER_CUBE),
(UICubemap, UNSIGNED_INT_SAMPLER_CUBE),
(Cubemap, SAMPLER_CUBE),
)
}
fn bind_vertex_attribs_locations<Sem>(program: &Program) -> Vec<VertexAttribWarning>
where
Sem: Semantics,
{
let mut warnings = Vec::new();
for desc in Sem::semantics_set() {
match get_vertex_attrib_location(program, &desc.name) {
Ok(_) => {
let index = desc.index as GLuint;
let c_name = CString::new(desc.name.as_bytes()).unwrap();
unsafe { gl::BindAttribLocation(program.handle, index, c_name.as_ptr() as *const GLchar) };
}
Err(warning) => warnings.push(warning),
}
}
warnings
}
fn get_vertex_attrib_location(
program: &Program,
name: &str,
) -> Result<GLuint, VertexAttribWarning> {
let location = {
let c_name = CString::new(name.as_bytes()).unwrap();
unsafe { gl::GetAttribLocation(program.handle, c_name.as_ptr() as *const GLchar) }
};
if location < 0 {
Err(VertexAttribWarning::inactive(name))
} else {
Ok(location as _)
}
}
macro_rules! impl_Uniformable {
(Arr<$t:ty>, $uty:tt, $f:tt) => {
unsafe impl<'a, const N: usize> Uniformable<'a, Arr<$t, N>> for GL33 {
type Target = &'a [$t; N];
const SIZE: usize = N;
unsafe fn ty() -> UniformType {
UniformType::$uty
}
unsafe fn update(_: &mut Program, uniform: &'a Uniform<Arr<$t, N>>, value: Self::Target) {
gl::$f(uniform.index(), N as GLsizei, value.as_ptr() as _);
}
}
};
(vec $t:ty, $uty:tt, $f:tt) => {
unsafe impl<'a> Uniformable<'a, $t> for GL33 {
type Target = $t;
const SIZE: usize = 1;
unsafe fn ty() -> UniformType {
UniformType::$uty
}
unsafe fn update(_: &mut Program, uniform: &'a Uniform<$t>, value: Self::Target) {
gl::$f(uniform.index(), 1, value.as_ptr());
}
}
};
($t:ty, $uty:tt, $f:tt) => {
unsafe impl<'a> Uniformable<'a, $t> for GL33 {
type Target = $t;
const SIZE: usize = 1;
unsafe fn ty() -> UniformType {
UniformType::$uty
}
unsafe fn update(_: &mut Program, uniform: &'a Uniform<$t>, value: Self::Target) {
gl::$f(uniform.index(), value);
}
}
};
(mat Arr<$t:ty>, $uty:tt, $f:tt) => {
unsafe impl<'a, const N: usize> Uniformable<'a, Arr<$t, N>> for GL33 {
type Target = &'a [$t; N];
const SIZE: usize = N;
unsafe fn ty() -> UniformType {
UniformType::$uty
}
unsafe fn update(_: &mut Program, uniform: &'a Uniform<Arr<$t, N>>, value: Self::Target) {
gl::$f(
uniform.index(),
N as GLsizei,
gl::FALSE,
value.as_ptr() as _,
);
}
}
};
(mat $t:ty, $uty:tt, $f:tt) => {
unsafe impl<'a> Uniformable<'a, $t> for GL33 {
type Target = $t;
const SIZE: usize = 1;
unsafe fn ty() -> UniformType {
UniformType::$uty
}
unsafe fn update(_: &mut Program, uniform: &'a Uniform<$t>, value: Self::Target) {
gl::$f(uniform.index(), 1, gl::FALSE, value.as_ptr() as _);
}
}
};
}
impl_Uniformable!(i32, Int, Uniform1i);
impl_Uniformable!(vec Vec2<i32>, IVec2, Uniform2iv);
impl_Uniformable!(vec Vec3<i32>, IVec3, Uniform3iv);
impl_Uniformable!(vec Vec4<i32>, IVec4, Uniform4iv);
impl_Uniformable!(Arr<i32>, Int, Uniform1iv);
impl_Uniformable!(Arr<Vec2<i32>>, IVec2, Uniform2iv);
impl_Uniformable!(Arr<Vec3<i32>>, IVec3, Uniform3iv);
impl_Uniformable!(Arr<Vec4<i32>>, IVec4, Uniform4iv);
impl_Uniformable!(u32, UInt, Uniform1ui);
impl_Uniformable!(vec Vec2<u32>, UIVec2, Uniform2uiv);
impl_Uniformable!(vec Vec3<u32>, UIVec3, Uniform3uiv);
impl_Uniformable!(vec Vec4<u32>, UIVec4, Uniform4uiv);
impl_Uniformable!(Arr<u32>, UInt, Uniform1uiv);
impl_Uniformable!(Arr<Vec2<u32>>, UIVec2, Uniform2uiv);
impl_Uniformable!(Arr<Vec3<u32>>, UIVec3, Uniform3uiv);
impl_Uniformable!(Arr<Vec4<u32>>, UIVec4, Uniform4uiv);
impl_Uniformable!(f32, Float, Uniform1f);
impl_Uniformable!(vec Vec2<f32>, Vec2, Uniform2fv);
impl_Uniformable!(vec Vec3<f32>, Vec3, Uniform3fv);
impl_Uniformable!(vec Vec4<f32>, Vec4, Uniform4fv);
impl_Uniformable!(Arr<f32>, Float, Uniform1fv);
impl_Uniformable!(Arr<Vec2<f32>>, Vec2, Uniform2fv);
impl_Uniformable!(Arr<Vec3<f32>>, Vec3, Uniform3fv);
impl_Uniformable!(Arr<Vec4<f32>>, Vec4, Uniform4fv);
#[cfg(feature = "GL_ARB_gpu_shader_fp64")]
impl_Uniformable!(f64, Double, Uniform1d);
#[cfg(feature = "GL_ARB_gpu_shader_fp64")]
impl_Uniformable!(vec Vec2<f64>, DVec2, Uniform2dv);
#[cfg(feature = "GL_ARB_gpu_shader_fp64")]
impl_Uniformable!(vec Vec3<f64>, DVec3, Uniform3dv);
#[cfg(feature = "GL_ARB_gpu_shader_fp64")]
impl_Uniformable!(vec Vec4<f64>, DVec4, Uniform4dv);
#[cfg(feature = "GL_ARB_gpu_shader_fp64")]
impl_Uniformable!(Arr<f64>, Double, Uniform1dv);
#[cfg(feature = "GL_ARB_gpu_shader_fp64")]
impl_Uniformable!(Arr<Vec2<f64>>, DVec2, Uniform2dv);
#[cfg(feature = "GL_ARB_gpu_shader_fp64")]
impl_Uniformable!(Arr<Vec3<f64>>, DVec3, Uniform3dv);
#[cfg(feature = "GL_ARB_gpu_shader_fp64")]
impl_Uniformable!(Arr<Vec4<f64>>, DVec4, Uniform4dv);
impl_Uniformable!(mat Mat22<f32>, M22, UniformMatrix2fv);
impl_Uniformable!(mat Arr<Mat22<f32>>, M22, UniformMatrix2fv);
impl_Uniformable!(mat Mat33<f32>, M33, UniformMatrix3fv);
impl_Uniformable!(mat Arr<Mat33<f32>>, M33, UniformMatrix3fv);
impl_Uniformable!(mat Mat44<f32>, M44, UniformMatrix4fv);
impl_Uniformable!(mat Arr<Mat44<f32>>, M44, UniformMatrix4fv);
#[cfg(feature = "GL_ARB_gpu_shader_fp64")]
impl_Uniformable!(mat Mat22<f64>, DM22, UniformMatrix2dv);
#[cfg(feature = "GL_ARB_gpu_shader_fp64")]
impl_Uniformable!(mat Arr<Mat22<f64>>, DM22, UniformMatrix2dv);
#[cfg(feature = "GL_ARB_gpu_shader_fp64")]
impl_Uniformable!(mat Mat33<f64>, DM33, UniformMatrix3dv);
#[cfg(feature = "GL_ARB_gpu_shader_fp64")]
impl_Uniformable!(mat Arr<Mat33<f64>>, DM33, UniformMatrix3dv);
#[cfg(feature = "GL_ARB_gpu_shader_fp64")]
impl_Uniformable!(mat Mat44<f64>, DM44, UniformMatrix4dv);
#[cfg(feature = "GL_ARB_gpu_shader_fp64")]
impl_Uniformable!(mat Arr<Mat44<f64>>, DM44, UniformMatrix4dv);
unsafe impl<'a> Uniformable<'a, bool> for GL33 {
type Target = bool;
const SIZE: usize = 1;
unsafe fn ty() -> UniformType {
UniformType::Bool
}
unsafe fn update(_: &mut Program, uniform: &'a Uniform<bool>, value: Self::Target) {
gl::Uniform1ui(uniform.index(), value as u32);
}
}
unsafe impl<'a> Uniformable<'a, Vec2<bool>> for GL33 {
type Target = Vec2<bool>;
const SIZE: usize = 1;
unsafe fn ty() -> UniformType {
UniformType::BVec2
}
unsafe fn update(_: &mut Program, uniform: &'a Uniform<Vec2<bool>>, value: Self::Target) {
let v = [value[0] as u32, value[1] as u32];
gl::Uniform2uiv(uniform.index(), 1, v.as_ptr() as _);
}
}
unsafe impl<'a> Uniformable<'a, Vec3<bool>> for GL33 {
type Target = Vec3<bool>;
const SIZE: usize = 1;
unsafe fn ty() -> UniformType {
UniformType::BVec3
}
unsafe fn update(_: &mut Program, uniform: &'a Uniform<Vec3<bool>>, value: Self::Target) {
let v = [value[0] as u32, value[1] as u32, value[2] as u32];
gl::Uniform3uiv(uniform.index(), 1, v.as_ptr() as _);
}
}
unsafe impl<'a> Uniformable<'a, Vec4<bool>> for GL33 {
type Target = Vec4<bool>;
const SIZE: usize = 1;
unsafe fn ty() -> UniformType {
UniformType::BVec4
}
unsafe fn update(_: &mut Program, uniform: &'a Uniform<Vec4<bool>>, value: Self::Target) {
let v = [
value[0] as u32,
value[1] as u32,
value[2] as u32,
value[3] as u32,
];
gl::Uniform4uiv(uniform.index(), 1, v.as_ptr() as _);
}
}
static mut BOOL_CACHE: Vec<u32> = Vec::new();
unsafe impl<'a, const N: usize> Uniformable<'a, Arr<bool, N>> for GL33 {
type Target = &'a [bool; N];
const SIZE: usize = N;
unsafe fn ty() -> UniformType {
UniformType::Bool
}
unsafe fn update(_: &mut Program, uniform: &'a Uniform<Arr<bool, N>>, value: Self::Target) {
BOOL_CACHE.clear();
BOOL_CACHE.extend(value.iter().map(|x| *x as u32));
gl::Uniform1uiv(uniform.index(), N as GLsizei, BOOL_CACHE.as_ptr() as _);
}
}
unsafe impl<'a, const N: usize> Uniformable<'a, Arr<Vec2<bool>, N>> for GL33 {
type Target = &'a [Vec2<bool>; N];
const SIZE: usize = N;
unsafe fn ty() -> UniformType {
UniformType::BVec2
}
unsafe fn update(_: &mut Program, uniform: &'a Uniform<Arr<Vec2<bool>, N>>, value: Self::Target) {
BOOL_CACHE.clear();
BOOL_CACHE.extend(value.iter().flat_map(|x| [x[0] as u32, x[1] as u32]));
gl::Uniform2uiv(uniform.index(), N as GLsizei, BOOL_CACHE.as_ptr() as _);
}
}
unsafe impl<'a, const N: usize> Uniformable<'a, Arr<Vec3<bool>, N>> for GL33 {
type Target = &'a [Vec3<bool>; N];
const SIZE: usize = N;
unsafe fn ty() -> UniformType {
UniformType::BVec3
}
unsafe fn update(_: &mut Program, uniform: &'a Uniform<Arr<Vec3<bool>, N>>, value: Self::Target) {
BOOL_CACHE.clear();
BOOL_CACHE.extend(
value
.iter()
.flat_map(|x| [x[0] as u32, x[1] as u32, x[2] as u32]),
);
gl::Uniform3uiv(uniform.index(), N as GLsizei, BOOL_CACHE.as_ptr() as _);
}
}
unsafe impl<'a, const N: usize> Uniformable<'a, Arr<Vec4<bool>, N>> for GL33 {
type Target = &'a [Vec4<bool>; N];
const SIZE: usize = N;
unsafe fn ty() -> UniformType {
UniformType::BVec4
}
unsafe fn update(_: &mut Program, uniform: &'a Uniform<Arr<Vec4<bool>, N>>, value: Self::Target) {
BOOL_CACHE.clear();
BOOL_CACHE.extend(
value
.iter()
.flat_map(|x| [x[0] as u32, x[1] as u32, x[2] as u32, x[3] as u32]),
);
gl::Uniform4uiv(uniform.index(), N as GLsizei, BOOL_CACHE.as_ptr() as _);
}
}
unsafe impl<'a, T> Uniformable<'a, ShaderDataBinding<T>> for GL33
where
T: 'a,
{
type Target = ShaderDataBinding<T>;
const SIZE: usize = 0;
unsafe fn ty() -> UniformType {
UniformType::ShaderDataBinding
}
unsafe fn update(
program: &mut Program,
uniform: &'a Uniform<ShaderDataBinding<T>>,
value: Self::Target,
) {
gl::UniformBlockBinding(
program.handle,
uniform.index() as GLuint,
value.binding() as GLuint,
)
}
}
unsafe impl<'a, D, S> Uniformable<'a, TextureBinding<D, S>> for GL33
where
D: 'a + Dimensionable,
S: 'a + SamplerType,
{
type Target = TextureBinding<D, S>;
const SIZE: usize = 0;
unsafe fn ty() -> UniformType {
match (S::sample_type(), D::dim()) {
(PixelType::NormIntegral, Dim::Dim1) => UniformType::Sampler1D,
(PixelType::NormUnsigned, Dim::Dim1) => UniformType::Sampler1D,
(PixelType::Integral, Dim::Dim1) => UniformType::ISampler1D,
(PixelType::Unsigned, Dim::Dim1) => UniformType::UISampler1D,
(PixelType::Floating, Dim::Dim1) => UniformType::Sampler1D,
(PixelType::NormIntegral, Dim::Dim2) => UniformType::Sampler2D,
(PixelType::NormUnsigned, Dim::Dim2) => UniformType::Sampler2D,
(PixelType::Integral, Dim::Dim2) => UniformType::ISampler2D,
(PixelType::Unsigned, Dim::Dim2) => UniformType::UISampler2D,
(PixelType::Floating, Dim::Dim2) => UniformType::Sampler2D,
(PixelType::NormIntegral, Dim::Dim3) => UniformType::Sampler3D,
(PixelType::NormUnsigned, Dim::Dim3) => UniformType::Sampler3D,
(PixelType::Integral, Dim::Dim3) => UniformType::ISampler3D,
(PixelType::Unsigned, Dim::Dim3) => UniformType::UISampler3D,
(PixelType::Floating, Dim::Dim3) => UniformType::Sampler3D,
(PixelType::NormIntegral, Dim::Cubemap) => UniformType::Cubemap,
(PixelType::NormUnsigned, Dim::Cubemap) => UniformType::Cubemap,
(PixelType::Integral, Dim::Cubemap) => UniformType::ICubemap,
(PixelType::Unsigned, Dim::Cubemap) => UniformType::UICubemap,
(PixelType::Floating, Dim::Cubemap) => UniformType::Cubemap,
(PixelType::NormIntegral, Dim::Dim1Array) => UniformType::Sampler1DArray,
(PixelType::NormUnsigned, Dim::Dim1Array) => UniformType::Sampler1DArray,
(PixelType::Integral, Dim::Dim1Array) => UniformType::ISampler1DArray,
(PixelType::Unsigned, Dim::Dim1Array) => UniformType::UISampler1DArray,
(PixelType::Floating, Dim::Dim1Array) => UniformType::Sampler1DArray,
(PixelType::NormIntegral, Dim::Dim2Array) => UniformType::Sampler2DArray,
(PixelType::NormUnsigned, Dim::Dim2Array) => UniformType::Sampler2DArray,
(PixelType::Integral, Dim::Dim2Array) => UniformType::ISampler2DArray,
(PixelType::Unsigned, Dim::Dim2Array) => UniformType::UISampler2DArray,
(PixelType::Floating, Dim::Dim2Array) => UniformType::Sampler2DArray,
}
}
unsafe fn update(
_: &mut Program,
uniform: &'a Uniform<TextureBinding<D, S>>,
value: Self::Target,
) {
gl::Uniform1i(uniform.index(), value.binding() as GLint)
}
}
unsafe impl<T> ShaderData<T> for GL33
where
T: Std140,
{
type ShaderDataRepr = Buffer<<ArrElem<T> as Std140>::Encoded>;
unsafe fn new_shader_data(
&mut self,
values: impl Iterator<Item = T>,
) -> Result<Self::ShaderDataRepr, ShaderDataError> {
Ok(Buffer::from_vec(
self,
values
.into_iter()
.map(|x| ArrElem(x).std140_encode())
.collect(),
))
}
unsafe fn get_shader_data_at(
shader_data: &Self::ShaderDataRepr,
i: usize,
) -> Result<T, ShaderDataError> {
shader_data
.buf
.get(i)
.map(|&x| <ArrElem<T> as Std140>::std140_decode(x).0)
.ok_or_else(|| ShaderDataError::OutOfBounds { index: i })
}
unsafe fn set_shader_data_at(
shader_data: &mut Self::ShaderDataRepr,
i: usize,
x: T,
) -> Result<T, ShaderDataError> {
let prev = mem::replace(
&mut shader_data
.slice_buffer_mut()
.map_err(|_| ShaderDataError::CannotSetData { index: i })?[i],
ArrElem(x).std140_encode(),
);
Ok(<ArrElem<T> as Std140>::std140_decode(prev).0)
}
unsafe fn set_shader_data_values(
shader_data: &mut Self::ShaderDataRepr,
values: impl Iterator<Item = T>,
) -> Result<(), ShaderDataError> {
let mut slice = shader_data
.slice_buffer_mut()
.map_err(|_| ShaderDataError::CannotReplaceData)?;
for (item, value) in slice.iter_mut().zip(values) {
*item = ArrElem(value).std140_encode();
}
Ok(())
}
}