use super::{PosNormMesh, PosNormTexMesh};
use building_blocks_core::{
axis::{Axis3Permutation, SignedAxis3},
prelude::*,
};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct OrientedCubeFace {
pub n_sign: i32,
pub permutation: Axis3Permutation,
pub n: Point3i,
pub u: Point3i,
pub v: Point3i,
}
impl OrientedCubeFace {
pub const fn new(n_sign: i32, permutation: Axis3Permutation) -> Self {
let [n_axis, u_axis, v_axis] = permutation.axes();
Self {
n_sign,
permutation,
n: n_axis.get_unit_vector(),
u: u_axis.get_unit_vector(),
v: v_axis.get_unit_vector(),
}
}
pub fn canonical(normal: SignedAxis3) -> Self {
Self::new(
normal.sign,
Axis3Permutation::even_with_normal_axis(normal.axis),
)
}
pub fn quad_from_extent(&self, extent: &Extent3i) -> UnorientedQuad {
UnorientedQuad {
minimum: extent.minimum,
width: self.u.dot(extent.shape),
height: self.v.dot(extent.shape),
}
}
pub fn quad_from_corners(&self, corner1: Point3i, corner2: Point3i) -> UnorientedQuad {
self.quad_from_extent(&Extent3i::from_corners(corner1, corner2))
}
pub fn signed_normal(&self) -> Point3i {
self.n * self.n_sign
}
pub fn mesh_normal(&self) -> Point3f {
self.signed_normal().into()
}
pub fn quad_corners(&self, quad: &UnorientedQuad) -> [Point3i; 4] {
let w_vec = self.u * quad.width;
let h_vec = self.v * quad.height;
let minu_minv = if self.n_sign > 0 {
quad.minimum + self.n
} else {
quad.minimum
};
let maxu_minv = minu_minv + w_vec;
let minu_maxv = minu_minv + h_vec;
let maxu_maxv = minu_minv + w_vec + h_vec;
[minu_minv, maxu_minv, minu_maxv, maxu_maxv]
}
pub fn quad_mesh_positions(&self, quad: &UnorientedQuad, voxel_size: f32) -> [[f32; 3]; 4] {
let [c0, c1, c2, c3] = self.quad_corners(quad);
[
(voxel_size * Point3f::from(c0)).0,
(voxel_size * Point3f::from(c1)).0,
(voxel_size * Point3f::from(c2)).0,
(voxel_size * Point3f::from(c3)).0,
]
}
pub fn quad_mesh_normals(&self) -> [[f32; 3]; 4] {
[self.mesh_normal().0; 4]
}
pub fn quad_mesh_indices(&self, start: u32) -> [u32; 6] {
quad_indices(start, self.n_sign * self.permutation.sign() > 0)
}
pub fn tex_coords(
&self,
u_flip_face: Axis3,
flip_v: bool,
quad: &UnorientedQuad,
) -> [[f32; 2]; 4] {
let face_normal_axis = self.permutation.axes()[0];
let flip_u = if self.n_sign < 0 {
u_flip_face != face_normal_axis
} else {
u_flip_face == face_normal_axis
};
match (flip_u, flip_v) {
(false, false) => [
[0.0, 0.0],
[quad.width as f32, 0.0],
[0.0, quad.height as f32],
[quad.width as f32, quad.height as f32],
],
(true, false) => [
[quad.width as f32, 0.0],
[0.0, 0.0],
[quad.width as f32, quad.height as f32],
[0.0, quad.height as f32],
],
(false, true) => [
[0.0, quad.height as f32],
[quad.width as f32, quad.height as f32],
[0.0, 0.0],
[quad.width as f32, 0.0],
],
(true, true) => [
[quad.width as f32, quad.height as f32],
[0.0, quad.height as f32],
[quad.width as f32, 0.0],
[0.0, 0.0],
],
}
}
pub fn add_quad_to_pos_norm_mesh(
&self,
quad: &UnorientedQuad,
voxel_size: f32,
mesh: &mut PosNormMesh,
) {
let start_index = mesh.positions.len() as u32;
mesh.positions
.extend_from_slice(&self.quad_mesh_positions(quad, voxel_size));
mesh.normals.extend_from_slice(&self.quad_mesh_normals());
mesh.indices
.extend_from_slice(&self.quad_mesh_indices(start_index));
}
pub fn add_quad_to_pos_norm_tex_mesh(
&self,
u_flip_face: Axis3,
flip_v: bool,
quad: &UnorientedQuad,
voxel_size: f32,
mesh: &mut PosNormTexMesh,
) {
let start_index = mesh.positions.len() as u32;
mesh.positions
.extend_from_slice(&self.quad_mesh_positions(quad, voxel_size));
mesh.normals.extend_from_slice(&self.quad_mesh_normals());
mesh.tex_coords
.extend_from_slice(&self.tex_coords(u_flip_face, flip_v, quad));
mesh.indices
.extend_from_slice(&self.quad_mesh_indices(start_index));
}
}
fn quad_indices(start: u32, counter_clockwise: bool) -> [u32; 6] {
if counter_clockwise {
[start, start + 1, start + 2, start + 1, start + 3, start + 2]
} else {
[start, start + 2, start + 1, start + 1, start + 2, start + 3]
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct UnorientedQuad {
pub minimum: Point3i,
pub width: i32,
pub height: i32,
}
impl UnorientedQuad {
pub fn from_voxel(voxel_point: Point3i) -> Self {
Self {
minimum: voxel_point,
width: 1,
height: 1,
}
}
}