Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentation/src/orxonox/objects/worldentities/WorldEntity.cc @ 2535

Last change on this file since 2535 was 2535, checked in by rgrieder, 15 years ago
  • Renamed TransformSpace::Space to TransformSpace::Enum
  • Small changes and adjustments WorldEntity (Revealed while commenting…)
  • Property svn:eol-style set to native
File size: 28.4 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *      Reto Grieder (physics)
25 *   Co-authors:
26 *      ...
27 *
28 */
29
30#include "OrxonoxStableHeaders.h"
31#include "WorldEntity.h"
32
33#include <cassert>
34#include <OgreSceneNode.h>
35#include <OgreSceneManager.h>
36#include "BulletDynamics/Dynamics/btRigidBody.h"
37
38#include "util/Exception.h"
39#include "util/Convert.h"
40#include "core/CoreIncludes.h"
41#include "core/XMLPort.h"
42
43#include "objects/Scene.h"
44
45namespace orxonox
46{
47    const Vector3 WorldEntity::FRONT = Vector3::NEGATIVE_UNIT_Z;
48    const Vector3 WorldEntity::BACK  = Vector3::UNIT_Z;
49    const Vector3 WorldEntity::LEFT  = Vector3::NEGATIVE_UNIT_X;
50    const Vector3 WorldEntity::RIGHT = Vector3::UNIT_X;
51    const Vector3 WorldEntity::DOWN  = Vector3::NEGATIVE_UNIT_Y;
52    const Vector3 WorldEntity::UP    = Vector3::UNIT_Y;
53
54    WorldEntity::WorldEntity(BaseObject* creator) : BaseObject(creator), Synchronisable(creator), collisionShape_(0)
55
56    {
57        RegisterObject(WorldEntity);
58
59        if (!this->getScene() || !this->getScene()->getRootSceneNode())
60            ThrowException(AbortLoading, "Can't create WorldEntity, no scene or no root-scenenode given.");
61
62        this->node_ = this->getScene()->getRootSceneNode()->createChildSceneNode();
63
64        this->parent_ = 0;
65        this->parentID_ = OBJECTID_UNKNOWN;
66
67        this->node_->setPosition(Vector3::ZERO);
68        this->node_->setOrientation(Quaternion::IDENTITY);
69
70
71        // Default behaviour does not include physics
72        // Note: CompoundCollisionShape is a Synchronisable, but must not be synchronised.
73        //       All objects will get attached on the client anyway, so we don't need synchronisation.
74        this->collisionShape_.setWorldEntityParent(this);
75        this->physicalBody_   = 0;
76        this->bPhysicsActive_ = false;
77        this->bPhysicsActiveSynchronised_    = false;
78        this->bPhysicsActiveBeforeAttaching_ = false;
79        this->collisionType_             = None;
80        this->collisionTypeSynchronised_ = None;
81        this->mass_           = 0;
82        this->childrenMass_   = 0;
83        // Using bullet default values
84        this->restitution_    = 0;
85        this->angularFactor_  = 1;
86        this->linearDamping_  = 0;
87        this->angularDamping_ = 0;
88        this->friction_       = 0.5;
89        this->bCollisionCallbackActive_ = false;
90
91        this->registerVariables();
92    }
93
94    WorldEntity::~WorldEntity()
95    {
96        if (this->isInitialized())
97        {
98            if (this->parent_)
99                this->detachFromParent();
100
101            for (std::set<WorldEntity*>::const_iterator it = this->children_.begin(); it != this->children_.end(); )
102                delete (*(it++));
103
104            if (this->physicalBody_)
105            {
106                this->deactivatePhysics();
107                delete this->physicalBody_;
108            }
109
110            this->node_->detachAllObjects();
111            this->node_->removeAllChildren();
112
113            OrxAssert(this->getScene()->getSceneManager(), "No SceneManager defined in a WorldEntity.");
114            this->getScene()->getSceneManager()->destroySceneNode(this->node_->getName());
115        }
116    }
117
118    void WorldEntity::XMLPort(Element& xmlelement, XMLPort::Mode mode)
119    {
120        SUPER(WorldEntity, XMLPort, xmlelement, mode);
121
122        XMLPortParamTemplate(WorldEntity, "position",    setPosition,    getPosition,    xmlelement, mode, const Vector3&);
123        XMLPortParamTemplate(WorldEntity, "orientation", setOrientation, getOrientation, xmlelement, mode, const Quaternion&);
124        XMLPortParamTemplate(WorldEntity, "scale3D",     setScale3D,     getScale3D,     xmlelement, mode, const Vector3&);
125        XMLPortParam        (WorldEntity, "scale",       setScale,       getScale,       xmlelement, mode);
126        XMLPortParamLoadOnly(WorldEntity, "lookat",      lookAt_xmlport,       xmlelement, mode);
127        XMLPortParamLoadOnly(WorldEntity, "direction",   setDirection_xmlport, xmlelement, mode);
128        XMLPortParamLoadOnly(WorldEntity, "yaw",         yaw_xmlport,          xmlelement, mode);
129        XMLPortParamLoadOnly(WorldEntity, "pitch",       pitch_xmlport,        xmlelement, mode);
130        XMLPortParamLoadOnly(WorldEntity, "roll",        roll_xmlport,         xmlelement, mode);
131
132        // Physics
133        XMLPortParam(WorldEntity, "collisionType",  setCollisionTypeStr, getCollisionTypeStr, xmlelement, mode);
134        XMLPortParam(WorldEntity, "mass",           setMass,             getMass,             xmlelement, mode);
135        XMLPortParam(WorldEntity, "restitution",    setRestitution,      getRestitution,      xmlelement, mode);
136        XMLPortParam(WorldEntity, "angularFactor",  setAngularFactor,    getAngularFactor,    xmlelement, mode);
137        XMLPortParam(WorldEntity, "linearDamping",  setLinearDamping,    getLinearDamping,    xmlelement, mode);
138        XMLPortParam(WorldEntity, "angularDamping", setAngularDamping,   getAngularDamping,   xmlelement, mode);
139        XMLPortParam(WorldEntity, "friction",       setFriction,         getFriction,         xmlelement, mode);
140
141        // Other attached WorldEntities
142        XMLPortObject(WorldEntity, WorldEntity, "attached", attach, getAttachedObject, xmlelement, mode);
143        // Attached collision shapes
144        XMLPortObject(WorldEntity, CollisionShape, "collisionShapes", attachCollisionShape, getAttachedCollisionShape, xmlelement, mode);
145    }
146
147    void WorldEntity::registerVariables()
148    {
149        registerVariable(this->mainStateName_,  variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::changedMainState));
150
151        registerVariable(this->bActive_,        variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::changedActivity));
152        registerVariable(this->bVisible_,       variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::changedVisibility));
153
154        registerVariable(this->getScale3D(),    variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::scaleChanged));
155
156        // Physics stuff
157        registerVariable(this->mass_,           variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::massChanged));
158        registerVariable(this->restitution_,    variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::restitutionChanged));
159        registerVariable(this->angularFactor_,  variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::angularFactorChanged));
160        registerVariable(this->linearDamping_,  variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::linearDampingChanged));
161        registerVariable(this->angularDamping_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::angularDampingChanged));
162        registerVariable(this->friction_,       variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::frictionChanged));
163        registerVariable(this->bCollisionCallbackActive_,
164                                                variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::collisionCallbackActivityChanged));
165        registerVariable((int&)this->collisionTypeSynchronised_,
166                                                variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::collisionTypeChanged));
167        registerVariable(this->bPhysicsActiveSynchronised_,
168                                                variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::physicsActivityChanged));
169
170        // Attach to parent if necessary
171        registerVariable(this->parentID_,       variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::parentChanged));
172    }
173
174    void WorldEntity::parentChanged()
175    {
176        if (this->parentID_ != OBJECTID_UNKNOWN)
177        {
178            WorldEntity* parent = dynamic_cast<WorldEntity*>(Synchronisable::getSynchronisable(this->parentID_));
179            if (parent)
180                this->attachToParent(parent);
181        }
182    }
183
184    void WorldEntity::attachToNode(Ogre::SceneNode* node)
185    {
186        Ogre::Node* parent = this->node_->getParent();
187        if (parent)
188            parent->removeChild(this->node_);
189        node->addChild(this->node_);
190    }
191
192    void WorldEntity::detachFromNode(Ogre::SceneNode* node)
193    {
194        node->removeChild(this->node_);
195//        this->getScene()->getRootSceneNode()->addChild(this->node_);
196    }
197
198    void WorldEntity::collisionTypeChanged()
199    {
200        if (this->collisionTypeSynchronised_ != Dynamic &&
201            this->collisionTypeSynchronised_ != Kinematic &&
202            this->collisionTypeSynchronised_ != Static &&
203            this->collisionTypeSynchronised_ != None)
204        {
205            CCOUT(1) << "Error when collsion Type was received over network. Unknown enum value:" << this->collisionTypeSynchronised_ << std::endl;
206        }
207        else if (this->collisionTypeSynchronised_ != collisionType_)
208        {
209            if (this->parent_)
210                CCOUT(2) << "Warning: Network connection tried to set the collision type of an attached WE. Ignoring." << std::endl;
211            else
212                this->setCollisionType(this->collisionTypeSynchronised_);
213        }
214    }
215
216    void WorldEntity::physicsActivityChanged()
217    {
218        if (this->bPhysicsActiveSynchronised_)
219            this->activatePhysics();
220        else
221            this->deactivatePhysics();
222    }
223
224    void WorldEntity::collisionCallbackActivityChanged()
225    {
226        if (this->hasPhysics())
227        {
228            if (bCollisionCallbackActive_)
229                this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() |
230                    btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
231            else
232                this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() &
233                    ~btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
234        }
235    }
236
237    void WorldEntity::attach(WorldEntity* object)
238    {
239        if (object == this)
240        {
241            COUT(2) << "Warning: Can't attach a WorldEntity to itself." << std::endl;
242            return;
243        }
244
245        if (!object->notifyBeingAttached(this))
246            return;
247
248        this->attachNode(object->node_);
249        this->children_.insert(object);
250
251        this->attachCollisionShape(&object->collisionShape_);
252        // mass
253        this->childrenMass_ += object->getMass();
254        recalculateMassProps();
255    }
256
257    bool WorldEntity::notifyBeingAttached(WorldEntity* newParent)
258    {
259        // check first whether attaching is even allowed
260        if (this->hasPhysics())
261        {
262            if (!newParent->hasPhysics())
263            {
264                COUT(2) << "Warning: Cannot attach a physical object to a non physical one." << std::endl;
265                return false;
266            }
267            else if (this->isDynamic())
268            {
269                COUT(2) << "Warning: Cannot attach a dynamic object to a WorldEntity." << std::endl;
270                return false;
271            }
272            else if (this->isKinematic() && newParent->isDynamic())
273            {
274                COUT(2) << "Warning: Cannot attach a kinematic object to a dynamic one." << std::endl;
275                return false;
276            }
277            else if (this->isKinematic())
278            {
279                COUT(2) << "Warning: Cannot attach a kinematic object to a static or kinematic one: Not yet implemented." << std::endl;
280                return false;
281            }
282        }
283
284        if (this->isPhysicsActive())
285            this->bPhysicsActiveBeforeAttaching_ = true;
286        this->deactivatePhysics();
287
288        if (this->parent_)
289            this->detachFromParent();
290
291        this->parent_ = newParent;
292        this->parentID_ = newParent->getObjectID();
293
294        // apply transform to collision shape
295        this->collisionShape_.setPosition(this->getPosition());
296        this->collisionShape_.setOrientation(this->getOrientation());
297        // TODO: Scale
298       
299        return true;
300    }
301
302    void WorldEntity::detach(WorldEntity* object)
303    {
304        if (this->children_.find(object) == this->children_.end())
305        {
306            CCOUT(2) << "Warning: Cannot detach an object that is not a child." << std::endl;
307            return;
308        }
309
310        // collision shapes
311        this->detachCollisionShape(&object->collisionShape_);
312
313        // mass
314        if (object->getMass() > 0.0f)
315        {
316            this->childrenMass_ -= object->getMass();
317            recalculateMassProps();
318        }
319
320        this->detachNode(object->node_);
321        this->children_.erase(object);
322
323        object->notifyDetached();
324    }
325
326    void WorldEntity::notifyDetached()
327    {
328        this->parent_ = 0;
329        this->parentID_ = OBJECTID_UNKNOWN;
330
331        // reset orientation of the collisionShape (cannot be set within a WE usually)
332        this->collisionShape_.setPosition(Vector3::ZERO);
333        this->collisionShape_.setOrientation(Quaternion::IDENTITY);
334        // TODO: Scale
335
336        if (this->bPhysicsActiveBeforeAttaching_)
337        {
338            this->activatePhysics();
339            this->bPhysicsActiveBeforeAttaching_ = false;
340        }
341    }
342
343    WorldEntity* WorldEntity::getAttachedObject(unsigned int index)
344    {
345        unsigned int i = 0;
346        for (std::set<WorldEntity*>::const_iterator it = this->children_.begin(); it != this->children_.end(); ++it)
347        {
348            if (i == index)
349                return (*it);
350            ++i;
351        }
352        return 0;
353    }
354
355    void WorldEntity::attachNode(Ogre::SceneNode* node)
356    {
357        Ogre::Node* parent = node->getParent();
358        if (parent)
359            parent->removeChild(node);
360        this->node_->addChild(node);
361    }
362
363    void WorldEntity::detachNode(Ogre::SceneNode* node)
364    {
365        this->node_->removeChild(node);
366//        this->getScene()->getRootSceneNode()->addChild(node);
367    }
368
369    void WorldEntity::attachOgreObject(Ogre::MovableObject* object)
370    {
371        this->node_->attachObject(object);
372    }
373
374    void WorldEntity::detachOgreObject(Ogre::MovableObject* object)
375    {
376        this->node_->detachObject(object);
377    }
378
379    Ogre::MovableObject* WorldEntity::detachOgreObject(const Ogre::String& name)
380    {
381        return this->node_->detachObject(name);
382    }
383
384    void WorldEntity::attachCollisionShape(CollisionShape* shape)
385    {
386        this->collisionShape_.attach(shape);
387        // Note: this->collisionShape_ already notifies us of any changes.
388    }
389
390    void WorldEntity::detachCollisionShape(CollisionShape* shape)
391    {
392        this->collisionShape_.detach(shape);
393        // Note: this->collisionShape_ already notifies us of any changes.
394    }
395
396    CollisionShape* WorldEntity::getAttachedCollisionShape(unsigned int index) const
397    {
398        return this->collisionShape_.getAttachedShape(index);
399    }
400
401    // Note: These functions are placed in WorldEntity.h as inline functions for the release build.
402#ifndef _NDEBUG
403    const Vector3& WorldEntity::getPosition() const
404    {
405        return this->node_->getPosition();
406    }
407
408    const Quaternion& WorldEntity::getOrientation() const
409    {
410        return this->node_->getOrientation();
411    }
412
413    const Vector3& WorldEntity::getScale3D() const
414    {
415        return this->node_->getScale();
416    }
417#endif
418
419    const Vector3& WorldEntity::getWorldPosition() const
420    {
421        return this->node_->_getDerivedPosition();
422    }
423
424    const Quaternion& WorldEntity::getWorldOrientation() const
425    {
426        return this->node_->_getDerivedOrientation();
427    }
428
429    const Vector3& WorldEntity::getWorldScale3D() const
430    {
431        return this->node_->_getDerivedScale();
432    }
433
434    float WorldEntity::getWorldScale() const
435    {
436        Vector3 scale = this->getWorldScale3D();
437        return (scale.x == scale.y && scale.x == scale.z) ? scale.x : 1;
438    }
439
440    void WorldEntity::setScale3D(const Vector3& scale)
441    {
442/*
443HACK HACK HACK
444        if (bScalePhysics && this->hasPhysics() && scale != Vector3::UNIT_SCALE)
445        {
446            CCOUT(2) << "Warning: Cannot set the scale of a physical object: Not yet implemented. Ignoring scaling." << std::endl;
447            return;
448        }
449HACK HACK HACK
450*/
451        this->node_->setScale(scale);
452
453        this->changedScale();
454    }
455
456    void WorldEntity::translate(const Vector3& distance, TransformSpace::Enum relativeTo)
457    {
458        switch (relativeTo)
459        {
460        case TransformSpace::Local:
461            // position is relative to parent so transform downwards
462            this->setPosition(this->getPosition() + this->getOrientation() * distance);
463            break;
464        case TransformSpace::Parent:
465            this->setPosition(this->getPosition() + distance);
466            break;
467        case TransformSpace::World:
468            // position is relative to parent so transform upwards
469            if (this->node_->getParent())
470                setPosition(getPosition() + (node_->getParent()->_getDerivedOrientation().Inverse() * distance)
471                    / node_->getParent()->_getDerivedScale());
472            else
473                this->setPosition(this->getPosition() + distance);
474            break;
475        }
476    }
477
478    void WorldEntity::rotate(const Quaternion& rotation, TransformSpace::Space relativeTo)
479    void WorldEntity::rotate(const Quaternion& rotation, TransformSpace::Enum relativeTo)
480    {
481        switch(relativeTo)
482        {
483        case TransformSpace::Local:
484            this->setOrientation(this->getOrientation() * rotation);
485            break;
486        case TransformSpace::Parent:
487            // Rotations are normally relative to local axes, transform up
488            this->setOrientation(rotation * this->getOrientation());
489            break;
490        case TransformSpace::World:
491            // Rotations are normally relative to local axes, transform up
492            this->setOrientation(this->getOrientation() * this->getWorldOrientation().Inverse()
493                * rotation * this->getWorldOrientation());
494            break;
495        }
496    }
497
498    void WorldEntity::lookAt(const Vector3& target, TransformSpace::Space relativeTo, const Vector3& localDirectionVector)
499    void WorldEntity::lookAt(const Vector3& target, TransformSpace::Enum relativeTo, const Vector3& localDirectionVector)
500    {
501        Vector3 origin;
502        switch (relativeTo)
503        {
504        case TransformSpace::Local:
505            origin = Vector3::ZERO;
506            break;
507        case TransformSpace::Parent:
508            origin = this->getPosition();
509            break;
510        case TransformSpace::World:
511            origin = this->getWorldPosition();
512            break;
513        }
514        this->setDirection(target - origin, relativeTo, localDirectionVector);
515    }
516
517    void WorldEntity::setDirection(const Vector3& direction, TransformSpace::Space relativeTo, const Vector3& localDirectionVector)
518    void WorldEntity::setDirection(const Vector3& direction, TransformSpace::Enum relativeTo, const Vector3& localDirectionVector)
519    {
520        Quaternion savedOrientation(this->getOrientation());
521        Ogre::Node::TransformSpace ogreRelativeTo;
522        switch (relativeTo)
523        {
524        case TransformSpace::Local:
525            ogreRelativeTo = Ogre::Node::TS_LOCAL; break;
526        case TransformSpace::Parent:
527            ogreRelativeTo = Ogre::Node::TS_PARENT; break;
528        case TransformSpace::World:
529            ogreRelativeTo = Ogre::Node::TS_WORLD; break;
530        }
531        this->node_->setDirection(direction, ogreRelativeTo, localDirectionVector);
532        Quaternion newOrientation(this->node_->getOrientation());
533        this->node_->setOrientation(savedOrientation);
534        this->setOrientation(newOrientation);
535    }
536
537    void WorldEntity::activatePhysics()
538    {
539        if (this->isActive() && this->hasPhysics() && !this->isPhysicsActive() && !this->parent_)
540        {
541            this->getScene()->addPhysicalObject(this);
542            this->bPhysicsActive_ = true;
543        }
544    }
545
546    void WorldEntity::deactivatePhysics()
547    {
548        if (this->isPhysicsActive())
549        {
550            this->getScene()->removePhysicalObject(this);
551            this->bPhysicsActive_ = false;
552        }
553    }
554
555    bool WorldEntity::addedToPhysicalWorld() const
556    {
557        return this->physicalBody_ && this->physicalBody_->isInWorld();
558    }
559
560    void WorldEntity::setCollisionType(CollisionType type)
561    {
562        if (this->collisionType_ == type)
563            return;
564
565        // If we are already attached to a parent, this would be a bad idea..
566        if (this->parent_)
567        {
568            CCOUT(2) << "Warning: Cannot set the collision type of a WorldEntity with a parent." << std::endl;
569            return;
570        }
571
572        // Check for type legality. Could be StaticEntity or MobileEntity.
573        if (!this->isCollisionTypeLegal(type))
574            return;
575        if (type != None && !this->getScene()->hasPhysics())
576        {
577            CCOUT(2) << "Warning: Cannot have physical bodies in a non physical scene." << std::endl;
578            return;
579        }
580
581        if (this->isPhysicsActive())
582            this->deactivatePhysics();
583
584        bool bReactivatePhysics = true;
585        if (this->hasPhysics() && !this->isPhysicsActive())
586            bReactivatePhysics = false;
587
588        // Check whether we have to create or destroy.
589        if (type != None && this->collisionType_ == None)
590        {
591/*
592HACK HACK HACK
593            // Check whether there was some scaling applied.
594            if (!this->node_->getScale().positionEquals(Vector3(1, 1, 1), 0.001))
595            {
596                CCOUT(2) << "Warning: Cannot create a physical body if there is scaling applied to the node: Not yet implemented." << std::endl;
597                return;
598            }
599HACK HACK HACK
600*/
601            // Create new rigid body
602            btRigidBody::btRigidBodyConstructionInfo bodyConstructionInfo(0, this, this->collisionShape_.getCollisionShape());
603            this->physicalBody_ = new btRigidBody(bodyConstructionInfo);
604            this->physicalBody_->setUserPointer(this);
605            this->physicalBody_->setActivationState(DISABLE_DEACTIVATION);
606        }
607        else if (type == None && this->collisionType_ != None)
608        {
609            // Destroy rigid body
610            assert(this->physicalBody_);
611            deactivatePhysics();
612            delete this->physicalBody_;
613            this->physicalBody_ = 0;
614            this->collisionType_ = None;
615            this->collisionTypeSynchronised_ = None;
616            return;
617        }
618
619        // Change type
620        switch (type)
621        {
622        case Dynamic:
623            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !(btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT));
624            break;
625        case Kinematic:
626            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT);
627            break;
628        case Static:
629            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT);
630            break;
631        case None:
632            assert(false); // Doesn't happen
633            return;
634        }
635
636        // Only sets this->collisionType_
637        // However the assertion is to ensure that the internal bullet setting is right
638        updateCollisionType();
639        assert(this->collisionType_ == type);
640
641        // update mass and inertia tensor
642        recalculateMassProps();
643        internalSetPhysicsProps();
644        collisionCallbackActivityChanged();
645        if (bReactivatePhysics)
646            activatePhysics();
647    }
648
649    void WorldEntity::setCollisionTypeStr(const std::string& typeStr)
650    {
651        std::string typeStrLower = getLowercase(typeStr);
652        CollisionType type;
653        if (typeStrLower == "dynamic")
654            type = Dynamic;
655        else if (typeStrLower == "static")
656            type = Static;
657        else if (typeStrLower == "kinematic")
658            type = Kinematic;
659        else if (typeStrLower == "none")
660            type = None;
661        else
662            ThrowException(ParseError, std::string("Attempting to set an unknown collision type: '") + typeStr + "'.");
663        this->setCollisionType(type);
664    }
665
666    std::string WorldEntity::getCollisionTypeStr() const
667    {
668        switch (this->getCollisionType())
669        {
670            case Dynamic:
671                return "dynamic";
672            case Kinematic:
673                return "kinematic";
674            case Static:
675                return "static";
676            case None:
677                return "none";
678            default:
679                assert(false);
680                return "";
681        }
682    }
683
684    void WorldEntity::updateCollisionType()
685    {
686        if (!this->physicalBody_)
687            this->collisionType_ = None;
688        else if (this->physicalBody_->isKinematicObject())
689            this->collisionType_ = Kinematic;
690        else if (this->physicalBody_->isStaticObject())
691            this->collisionType_ = Static;
692        else
693            this->collisionType_ = Dynamic;
694        this->collisionTypeSynchronised_ = this->collisionType_;
695    }
696
697    void WorldEntity::notifyChildMassChanged()
698    {
699        // Note: CollisionShape changes of a child get handled over the internal CompoundCollisionShape already
700        // Recalculate mass
701        this->childrenMass_ = 0.0f;
702        for (std::set<WorldEntity*>::const_iterator it = this->children_.begin(); it != this->children_.end(); ++it)
703            this->childrenMass_ += (*it)->getMass();
704        recalculateMassProps();
705        // Notify parent WE
706        if (this->parent_)
707            parent_->notifyChildMassChanged();
708    }
709
710    void WorldEntity::notifyCollisionShapeChanged()
711    {
712        if (hasPhysics())
713        {
714            // Bullet doesn't like sudden changes of the collision shape, so we remove and add it again
715            if (this->addedToPhysicalWorld())
716            {
717                this->deactivatePhysics();
718                this->physicalBody_->setCollisionShape(this->collisionShape_.getCollisionShape());
719                this->activatePhysics();
720            }
721            else
722                this->physicalBody_->setCollisionShape(this->collisionShape_.getCollisionShape());
723        }
724        recalculateMassProps();
725    }
726
727    void WorldEntity::recalculateMassProps()
728    {
729        // Store local inertia for faster access. Evaluates to (0,0,0) if there is no collision shape.
730        float totalMass = this->mass_ + this->childrenMass_;
731        this->collisionShape_.calculateLocalInertia(totalMass, this->localInertia_);
732        if (this->hasPhysics())
733        {
734            if (this->isStatic())
735            {
736                // Just set everything to zero
737                this->physicalBody_->setMassProps(0.0f, btVector3(0, 0, 0));
738            }
739            else if ((this->mass_ + this->childrenMass_) == 0.0f)
740            {
741                // Use default values to avoid very large or very small values
742                CCOUT(4) << "Warning: Setting the internal physical mass to 1.0 because mass_ is 0.0." << std::endl;
743                btVector3 inertia(0, 0, 0);
744                this->collisionShape_.calculateLocalInertia(1.0f, inertia);
745                this->physicalBody_->setMassProps(1.0f, inertia);
746            }
747            else
748            {
749                this->physicalBody_->setMassProps(totalMass, this->localInertia_);
750            }
751        }
752    }
753
754    void WorldEntity::internalSetPhysicsProps()
755    {
756        if (this->hasPhysics())
757        {
758            this->physicalBody_->setRestitution(this->restitution_);
759            this->physicalBody_->setAngularFactor(this->angularFactor_);
760            this->physicalBody_->setDamping(this->linearDamping_, this->angularDamping_);
761            this->physicalBody_->setFriction(this->friction_);
762        }
763    }
764}
Note: See TracBrowser for help on using the repository browser.