1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Author: Tom Olsson <tom.olsson@embark-studios.com>
// Copyright © 2019, Embark Studios, all rights reserved.
// Created: 12 April 2019

#![warn(clippy::all)]
#![warn(rust_2018_idioms)]

/*!

*/

use super::{foundation::*, geometry::*, px_type::*, transform::gl_to_px_v3};
use glam::Vec3;
use physx_macros::*;
use physx_sys::*;

/*
todo[tolsson]: Make these into builder parameters
*/
pub const HEIGHT_SCALE: f32 = 1.0;
pub const XZ_SCALE: f32 = 100.0;

#[physx_type]
impl Cooking {
    pub fn new(
        physx_version: u32,
        foundation: &mut Foundation,
        cook_params: PxCookingParams,
    ) -> Self {
        let px_cooking =
            unsafe { phys_PxCreateCooking(physx_version, foundation.get_raw_mut(), &cook_params) };

        Self::from_ptr(px_cooking)
    }

    /// Validate that the provided description is valid
    pub fn validate_triangle_mesh(&self, mesh_desc: &PxTriangleMeshDesc) -> bool {
        unsafe { PxCooking_validateTriangleMesh(self.get_raw(), mesh_desc) }
    }

    pub fn create_triangle_mesh(
        &self,
        mesh_desc: &PxTriangleMeshDesc,
        mesh_scale: Vec3,
    ) -> Result<Geometry, ()> {
        let mut cooking_result = PxTriangleMeshCookingResult::eSUCCESS;
        unsafe {
            if !self.validate_triangle_mesh(mesh_desc) {
                Err(())
            } else {
                let insertion_callback =
                    PxPhysics_getPhysicsInsertionCallback_mut(phys_PxGetPhysics());

                let tri_mesh = PxCooking_createTriangleMesh(
                    self.get_raw(),
                    mesh_desc,
                    insertion_callback,
                    &mut cooking_result,
                );

                let mesh_scale = PxMeshScale_new_2(&gl_to_px_v3(mesh_scale));

                Ok(Geometry::TriangleMesh(PxTriangleMeshGeometry_new_1(
                    tri_mesh,
                    &mesh_scale,
                    PxMeshGeometryFlags { mBits: 0 },
                )))
            }
        }
    }

    /// Build heightfield geometry from a description
    pub fn create_heightfield(
        &self,
        heightfield_desc: PxHeightFieldDesc,
        double_sided: bool,
    ) -> Geometry {
        unsafe {
            let insertion_callback = PxPhysics_getPhysicsInsertionCallback_mut(phys_PxGetPhysics());

            let heightfield =
                PxCooking_createHeightField(self.get_raw(), &heightfield_desc, insertion_callback);
            let mesh_flags = if double_sided {
                PxMeshGeometryFlag::eDOUBLE_SIDED
            } else {
                0
            };

            let heightfield_geom = PxHeightFieldGeometry_new_1(
                heightfield,
                PxMeshGeometryFlags {
                    mBits: mesh_flags as u8,
                },
                HEIGHT_SCALE,
                XZ_SCALE,
                XZ_SCALE,
            );

            Geometry::HeightField(heightfield_geom)
        }
    }

    pub fn make_geometry(&mut self, desc: ColliderDesc) -> PhysicsGeometry {
        let geometry: Geometry = unsafe {
            match desc {
                ColliderDesc::Sphere(radius) => Geometry::Sphere(PxSphereGeometry_new_1(radius)),
                ColliderDesc::Box(x, y, z) => Geometry::Box(PxBoxGeometry_new_1(x, y, z)),
                ColliderDesc::Capsule(r, h) => {
                    Geometry::Capsule(PxCapsuleGeometry_new_1(r, h / 2.0))
                }
                ColliderDesc::Cylinder(r, h) => {
                    Geometry::Capsule(PxCapsuleGeometry_new_1(r, h / 2.0))
                }
                ColliderDesc::TriMesh {
                    vertices,
                    indices,
                    mesh_scale,
                } => {
                    let mut mesh_desc = PxTriangleMeshDesc_new();

                    mesh_desc.points.count = vertices.len() as u32;
                    mesh_desc.points.stride = (3 * std::mem::size_of::<f32>()) as u32;
                    mesh_desc.points.data = vertices.as_ptr() as *const std::ffi::c_void;

                    mesh_desc.triangles.count = (indices.len() as u32) / 3;
                    mesh_desc.triangles.stride = (3 * std::mem::size_of::<u32>()) as u32;
                    mesh_desc.triangles.data = indices.as_ptr() as *const std::ffi::c_void;

                    self.create_triangle_mesh(&mesh_desc, mesh_scale)
                        .expect("failed creating triangle mesh")
                }
            }
        };

        PhysicsGeometry::new(geometry)
    }
}