use crate::scene::node::constructor::NodeConstructor;
use crate::{
core::{
color::Color,
math::aabb::AxisAlignedBoundingBox,
parking_lot::RwLock,
pool::Handle,
reflect::prelude::*,
type_traits::prelude::*,
uuid::{uuid, Uuid},
variable::InheritableVariable,
visitor::prelude::*,
},
scene::{
base::{Base, BaseBuilder},
debug::{Line, SceneDrawingContext},
graph::Graph,
node::{Node, NodeTrait},
},
utils::navmesh::Navmesh,
};
use fyrox_core::algebra::Vector3;
use fyrox_core::math::TriangleDefinition;
use fyrox_core::parking_lot::{RwLockReadGuard, RwLockWriteGuard};
use fyrox_graph::constructor::ConstructorProvider;
use fyrox_graph::SceneGraph;
use std::{
ops::{Deref, DerefMut},
sync::Arc,
};
#[derive(Clone, Default, Reflect, Debug)]
pub(crate) struct Container(Arc<RwLock<Navmesh>>);
impl PartialEq for Container {
fn eq(&self, other: &Self) -> bool {
*self.0.read() == *other.0.read()
}
}
impl Visit for Container {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
self.0.write().visit(name, visitor)
}
}
#[derive(Debug, Clone, Visit, Reflect, Default, ComponentProvider)]
#[reflect(derived_type = "Node")]
pub struct NavigationalMesh {
base: Base,
#[reflect(read_only)]
navmesh: InheritableVariable<Container>,
}
impl TypeUuidProvider for NavigationalMesh {
fn type_uuid() -> Uuid {
uuid!("d0ce963c-b50a-4707-bd21-af6dc0d1c668")
}
}
impl Deref for NavigationalMesh {
type Target = Base;
fn deref(&self) -> &Self::Target {
&self.base
}
}
impl DerefMut for NavigationalMesh {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.base
}
}
impl ConstructorProvider<Node, Graph> for NavigationalMesh {
fn constructor() -> NodeConstructor {
NodeConstructor::new::<Self>().with_variant("Navmesh", |_| {
let navmesh = Navmesh::new(
vec![TriangleDefinition([0, 1, 2]), TriangleDefinition([0, 2, 3])],
vec![
Vector3::new(-1.0, 0.0, 1.0),
Vector3::new(1.0, 0.0, 1.0),
Vector3::new(1.0, 0.0, -1.0),
Vector3::new(-1.0, 0.0, -1.0),
],
);
NavigationalMeshBuilder::new(BaseBuilder::new().with_name("Navmesh"))
.with_navmesh(navmesh)
.build_node()
.into()
})
}
}
impl NodeTrait for NavigationalMesh {
fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
self.base.local_bounding_box()
}
fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
self.base.world_bounding_box()
}
fn id(&self) -> Uuid {
Self::type_uuid()
}
fn debug_draw(&self, ctx: &mut SceneDrawingContext) {
let navmesh = self.navmesh.0.read();
for vertex in navmesh.vertices().iter() {
ctx.draw_sphere(*vertex, 6, 6, 0.1, Color::GREEN);
}
for triangle in navmesh.triangles().iter() {
for edge in &triangle.edges() {
ctx.add_line(Line {
begin: navmesh.vertices()[edge.a as usize],
end: navmesh.vertices()[edge.b as usize],
color: Color::GREEN,
});
}
}
}
}
impl NavigationalMesh {
pub fn navmesh_ref(&self) -> RwLockReadGuard<Navmesh> {
self.navmesh.0.read()
}
pub fn navmesh_mut(&mut self) -> RwLockWriteGuard<Navmesh> {
self.navmesh.0.write()
}
pub fn navmesh(&self) -> Arc<RwLock<Navmesh>> {
self.navmesh.0.clone()
}
}
pub struct NavigationalMeshBuilder {
base_builder: BaseBuilder,
navmesh: Navmesh,
}
impl NavigationalMeshBuilder {
pub fn new(base_builder: BaseBuilder) -> Self {
Self {
base_builder,
navmesh: Default::default(),
}
}
pub fn with_navmesh(mut self, navmesh: Navmesh) -> Self {
self.navmesh = navmesh;
self
}
fn build_navigational_mesh(self) -> NavigationalMesh {
NavigationalMesh {
base: self.base_builder.build_base(),
navmesh: InheritableVariable::new_modified(Container(Arc::new(RwLock::new(
self.navmesh,
)))),
}
}
pub fn build_node(self) -> Node {
Node::new(self.build_navigational_mesh())
}
pub fn build(self, graph: &mut Graph) -> Handle<NavigationalMesh> {
graph.add_node(self.build_node()).to_variant()
}
}