mod drop_target_t2_mesh;
mod drop_target_t3_mesh;
mod drop_target_t4_mesh;
mod hit_target_fat_rectangle_mesh;
mod hit_target_fat_square_mesh;
mod hit_target_rectangle_mesh;
mod hit_target_round_mesh;
mod hit_target_t1_slim_mesh;
mod hit_target_t2_slim_mesh;
use crate::vpx::gameitem::hittarget::{HitTarget, TargetType};
use crate::vpx::gameitem::primitive::VertexWrapper;
use crate::vpx::model::Vertex3dNoTex2;
use crate::vpx::obj::VpxFace;
use crate::vpx::math::{Mat3, Vec3};
use drop_target_t2_mesh::{DROP_TARGET_T2_INDICES, DROP_TARGET_T2_MESH};
use drop_target_t3_mesh::{DROP_TARGET_T3_INDICES, DROP_TARGET_T3_MESH};
use drop_target_t4_mesh::{DROP_TARGET_T4_INDICES, DROP_TARGET_T4_MESH};
use hit_target_fat_rectangle_mesh::{
HIT_TARGET_FAT_RECTANGLE_INDICES, HIT_TARGET_FAT_RECTANGLE_MESH,
};
use hit_target_fat_square_mesh::{HIT_TARGET_FAT_SQUARE_INDICES, HIT_TARGET_FAT_SQUARE_MESH};
use hit_target_rectangle_mesh::{HIT_TARGET_RECTANGLE_INDICES, HIT_TARGET_RECTANGLE_MESH};
use hit_target_round_mesh::{HIT_TARGET_ROUND_INDICES, HIT_TARGET_ROUND_MESH};
use hit_target_t1_slim_mesh::{HIT_TARGET_T1_SLIM_INDICES, HIT_TARGET_T1_SLIM_MESH};
use hit_target_t2_slim_mesh::{HIT_TARGET_T2_SLIM_INDICES, HIT_TARGET_T2_SLIM_MESH};
fn get_mesh_for_type(target_type: &TargetType) -> (&'static [Vertex3dNoTex2], &'static [u16]) {
match target_type {
TargetType::DropTargetBeveled => (&DROP_TARGET_T2_MESH, &DROP_TARGET_T2_INDICES),
TargetType::DropTargetSimple => (&DROP_TARGET_T3_MESH, &DROP_TARGET_T3_INDICES),
TargetType::DropTargetFlatSimple => (&DROP_TARGET_T4_MESH, &DROP_TARGET_T4_INDICES),
TargetType::HitTargetRound => (&HIT_TARGET_ROUND_MESH, &HIT_TARGET_ROUND_INDICES),
TargetType::HitTargetRectangle => {
(&HIT_TARGET_RECTANGLE_MESH, &HIT_TARGET_RECTANGLE_INDICES)
}
TargetType::HitFatTargetRectangle => (
&HIT_TARGET_FAT_RECTANGLE_MESH,
&HIT_TARGET_FAT_RECTANGLE_INDICES,
),
TargetType::HitFatTargetSquare => {
(&HIT_TARGET_FAT_SQUARE_MESH, &HIT_TARGET_FAT_SQUARE_INDICES)
}
TargetType::HitTargetSlim => (&HIT_TARGET_T1_SLIM_MESH, &HIT_TARGET_T1_SLIM_INDICES),
TargetType::HitFatTargetSlim => (&HIT_TARGET_T2_SLIM_MESH, &HIT_TARGET_T2_SLIM_INDICES),
}
}
pub fn build_hit_target_mesh(target: &HitTarget) -> Option<(Vec<VertexWrapper>, Vec<VpxFace>)> {
if !target.is_visible {
return None;
}
let (mesh, indices) = get_mesh_for_type(&target.target_type);
let full_matrix = Mat3::rotate_z(target.rot_z.to_radians());
let vertices: Vec<VertexWrapper> = mesh
.iter()
.map(|v| {
let mut vert = Vec3 {
x: v.x * target.size.x,
y: v.y * target.size.y,
z: v.z * target.size.z,
};
vert = full_matrix.multiply_vector(vert);
let norm = full_matrix.multiply_vector_no_translate(Vec3 {
x: v.nx,
y: v.ny,
z: v.nz,
});
VertexWrapper {
vpx_encoded_vertex: [0u8; 32], vertex: Vertex3dNoTex2 {
x: vert.x,
y: vert.y,
z: vert.z,
nx: norm.x,
ny: norm.y,
nz: norm.z,
tu: v.tu,
tv: v.tv,
},
}
})
.collect();
let faces: Vec<VpxFace> = indices
.chunks(3)
.map(|chunk| VpxFace {
i0: chunk[0] as i64,
i1: chunk[1] as i64,
i2: chunk[2] as i64,
})
.collect();
Some((vertices, faces))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::vpx::gameitem::vertex3d::Vertex3D;
fn make_test_target(target_type: TargetType, is_visible: bool) -> HitTarget {
HitTarget {
position: Vertex3D::new(100.0, 200.0, 0.0),
size: Vertex3D::new(32.0, 32.0, 32.0),
rot_z: 0.0,
target_type,
is_visible,
..Default::default()
}
}
#[test]
fn test_build_hit_target_mesh_drop_target_beveled() {
let target = make_test_target(TargetType::DropTargetBeveled, true);
let result = build_hit_target_mesh(&target);
assert!(result.is_some());
let (vertices, faces) = result.unwrap();
assert!(!vertices.is_empty());
assert!(!faces.is_empty());
for v in &vertices {
assert!(v.vertex.x > -50.0 && v.vertex.x < 50.0);
assert!(v.vertex.y > -50.0 && v.vertex.y < 50.0);
}
}
#[test]
fn test_build_hit_target_mesh_invisible() {
let target = make_test_target(TargetType::DropTargetBeveled, false);
let result = build_hit_target_mesh(&target);
assert!(result.is_none());
}
#[test]
fn test_build_hit_target_mesh_all_types() {
let types = [
TargetType::DropTargetBeveled,
TargetType::DropTargetSimple,
TargetType::DropTargetFlatSimple,
TargetType::HitTargetRound,
TargetType::HitTargetRectangle,
TargetType::HitFatTargetRectangle,
TargetType::HitFatTargetSquare,
TargetType::HitTargetSlim,
TargetType::HitFatTargetSlim,
];
for target_type in types {
let target = make_test_target(target_type.clone(), true);
let result = build_hit_target_mesh(&target);
assert!(
result.is_some(),
"Failed to generate mesh for {:?}",
target_type
);
}
}
}