use crate::core::*;
use crate::renderer::*;
use super::BaseMesh;
pub struct Mesh {
base_mesh: BaseMesh,
context: Context,
aabb: AxisAlignedBoundingBox,
transformation: Mat4,
current_transformation: Mat4,
animation: Option<Box<dyn Fn(f32) -> Mat4 + Send + Sync>>,
}
impl Mesh {
pub fn new(context: &Context, cpu_mesh: &CpuMesh) -> Self {
let aabb = cpu_mesh.compute_aabb();
Self {
context: context.clone(),
base_mesh: BaseMesh::new(context, cpu_mesh),
aabb,
transformation: Mat4::identity(),
current_transformation: Mat4::identity(),
animation: None,
}
}
pub(in crate::renderer) fn set_transformation_2d(&mut self, transformation: Mat3) {
self.set_transformation(Mat4::new(
transformation.x.x,
transformation.x.y,
0.0,
transformation.x.z,
transformation.y.x,
transformation.y.y,
0.0,
transformation.y.z,
0.0,
0.0,
1.0,
0.0,
transformation.z.x,
transformation.z.y,
0.0,
transformation.z.z,
));
}
pub fn transformation(&self) -> Mat4 {
self.transformation
}
pub fn set_transformation(&mut self, transformation: Mat4) {
self.transformation = transformation;
self.current_transformation = transformation;
}
pub fn set_animation(&mut self, animation: impl Fn(f32) -> Mat4 + Send + Sync + 'static) {
self.animation = Some(Box::new(animation));
}
}
impl<'a> IntoIterator for &'a Mesh {
type Item = &'a dyn Geometry;
type IntoIter = std::iter::Once<&'a dyn Geometry>;
fn into_iter(self) -> Self::IntoIter {
std::iter::once(self)
}
}
impl Geometry for Mesh {
fn aabb(&self) -> AxisAlignedBoundingBox {
let mut aabb = self.aabb;
aabb.transform(&self.current_transformation);
aabb
}
fn animate(&mut self, time: f32) {
if let Some(animation) = &self.animation {
self.current_transformation = self.transformation * animation(time);
}
}
fn draw(
&self,
camera: &Camera,
program: &Program,
render_states: RenderStates,
attributes: FragmentAttributes,
) {
if attributes.normal {
if let Some(inverse) = self.current_transformation.invert() {
program.use_uniform("normalMatrix", inverse.transpose());
} else {
return;
}
}
program.use_uniform("viewProjection", camera.projection() * camera.view());
program.use_uniform("modelMatrix", self.current_transformation);
self.base_mesh
.draw(program, render_states, camera, attributes);
}
fn vertex_shader_source(&self, required_attributes: FragmentAttributes) -> String {
format!(
"{}{}{}{}{}{}",
if required_attributes.normal {
"#define USE_NORMALS\n"
} else {
""
},
if required_attributes.tangents {
"#define USE_TANGENTS\n"
} else {
""
},
if required_attributes.uv {
"#define USE_UVS\n"
} else {
""
},
if required_attributes.color && self.base_mesh.colors.is_some() {
"#define USE_VERTEX_COLORS\n"
} else {
""
},
include_str!("../../core/shared.frag"),
include_str!("shaders/mesh.vert"),
)
}
fn id(&self, required_attributes: FragmentAttributes) -> u16 {
let mut id = 0b1u16 << 15 | 0b1u16 << 4;
if required_attributes.normal {
id |= 0b1u16;
}
if required_attributes.tangents {
id |= 0b1u16 << 1;
}
if required_attributes.uv {
id |= 0b1u16 << 2;
}
if required_attributes.color && self.base_mesh.colors.is_some() {
id |= 0b1u16 << 3;
}
id
}
fn render_with_material(
&self,
material: &dyn Material,
camera: &Camera,
lights: &[&dyn Light],
) {
render_with_material(&self.context, camera, &self, material, lights);
}
fn render_with_effect(
&self,
material: &dyn Effect,
camera: &Camera,
lights: &[&dyn Light],
color_texture: Option<ColorTexture>,
depth_texture: Option<DepthTexture>,
) {
render_with_effect(
&self.context,
camera,
self,
material,
lights,
color_texture,
depth_texture,
)
}
}