1 module unecht.core.components.physics.dynamic;
2 
3 import derelict.ode.ode;
4 import derelict.util.system;
5 
6 import unecht.core.component;
7 import unecht.core.defaultInspector;
8 import unecht.core.components.physics.system;
9 
10 import gl3n.linalg;
11 
12 ///
13 @UEDefaultInspector!UEPhysicsBody
14 final class UEPhysicsBody : UEComponent 
15 {
16     mixin(UERegisterObject!());
17     
18     void addForce(vec3 _v)
19     {
20         dBodyAddForce(Body, _v.x, _v.y, _v.z);
21     }
22     
23     void setDamping(float _v)
24     {
25         dBodySetLinearDamping(Body, _v);
26     }
27     
28     vec3 getVelocity() {
29         auto vel = dBodyGetLinearVel(Body);
30         return vec3(vel[0..2]);
31     }
32     
33     void setVelocity(vec3 _v) {
34         dBodySetLinearVel(Body, _v.x,_v.y,_v.z);
35     }
36     
37     override void onCreate() {
38         super.onCreate;
39         
40         // This brings us to the end of the world settings, now we have to initialize the objects themselves.
41         // Create a new body for our object in the world and get its ID.
42         Body = dBodyCreate(UEPhysicsSystem.world);
43         
44         auto pos = sceneNode.position;
45         dBodySetPosition(Body, pos.x, pos.y, pos.z);
46         auto rot = sceneNode.rotation;
47         dBodySetQuaternion(Body, rot.quaternion);
48         
49         // Here I have set the initial linear velocity to stationary and let gravity do the work, but you can experiment
50         // with the velocity vector to change the starting behaviour. You can also set the rotational velocity for the new
51         // body using dBodySetAngularVel which takes the same parameters.
52         dBodySetLinearVel(Body, 0,0,0);
53         
54         dBodySetData(Body, cast(void*)this);
55         
56         // Now we need to create a box mass to go with our geom. First we create a new dMass structure (the internals
57         // of which aren't important at the moment) then create an array of 3 float (dReal) values and set them
58         // to the side lengths of our box along the x, y and z axes. We then pass the both of these to dMassSetBox with a
59         // pre-defined DENSITY value of 0.5 in this case.
60         dMass m;
61         
62         dReal[3] sides;
63         sides[0] = 2.0;
64         sides[1] = 2.0;
65         sides[2] = 2.0;
66         static immutable DENSITY = 1.0f;
67         dMassSetBox(&m, DENSITY, sides[0], sides[1], sides[2]);
68         
69         // We can then apply this mass to our objects body.
70         dBodySetMass(Body, &m);
71     }
72 
73     override void onDestroy() {
74         super.onDestroy;
75 
76         //reactivate connected bodies
77         auto n = dBodyGetNumJoints(Body);
78 
79         foreach(i; 0..n)
80         {
81             auto joint = dBodyGetJoint(Body, i);
82             auto body0 = dJointGetBody(joint,0);
83             auto body1 = dJointGetBody(joint,1);
84             if(body0)
85                 dBodyEnable(body0);
86             if(body1)
87                 dBodyEnable(body1);
88         }
89 
90         dBodyDestroy(Body);
91         Body = null;
92     }
93     
94     ///
95     override void onUpdate() {
96         auto doEnable = lastPos != sceneNode.position ||
97             lastAngles != sceneNode.angles;
98 
99         if(doEnable)
100             dBodyEnable(Body);
101 
102         if(lastPos != sceneNode.position)
103             dBodySetPosition(Body, sceneNode.position.x,sceneNode.position.y,sceneNode.position.z);
104 
105         if(lastAngles != sceneNode.angles)
106             dBodySetQuaternion(Body, sceneNode.rotation.quaternion);
107 
108         //TODO: use CopyPosition to save mem traffic
109         auto pos = dBodyGetPosition(Body);
110         quat rot;
111         dBodyCopyQuaternion(Body, rot.quaternion);
112         
113         this.sceneNode.position = lastPos = vec3(pos[0..3]);
114         this.sceneNode.rotation = rot;
115 
116         lastAngles = sceneNode.angles;
117     }
118     
119 private:
120     vec3 lastPos;
121     vec3 lastAngles;
122     
123     package dBodyID Body;  // the dynamics body
124 }