use std::sync::{Arc, RwLock};
use amethyst_core::{
ecs::{Component, DenseVecStorage, FlaggedStorage},
math::Isometry3,
};
use crate::PtReal;
macro_rules! define_opaque_object {
($what:ident, $gc_name:ident) => {
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum $what {
#[allow(missing_docs)]
U32(u32),
#[allow(missing_docs)]
U64(u64),
#[allow(missing_docs)]
U32U32(u32, u32),
#[allow(missing_docs)]
U64U64(u64, u64),
#[allow(missing_docs)]
UsizeU32(usize, u32),
#[allow(missing_docs)]
UsizeU64(usize, u64),
}
impl $what {
#[allow(missing_docs)]
pub unsafe fn new_u32(a: u32) -> Self {
$what::U32(a)
}
#[allow(missing_docs)]
pub unsafe fn new_u64(a: u64) -> Self {
$what::U64(a)
}
#[allow(missing_docs)]
pub unsafe fn new_u32u32(a: u32, b: u32) -> Self {
$what::U32U32(a, b)
}
#[allow(missing_docs)]
pub unsafe fn new_u64u64(a: u64, b: u64) -> Self {
$what::U64U64(a, b)
}
#[allow(missing_docs)]
pub unsafe fn new_usizeu32(a: usize, b: u32) -> Self {
$what::UsizeU32(a, b)
}
#[allow(missing_docs)]
pub unsafe fn new_usizeu64(a: usize, b: u64) -> Self {
$what::UsizeU64(a, b)
}
}
impl PhysicsTag for $what {
fn request_resource_removal(&mut self, gc: &mut PhysicsGarbageCollector) {
gc.$gc_name.push(*self);
}
}
};
}
define_opaque_object!(PhysicsRigidBodyTag, bodies);
define_opaque_object!(PhysicsAreaTag, areas);
define_opaque_object!(PhysicsShapeTag, shapes);
define_opaque_object!(PhysicsJointTag, joints);
pub(crate) type PhysicsSetupStorages<'a> = (
amethyst_core::ecs::ReadStorage<'a, PhysicsHandle<PhysicsRigidBodyTag>>,
amethyst_core::ecs::ReadStorage<'a, PhysicsHandle<PhysicsAreaTag>>,
amethyst_core::ecs::ReadStorage<'a, PhysicsHandle<PhysicsShapeTag>>,
amethyst_core::ecs::ReadStorage<'a, PhysicsHandle<PhysicsJointTag>>,
);
pub trait PhysicsTag: Copy + std::fmt::Debug + Sync + Send + Sized + 'static {
fn request_resource_removal(&mut self, gc: &mut PhysicsGarbageCollector);
}
pub struct PhysicsHandle<T: PhysicsTag> {
tag_container: Arc<PhysicsTagContainer<T>>,
}
impl<T: PhysicsTag> PhysicsHandle<T> {
pub fn new(tag: T, garbage_collector: Arc<RwLock<PhysicsGarbageCollector>>) -> Self {
PhysicsHandle {
tag_container: Arc::new(PhysicsTagContainer {
tag,
garbage_collector,
}),
}
}
pub fn get(&self) -> T {
self.tag_container.tag
}
}
impl<T: PhysicsTag> std::fmt::Debug for PhysicsHandle<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"PhysicsHandle{{\n tag = {:?}\n owner = {}\n weak = {}\n}};",
self.get(),
Arc::strong_count(&self.tag_container),
Arc::weak_count(&self.tag_container)
)
}
}
impl<T: PhysicsTag> Clone for PhysicsHandle<T> {
fn clone(&self) -> Self {
PhysicsHandle {
tag_container: self.tag_container.clone(),
}
}
}
impl<T: PhysicsTag> Component for PhysicsHandle<T> {
type Storage = FlaggedStorage<PhysicsHandle<T>, DenseVecStorage<PhysicsHandle<T>>>;
}
struct PhysicsTagContainer<T: PhysicsTag> {
tag: T,
garbage_collector: Arc<RwLock<PhysicsGarbageCollector>>,
}
impl<T: PhysicsTag> std::ops::Drop for PhysicsTagContainer<T> {
fn drop(&mut self) {
let mut gc = self.garbage_collector.write().unwrap();
self.tag.request_resource_removal(&mut gc);
}
}
#[derive(Debug)]
pub struct PhysicsGarbageCollector {
pub bodies: Vec<PhysicsRigidBodyTag>,
pub areas: Vec<PhysicsAreaTag>,
pub shapes: Vec<PhysicsShapeTag>,
pub joints: Vec<PhysicsJointTag>,
}
impl Default for PhysicsGarbageCollector {
fn default() -> Self {
PhysicsGarbageCollector {
bodies: Vec::new(),
areas: Vec::new(),
shapes: Vec::new(),
joints: Vec::new(),
}
}
}
#[allow(missing_debug_implementations)]
pub struct PhysicsAttachment<N: PtReal> {
pub(crate) cache_world_transform: Isometry3<N>,
}
impl<N: PtReal> Component for PhysicsAttachment<N> {
type Storage = DenseVecStorage<Self>;
}
impl<N: PtReal> Default for PhysicsAttachment<N> {
fn default() -> Self {
PhysicsAttachment {
cache_world_transform: Isometry3::identity(),
}
}
}
#[derive(Debug, Copy, Clone)]
pub struct CollisionGroup(u8);
impl Default for CollisionGroup {
fn default() -> Self {
CollisionGroup(1u8)
}
}
impl CollisionGroup {
pub fn new(group: u8) -> Self {
assert!(group < 29);
CollisionGroup(group)
}
pub fn get(self) -> u8 {
self.0
}
}