use crate::error::Error;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub enum PrimitiveType {
Point = 0,
Line = 1,
LineStrip = 2,
LineLoop = 3,
Triangles = 4,
TriangleStrip = 5,
TriangleFan = 6,
}
#[derive(Clone)]
pub enum IndexData {
NonIndexed(usize),
Indices(Vec<u32>),
}
impl IndexData {
pub fn num_indices(&self) -> usize {
match self {
IndexData::NonIndexed(n) => *n,
IndexData::Indices(indices) => indices.len(),
}
}
pub fn get_indices_ref(&self) -> Option<&[u32]> {
match self {
IndexData::Indices(indices) => Some(indices),
_ => None,
}
}
}
pub struct Primitives {
primitive_type: PrimitiveType,
index_data: IndexData,
}
impl Primitives {
pub fn new(index_data: IndexData, primitive_type: PrimitiveType) -> Result<Self, Error> {
let num_indices = index_data.num_indices();
match primitive_type {
PrimitiveType::Line => {
if num_indices % 2 != 0 {
return Err(Error::Indices(format!("Lines primitive indices must be a multiple of 2")));
}
},
PrimitiveType::LineStrip => {
if num_indices < 2 {
return Err(Error::Indices(format!("Line-strips indices must be at least 2")));
}
},
PrimitiveType::LineLoop => {
if num_indices < 2 {
return Err(Error::Indices(format!("Line-loop indices must be at least 2")));
}
},
PrimitiveType::Triangles => {
if num_indices % 3 != 0 {
return Err(Error::Indices(format!("Triangle indices must be a multiple of 3")));
}
},
PrimitiveType::TriangleStrip => {
if num_indices < 3 {
return Err(Error::Indices(format!("Triangle-strip indices must be at least 3")));
}
},
PrimitiveType::TriangleFan => {
if num_indices < 3 {
return Err(Error::Indices(format!("Triangle-fan indices must be at least 3")));
}
},
_ => {},
}
Ok(Self {
primitive_type,
index_data,
})
}
pub fn num_primitives(&self) -> usize {
let num_indices = self.index_data.num_indices();
match self.primitive_type {
PrimitiveType::Point =>num_indices,
PrimitiveType::Line =>num_indices / 2,
PrimitiveType::LineStrip => if num_indices == 0 { 0 } else { num_indices - 1 },
PrimitiveType::LineLoop =>num_indices,
PrimitiveType::Triangles =>num_indices / 3,
PrimitiveType::TriangleStrip => if num_indices >= 2 { num_indices - 2 } else { 0 },
PrimitiveType::TriangleFan => if num_indices >= 2 { num_indices - 2 } else { 0 },
}
}
pub fn get_primitive_type(&self) -> PrimitiveType {
self.primitive_type
}
pub fn get_raw_index_data(&self) -> &IndexData {
&self.index_data
}
pub fn max_index(&self) -> Option<u32> {
match &self.index_data {
IndexData::Indices(indices) => {
match indices.iter().max() {
Some(m) => Some(*m),
None => None,
}
}
IndexData::NonIndexed(n) => if *n == 0 { None } else { Some((*n - 1) as u32) }
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_num_primitives() {
let p = Primitives::new(IndexData::Indices(vec![1,2]), PrimitiveType::Point).unwrap();
assert_eq!(p.num_primitives(), 2);
let p = Primitives::new(IndexData::Indices(vec![1,2,3,4]), PrimitiveType::Line).unwrap();
assert_eq!(p.num_primitives(), 2);
let p = Primitives::new(IndexData::Indices(vec![1,2,3,4]), PrimitiveType::LineLoop).unwrap();
assert_eq!(p.num_primitives(), 4);
let p = Primitives::new(IndexData::Indices(vec![1,2,3,4]), PrimitiveType::LineStrip).unwrap();
assert_eq!(p.num_primitives(), 3);
let p = Primitives::new(IndexData::Indices(vec![1,2,3,4,5,6]), PrimitiveType::Triangles).unwrap();
assert_eq!(p.num_primitives(), 2);
let p = Primitives::new(IndexData::Indices(vec![1,2,3,4,5,6]), PrimitiveType::TriangleStrip).unwrap();
assert_eq!(p.num_primitives(), 4);
let p = Primitives::new(IndexData::Indices(vec![1,2,3,4,5,6]), PrimitiveType::TriangleFan).unwrap();
assert_eq!(p.num_primitives(), 4);
}
}