1 module re.phys.newton3d; 2 3 version (physics) { 4 import std.math; 5 import std.format; 6 import std.typecons; 7 import std.container.array; 8 9 import re.ecs.component; 10 import re.ecs.updatable; 11 import re.math; 12 import re.math.raytypes; 13 import re.time; 14 import re.core; 15 import re.ng.manager; 16 import re.ng.scene; 17 import re.phys.collider; 18 import re.util.dual_map; 19 import re.util.newtonphys; 20 import bindbc.newton; 21 22 @nogc nothrow pragma(inline, true) { 23 float[3] arrayof(Vector3 v) { 24 return raymath.Vector3ToFloat(v); 25 } 26 27 float[4] arrayof(Quaternion q) { 28 return [q.x, q.y, q.z, q.w]; 29 } 30 31 float[16] arrayof(Matrix4 m) { 32 return raymath.MatrixToFloat(m); 33 } 34 35 Vector3 xyz(Vector4 v) { 36 return Vector3(v.x, v.y, v.z); 37 } 38 } 39 40 extern (C) { 41 nothrow @nogc void newtonBodyForceCallback( 42 const NewtonBody* nbody, 43 dFloat timestep, 44 int threadIndex) { 45 NewtonRigidBody b = cast(NewtonRigidBody) NewtonBodyGetUserData(nbody); 46 if (b) { 47 Vector3 gravityForce = b.gravity * b.mass; 48 NewtonBodyAddForce(nbody, gravityForce.arrayof.ptr); 49 NewtonBodyAddForce(nbody, b.force.arrayof.ptr); 50 NewtonBodyAddTorque(nbody, b.torque.arrayof.ptr); 51 b.force = Vector3(0.0f, 0.0f, 0.0f); 52 b.torque = Vector3(0.0f, 0.0f, 0.0f); 53 } 54 } 55 } 56 57 class NewtonWorldManager { 58 public NewtonWorld* newtonWorld; 59 int defaultGroupId; 60 61 this(NewtonWorld* world) { 62 this.newtonWorld = world; 63 defaultGroupId = NewtonMaterialGetDefaultGroupID(newtonWorld); 64 } 65 } 66 67 class NewtonRigidBody { 68 NewtonWorldManager world; 69 NewtonBody* newtonBody; 70 int materialGroupId; 71 bool dynamic = false; 72 float mass; 73 Vector3 gravity = Vector3(0.0f, -9.8f, 0.0f); 74 Vector3 force = Vector3(0.0f, 0.0f, 0.0f); 75 Vector3 torque = Vector3(0.0f, 0.0f, 0.0f); 76 Vector4 position = Vector4(0.0f, 0.0f, 0.0f, 1.0f); 77 Quaternion rotation = raymath.QuaternionIdentity(); 78 Matrix4 transformation = Matrix4Identity; 79 bool enableRotation = true; 80 bool raycastable = true; 81 bool sensor = false; 82 void delegate(NewtonRigidBody, NewtonRigidBody) collisionCallback; 83 84 bool isRaycastable() { 85 return raycastable; 86 } 87 88 bool isSensor() { 89 return sensor; 90 } 91 92 this(NewtonCollisionShape shape, float mass, NewtonWorldManager world) { 93 this.world = world; 94 95 newtonBody = NewtonCreateDynamicBody(world.newtonWorld, shape.newtonCollision, transformation 96 .arrayof.ptr); 97 NewtonBodySetUserData(newtonBody, cast(void*) this); 98 this.groupId = world.defaultGroupId; 99 this.mass = mass; 100 NewtonBodySetMassProperties(newtonBody, mass, shape.newtonCollision); 101 NewtonBodySetForceAndTorqueCallback(newtonBody, &newtonBodyForceCallback); 102 103 collisionCallback = &defaultCollisionCallback; 104 } 105 106 void defaultCollisionCallback(NewtonRigidBody, NewtonRigidBody) { 107 } 108 109 void update(double dt) { 110 NewtonBodyGetPosition(newtonBody, position.arrayof.ptr); 111 NewtonBodyGetMatrix(newtonBody, transformation.arrayof.ptr); 112 if (enableRotation) { 113 // rotation = Quaternion.fromMatrix(transformation); 114 // raymath.QuaternionFromMatrix 115 rotation = raymath.QuaternionFromMatrix(transformation); 116 } else { 117 rotation = raymath.QuaternionIdentity; 118 // transformation = translationMatrix(position.xyz); 119 transformation = raymath.MatrixTranslate(position.x, position.y, position.z); 120 NewtonBodySetMatrix(newtonBody, transformation.arrayof.ptr); 121 } 122 // TODO: enableTranslation 123 } 124 125 void groupId(int id) @property { 126 NewtonBodySetMaterialGroupID(newtonBody, id); 127 materialGroupId = id; 128 } 129 130 int groupId() @property { 131 return materialGroupId; 132 } 133 134 Vector3 worldCenterOfMass() { 135 Vector3 centerOfMass; 136 NewtonBodyGetCentreOfMass(newtonBody, centerOfMass.arrayof.ptr); 137 // return position.xyz + rotation.rotate(centerOfMass); 138 return Vector3(position.x, position.y, position.z) + raymath.Vector3RotateByQuaternion(centerOfMass, rotation); 139 } 140 141 void addForce(Vector3 f) { 142 // force += f; 143 this.force = this.force + f; 144 } 145 146 void addForceAtPos(Vector3 f, Vector3 pos) { 147 this.force = this.force + f; 148 // torque += cross(position.xyz - worldCenterOfMass(), force); 149 this.torque = this.torque + raymath.Vector3CrossProduct( 150 (position.xyz - worldCenterOfMass()), force); 151 } 152 153 void addTorque(Vector3 t) { 154 // torque += t; 155 this.torque = this.torque + t; 156 } 157 158 void createUpVectorConstraint(Vector3 up) { 159 NewtonJoint* joint = NewtonConstraintCreateUpVector(world.newtonWorld, up.arrayof.ptr, newtonBody); 160 } 161 162 void velocity(Vector3 v) @property { 163 NewtonBodySetVelocity(newtonBody, v.arrayof.ptr); 164 } 165 166 Vector3 velocity() @property { 167 Vector3 v; 168 NewtonBodyGetVelocity(newtonBody, v.arrayof.ptr); 169 return v; 170 } 171 172 void onCollision(NewtonRigidBody otherBody) { 173 collisionCallback(this, otherBody); 174 } 175 } 176 177 abstract class NewtonCollisionShape { 178 NewtonWorldManager world; 179 NewtonCollision* newtonCollision; 180 181 this(NewtonWorldManager world) { 182 // super(world); 183 this.world = world; 184 } 185 186 ~this() { 187 //if (newtonCollision) 188 // NewtonDestroyCollision(newtonCollision); 189 } 190 191 void setTransformation(Matrix4 m) { 192 if (newtonCollision) 193 NewtonCollisionSetMatrix(newtonCollision, m.arrayof.ptr); 194 } 195 } 196 197 class NewtonBoxShape : NewtonCollisionShape { 198 Vector3 halfSize; 199 200 this(Vector3 extents, NewtonWorldManager world) { 201 super(world); 202 newtonCollision = NewtonCreateBox(world.newtonWorld, extents.x, extents.y, extents.z, 0, null); 203 NewtonCollisionSetUserData(newtonCollision, cast(void*) this); 204 halfSize = extents * 0.5f; 205 } 206 } 207 208 class NewtonSphereShape : NewtonCollisionShape { 209 float radius; 210 211 this(float radius, NewtonWorldManager world) { 212 super(world); 213 this.radius = radius; 214 newtonCollision = NewtonCreateSphere(world.newtonWorld, radius, 0, null); 215 NewtonCollisionSetUserData(newtonCollision, cast(void*) this); 216 } 217 } 218 219 class NewtonCylinderShape : NewtonCollisionShape { 220 float radius1; 221 float radius2; 222 float height; 223 224 this(float radius1, float radius2, float height, NewtonWorldManager world) { 225 super(world); 226 this.radius1 = radius1; 227 this.radius2 = radius2; 228 this.height = height; 229 newtonCollision = NewtonCreateCylinder(world.newtonWorld, radius1, radius2, height, 0, null); 230 NewtonCollisionSetUserData(newtonCollision, cast(void*) this); 231 } 232 } 233 234 class NewtonChamferCylinderShape : NewtonCollisionShape { 235 float radius; 236 float height; 237 238 this(float radius, float height, NewtonWorldManager world) { 239 super(world); 240 this.radius = radius; 241 this.height = height; 242 newtonCollision = NewtonCreateChamferCylinder(world.newtonWorld, radius, height, 0, null); 243 NewtonCollisionSetUserData(newtonCollision, cast(void*) this); 244 } 245 } 246 247 class NewtonCapsuleShape : NewtonCollisionShape { 248 float radius1; 249 float radius2; 250 float height; 251 252 this(float radius, float height, NewtonWorldManager world) { 253 super(world); 254 this.radius1 = radius1; 255 this.radius2 = radius2; 256 this.height = height; 257 newtonCollision = NewtonCreateCapsule(world.newtonWorld, radius1, radius2, height, 0, null); 258 NewtonCollisionSetUserData(newtonCollision, cast(void*) this); 259 } 260 } 261 262 class NewtonConeShape : NewtonCollisionShape { 263 float radius; 264 float height; 265 266 this(float radius, float height, NewtonWorldManager world) { 267 super(world); 268 this.radius = radius; 269 this.height = height; 270 newtonCollision = NewtonCreateCone(world.newtonWorld, radius, height, 0, null); 271 NewtonCollisionSetUserData(newtonCollision, cast(void*) this); 272 } 273 } 274 275 // class NewtonMeshShape : NewtonCollisionShape { 276 // this(TriangleSet triangleSet, NewtonWorldManager world) { 277 // super(world); 278 // NewtonMesh* nmesh = NewtonMeshCreate(world.newtonWorld); 279 // NewtonMeshBeginBuild(nmesh); 280 // foreach (triangle; triangleSet) 281 // foreach (i, p; triangle.v) { 282 // Vector3 n = triangle.n[i]; 283 // NewtonMeshAddPoint(nmesh, p.x, p.y, p.z); 284 // NewtonMeshAddNormal(nmesh, n.x, n.y, n.z); 285 // } 286 // NewtonMeshEndBuild(nmesh); 287 288 // newtonCollision = NewtonCreateTreeCollisionFromMesh(world.newtonWorld, nmesh, 0); 289 // NewtonCollisionSetUserData(newtonCollision, cast(void*) this); 290 291 // NewtonMeshDestroy(nmesh); 292 // } 293 // } 294 295 // class NewtonConvexHullShape : NewtonCollisionShape { 296 // this(Mesh mesh, float tolerance, NewtonWorldManager world) { 297 // super(world); 298 // NewtonMesh* nmesh = NewtonMeshCreate(world.newtonWorld); 299 // NewtonMeshBeginBuild(nmesh); 300 // foreach (face; mesh.indices) 301 // foreach (i; face) { 302 // Vector3 p = mesh.vertices[i]; 303 // Vector3 n = mesh.normals[i]; 304 // NewtonMeshAddPoint(nmesh, p.x, p.y, p.z); 305 // NewtonMeshAddNormal(nmesh, n.x, n.y, n.z); 306 // } 307 // NewtonMeshEndBuild(nmesh); 308 309 // newtonCollision = NewtonCreateConvexHullFromMesh(world.newtonWorld, nmesh, tolerance, 0); 310 // NewtonCollisionSetUserData(newtonCollision, cast(void*) this); 311 312 // NewtonMeshDestroy(nmesh); 313 // } 314 // } 315 316 class NewtonCompoundShape : NewtonCollisionShape { 317 this(NewtonCollisionShape[] shapes, NewtonWorldManager world) { 318 super(world); 319 newtonCollision = NewtonCreateCompoundCollision(world.newtonWorld, 0); 320 NewtonCompoundCollisionBeginAddRemove(newtonCollision); 321 foreach (shape; shapes) { 322 NewtonCompoundCollisionAddSubCollision(newtonCollision, shape.newtonCollision); 323 } 324 NewtonCompoundCollisionEndAddRemove(newtonCollision); 325 } 326 } 327 328 // class NewtonHeightmapShape : NewtonCollisionShape { 329 // uint width; 330 // uint height; 331 // float[] elevationMap; 332 // ubyte[] attributeMap; 333 334 // this(Heightmap heightmap, uint w, uint h, Vector3 scale, NewtonWorldManager world) { 335 // super(world); 336 337 // width = w; 338 // height = h; 339 340 // elevationMap = New!(float[])(width * height); 341 // attributeMap = New!(ubyte[])(width * height); 342 343 // foreach (x; 0 .. width) 344 // foreach (z; 0 .. height) { 345 // float y = heightmap.getHeight( 346 // cast(float) x / cast(float)(width - 1), 347 // cast(float) z / cast(float)(height - 1)); 348 // elevationMap[z * width + x] = y; 349 // attributeMap[z * width + x] = 0; // TODO 350 // } 351 352 // newtonCollision = NewtonCreateHeightFieldCollision(world.newtonWorld, 353 // width, height, 1, 0, elevationMap.ptr, cast(char*) attributeMap.ptr, scale.y, scale.x, scale.z, 0); 354 // } 355 356 // ~this() { 357 // Delete(elevationMap); 358 // Delete(attributeMap); 359 // } 360 // } 361 }