rust/hwphysics/src/lib.rs
changeset 14199 a4c17cfaa4c9
parent 14165 165e43c3ed59
child 14200 abbb74b9cb62
--- a/rust/hwphysics/src/lib.rs	Thu Nov 08 22:00:43 2018 +0100
+++ b/rust/hwphysics/src/lib.rs	Fri Nov 09 01:05:34 2018 +0300
@@ -1,191 +1,45 @@
-use std::{
-    ops::RangeInclusive
-};
+mod common;
+mod physics;
+mod grid;
+mod collision;
 
-use fpnum::*;
-use integral_geometry::{
-    Point, Size, GridIndex
-};
+use fpnum::FPNum;
 use land2d::Land2D;
 
-type Index = u16;
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-struct PhysicsData {
-    position: FPPoint,
-    velocity: FPPoint,
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-struct  CollisionData {
-    bounds: CircleBounds
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-struct ContactData {
-    elasticity: FPNum,
-    friction: FPNum
-}
-
-pub struct PhysicsCollection {
-    positions: Vec<FPPoint>,
-    velocities: Vec<FPPoint>
-}
-
-impl PhysicsCollection {
-    fn push(&mut self, data: PhysicsData) {
-        self.positions.push(data.position);
-        self.velocities.push(data.velocity);
+use crate::{
+    common::GearId,
+    physics::{
+        PhysicsProcessor,
+        PhysicsData
+    },
+    collision::{
+        CollisionProcessor,
+        CollisionData,
+        ContactData
     }
-
-    fn iter_mut_pos(&mut self) -> impl Iterator<Item = (&mut FPPoint, &FPPoint)> {
-        self.positions.iter_mut().zip(self.velocities.iter())
-    }
-}
+};
 
 pub struct JoinedData {
+    gear_id: GearId,
     physics: PhysicsData,
     collision: CollisionData,
     contact: ContactData
 }
 
 pub struct World {
-    enabled_physics: PhysicsCollection,
-    disabled_physics: Vec<PhysicsData>,
-
-    enabled_collision: Vec<CollisionData>,
-    disabled_collision: Vec<CollisionData>,
-    grid: Grid,
-
-    physics_cleanup: Vec<PhysicsData>,
-    collision_output: Vec<(Index, Index)>,
-    land_collision_output: Vec<Index>
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-struct CircleBounds {
-    center: FPPoint,
-    radius: FPNum
-}
-
-impl CircleBounds {
-    pub fn intersects(&self, other: &CircleBounds) -> bool {
-        (other.center - self.center).is_in_range(self.radius + other.radius)
-    }
-
-    pub fn rows(&self) -> impl Iterator<Item = (usize, RangeInclusive<usize>)> {
-        let radius = self.radius.abs_round() as usize;
-        let center = Point::from_fppoint(&self.center);
-        (center.y as usize - radius..=center.y as usize + radius)
-            .map(move |row| (row, center.x as usize - radius..=center.x as usize + radius))
-    }
-}
-
-fn fppoint_round(point: &FPPoint) -> Point {
-    Point::new(point.x().round() as i32, point.y().round() as i32)
-}
-
-struct GridBin {
-    refs: Vec<Index>,
-    static_entries: Vec<CircleBounds>,
-    dynamic_entries: Vec<CircleBounds>
-}
-
-impl GridBin {
-    fn new() -> Self {
-        Self {
-            refs: vec![],
-            static_entries: vec![],
-            dynamic_entries: vec![]
-        }
-    }
-}
-
-const GRID_BIN_SIZE: usize = 256;
-
-struct Grid {
-    bins: Vec<GridBin>,
-    space_size: Size,
-    bins_count: Size,
-    index: GridIndex
-}
-
-impl Grid {
-    fn new(size: Size) -> Self {
-        assert!(size.is_power_of_two());
-        let bins_count =
-            Size::new(size.width / GRID_BIN_SIZE,
-                      size.height / GRID_BIN_SIZE);
-
-        Self {
-            bins: (0..bins_count.area()).map(|_| GridBin::new()).collect(),
-            space_size: size,
-            bins_count,
-            index: Size::square(GRID_BIN_SIZE).to_grid_index()
-        }
-    }
-
-    fn bin_index(&self, position: &FPPoint) -> Point {
-        self.index.map(fppoint_round(position))
-    }
-
-    fn lookup_bin(&mut self, position: &FPPoint) -> &mut GridBin {
-        let index = self.bin_index(position);
-        &mut self.bins[index.x as usize * self.bins_count.width + index.y as usize]
-    }
-
-    fn insert_static(&mut self, index: Index, position: &FPPoint, bounds: &CircleBounds) {
-        self.lookup_bin(position).static_entries.push(*bounds)
-    }
-
-    fn insert_dynamic(&mut self, index: Index, position: &FPPoint, bounds: &CircleBounds) {
-        self.lookup_bin(position).dynamic_entries.push(*bounds)
-    }
-
-    fn check_collisions(&self, collisions: &mut Vec<(Index, Index)>) {
-        for bin in &self.bins {
-            for bounds in &bin.dynamic_entries {
-                for other in &bin.dynamic_entries {
-                    if bounds.intersects(other) && bounds != other {
-                        collisions.push((0, 0))
-                    }
-                }
-
-                for other in &bin.static_entries {
-                    if bounds.intersects(other) {
-                        collisions.push((0, 0))
-                    }
-                }
-            }
-        }
-    }
+    physics: PhysicsProcessor,
+    collision: CollisionProcessor,
 }
 
 impl World {
     pub fn step(&mut self, time_step: FPNum, land: &Land2D<u32>) {
-        for (pos, vel) in self.enabled_physics.iter_mut_pos() {
-            *pos += *vel
-        }
-
-        self.grid.check_collisions(&mut self.collision_output);
-    }
-
-    fn check_land_collisions(&mut self, land: &Land2D<u32>) {
-        for collision in &self.enabled_collision {
-            if collision.bounds.rows().any(|(y, r)| (&land[y][r]).iter().any(|v| *v != 0)) {
-                self.land_collision_output.push(0)
-            }
-        }
+        let updates = self.physics.process(time_step);
+        self.collision.process(land, &updates);
     }
 
     pub fn add_gear(&mut self, data: JoinedData) {
-        if data.physics.velocity == FPPoint::zero() {
-            self.disabled_physics.push(data.physics);
-            self.grid.insert_static(0, &data.physics.position, &data.collision.bounds);
-        } else {
-            self.enabled_physics.push(data.physics);
-            self.grid.insert_dynamic(0, &data.physics.position, &data.collision.bounds);
-        }
+        self.physics.push(data.gear_id, data.physics);
+        self.collision.push(data.gear_id, data.physics, data.collision);
     }
 }