This repository has been archived by the owner on Jun 6, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature(polygon::MeshBuilder): add mesh builder system
Remove Mesh::from_raw_data() and replace it with MeshBuilder which provides better typesafety and performs validation on the data.
- Loading branch information
1 parent
137f3c3
commit 907bf23
Showing
5 changed files
with
192 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,49 +1,198 @@ | ||
use math::*; | ||
|
||
pub type MeshIndex = u32; | ||
|
||
/// The raw data representing a mesh in memory. | ||
/// | ||
/// Meshes are represented as list of vertex positions and a list of faces. | ||
/// Each face is represented as 3 indices into the vertex array. | ||
#[derive(Debug)] | ||
pub struct Mesh { | ||
pub raw_data: Vec<f32>, | ||
pub indices: Vec<u32>, | ||
pub position_attribute: VertexAttribute, | ||
pub normal_attribute: Option<VertexAttribute>, | ||
// pub uv_attribute: Option<VertexAttribute>, | ||
// pub color_attribute: Option<VertexAttribute>, | ||
vertex_data: Vec<f32>, | ||
indices: Vec<MeshIndex>, | ||
|
||
position: VertexAttribute, | ||
normal: Option<VertexAttribute>, | ||
texcoord: Vec<VertexAttribute>, | ||
} | ||
|
||
impl Mesh { | ||
/// Create a new mesh from existing data passed as slices. | ||
pub fn from_raw_data(positions_raw: &[f32], indices_raw: &[u32]) -> Mesh { | ||
let mut raw_data: Vec<f32> = Vec::with_capacity(positions_raw.len()); | ||
raw_data.extend(positions_raw); | ||
|
||
let mut indices: Vec<u32> = Vec::with_capacity(indices_raw.len()); | ||
indices.extend(indices_raw); | ||
|
||
Mesh { | ||
raw_data: raw_data, | ||
indices: indices, | ||
position_attribute: VertexAttribute { | ||
stride: 4, | ||
offset: 0, | ||
}, | ||
normal_attribute: None, | ||
} | ||
pub fn vertex_data(&self) -> &[f32] { | ||
&*self.vertex_data | ||
} | ||
|
||
pub fn indices(&self) -> &[MeshIndex] { | ||
&*self.indices | ||
} | ||
|
||
/// Adds the normals data to the mesh's raw data and creates the associated `VertexAttribute`. | ||
pub fn add_normals(&mut self, normals_raw: &[f32]) { | ||
self.normal_attribute = Some(VertexAttribute { | ||
stride: 3, | ||
offset: self.raw_data.len(), | ||
}); | ||
self.raw_data.extend(normals_raw); | ||
pub fn position(&self) -> VertexAttribute { | ||
self.position | ||
} | ||
|
||
pub fn normal(&self) -> Option<VertexAttribute> { | ||
self.normal | ||
} | ||
|
||
pub fn texcoord(&self) -> &[VertexAttribute] { | ||
&*self.texcoord | ||
} | ||
} | ||
|
||
/// Represents a single vertex in a mesh with all of its supported attributes. | ||
#[derive(Debug, Clone)] | ||
pub struct Vertex { | ||
pub position: Point, | ||
pub normal: Option<Vector3>, | ||
|
||
/// Support an arbitrary number of texture units. The actual maximum is dependent on hardware | ||
/// and so is not limited by polygon directly. If the number of | ||
pub texcoord: Vec<Vector2>, | ||
} | ||
|
||
impl Vertex { | ||
pub fn new(position: Point) -> Vertex { | ||
Vertex { | ||
position: position, | ||
normal: None, | ||
texcoord: Vec::new(), | ||
} | ||
} | ||
} | ||
|
||
#[derive(Debug, Clone, Copy)] | ||
pub struct VertexAttribute { | ||
pub stride: usize, | ||
pub offset: usize, | ||
pub stride: usize, | ||
} | ||
|
||
#[derive(Debug, Clone, Copy)] | ||
pub enum BuildMeshError { | ||
IndexOutOfBounds { | ||
vertex_count: MeshIndex, | ||
index: MeshIndex, | ||
}, | ||
|
||
/// Indicates that one or more attributes had a count that did not match the total number of | ||
/// vertices. | ||
IncorrectAttributeCount, | ||
} | ||
|
||
#[derive(Debug, Clone)] | ||
pub struct MeshBuilder { | ||
position_data: Vec<Point>, | ||
normal_data: Vec<Vector3>, | ||
texcoord_data: Vec<Vec<Vector3>>, | ||
|
||
indices: Vec<u32>, | ||
} | ||
|
||
// TODO: I'd like to support building the mesh by specifying all of each attribute at once, since | ||
// that seems like a common use case for game development. We still want to support building it | ||
// vert-by-vert because that works best in other situations (e.g. COLLADA files). | ||
impl MeshBuilder { | ||
pub fn new() -> MeshBuilder { | ||
MeshBuilder { | ||
position_data: Vec::new(), | ||
normal_data: Vec::new(), | ||
texcoord_data: Vec::new(), | ||
indices: Vec::new(), | ||
} | ||
} | ||
|
||
pub fn add_vertex(mut self, vertex: Vertex) -> MeshBuilder { | ||
self.position_data.push(vertex.position); | ||
|
||
if let Some(normal) = vertex.normal { | ||
self.normal_data.push(normal); | ||
} | ||
|
||
// TODO: Handle texcoord data. | ||
|
||
self | ||
} | ||
|
||
pub fn add_index(mut self, index: MeshIndex) -> MeshBuilder { | ||
self.indices.push(index); | ||
self | ||
} | ||
|
||
pub fn set_position_data(mut self, position_data: &[Point]) -> MeshBuilder { | ||
self.position_data.clear(); | ||
self.position_data.extend(position_data); | ||
self | ||
} | ||
|
||
pub fn set_normal_data(mut self, normal_data: &[Vector3]) -> MeshBuilder { | ||
self.normal_data.clear(); | ||
self.normal_data.extend(normal_data); | ||
self | ||
} | ||
|
||
pub fn set_texcoord_data(mut self, _texcoord_data: &[Vector2], _texcoord_index: MeshIndex) -> MeshBuilder { | ||
// TODO | ||
|
||
self | ||
} | ||
|
||
pub fn set_indices(mut self, indices: &[u32]) -> MeshBuilder { | ||
self.indices.clear(); | ||
self.indices.extend(indices); | ||
self | ||
} | ||
|
||
pub fn build(self) -> Result<Mesh, BuildMeshError> { | ||
// Validate the mesh data. | ||
|
||
// The vertex count is defined by the position data, since position is the only required | ||
// vertex attribute. | ||
let vertex_count = self.position_data.len(); | ||
|
||
// TODO: Validate texcoord data. | ||
if self.normal_data.len() != 0 && self.normal_data.len() != vertex_count { | ||
return Err(BuildMeshError::IncorrectAttributeCount); | ||
} | ||
|
||
// Make sure all indices at least point to a valid vertex. | ||
for index in self.indices.iter().cloned() { | ||
if index >= vertex_count as MeshIndex { | ||
return Err(BuildMeshError::IndexOutOfBounds { | ||
vertex_count: vertex_count as MeshIndex, | ||
index: index, | ||
}); | ||
} | ||
} | ||
|
||
// TODO: Make sure all normals are normalized? | ||
|
||
// Create the mesh. | ||
let mut vertex_data = | ||
Vec::<f32>::with_capacity( | ||
self.position_data.len() * 4 | ||
+ self.normal_data.len() * 3); | ||
vertex_data.extend(Point::as_ref(&*self.position_data)); | ||
vertex_data.extend(Vector3::as_ref(&*self.normal_data)); | ||
|
||
// TODO: Add texcoord data. | ||
|
||
Ok(Mesh { | ||
vertex_data: vertex_data, | ||
indices: self.indices, | ||
|
||
position: VertexAttribute { | ||
offset: 0, | ||
stride: 0, // TODO: Should stride 4 (as in every 4 floats) or 0 (as in tightly packed)? Does that change between OpenGL and DirectX? | ||
}, | ||
|
||
normal: if self.normal_data.len() > 0 { | ||
Some(VertexAttribute { | ||
offset: self.position_data.len() * 4, | ||
stride: 0, // TODO: Same as above. | ||
}) | ||
} else { | ||
None | ||
}, | ||
|
||
texcoord: Vec::new(), | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
pub mod mesh; | ||
|
||
pub use self::mesh::{Mesh, VertexAttribute}; | ||
pub use self::mesh::*; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,13 @@ | ||
extern crate polygon_math as math; | ||
extern crate bootstrap_rs as bootstrap; | ||
extern crate bootstrap_gl as gl; | ||
extern crate bootstrap_rs as bootstrap; | ||
extern crate polygon_math as math; | ||
|
||
pub mod camera; | ||
pub mod geometry; | ||
pub mod gl_render; | ||
pub mod camera; | ||
pub mod light; | ||
|
||
pub use camera::Camera; | ||
pub use light::{Light, PointLight}; | ||
pub use geometry::*; | ||
pub use gl_render::{GLRender, ShaderProgram}; | ||
pub use light::{Light, PointLight}; |