use std::cell::Cell;
use device::shade;
use device::shade::UniformValue;
use device::{RawBufferHandle, TextureHandle, SamplerHandle};
pub use device::shade::{Stage, CreateShaderError};
pub trait ToUniform {
fn to_uniform(&self) -> shade::UniformValue;
}
macro_rules! impl_ToUniform(
($srcty:ty, $dstty:expr) => (
impl ToUniform for $srcty {
fn to_uniform(&self) -> shade::UniformValue {
$dstty(*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 = (TextureHandle, Option<SamplerHandle>);
pub struct ParamValues<'a> {
pub uniforms: &'a mut Vec<UniformValue>,
pub blocks : &'a mut Vec<RawBufferHandle>,
pub textures: &'a mut Vec<TextureParam>,
}
#[derive(Clone, PartialEq, Debug)]
pub enum ParameterError {
ParameterGeneralMismatch,
MissingUniform(String),
MissingBlock(String),
MissingTexture(String),
}
pub trait ShaderParam {
type Link;
fn create_link(Option<&Self>, &shade::ProgramInfo) -> Result<Self::Link, ParameterError>;
fn fill_params(&self, &Self::Link, ParamValues);
}
impl ShaderParam for () {
type Link = ();
fn create_link(_: Option<&()>, 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, _: &(), _: ParamValues) {
}
}
pub struct NamedCell<T> {
pub name: String,
pub value: Cell<T>,
}
pub struct ParamDictionary {
pub uniforms: Vec<NamedCell<shade::UniformValue>>,
pub blocks: Vec<NamedCell<RawBufferHandle>>,
pub textures: Vec<NamedCell<TextureParam>>,
}
pub struct ParamDictionaryLink {
uniforms: Vec<usize>,
blocks: Vec<usize>,
textures: Vec<usize>,
}
impl ShaderParam for ParamDictionary {
type Link = ParamDictionaryLink;
fn create_link(this: Option<&ParamDictionary>, 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: ParamValues) {
for &id in link.uniforms.iter() {
params.uniforms.push(self.uniforms[id].value.get());
}
for &id in link.blocks.iter() {
params.blocks.push(self.blocks[id].value.get());
}
for &id in link.textures.iter() {
params.textures.push(self.textures[id].value.get());
}
}
}