1 /* 2 Copyright (c) 2019-2022 Timur Gafarov 3 4 Boost Software License - Version 1.0 - August 17th, 2003 5 Permission is hereby granted, free of charge, to any person or organization 6 obtaining a copy of the software and accompanying documentation covered by 7 this license (the "Software") to use, reproduce, display, distribute, 8 execute, and transmit the Software, and to prepare derivative works of the 9 Software, and to permit third-parties to whom the Software is furnished to 10 do so, all subject to the following: 11 12 The copyright notices in the Software and this entire statement, including 13 the above license grant, this restriction and the following disclaimer, 14 must be included in all copies of the Software, in whole or in part, and 15 all derivative works of the Software, unless such copies or derivative 16 works are solely in the form of machine-executable object code generated by 17 a source language processor. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 DEALINGS IN THE SOFTWARE. 26 */ 27 28 module dagon.ext.newton.rigidbody; 29 30 import dlib.core.ownership; 31 import dlib.core.memory; 32 import dlib.math.vector; 33 import dlib.math.matrix; 34 import dlib.math.quaternion; 35 import dlib.math.transformation; 36 import bindbc.newton; 37 import dagon.core.event; 38 import dagon.core.time; 39 import dagon.graphics.entity; 40 import dagon.ext.newton.world; 41 import dagon.ext.newton.shape; 42 43 extern(C) 44 { 45 nothrow @nogc void newtonBodyForceCallback( 46 const NewtonBody* nbody, 47 dFloat timestep, 48 int threadIndex) 49 { 50 NewtonRigidBody b = cast(NewtonRigidBody)NewtonBodyGetUserData(nbody); 51 if (b) 52 { 53 Vector3f gravityForce = b.gravity * b.mass; 54 NewtonBodyAddForce(nbody, gravityForce.arrayof.ptr); 55 NewtonBodyAddForce(nbody, b.force.arrayof.ptr); 56 NewtonBodyAddTorque(nbody, b.torque.arrayof.ptr); 57 b.force = Vector3f(0.0f, 0.0f, 0.0f); 58 b.torque = Vector3f(0.0f, 0.0f, 0.0f); 59 } 60 } 61 } 62 63 class NewtonRigidBody: Owner 64 { 65 NewtonPhysicsWorld world; 66 NewtonBody* newtonBody; 67 int materialGroupId; 68 bool dynamic = false; 69 float mass; 70 Vector3f gravity = Vector3f(0.0f, -9.8f, 0.0f); 71 Vector3f force = Vector3f(0.0f, 0.0f, 0.0f); 72 Vector3f torque = Vector3f(0.0f, 0.0f, 0.0f); 73 Vector4f position = Vector4f(0.0f, 0.0f, 0.0f, 1.0f); 74 Quaternionf rotation = Quaternionf.identity; 75 Matrix4x4f transformation = Matrix4x4f.identity; 76 bool enableRotation = true; 77 bool raycastable = true; 78 bool sensor = false; 79 void delegate(NewtonRigidBody, NewtonRigidBody) collisionCallback; 80 81 bool isRaycastable() 82 { 83 return raycastable; 84 } 85 86 bool isSensor() 87 { 88 return sensor; 89 } 90 91 this(NewtonCollisionShape shape, float mass, NewtonPhysicsWorld world, Owner o) 92 { 93 super(o); 94 95 this.world = world; 96 97 newtonBody = NewtonCreateDynamicBody(world.newtonWorld, shape.newtonCollision, transformation.arrayof.ptr); 98 NewtonBodySetUserData(newtonBody, cast(void*)this); 99 this.groupId = world.defaultGroupId; 100 this.mass = mass; 101 NewtonBodySetMassProperties(newtonBody, mass, shape.newtonCollision); 102 NewtonBodySetForceAndTorqueCallback(newtonBody, &newtonBodyForceCallback); 103 104 collisionCallback = &defaultCollisionCallback; 105 } 106 107 void defaultCollisionCallback(NewtonRigidBody, NewtonRigidBody) 108 { 109 } 110 111 void update(double dt) 112 { 113 NewtonBodyGetPosition(newtonBody, position.arrayof.ptr); 114 NewtonBodyGetMatrix(newtonBody, transformation.arrayof.ptr); 115 if (enableRotation) 116 { 117 rotation = Quaternionf.fromMatrix(transformation); 118 } 119 else 120 { 121 rotation = Quaternionf.identity; 122 transformation = translationMatrix(position.xyz); 123 NewtonBodySetMatrix(newtonBody, transformation.arrayof.ptr); 124 } 125 // TODO: enableTranslation 126 } 127 128 void groupId(int id) @property 129 { 130 NewtonBodySetMaterialGroupID(newtonBody, id); 131 materialGroupId = id; 132 } 133 134 int groupId() @property 135 { 136 return materialGroupId; 137 } 138 139 Vector3f worldCenterOfMass() @property 140 { 141 Vector3f centerOfMass; 142 NewtonBodyGetCentreOfMass(newtonBody, centerOfMass.arrayof.ptr); 143 return position.xyz + rotation.rotate(centerOfMass); 144 } 145 146 void centerOfMass(Vector3f center) @property 147 { 148 NewtonBodySetCentreOfMass(newtonBody, center.arrayof.ptr); 149 } 150 151 void addForce(Vector3f f) 152 { 153 force += f; 154 } 155 156 void addForceAtPos(Vector3f f, Vector3f pos) 157 { 158 force += f; 159 torque += cross(pos - worldCenterOfMass(), f); 160 } 161 162 void addTorque(Vector3f t) 163 { 164 torque += t; 165 } 166 167 NewtonJoint* createUpVectorConstraint(Vector3f up) 168 { 169 return NewtonConstraintCreateUpVector(world.newtonWorld, up.arrayof.ptr, newtonBody); 170 } 171 172 void velocity(Vector3f v) @property 173 { 174 NewtonBodySetVelocity(newtonBody, v.arrayof.ptr); 175 } 176 177 Vector3f velocity() @property 178 { 179 Vector3f v; 180 NewtonBodyGetVelocity(newtonBody, v.arrayof.ptr); 181 return v; 182 } 183 184 Vector3f pointVelocity(Vector3f worldPoint) 185 { 186 Vector3f v; 187 NewtonBodyGetPointVelocity(newtonBody, worldPoint.arrayof.ptr, v.arrayof.ptr); 188 return v; 189 } 190 191 Vector3f localPointVelocity(Vector3f point) 192 { 193 Vector3f worldPoint = point * transformation; 194 return pointVelocity(worldPoint); 195 } 196 197 void addImpulse(Vector3f deltaVelocity, Vector3f impulsePoint, double dt) 198 { 199 NewtonBodyAddImpulse(newtonBody, deltaVelocity.arrayof.ptr, impulsePoint.arrayof.ptr, dt); 200 } 201 202 void onCollision(NewtonRigidBody otherBody) 203 { 204 collisionCallback(this, otherBody); 205 } 206 } 207 208 class NewtonBodyComponent: EntityComponent 209 { 210 NewtonRigidBody rigidBody; 211 Matrix4x4f prevTransformation; 212 213 this(EventManager em, Entity e, NewtonRigidBody b) 214 { 215 super(em, e); 216 rigidBody = b; 217 218 Quaternionf rot = e.rotation; 219 rigidBody.transformation = 220 translationMatrix(e.position) * 221 rot.toMatrix4x4; 222 223 NewtonBodySetMatrix(rigidBody.newtonBody, rigidBody.transformation.arrayof.ptr); 224 225 prevTransformation = Matrix4x4f.identity; 226 } 227 228 override void update(Time t) 229 { 230 rigidBody.update(t.delta); 231 232 entity.prevTransformation = prevTransformation; 233 234 entity.position = rigidBody.position.xyz; 235 entity.transformation = rigidBody.transformation * scaleMatrix(entity.scaling); 236 entity.invTransformation = entity.transformation.inverse; 237 entity.rotation = rigidBody.rotation; 238 239 entity.absoluteTransformation = entity.transformation; 240 entity.invAbsoluteTransformation = entity.invTransformation; 241 entity.prevAbsoluteTransformation = entity.prevTransformation; 242 243 prevTransformation = entity.transformation; 244 } 245 } 246 247 NewtonBodyComponent makeStaticBody(Entity entity, NewtonPhysicsWorld world, NewtonCollisionShape collisionShape) 248 { 249 auto rigidBody = world.createStaticBody(collisionShape); 250 return New!NewtonBodyComponent(world.eventManager, entity, rigidBody); 251 } 252 253 NewtonBodyComponent makeDynamicBody(Entity entity, NewtonPhysicsWorld world, NewtonCollisionShape collisionShape, float mass) 254 { 255 auto rigidBody = world.createDynamicBody(collisionShape, mass); 256 return New!NewtonBodyComponent(world.eventManager, entity, rigidBody); 257 }