use std::cell::Cell;
use device::shade;
use device::shade::UniformValue;
use device::{Resources, RawBufferHandle, TextureHandle, SamplerHandle};
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> = (TextureHandle<R>, Option<SamplerHandle<R>>);
pub struct ParamValues<'a, R: Resources> where
<R as Resources>::Buffer: 'a,
<R as Resources>::Sampler: 'a,
<R as Resources>::Texture: 'a,
{
pub uniforms: &'a mut Vec<UniformValue>,
pub blocks : &'a mut Vec<RawBufferHandle<R>>,
pub textures: &'a mut Vec<TextureParam<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, ParamValues<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, _: &(), _: ParamValues<R>) {
}
}
pub struct NamedCell<T> {
pub name: String,
pub value: Cell<T>,
}
pub struct ParamDictionary<R: Resources> {
pub uniforms: Vec<NamedCell<shade::UniformValue>>,
pub blocks: Vec<NamedCell<RawBufferHandle<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: ParamValues<R>) {
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());
}
}
}