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 void createUpVectorConstraint(Vector3f up) 163 { 164 NewtonJoint* joint = 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 onCollision(NewtonRigidBody otherBody) 180 { 181 collisionCallback(this, otherBody); 182 } 183 } 184 185 class NewtonBodyComponent: EntityComponent 186 { 187 NewtonRigidBody rigidBody; 188 Matrix4x4f prevTransformation; 189 190 this(EventManager em, Entity e, NewtonRigidBody b) 191 { 192 super(em, e); 193 rigidBody = b; 194 195 Quaternionf rot = e.rotation; 196 rigidBody.transformation = 197 translationMatrix(e.position) * 198 rot.toMatrix4x4; 199 200 NewtonBodySetMatrix(rigidBody.newtonBody, rigidBody.transformation.arrayof.ptr); 201 202 prevTransformation = Matrix4x4f.identity; 203 } 204 205 override void update(Time t) 206 { 207 rigidBody.update(t.delta); 208 209 entity.prevTransformation = prevTransformation; 210 211 entity.position = rigidBody.position.xyz; 212 entity.transformation = rigidBody.transformation * scaleMatrix(entity.scaling); 213 entity.invTransformation = entity.transformation.inverse; 214 entity.rotation = rigidBody.rotation; 215 216 entity.absoluteTransformation = entity.transformation; 217 entity.invAbsoluteTransformation = entity.invTransformation; 218 entity.prevAbsoluteTransformation = entity.prevTransformation; 219 220 prevTransformation = entity.transformation; 221 } 222 } 223 224 NewtonBodyComponent makeStaticBody(Entity entity, NewtonPhysicsWorld world, NewtonCollisionShape collisionShape) 225 { 226 auto rigidBody = world.createStaticBody(collisionShape); 227 return New!NewtonBodyComponent(world.eventManager, entity, rigidBody); 228 } 229 230 NewtonBodyComponent makeDynamicBody(Entity entity, NewtonPhysicsWorld world, NewtonCollisionShape collisionShape, float mass) 231 { 232 auto rigidBody = world.createDynamicBody(collisionShape, mass); 233 return New!NewtonBodyComponent(world.eventManager, entity, rigidBody); 234 }