use gl;
use gl::types::*;
use std::error::Error;
use std::ffi::CString;
use std::fmt;
use std::marker::PhantomData;
use std::ops::Deref;
use std::ptr::null_mut;
use linear::{M22, M33, M44};
use shader::stage::{self, Stage, StageError};
use vertex::Vertex;
#[derive(Debug)]
pub struct RawProgram {
handle: GLuint
}
impl RawProgram {
fn new<'a, T, G>(tess: T,
vertex: &Stage,
geometry: G,
fragment: &Stage)
-> Result<Self, ProgramError>
where T: Into<Option<(&'a Stage, &'a Stage)>>,
G: Into<Option<&'a Stage>> {
unsafe {
let handle = gl::CreateProgram();
if let Some((tcs, tes)) = tess.into() {
gl::AttachShader(handle, tcs.handle());
gl::AttachShader(handle, tes.handle());
}
gl::AttachShader(handle, vertex.handle());
if let Some(geometry) = geometry.into() {
gl::AttachShader(handle, geometry.handle());
}
gl::AttachShader(handle, fragment.handle());
gl::LinkProgram(handle);
let mut linked: GLint = gl::FALSE as GLint;
gl::GetProgramiv(handle, gl::LINK_STATUS, &mut linked);
if linked == (gl::TRUE as GLint) {
Ok(RawProgram { handle: handle })
} 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);
gl::DeleteProgram(handle);
log.set_len(log_len as usize);
Err(ProgramError::LinkFailed(String::from_utf8(log).unwrap()))
}
}
}
#[inline]
pub(crate) fn handle(&self) -> GLuint {
self.handle
}
}
impl Drop for RawProgram {
fn drop(&mut self) {
unsafe { gl::DeleteProgram(self.handle) }
}
}
pub struct Program<In, Out, Uni> {
raw: RawProgram,
uni_iface: Uni,
_in: PhantomData<*const In>,
_out: PhantomData<*const Out>
}
impl<In, Out, Uni> Program<In, Out, Uni> where In: Vertex, Uni: UniformInterface {
pub fn from_stages<'a, T, G>(
tess: T,
vertex: &Stage,
geometry: G,
fragment: &Stage)
-> Result<(Self, Vec<UniformWarning>), ProgramError>
where T: Into<Option<(&'a Stage, &'a Stage)>>,
G: Into<Option<&'a Stage>> {
let raw = RawProgram::new(tess, vertex, geometry, fragment)?;
let (iface, warnings) = Uni::uniform_interface(UniformBuilder::new(&raw))?;
let program = Program {
raw: raw,
uni_iface: iface,
_in: PhantomData,
_out: PhantomData
};
Ok((program, warnings))
}
pub fn from_strings<'a, T, G>(
tess: T,
vertex: &str,
geometry: G,
fragment: &str)
-> Result<(Self, Vec<UniformWarning>), ProgramError>
where T: Into<Option<(&'a str, &'a str)>>,
G: Into<Option<&'a str>> {
let tess = match tess.into() {
Some((tcs_str, tes_str)) => {
let tcs = Stage::new(stage::Type::TessellationControlShader, tcs_str).map_err(ProgramError::StageError)?;
let tes = Stage::new(stage::Type::TessellationControlShader, tes_str).map_err(ProgramError::StageError)?;
Some((tcs, tes))
},
None => None
};
let gs = match geometry.into() {
Some(gs_str) => Some(Stage::new(stage::Type::GeometryShader, gs_str).map_err(ProgramError::StageError)?),
None => None
};
let vs = Stage::new(stage::Type::VertexShader, vertex).map_err(ProgramError::StageError)?;
let fs = Stage::new(stage::Type::FragmentShader, fragment).map_err(ProgramError::StageError)?;
Self::from_stages(tess.as_ref().map(|&(ref tcs, ref tes)| (tcs, tes)), &vs, gs.as_ref(), &fs)
}
pub(crate) fn uniform_interface(&self) -> &Uni {
&self.uni_iface
}
}
impl<In, Out, Uni> Deref for Program<In, Out, Uni> {
type Target = RawProgram;
fn deref(&self) -> &Self::Target {
&self.raw
}
}
pub trait UniformInterface: Sized {
fn uniform_interface<'a>(
builder: UniformBuilder<'a>
) -> Result<(Self, Vec<UniformWarning>), ProgramError>;
}
impl UniformInterface for () {
fn uniform_interface<'a>(
_: UniformBuilder<'a>
) -> Result<(Self, Vec<UniformWarning>), ProgramError> {
Ok(((), Vec::new()))
}
}
pub struct UniformBuilder<'a> {
raw: &'a RawProgram
}
impl<'a> UniformBuilder<'a> {
fn new(raw: &'a RawProgram) -> Self {
UniformBuilder {
raw: raw
}
}
pub fn ask<T>(&self, name: &str) -> Result<Uniform<T>, UniformWarning> where T: Uniformable {
let uniform = match T::ty() {
Type::BufferBinding => self.ask_uniform_block(name)?,
_ => self.ask_uniform(name)?
};
uniform_type_match(self.raw.handle, name, T::ty(), T::dim()).map_err(|err| UniformWarning::TypeMismatch(name.to_owned(), err))?;
Ok(uniform)
}
fn ask_uniform<T>(&self, name: &str) -> Result<Uniform<T>, UniformWarning> where T: Uniformable {
let c_name = CString::new(name.as_bytes()).unwrap();
let location = unsafe { gl::GetUniformLocation(self.raw.handle, c_name.as_ptr() as *const GLchar) };
if location < 0 {
Err(UniformWarning::Inactive(name.to_owned()))
} else {
Ok(Uniform::new(self.raw.handle, location))
}
}
fn ask_uniform_block<T>(&self, name: &str) -> Result<Uniform<T>, UniformWarning> where T: Uniformable {
let c_name = CString::new(name.as_bytes()).unwrap();
let location = unsafe { gl::GetUniformBlockIndex(self.raw.handle, c_name.as_ptr() as *const GLchar) };
if location == gl::INVALID_INDEX {
Err(UniformWarning::Inactive(name.to_owned()))
} else {
Ok(Uniform::new(self.raw.handle, location as GLint))
}
}
pub fn unbound<T>(&self) -> Uniform<T> where T: Uniformable {
Uniform::unbound(self.raw.handle)
}
}
#[derive(Clone, Debug)]
pub enum ProgramError {
StageError(StageError),
LinkFailed(String),
UniformWarning(UniformWarning)
}
impl fmt::Display for ProgramError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
ProgramError::StageError(ref e) => {
write!(f, "shader program has stage error: {}", e)
}
ProgramError::LinkFailed(ref s) => {
write!(f, "shader program failed to link: {}", s)
}
ProgramError::UniformWarning(ref e) => {
write!(f, "shader program contains warning(s): {}", e)
}
}
}
}
impl Error for ProgramError {
fn cause(&self) -> Option<&Error> {
match *self {
ProgramError::StageError(ref e) => Some(e),
ProgramError::UniformWarning(ref e) => Some(e),
_ => None
}
}
}
#[derive(Clone, Debug)]
pub enum UniformWarning {
Inactive(String),
TypeMismatch(String, String)
}
impl fmt::Display for UniformWarning {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
UniformWarning::Inactive(ref s) => {
write!(f, "inactive {} uniform", s)
}
UniformWarning::TypeMismatch(ref n, ref t) => {
write!(f, "type mismatch for uniform {}: {}", n, t)
}
}
}
}
impl Error for UniformWarning {}
#[derive(Debug)]
pub struct Uniform<T> {
program: GLuint,
index: GLint,
_t: PhantomData<*const T>
}
impl<T> Uniform<T> where T: Uniformable {
fn new(program: GLuint, index: GLint) -> Self {
Uniform {
program: program,
index: index,
_t: PhantomData
}
}
fn unbound(program: GLuint) -> Self {
Uniform {
program: program,
index: -1,
_t: PhantomData
}
}
pub(crate) fn program(&self) -> GLuint {
self.program
}
pub(crate) fn index(&self) -> GLint {
self.index
}
pub fn update(&self, x: T) {
x.update(self);
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Type {
Integral,
Unsigned,
Floating,
Boolean,
TextureUnit,
BufferBinding
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Dim {
Dim1,
Dim2,
Dim3,
Dim4,
Dim22,
Dim33,
Dim44,
Cubemap
}
pub unsafe trait Uniformable: Sized {
fn update(self, u: &Uniform<Self>);
fn ty() -> Type;
fn dim() -> Dim;
}
unsafe impl Uniformable for i32 {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform1i(u.index, self) }
}
fn ty() -> Type { Type::Integral }
fn dim() -> Dim { Dim::Dim1 }
}
unsafe impl Uniformable for [i32; 2] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform2iv(u.index, 1, &self as *const i32) }
}
fn ty() -> Type { Type::Integral }
fn dim() -> Dim { Dim::Dim2 }
}
unsafe impl Uniformable for [i32; 3] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform3iv(u.index, 1, &self as *const i32) }
}
fn ty() -> Type { Type::Integral }
fn dim() -> Dim { Dim::Dim3 }
}
unsafe impl Uniformable for [i32; 4] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform4iv(u.index, 1, &self as *const i32) }
}
fn ty() -> Type { Type::Integral }
fn dim() -> Dim { Dim::Dim4 }
}
unsafe impl<'a> Uniformable for &'a [i32] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform1iv(u.index, self.len() as GLsizei, self.as_ptr()) }
}
fn ty() -> Type { Type::Integral }
fn dim() -> Dim { Dim::Dim1 }
}
unsafe impl<'a> Uniformable for &'a [[i32; 2]] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform2iv(u.index, self.len() as GLsizei, self.as_ptr() as *const i32) }
}
fn ty() -> Type { Type::Integral }
fn dim() -> Dim { Dim::Dim2 }
}
unsafe impl<'a> Uniformable for &'a [[i32; 3]] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform3iv(u.index, self.len() as GLsizei, self.as_ptr() as *const i32) }
}
fn ty() -> Type { Type::Integral }
fn dim() -> Dim { Dim::Dim3 }
}
unsafe impl<'a> Uniformable for &'a [[i32; 4]] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform4iv(u.index, self.len() as GLsizei, self.as_ptr() as *const i32) }
}
fn ty() -> Type { Type::Integral }
fn dim() -> Dim { Dim::Dim4 }
}
unsafe impl Uniformable for u32 {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform1ui(u.index, self) }
}
fn ty() -> Type { Type::Unsigned }
fn dim() -> Dim { Dim::Dim1 }
}
unsafe impl Uniformable for [u32; 2] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform2uiv(u.index, 1, &self as *const u32) }
}
fn ty() -> Type { Type::Unsigned }
fn dim() -> Dim { Dim::Dim2 }
}
unsafe impl Uniformable for [u32; 3] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform3uiv(u.index, 1, &self as *const u32) }
}
fn ty() -> Type { Type::Unsigned }
fn dim() -> Dim { Dim::Dim3 }
}
unsafe impl Uniformable for [u32; 4] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform4uiv(u.index, 1, &self as *const u32) }
}
fn ty() -> Type { Type::Unsigned }
fn dim() -> Dim { Dim::Dim4 }
}
unsafe impl<'a> Uniformable for &'a [u32] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform1uiv(u.index, self.len() as GLsizei, self.as_ptr() as *const u32) }
}
fn ty() -> Type { Type::Unsigned }
fn dim() -> Dim { Dim::Dim1 }
}
unsafe impl<'a> Uniformable for &'a [[u32; 2]] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform2uiv(u.index, self.len() as GLsizei, self.as_ptr() as *const u32) }
}
fn ty() -> Type { Type::Unsigned }
fn dim() -> Dim { Dim::Dim2 }
}
unsafe impl<'a> Uniformable for &'a [[u32; 3]] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform3uiv(u.index, self.len() as GLsizei, self.as_ptr() as *const u32) }
}
fn ty() -> Type { Type::Unsigned }
fn dim() -> Dim { Dim::Dim3 }
}
unsafe impl<'a> Uniformable for &'a [[u32; 4]] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform4uiv(u.index, self.len() as GLsizei, self.as_ptr() as *const u32) }
}
fn ty() -> Type { Type::Unsigned }
fn dim() -> Dim { Dim::Dim4 }
}
unsafe impl Uniformable for f32 {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform1f(u.index, self) }
}
fn ty() -> Type { Type::Floating }
fn dim() -> Dim { Dim::Dim1 }
}
unsafe impl Uniformable for [f32; 2] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform2fv(u.index, 1, &self as *const f32) }
}
fn ty() -> Type { Type::Floating }
fn dim() -> Dim { Dim::Dim2 }
}
unsafe impl Uniformable for [f32; 3] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform3fv(u.index, 1, &self as *const f32) }
}
fn ty() -> Type { Type::Floating }
fn dim() -> Dim { Dim::Dim3 }
}
unsafe impl Uniformable for [f32; 4] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform4fv(u.index, 1, &self as *const f32) }
}
fn ty() -> Type { Type::Floating }
fn dim() -> Dim { Dim::Dim4 }
}
unsafe impl<'a> Uniformable for &'a [f32] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform1fv(u.index, self.len() as GLsizei, self.as_ptr() as *const f32) }
}
fn ty() -> Type { Type::Floating }
fn dim() -> Dim { Dim::Dim1 }
}
unsafe impl<'a> Uniformable for &'a [[f32; 2]] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform2fv(u.index, self.len() as GLsizei, self.as_ptr() as *const f32) }
}
fn ty() -> Type { Type::Floating }
fn dim() -> Dim { Dim::Dim2 }
}
unsafe impl<'a> Uniformable for &'a [[f32; 3]] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform3fv(u.index, self.len() as GLsizei, self.as_ptr() as *const f32) }
}
fn ty() -> Type { Type::Floating }
fn dim() -> Dim { Dim::Dim3 }
}
unsafe impl<'a> Uniformable for &'a [[f32; 4]] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform4fv(u.index, self.len() as GLsizei, self.as_ptr() as *const f32) }
}
fn ty() -> Type { Type::Floating }
fn dim() -> Dim { Dim::Dim4 }
}
unsafe impl Uniformable for M22 {
fn update(self, u: &Uniform<Self>) {
let v = [self];
unsafe { gl::UniformMatrix2fv(u.index, 1, gl::FALSE, v.as_ptr() as *const f32) }
}
fn ty() -> Type { Type::Floating }
fn dim() -> Dim { Dim::Dim22 }
}
unsafe impl Uniformable for M33 {
fn update(self, u: &Uniform<Self>) {
let v = [self];
unsafe { gl::UniformMatrix3fv(u.index, 1, gl::FALSE, v.as_ptr() as *const f32) }
}
fn ty() -> Type { Type::Floating }
fn dim() -> Dim { Dim::Dim33 }
}
unsafe impl Uniformable for M44 {
fn update(self, u: &Uniform<Self>) {
let v = [self];
unsafe { gl::UniformMatrix4fv(u.index, 1, gl::FALSE, v.as_ptr() as *const f32) }
}
fn ty() -> Type { Type::Floating }
fn dim() -> Dim { Dim::Dim44 }
}
unsafe impl<'a> Uniformable for &'a [M22] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::UniformMatrix2fv(u.index, self.len() as GLsizei, gl::FALSE, self.as_ptr() as *const f32) }
}
fn ty() -> Type { Type::Floating }
fn dim() -> Dim { Dim::Dim22 }
}
unsafe impl<'a> Uniformable for &'a [M33] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::UniformMatrix3fv(u.index, self.len() as GLsizei, gl::FALSE, self.as_ptr() as *const f32) }
}
fn ty() -> Type { Type::Floating }
fn dim() -> Dim { Dim::Dim33 }
}
unsafe impl<'a> Uniformable for &'a [M44] {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::UniformMatrix4fv(u.index, self.len() as GLsizei, gl::FALSE, self.as_ptr() as *const f32) }
}
fn ty() -> Type { Type::Floating }
fn dim() -> Dim { Dim::Dim44 }
}
unsafe impl Uniformable for bool {
fn update(self, u: &Uniform<Self>) {
unsafe { gl::Uniform1ui(u.index, self as GLuint) }
}
fn ty() -> Type { Type::Boolean }
fn dim() -> Dim { Dim::Dim1 }
}
unsafe impl Uniformable for [bool; 2] {
fn update(self, u: &Uniform<Self>) {
let v = [self[0] as u32, self[1] as u32];
unsafe { gl::Uniform2uiv(u.index, 1, &v as *const u32) }
}
fn ty() -> Type { Type::Boolean }
fn dim() -> Dim { Dim::Dim2 }
}
unsafe impl Uniformable for [bool; 3] {
fn update(self, u: &Uniform<Self>) {
let v = [self[0] as u32, self[1] as u32, self[2] as u32];
unsafe { gl::Uniform3uiv(u.index, 1, &v as *const u32) }
}
fn ty() -> Type { Type::Boolean }
fn dim() -> Dim { Dim::Dim3 }
}
unsafe impl Uniformable for [bool; 4] {
fn update(self, u: &Uniform<Self>) {
let v = [self[0] as u32, self[1] as u32, self[2] as u32, self[3] as u32];
unsafe { gl::Uniform4uiv(u.index, 1, &v as *const u32) }
}
fn ty() -> Type { Type::Boolean }
fn dim() -> Dim { Dim::Dim4 }
}
unsafe impl<'a> Uniformable for &'a [bool] {
fn update(self, u: &Uniform<Self>) {
let v: Vec<_> = self.iter().map(|x| *x as u32).collect();
unsafe { gl::Uniform1uiv(u.index, v.len() as GLsizei, v.as_ptr()) }
}
fn ty() -> Type { Type::Boolean }
fn dim() -> Dim { Dim::Dim1 }
}
unsafe impl<'a> Uniformable for &'a [[bool; 2]] {
fn update(self, u: &Uniform<Self>) {
let v: Vec<_> = self.iter().map(|x| [x[0] as u32, x[1] as u32]).collect();
unsafe { gl::Uniform2uiv(u.index, v.len() as GLsizei, v.as_ptr() as *const u32) }
}
fn ty() -> Type { Type::Boolean }
fn dim() -> Dim { Dim::Dim2 }
}
unsafe impl<'a> Uniformable for &'a [[bool; 3]] {
fn update(self, u: &Uniform<Self>) {
let v: Vec<_> = self.iter().map(|x| [x[0] as u32, x[1] as u32, x[2] as u32]).collect();
unsafe { gl::Uniform3uiv(u.index, v.len() as GLsizei, v.as_ptr() as *const u32) }
}
fn ty() -> Type { Type::Boolean }
fn dim() -> Dim { Dim::Dim3 }
}
unsafe impl<'a> Uniformable for &'a [[bool; 4]] {
fn update(self, u: &Uniform<Self>) {
let v: Vec<_> = self.iter().map(|x| [x[0] as u32, x[1] as u32, x[2] as u32, x[3] as u32]).collect();
unsafe { gl::Uniform4uiv(u.index, v.len() as GLsizei, v.as_ptr() as *const u32) }
}
fn ty() -> Type { Type::Boolean }
fn dim() -> Dim { Dim::Dim4 }
}
fn uniform_type_match(program: GLuint, name: &str, ty: Type, dim: Dim) -> Result<(), String> {
let mut size: GLint = 0;
let mut typ: GLuint = 0;
let c_name = CString::new(name.as_bytes()).unwrap();
unsafe {
let mut max_len = 0;
gl::GetProgramiv(program, gl::ACTIVE_UNIFORM_MAX_LENGTH, &mut max_len);
let mut index = 0;
let mut name_ = Vec::<i8>::with_capacity(max_len as usize);
gl::GetUniformIndices(program, 1, [c_name.as_ptr() as *const i8].as_ptr(), &mut index);
gl::GetActiveUniform(program, index, max_len, null_mut(), &mut size, &mut typ, name_.as_mut_ptr());
}
if size != 1 {
return Ok(());
}
match (ty, dim) {
(Type::Integral, Dim::Dim1) if typ != gl::INT => Err("requested int doesn't match".to_owned()),
(Type::Integral, Dim::Dim2) if typ != gl::INT_VEC2 => Err("requested ivec2 doesn't match".to_owned()),
(Type::Integral, Dim::Dim3) if typ != gl::INT_VEC3 => Err("requested ivec3 doesn't match".to_owned()),
(Type::Integral, Dim::Dim4) if typ != gl::INT_VEC4 => Err("requested ivec4 doesn't match".to_owned()),
(Type::Unsigned, Dim::Dim1) if typ != gl::UNSIGNED_INT => Err("requested uint doesn't match".to_owned()),
(Type::Unsigned, Dim::Dim2) if typ != gl::UNSIGNED_INT_VEC2 => Err("requested uvec2 doesn't match".to_owned()),
(Type::Unsigned, Dim::Dim3) if typ != gl::UNSIGNED_INT_VEC3 => Err("requested uvec3 doesn't match".to_owned()),
(Type::Unsigned, Dim::Dim4) if typ != gl::UNSIGNED_INT_VEC4 => Err("requested uvec4 doesn't match".to_owned()),
(Type::Floating, Dim::Dim1) if typ != gl::FLOAT => Err("requested float doesn't match".to_owned()),
(Type::Floating, Dim::Dim2) if typ != gl::FLOAT_VEC2 => Err("requested vec2 doesn't match".to_owned()),
(Type::Floating, Dim::Dim3) if typ != gl::FLOAT_VEC3 => Err("requested vec3 doesn't match".to_owned()),
(Type::Floating, Dim::Dim4) if typ != gl::FLOAT_VEC4 => Err("requested vec4 doesn't match".to_owned()),
(Type::Floating, Dim::Dim22) if typ != gl::FLOAT_MAT2 => Err("requested mat2 doesn't match".to_owned()),
(Type::Floating, Dim::Dim33) if typ != gl::FLOAT_MAT3 => Err("requested mat3 doesn't match".to_owned()),
(Type::Floating, Dim::Dim44) if typ != gl::FLOAT_MAT4 => Err("requested mat4 doesn't match".to_owned()),
(Type::Boolean, Dim::Dim1) if typ != gl::BOOL => Err("requested bool doesn't match".to_owned()),
(Type::Boolean, Dim::Dim2) if typ != gl::BOOL_VEC2 => Err("requested bvec2 doesn't match".to_owned()),
(Type::Boolean, Dim::Dim3) if typ != gl::BOOL_VEC3 => Err("requested bvec3 doesn't match".to_owned()),
(Type::Boolean, Dim::Dim4) if typ != gl::BOOL_VEC4 => Err("requested bvec4 doesn't match".to_owned()),
_ => Ok(())
}
}
#[macro_export]
macro_rules! uniform_interface {
(struct $struct_name:ident { $($fields:tt)* }) => {
uniform_interface_build_struct!([], $struct_name, $($fields)*);
uniform_interface_impl_trait!($struct_name, $($fields)*);
};
(pub struct $struct_name:ident { $($fields:tt)* }) => {
uniform_interface_build_struct!([pub], $struct_name, $($fields)*);
uniform_interface_impl_trait!($struct_name, $($fields)*);
};
(pub($visibility:tt) struct $struct_name:ident { $($fields:tt)* }) => {
uniform_interface_build_struct!([pub($visibility)], $struct_name, $($fields)*);
uniform_interface_impl_trait!($struct_name, $($fields)*);
};
}
#[macro_export]
macro_rules! uniform_interface_build_struct {
([$($visibility:tt)*], $struct_name:ident, $($(#[$($field_attrs:tt)*])* $field_name:ident : $field_ty:ty),+) => {
$($visibility)* struct $struct_name {
$(
$field_name: $crate::shader::program::Uniform<$field_ty>
),+
}
}
}
#[macro_export]
macro_rules! uniform_interface_impl_trait {
($struct_name:ident, $($(#[$($field_attrs:tt)*])* $field_name:ident : $field_ty:ty),+) => {
impl $crate::shader::program::UniformInterface for $struct_name {
fn uniform_interface(
builder: $crate::shader::program::UniformBuilder
) -> Result<(Self, Vec<$crate::shader::program::UniformWarning>), $crate::shader::program::ProgramError> {
#[allow(unused_mut)]
let mut warnings = Vec::new();
$(
uniform_interface_impl_trait_map!(builder, warnings, $field_name $(#[$($field_attrs)*])*);
)+
let iface = $struct_name { $($field_name),+ };
Ok((iface, warnings))
}
}
}
}
#[macro_export]
macro_rules! uniform_interface_impl_trait_map {
($builder:ident, $warnings:ident, $field_name:ident #[as($field_mapping:expr), unbound]) => {
let $field_name = $builder.ask($field_mapping).unwrap_or_else(|warning| {
$warnings.push(warning);
$builder.unbound()
});
};
($builder:ident, $warnings:ident, $field_name:ident #[unbound, as($field_mapping:expr)]) => {
let $field_name = $builder.ask($field_mapping).unwrap_or_else(|warning| {
$warnings.push(warning);
$builder.unbound()
});
};
($builder:ident, $warnings:ident, $field_name:ident #[as($field_mapping:expr)]) => {
let $field_name = $builder.ask($field_mapping).map_err($crate::shader::program::ProgramError::UniformWarning)?;
};
($builder:ident, $warnings:ident, $field_name:ident #[unbound]) => {
let $field_name = $builder.ask(stringify!($field_name)).unwrap_or_else(|warning| {
$warnings.push(warning);
$builder.unbound()
});
};
($builder:ident, $warnings:ident, $field_name:ident) => {
let $field_name = $builder.ask(stringify!($field_name)).map_err($crate::shader::program::ProgramError::UniformWarning)?;
}
}