comparison trunk/chipmunkd/cpBody.d @ 4:7ebbd4d05553

initial commit
author Extrawurst
date Thu, 02 Dec 2010 02:11:26 +0100
parents
children c03a41d47b60
comparison
equal deleted inserted replaced
3:81145a61c2fe 4:7ebbd4d05553
1
2 // written in the D programming language
3
4 module chipmunkd.cpBody;
5
6 import chipmunkd.chipmunk;
7 import chipmunkd.chipmunk_types_h;
8 import chipmunkd.cpVect,chipmunkd.cpVect_h;
9 import chipmunkd.cpShape;
10
11 alias void function(cpBody *_body, cpVect gravity, cpFloat damping, cpFloat dt)cpBodyVelocityFunc;
12 alias void function(cpBody *_body, cpFloat dt)cpBodyPositionFunc;
13
14 //extern cpBodyVelocityFunc cpBodyUpdateVelocityDefault;
15 //extern cpBodyPositionFunc cpBodyUpdatePositionDefault;
16
17 // Structure to hold information about the contact graph components
18 // when putting groups of objects to sleep.
19 // No interesting user accessible fields.
20 struct cpComponentNode {
21 cpBody *parent;
22 cpBody *next;
23 int rank;
24 cpFloat idleTime;
25 }
26
27 struct cpBody{
28 // *** Integration Functions.
29
30 // Function that is called to integrate the body's velocity. (Defaults to cpBodyUpdateVelocity)
31 cpBodyVelocityFunc velocity_func;
32
33 // Function that is called to integrate the body's position. (Defaults to cpBodyUpdatePosition)
34 cpBodyPositionFunc position_func;
35
36 // *** Mass Properties
37
38 // Mass and it's inverse.
39 // Always use cpBodySetMass() whenever changing the mass as these values must agree.
40 cpFloat m, m_inv;
41
42 // Moment of inertia and it's inverse.
43 // Always use cpBodySetMoment() whenever changing the moment as these values must agree.
44 cpFloat i, i_inv;
45
46 // *** Positional Properties
47
48 // Linear components of motion (position, velocity, and force)
49 cpVect p, v, f;
50
51 // Angular components of motion (angle, angular velocity, and torque)
52 // Always use cpBodySetAngle() to set the angle of the body as a and rot must agree.
53 cpFloat a, w, t;
54
55 // Cached unit length vector representing the angle of the body.
56 // Used for fast vector rotation using cpvrotate().
57 cpVect rot;
58
59 // *** User Definable Fields
60
61 // User defined data pointer.
62 cpDataPointer data;
63
64 // *** Other Fields
65
66 // Maximum velocities this body can move at after integrating velocity
67 cpFloat v_limit, w_limit;
68
69 // *** Internally Used Fields
70
71 // Velocity bias values used when solving penetrations and correcting constraints.
72 cpVect v_bias;
73 cpFloat w_bias;
74
75 // Space this body has been added to
76 cpSpace* space;
77
78 // Pointer to the shape list.
79 // Shapes form a linked list using cpShape.next when added to a space.
80 cpShape *shapesList;
81
82 // Used by cpSpaceStep() to store contact graph information.
83 cpComponentNode node;
84 }
85
86 //// Basic allocation/destruction functions
87 //cpBody *cpBodyAlloc(void);
88 //cpBody *cpBodyInit(cpBody *body, cpFloat m, cpFloat i);
89 //cpBody *cpBodyNew(cpFloat m, cpFloat i);
90 //
91 //void cpBodyDestroy(cpBody *body);
92 //void cpBodyFree(cpBody *body);
93 //
94 //// Wake up a sleeping or idle body. (defined in cpSpace.c)
95 //void cpBodyActivate(cpBody *body);
96 //
97 //// Force a body to sleep;
98 //void cpBodySleep(cpBody *body);
99 ////void cpBodySleepGroup(cpBody *body, ...);
100
101 static cpBool
102 cpBodyIsSleeping(const cpBody *_body)
103 {
104 return (_body.node.next !is null);
105 }
106
107 //cpBool cpBodyIsStatic(const cpBody *body);
108
109 static cpBool
110 cpBodyIsRogue(const cpBody* _body)
111 {
112 return (_body.space is null);
113 }
114
115
116 //#define CP_DefineBodyGetter(type, member, name) \
117 //static inline type cpBodyGet##name(const cpBody *body){return body.member;}
118 //
119 //#define CP_DefineBodySetter(type, member, name) \
120 //static inline void \
121 //cpBodySet##name(cpBody *body, const type value){ \
122 // cpBodyActivate(body); \
123 // body.member = value; \
124 //} \
125
126 //#define CP_DefineBodyProperty(type, member, name) \
127 //CP_DefineBodyGetter(type, member, name) \
128 //CP_DefineBodySetter(type, member, name)
129
130
131 //// Accessors for cpBody struct members
132 //CP_DefineBodyGetter(cpFloat, m, Mass);
133 //void cpBodySetMass(cpBody *body, cpFloat m);
134 //
135 //CP_DefineBodyGetter(cpFloat, i, Moment);
136 //void cpBodySetMoment(cpBody *body, cpFloat i);
137 //
138 //
139 //CP_DefineBodyProperty(cpVect, p, Pos);
140 //CP_DefineBodyProperty(cpVect, v, Vel);
141 //CP_DefineBodyProperty(cpVect, f, Force);
142 static cpFloat cpBodyGetAngle(const cpBody *_body){return _body.a;}
143 static cpFloat cpBodySetAngle(cpBody *_body, const cpFloat value){cpBodyActivate(_body); return _body.a = value;}
144 //CP_DefineBodyProperty(cpFloat, w, AngVel);
145 //CP_DefineBodyProperty(cpFloat, t, Torque);
146 //CP_DefineBodyGetter(cpVect, rot, Rot);
147 //CP_DefineBodyProperty(cpFloat, v_limit, VelLimit);
148 //CP_DefineBodyProperty(cpFloat, w_limit, AngVelLimit);
149
150 //// Modify the velocity of the body so that it will move to the specified absolute coordinates in the next timestep.
151 //// Intended for objects that are moved manually with a custom velocity integration function.
152 //void cpBodySlew(cpBody *body, cpVect pos, cpFloat dt);
153 //
154 //// Default Integration functions.
155 //void cpBodyUpdateVelocity(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt);
156 //void cpBodyUpdatePosition(cpBody *body, cpFloat dt);
157
158 // Convert body local to world coordinates
159 static cpVect
160 cpBodyLocal2World(const cpBody *_body, const cpVect v)
161 {
162 return cpvadd(_body.p, cpvrotate(v, _body.rot));
163 }
164
165 // Convert world to body local coordinates
166 static cpVect
167 cpBodyWorld2Local(const cpBody *_body, const cpVect v)
168 {
169 return cpvunrotate(cpvsub(v, _body.p), _body.rot);
170 }
171
172 // Apply an impulse (in world coordinates) to the body at a point relative to the center of gravity (also in world coordinates).
173 static void
174 cpBodyApplyImpulse(cpBody *_body, const cpVect j, const cpVect r)
175 {
176 _body.v = cpvadd(_body.v, cpvmult(j, _body.m_inv));
177 _body.w += _body.i_inv*cpvcross(r, j);
178 }
179
180 //// Zero the forces on a body.
181 //void cpBodyResetForces(cpBody *body);
182 //// Apply a force (in world coordinates) to a body at a point relative to the center of gravity (also in world coordinates).
183 //void cpBodyApplyForce(cpBody *body, const cpVect f, const cpVect r);
184
185 static cpFloat
186 cpBodyKineticEnergy(const cpBody *_body)
187 {
188 // Need to do some fudging to avoid NaNs
189 cpFloat vsq = cpvdot(_body.v, _body.v);
190 cpFloat wsq = _body.w*_body.w;
191 return (vsq ? vsq*_body.m : 0.0f) + (wsq ? wsq*_body.i : 0.0f);
192 }
193
194 //// Apply a damped spring force between two bodies.
195 //// Warning: Large damping values can be unstable. Use a cpDampedSpring constraint for this instead.
196 //void cpApplyDampedSpring(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat rlen, cpFloat k, cpFloat dmp, cpFloat dt);
197
198 // initialized in cpInitChipmunk()
199 cpBody cpStaticBodySingleton;
200
201 cpBody*
202 cpBodyAlloc()
203 {
204 return cast(cpBody *)cpmalloc(cpBody.sizeof);
205 }
206
207 cpBodyVelocityFunc cpBodyUpdateVelocityDefault = &cpBodyUpdateVelocity;
208 cpBodyPositionFunc cpBodyUpdatePositionDefault = &cpBodyUpdatePosition;
209
210 cpBody*
211 cpBodyInit(cpBody *_body, cpFloat m, cpFloat i)
212 {
213 _body.velocity_func = cpBodyUpdateVelocityDefault;
214 _body.position_func = cpBodyUpdatePositionDefault;
215
216 cpBodySetMass(_body, m);
217 cpBodySetMoment(_body, i);
218
219 _body.p = cpvzero;
220 _body.v = cpvzero;
221 _body.f = cpvzero;
222
223 cpBodySetAngle(_body, 0.0f);
224 _body.w = 0.0f;
225 _body.t = 0.0f;
226
227 _body.v_bias = cpvzero;
228 _body.w_bias = 0.0f;
229
230 _body.data = null;
231 _body.v_limit = INFINITY;
232 _body.w_limit = INFINITY;
233
234 _body.space = null;
235 _body.shapesList = null;
236
237 cpComponentNode node = {null, null, 0, 0.0f};
238 _body.node = node;
239
240 return _body;
241 }
242
243 cpBody*
244 cpBodyNew(cpFloat m, cpFloat i)
245 {
246 return cpBodyInit(cpBodyAlloc(), m, i);
247 }
248
249 void cpBodyDestroy(cpBody *_body){}
250
251 void
252 cpBodyFree(cpBody *_body)
253 {
254 if(_body){
255 cpBodyDestroy(_body);
256 cpfree(_body);
257 }
258 }
259
260 void
261 cpBodySetMass(cpBody *_body, cpFloat mass)
262 {
263 _body.m = mass;
264 _body.m_inv = 1.0f/mass;
265 }
266
267 void
268 cpBodySetMoment(cpBody *_body, cpFloat moment)
269 {
270 _body.i = moment;
271 _body.i_inv = 1.0f/moment;
272 }
273
274 void
275 cpBodySetAngle(cpBody *_body, cpFloat angle)
276 {
277 _body.a = angle;//fmod(a, (cpFloat)M_PI*2.0f);
278 _body.rot = cpvforangle(angle);
279 }
280
281 void
282 cpBodySlew(cpBody *_body, cpVect pos, cpFloat dt)
283 {
284 cpVect delta = cpvsub(pos, _body.p);
285 _body.v = cpvmult(delta, 1.0f/dt);
286 }
287
288 void
289 cpBodyUpdateVelocity(cpBody *_body, cpVect gravity, cpFloat damping, cpFloat dt)
290 {
291 _body.v = cpvclamp(
292 cpvadd(cpvmult(_body.v, damping), cpvmult(cpvadd(gravity, cpvmult(_body.f, _body.m_inv)), dt)),
293 _body.v_limit);
294
295 cpFloat w_limit = _body.w_limit;
296 _body.w = cpfclamp(_body.w*damping + _body.t*_body.i_inv*dt, -w_limit, w_limit);
297 }
298
299 void
300 cpBodyUpdatePosition(cpBody *_body, cpFloat dt)
301 {
302 _body.p = cpvadd(_body.p, cpvmult(cpvadd(_body.v, _body.v_bias), dt));
303 cpBodySetAngle(_body, _body.a + (_body.w + _body.w_bias)*dt);
304
305 _body.v_bias = cpvzero;
306 _body.w_bias = 0.0f;
307 }
308
309 void
310 cpBodyResetForces(cpBody *_body)
311 {
312 _body.f = cpvzero;
313 _body.t = 0.0f;
314 }
315
316 void
317 cpBodyApplyForce(cpBody *_body, cpVect force, cpVect r)
318 {
319 _body.f = cpvadd(_body.f, force);
320 _body.t += cpvcross(r, force);
321 }
322
323 void
324 cpApplyDampedSpring(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat rlen, cpFloat k, cpFloat dmp, cpFloat dt)
325 {
326 // Calculate the world space anchor coordinates.
327 cpVect r1 = cpvrotate(anchr1, a.rot);
328 cpVect r2 = cpvrotate(anchr2, b.rot);
329
330 cpVect delta = cpvsub(cpvadd(b.p, r2), cpvadd(a.p, r1));
331 cpFloat dist = cpvlength(delta);
332 cpVect n = dist ? cpvmult(delta, 1.0f/dist) : cpvzero;
333
334 cpFloat f_spring = (dist - rlen)*k;
335
336 // Calculate the world relative velocities of the anchor points.
337 cpVect v1 = cpvadd(a.v, cpvmult(cpvperp(r1), a.w));
338 cpVect v2 = cpvadd(b.v, cpvmult(cpvperp(r2), b.w));
339
340 // Calculate the damping force.
341 // This really should be in the impulse solver and can produce problems when using large damping values.
342 cpFloat vrn = cpvdot(cpvsub(v2, v1), n);
343 cpFloat f_damp = vrn*cpfmin(dmp, 1.0f/(dt*(a.m_inv + b.m_inv)));
344
345 // Apply!
346 cpVect f = cpvmult(n, f_spring + f_damp);
347 cpBodyApplyForce(a, f, r1);
348 cpBodyApplyForce(b, cpvneg(f), r2);
349 }
350
351 cpBool
352 cpBodyIsStatic(/+const+/ cpBody *_body)
353 {
354 cpSpace *space = _body.space;
355 return ( (space !is null) && (_body is &space.staticBody) );
356 }
357
358 //void cpSpaceSleepBody(cpSpace *space, cpBody *_body);
359
360 void
361 cpBodySleep(cpBody *_body)
362 {
363 if(cpBodyIsSleeping(_body)) return;
364
365 assert(!cpBodyIsStatic(_body) && !cpBodyIsRogue(_body), "Rogue and static bodies cannot be put to sleep.");
366 cpSpaceSleepBody(_body.space, _body); //TODO
367 }