physx 0.8.0

High-level Rust interface for Nvidia PhysX
Documentation
#![warn(clippy::all)]

use crate::px_type::*;
use crate::rigid_dynamic::RigidDynamic;

use glam::Vec3;
use physx_macros::*;

use physx_sys::{
    phys_PxCreateControllerManager, PxCapsuleControllerDesc, PxCapsuleControllerDesc_delete,
    PxCapsuleControllerDesc_isValid, PxCapsuleControllerDesc_new_alloc, PxController,
    PxControllerDesc, PxControllerManager, PxControllerManager_createController_mut,
    PxControllerManager_release_mut, PxController_getActor, PxController_getPosition,
    PxController_release_mut, PxController_setPosition_mut, PxExtendedVec3, PxMaterial, PxScene,
};
use thiserror::Error;

#[physx_type]
impl ControllerDesc {}

#[physx_type]
impl ControllerManager {
    pub fn new(scene: *mut PxScene, locking_enabled: bool) -> Self {
        let ptr = unsafe { phys_PxCreateControllerManager(scene, locking_enabled) };
        ControllerManager { ptr }
    }

    pub fn create_controller(&self, desc: &ControllerDesc) -> Controller {
        let controller =
            unsafe { PxControllerManager_createController_mut(self.ptr, desc.get_raw()) };
        Controller::new(controller)
    }

    pub unsafe fn release(self) {
        PxControllerManager_release_mut(self.ptr);
    }
}

#[physx_type(inherit = "ControllerDesc")]
impl CapsuleControllerDesc {
    pub fn new(
        height: f32,
        radius: f32,
        step_offset: f32,
        material: *mut PxMaterial,
    ) -> Result<Self, ControllerError> {
        unsafe {
            let c = PxCapsuleControllerDesc_new_alloc();
            (*c).height = height;
            (*c).radius = radius;
            (*c).stepOffset = step_offset;
            (*c).material = material;

            if PxCapsuleControllerDesc_isValid(c) {
                Ok(CapsuleControllerDesc { ptr: c })
            } else {
                PxCapsuleControllerDesc_delete(c);
                Err(ControllerError::InvalidDescription {
                    height,
                    radius,
                    step_offset,
                })
            }
        }
    }

    pub fn release(self) {
        unsafe { PxCapsuleControllerDesc_delete(self.ptr) };
    }
}

#[physx_type]
impl Controller {
    pub fn new(controller: *mut PxController) -> Self {
        Self { ptr: controller }
    }

    pub fn set_position(&mut self, position: Vec3) {
        unsafe {
            PxController_setPosition_mut(self.get_raw_mut(), &to_extended(&position));
        }
    }

    pub fn get_position(&self) -> Vec3 {
        unsafe { from_extended(*PxController_getPosition(self.get_raw())) }
    }

    pub fn get_actor(&self) -> RigidDynamic {
        unsafe { RigidDynamic::from_ptr(PxController_getActor(self.ptr)) }
    }

    pub fn release(&mut self) {
        unsafe {
            PxController_release_mut(self.get_raw_mut());
        }
    }
}

fn to_extended(vec: &Vec3) -> PxExtendedVec3 {
    PxExtendedVec3 {
        x: vec.x() as f64,
        y: vec.y() as f64,
        z: vec.z() as f64,
    }
}

fn from_extended(vec: PxExtendedVec3) -> Vec3 {
    Vec3::new(vec.x as f32, vec.y as f32, vec.z as f32)
}

#[derive(Error, Debug)]
pub enum ControllerError {
    #[error(
        "Controller description is invalid. height={}, radius={}, step_offset={}",
        height,
        radius,
        step_offset
    )]
    InvalidDescription {
        height: f32,
        radius: f32,
        step_offset: f32,
    },

    #[error("No controller manager present")]
    NoControllerManager,
}