use device::{PrimitiveType, Resources, VertexCount};
use device::{attrib, handle, shade};
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Attribute<R: Resources> {
pub name: String,
pub buffer: handle::RawBuffer<R>,
pub format: attrib::Format,
}
#[allow(missing_docs)]
pub trait VertexFormat {
fn generate<R: Resources>(buffer: &handle::Buffer<R, Self>) -> Vec<Attribute<R>>;
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Mesh<R: Resources> {
pub num_vertices: VertexCount,
pub attributes: Vec<Attribute<R>>,
}
impl<R: Resources> Mesh<R> {
pub fn new(nv: VertexCount) -> Mesh<R> {
Mesh {
num_vertices: nv,
attributes: Vec::new(),
}
}
pub fn from_format<V: VertexFormat>(buf: handle::Buffer<R, V>, nv: VertexCount)
-> Mesh<R> {
Mesh {
num_vertices: nv,
attributes: V::generate(&buf),
}
}
pub fn from_format_instanced<V: VertexFormat, U: VertexFormat>(
buf: handle::Buffer<R, V>,
nv: VertexCount,
inst: handle::Buffer<R, U>) -> Mesh<R> {
let per_vertex = V::generate(&buf);
let per_instance = U::generate(&inst);
let mut attributes = per_vertex;
attributes.extend(per_instance.into_iter().map(|mut a| {
a.format.instance_rate = 1;
a
}));
Mesh {
num_vertices: nv,
attributes: attributes,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Slice<R: Resources> {
pub start: VertexCount,
pub end: VertexCount,
pub prim_type: PrimitiveType,
pub kind: SliceKind<R>,
}
impl<R: Resources> Slice<R> {
pub fn get_prim_count(&self) -> u32 {
use device::PrimitiveType::*;
let nv = (self.end - self.start) as u32;
match self.prim_type {
Point => nv,
Line => nv / 2,
LineStrip => (nv-1),
TriangleList => nv / 3,
TriangleStrip | TriangleFan => (nv-2) / 3,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum SliceKind<R: Resources> {
Vertex,
Index8(handle::IndexBuffer<R, u8>, VertexCount),
Index16(handle::IndexBuffer<R, u16>, VertexCount),
Index32(handle::IndexBuffer<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 handle::IndexBuffer<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.clone(), 0)
}
}
}
impl<R: Resources> ToSlice<R> for handle::IndexBuffer<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.clone(), 0)
}
}
}
impl<R: Resources> ToSlice<R> for handle::IndexBuffer<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.clone(), 0)
}
}
}
pub type AttributeIndex = usize;
#[derive(Clone, Debug, PartialEq)]
pub enum Error {
AttributeMissing(String),
AttributeType(String, 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(Clone, 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(Clone, Copy)]
pub struct Link {
table: u64,
}
impl Link {
pub fn new<R: Resources>(mesh: &Mesh<R>, pinfo: &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,
}
}
}