steel_core/player/game_mode/
raycast.rs1use super::{ClipBlockShape, ClipFluid, DVec3, World, WorldAabb, swap};
2
3pub(super) fn piercing_ray_hit_t(
4 world: &World,
5 bounding_box: WorldAabb,
6 from: DVec3,
7 to: DVec3,
8 entity_margin: f64,
9) -> Option<f64> {
10 if let Some(hit_t) = ray_aabb_hit_t(bounding_box, from, to) {
11 return Some(hit_t);
12 }
13 if entity_margin <= 0.0 {
14 return None;
15 }
16
17 let outside_hit_t = ray_aabb_hit_t(bounding_box.inflate(entity_margin), from, to)?;
18 let outside_hit = from + (to - from) * outside_hit_t;
19 let mut towards_target = DVec3::new(
20 f64::midpoint(bounding_box.min_x(), bounding_box.max_x()),
21 f64::midpoint(bounding_box.min_y(), bounding_box.max_y()),
22 f64::midpoint(bounding_box.min_z(), bounding_box.max_z()),
23 );
24 let block_hit = world.clip(
25 outside_hit,
26 towards_target,
27 ClipBlockShape::Collider,
28 ClipFluid::None,
29 );
30 if !block_hit.is_miss() {
31 towards_target = block_hit.location;
32 }
33 ray_aabb_hit_t(bounding_box, outside_hit, towards_target).map(|_| outside_hit_t)
34}
35
36fn ray_aabb_hit_t(aabb: WorldAabb, from: DVec3, to: DVec3) -> Option<f64> {
37 if aabb.contains(from) {
38 return Some(0.0);
39 }
40
41 let delta = to - from;
42 let mut t_min = 0.0_f64;
43 let mut t_max = 1.0_f64;
44 if !update_ray_axis(
45 from.x,
46 delta.x,
47 aabb.min_x(),
48 aabb.max_x(),
49 &mut t_min,
50 &mut t_max,
51 ) {
52 return None;
53 }
54 if !update_ray_axis(
55 from.y,
56 delta.y,
57 aabb.min_y(),
58 aabb.max_y(),
59 &mut t_min,
60 &mut t_max,
61 ) {
62 return None;
63 }
64 if !update_ray_axis(
65 from.z,
66 delta.z,
67 aabb.min_z(),
68 aabb.max_z(),
69 &mut t_min,
70 &mut t_max,
71 ) {
72 return None;
73 }
74
75 Some(t_min)
76}
77
78fn update_ray_axis(
79 start: f64,
80 delta: f64,
81 min: f64,
82 max: f64,
83 t_min: &mut f64,
84 t_max: &mut f64,
85) -> bool {
86 if delta.abs() < f64::EPSILON {
87 return start >= min && start <= max;
88 }
89
90 let inverse_delta = 1.0 / delta;
91 let mut enter = (min - start) * inverse_delta;
92 let mut exit = (max - start) * inverse_delta;
93 if enter > exit {
94 swap(&mut enter, &mut exit);
95 }
96
97 *t_min = (*t_min).max(enter);
98 *t_max = (*t_max).min(exit);
99 *t_min <= *t_max
100}