|
1 use crate::{ |
|
2 common::GearId, |
|
3 collision::{ |
|
4 fppoint_round, |
|
5 CircleBounds, |
|
6 DetectedCollisions |
|
7 } |
|
8 }; |
|
9 |
|
10 use integral_geometry::{ |
|
11 Point, |
|
12 Size, |
|
13 GridIndex |
|
14 }; |
|
15 use fpnum::FPPoint; |
|
16 |
|
17 struct GridBin { |
|
18 refs: Vec<GearId>, |
|
19 static_entries: Vec<CircleBounds>, |
|
20 dynamic_entries: Vec<CircleBounds> |
|
21 } |
|
22 |
|
23 impl GridBin { |
|
24 fn new() -> Self { |
|
25 Self { |
|
26 refs: vec![], |
|
27 static_entries: vec![], |
|
28 dynamic_entries: vec![] |
|
29 } |
|
30 } |
|
31 } |
|
32 |
|
33 const GRID_BIN_SIZE: usize = 256; |
|
34 |
|
35 pub struct Grid { |
|
36 bins: Vec<GridBin>, |
|
37 space_size: Size, |
|
38 bins_count: Size, |
|
39 index: GridIndex |
|
40 } |
|
41 |
|
42 impl Grid { |
|
43 pub fn new(size: Size) -> Self { |
|
44 assert!(size.is_power_of_two()); |
|
45 let bins_count = |
|
46 Size::new(size.width / GRID_BIN_SIZE, |
|
47 size.height / GRID_BIN_SIZE); |
|
48 |
|
49 Self { |
|
50 bins: (0..bins_count.area()).map(|_| GridBin::new()).collect(), |
|
51 space_size: size, |
|
52 bins_count, |
|
53 index: Size::square(GRID_BIN_SIZE).to_grid_index() |
|
54 } |
|
55 } |
|
56 |
|
57 fn bin_index(&self, position: &FPPoint) -> Point { |
|
58 self.index.map(fppoint_round(position)) |
|
59 } |
|
60 |
|
61 fn lookup_bin(&mut self, position: &FPPoint) -> &mut GridBin { |
|
62 let index = self.bin_index(position); |
|
63 &mut self.bins[index.x as usize * self.bins_count.width + index.y as usize] |
|
64 } |
|
65 |
|
66 pub fn insert_static(&mut self, gear_id: GearId, position: &FPPoint, bounds: &CircleBounds) { |
|
67 self.lookup_bin(position).static_entries.push(*bounds) |
|
68 } |
|
69 |
|
70 pub fn insert_dynamic(&mut self, gear_id: GearId, position: &FPPoint, bounds: &CircleBounds) { |
|
71 self.lookup_bin(position).dynamic_entries.push(*bounds) |
|
72 } |
|
73 |
|
74 pub fn check_collisions(&self, collisions: &mut DetectedCollisions) { |
|
75 for bin in &self.bins { |
|
76 for bounds in &bin.dynamic_entries { |
|
77 for other in &bin.dynamic_entries { |
|
78 if bounds.intersects(other) && bounds != other { |
|
79 collisions.push(0, 0, &bounds.center) |
|
80 } |
|
81 } |
|
82 |
|
83 for other in &bin.static_entries { |
|
84 if bounds.intersects(other) { |
|
85 collisions.push(0, 0, &bounds.center) |
|
86 } |
|
87 } |
|
88 } |
|
89 } |
|
90 } |
|
91 } |