update hwphysics motion to use the new system
authoralfadur
Wed, 28 Aug 2019 23:06:34 +0300
changeset 15401 6e3e5be8b2e2
parent 15400 27915135f87f
child 15402 52844baced17
update hwphysics motion to use the new system
rust/hwphysics/src/collision.rs
rust/hwphysics/src/common.rs
rust/hwphysics/src/data.rs
rust/hwphysics/src/lib.rs
rust/hwphysics/src/physics.rs
--- a/rust/hwphysics/src/collision.rs	Wed Aug 28 22:53:40 2019 +0300
+++ b/rust/hwphysics/src/collision.rs	Wed Aug 28 23:06:34 2019 +0300
@@ -1,9 +1,6 @@
 use std::ops::RangeInclusive;
 
-use crate::{
-    common::{GearData, GearDataProcessor, GearId},
-    grid::Grid,
-};
+use crate::{common::GearId, data::GearDataManager, grid::Grid};
 
 use fpnum::*;
 use integral_geometry::{Point, Size};
@@ -37,16 +34,12 @@
     pub bounds: CircleBounds,
 }
 
-impl GearData for CollisionData {}
-
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
 pub struct ContactData {
     pub elasticity: FPNum,
     pub friction: FPNum,
 }
 
-impl GearData for ContactData {}
-
 struct EnabledCollisionsCollection {
     gear_ids: Vec<GearId>,
     collisions: Vec<CollisionData>,
@@ -107,6 +100,11 @@
 }
 
 impl CollisionProcessor {
+    pub fn register_components(data: &mut GearDataManager) {
+        data.register::<CollisionData>();
+        data.register::<ContactData>();
+    }
+
     pub fn new(size: Size) -> Self {
         Self {
             grid: Grid::new(size),
@@ -115,6 +113,18 @@
         }
     }
 
+    pub fn add(&mut self, gear_id: GearId, gear_data: CollisionData) {
+        self.grid.insert_static(gear_id, &gear_data.bounds);
+    }
+
+    pub fn remove(&mut self, gear_id: GearId) {
+        self.grid.remove(gear_id);
+    }
+
+    pub fn get(&mut self, gear_id: GearId) -> Option<CollisionData> {
+        None
+    }
+
     pub fn process(
         &mut self,
         land: &Land2D<u32>,
@@ -141,17 +151,3 @@
         &self.detected_collisions
     }
 }
-
-impl GearDataProcessor<CollisionData> for CollisionProcessor {
-    fn add(&mut self, gear_id: GearId, gear_data: CollisionData) {
-        self.grid.insert_static(gear_id, &gear_data.bounds);
-    }
-
-    fn remove(&mut self, gear_id: GearId) {
-        self.grid.remove(gear_id);
-    }
-
-    fn get(&mut self, gear_id: GearId) -> Option<CollisionData> {
-        None
-    }
-}
--- a/rust/hwphysics/src/common.rs	Wed Aug 28 22:53:40 2019 +0300
+++ b/rust/hwphysics/src/common.rs	Wed Aug 28 23:06:34 2019 +0300
@@ -6,7 +6,6 @@
 };
 
 pub type GearId = NonZeroU16;
-pub trait GearData {}
 
 #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
 #[repr(transparent)]
@@ -37,16 +36,6 @@
     }
 }
 
-pub trait GearDataProcessor<T: GearData> {
-    fn add(&mut self, gear_id: GearId, gear_data: T);
-    fn remove(&mut self, gear_id: GearId);
-    fn get(&mut self, gear_id: GearId) -> Option<T>;
-}
-
-pub trait GearDataAggregator<T: GearData> {
-    fn find_processor(&mut self) -> &mut GearDataProcessor<T>;
-}
-
 pub struct GearAllocator {
     max_id: u16,
     free_ids: BinaryHeap<GearId>,
@@ -73,91 +62,3 @@
         self.free_ids.push(gear_id)
     }
 }
