1 /* 2 Copyright (c) 2019-2020 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() 140 { 141 Vector3f centerOfMass; 142 NewtonBodyGetCentreOfMass(newtonBody, centerOfMass.arrayof.ptr); 143 return position.xyz + rotation.rotate(centerOfMass); 144 } 145 146 void addForce(Vector3f f) 147 { 148 force += f; 149 } 150 151 void addForceAtPos(Vector3f f, Vector3f pos) 152 { 153 force += f; 154 torque += cross(position.xyz - worldCenterOfMass(), force); 155 } 156 157 void addTorque(Vector3f t) 158 { 159 torque += t; 160 } 161 162 NewtonJoint* createUpVectorConstraint(Vector3f up) 163 { 164 return NewtonConstraintCreateUpVector(world.newtonWorld, up.arrayof.ptr, newtonBody); 165 } 166 167 void velocity(Vector3f v) @property 168 { 169 NewtonBodySetVelocity(newtonBody, v.arrayof.ptr); 170 } 171 172 Vector3f velocity() @property 173 { 174 Vector3f v; 175 NewtonBodyGetVelocity(newtonBody, v.arrayof.ptr); 176 return v; 177 } 178 179 void addImpulse(Vector3f deltaVelocity, Vector3f impulsePoint, double dt) 180 { 181 NewtonBodyAddImpulse(newtonBody, deltaVelocity.arrayof.ptr, impulsePoint.arrayof.ptr, dt); 182 } 183 184 void onCollision(NewtonRigidBody otherBody) 185 { 186 collisionCallback(this, otherBody); 187 } 188 } 189 190 class NewtonBodyComponent: EntityComponent 191 { 192 NewtonRigidBody rigidBody; 193 Matrix4x4f prevTransformation; 194 195 this(EventManager em, Entity e, NewtonRigidBody b) 196 { 197 super(em, e); 198 rigidBody = b; 199 200 Quaternionf rot = e.rotation; 201 rigidBody.transformation = 202 translationMatrix(e.position) * 203 rot.toMatrix4x4; 204 205 NewtonBodySetMatrix(rigidBody.newtonBody, rigidBody.transformation.arrayof.ptr); 206 207 prevTransformation = Matrix4x4f.identity; 208 } 209 210 override void update(Time t) 211 { 212 rigidBody.update(t.delta); 213 214 entity.prevTransformation = prevTransformation; 215 216 entity.position = rigidBody.position.xyz; 217 entity.transformation = rigidBody.transformation * scaleMatrix(entity.scaling); 218 entity.invTransformation = entity.transformation.inverse; 219 entity.rotation = rigidBody.rotation; 220 221 entity.absoluteTransformation = entity.transformation; 222 entity.invAbsoluteTransformation = entity.invTransformation; 223 entity.prevAbsoluteTransformation = entity.prevTransformation; 224 225 prevTransformation = entity.transformation; 226 } 227 } 228 229 NewtonBodyComponent makeStaticBody(Entity entity, NewtonPhysicsWorld world, NewtonCollisionShape collisionShape) 230 { 231 auto rigidBody = world.createStaticBody(collisionShape); 232 return New!NewtonBodyComponent(world.eventManager, entity, rigidBody); 233 } 234 235 NewtonBodyComponent makeDynamicBody(Entity entity, NewtonPhysicsWorld world, NewtonCollisionShape collisionShape, float mass) 236 { 237 auto rigidBody = world.createDynamicBody(collisionShape, mass); 238 return New!NewtonBodyComponent(world.eventManager, entity, rigidBody); 239 }