use device;
use device::{PrimitiveType, BufferHandle, Resources, VertexCount};
use device::attrib;
#[derive(Clone, Debug, PartialEq)]
pub struct Attribute<R: Resources> {
pub name: String,
pub buffer: device::RawBufferHandle<R>,
pub format: attrib::Format,
}
#[allow(missing_docs)]
pub trait VertexFormat {
fn generate<R: Resources>(Option<&Self>, buffer: device::RawBufferHandle<R>)
-> Vec<Attribute<R>>;
}
#[derive(Clone, Debug, PartialEq)]
pub struct Mesh<R: Resources> {
pub num_vertices: device::VertexCount,
pub attributes: Vec<Attribute<R>>,
}
impl<R: Resources> Mesh<R> {
pub fn new(nv: device::VertexCount) -> Mesh<R> {
Mesh {
num_vertices: nv,
attributes: Vec::new(),
}
}
pub fn from_format<V: VertexFormat>(buf: device::BufferHandle<R, V>, nv: device::VertexCount)
-> Mesh<R> {
Mesh {
num_vertices: nv,
attributes: VertexFormat::generate(None::<&V>, buf.raw()),
}
}
pub fn from_format_instanced<V: VertexFormat, U: VertexFormat>(
buf: device::BufferHandle<R, V>,
nv: device::VertexCount,
inst: device::BufferHandle<R, U>) -> Mesh<R> {
let per_vertex = VertexFormat::generate(None::<&V>, buf.raw());
let per_instance = VertexFormat::generate(None::<&U>, inst.raw());
let mut attributes = per_vertex;
for mut at in per_instance.into_iter() {
at.format.instance_rate = 1;
attributes.push(at);
}
Mesh {
num_vertices: nv,
attributes: attributes,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Slice<R: Resources> {
pub start: VertexCount,
pub end: VertexCount,
pub prim_type: PrimitiveType,
pub kind: SliceKind<R>,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum SliceKind<R: Resources> {
Vertex,
Index8(BufferHandle<R, u8>, VertexCount),
Index16(BufferHandle<R, u16>, VertexCount),
Index32(BufferHandle<R, u32>, VertexCount),
}
pub trait ToSlice<R: Resources> {
fn to_slice(&self, pt: PrimitiveType) -> Slice<R>;
}
impl<R: Resources> ToSlice<R> for Mesh<R> {
fn to_slice(&self, ty: PrimitiveType) -> Slice<R> {
Slice {
start: 0,
end: self.num_vertices,
prim_type: ty,
kind: SliceKind::Vertex
}
}
}
impl<R: Resources> ToSlice<R> for BufferHandle<R, u8> {
fn to_slice(&self, ty: PrimitiveType) -> Slice<R> {
Slice {
start: 0,
end: self.len() as VertexCount,
prim_type: ty,
kind: SliceKind::Index8(*self, 0)
}
}
}
impl<R: Resources> ToSlice<R> for BufferHandle<R, u16> {
fn to_slice(&self, ty: PrimitiveType) -> Slice<R> {
Slice {
start: 0,
end: self.len() as VertexCount,
prim_type: ty,
kind: SliceKind::Index16(*self, 0)
}
}
}
impl<R: Resources> ToSlice<R> for BufferHandle<R, u32> {
fn to_slice(&self, ty: PrimitiveType) -> Slice<R> {
Slice {
start: 0,
end: self.len() as VertexCount,
prim_type: ty,
kind: SliceKind::Index32(*self, 0)
}
}
}
pub type AttributeIndex = usize;
#[derive(Clone, Debug, PartialEq)]
pub enum Error {
AttributeMissing(String),
AttributeType(String, device::shade::BaseType),
AttributeIndex(AttributeIndex),
ShaderInputIndex(usize),
}
const BITS_PER_ATTRIBUTE: AttributeIndex = 4;
const MESH_ATTRIBUTE_MASK: AttributeIndex = (1 << BITS_PER_ATTRIBUTE) - 1;
const MAX_SHADER_INPUTS: usize = 64 / BITS_PER_ATTRIBUTE;
#[derive(Copy)]
pub struct AttributeIter {
value: u64,
}
impl Iterator for AttributeIter {
type Item = AttributeIndex;
fn next(&mut self) -> Option<AttributeIndex> {
let id = (self.value as AttributeIndex) & MESH_ATTRIBUTE_MASK;
self.value >>= BITS_PER_ATTRIBUTE;
Some(id)
}
}
#[derive(Copy)]
pub struct Link {
table: u64,
}
impl Link {
pub fn new<R: Resources>(mesh: &Mesh<R>, pinfo: &device::shade::ProgramInfo)
-> Result<Link, Error> {
let mut indices = Vec::new();
for sat in pinfo.attributes.iter() {
match mesh.attributes.iter().enumerate()
.find(|&(_, a)| a.name == sat.name) {
Some((attrib_id, vat)) => match vat.format.elem_type.is_compatible(sat.base_type) {
Ok(_) => indices.push(attrib_id),
Err(_) => return Err(Error::AttributeType(sat.name.clone(), sat.base_type)),
},
None => return Err(Error::AttributeMissing(sat.name.clone())),
}
}
Link::from_iter(indices.into_iter())
}
pub fn from_iter<I: Iterator<Item = AttributeIndex>>(iter: I)
-> Result<Link, Error> {
let mut table = 0u64;
for (input, attrib) in iter.enumerate() {
if input >= MAX_SHADER_INPUTS {
return Err(Error::ShaderInputIndex(input))
} else if attrib > MESH_ATTRIBUTE_MASK {
return Err(Error::AttributeIndex(attrib))
} else {
table |= (attrib as u64) << (input * BITS_PER_ATTRIBUTE);
}
}
Ok(Link {
table: table,
})
}
pub fn to_iter(&self) -> AttributeIter {
AttributeIter {
value: self.table,
}
}
}