use std;
use std::borrow::{Borrow, BorrowMut};
use derive_more::From;
#[cfg(feature = "derive_serdes")]
use serde::{Deserialize, Serialize};
use crate::{collision, component};
use crate::geometry::{self, shape, Shape};
use crate::math::*;
pub type KeyType = u32;
pub const KEY_MAX : KeyType = collision::OBJECT_KEY_MAX;
pub trait Object : Clone + std::fmt::Debug {
fn kind() -> Kind;
fn position (&self) -> &component::Position;
fn position_mut (&mut self) -> &mut component::Position;
}
pub trait Bounded : Object {
fn bound (&self) -> &component::Bound;
fn bound_mut (&mut self) -> &mut component::Bound;
fn hit_test (&self, line_segment : geometry::Segment3 <f64>)
-> Option <(Normalized <f64>, Point3 <f64>)>
{
use geometry::Primitive;
let position = self.position().0;
match &self.bound().0 {
shape::Variant::Bounded (bounded) => match bounded {
shape::Bounded::Sphere (sphere) =>
line_segment.intersect_sphere (sphere.sphere3 (position)),
shape::Bounded::Capsule (capsule) =>
line_segment.intersect_capsule (capsule.capsule3 (position)),
shape::Bounded::Cylinder (cylinder) =>
line_segment.intersect_cylinder (cylinder.cylinder3 (position)),
shape::Bounded::Cuboid (cuboid) =>
line_segment.intersect_aabb (cuboid.aabb3 (position)),
shape::Bounded::Hull (hull) => {
let mut hull = hull.clone();
hull.translate (position.0);
line_segment.intersect_hull (&hull)
}
shape::Bounded::Cone (_cone) => unimplemented!(),
shape::Bounded::Cube (_cube) => unimplemented!(),
}
shape::Variant::Unbounded (unbounded) => match unbounded {
shape::Unbounded::Halfspace (_halfspace) => unimplemented!(),
shape::Unbounded::Orthant (_orthant) => unimplemented!()
}
}.map (|(start, _)| start)
}
fn to_primitive (&self) -> Box <dyn geometry::Primitive <f64, Point3 <f64>>> {
self.bound().0.to_primitive (self.position().0)
}
}
pub trait Temporal : Object {
fn derivatives (&self) -> &component::Derivatives;
fn derivatives_mut (&mut self) -> &mut component::Derivatives;
}
pub trait Inertial : Temporal {
fn mass (&self) -> &component::Mass;
fn mass_mut (&mut self) -> &mut component::Mass;
fn momentum (&self) -> Vector3 <f64> {
self.mass().mass() * self.derivatives().velocity
}
fn compute_acceleration (&self) -> Vector3 <f64> {
self.mass().mass_reciprocal() * self.derivatives().force
}
fn compute_acceleration_inplace (&mut self) {
let acceleration = self.mass().mass_reciprocal() * self.derivatives().force;
self.derivatives_mut().acceleration = acceleration;
}
}
pub trait Massive : Bounded + Inertial {
fn drag (&self) -> f64;
fn density (&self) -> Option <f64> {
use geometry::shape::Stereometric;
if let component::Bound (shape::Variant::Bounded (bounded)) = self.bound() {
Some (self.mass().mass() / *bounded.volume())
} else {
None
}
}
}
pub trait Solid : Bounded {
fn material (&self) -> &component::Material;
fn material_mut (&mut self) -> &mut component::Material;
}
#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Kind {
Static,
Dynamic,
Nodetect
}
#[derive(Clone, Debug, PartialEq, From)]
pub enum Variant {
Static (Static),
Dynamic (Dynamic),
Nodetect (Nodetect)
}
#[derive(Clone, Debug, PartialEq, From)]
pub enum VariantRef <'a> {
Static (&'a Static),
Dynamic (&'a Dynamic),
Nodetect (&'a Nodetect)
}
#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Key (KeyType);
#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Id {
pub kind : Kind,
pub key : Key
}
#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq)]
pub struct Static {
pub position : component::Position,
pub bound : component::Bound,
pub material : component::Material,
pub collidable : bool
}
#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq)]
pub struct Dynamic {
pub position : component::Position,
pub mass : component::Mass,
pub derivatives : component::Derivatives,
pub drag : component::Drag,
pub bound : component::Bound,
pub material : component::Material,
pub collidable : bool
}
#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq)]
pub struct Nodetect {
pub position : component::Position,
pub mass : component::Mass,
pub derivatives : component::Derivatives,
pub drag : component::Drag
}
pub fn report_sizes() {
use std::mem::size_of;
println!("object report sizes...");
println!(" size of Variant: {}", size_of::<Variant>());
println!(" size of Static: {}", size_of::<Static>());
println!(" size of Dynamic: {}", size_of::<Dynamic>());
println!(" size of Nodetect: {}", size_of::<Nodetect>());
println!("...object report sizes");
}
impl Variant {
pub const fn kind (&self) -> Kind {
match self {
Variant::Static (_) => Kind::Static,
Variant::Dynamic (_) => Kind::Dynamic,
Variant::Nodetect (_) => Kind::Nodetect
}
}
}
impl Static {
pub (crate) fn aabb_dilated (&self) -> geometry::Aabb3 <f64> {
use shape::Aabb;
self.aabb().dilate (0.5 * collision::CONTACT_DISTANCE).unwrap()
}
}
impl Object for Static {
fn kind() -> Kind { Kind::Static }
fn position (&self) -> &component::Position {
&self.position
}
fn position_mut (&mut self) -> &mut component::Position {
&mut self.position
}
}
impl Bounded for Static {
fn bound (&self) -> &component::Bound {
&self.bound
}
fn bound_mut (&mut self) -> &mut component::Bound {
&mut self.bound
}
}
impl shape::Aabb <f64> for Static {
fn aabb (&self) -> geometry::Aabb3 <f64> {
let component::Bound (variant) = &self.bound;
let aabb_shape = variant.aabb();
geometry::Aabb3::with_minmax_unchecked (
aabb_shape.min() + self.position().0.0,
aabb_shape.max() + self.position().0.0)
}
}
impl shape::Stereometric <f64> for Static {
fn volume (&self) -> Positive <f64> {
let component::Bound (variant) = &self.bound;
variant.volume()
}
}
impl Dynamic {
pub (crate) fn aabb_dilated (&self) -> geometry::Aabb3 <f64> {
use shape::Aabb;
self.aabb().dilate (0.5 * collision::CONTACT_DISTANCE).unwrap()
}
}
impl Object for Dynamic {
fn kind() -> Kind { Kind::Dynamic }
fn position (&self) -> &component::Position {
&self.position
}
fn position_mut (&mut self) -> &mut component::Position {
&mut self.position
}
}
impl Bounded for Dynamic {
fn bound (&self) -> &component::Bound {
&self.bound
}
fn bound_mut (&mut self) -> &mut component::Bound {
&mut self.bound
}
}
impl Temporal for Dynamic {
fn derivatives (&self) -> &component::Derivatives {
&self.derivatives
}
fn derivatives_mut (&mut self) -> &mut component::Derivatives {
&mut self.derivatives
}
}
impl Inertial for Dynamic {
fn mass (&self) -> &component::Mass {
&self.mass
}
fn mass_mut (&mut self) -> &mut component::Mass {
&mut self.mass
}
}
impl Borrow <component::Derivatives> for Dynamic {
fn borrow (&self) -> &component::Derivatives {
&self.derivatives
}
}
impl BorrowMut <component::Derivatives> for Dynamic {
fn borrow_mut (&mut self) -> &mut component::Derivatives {
&mut self.derivatives
}
}
impl shape::Aabb <f64> for Dynamic {
fn aabb (&self) -> geometry::Aabb3 <f64> {
let component::Bound (variant) = &self.bound;
let aabb_shape = variant.aabb();
geometry::Aabb3::with_minmax_unchecked (
aabb_shape.min() + self.position().0.0,
aabb_shape.max() + self.position().0.0)
}
}
impl shape::Stereometric <f64> for Dynamic {
fn volume (&self) -> Positive <f64> {
let component::Bound (variant) = &self.bound;
variant.volume()
}
}
impl Object for Nodetect {
fn kind() -> Kind { Kind::Nodetect }
fn position (&self) -> &component::Position {
&self.position
}
fn position_mut (&mut self) -> &mut component::Position {
&mut self.position
}
}
impl Temporal for Nodetect {
fn derivatives (&self) -> &component::Derivatives {
&self.derivatives
}
fn derivatives_mut (&mut self) -> &mut component::Derivatives {
&mut self.derivatives
}
}
impl Inertial for Nodetect {
fn mass (&self) -> &component::Mass {
&self.mass
}
fn mass_mut (&mut self) -> &mut component::Mass {
&mut self.mass
}
}
impl Borrow <component::Derivatives> for Nodetect {
fn borrow (&self) -> &component::Derivatives {
&self.derivatives
}
}
impl BorrowMut <component::Derivatives> for Nodetect {
fn borrow_mut (&mut self) -> &mut component::Derivatives {
&mut self.derivatives
}
}
impl Key {
pub const fn from_raw (key : KeyType) -> Self {
Key (key)
}
pub const fn value (&self) -> KeyType {
self.0
}
pub const fn index (&self) -> usize {
self.0 as usize
}
}
impl std::ops::Deref for Key {
type Target = KeyType;
fn deref (&self) -> &KeyType {
&self.0
}
}
impl From <KeyType> for Key {
fn from (key : KeyType) -> Self {
debug_assert!(key < KEY_MAX);
Key (key)
}
}
impl From <usize> for Key {
fn from (key : usize) -> Self {
debug_assert!((key as KeyType) < KEY_MAX);
Key (key as KeyType)
}
}
impl Object for (component::Position, component::Bound) {
fn kind() -> Kind {
Kind::Static
}
fn position (&self) -> &component::Position {
&self.0
}
fn position_mut (&mut self) -> &mut component::Position {
&mut self.0
}
}
impl Bounded for (component::Position, component::Bound) {
fn bound (&self) -> &component::Bound {
&self.1
}
fn bound_mut (&mut self) -> &mut component::Bound {
&mut self.1
}
}