use crate::draw::mesh::vertex::IntoVertex;
use crate::draw::properties::spatial::{self, orientation, position};
use crate::draw::properties::{Draw, Drawn, IntoDrawn, Primitive, SetOrientation, SetPosition};
use crate::draw::{self, Drawing};
use crate::geom;
use crate::math::BaseFloat;
use crate::mesh::vertex::{WithColor, WithTexCoords};
use std::{iter, ops};
#[derive(Clone, Debug, Default)]
pub struct Vertexless;
#[derive(Clone, Debug)]
pub struct Mesh<S = geom::scalar::Default> {
position: position::Properties<S>,
orientation: orientation::Properties<S>,
vertex_data_ranges: draw::IntermediaryVertexDataRanges,
index_range: ops::Range<usize>,
}
struct FlattenIndices<I> {
iter: I,
index: usize,
current: [usize; 3],
}
impl Vertexless {
pub fn tris<S, I, V>(self, mesh: &mut draw::IntermediaryMesh<S>, tris: I) -> Mesh<S>
where
S: BaseFloat,
I: IntoIterator<Item = geom::Tri<V>>,
V: geom::Vertex + IntoVertex<S>,
{
let mut vertex_data_ranges = draw::IntermediaryVertexDataRanges::default();
let mut index_range = 0..0;
vertex_data_ranges.points.start = mesh.vertex_data.points.len();
vertex_data_ranges.colors.start = mesh.vertex_data.colors.len();
vertex_data_ranges.tex_coords.start = mesh.vertex_data.tex_coords.len();
index_range.start = mesh.indices.len();
let vertices = tris
.into_iter()
.flat_map(geom::Tri::vertices)
.map(IntoVertex::into_vertex);
for (i, vertex) in vertices.enumerate() {
let WithTexCoords {
tex_coords,
vertex:
WithColor {
color,
vertex: point,
},
} = vertex;
mesh.vertex_data.points.push(point);
mesh.vertex_data.colors.push(color);
mesh.vertex_data.tex_coords.push(tex_coords);
mesh.indices.push(i);
}
vertex_data_ranges.points.end = mesh.vertex_data.points.len();
vertex_data_ranges.colors.end = mesh.vertex_data.colors.len();
vertex_data_ranges.tex_coords.end = mesh.vertex_data.tex_coords.len();
index_range.end = mesh.indices.len();
Mesh::new(vertex_data_ranges, index_range)
}
pub fn indexed<S, V, I>(
self,
mesh: &mut draw::IntermediaryMesh<S>,
vertices: V,
indices: I,
) -> Mesh<S>
where
S: BaseFloat,
V: IntoIterator,
V::Item: IntoVertex<S>,
I: IntoIterator<Item = [usize; 3]>,
{
let mut vertex_data_ranges = draw::IntermediaryVertexDataRanges::default();
vertex_data_ranges.points.start = mesh.vertex_data.points.len();
vertex_data_ranges.colors.start = mesh.vertex_data.colors.len();
vertex_data_ranges.tex_coords.start = mesh.vertex_data.tex_coords.len();
for vertex in vertices {
let WithTexCoords {
tex_coords,
vertex:
WithColor {
color,
vertex: point,
},
} = vertex.into_vertex();
mesh.vertex_data.points.push(point);
mesh.vertex_data.colors.push(color);
mesh.vertex_data.tex_coords.push(tex_coords);
}
vertex_data_ranges.points.end = mesh.vertex_data.points.len();
vertex_data_ranges.colors.end = mesh.vertex_data.colors.len();
vertex_data_ranges.tex_coords.end = mesh.vertex_data.tex_coords.len();
let mut index_range = mesh.indices.len()..mesh.indices.len();
let iter = FlattenIndices {
iter: indices.into_iter(),
current: [0; 3],
index: 3,
};
mesh.indices.extend(iter);
index_range.end = mesh.indices.len();
Mesh::new(vertex_data_ranges, index_range)
}
}
impl<S> Mesh<S>
where
S: BaseFloat,
{
fn new(
vertex_data_ranges: draw::IntermediaryVertexDataRanges,
index_range: ops::Range<usize>,
) -> Self {
let orientation = Default::default();
let position = Default::default();
Mesh {
orientation,
position,
vertex_data_ranges,
index_range,
}
}
}
impl<'a, S> Drawing<'a, Vertexless, S>
where
S: BaseFloat,
{
pub fn tris<I, V>(self, tris: I) -> Drawing<'a, Mesh<S>, S>
where
I: IntoIterator<Item = geom::Tri<V>>,
V: geom::Vertex + IntoVertex<S>,
{
self.map_ty_with_vertices(|ty, mesh| ty.tris(mesh, tris))
}
pub fn indexed<V, I>(self, vertices: V, indices: I) -> Drawing<'a, Mesh<S>, S>
where
V: IntoIterator,
V::Item: IntoVertex<S>,
I: IntoIterator<Item = [usize; 3]>,
{
self.map_ty_with_vertices(|ty, mesh| ty.indexed(mesh, vertices, indices))
}
}
impl<S> IntoDrawn<S> for Vertexless
where
S: BaseFloat,
{
type Vertices = iter::Empty<draw::mesh::Vertex<S>>;
type Indices = iter::Empty<usize>;
fn into_drawn(self, _draw: Draw<S>) -> Drawn<S, Self::Vertices, Self::Indices> {
let properties = Default::default();
let vertices = iter::empty();
let indices = iter::empty();
(properties, vertices, indices)
}
}
impl<S> IntoDrawn<S> for Mesh<S>
where
S: BaseFloat,
{
type Vertices = draw::properties::VerticesFromRanges;
type Indices = draw::properties::IndicesFromRange;
fn into_drawn(self, _draw: Draw<S>) -> Drawn<S, Self::Vertices, Self::Indices> {
let Mesh {
orientation,
position,
vertex_data_ranges,
index_range,
} = self;
let dimensions = spatial::dimension::Properties::default();
let spatial = spatial::Properties {
dimensions,
orientation,
position,
};
let vertices = draw::properties::VerticesFromRanges {
ranges: vertex_data_ranges,
fill_color: None,
};
let indices = draw::properties::IndicesFromRange { range: index_range };
(spatial, vertices, indices)
}
}
impl<I> Iterator for FlattenIndices<I>
where
I: Iterator<Item = [usize; 3]>,
{
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
loop {
if self.index < self.current.len() {
let ix = self.current[self.index];
self.index += 1;
return Some(ix);
}
match self.iter.next() {
None => return None,
Some(trio) => {
self.current = trio;
self.index = 0;
}
}
}
}
}
impl<S> SetOrientation<S> for Mesh<S> {
fn properties(&mut self) -> &mut orientation::Properties<S> {
SetOrientation::properties(&mut self.orientation)
}
}
impl<S> SetPosition<S> for Mesh<S> {
fn properties(&mut self) -> &mut position::Properties<S> {
SetPosition::properties(&mut self.position)
}
}
impl<S> From<Vertexless> for Primitive<S> {
fn from(prim: Vertexless) -> Self {
Primitive::MeshVertexless(prim)
}
}
impl<S> From<Mesh<S>> for Primitive<S> {
fn from(prim: Mesh<S>) -> Self {
Primitive::Mesh(prim)
}
}
impl<S> Into<Option<Vertexless>> for Primitive<S> {
fn into(self) -> Option<Vertexless> {
match self {
Primitive::MeshVertexless(prim) => Some(prim),
_ => None,
}
}
}
impl<S> Into<Option<Mesh<S>>> for Primitive<S> {
fn into(self) -> Option<Mesh<S>> {
match self {
Primitive::Mesh(prim) => Some(prim),
_ => None,
}
}
}