use std::cell::RefCell;
use device::shade;
use device::shade::UniformValue;
use device::{handle, Resources};
use super::ParamStorage;
pub use device::shade::{Stage, CreateShaderError};
pub trait ToUniform {
fn to_uniform(&self) -> shade::UniformValue;
}
macro_rules! impl_ToUniform{
($ty_src:ty, $ty_dst:expr) => {
impl ToUniform for $ty_src {
fn to_uniform(&self) -> shade::UniformValue {
$ty_dst(*self)
}
}
}
}
impl_ToUniform!(i32, UniformValue::I32);
impl_ToUniform!(f32, UniformValue::F32);
impl_ToUniform!([i32; 2], UniformValue::I32Vector2);
impl_ToUniform!([i32; 3], UniformValue::I32Vector3);
impl_ToUniform!([i32; 4], UniformValue::I32Vector4);
impl_ToUniform!([f32; 2], UniformValue::F32Vector2);
impl_ToUniform!([f32; 3], UniformValue::F32Vector3);
impl_ToUniform!([f32; 4], UniformValue::F32Vector4);
impl_ToUniform!([[f32; 2]; 2], UniformValue::F32Matrix2);
impl_ToUniform!([[f32; 3]; 3], UniformValue::F32Matrix3);
impl_ToUniform!([[f32; 4]; 4], UniformValue::F32Matrix4);
pub type VarUniform = u16;
pub type VarBlock = u8;
pub type VarTexture = u8;
pub type TextureParam<R: Resources> = (handle::Texture<R>, Option<handle::Sampler<R>>);
#[derive(Clone, PartialEq, Debug)]
pub enum ParameterError {
ParameterGeneralMismatch,
MissingUniform(String),
MissingBlock(String),
MissingTexture(String),
}
#[allow(missing_docs)]
pub trait ShaderParam {
type Resources: Resources;
type Link;
fn create_link(Option<&Self>, &shade::ProgramInfo) -> Result<Self::Link, ParameterError>;
fn fill_params(&self, &Self::Link, &mut ParamStorage<Self::Resources>);
}
impl<R: Resources> ShaderParam for Option<R> {
type Resources = R;
type Link = ();
fn create_link(_: Option<&Option<R>>, info: &shade::ProgramInfo) -> Result<(), ParameterError> {
match info.uniforms[..].first() {
Some(u) => return Err(ParameterError::MissingUniform(u.name.clone())),
None => (),
}
match info.blocks[..].first() {
Some(b) => return Err(ParameterError::MissingBlock(b.name.clone())),
None => (),
}
match info.textures[..].first() {
Some(t) => return Err(ParameterError::MissingTexture(t.name.clone())),
None => (),
}
Ok(())
}
fn fill_params(&self, _: &(), _: &mut ParamStorage<R>) {
}
}
pub struct NamedCell<T> {
pub name: String,
pub value: RefCell<T>,
}
pub struct ParamDictionary<R: Resources> {
pub uniforms: Vec<NamedCell<shade::UniformValue>>,
pub blocks: Vec<NamedCell<handle::RawBuffer<R>>>,
pub textures: Vec<NamedCell<TextureParam<R>>>,
}
pub struct ParamDictionaryLink {
uniforms: Vec<usize>,
blocks: Vec<usize>,
textures: Vec<usize>,
}
impl<R: Resources> ShaderParam for ParamDictionary<R> {
type Resources = R;
type Link = ParamDictionaryLink;
fn create_link(this: Option<&ParamDictionary<R>>, info: &shade::ProgramInfo)
-> Result<ParamDictionaryLink, ParameterError> {
let this = match this {
Some(d) => d,
None => return Err(ParameterError::ParameterGeneralMismatch),
};
Ok(ParamDictionaryLink {
uniforms: info.uniforms.iter().map(|var|
this.uniforms.iter().position(|c| c.name == var.name).unwrap()
).collect(),
blocks: info.blocks.iter().map(|var|
this.blocks .iter().position(|c| c.name == var.name).unwrap()
).collect(),
textures: info.textures.iter().map(|var|
this.textures.iter().position(|c| c.name == var.name).unwrap()
).collect(),
})
}
fn fill_params(&self, link: &ParamDictionaryLink, params: &mut ParamStorage<R>) {
for &id in link.uniforms.iter() {
params.uniforms[id] = Some(self.uniforms[id].value.borrow().clone());
}
for &id in link.blocks.iter() {
params.blocks[id] = Some(self.blocks[id].value.borrow().clone());
}
for &id in link.textures.iter() {
params.textures[id] = Some(self.textures[id].value.borrow().clone());
}
}
}