use crate::scene::mesh::buffer::{VertexAttributeUsage, VertexReadTrait};
use crate::{
core::{
algebra::{Matrix4, Point3, Vector3},
color::Color,
math::{aabb::AxisAlignedBoundingBox, frustum::Frustum},
pool::Handle,
visitor::{Visit, VisitResult, Visitor},
},
scene::{
base::{Base, BaseBuilder},
graph::Graph,
mesh::surface::Surface,
node::Node,
},
};
use std::{
cell::Cell,
ops::{Deref, DerefMut},
};
pub mod buffer;
pub mod surface;
pub mod vertex;
#[derive(Copy, Clone, PartialOrd, PartialEq, Eq, Ord, Hash, Debug)]
#[repr(u32)]
pub enum RenderPath {
Deferred = 0,
Forward = 1,
}
impl Default for RenderPath {
fn default() -> Self {
Self::Deferred
}
}
impl RenderPath {
pub fn from_id(id: u32) -> Result<Self, String> {
match id {
0 => Ok(Self::Deferred),
1 => Ok(Self::Forward),
_ => Err(format!("Invalid render path id {}!", id)),
}
}
}
#[derive(Debug)]
pub struct Mesh {
base: Base,
surfaces: Vec<Surface>,
bounding_box: Cell<AxisAlignedBoundingBox>,
bounding_box_dirty: Cell<bool>,
cast_shadows: bool,
render_path: RenderPath,
}
impl Default for Mesh {
fn default() -> Self {
Self {
base: Default::default(),
surfaces: Default::default(),
bounding_box: Default::default(),
bounding_box_dirty: Cell::new(true),
cast_shadows: true,
render_path: RenderPath::Deferred,
}
}
}
impl Deref for Mesh {
type Target = Base;
fn deref(&self) -> &Self::Target {
&self.base
}
}
impl DerefMut for Mesh {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.base
}
}
impl Visit for Mesh {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.base.visit("Common", visitor)?;
self.cast_shadows.visit("CastShadows", visitor)?;
let mut render_path = self.render_path as u32;
render_path.visit("RenderPath", visitor)?;
if visitor.is_reading() {
self.render_path = RenderPath::from_id(render_path)?;
}
self.surfaces.visit("Surfaces", visitor)?;
visitor.leave_region()
}
}
impl Mesh {
#[inline]
pub fn surfaces(&self) -> &[Surface] {
&self.surfaces
}
#[inline]
pub fn surfaces_mut(&mut self) -> &mut [Surface] {
&mut self.surfaces
}
#[inline]
pub fn clear_surfaces(&mut self) {
self.surfaces.clear();
self.bounding_box_dirty.set(true);
}
#[inline]
pub fn add_surface(&mut self, surface: Surface) {
self.surfaces.push(surface);
self.bounding_box_dirty.set(true);
}
#[inline]
pub fn set_color(&mut self, color: Color) {
for surface in self.surfaces.iter_mut() {
surface.set_color(color);
}
}
#[inline]
pub fn cast_shadows(&self) -> bool {
self.cast_shadows
}
#[inline]
pub fn set_cast_shadows(&mut self, cast_shadows: bool) {
self.cast_shadows = cast_shadows;
}
pub fn bounding_box(&self) -> AxisAlignedBoundingBox {
if self.bounding_box_dirty.get() {
let mut bounding_box = AxisAlignedBoundingBox::default();
for surface in self.surfaces.iter() {
let data = surface.data();
let data = data.read().unwrap();
for view in data.vertex_buffer.iter() {
bounding_box
.add_point(view.read_3_f32(VertexAttributeUsage::Position).unwrap());
}
}
self.bounding_box.set(bounding_box);
self.bounding_box_dirty.set(false);
}
self.bounding_box.get()
}
pub fn set_render_path(&mut self, render_path: RenderPath) {
self.render_path = render_path;
}
pub fn render_path(&self) -> RenderPath {
self.render_path
}
pub fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
let mut bounding_box = AxisAlignedBoundingBox::default();
for surface in self.surfaces.iter() {
let data = surface.data();
let data = data.read().unwrap();
for view in data.vertex_buffer.iter() {
bounding_box.add_point(
self.global_transform()
.transform_point(&Point3::from(
view.read_3_f32(VertexAttributeUsage::Position).unwrap(),
))
.coords,
);
}
}
bounding_box
}
pub fn full_world_bounding_box(&self, graph: &Graph) -> AxisAlignedBoundingBox {
let mut bounding_box = AxisAlignedBoundingBox::default();
for surface in self.surfaces.iter() {
let data = surface.data();
let data = data.read().unwrap();
if surface.bones().is_empty() {
for view in data.vertex_buffer.iter() {
bounding_box.add_point(
self.global_transform()
.transform_point(&Point3::from(
view.read_3_f32(VertexAttributeUsage::Position).unwrap(),
))
.coords,
);
}
} else {
let bone_matrices = surface
.bones()
.iter()
.map(|&b| {
let bone_node = &graph[b];
bone_node.global_transform() * bone_node.inv_bind_pose_transform()
})
.collect::<Vec<Matrix4<f32>>>();
for view in data.vertex_buffer.iter() {
let mut position = Vector3::default();
for (&bone_index, &weight) in view
.read_4_u8(VertexAttributeUsage::BoneIndices)
.unwrap()
.iter()
.zip(
view.read_4_f32(VertexAttributeUsage::BoneWeight)
.unwrap()
.iter(),
)
{
position += bone_matrices[bone_index as usize]
.transform_point(&Point3::from(
view.read_3_f32(VertexAttributeUsage::Position).unwrap(),
))
.coords
.scale(weight);
}
bounding_box.add_point(position);
}
}
}
bounding_box
}
pub fn is_intersect_frustum(&self, graph: &Graph, frustum: &Frustum) -> bool {
if frustum.is_intersects_aabb_transform(&self.bounding_box(), &self.global_transform.get())
{
return true;
}
for surface in self.surfaces.iter() {
for &bone in surface.bones.iter() {
if frustum.is_contains_point(graph[bone].global_position()) {
return true;
}
}
}
false
}
pub fn raw_copy(&self) -> Self {
Self {
base: self.base.raw_copy(),
surfaces: self.surfaces.clone(),
bounding_box: self.bounding_box.clone(),
bounding_box_dirty: self.bounding_box_dirty.clone(),
cast_shadows: self.cast_shadows,
render_path: self.render_path,
}
}
}
pub struct MeshBuilder {
base_builder: BaseBuilder,
surfaces: Vec<Surface>,
cast_shadows: bool,
render_path: RenderPath,
}
impl MeshBuilder {
pub fn new(base_builder: BaseBuilder) -> Self {
Self {
base_builder,
surfaces: Default::default(),
cast_shadows: true,
render_path: RenderPath::Deferred,
}
}
pub fn with_surfaces(mut self, surfaces: Vec<Surface>) -> Self {
self.surfaces = surfaces;
self
}
pub fn with_cast_shadows(mut self, cast_shadows: bool) -> Self {
self.cast_shadows = cast_shadows;
self
}
pub fn with_render_path(mut self, render_path: RenderPath) -> Self {
self.render_path = render_path;
self
}
pub fn build_node(self) -> Node {
Node::Mesh(Mesh {
base: self.base_builder.build_base(),
cast_shadows: self.cast_shadows,
surfaces: self.surfaces,
bounding_box: Default::default(),
bounding_box_dirty: Cell::new(true),
render_path: self.render_path,
})
}
pub fn build(self, graph: &mut Graph) -> Handle<Node> {
graph.add_node(self.build_node())
}
}