use draw_state::DrawState;
use device::{Resources, PrimitiveType};
use device::handle::Program as ProgramHandle;
use render::mesh;
use render::mesh::ToSlice;
use shade::{ParameterError, ShaderParam};
use super::ParamStorage;
#[derive(Clone, Debug, PartialEq)]
pub enum Error {
Mesh(mesh::Error),
Parameters(ParameterError),
Other(String),
}
pub type BatchData<'a, R: Resources> = (&'a mesh::Mesh<R>, mesh::AttributeIter,
&'a mesh::Slice<R>, &'a DrawState);
pub trait Batch<R: Resources> {
fn get_data(&self) -> Result<BatchData<R>, Error>;
fn fill_params(&self, &mut ParamStorage<R>) -> Result<&ProgramHandle<R>, Error>;
}
pub type Implicit<'a, T: ShaderParam> = (
&'a mesh::Mesh<T::Resources>,
mesh::Slice<T::Resources>,
&'a ProgramHandle<T::Resources>,
&'a T,
&'a DrawState
);
pub fn bind<'a, T: ShaderParam>(draw_state: &'a DrawState,
mesh: &'a mesh::Mesh<T::Resources>,
slice: mesh::Slice<T::Resources>,
program: &'a ProgramHandle<T::Resources>,
data: &'a T) -> Implicit<'a, T> {
(mesh, slice, program, data, draw_state)
}
impl<'a, T: ShaderParam> Batch<T::Resources> for Implicit<'a, T> {
fn get_data(&self) -> Result<BatchData<T::Resources>, Error> {
let (mesh, ref slice, program, _, state) = *self;
match mesh::Link::new(mesh, program.get_info()) {
Ok(link) => Ok((mesh, link.to_iter(), &slice, state)),
Err(e) => Err(Error::Mesh(e)),
}
}
fn fill_params(&self, values: &mut ParamStorage<T::Resources>)
-> Result<&ProgramHandle<T::Resources>, Error> {
let (_, _, program, params, _) = *self;
match ShaderParam::create_link(None::<&T>, program.get_info()) {
Ok(link) => {
values.reserve(program.get_info());
params.fill_params(&link, values);
Ok(program)
},
Err(e) => return Err(Error::Parameters(e)),
}
}
}
#[derive(Clone)]
pub struct Full<T: ShaderParam> {
mesh: mesh::Mesh<T::Resources>,
mesh_link: mesh::Link,
pub slice: mesh::Slice<T::Resources>,
pub params: T,
program: ProgramHandle<T::Resources>,
param_link: T::Link,
pub state: DrawState,
}
impl<T: ShaderParam> Full<T> {
pub fn new(mesh: mesh::Mesh<T::Resources>, program: ProgramHandle<T::Resources>, params: T)
-> Result<Full<T>, Error> {
let slice = mesh.to_slice(PrimitiveType::TriangleList);
let mesh_link = match mesh::Link::new(&mesh, program.get_info()) {
Ok(l) => l,
Err(e) => return Err(Error::Mesh(e)),
};
let param_link = match ShaderParam::create_link(Some(¶ms), program.get_info()) {
Ok(l) => l,
Err(e) => return Err(Error::Parameters(e)),
};
Ok(Full {
mesh: mesh,
mesh_link: mesh_link,
slice: slice,
program: program,
params: params,
param_link: param_link,
state: DrawState::new(),
})
}
}
impl<T: ShaderParam> Batch<T::Resources> for Full<T> {
fn get_data(&self) -> Result<BatchData<T::Resources>, Error> {
Ok((&self.mesh, self.mesh_link.to_iter(), &self.slice, &self.state))
}
fn fill_params(&self, values: &mut ParamStorage<T::Resources>)
-> Result<&ProgramHandle<T::Resources>, Error> {
values.reserve(self.program.get_info());
self.params.fill_params(&self.param_link, values);
Ok(&self.program)
}
}
#[derive(Clone)]
pub struct Core<T: ShaderParam> {
mesh: mesh::Mesh<T::Resources>,
mesh_link: mesh::Link,
program: ProgramHandle<T::Resources>,
param_link: T::Link,
}
pub type Complete<'a, T: ShaderParam> = (
&'a Core<T>,
&'a mesh::Slice<T::Resources>,
&'a T,
&'a DrawState
);
impl<T: ShaderParam> Core<T> {
pub fn new(mesh: mesh::Mesh<T::Resources>, program: ProgramHandle<T::Resources>)
-> Result<Core<T>, Error> {
let mesh_link = match mesh::Link::new(&mesh, program.get_info()) {
Ok(l) => l,
Err(e) => return Err(Error::Mesh(e)),
};
let param_link = match ShaderParam::create_link(None::<&T>, program.get_info()) {
Ok(l) => l,
Err(e) => return Err(Error::Parameters(e)),
};
Ok(Core {
mesh: mesh,
mesh_link: mesh_link,
program: program,
param_link: param_link,
})
}
pub fn with<'a>(&'a self, slice: &'a mesh::Slice<T::Resources>,
params: &'a T, state: &'a DrawState)
-> Complete<'a, T> {
(self, slice, params, state)
}
pub fn program(&self) -> &ProgramHandle<T::Resources> {
&self.program
}
pub fn mesh(&self) -> &mesh::Mesh<T::Resources> {
&self.mesh
}
}
impl<'a, T: ShaderParam + 'a> Batch<T::Resources> for Complete<'a, T> {
fn get_data(&self) -> Result<BatchData<T::Resources>, Error> {
let (b, slice, _, state) = *self;
Ok((&b.mesh, b.mesh_link.to_iter(), slice, state))
}
fn fill_params(&self, values: &mut ParamStorage<T::Resources>)
-> Result<&ProgramHandle<T::Resources>, Error> {
let (b, _, data, _) = *self;
values.reserve(b.program.get_info());
data.fill_params(&b.param_link, values);
Ok(&b.program)
}
}