use alloc::vec::Vec;
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::prelude::*;
use glam::{IVec3, Vec2};
use crate::{Aabb2d, AreaType, CompactHeightfield};
impl CompactHeightfield {
pub fn mark_convex_poly_area(&mut self, volume: &ConvexVolume) {
let Some(aabb) = Aabb2d::from_verts(&volume.vertices) else {
return;
};
let aabb = aabb.extend_y(volume.min_y, volume.max_y);
let mut min = aabb.min - self.aabb.min;
min.x /= self.cell_size;
min.y /= self.cell_height;
min.z /= self.cell_size;
let mut max = aabb.max - self.aabb.min;
max.x /= self.cell_size;
max.y /= self.cell_height;
max.z /= self.cell_size;
let mut min = IVec3::new(min.x as i32, min.y as i32, min.z as i32);
let mut max = IVec3::new(max.x as i32, max.y as i32, max.z as i32);
if max.x < 0 || min.x >= self.width as i32 || max.z < 0 || min.z >= self.height as i32 {
return;
}
min.x = min.x.max(0);
max.x = max.x.min(self.width as i32 - 1);
min.z = min.z.max(0);
max.z = max.z.min(self.height as i32 - 1);
for z in min.z..=max.z {
for x in min.x..=max.x {
let cell_index = (x + z * self.width as i32) as usize;
let cell = &self.cells[cell_index];
let max_index = cell.index() as usize + cell.count() as usize;
for i in cell.index() as usize..max_index {
let span = &self.spans[i];
if !self.areas[i].is_walkable() {
continue;
}
if (span.y as i32) < min.y || (span.y as i32) > max.y {
continue;
}
let point = Vec2::new(
self.aabb.min.x + (x as f32 + 0.5) * self.cell_size,
self.aabb.min.z + (z as f32 + 0.5) * self.cell_size,
);
if point_in_poly(&point, &volume.vertices) {
self.areas[i] = volume.area;
}
}
}
}
}
}
fn point_in_poly(point: &Vec2, vertices: &[Vec2]) -> bool {
let mut inside = false;
let mut j = vertices.len() - 1;
for i in 0..vertices.len() {
let xi = vertices[i].x;
let yi = vertices[i].y;
let xj = vertices[j].x;
let yj = vertices[j].y;
if ((yi > point.y) != (yj > point.y))
&& (point.x < (xj - xi) * (point.y - yi) / (yj - yi) + xi)
{
inside = !inside;
}
j = i;
}
inside
}
#[derive(Debug, Default, PartialEq, Clone)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(
all(feature = "serialize", feature = "bevy_reflect"),
reflect(Serialize, Deserialize)
)]
pub struct ConvexVolume {
pub vertices: Vec<Vec2>,
pub min_y: f32,
pub max_y: f32,
pub area: AreaType,
}