use std::path::Path;
use std::collections::HashMap;
use std::sync::Arc;
use tobj;
use lighting::Light;
use geometry::prelude::*;
use material::prelude::*;
use shape::prelude::*;
use texturing::prelude::*;
use spectrum::prelude::*;
pub trait Composable: Sync + Send {
fn bbox_parent(&self) -> BBox3f;
fn intersect_ray(&self, ray: &mut RawRay) -> Option<SurfaceInteraction>;
#[inline]
fn can_intersect(&self, ray: &RawRay) -> bool {
let mut ray = ray.clone();
self.intersect_ray(&mut ray).is_some()
}
fn as_light(&self) -> &Light {
unimplemented!();
}
#[inline]
fn intersection_cost(&self) -> Float {
1.0 as Float
}
}
pub trait Primitive: Composable + Light {
fn is_emissive(&self) -> bool;
fn get_material(&self) -> &Material;
}
pub fn load_obj(path: &Path, transform: Matrix4f) -> Result<Vec<ComponentPointer>, tobj::LoadError> {
let parent_path = path.parent().unwrap_or("".as_ref());
let (models, mtls) = tobj::load_obj(path)?;
let mut texturess = HashMap::new();
let mut bumps = HashMap::new();
let mut materials: Vec<Arc<Material>> = Vec::with_capacity(mtls.len()+1);
for mtl in mtls {
let diffuse_texture_path = parent_path.join(mtl.diffuse_texture.clone());
let diffuse = RGBImageTexture::new_as_arc(
ImageInfo{
name: diffuse_texture_path.into_os_string().into_string().unwrap_or_default(),
trilinear: false,
max_aniso: 16. as Float,
wrapping: ImageWrapMode::Repeat,
gamma: false,
scale: 1. as Float,
},
UVMapping{
scaling: Vector2f::new(1. as Float, 1. as Float),
shifting: Vector2f::zero(),
},
&mut texturess
).unwrap_or_else(|| {
if mtl.diffuse_texture != "" {
warn!("diffuse texture {} unfound!", mtl.diffuse_texture);
}
Arc::new(ConstantTexture{value: RGBSpectrum::new(
mtl.diffuse[0], mtl.diffuse[1], mtl.diffuse[2]
) })
});
let specular_texture_path = parent_path.join(mtl.specular_texture.clone());
let specular = RGBImageTexture::new_as_arc(
ImageInfo{
name: specular_texture_path.into_os_string().into_string().unwrap_or_default(),
trilinear: false,
max_aniso: 16. as Float,
wrapping: ImageWrapMode::Repeat,
gamma: false,
scale: 1. as Float,
},
UVMapping{
scaling: Vector2f::new(1. as Float, 1. as Float),
shifting: Vector2f::zero(),
},
&mut texturess
).unwrap_or_else(|| {
if mtl.specular_texture != "" {
warn!("specular texture {} unfound!", mtl.specular_texture);
}
Arc::new(ConstantTexture{value: RGBSpectrum::new(
mtl.specular[0], mtl.specular[1], mtl.specular[2]
) })
});
let roughness = ConstantTexture{
value: ((1000. - mtl.shininess) / 1000.).min(1.).max(0.) as Float
};
let bump = LumaImageTexture::new_as_arc(
ImageInfo{
name: mtl.unknown_param.get("map_bump").map_or_else(|| String::new(), |r| r.to_owned()),
trilinear: false,
max_aniso: 16. as Float,
wrapping: ImageWrapMode::Repeat,
gamma: false,
scale: 1. as Float,
},
UVMapping{
scaling: Vector2f::new(1. as Float, 1. as Float),
shifting: Vector2f::zero(),
},
&mut bumps
);
let illum = mtl.unknown_param.get("illum").map(|a| a.as_ref()).unwrap_or("2");
let dissolve = mtl.dissolve.max(0.).min(1.) as Float;
if illum.contains("4") {
materials.push(Arc::new(GlassMaterial::new(
diffuse, specular, Arc::new(roughness),
mtl.optical_density, bump
)));
} else if !relative_eq!(dissolve, 1.0 as Float) {
materials.push(Arc::new(TranslucentMaterial::new(
diffuse, specular, Arc::new(roughness), dissolve, bump
)));
} else if specular.mean() == RGBSpectrumf::black() || !specular.mean().valid() {
materials.push(Arc::new(MatteMaterial::new(
diffuse, Arc::new(ConstantTexture{value: 0. as Float}),
bump
)));
} else {
materials.push(Arc::new(PlasticMaterial::new(
diffuse, specular, Arc::new(roughness), bump
)));
}
}
materials.push(Arc::new(MatteMaterial::new(
Arc::new(ConstantTexture{
value: RGBSpectrumf::new(0.5 as Float, 0.6 as Float, 0.7 as Float)
}),
Arc::new(ConstantTexture{value: 0. as Float}),
None
)));
let mut shapes: Vec<ComponentPointer> = Vec::new();
for model in models {
let mid = model.mesh.material_id.unwrap_or(materials.len()-1);
let mesh = TriangleMesh::from_model_transformed(model, transform, materials[mid].clone(), None);
for shape in mesh {
shapes.push(
shape.into()
);
}
}
Ok(shapes)
}
#[derive(Clone)]
pub enum ComponentPointer {
Triangle(TriangleInstance),
Arc(Arc<Composable>),
}
impl Composable for ComponentPointer {
#[inline]
fn bbox_parent(&self) -> BBox3f {
match *self {
ComponentPointer::Arc(ref arc) => arc.bbox_parent(),
ComponentPointer::Triangle(ref t) => Composable::bbox_parent(t),
}
}
#[inline]
fn intersect_ray(&self, ray: &mut RawRay) -> Option<SurfaceInteraction> {
match *self {
ComponentPointer::Arc(ref arc) => arc.intersect_ray(ray),
ComponentPointer::Triangle(ref t) => Composable::intersect_ray(t, ray),
}
}
#[inline]
fn can_intersect(&self, ray: &RawRay) -> bool {
match *self {
ComponentPointer::Arc(ref arc) => arc.can_intersect(ray),
ComponentPointer::Triangle(ref t) => Composable::can_intersect(t, ray),
}
}
#[inline]
fn as_light(&self) -> &Light {
match *self {
ComponentPointer::Arc(ref arc) => arc.as_light(),
ComponentPointer::Triangle(ref t) => t.as_light(),
}
}
#[inline]
fn intersection_cost(&self) -> Float {
match *self {
ComponentPointer::Arc(ref arc) => arc.intersection_cost(),
ComponentPointer::Triangle(ref t) => t.intersection_cost(),
}
}
}
impl From<Arc<Composable>> for ComponentPointer {
#[inline]
fn from(arc: Arc<Composable>) -> ComponentPointer {
ComponentPointer::Arc(arc)
}
}
impl From<TriangleInstance> for ComponentPointer {
#[inline]
fn from(t: TriangleInstance) -> ComponentPointer {
ComponentPointer::Triangle(t)
}
}
pub mod shape;
pub mod transformed;
pub mod bvh;
pub mod naive;
pub mod prelude;