-
-#[derive(Clone, Copy, Default)]
-pub struct LookupEntry<T> {
-    index: Option<NonZeroU16>,
-    value: T,
-}
-
-impl<T> LookupEntry<T> {
-    #[inline]
-    pub fn index(&self) -> u16 {
-        self.index.map(|i| i.get()).unwrap_or(0) - 1
-    }
-
-    #[inline]
-    pub fn set_index(&mut self, index: u16) {
-        self.index = unsafe { Some(NonZeroU16::new_unchecked(index.saturating_add(1))) };
-    }
-
-    #[inline]
-    pub fn value(&self) -> &T {
-        &self.value
-    }
-
-    #[inline]
-    pub fn value_mut(&mut self) -> &mut T {
-        &mut self.value
-    }
-
-    #[inline]
-    pub fn set_value(&mut self, value: T) {
-        self.value = value;
-    }
-}
-
-pub struct GearDataLookup<T> {
-    lookup: Box<[LookupEntry<T>]>,
-}
-
-impl<T: Default + Copy> GearDataLookup<T> {
-    pub fn new() -> Self {
-        Self {
-            lookup: vec![LookupEntry::default(); u16::max_value() as usize].into_boxed_slice(),
-        }
-    }
-}
-
-impl<T> GearDataLookup<T> {
-    pub fn add(&mut self, gear_id: GearId, index: u16, value: T) {
-        // All possible Gear IDs are valid indices
-        let entry = unsafe { self.lookup.get_unchecked_mut(gear_id.get() as usize - 1) };
-        entry.set_index(index);
-        entry.set_value(value);
-    }
-
-    pub fn get(&self, gear_id: GearId) -> Option<&LookupEntry<T>> {
-        // All possible Gear IDs are valid indices
-        let entry = unsafe { self.lookup.get_unchecked(gear_id.get() as usize - 1) };
-        if let Some(index) = entry.index {
-            Some(entry)
-        } else {
-            None
-        }
-    }
-
-    pub fn get_mut(&mut self, gear_id: GearId) -> Option<&mut LookupEntry<T>> {
-        // All possible Gear IDs are valid indices
-        let entry = unsafe { self.lookup.get_unchecked_mut(gear_id.get() as usize - 1) };
-        if let Some(index) = entry.index {
-            Some(entry)
-        } else {
-            None
-        }
-    }
-}
-
-impl<T> Index<GearId> for GearDataLookup<T> {
-    type Output = LookupEntry<T>;
-
-    fn index(&self, index: GearId) -> &Self::Output {
-        self.get(index).unwrap()
-    }
-}
-
-impl<T> IndexMut<GearId> for GearDataLookup<T> {
-    fn index_mut(&mut self, index: GearId) -> &mut Self::Output {
-        self.get_mut(index).unwrap()
-    }
-}
--- a/rust/hwphysics/src/data.rs	Wed Aug 28 22:53:40 2019 +0300
+++ b/rust/hwphysics/src/data.rs	Wed Aug 28 23:06:34 2019 +0300
@@ -23,10 +23,8 @@
 
             unsafe fn iter<F: FnMut(GearId, Self)>(slices: &[*mut u8], count: usize, mut f: F) {
                 for i in 0..count {
-                    unsafe {
-                        f(*(*slices.get_unchecked(0) as *const GearId).add(i),
-                          ($(&*(*slices.get_unchecked($n + 1) as *mut $t).add(i)),+,));
-                    }
+                    f(*(*slices.get_unchecked(0) as *const GearId).add(i),
+                      ($(&*(*slices.get_unchecked($n + 1) as *mut $t).add(i)),+,));
                 }
             }
         }
@@ -38,10 +36,8 @@
 
             unsafe fn iter<F: FnMut(GearId, Self)>(slices: &[*mut u8], count: usize, mut f: F) {
                 for i in 0..count {
-                    unsafe {
-                        f(*(*slices.get_unchecked(0) as *const GearId).add(i),
-                          ($(&mut *(*slices.get_unchecked($n + 1) as *mut $t).add(i)),+,));
-                    }
+                    f(*(*slices.get_unchecked(0) as *const GearId).add(i),
+                      ($(&mut *(*slices.get_unchecked($n + 1) as *mut $t).add(i)),+,));
                 }
             }
         }
@@ -382,7 +378,6 @@
         }
     }
 
-
     pub fn iter<T: TypeTuple + 'static, F: FnMut(T)>(&mut self, mut f: F) {
         self.iter_id(|_, x| f(x));
     }
--- a/rust/hwphysics/src/lib.rs	Wed Aug 28 22:53:40 2019 +0300
+++ b/rust/hwphysics/src/lib.rs	Wed Aug 28 23:06:34 2019 +0300
@@ -10,41 +10,28 @@
 
 use crate::{
     collision::{CollisionData, CollisionProcessor, ContactData},
-    common::{GearAllocator, GearData, GearDataAggregator, GearDataProcessor, GearId, Millis},
-    physics::{PhysicsData, PhysicsProcessor},
+    common::{GearAllocator, GearId, Millis},
+    data::GearDataManager,
+    physics::PhysicsProcessor,
     time::TimeProcessor,
 };
 
-pub struct JoinedData {
-    gear_id: GearId,
-    physics: PhysicsData,
-    collision: CollisionData,
-    contact: ContactData,
-}
-
 pub struct World {
     allocator: GearAllocator,
+    data: GearDataManager,
     physics: PhysicsProcessor,
     collision: CollisionProcessor,
     time: TimeProcessor,
 }
 
