voxel_tile_raycast/
lib.rs1use nalgebra::{Vector3, Vector2};
2
3pub mod na {
4 pub use nalgebra::*;
5}
6
7#[cfg(all(feature = "f64", feature = "f32"))]
8compile_error!("f32 and f64 features can not be enabled together");
9
10#[cfg(not(any(feature = "f64", feature = "f32")))]
11compile_error!("f32 or f64 feature should be enabled");
12
13#[cfg(feature = "f64")]
14type Real = f64;
15
16#[cfg(feature = "f32")]
17type Real = f32;
18
19macro_rules! raycast {
20 ($func: ident, $vec_i: ident, $vec_indexes: expr, $stepped_index_func: ident) => {
21 pub fn $func(
22 origin: $vec_i<Real>,
23 dir: $vec_i<Real>,
24 max_dir: Real,
25 mut func: impl FnMut($vec_i<i32>, $vec_i<Real>, $vec_i<i32>) -> bool,
26 ) {
27 if dir == $vec_i::zeros() {
28 panic!("dir is zero");
29 }
30 let dir = dir.normalize();
31 let mut t = 0.0;
32 let mut index = origin.map(|val| val.floor() as i32);
33 let step = dir.map(|val| val.signum() as i32);
34 let t_delta = dir.map(|val| 1.0 / val).abs();
35 let dist = $vec_indexes.map(|val| {
36 if step[val] > 0 {
37 index[val] as Real + 1.0 - origin[val]
38 } else {
39 origin[val] - index[val] as Real
40 }
41 });
42 let mut t_max = $vec_indexes.map(|val| {
43 if t_delta[val] < Real::INFINITY {
44 t_delta[val] * dist[val]
45 } else {
46 Real::INFINITY
47 }
48 });
49
50 if !func(
51 index,
52 $vec_indexes.map(|val| origin[val] + t * dist[val]),
53 $vec_i::zeros(),
54 ) {
55 while t < max_dir {
56 let stepped_index = $stepped_index_func(t_max);
57
58 index[stepped_index] += step[stepped_index];
59 t = t_max[stepped_index];
60 t_max[stepped_index] += t_delta[stepped_index];
61
62 if func(
63 index,
64 $vec_indexes.map(|val| origin[val] + t * dist[val]),
65 {
66 let mut hit_norm = $vec_i::zeros();
67 hit_norm[stepped_index] = -step[stepped_index];
68 hit_norm
69 },
70 ) {
71 break;
72 }
73 }
74 }
75 }
76 };
77}
78
79#[cfg(feature = "voxel")]
80fn voxel_stepped_index(t_max: Vector3<Real>) -> usize {
81 if t_max.x < t_max.y && t_max.x < t_max.z {
82 0
83 } else if t_max.y < t_max.z {
84 1
85 } else {
86 2
87 }
88}
89
90#[cfg(feature = "tile")]
91fn tile_stepped_index(t_max: Vector2<Real>) -> usize {
92 if t_max.x < t_max.y {
93 0
94 } else {
95 1
96 }
97}
98
99#[cfg(feature = "voxel")]
100raycast!(voxel_raycast, Vector3, Vector3::new(0, 1, 2), voxel_stepped_index);
101#[cfg(feature = "tile")]
102raycast!(tile_raycast, Vector2, Vector2::new(0, 1), tile_stepped_index);