Fixed some things, enable parsing from anything that impl Read
This commit is contained in:
+123
-11
@@ -5,11 +5,12 @@ pub mod material;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::rc::Rc;
|
||||
|
||||
use glium::VertexBuffer;
|
||||
use glium::texture::SrgbTexture2d;
|
||||
|
||||
use parser::{parse, ParserError};
|
||||
use parser::{parse_file, ParserError};
|
||||
|
||||
use model::face::{FaceVertex, Face};
|
||||
use model::material::Material;
|
||||
@@ -38,11 +39,14 @@ pub struct Part {
|
||||
pub material_name: Option<String>,
|
||||
|
||||
/// List of all the faces in the part.
|
||||
pub faces: Vec<Face>,
|
||||
faces: Vec<Face>,
|
||||
|
||||
/// VertexBuffer for rendering.
|
||||
vertex_buffer: Option<VertexBuffer<Vertex>>,
|
||||
|
||||
/// True if the faces have been changed since the last time the buffer was built.
|
||||
needs_update: bool,
|
||||
|
||||
}
|
||||
|
||||
impl Part {
|
||||
@@ -53,6 +57,7 @@ impl Part {
|
||||
material_name: material_name,
|
||||
faces: vec![],
|
||||
vertex_buffer: None,
|
||||
needs_update: true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +68,7 @@ impl Part {
|
||||
let mut f = f;
|
||||
f.material_name = self.material_name.clone();
|
||||
self.faces.push(f);
|
||||
self.needs_update = true;
|
||||
}
|
||||
|
||||
/// Returns a reference to the vertex buffer.
|
||||
@@ -70,6 +76,11 @@ impl Part {
|
||||
&self.vertex_buffer
|
||||
}
|
||||
|
||||
/// Returns a reference to the faces.
|
||||
pub fn faces(&self) -> &Vec<Face> {
|
||||
&self.faces
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -91,7 +102,7 @@ pub struct Model {
|
||||
pub materials: HashMap<String, Material>,
|
||||
|
||||
/// Map associating the name of a texture and the real texture.
|
||||
pub textures: HashMap<String, SrgbTexture2d>,
|
||||
pub textures: HashMap<String, Rc<SrgbTexture2d>>,
|
||||
|
||||
/// The list of parts of the model.
|
||||
pub parts: Vec<Part>,
|
||||
@@ -127,10 +138,57 @@ impl Model {
|
||||
}
|
||||
}
|
||||
|
||||
/// Merges the model passed as parameter into the current model.
|
||||
pub fn merge(&mut self, other: Model) {
|
||||
/// Copies the materials and textures from the other model into self.
|
||||
pub fn merge_material_and_textures(&mut self, other: &Model) {
|
||||
// Merge the materials
|
||||
for (name, material) in &other.materials {
|
||||
let entry = self.materials.entry(name.clone());
|
||||
if let Entry::Occupied(_) = entry {
|
||||
eprintln!("Warning: materials merged but sharing the same name");
|
||||
// Return error
|
||||
} else {
|
||||
entry.or_insert(material.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// Merge the textures
|
||||
for (name, texture) in &other.textures {
|
||||
let entry = self.textures.entry(name.clone());
|
||||
if let Entry::Occupied(_) = entry {
|
||||
eprintln!("Warning: textures merged but sharing the same name");
|
||||
// return Error;
|
||||
} else {
|
||||
entry.or_insert(texture.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Merges the model passed as parameter into new parts of the current model.
|
||||
pub fn merge_in_new_parts(&mut self, other: Model) {
|
||||
let mut other = other;
|
||||
|
||||
// Merge the materials
|
||||
for (name, material) in other.materials {
|
||||
let entry = self.materials.entry(name);
|
||||
if let Entry::Occupied(_) = entry {
|
||||
eprintln!("Warning: materials merged but sharing the same name");
|
||||
// Return error
|
||||
} else {
|
||||
entry.or_insert(material);
|
||||
}
|
||||
}
|
||||
|
||||
// Merge the textures
|
||||
for (name, texture) in other.textures {
|
||||
let entry = self.textures.entry(name);
|
||||
if let Entry::Occupied(_) = entry {
|
||||
eprintln!("Warning: textures merged but sharing the same name");
|
||||
// return Error;
|
||||
} else {
|
||||
entry.or_insert(texture);
|
||||
}
|
||||
}
|
||||
|
||||
let vertex_offset = self.vertices.len();
|
||||
let tex_coord_offset = self.texture_coordinates.len();
|
||||
let normal_offset = self.normals.len();
|
||||
@@ -161,9 +219,17 @@ impl Model {
|
||||
new_part.faces.push(face.clone());
|
||||
self.faces.push(face.clone());
|
||||
}
|
||||
new_part.needs_update = true;
|
||||
self.parts.push(new_part);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// Merges the model passed as parameter into existing parts of the current model.
|
||||
pub fn merge_in_existing_parts(&mut self, other: Model) {
|
||||
let mut other = other;
|
||||
|
||||
// Merge the materials
|
||||
for (name, material) in other.materials {
|
||||
let entry = self.materials.entry(name);
|
||||
@@ -185,11 +251,51 @@ impl Model {
|
||||
entry.or_insert(texture);
|
||||
}
|
||||
}
|
||||
|
||||
let vertex_offset = self.vertices.len();
|
||||
let tex_coord_offset = self.texture_coordinates.len();
|
||||
let normal_offset = self.normals.len();
|
||||
let face_offset = self.faces.len();
|
||||
|
||||
// Merge the elements
|
||||
self.vertices.append(&mut other.vertices);
|
||||
self.texture_coordinates.append(&mut other.texture_coordinates);
|
||||
self.normals.append(&mut other.normals);
|
||||
|
||||
// Merge the parts and faces
|
||||
for part in &mut other.parts {
|
||||
self.change_part(part.material_name.clone());
|
||||
let mut new_faces = vec![];
|
||||
{
|
||||
let new_part = self.current_part_mut().unwrap();
|
||||
for face in &mut part.faces {
|
||||
for fv in &mut [&mut face.a, &mut face.b, &mut face.c] {
|
||||
fv.vertex += vertex_offset;
|
||||
if let Some(tex_coord) = fv.texture_coordinate {
|
||||
fv.texture_coordinate = Some(tex_coord + tex_coord_offset);
|
||||
}
|
||||
if let Some(normal) = fv.normal {
|
||||
fv.normal = Some(normal + normal_offset);
|
||||
}
|
||||
}
|
||||
if let Some(id) = face.id {
|
||||
face.id = Some(id + face_offset);
|
||||
}
|
||||
face.material_name = new_part.material_name.clone();
|
||||
new_part.faces.push(face.clone());
|
||||
new_faces.push(face);
|
||||
}
|
||||
}
|
||||
|
||||
for face in new_faces {
|
||||
self.faces.push(face.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a model from a file.
|
||||
pub fn from(path: &str) -> Result<Model, ParserError> {
|
||||
parse(path)
|
||||
parse_file(path)
|
||||
}
|
||||
|
||||
/// Computes the area of a 3D face of the model.
|
||||
@@ -380,7 +486,7 @@ impl Model {
|
||||
/// Creates only non-existant vertex buffers, doesn't update the old ones.
|
||||
pub fn build_new_vertex_buffers(&mut self, renderer: &Renderer) {
|
||||
for part in &mut self.parts {
|
||||
if part.vertex_buffer.is_none() {
|
||||
if part.vertex_buffer.is_none() || part.needs_update {
|
||||
Model::build_vertex_buffer_for_part(
|
||||
&self.vertices,
|
||||
&self.texture_coordinates,
|
||||
@@ -400,7 +506,7 @@ impl Model {
|
||||
renderer: &Renderer) {
|
||||
|
||||
let mut vertex_buffer = vec![];
|
||||
for face in &part.faces {
|
||||
for face in part.faces() {
|
||||
for &&v in &[&face.a, &face.b, &face.c] {
|
||||
let vertex = vertices[v.vertex].into();
|
||||
let tex_coord = if let Some(tex_index) = v.texture_coordinate {
|
||||
@@ -424,6 +530,7 @@ impl Model {
|
||||
}
|
||||
|
||||
part.vertex_buffer = Some(renderer.build_vertex_buffer(&vertex_buffer));
|
||||
part.needs_update = false;
|
||||
}
|
||||
|
||||
/// Builds the textures of all materials.
|
||||
@@ -438,17 +545,22 @@ impl Model {
|
||||
if let Some(path) = material.textures.get("map_Kd") {
|
||||
let texture = renderer.make_texture(path);
|
||||
// Don't need to insert multiple times the same texture
|
||||
self.textures.entry(path.to_owned()).or_insert(texture);
|
||||
self.textures.entry(path.to_owned()).or_insert(Rc::new(texture));
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the rendering texture.
|
||||
pub fn get_texture_by_name(&self, name: &str) -> Option<&SrgbTexture2d> {
|
||||
pub fn get_texture_by_name(&self, name: &str) -> Option<&Rc<SrgbTexture2d>> {
|
||||
self.textures.get(name)
|
||||
}
|
||||
|
||||
/// Returns the material.
|
||||
pub fn get_material_by_name(&self, name: &str) -> Option<&Material> {
|
||||
self.materials.get(name)
|
||||
}
|
||||
|
||||
/// Returns a ref mut to the table of textures.
|
||||
pub fn textures_mut(&mut self) -> &mut HashMap<String, SrgbTexture2d> {
|
||||
pub fn textures_mut(&mut self) -> &mut HashMap<String, Rc<SrgbTexture2d>> {
|
||||
&mut self.textures
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user