1 | /*
|
---|
2 | -----------------------------------------------------------------------------
|
---|
3 | This source file is part of the OGRE Reference Application, a layer built
|
---|
4 | on top of OGRE(Object-oriented Graphics Rendering Engine)
|
---|
5 | For the latest info, see http://www.ogre3d.org/
|
---|
6 |
|
---|
7 | Copyright (c) 2000-2005 The OGRE Team
|
---|
8 | Also see acknowledgements in Readme.html
|
---|
9 |
|
---|
10 | This program is free software; you can redistribute it and/or modify it under
|
---|
11 | the terms of the GNU Lesser General Public License as published by the Free Software
|
---|
12 | Foundation; either version 2 of the License, or (at your option) any later
|
---|
13 | version.
|
---|
14 |
|
---|
15 | This program is distributed in the hope that it will be useful, but WITHOUT
|
---|
16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
---|
17 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
---|
18 |
|
---|
19 | You should have received a copy of the GNU Lesser General Public License along with
|
---|
20 | this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
---|
21 | Place - Suite 330, Boston, MA 02111-1307, USA, or go to
|
---|
22 | http://www.gnu.org/copyleft/lesser.txt.
|
---|
23 | -----------------------------------------------------------------------------
|
---|
24 | */
|
---|
25 |
|
---|
26 | #include "OgreRefAppApplicationObject.h"
|
---|
27 | #include "OgreRefAppWorld.h"
|
---|
28 | #include "ode/collision.h"
|
---|
29 | #include "OgreControllerManager.h"
|
---|
30 | #include "OgreStringConverter.h"
|
---|
31 | #include "OgreRoot.h"
|
---|
32 |
|
---|
33 | namespace OgreRefApp
|
---|
34 | {
|
---|
35 | //-------------------------------------------------------------------------
|
---|
36 | ApplicationObject::ApplicationObject(const String& name)
|
---|
37 | {
|
---|
38 | mSceneNode = 0;
|
---|
39 | mEntity = 0;
|
---|
40 | mOdeBody = 0;
|
---|
41 | mDynamicsEnabled = false;
|
---|
42 | mReenableIfInteractedWith = false;
|
---|
43 | mCollisionEnabled = true;
|
---|
44 | mSoftness = 0.0;
|
---|
45 | mBounceCoeffRestitution = 0;
|
---|
46 | mBounceVelocityThreshold = 0.1;
|
---|
47 | setFriction(Math::POS_INFINITY);
|
---|
48 | dMassSetZero(&mMass);
|
---|
49 |
|
---|
50 | mDisableTimeEnd = 0;
|
---|
51 | mDisableTime = 3000.0f; // millisenconds
|
---|
52 | mAngularVelDisableThreshold = 1.0f;
|
---|
53 | mLinearVelDisableThreshold = 1.0f;
|
---|
54 |
|
---|
55 |
|
---|
56 |
|
---|
57 | }
|
---|
58 | //-------------------------------------------------------------------------
|
---|
59 | ApplicationObject::~ApplicationObject()
|
---|
60 | {
|
---|
61 | SceneManager* sm = World::getSingleton().getSceneManager();
|
---|
62 | if (mSceneNode)
|
---|
63 | {
|
---|
64 | sm->destroySceneNode(mSceneNode->getName());
|
---|
65 | mSceneNode = 0;
|
---|
66 | }
|
---|
67 |
|
---|
68 | // TODO destroy entity
|
---|
69 |
|
---|
70 | // Destroy mass
|
---|
71 | if (mOdeBody)
|
---|
72 | {
|
---|
73 | delete mOdeBody;
|
---|
74 | mOdeBody = 0;
|
---|
75 | }
|
---|
76 |
|
---|
77 | // Destroy collision proxies
|
---|
78 | CollisionProxyList::iterator i, iend;
|
---|
79 | iend = mCollisionProxies.end();
|
---|
80 | for (i = mCollisionProxies.begin(); i != iend; ++i)
|
---|
81 | {
|
---|
82 | delete (*i);
|
---|
83 | }
|
---|
84 |
|
---|
85 |
|
---|
86 |
|
---|
87 | }
|
---|
88 | //-------------------------------------------------------------------------
|
---|
89 | void ApplicationObject::setPosition(const Vector3& vec)
|
---|
90 | {
|
---|
91 | setPosition(vec.x, vec.y, vec.z);
|
---|
92 | }
|
---|
93 | //-------------------------------------------------------------------------
|
---|
94 | void ApplicationObject::setPosition(Real x, Real y, Real z)
|
---|
95 | {
|
---|
96 | mSceneNode->setPosition(x, y, z);
|
---|
97 | if (isDynamicsEnabled() && mOdeBody)
|
---|
98 | mOdeBody->setPosition(x, y, z);
|
---|
99 | updateCollisionProxies();
|
---|
100 | }
|
---|
101 | //-------------------------------------------------------------------------
|
---|
102 | void ApplicationObject::setOrientation(const Quaternion& orientation)
|
---|
103 | {
|
---|
104 | mSceneNode->setOrientation(orientation);
|
---|
105 | if (isDynamicsEnabled() && mOdeBody)
|
---|
106 | {
|
---|
107 | dReal dquat[4] = {orientation.w, orientation.x, orientation.y, orientation.z };
|
---|
108 | mOdeBody->setQuaternion(dquat);
|
---|
109 | }
|
---|
110 | updateCollisionProxies();
|
---|
111 | }
|
---|
112 | //-------------------------------------------------------------------------
|
---|
113 | const Vector3& ApplicationObject::getPosition(void)
|
---|
114 | {
|
---|
115 | return mSceneNode->getPosition();
|
---|
116 | }
|
---|
117 | //-------------------------------------------------------------------------
|
---|
118 | const Quaternion& ApplicationObject::getOrientation(void)
|
---|
119 | {
|
---|
120 | return mSceneNode->getOrientation();
|
---|
121 | }
|
---|
122 | //-------------------------------------------------------------------------
|
---|
123 | void ApplicationObject::setDynamicsDisableThreshold(Real linearSq,
|
---|
124 | Real angularSq, Real overTime)
|
---|
125 | {
|
---|
126 | mLinearVelDisableThreshold = linearSq;
|
---|
127 | mAngularVelDisableThreshold = angularSq;
|
---|
128 | mDisableTime = overTime * 1000;
|
---|
129 | }
|
---|
130 | //-------------------------------------------------------------------------
|
---|
131 | void ApplicationObject::_updateFromDynamics()
|
---|
132 | {
|
---|
133 | if (!mOdeBody)
|
---|
134 | {
|
---|
135 | return;
|
---|
136 | }
|
---|
137 | // Update dynamics enabled flag from dynamics (may have been reenabled)
|
---|
138 | if (mReenableIfInteractedWith)
|
---|
139 | {
|
---|
140 | mDynamicsEnabled = mOdeBody->isEnabled() == 0 ? false : true;
|
---|
141 | }
|
---|
142 |
|
---|
143 | if (mDynamicsEnabled)
|
---|
144 | {
|
---|
145 | // Get position & rotation from ODE
|
---|
146 | const dReal* pos = mOdeBody->getPosition();
|
---|
147 | const dReal* quat = mOdeBody->getQuaternion();
|
---|
148 |
|
---|
149 | mSceneNode->setPosition((Real)pos[0], (Real)pos[1], (Real)pos[2]);
|
---|
150 | mSceneNode->setOrientation((Real)quat[0], (Real)quat[1],
|
---|
151 | (Real)quat[2], (Real)quat[3]);
|
---|
152 |
|
---|
153 | updateCollisionProxies();
|
---|
154 |
|
---|
155 | // Check to see if object has stabilised, if so turn off dynamics
|
---|
156 | // to save processor time
|
---|
157 | // NB will be reenabled if interacted with
|
---|
158 |
|
---|
159 | if (this->getLinearVelocity().squaredLength() <= mLinearVelDisableThreshold
|
---|
160 | && this->getAngularVelocity().squaredLength() <= mAngularVelDisableThreshold)
|
---|
161 | {
|
---|
162 | if (mDisableTimeEnd > 0.0f)
|
---|
163 | {
|
---|
164 | // We're counting, check disable time
|
---|
165 | if (Root::getSingleton().getTimer()->getMilliseconds() > mDisableTimeEnd)
|
---|
166 | {
|
---|
167 | this->setDynamicsEnabled(false, true);
|
---|
168 | //LogManager::getSingleton().logMessage(mEntity->getName() + " disabled");
|
---|
169 | mDisableTimeEnd = 0.0f;
|
---|
170 | }
|
---|
171 |
|
---|
172 | }
|
---|
173 | else
|
---|
174 | {
|
---|
175 | // We're not counting down yet, so start the count
|
---|
176 | // NB is mDisableTime = 0 we never disable
|
---|
177 | if (mDisableTime > 0)
|
---|
178 | {
|
---|
179 | mDisableTimeEnd = Root::getSingleton().getTimer()->getMilliseconds() + mDisableTime;
|
---|
180 | //LogManager::getSingleton().logMessage("Starting countdown...");
|
---|
181 | }
|
---|
182 | }
|
---|
183 | }
|
---|
184 | else
|
---|
185 | {
|
---|
186 | // We're still moving
|
---|
187 | mDisableTimeEnd = 0.0f;
|
---|
188 | }
|
---|
189 |
|
---|
190 | }
|
---|
191 | }
|
---|
192 | //-------------------------------------------------------------------------
|
---|
193 | bool ApplicationObject::isCollisionEnabled(void)
|
---|
194 | {
|
---|
195 | return mCollisionEnabled;
|
---|
196 | }
|
---|
197 | //-------------------------------------------------------------------------
|
---|
198 | bool ApplicationObject::isDynamicsEnabled(void)
|
---|
199 | {
|
---|
200 | return (mDynamicsEnabled || mReenableIfInteractedWith);
|
---|
201 | }
|
---|
202 | //-------------------------------------------------------------------------
|
---|
203 | void ApplicationObject::setCollisionEnabled(bool enabled)
|
---|
204 | {
|
---|
205 | mCollisionEnabled = enabled;
|
---|
206 | setEntityQueryFlags();
|
---|
207 | }
|
---|
208 | //-------------------------------------------------------------------------
|
---|
209 | void ApplicationObject::setDynamicsEnabled(bool enabled, bool reEnableOnInteraction)
|
---|
210 | {
|
---|
211 |
|
---|
212 | mDynamicsEnabled = enabled;
|
---|
213 | mReenableIfInteractedWith = reEnableOnInteraction;
|
---|
214 |
|
---|
215 | // World must keep an eye on enabled or potentially reenabled objects
|
---|
216 | World::getSingleton()._notifyDynamicsStateForObject(this,
|
---|
217 | mDynamicsEnabled || mReenableIfInteractedWith);
|
---|
218 |
|
---|
219 | if (mDynamicsEnabled)
|
---|
220 | {
|
---|
221 | // Ensure body is synced
|
---|
222 | mOdeBody->enable();
|
---|
223 | }
|
---|
224 | else if (mOdeBody)
|
---|
225 | {
|
---|
226 | mOdeBody->disable();
|
---|
227 | }
|
---|
228 | // Set properties
|
---|
229 | if (mDynamicsEnabled || mReenableIfInteractedWith)
|
---|
230 | {
|
---|
231 | const Vector3& pos = getPosition();
|
---|
232 | mOdeBody->setPosition(pos.x, pos.y, pos.z);
|
---|
233 | const Quaternion& q = getOrientation();
|
---|
234 | dReal dquat[4] = {q.w, q.x, q.y, q.z };
|
---|
235 | mOdeBody->setQuaternion(dquat);
|
---|
236 | }
|
---|
237 | }
|
---|
238 | //-------------------------------------------------------------------------
|
---|
239 | void ApplicationObject::addForce(const Vector3& direction, const Vector3& atPosition)
|
---|
240 | {
|
---|
241 | addForce(direction.x, direction.y, direction.z,
|
---|
242 | atPosition.x, atPosition.y, atPosition.z);
|
---|
243 | }
|
---|
244 | //-------------------------------------------------------------------------
|
---|
245 | void ApplicationObject::addForce(Real dir_x, Real dir_y, Real dir_z,
|
---|
246 | Real pos_x, Real pos_y, Real pos_z)
|
---|
247 | {
|
---|
248 | assert (mOdeBody && "No dynamics body set up for this object");
|
---|
249 | mOdeBody->addRelForceAtRelPos(dir_x, dir_y, dir_z,
|
---|
250 | pos_x, pos_y, pos_z);
|
---|
251 |
|
---|
252 | }
|
---|
253 | //-------------------------------------------------------------------------
|
---|
254 | void ApplicationObject::addForceWorldSpace(const Vector3& direction, const Vector3& atPosition)
|
---|
255 | {
|
---|
256 | addForceWorldSpace(direction.x, direction.y, direction.z,
|
---|
257 | atPosition.x, atPosition.y, atPosition.z);
|
---|
258 | }
|
---|
259 | //-------------------------------------------------------------------------
|
---|
260 | void ApplicationObject::addForceWorldSpace(Real dir_x, Real dir_y, Real dir_z,
|
---|
261 | Real pos_x, Real pos_y, Real pos_z)
|
---|
262 | {
|
---|
263 | assert (mOdeBody && "No dynamics body set up for this object");
|
---|
264 | mOdeBody->addForceAtPos(dir_x, dir_y, dir_z,
|
---|
265 | pos_x, pos_y, pos_z);
|
---|
266 | }
|
---|
267 | //-------------------------------------------------------------------------
|
---|
268 | void ApplicationObject::addTorque(const Vector3& direction)
|
---|
269 | {
|
---|
270 | addTorque(direction.x, direction.y, direction.z);
|
---|
271 | }
|
---|
272 | //-------------------------------------------------------------------------
|
---|
273 | void ApplicationObject::addTorque(Real x, Real y, Real z)
|
---|
274 | {
|
---|
275 | assert (mOdeBody && "No dynamics body set up for this object");
|
---|
276 | mOdeBody->addRelTorque(x, y, z);
|
---|
277 | }
|
---|
278 | //-------------------------------------------------------------------------
|
---|
279 | void ApplicationObject::addTorqueWorldSpace(const Vector3& direction)
|
---|
280 | {
|
---|
281 | addTorqueWorldSpace(direction.x, direction.y, direction.z);
|
---|
282 | }
|
---|
283 | //-------------------------------------------------------------------------
|
---|
284 | void ApplicationObject::addTorqueWorldSpace(Real x, Real y, Real z)
|
---|
285 | {
|
---|
286 | assert (mOdeBody && "No dynamics body set up for this object");
|
---|
287 | mOdeBody->addTorque(x, y, z);
|
---|
288 | }
|
---|
289 | //-------------------------------------------------------------------------
|
---|
290 | SceneNode* ApplicationObject::getSceneNode(void)
|
---|
291 | {
|
---|
292 | return mSceneNode;
|
---|
293 | }
|
---|
294 | //-------------------------------------------------------------------------
|
---|
295 | Entity* ApplicationObject::getEntity(void)
|
---|
296 | {
|
---|
297 | return mEntity;
|
---|
298 | }
|
---|
299 | //-------------------------------------------------------------------------
|
---|
300 | dBody* ApplicationObject::getOdeBody(void)
|
---|
301 | {
|
---|
302 | if (isDynamicsEnabled())
|
---|
303 | {
|
---|
304 | return mOdeBody;
|
---|
305 | }
|
---|
306 | else
|
---|
307 | {
|
---|
308 | // dynamics are disabled
|
---|
309 | return 0;
|
---|
310 | }
|
---|
311 | }
|
---|
312 | //-------------------------------------------------------------------------
|
---|
313 | void ApplicationObject::updateCollisionProxies(void)
|
---|
314 | {
|
---|
315 | CollisionProxyList::iterator i, iend;
|
---|
316 | iend = mCollisionProxies.end();
|
---|
317 | for (i = mCollisionProxies.begin(); i != iend; ++i)
|
---|
318 | {
|
---|
319 | // set from node
|
---|
320 | const Vector3& pos = mSceneNode->getPosition();
|
---|
321 | dGeom* pProxy = *i;
|
---|
322 | pProxy->setPosition(pos.x, pos.y, pos.z);
|
---|
323 | const Quaternion& orientation = mSceneNode->getOrientation();
|
---|
324 | // Hmm, no setQuaternion on proxy
|
---|
325 | // Do a conversion
|
---|
326 | dReal dquat[4] = {orientation.w, orientation.x, orientation.y, orientation.z };
|
---|
327 | dMatrix3 dm3;
|
---|
328 | memset(dm3, 0, sizeof(dMatrix3));
|
---|
329 | dQtoR(dquat, dm3);
|
---|
330 | pProxy->setRotation(dm3);
|
---|
331 |
|
---|
332 | }
|
---|
333 |
|
---|
334 | }
|
---|
335 | //-------------------------------------------------------------------------
|
---|
336 | bool ApplicationObject::testCollide(ApplicationObject* otherObj)
|
---|
337 | {
|
---|
338 | bool collided = false;
|
---|
339 | dContactGeom contactGeom;
|
---|
340 | dGeom *o1, *o2;
|
---|
341 | CollisionProxyList::const_iterator proxy1, proxy2, proxy1end, proxy2end;
|
---|
342 | proxy1end = mCollisionProxies.end();
|
---|
343 | proxy2end = otherObj->mCollisionProxies.end();
|
---|
344 |
|
---|
345 | CollisionInfo collInfo;
|
---|
346 |
|
---|
347 | for (proxy1 = mCollisionProxies.begin(); proxy1 != proxy1end; ++proxy1)
|
---|
348 | {
|
---|
349 | for (proxy2 = otherObj->mCollisionProxies.begin(); proxy2 != proxy2end; ++proxy2)
|
---|
350 | {
|
---|
351 | o1 = *proxy1;
|
---|
352 | o2 = *proxy2;
|
---|
353 | int numc = dCollide(o1->id(), o2->id(), 0, &contactGeom, sizeof(dContactGeom));
|
---|
354 | if (numc)
|
---|
355 | {
|
---|
356 | // Create contact joints if either object is dynamics simulated
|
---|
357 | // If one is not, then sim will not affect it anyway, it will be fixed
|
---|
358 | // However if one is enabled, we need the contact joint
|
---|
359 | if (this->isDynamicsEnabled() || otherObj->isDynamicsEnabled())
|
---|
360 | {
|
---|
361 | // We use the most agressive parameters from both objects for the contact
|
---|
362 | dContact contact;
|
---|
363 | Real bounce, velThresh, softness;
|
---|
364 | // Use the highest coeff of restitution from both objects
|
---|
365 | bounce = std::max(this->getBounceRestitutionValue(),
|
---|
366 | otherObj->getBounceRestitutionValue());
|
---|
367 | // Use the lowest velocity threshold from both objects
|
---|
368 | velThresh = std::min(this->getBounceVelocityThreshold(),
|
---|
369 | otherObj->getBounceVelocityThreshold());
|
---|
370 | // Set flags
|
---|
371 | contact.surface.mode = dContactBounce | dContactApprox1;
|
---|
372 | contact.surface.bounce = bounce;
|
---|
373 | contact.surface.bounce_vel = velThresh;
|
---|
374 |
|
---|
375 | softness = this->getSoftness() + otherObj->getSoftness();
|
---|
376 | if (softness > 0)
|
---|
377 | {
|
---|
378 | contact.surface.mode |= dContactSoftCFM;
|
---|
379 | contact.surface.soft_cfm = softness;
|
---|
380 | }
|
---|
381 |
|
---|
382 | // Set friction to min of 2 objects
|
---|
383 | // Note that ODE dInfinity == Math::POS_INFINITY
|
---|
384 | contact.surface.mu = std::min(this->getFriction(), otherObj->getFriction());
|
---|
385 | contact.surface.mu2 = 0;
|
---|
386 | contact.geom = contactGeom;
|
---|
387 | dContactJoint contactJoint(
|
---|
388 | World::getSingleton().getOdeWorld()->id(),
|
---|
389 | World::getSingleton().getOdeContactJointGroup()->id(),
|
---|
390 | &contact);
|
---|
391 |
|
---|
392 | // Get ODE bodies
|
---|
393 | // May be null, if so use 0 (immovable) body ids
|
---|
394 | dBody *b1, *b2;
|
---|
395 | dBodyID bid1, bid2;
|
---|
396 | bid1 = bid2 = 0;
|
---|
397 | b1 = this->getOdeBody();
|
---|
398 | b2 = otherObj->getOdeBody();
|
---|
399 | if (b1) bid1 = b1->id();
|
---|
400 | if (b2) bid2 = b2->id();
|
---|
401 | contactJoint.attach(bid1, bid2);
|
---|
402 | }
|
---|
403 |
|
---|
404 | // Tell both objects about the collision
|
---|
405 | collInfo.position.x = contactGeom.pos[0];
|
---|
406 | collInfo.position.y = contactGeom.pos[1];
|
---|
407 | collInfo.position.z = contactGeom.pos[2];
|
---|
408 | collInfo.normal.x = contactGeom.normal[0];
|
---|
409 | collInfo.normal.y = contactGeom.normal[1];
|
---|
410 | collInfo.normal.z = contactGeom.normal[2];
|
---|
411 | collInfo.penetrationDepth = contactGeom.depth;
|
---|
412 | this->_notifyCollided(otherObj, collInfo);
|
---|
413 | otherObj->_notifyCollided(this, collInfo);
|
---|
414 |
|
---|
415 |
|
---|
416 | // set return
|
---|
417 | collided = true;
|
---|
418 | }
|
---|
419 | }
|
---|
420 | }
|
---|
421 | return collided;
|
---|
422 |
|
---|
423 | }
|
---|
424 | //-------------------------------------------------------------------------
|
---|
425 | bool ApplicationObject::testCollide(SceneQuery::WorldFragment* wf)
|
---|
426 | {
|
---|
427 | switch (wf->fragmentType)
|
---|
428 | {
|
---|
429 | case SceneQuery::WFT_NONE:
|
---|
430 | return false;
|
---|
431 | case SceneQuery::WFT_PLANE_BOUNDED_REGION:
|
---|
432 | return testCollidePlaneBounds(wf);
|
---|
433 | default:
|
---|
434 | break;
|
---|
435 | };
|
---|
436 |
|
---|
437 | // not handled
|
---|
438 | return false;
|
---|
439 | }
|
---|
440 | //-------------------------------------------------------------------------
|
---|
441 | bool ApplicationObject::testCollidePlaneBounds(SceneQuery::WorldFragment* wf)
|
---|
442 | {
|
---|
443 | bool collided = false;
|
---|
444 | dContactGeom contactGeom;
|
---|
445 | dGeom *obj;
|
---|
446 | CollisionProxyList::const_iterator proxy, proxyend;
|
---|
447 | proxyend = mCollisionProxies.end();
|
---|
448 |
|
---|
449 | std::list<Plane>::const_iterator pi, piend;
|
---|
450 | piend = wf->planes->end();
|
---|
451 |
|
---|
452 | CollisionInfo collInfo;
|
---|
453 |
|
---|
454 | for (proxy = mCollisionProxies.begin(); proxy != proxyend; ++proxy)
|
---|
455 | {
|
---|
456 | // Hack, simply collide against planes which is facing towards center
|
---|
457 | // We can't do this properly without mesh collision
|
---|
458 | obj = *proxy;
|
---|
459 | Real maxdist = -1.0f;
|
---|
460 | const Plane* bestPlane = 0;
|
---|
461 | for (pi = wf->planes->begin(); pi != piend; ++pi)
|
---|
462 | {
|
---|
463 | const Plane *boundPlane = &(*pi);
|
---|
464 | Real dist = boundPlane->getDistance(this->getPosition());
|
---|
465 | if (dist >= 0.0f)
|
---|
466 | {
|
---|
467 | dPlane odePlane(0, boundPlane->normal.x, boundPlane->normal.y, boundPlane->normal.z,
|
---|
468 | -boundPlane->d);
|
---|
469 |
|
---|
470 | int numc = dCollide(obj->id(), odePlane.id() , 0, &contactGeom, sizeof(dContactGeom));
|
---|
471 | if (numc)
|
---|
472 | {
|
---|
473 | // Create contact joints if object is dynamics simulated
|
---|
474 | if (this->isDynamicsEnabled())
|
---|
475 | {
|
---|
476 | // TODO: combine object parameters with WorldFragment physical properties
|
---|
477 | dContact contact;
|
---|
478 | // Set flags
|
---|
479 | contact.surface.mode = dContactBounce | dContactApprox1;
|
---|
480 | contact.surface.bounce = this->getBounceRestitutionValue();
|
---|
481 | contact.surface.bounce_vel = this->getBounceVelocityThreshold();
|
---|
482 | Real softness = this->getSoftness();
|
---|
483 | if (softness > 0)
|
---|
484 | {
|
---|
485 | contact.surface.mode |= dContactSoftCFM;
|
---|
486 | contact.surface.soft_cfm = softness;
|
---|
487 | }
|
---|
488 |
|
---|
489 | // Set friction
|
---|
490 | contact.surface.mu = this->getFriction();
|
---|
491 | contact.surface.mu2 = 0;
|
---|
492 | contact.geom = contactGeom;
|
---|
493 | dContactJoint contactJoint(
|
---|
494 | World::getSingleton().getOdeWorld()->id(),
|
---|
495 | World::getSingleton().getOdeContactJointGroup()->id(),
|
---|
496 | &contact);
|
---|
497 |
|
---|
498 | // Get ODE body,world fragment body is 0 clearly (immovable)
|
---|
499 | dBody* body = this->getOdeBody();
|
---|
500 | dBodyID bid;
|
---|
501 | bid = 0;
|
---|
502 | if (body) bid = body->id();
|
---|
503 | contactJoint.attach(bid, 0);
|
---|
504 | }
|
---|
505 |
|
---|
506 | // Tell object about the collision
|
---|
507 | collInfo.position.x = contactGeom.pos[0];
|
---|
508 | collInfo.position.y = contactGeom.pos[1];
|
---|
509 | collInfo.position.z = contactGeom.pos[2];
|
---|
510 | collInfo.normal.x = contactGeom.normal[0];
|
---|
511 | collInfo.normal.y = contactGeom.normal[1];
|
---|
512 | collInfo.normal.z = contactGeom.normal[2];
|
---|
513 |
|
---|
514 | // NB clamp the depth to compensate for crazy results
|
---|
515 | collInfo.penetrationDepth = contactGeom.depth;
|
---|
516 | //collInfo.penetrationDepth = std::max(collInfo.penetrationDepth,
|
---|
517 | // this->getLinearVelocity().length());
|
---|
518 | this->_notifyCollided(wf, collInfo);
|
---|
519 |
|
---|
520 |
|
---|
521 | // set return
|
---|
522 | collided = true;
|
---|
523 | }
|
---|
524 | }
|
---|
525 | }
|
---|
526 |
|
---|
527 | }
|
---|
528 | return collided;
|
---|
529 | }
|
---|
530 | //-------------------------------------------------------------------------
|
---|
531 | void ApplicationObject::_notifyCollided(ApplicationObject* otherObj,
|
---|
532 | const ApplicationObject::CollisionInfo& info)
|
---|
533 | {
|
---|
534 | // NB contacts for physics are not created here but in testCollide
|
---|
535 | // Application subclasses should do their own respose here if required
|
---|
536 | }
|
---|
537 | //-------------------------------------------------------------------------
|
---|
538 | void ApplicationObject::_notifyCollided(SceneQuery::WorldFragment* wf,
|
---|
539 | const CollisionInfo& info)
|
---|
540 | {
|
---|
541 | // NB contacts for physics are not created here but in testCollide
|
---|
542 | // Application subclasses should do their own respose here if required
|
---|
543 | }
|
---|
544 | //-------------------------------------------------------------------------
|
---|
545 | void ApplicationObject::setBounceParameters(Real restitutionValue,
|
---|
546 | Real velocityThreshold)
|
---|
547 | {
|
---|
548 | mBounceCoeffRestitution = restitutionValue;
|
---|
549 | mBounceVelocityThreshold = velocityThreshold;
|
---|
550 | }
|
---|
551 | //-------------------------------------------------------------------------
|
---|
552 | Real ApplicationObject::getBounceRestitutionValue(void)
|
---|
553 | {
|
---|
554 | return mBounceCoeffRestitution;
|
---|
555 | }
|
---|
556 | //-------------------------------------------------------------------------
|
---|
557 | Real ApplicationObject::getBounceVelocityThreshold(void)
|
---|
558 | {
|
---|
559 | return mBounceVelocityThreshold;
|
---|
560 | }
|
---|
561 | //-------------------------------------------------------------------------
|
---|
562 | void ApplicationObject::setSoftness(Real softness)
|
---|
563 | {
|
---|
564 | mSoftness = softness;
|
---|
565 | }
|
---|
566 | //-------------------------------------------------------------------------
|
---|
567 | Real ApplicationObject::getSoftness(void)
|
---|
568 | {
|
---|
569 | return mSoftness;
|
---|
570 | }
|
---|
571 | //-------------------------------------------------------------------------
|
---|
572 | void ApplicationObject::setFriction(Real friction)
|
---|
573 | {
|
---|
574 | if (friction == Math::POS_INFINITY)
|
---|
575 | {
|
---|
576 | mFriction = dInfinity;
|
---|
577 | }
|
---|
578 | else
|
---|
579 | {
|
---|
580 | mFriction = friction;
|
---|
581 | }
|
---|
582 | }
|
---|
583 | //-------------------------------------------------------------------------
|
---|
584 | Real ApplicationObject::getFriction(void)
|
---|
585 | {
|
---|
586 | return mFriction;
|
---|
587 | }
|
---|
588 | //-------------------------------------------------------------------------
|
---|
589 | void ApplicationObject::setMassSphere(Real density, Real radius)
|
---|
590 | {
|
---|
591 | dMassSetSphere(&mMass, density, radius);
|
---|
592 | mOdeBody->setMass(&mMass);
|
---|
593 | }
|
---|
594 | //-------------------------------------------------------------------------
|
---|
595 | void ApplicationObject::setMassBox(Real density, const Vector3& dimensions,
|
---|
596 | const Quaternion& orientation)
|
---|
597 | {
|
---|
598 | dMassSetBox(&mMass, density, dimensions.x, dimensions.y, dimensions.z);
|
---|
599 |
|
---|
600 | Matrix3 m3;
|
---|
601 | orientation.ToRotationMatrix(m3);
|
---|
602 | dMatrix3 dm3;
|
---|
603 | OgreToOde(m3, dm3);
|
---|
604 | dMassRotate(&mMass, dm3);
|
---|
605 |
|
---|
606 | mOdeBody->setMass(&mMass);
|
---|
607 |
|
---|
608 |
|
---|
609 | }
|
---|
610 | //-------------------------------------------------------------------------
|
---|
611 | void ApplicationObject::setMassCappedCylinder(Real density, Real length, Real width,
|
---|
612 | const Quaternion& orientation)
|
---|
613 | {
|
---|
614 | dMassSetCappedCylinder(&mMass, density, 3, width, length);
|
---|
615 |
|
---|
616 | Matrix3 m3;
|
---|
617 | orientation.ToRotationMatrix(m3);
|
---|
618 | dMatrix3 dm3;
|
---|
619 | OgreToOde(m3, dm3);
|
---|
620 | dMassRotate(&mMass, dm3);
|
---|
621 |
|
---|
622 | mOdeBody->setMass(&mMass);
|
---|
623 | }
|
---|
624 | //-------------------------------------------------------------------------
|
---|
625 | void ApplicationObject::setMassExpert(Real mass, const Vector3 center, const Matrix3 inertia)
|
---|
626 | {
|
---|
627 |
|
---|
628 | mMass.mass = mass;
|
---|
629 | mMass.c[0] = center.x;
|
---|
630 | mMass.c[1] = center.y;
|
---|
631 | mMass.c[2] = center.z;
|
---|
632 | OgreToOde(inertia, mMass.I);
|
---|
633 |
|
---|
634 | mOdeBody->setMass(&mMass);
|
---|
635 |
|
---|
636 | }
|
---|
637 | //-------------------------------------------------------------------------
|
---|
638 | const dMass* ApplicationObject::getOdeMass(void)
|
---|
639 | {
|
---|
640 | return &mMass;
|
---|
641 | }
|
---|
642 | //-------------------------------------------------------------------------
|
---|
643 | void ApplicationObject::setLinearVelocity(const Vector3& vel)
|
---|
644 | {
|
---|
645 | setLinearVelocity(vel.x, vel.y, vel.z);
|
---|
646 | }
|
---|
647 | //-------------------------------------------------------------------------
|
---|
648 | void ApplicationObject::setLinearVelocity(Real x, Real y, Real z)
|
---|
649 | {
|
---|
650 | assert(mOdeBody && isDynamicsEnabled() &&
|
---|
651 | "Cannot set velocity on an object unless dynamics are enabled and"
|
---|
652 | " an ODE body exists");
|
---|
653 | mOdeBody->setLinearVel(x, y, z);
|
---|
654 | // Reenable if on trigger
|
---|
655 | setDynamicsEnabled(true, true);
|
---|
656 | }
|
---|
657 | //-------------------------------------------------------------------------
|
---|
658 | const Vector3& ApplicationObject::getLinearVelocity(void)
|
---|
659 | {
|
---|
660 | assert(mOdeBody && isDynamicsEnabled() &&
|
---|
661 | "Cannot get velocity on an object unless dynamics are enabled and"
|
---|
662 | " an ODE body exists");
|
---|
663 | static Vector3 vel;
|
---|
664 | const dReal* odeVel = mOdeBody->getLinearVel();
|
---|
665 | vel.x = odeVel[0];
|
---|
666 | vel.y = odeVel[1];
|
---|
667 | vel.z = odeVel[2];
|
---|
668 | return vel;
|
---|
669 |
|
---|
670 | }
|
---|
671 | //-------------------------------------------------------------------------
|
---|
672 | const Vector3& ApplicationObject::getAngularVelocity(void)
|
---|
673 | {
|
---|
674 | assert(mOdeBody && isDynamicsEnabled() &&
|
---|
675 | "Cannot get velocity on an object unless dynamics are enabled and"
|
---|
676 | " an ODE body exists");
|
---|
677 | static Vector3 vel;
|
---|
678 | const dReal* odeVel = mOdeBody->getAngularVel();
|
---|
679 | vel.x = odeVel[0];
|
---|
680 | vel.y = odeVel[1];
|
---|
681 | vel.z = odeVel[2];
|
---|
682 | return vel;
|
---|
683 | }
|
---|
684 | //-------------------------------------------------------------------------
|
---|
685 | void ApplicationObject::setAngularVelocity(const Vector3& vel)
|
---|
686 | {
|
---|
687 | setAngularVelocity(vel.x, vel.y, vel.z);
|
---|
688 | }
|
---|
689 | //-------------------------------------------------------------------------
|
---|
690 | void ApplicationObject::setAngularVelocity(Real x, Real y, Real z)
|
---|
691 | {
|
---|
692 | assert(mOdeBody && isDynamicsEnabled() &&
|
---|
693 | "Cannot set velocity on an object unless dynamics are enabled and"
|
---|
694 | " an ODE body exists");
|
---|
695 | mOdeBody->setAngularVel(x, y, z);
|
---|
696 | // Reenable if on trigger
|
---|
697 | setDynamicsEnabled(true, true);
|
---|
698 | }
|
---|
699 | //-------------------------------------------------------------------------
|
---|
700 | void ApplicationObject::translate(const Vector3& d)
|
---|
701 | {
|
---|
702 | // Adjust position by rotation
|
---|
703 | Vector3 newTrans = mSceneNode->getOrientation() * d;
|
---|
704 | translateWorldSpace(newTrans);
|
---|
705 | }
|
---|
706 | //-------------------------------------------------------------------------
|
---|
707 | void ApplicationObject::translate(Real x, Real y, Real z)
|
---|
708 | {
|
---|
709 | translate(Vector3(x, y, z));
|
---|
710 | }
|
---|
711 | //-------------------------------------------------------------------------
|
---|
712 | void ApplicationObject::translateWorldSpace(const Vector3& d)
|
---|
713 | {
|
---|
714 | setPosition(getPosition() + d);
|
---|
715 | }
|
---|
716 | //-------------------------------------------------------------------------
|
---|
717 | void ApplicationObject::translateWorldSpace(Real x, Real y, Real z)
|
---|
718 | {
|
---|
719 | translateWorldSpace(Vector3(x, y, z));
|
---|
720 | }
|
---|
721 | //-------------------------------------------------------------------------
|
---|
722 | void ApplicationObject::roll(const Radian& angle)
|
---|
723 | {
|
---|
724 | rotate(Vector3::UNIT_Z, angle);
|
---|
725 | }
|
---|
726 | //-------------------------------------------------------------------------
|
---|
727 | void ApplicationObject::pitch(const Radian& angle)
|
---|
728 | {
|
---|
729 | rotate(Vector3::UNIT_X, angle);
|
---|
730 | }
|
---|
731 | //-------------------------------------------------------------------------
|
---|
732 | void ApplicationObject::yaw(const Radian& angle)
|
---|
733 | {
|
---|
734 | rotate(Vector3::UNIT_Y, angle);
|
---|
735 | }
|
---|
736 | //-------------------------------------------------------------------------
|
---|
737 | void ApplicationObject::rotate(const Vector3& axis, const Radian& angle)
|
---|
738 | {
|
---|
739 | Quaternion q;
|
---|
740 | q.FromAngleAxis(angle,axis);
|
---|
741 | rotate(q);
|
---|
742 | }
|
---|
743 | //-------------------------------------------------------------------------
|
---|
744 | void ApplicationObject::rotate(const Quaternion& q)
|
---|
745 | {
|
---|
746 | setOrientation(getOrientation() * q);
|
---|
747 | }
|
---|
748 | //-------------------------------------------------------------------------
|
---|
749 | void ApplicationObject::setEntityQueryFlags(void)
|
---|
750 | {
|
---|
751 | // Real basic query mask usage for now
|
---|
752 | // collision enabled = 0xFFFFFFFF
|
---|
753 | // collision disabled = 0x0
|
---|
754 | if (mEntity)
|
---|
755 | {
|
---|
756 | mEntity->setQueryFlags( mCollisionEnabled ? 0xFFFFFFFF : 0 );
|
---|
757 | }
|
---|
758 | }
|
---|
759 |
|
---|
760 |
|
---|
761 |
|
---|
762 | }
|
---|
763 |
|
---|