-macro_rules! processor_map {
-    ( $data_type: ident => $field: ident ) => {
-        impl GearDataAggregator<$data_type> for World {
-            fn find_processor(&mut self) -> &mut GearDataProcessor<$data_type> {
-                &mut self.$field
-            }
-        }
-    };
-}
-
-processor_map!(PhysicsData => physics);
-processor_map!(CollisionData => collision);
-
 impl World {
     pub fn new(world_size: Size) -> Self {
+        let mut data = GearDataManager::new();
+        PhysicsProcessor::register_components(&mut data);
+        CollisionProcessor::register_components(&mut data);
+
         Self {
+            data,
             allocator: GearAllocator::new(),
             physics: PhysicsProcessor::new(),
             collision: CollisionProcessor::new(world_size),
@@ -59,24 +46,21 @@
 
     #[inline]
     pub fn delete_gear(&mut self, gear_id: GearId) {
-        self.physics.remove(gear_id);
+        self.data.remove_all(gear_id);
         self.collision.remove(gear_id);
         self.time.cancel(gear_id);
         self.allocator.free(gear_id)
     }
 
     pub fn step(&mut self, time_step: Millis, land: &Land2D<u32>) {
-        let updates = self.physics.process(time_step);
-        let collision = self.collision.process(land, &updates);
+        let updates = self.physics.process(&mut self.data, time_step);
+        let collisions = self.collision.process(land, &updates);
         let events = self.time.process(time_step);
     }
 
-    pub fn add_gear_data<T>(&mut self, gear_id: GearId, data: T)
-    where
-        T: GearData,
-        Self: GearDataAggregator<T>,
-    {
-        self.find_processor().add(gear_id, data);
+    #[inline]
+    pub fn add_gear_data<T: Clone + 'static>(&mut self, gear_id: GearId, data: &T) {
+        self.data.add(gear_id, data);
     }
 }
 
@@ -85,7 +69,7 @@
     use crate::{
         collision::{CircleBounds, CollisionData},
         common::Millis,
-        physics::PhysicsData,
+        physics::{PositionData, VelocityData},
         World,
     };
     use fpnum::{fp, FPNum, FPPoint};
@@ -97,19 +81,14 @@
         let world_size = Size::new(2048, 2048);
 
         let mut world = World::new(world_size);
-        let gear_id = std::num::NonZeroU16::new(46631).unwrap();
+        let gear_id = world.new_gear().unwrap();
+
+        world.add_gear_data(gear_id, &PositionData(FPPoint::zero()));
+        world.add_gear_data(gear_id, &VelocityData(FPPoint::unit_y()));
 
         world.add_gear_data(
             gear_id,
-            PhysicsData {
-                position: FPPoint::zero(),
-                velocity: FPPoint::unit_y(),
-            },
-        );
-
-        world.add_gear_data(
-            gear_id,
-            CollisionData {
+            &CollisionData {
                 bounds: CircleBounds {
                     center: FPPoint::zero(),
                     radius: fp!(10),
--- a/rust/hwphysics/src/physics.rs	Wed Aug 28 22:53:40 2019 +0300
+++ b/rust/hwphysics/src/physics.rs	Wed Aug 28 23:06:34 2019 +0300
@@ -1,97 +1,18 @@
-use crate::common::{GearData, GearDataLookup, GearDataProcessor, GearId, Millis};
+use crate::{
+    common::{GearId, Millis},
+    data::GearDataManager,
+};
 use fpnum::*;
 
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub struct PhysicsData {
-    pub position: FPPoint,
-    pub velocity: FPPoint,
-}
-
-impl GearData for PhysicsData {}
-
-impl PhysicsData {
-    pub fn new(position: FPPoint, velocity: FPPoint) -> Self {
-        Self { position, velocity }
-    }
-}
-
-pub struct DynamicPhysicsCollection {
-    gear_ids: Vec<GearId>,
-    positions: Vec<FPPoint>,
-    velocities: Vec<FPPoint>,
-}
-
-impl DynamicPhysicsCollection {
-    fn new() -> Self {
-        Self {
-            gear_ids: Vec::new(),
-            positions: Vec::new(),
-            velocities: Vec::new(),
-        }
-    }
-
-    fn len(&self) -> usize {
-        self.gear_ids.len()
-    }
-
-    fn push(&mut self, gear_id: GearId, physics: PhysicsData) -> u16 {
-        self.gear_ids.push(gear_id);
-        self.positions.push(physics.position);
-        self.velocities.push(physics.velocity);
-
-        (self.gear_ids.len() - 1) as u16
-    }
+#[repr(transparent)]
+pub struct PositionData(pub FPPoint);
 
-    fn remove(&mut self, index: usize) -> Option<GearId> {
-        self.gear_ids.swap_remove(index);
-        self.positions.swap_remove(index);
-        self.velocities.swap_remove(index);
-
-        self.gear_ids.get(index).cloned()
-    }
-
-    fn iter_pos_update(&mut self) -> impl Iterator<Item = (GearId, (&mut FPPoint, &FPPoint))> {
-        self.gear_ids
-            .iter()
-            .cloned()
-            .zip(self.positions.iter_mut().zip(self.velocities.iter()))
-    }
-}
-
-pub struct StaticPhysicsCollection {
-    gear_ids: Vec<GearId>,
-    positions: Vec<FPPoint>,
-}
-
-impl StaticPhysicsCollection {
-    fn new() -> Self {
-        Self {
-            gear_ids: Vec::new(),
-            positions: Vec::new(),
-        }
-    }
-
-    fn push(&mut self, gear_id: GearId, physics: PhysicsData) -> u16 {
-        self.gear_ids.push(gear_id);
-        self.positions.push(physics.position);
-
-        (self.gear_ids.len() - 1) as u16
-    }
-
-    fn remove(&mut self, index: usize) -> Option<GearId> {
-        self.gear_ids.swap_remove(index);
-        self.positions.swap_remove(index);
-
-        self.gear_ids.get(index).cloned()
-    }
-}
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+#[repr(transparent)]
+pub struct VelocityData(pub FPPoint);
 
 pub struct PhysicsProcessor {
-    gear_lookup: GearDataLookup<bool>,
-    dynamic_physics: DynamicPhysicsCollection,
-    static_physics: StaticPhysicsCollection,
-
-    physics_cleanup: Vec<GearId>,
     position_updates: PositionUpdates,
 }
 
@@ -128,75 +49,31 @@
 }
 
 impl PhysicsProcessor {
+    pub fn register_components(data: &mut GearDataManager) {
+        data.register::<PositionData>();
+        data.register::<VelocityData>();
+    }
+
     pub fn new() -> Self {
         Self {
-            gear_lookup: GearDataLookup::new(),
-            dynamic_physics: DynamicPhysicsCollection::new(),
-            static_physics: StaticPhysicsCollection::new(),
-            physics_cleanup: Vec::new(),
-            position_updates: PositionUpdates::new(0),
+            position_updates: PositionUpdates::new(64),
         }
     }
 
-    pub fn process(&mut self, time_step: Millis) -> &PositionUpdates {
+    pub fn process(&mut self, data: &mut GearDataManager, time_step: Millis) -> &PositionUpdates {
         let fp_step = time_step.to_fixed();
         self.position_updates.clear();
-        for (gear_id, (pos, vel)) in self.dynamic_physics.iter_pos_update() {
-            let old_pos = *pos;
-            *pos += *vel * fp_step;
-            if !vel.is_zero() {
-                self.position_updates.push(gear_id, &old_pos, pos)
-            } else {
-                self.physics_cleanup.push(gear_id)
-            }
-        }
+
+        data.iter_id(
+            |gear_id, (pos, vel): (&mut PositionData, &mut VelocityData)| {
+                if !vel.0.is_zero() {
+                    let old_pos = pos.0;
+                    pos.0 += vel.0 * fp_step;
+                    self.position_updates.push(gear_id, &old_pos, &pos.0)
+                }
+            },
+        );
+
         &self.position_updates
     }
 }
-
-impl GearDataProcessor<PhysicsData> for PhysicsProcessor {
-    fn add(&mut self, gear_id: GearId, gear_data: PhysicsData) {
-        let is_dynamic = !gear_data.velocity.is_zero();
-        let index = if is_dynamic {
-            self.dynamic_physics.push(gear_id, gear_data)
-        } else {
-            self.static_physics.push(gear_id, gear_data)
-        };
-
-        self.gear_lookup.add(gear_id, index, is_dynamic);
-    }
-
-    fn remove(&mut self, gear_id: GearId) {
-        if let Some(entry) = self.gear_lookup.get(gear_id) {
-            let relocated_gear_id = if *entry.value() {
-                self.dynamic_physics.remove(entry.index() as usize)
-            } else {
-                self.static_physics.remove(entry.index() as usize)
-            };
-
-            if let Some(id) = relocated_gear_id {
-                let index = entry.index();
-                self.gear_lookup[id].set_index(index);
-            }
-        }
-    }
-
-    fn get(&mut self, gear_id: GearId) -> Option<PhysicsData> {
-        if let Some(entry) = self.gear_lookup.get(gear_id) {
-            let data = if *entry.value() {
-                PhysicsData {
-                    position: self.dynamic_physics.positions[entry.index() as usize],
-                    velocity: self.dynamic_physics.velocities[entry.index() as usize],
-                }
-            } else {
-                PhysicsData {
-                    position: self.static_physics.positions[entry.index() as usize],
-                    velocity: FPPoint::zero(),
-                }
-            };
-            Some(data)
-        } else {
-            None
-        }
-    }
-}