use std::collections::HashMap;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct SceneNavMesh {
pub vertices: Vec<[f32; 3]>,
pub triangles: Vec<SceneNavMeshTriangle>,
pub edges: Vec<SceneNavMeshEdge>,
pub adjacency: HashMap<usize, Vec<SceneNavMeshConnection>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SceneNavMeshTriangle {
pub vertex_indices: [usize; 3],
pub center: [f32; 3],
pub normal: [f32; 3],
pub area: f32,
pub edge_indices: [usize; 3],
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SceneNavMeshEdge {
pub vertex_indices: [usize; 2],
pub triangle_indices: [Option<usize>; 2],
pub midpoint: [f32; 3],
pub length: f32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SceneNavMeshConnection {
pub target_triangle: usize,
pub shared_edge: usize,
pub cost: f32,
}
impl SceneNavMesh {
pub fn from_navmesh_world(navmesh: &crate::ecs::navmesh::resources::NavMeshWorld) -> Self {
let vertices: Vec<[f32; 3]> = navmesh.vertices.iter().map(|v| [v.x, v.y, v.z]).collect();
let triangles: Vec<SceneNavMeshTriangle> = navmesh
.triangles
.iter()
.map(|t| SceneNavMeshTriangle {
vertex_indices: t.vertex_indices,
center: [t.center.x, t.center.y, t.center.z],
normal: [t.normal.x, t.normal.y, t.normal.z],
area: t.area,
edge_indices: t.edge_indices,
})
.collect();
let edges: Vec<SceneNavMeshEdge> = navmesh
.edges
.iter()
.map(|e| SceneNavMeshEdge {
vertex_indices: e.vertex_indices,
triangle_indices: e.triangle_indices,
midpoint: [e.midpoint.x, e.midpoint.y, e.midpoint.z],
length: e.length,
})
.collect();
let adjacency: HashMap<usize, Vec<SceneNavMeshConnection>> = navmesh
.adjacency
.iter()
.map(|(key, connections)| {
let scene_connections: Vec<SceneNavMeshConnection> = connections
.iter()
.map(|c| SceneNavMeshConnection {
target_triangle: c.target_triangle,
shared_edge: c.shared_edge,
cost: c.cost,
})
.collect();
(*key, scene_connections)
})
.collect();
Self {
vertices,
triangles,
edges,
adjacency,
}
}
pub fn to_navmesh_world(&self) -> crate::ecs::navmesh::resources::NavMeshWorld {
use crate::ecs::navmesh::resources::{
NavMeshConnection, NavMeshEdge, NavMeshTriangle, NavMeshWorld, SpatialHash,
};
let vertices: Vec<nalgebra_glm::Vec3> = self
.vertices
.iter()
.map(|v| nalgebra_glm::vec3(v[0], v[1], v[2]))
.collect();
let triangles: Vec<NavMeshTriangle> = self
.triangles
.iter()
.map(|t| NavMeshTriangle {
vertex_indices: t.vertex_indices,
center: nalgebra_glm::vec3(t.center[0], t.center[1], t.center[2]),
normal: nalgebra_glm::vec3(t.normal[0], t.normal[1], t.normal[2]),
area: t.area,
edge_indices: t.edge_indices,
})
.collect();
let edges: Vec<NavMeshEdge> = self
.edges
.iter()
.map(|e| NavMeshEdge {
vertex_indices: e.vertex_indices,
triangle_indices: e.triangle_indices,
midpoint: nalgebra_glm::vec3(e.midpoint[0], e.midpoint[1], e.midpoint[2]),
length: e.length,
})
.collect();
let adjacency: HashMap<usize, Vec<NavMeshConnection>> = self
.adjacency
.iter()
.map(|(key, connections)| {
let nav_connections: Vec<NavMeshConnection> = connections
.iter()
.map(|c| NavMeshConnection {
target_triangle: c.target_triangle,
shared_edge: c.shared_edge,
cost: c.cost,
})
.collect();
(*key, nav_connections)
})
.collect();
let mut spatial_hash = SpatialHash::new(2.0);
for (triangle_index, triangle) in triangles.iter().enumerate() {
let vertex_a = vertices[triangle.vertex_indices[0]];
let vertex_b = vertices[triangle.vertex_indices[1]];
let vertex_c = vertices[triangle.vertex_indices[2]];
let min_x = vertex_a.x.min(vertex_b.x).min(vertex_c.x);
let max_x = vertex_a.x.max(vertex_b.x).max(vertex_c.x);
let min_z = vertex_a.z.min(vertex_b.z).min(vertex_c.z);
let max_z = vertex_a.z.max(vertex_b.z).max(vertex_c.z);
spatial_hash.insert_with_bounds(
triangle_index,
nalgebra_glm::vec3(min_x, 0.0, min_z),
nalgebra_glm::vec3(max_x, 0.0, max_z),
);
}
NavMeshWorld {
vertices,
triangles,
edges,
adjacency,
spatial_hash,
debug_draw: false,
debug_entity: None,
algorithm: Default::default(),
}
}
pub fn is_empty(&self) -> bool {
self.triangles.is_empty()
}
}