1 /*************************************************************************
3 * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
4 * All rights reserved. Email: russ@q12.org Web: www.q12.org *
6 * This library is free software; you can redistribute it and/or *
7 * modify it under the terms of EITHER: *
8 * (1) The GNU Lesser General Public License as published by the Free *
9 * Software Foundation; either version 2.1 of the License, or (at *
10 * your option) any later version. The text of the GNU Lesser *
11 * General Public License is included with this library in the *
13 * (2) The BSD-style license that is included with this library in *
14 * the file LICENSE-BSD.TXT. *
16 * This library is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
19 * LICENSE.TXT and LICENSE-BSD.TXT for more details. *
21 *************************************************************************/
28 #define ALLOCA dALLOCA16
30 //****************************************************************************
33 void dInternalHandleAutoDisabling (dxWorld
*world
, dReal stepsize
)
36 for ( bb
=world
->firstbody
; bb
; bb
=(dxBody
*)bb
->next
)
38 // don't freeze objects mid-air (patch 1586738)
39 if ( bb
->firstjoint
== NULL
) continue;
41 // nothing to do unless this body is currently enabled and has
42 // the auto-disable flag set
43 if ( (bb
->flags
& (dxBodyAutoDisable
|dxBodyDisabled
)) != dxBodyAutoDisable
) continue;
45 // if sampling / threshold testing is disabled, we can never sleep.
46 if ( bb
->adis
.average_samples
== 0 ) continue;
49 // see if the body is idle
54 if ( bb
->average_counter
>= bb
->adis
.average_samples
)
56 dUASSERT( bb
->average_counter
< bb
->adis
.average_samples
, "buffer overflow" );
58 // something is going wrong, reset the average-calculations
59 bb
->average_ready
= 0; // not ready for average calculation
60 bb
->average_counter
= 0; // reset the buffer index
64 // sample the linear and angular velocity
65 bb
->average_lvel_buffer
[bb
->average_counter
][0] = bb
->lvel
[0];
66 bb
->average_lvel_buffer
[bb
->average_counter
][1] = bb
->lvel
[1];
67 bb
->average_lvel_buffer
[bb
->average_counter
][2] = bb
->lvel
[2];
68 bb
->average_avel_buffer
[bb
->average_counter
][0] = bb
->avel
[0];
69 bb
->average_avel_buffer
[bb
->average_counter
][1] = bb
->avel
[1];
70 bb
->average_avel_buffer
[bb
->average_counter
][2] = bb
->avel
[2];
71 bb
->average_counter
++;
74 if ( bb
->average_counter
>= bb
->adis
.average_samples
)
76 bb
->average_counter
= 0; // fill the buffer from the beginning
77 bb
->average_ready
= 1; // this body is ready now for average calculation
80 int idle
= 0; // Assume it's in motion unless we have samples to disprove it.
83 if ( bb
->average_ready
)
85 idle
= 1; // Initial assumption: IDLE
87 // the sample buffers are filled and ready for calculation
88 dVector3 average_lvel
, average_avel
;
90 // Store first velocity samples
91 average_lvel
[0] = bb
->average_lvel_buffer
[0][0];
92 average_avel
[0] = bb
->average_avel_buffer
[0][0];
93 average_lvel
[1] = bb
->average_lvel_buffer
[0][1];
94 average_avel
[1] = bb
->average_avel_buffer
[0][1];
95 average_lvel
[2] = bb
->average_lvel_buffer
[0][2];
96 average_avel
[2] = bb
->average_avel_buffer
[0][2];
98 // If we're not in "instantaneous mode"
99 if ( bb
->adis
.average_samples
> 1 )
101 // add remaining velocities together
102 for ( unsigned int i
= 1; i
< bb
->adis
.average_samples
; ++i
)
104 average_lvel
[0] += bb
->average_lvel_buffer
[i
][0];
105 average_avel
[0] += bb
->average_avel_buffer
[i
][0];
106 average_lvel
[1] += bb
->average_lvel_buffer
[i
][1];
107 average_avel
[1] += bb
->average_avel_buffer
[i
][1];
108 average_lvel
[2] += bb
->average_lvel_buffer
[i
][2];
109 average_avel
[2] += bb
->average_avel_buffer
[i
][2];
113 dReal r1
= dReal( 1.0 ) / dReal( bb
->adis
.average_samples
);
115 average_lvel
[0] *= r1
;
116 average_avel
[0] *= r1
;
117 average_lvel
[1] *= r1
;
118 average_avel
[1] *= r1
;
119 average_lvel
[2] *= r1
;
120 average_avel
[2] *= r1
;
124 dReal av_lspeed
, av_aspeed
;
125 av_lspeed
= dDOT( average_lvel
, average_lvel
);
126 if ( av_lspeed
> bb
->adis
.linear_average_threshold
)
128 idle
= 0; // average linear velocity is too high for idle
132 av_aspeed
= dDOT( average_avel
, average_avel
);
133 if ( av_aspeed
> bb
->adis
.angular_average_threshold
)
135 idle
= 0; // average angular velocity is too high for idle
140 // if it's idle, accumulate steps and time.
141 // these counters won't overflow because this code doesn't run for disabled bodies.
143 bb
->adis_stepsleft
--;
144 bb
->adis_timeleft
-= stepsize
;
148 bb
->adis_stepsleft
= bb
->adis
.idle_steps
;
149 bb
->adis_timeleft
= bb
->adis
.idle_time
;
152 // disable the body if it's idle for a long enough time
153 if ( bb
->adis_stepsleft
<= 0 && bb
->adis_timeleft
<= 0 )
155 bb
->flags
|= dxBodyDisabled
; // set the disable flag
157 // disabling bodies should also include resetting the velocity
158 // should prevent jittering in big "islands"
170 //****************************************************************************
173 // return sin(x)/x. this has a singularity at 0 so special handling is needed
174 // for small arguments.
176 static inline dReal
sinc (dReal x
)
178 // if |x| < 1e-4 then use a taylor series expansion. this two term expansion
179 // is actually accurate to one LS bit within this range if double precision
180 // is being used - so don't worry!
181 if (dFabs(x
) < 1.0e-4) return REAL(1.0) - x
*x
*REAL(0.166666666666666666667);
182 else return dSin(x
)/x
;
186 // given a body b, apply its linear and angular rotation over the time
187 // interval h, thereby adjusting its position and orientation.
189 void dxStepBody (dxBody
*b
, dReal h
)
191 // cap the angular velocity
192 if (b
->flags
& dxBodyMaxAngularSpeed
) {
193 const dReal max_ang_speed
= b
->max_angular_speed
;
194 const dReal aspeed
= dDOT( b
->avel
, b
->avel
);
195 if (aspeed
> max_ang_speed
*max_ang_speed
) {
196 const dReal coef
= max_ang_speed
/dSqrt(aspeed
);
197 dOPEC(b
->avel
, *=, coef
);
200 // end of angular velocity cap
205 // handle linear velocity
206 for (j
=0; j
<3; j
++) b
->posr
.pos
[j
] += h
* b
->lvel
[j
];
208 if (b
->flags
& dxBodyFlagFiniteRotation
) {
209 dVector3 irv
; // infitesimal rotation vector
210 dQuaternion q
; // quaternion for finite rotation
212 if (b
->flags
& dxBodyFlagFiniteRotationAxis
) {
213 // split the angular velocity vector into a component along the finite
214 // rotation axis, and a component orthogonal to it.
215 dVector3 frv
; // finite rotation vector
216 dReal k
= dDOT (b
->finite_rot_axis
,b
->avel
);
217 frv
[0] = b
->finite_rot_axis
[0] * k
;
218 frv
[1] = b
->finite_rot_axis
[1] * k
;
219 frv
[2] = b
->finite_rot_axis
[2] * k
;
220 irv
[0] = b
->avel
[0] - frv
[0];
221 irv
[1] = b
->avel
[1] - frv
[1];
222 irv
[2] = b
->avel
[2] - frv
[2];
224 // make a rotation quaternion q that corresponds to frv * h.
225 // compare this with the full-finite-rotation case below.
229 dReal s
= sinc(theta
) * h
;
235 // make a rotation quaternion q that corresponds to w * h
236 dReal wlen
= dSqrt (b
->avel
[0]*b
->avel
[0] + b
->avel
[1]*b
->avel
[1] +
237 b
->avel
[2]*b
->avel
[2]);
239 dReal theta
= wlen
* h
;
241 dReal s
= sinc(theta
) * h
;
242 q
[1] = b
->avel
[0] * s
;
243 q
[2] = b
->avel
[1] * s
;
244 q
[3] = b
->avel
[2] * s
;
247 // do the finite rotation
249 dQMultiply0 (q2
,q
,b
->q
);
250 for (j
=0; j
<4; j
++) b
->q
[j
] = q2
[j
];
252 // do the infitesimal rotation if required
253 if (b
->flags
& dxBodyFlagFiniteRotationAxis
) {
255 dWtoDQ (irv
,b
->q
,dq
);
256 for (j
=0; j
<4; j
++) b
->q
[j
] += h
* dq
[j
];
260 // the normal way - do an infitesimal rotation
262 dWtoDQ (b
->avel
,b
->q
,dq
);
263 for (j
=0; j
<4; j
++) b
->q
[j
] += h
* dq
[j
];
266 // normalize the quaternion and convert it to a rotation matrix
268 dQtoR (b
->q
,b
->posr
.R
);
270 // notify all attached geoms that this body has moved
271 for (dxGeom
*geom
= b
->geom
; geom
; geom
= dGeomGetBodyNext (geom
))
275 if (b
->moved_callback
)
276 b
->moved_callback(b
);
280 if (b
->flags
& dxBodyLinearDamping
) {
281 const dReal lin_threshold
= b
->dampingp
.linear_threshold
;
282 const dReal lin_speed
= dDOT( b
->lvel
, b
->lvel
);
283 if ( lin_speed
> lin_threshold
) {
284 const dReal k
= 1 - b
->dampingp
.linear_scale
;
285 dOPEC(b
->lvel
, *=, k
);
288 if (b
->flags
& dxBodyAngularDamping
) {
289 const dReal ang_threshold
= b
->dampingp
.angular_threshold
;
290 const dReal ang_speed
= dDOT( b
->avel
, b
->avel
);
291 if ( ang_speed
> ang_threshold
) {
292 const dReal k
= 1 - b
->dampingp
.angular_scale
;
293 dOPEC(b
->avel
, *=, k
);
299 //****************************************************************************
302 // this groups all joints and bodies in a world into islands. all objects
303 // in an island are reachable by going through connected bodies and joints.
304 // each island can be simulated separately.
305 // note that joints that are not attached to anything will not be included
306 // in any island, an so they do not affect the simulation.
308 // this function starts new island from unvisited bodies. however, it will
309 // never start a new islands from a disabled body. thus islands of disabled
310 // bodies will not be included in the simulation. disabled bodies are
311 // re-enabled if they are found to be part of an active island.
313 void dxProcessIslands (dxWorld
*world
, dReal stepsize
, dstepper_fn_t stepper
)
315 dxBody
*b
,*bb
,**body
;
318 // nothing to do if no bodies
319 if (world
->nb
<= 0) return;
321 // handle auto-disabling of bodies
322 dInternalHandleAutoDisabling (world
,stepsize
);
324 // make arrays for body and joint lists (for a single island) to go into
325 body
= (dxBody
**) ALLOCA (world
->nb
* sizeof(dxBody
*));
326 joint
= (dxJoint
**) ALLOCA (world
->nj
* sizeof(dxJoint
*));
327 int bcount
= 0; // number of bodies in `body'
328 int jcount
= 0; // number of joints in `joint'
330 // set all body/joint tags to 0
331 for (b
=world
->firstbody
; b
; b
=(dxBody
*)b
->next
) b
->tag
= 0;
332 for (j
=world
->firstjoint
; j
; j
=(dxJoint
*)j
->next
) j
->tag
= 0;
334 // allocate a stack of unvisited bodies in the island. the maximum size of
335 // the stack can be the lesser of the number of bodies or joints, because
336 // new bodies are only ever added to the stack by going through untagged
337 // joints. all the bodies in the stack must be tagged!
338 int stackalloc
= (world
->nj
< world
->nb
) ? world
->nj
: world
->nb
;
339 dxBody
**stack
= (dxBody
**) ALLOCA (stackalloc
* sizeof(dxBody
*));
341 for (bb
=world
->firstbody
; bb
; bb
=(dxBody
*)bb
->next
) {
342 // get bb = the next enabled, untagged body, and tag it
343 if (bb
->tag
|| (bb
->flags
& dxBodyDisabled
)) continue;
346 // tag all bodies and joints starting from bb.
353 while (stacksize
> 0) {
354 b
= stack
[--stacksize
]; // pop body off stack
355 body
[bcount
++] = b
; // put body on body list
358 // traverse and tag all body's joints, add untagged connected bodies
360 for (dxJointNode
*n
=b
->firstjoint
; n
; n
=n
->next
) {
361 if (!n
->joint
->tag
) {
363 joint
[jcount
++] = n
->joint
;
364 if (n
->body
&& !n
->body
->tag
) {
366 stack
[stacksize
++] = n
->body
;
370 dIASSERT(stacksize
<= world
->nb
);
371 dIASSERT(stacksize
<= world
->nj
);
374 // now do something with body and joint lists
375 stepper (world
,body
,bcount
,joint
,jcount
,stepsize
);
377 // what we've just done may have altered the body/joint tag values.
378 // we must make sure that these tags are nonzero.
379 // also make sure all bodies are in the enabled state.
381 for (i
=0; i
<bcount
; i
++) {
383 body
[i
]->flags
&= ~dxBodyDisabled
;
385 for (i
=0; i
<jcount
; i
++) joint
[i
]->tag
= 1;
388 // if debugging, check that all objects (except for disabled bodies,
389 // unconnected joints, and joints that are connected to disabled bodies)
392 for (b
=world
->firstbody
; b
; b
=(dxBody
*)b
->next
) {
393 if (b
->flags
& dxBodyDisabled
) {
394 if (b
->tag
) dDebug (0,"disabled body tagged");
397 if (!b
->tag
) dDebug (0,"enabled body not tagged");
400 for (j
=world
->firstjoint
; j
; j
=(dxJoint
*)j
->next
) {
401 if ((j
->node
[0].body
&& (j
->node
[0].body
->flags
& dxBodyDisabled
)==0) ||
402 (j
->node
[1].body
&& (j
->node
[1].body
->flags
& dxBodyDisabled
)==0)) {
403 if (!j
->tag
) dDebug (0,"attached enabled joint not tagged");
406 if (j
->tag
) dDebug (0,"unattached or disabled joint tagged");