use oxijolt_sys::*;
use crate::limits::{self, is_compliance};
use crate::{SoftBodyError, Vec3};
mod handle;
mod settings;
mod shared;
pub use handle::{SoftBodyMut, SoftBodyRef, SoftBodyVertexState};
pub use settings::SoftBodySettings;
use shared::{require, COMPLIANCE_RULE};
pub use shared::{
SoftBodyDihedralBend, SoftBodyEdge, SoftBodySharedSettings, SoftBodySharedSettingsBuilder,
SoftBodyVolume,
};
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct SoftBodyVertex {
pub position: Vec3,
pub velocity: Vec3,
pub inverse_mass: f32,
}
impl SoftBodyVertex {
pub fn new(position: Vec3) -> Self {
Self {
position,
velocity: Vec3::ZERO,
inverse_mass: 1.0,
}
}
pub fn kinematic(position: Vec3) -> Self {
Self {
inverse_mass: 0.0,
..Self::new(position)
}
}
fn to_jph(self) -> JPH_SoftVertex {
JPH_SoftVertex {
position: self.position.to_jph(),
velocity: self.velocity.to_jph(),
invMass: self.inverse_mass,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum SoftBodyBendType {
None,
Distance,
Dihedral,
}
impl SoftBodyBendType {
fn to_jph(self) -> JPH_SoftBodyBendType {
match self {
Self::None => JPH_SoftBodyBendType_None,
Self::Distance => JPH_SoftBodyBendType_Distance,
Self::Dihedral => JPH_SoftBodyBendType_Dihedral,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum LongRangeAttachment {
None,
EuclideanDistance,
GeodesicDistance,
}
impl LongRangeAttachment {
fn to_jph(self) -> JPH_SoftBodyLRAType {
match self {
Self::None => JPH_SoftBodyLRAType_None,
Self::EuclideanDistance => JPH_SoftBodyLRAType_EuclideanDistance,
Self::GeodesicDistance => JPH_SoftBodyLRAType_GeodesicDistance,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct SoftBodyVertexAttributes {
compliance: f32,
shear_compliance: f32,
bend_compliance: Option<f32>,
long_range_attachment: LongRangeAttachment,
lra_multiplier: f32,
}
impl Default for SoftBodyVertexAttributes {
fn default() -> Self {
Self {
compliance: 0.0,
shear_compliance: 0.0,
bend_compliance: None,
long_range_attachment: LongRangeAttachment::None,
lra_multiplier: 1.0,
}
}
}
impl SoftBodyVertexAttributes {
#[must_use]
pub fn compliance(mut self, value: f32) -> Self {
self.compliance = value;
self
}
#[must_use]
pub fn shear_compliance(mut self, value: f32) -> Self {
self.shear_compliance = value;
self
}
#[must_use]
pub fn bend_compliance(mut self, value: Option<f32>) -> Self {
self.bend_compliance = value;
self
}
#[must_use]
pub fn long_range_attachment(mut self, kind: LongRangeAttachment, multiplier: f32) -> Self {
self.long_range_attachment = kind;
self.lra_multiplier = multiplier;
self
}
fn validate(&self) -> Result<(), SoftBodyError> {
let compliances = [self.compliance, self.shear_compliance];
require(
compliances
.into_iter()
.chain(self.bend_compliance)
.all(is_compliance),
COMPLIANCE_RULE,
)?;
require(
(1.0..=limits::MAX_RATIO).contains(&self.lra_multiplier),
"an LRA multiplier must be finite and within 1..=limits::MAX_RATIO",
)
}
fn to_jph(self) -> JPH_SoftBodyVertexAttributes {
JPH_SoftBodyVertexAttributes {
compliance: self.compliance,
shearCompliance: self.shear_compliance,
bendCompliance: self.bend_compliance.unwrap_or(f32::MAX),
lraType: self.long_range_attachment.to_jph(),
lraMaxDistanceMultiplier: self.lra_multiplier,
}
}
}
#[cfg(test)]
mod tests;