use crate::{
core::{
algebra::{Matrix4, Point3, Vector3},
inspect::{Inspect, PropertyInfo},
math::aabb::AxisAlignedBoundingBox,
pool::Handle,
visitor::{Visit, VisitResult, Visitor},
},
scene::{
base::{Base, BaseBuilder},
graph::Graph,
mesh::{
buffer::{VertexAttributeUsage, VertexReadTrait},
surface::Surface,
},
node::Node,
},
};
use std::{
cell::Cell,
ops::{Deref, DerefMut},
};
use strum_macros::{AsRefStr, EnumString, EnumVariantNames};
pub mod buffer;
pub mod surface;
pub mod vertex;
#[derive(
Copy,
Clone,
PartialOrd,
PartialEq,
Eq,
Ord,
Hash,
Debug,
Visit,
Inspect,
AsRefStr,
EnumString,
EnumVariantNames,
)]
#[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, Inspect)]
pub struct Mesh {
base: Base,
surfaces: Vec<Surface>,
#[inspect(skip)]
local_bounding_box: Cell<AxisAlignedBoundingBox>,
#[inspect(skip)]
local_bounding_box_dirty: Cell<bool>,
#[inspect(skip)]
world_bounding_box: Cell<AxisAlignedBoundingBox>,
cast_shadows: bool,
render_path: RenderPath,
decal_layer_index: u8,
}
impl Default for Mesh {
fn default() -> Self {
Self {
base: Default::default(),
surfaces: Default::default(),
local_bounding_box: Default::default(),
world_bounding_box: Default::default(),
local_bounding_box_dirty: Cell::new(true),
cast_shadows: true,
render_path: RenderPath::Deferred,
decal_layer_index: 0,
}
}
}
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 _ = self.decal_layer_index.visit("DecalLayerIndex", 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.local_bounding_box_dirty.set(true);
}
#[inline]
pub fn add_surface(&mut self, surface: Surface) {
self.surfaces.push(surface);
self.local_bounding_box_dirty.set(true);
}
#[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 local_bounding_box(&self) -> AxisAlignedBoundingBox {
self.local_bounding_box.get()
}
pub fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
self.world_bounding_box.get()
}
pub(in crate) fn update(&self, graph: &Graph) {
if self.local_bounding_box_dirty.get() {
let mut bounding_box = AxisAlignedBoundingBox::default();
for surface in self.surfaces.iter() {
let data = surface.data();
let data = data.lock();
for view in data.vertex_buffer.iter() {
bounding_box
.add_point(view.read_3_f32(VertexAttributeUsage::Position).unwrap());
}
}
self.local_bounding_box.set(bounding_box);
self.local_bounding_box_dirty.set(false);
}
if self.surfaces.iter().any(|s| !s.bones.is_empty()) {
let mut world_aabb = self
.local_bounding_box()
.transform(&self.global_transform());
for surface in self.surfaces.iter() {
for &bone in surface.bones() {
world_aabb.add_point(graph[bone].global_position())
}
}
self.world_bounding_box.set(world_aabb)
} else {
self.world_bounding_box.set(
self.local_bounding_box()
.transform(&self.global_transform()),
);
}
}
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 accurate_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.lock();
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 set_decal_layer_index(&mut self, index: u8) {
self.decal_layer_index = index;
}
pub fn decal_layer_index(&self) -> u8 {
self.decal_layer_index
}
pub fn raw_copy(&self) -> Self {
Self {
base: self.base.raw_copy(),
surfaces: self.surfaces.clone(),
local_bounding_box: self.local_bounding_box.clone(),
local_bounding_box_dirty: self.local_bounding_box_dirty.clone(),
world_bounding_box: Default::default(),
cast_shadows: self.cast_shadows,
render_path: self.render_path,
decal_layer_index: self.decal_layer_index,
}
}
}
pub struct MeshBuilder {
base_builder: BaseBuilder,
surfaces: Vec<Surface>,
cast_shadows: bool,
render_path: RenderPath,
decal_layer_index: u8,
}
impl MeshBuilder {
pub fn new(base_builder: BaseBuilder) -> Self {
Self {
base_builder,
surfaces: Default::default(),
cast_shadows: true,
render_path: RenderPath::Deferred,
decal_layer_index: 0,
}
}
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 with_decal_layer_index(mut self, decal_layer_index: u8) -> Self {
self.decal_layer_index = decal_layer_index;
self
}
pub fn build_node(self) -> Node {
Node::Mesh(Mesh {
base: self.base_builder.build_base(),
cast_shadows: self.cast_shadows,
surfaces: self.surfaces,
local_bounding_box: Default::default(),
local_bounding_box_dirty: Cell::new(true),
render_path: self.render_path,
decal_layer_index: self.decal_layer_index,
world_bounding_box: Default::default(),
})
}
pub fn build(self, graph: &mut Graph) -> Handle<Node> {
graph.add_node(self.build_node())
}
}