use serde::{Deserialize, Serialize};
use crate::ecs::physics::components::{ColliderComponent, ColliderShape, RigidBodyComponent};
use crate::ecs::physics::types::{InteractionGroups, LockedAxes, RigidBodyType};
use super::asset_uuid::AssetUuid;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
pub enum SceneBodyType {
#[default]
Static,
Dynamic,
KinematicPositionBased,
KinematicVelocityBased,
}
impl SceneBodyType {
pub fn to_body_type(self) -> RigidBodyType {
match self {
SceneBodyType::Static => RigidBodyType::Fixed,
SceneBodyType::Dynamic => RigidBodyType::Dynamic,
SceneBodyType::KinematicPositionBased => RigidBodyType::KinematicPositionBased,
SceneBodyType::KinematicVelocityBased => RigidBodyType::KinematicVelocityBased,
}
}
}
impl From<RigidBodyType> for SceneBodyType {
fn from(body_type: RigidBodyType) -> Self {
match body_type {
RigidBodyType::Fixed => SceneBodyType::Static,
RigidBodyType::Dynamic => SceneBodyType::Dynamic,
RigidBodyType::KinematicPositionBased => SceneBodyType::KinematicPositionBased,
RigidBodyType::KinematicVelocityBased => SceneBodyType::KinematicVelocityBased,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScenePhysics {
pub body_type: SceneBodyType,
pub collider: SceneCollider,
#[serde(default = "default_friction")]
pub friction: f32,
#[serde(default = "default_restitution")]
pub restitution: f32,
#[serde(default)]
pub mass: Option<f32>,
#[serde(default)]
pub is_sensor: bool,
#[serde(default = "default_collision_membership")]
pub collision_membership: u32,
#[serde(default = "default_collision_filter")]
pub collision_filter: u32,
#[serde(default = "default_solver_membership")]
pub solver_membership: u32,
#[serde(default = "default_solver_filter")]
pub solver_filter: u32,
#[serde(default)]
pub locked_axes: LockedAxes,
}
fn default_collision_membership() -> u32 {
0xFFFFFFFF
}
fn default_collision_filter() -> u32 {
0xFFFFFFFF
}
fn default_solver_membership() -> u32 {
0xFFFFFFFF
}
fn default_solver_filter() -> u32 {
0xFFFFFFFF
}
fn default_friction() -> f32 {
0.8
}
fn default_restitution() -> f32 {
0.1
}
impl Default for ScenePhysics {
fn default() -> Self {
Self {
body_type: SceneBodyType::Static,
collider: SceneCollider::Cuboid {
half_extents: [0.5, 0.5, 0.5],
},
friction: default_friction(),
restitution: default_restitution(),
mass: None,
is_sensor: false,
collision_membership: default_collision_membership(),
collision_filter: default_collision_filter(),
solver_membership: default_solver_membership(),
solver_filter: default_solver_filter(),
locked_axes: LockedAxes::default(),
}
}
}
impl ScenePhysics {
pub fn static_cuboid(half_extents: [f32; 3]) -> Self {
Self {
collider: SceneCollider::Cuboid { half_extents },
..Default::default()
}
}
pub fn dynamic_ball(radius: f32, mass: f32) -> Self {
Self {
body_type: SceneBodyType::Dynamic,
collider: SceneCollider::Ball { radius },
friction: 0.7,
restitution: 0.3,
mass: Some(mass),
..Default::default()
}
}
pub fn dynamic_cuboid(half_extents: [f32; 3], mass: f32) -> Self {
Self {
body_type: SceneBodyType::Dynamic,
collider: SceneCollider::Cuboid { half_extents },
friction: 0.7,
restitution: 0.2,
mass: Some(mass),
..Default::default()
}
}
pub fn to_rigid_body(&self) -> RigidBodyComponent {
let mut body = match self.body_type {
SceneBodyType::Static => RigidBodyComponent::new_static(),
SceneBodyType::Dynamic => RigidBodyComponent::new_dynamic(),
SceneBodyType::KinematicPositionBased => RigidBodyComponent::new_kinematic(),
SceneBodyType::KinematicVelocityBased => RigidBodyComponent {
body_type: RigidBodyType::KinematicVelocityBased,
..Default::default()
},
};
if let Some(mass) = self.mass {
body = body.with_mass(mass);
}
body.locked_axes = self.locked_axes;
body
}
pub fn to_collider(&self) -> ColliderComponent {
let mut collider = match &self.collider {
SceneCollider::Cuboid { half_extents } => {
ColliderComponent::new_cuboid(half_extents[0], half_extents[1], half_extents[2])
}
SceneCollider::Ball { radius } => ColliderComponent::new_ball(*radius),
SceneCollider::Cylinder {
half_height,
radius,
} => ColliderComponent::new_cylinder(*half_height, *radius),
SceneCollider::Capsule {
half_height,
radius,
} => ColliderComponent::new_capsule(*half_height, *radius),
SceneCollider::TriMesh { vertices, indices } => ColliderComponent {
shape: ColliderShape::TriMesh {
vertices: vertices.clone(),
indices: indices.clone(),
},
..Default::default()
},
SceneCollider::ConvexHull { points } => ColliderComponent {
shape: ColliderShape::ConvexMesh {
vertices: points.clone(),
},
..Default::default()
},
SceneCollider::Cone {
half_height,
radius,
} => ColliderComponent {
shape: ColliderShape::Cone {
half_height: *half_height,
radius: *radius,
},
..Default::default()
},
SceneCollider::HeightField {
nrows,
ncols,
heights,
scale,
} => ColliderComponent {
shape: ColliderShape::HeightField {
nrows: *nrows,
ncols: *ncols,
heights: heights.clone(),
scale: *scale,
},
..Default::default()
},
};
collider = collider
.with_friction(self.friction)
.with_restitution(self.restitution);
collider.is_sensor = self.is_sensor;
collider.collision_groups =
InteractionGroups::new(self.collision_membership, self.collision_filter);
collider.solver_groups = InteractionGroups::new(self.solver_membership, self.solver_filter);
collider
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SceneJoint {
Fixed {
parent_anchor: [f32; 3],
child_anchor: [f32; 3],
},
Revolute {
parent_anchor: [f32; 3],
child_anchor: [f32; 3],
axis: [f32; 3],
#[serde(default)]
limits: Option<[f32; 2]>,
},
Prismatic {
parent_anchor: [f32; 3],
child_anchor: [f32; 3],
axis: [f32; 3],
#[serde(default)]
limits: Option<[f32; 2]>,
},
Spherical {
parent_anchor: [f32; 3],
child_anchor: [f32; 3],
},
Rope {
parent_anchor: [f32; 3],
child_anchor: [f32; 3],
max_distance: f32,
},
Spring {
parent_anchor: [f32; 3],
child_anchor: [f32; 3],
rest_length: f32,
stiffness: f32,
damping: f32,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SceneJointConnection {
pub parent_entity: AssetUuid,
pub child_entity: AssetUuid,
pub joint: SceneJoint,
#[serde(default)]
pub collisions_enabled: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SceneCollider {
Cuboid {
half_extents: [f32; 3],
},
Ball {
radius: f32,
},
Cylinder {
half_height: f32,
radius: f32,
},
Capsule {
half_height: f32,
radius: f32,
},
TriMesh {
vertices: Vec<[f32; 3]>,
indices: Vec<[u32; 3]>,
},
ConvexHull {
points: Vec<[f32; 3]>,
},
Cone {
half_height: f32,
radius: f32,
},
HeightField {
nrows: usize,
ncols: usize,
heights: Vec<f32>,
scale: [f32; 3],
},
}