Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 2563 was 2563, checked in by rgrieder, 15 years ago

When the Scene does not support physics, the physical bodies in the WE still get created. Therefore the WE's will be added to the Scene to be added to Bullet.
So when a Scene suddenly becomes physical, it will empty the queue with WE's to Bullet.
This was a problem when synchronising over the network: The scene may not yet have had physics when certains WE's already got synchronised.

Also fixed a bug the synchronisation of the physics status of a WE.

  • Property svn:eol-style set to native
File size: 33.3 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#include "objects/collisionshapes/WorldEntityCollisionShape.h"
45
46namespace orxonox
47{
48    const Vector3 WorldEntity::FRONT = Vector3::NEGATIVE_UNIT_Z;
49    const Vector3 WorldEntity::BACK  = Vector3::UNIT_Z;
50    const Vector3 WorldEntity::LEFT  = Vector3::NEGATIVE_UNIT_X;
51    const Vector3 WorldEntity::RIGHT = Vector3::UNIT_X;
52    const Vector3 WorldEntity::DOWN  = Vector3::NEGATIVE_UNIT_Y;
53    const Vector3 WorldEntity::UP    = Vector3::UNIT_Y;
54
55    /**
56    @brief
57        Creates a new WorldEntity that may immediately be used.
58        All the default values are being set here.
59    */
60    WorldEntity::WorldEntity(BaseObject* creator) : BaseObject(creator), Synchronisable(creator)
61    {
62        RegisterObject(WorldEntity);
63
64        if (!this->getScene() || !this->getScene()->getRootSceneNode())
65            ThrowException(AbortLoading, "Can't create WorldEntity, no scene or no root-scenenode given.");
66
67        this->node_ = this->getScene()->getRootSceneNode()->createChildSceneNode();
68
69        this->parent_ = 0;
70        this->parentID_ = OBJECTID_UNKNOWN;
71
72        this->node_->setPosition(Vector3::ZERO);
73        this->node_->setOrientation(Quaternion::IDENTITY);
74
75
76        // Default behaviour does not include physics
77        this->physicalBody_   = 0;
78        this->bPhysicsActive_ = false;
79        this->bPhysicsActiveSynchronised_    = false;
80        this->bPhysicsActiveBeforeAttaching_ = false;
81        this->collisionShape_ = new WorldEntityCollisionShape(this);
82        this->collisionType_             = None;
83        this->collisionTypeSynchronised_ = None;
84        this->mass_           = 0;
85        this->childrenMass_   = 0;
86        // Using bullet default values
87        this->restitution_    = 0;
88        this->angularFactor_  = 1;
89        this->linearDamping_  = 0;
90        this->angularDamping_ = 0;
91        this->friction_       = 0.5;
92        this->bCollisionCallbackActive_ = false;
93
94        this->registerVariables();
95    }
96
97    /**
98    @brief
99        Destroys the WorldEntity AND ALL its children with it.
100    */
101    WorldEntity::~WorldEntity()
102    {
103        if (this->isInitialized())
104        {
105            if (this->parent_)
106                this->detachFromParent();
107
108            for (std::set<WorldEntity*>::const_iterator it = this->children_.begin(); it != this->children_.end(); )
109                delete (*(it++));
110
111            if (this->physicalBody_)
112            {
113                this->deactivatePhysics();
114                delete this->physicalBody_;
115            }
116            delete this->collisionShape_;
117
118            this->node_->detachAllObjects();
119            this->node_->removeAllChildren();
120
121            OrxAssert(this->getScene()->getSceneManager(), "No SceneManager defined in a WorldEntity.");
122            this->getScene()->getSceneManager()->destroySceneNode(this->node_->getName());
123        }
124    }
125
126    void WorldEntity::XMLPort(Element& xmlelement, XMLPort::Mode mode)
127    {
128        SUPER(WorldEntity, XMLPort, xmlelement, mode);
129
130        XMLPortParamTemplate(WorldEntity, "position",    setPosition,    getPosition,    xmlelement, mode, const Vector3&);
131        XMLPortParamTemplate(WorldEntity, "orientation", setOrientation, getOrientation, xmlelement, mode, const Quaternion&);
132        XMLPortParamTemplate(WorldEntity, "scale3D",     setScale3D,     getScale3D,     xmlelement, mode, const Vector3&);
133        XMLPortParam        (WorldEntity, "scale",       setScale,       getScale,       xmlelement, mode);
134        XMLPortParamLoadOnly(WorldEntity, "lookat",      lookAt_xmlport,       xmlelement, mode);
135        XMLPortParamLoadOnly(WorldEntity, "direction",   setDirection_xmlport, xmlelement, mode);
136        XMLPortParamLoadOnly(WorldEntity, "yaw",         yaw_xmlport,          xmlelement, mode);
137        XMLPortParamLoadOnly(WorldEntity, "pitch",       pitch_xmlport,        xmlelement, mode);
138        XMLPortParamLoadOnly(WorldEntity, "roll",        roll_xmlport,         xmlelement, mode);
139
140        // Physics
141        XMLPortParam(WorldEntity, "collisionType",  setCollisionTypeStr, getCollisionTypeStr, xmlelement, mode);
142        XMLPortParam(WorldEntity, "mass",           setMass,             getMass,             xmlelement, mode);
143        XMLPortParam(WorldEntity, "restitution",    setRestitution,      getRestitution,      xmlelement, mode);
144        XMLPortParam(WorldEntity, "angularFactor",  setAngularFactor,    getAngularFactor,    xmlelement, mode);
145        XMLPortParam(WorldEntity, "linearDamping",  setLinearDamping,    getLinearDamping,    xmlelement, mode);
146        XMLPortParam(WorldEntity, "angularDamping", setAngularDamping,   getAngularDamping,   xmlelement, mode);
147        XMLPortParam(WorldEntity, "friction",       setFriction,         getFriction,         xmlelement, mode);
148
149        // Other attached WorldEntities
150        XMLPortObject(WorldEntity, WorldEntity, "attached", attach, getAttachedObject, xmlelement, mode);
151        // Attached collision shapes
152        XMLPortObject(WorldEntity, CollisionShape, "collisionShapes", attachCollisionShape, getAttachedCollisionShape, xmlelement, mode);
153    }
154
155    void WorldEntity::registerVariables()
156    {
157        registerVariable(this->mainStateName_,  variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::changedMainState));
158
159        registerVariable(this->bActive_,        variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::changedActivity));
160        registerVariable(this->bVisible_,       variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::changedVisibility));
161
162        registerVariable(this->getScale3D(),    variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::scaleChanged));
163
164        // Physics stuff
165        registerVariable(this->mass_,           variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::massChanged));
166        registerVariable(this->restitution_,    variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::restitutionChanged));
167        registerVariable(this->angularFactor_,  variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::angularFactorChanged));
168        registerVariable(this->linearDamping_,  variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::linearDampingChanged));
169        registerVariable(this->angularDamping_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::angularDampingChanged));
170        registerVariable(this->friction_,       variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::frictionChanged));
171        registerVariable(this->bCollisionCallbackActive_,
172                                                variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::collisionCallbackActivityChanged));
173        registerVariable((int&)this->collisionTypeSynchronised_,
174                                                variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::collisionTypeChanged));
175        registerVariable(this->bPhysicsActiveSynchronised_,
176                                                variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::physicsActivityChanged));
177
178        // Attach to parent if necessary
179        registerVariable(this->parentID_,       variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::parentChanged));
180    }
181
182    /**
183    @brief
184        Network function that object this instance to its correct parent.
185    */
186    void WorldEntity::parentChanged()
187    {
188        if (this->parentID_ != OBJECTID_UNKNOWN)
189        {
190            WorldEntity* parent = dynamic_cast<WorldEntity*>(Synchronisable::getSynchronisable(this->parentID_));
191            if (parent)
192                this->attachToParent(parent);
193        }
194    }
195
196    /**
197    @brief
198        Attaches this object to a parent SceneNode.
199    @Remarks
200        Only use this method if you know exactly what you're doing!
201        Normally, attaching works internally by attaching WE's.
202    */
203    void WorldEntity::attachToNode(Ogre::SceneNode* node)
204    {
205        Ogre::Node* parent = this->node_->getParent();
206        if (parent)
207            parent->removeChild(this->node_);
208        node->addChild(this->node_);
209    }
210
211    /**
212    @brief
213        Detaches this object from a parent SceneNode.
214    @Remarks
215        Only use this method if you know exactly what you're doing!
216        Normally, attaching works internally by attaching WE's.
217    */
218    void WorldEntity::detachFromNode(Ogre::SceneNode* node)
219    {
220        node->removeChild(this->node_);
221//        this->getScene()->getRootSceneNode()->addChild(this->node_);
222    }
223
224    /**
225    @brief
226        Network callback for the collision type. Only change the type if it was valid.
227    */
228    void WorldEntity::collisionTypeChanged()
229    {
230        if (this->collisionTypeSynchronised_ != Dynamic &&
231            this->collisionTypeSynchronised_ != Kinematic &&
232            this->collisionTypeSynchronised_ != Static &&
233            this->collisionTypeSynchronised_ != None)
234        {
235            CCOUT(1) << "Error when collsion Type was received over network. Unknown enum value:" << this->collisionTypeSynchronised_ << std::endl;
236        }
237        else if (this->collisionTypeSynchronised_ != collisionType_)
238        {
239            if (this->parent_)
240                CCOUT(2) << "Warning: Network connection tried to set the collision type of an attached WE. Ignoring." << std::endl;
241            else
242                this->setCollisionType(this->collisionTypeSynchronised_);
243        }
244    }
245
246    //! Network callback for this->bPhysicsActive_
247    void WorldEntity::physicsActivityChanged()
248    {
249        if (this->bPhysicsActiveSynchronised_)
250            this->activatePhysics();
251        else
252            this->deactivatePhysics();
253    }
254
255    //! Function is called to set the right flags in Bullet (if there is physics at all)
256    void WorldEntity::collisionCallbackActivityChanged()
257    {
258        if (this->hasPhysics())
259        {
260            if (bCollisionCallbackActive_)
261                this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() |
262                    btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
263            else
264                this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() &
265                    ~btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
266        }
267    }
268
269    /**
270    @brief
271        Attaches a child WorldEntity to this object. This calls notifyBeingAttached()
272        of the child WE.
273    @Note
274        The collision shape of the child object gets attached nevertheless. That also means
275        that you can change the collision shape of the child and it correctly cascadeds the changes to this instance.
276        Be aware of this implication: When implementing attaching of kinematic objects to others, you have to change
277        this behaviour because you then might not want to merge the collision shapes.
278    */
279    void WorldEntity::attach(WorldEntity* object)
280    {
281        if (object == this)
282        {
283            COUT(2) << "Warning: Can't attach a WorldEntity to itself." << std::endl;
284            return;
285        }
286
287        if (!object->notifyBeingAttached(this))
288            return;
289
290        this->attachNode(object->node_);
291        this->children_.insert(object);
292
293        this->attachCollisionShape(object->collisionShape_);
294        // mass
295        this->childrenMass_ += object->getMass();
296        recalculateMassProps();
297    }
298
299    /**
300    @brief
301        Function gets called when this object is being attached to a new parent.
302
303        This operation is only allowed if the collision types "like" each other.
304        - You cannot a attach a non physical object to a physical one.
305        - Dynamic object can NOT be attached at all.
306        - It is also not possible to attach a kinematic to a dynamic one.
307        - Attaching of kinematic objects otherwise is not yet supported.
308    */
309    bool WorldEntity::notifyBeingAttached(WorldEntity* newParent)
310    {
311        // check first whether attaching is even allowed
312        if (this->hasPhysics())
313        {
314            if (!newParent->hasPhysics())
315            {
316                COUT(2) << "Warning: Cannot attach a physical object to a non physical one." << std::endl;
317                return false;
318            }
319            else if (this->isDynamic())
320            {
321                COUT(2) << "Warning: Cannot attach a dynamic object to a WorldEntity." << std::endl;
322                return false;
323            }
324            else if (this->isKinematic() && newParent->isDynamic())
325            {
326                COUT(2) << "Warning: Cannot attach a kinematic object to a dynamic one." << std::endl;
327                return false;
328            }
329            else if (this->isKinematic())
330            {
331                COUT(2) << "Warning: Cannot attach a kinematic object to a static or kinematic one: Not yet implemented." << std::endl;
332                return false;
333            }
334        }
335
336        if (this->isPhysicsActive())
337            this->bPhysicsActiveBeforeAttaching_ = true;
338        this->deactivatePhysics();
339
340        if (this->parent_)
341            this->detachFromParent();
342
343        this->parent_ = newParent;
344        this->parentID_ = newParent->getObjectID();
345
346        // apply transform to collision shape
347        this->collisionShape_->setPosition(this->getPosition());
348        this->collisionShape_->setOrientation(this->getOrientation());
349        // TODO: Scale
350       
351        return true;
352    }
353
354    /**
355    @brief
356        Detaches a child WorldEntity from this instance.
357    */
358    void WorldEntity::detach(WorldEntity* object)
359    {
360        if (this->children_.find(object) == this->children_.end())
361        {
362            CCOUT(2) << "Warning: Cannot detach an object that is not a child." << std::endl;
363            return;
364        }
365
366        // collision shapes
367        this->detachCollisionShape(object->collisionShape_);
368
369        // mass
370        if (object->getMass() > 0.0f)
371        {
372            this->childrenMass_ -= object->getMass();
373            recalculateMassProps();
374        }
375
376        this->detachNode(object->node_);
377        this->children_.erase(object);
378
379        object->notifyDetached();
380    }
381
382    /**
383    @brief
384        Function gets called when the object has been detached from its parent.
385    */
386    void WorldEntity::notifyDetached()
387    {
388        this->parent_ = 0;
389        this->parentID_ = OBJECTID_UNKNOWN;
390
391        // reset orientation of the collisionShape (cannot be set within a WE usually)
392        this->collisionShape_->setPosition(Vector3::ZERO);
393        this->collisionShape_->setOrientation(Quaternion::IDENTITY);
394        // TODO: Scale
395
396        if (this->bPhysicsActiveBeforeAttaching_)
397        {
398            this->activatePhysics();
399            this->bPhysicsActiveBeforeAttaching_ = false;
400        }
401    }
402
403    //! Returns an attached object (merely for XMLPort).
404    WorldEntity* WorldEntity::getAttachedObject(unsigned int index)
405    {
406        unsigned int i = 0;
407        for (std::set<WorldEntity*>::const_iterator it = this->children_.begin(); it != this->children_.end(); ++it)
408        {
409            if (i == index)
410                return (*it);
411            ++i;
412        }
413        return 0;
414    }
415
416    //! Attaches an Ogre::SceneNode to this WorldEntity.
417    void WorldEntity::attachNode(Ogre::SceneNode* node)
418    {
419        Ogre::Node* parent = node->getParent();
420        if (parent)
421            parent->removeChild(node);
422        this->node_->addChild(node);
423    }
424
425    //! Detaches an Ogre::SceneNode from this WorldEntity.
426    void WorldEntity::detachNode(Ogre::SceneNode* node)
427    {
428        this->node_->removeChild(node);
429//        this->getScene()->getRootSceneNode()->addChild(node);
430    }
431
432    //! Attaches an Ogre::MovableObject to this WorldEntity.
433    void WorldEntity::attachOgreObject(Ogre::MovableObject* object)
434    {
435        this->node_->attachObject(object);
436    }
437
438    //! Detaches an Ogre::MovableObject from this WorldEntity.
439    void WorldEntity::detachOgreObject(Ogre::MovableObject* object)
440    {
441        this->node_->detachObject(object);
442    }
443
444    //! Detaches an Ogre::MovableObject (by string) from this WorldEntity.
445    Ogre::MovableObject* WorldEntity::detachOgreObject(const Ogre::String& name)
446    {
447        return this->node_->detachObject(name);
448    }
449
450    //! Attaches a collision Shape to this object (delegated to the internal CompoundCollisionShape)
451    void WorldEntity::attachCollisionShape(CollisionShape* shape)
452    {
453        this->collisionShape_->attach(shape);
454        // Note: this->collisionShape_ already notifies us of any changes.
455    }
456
457    //! Detaches a collision Shape from this object (delegated to the internal CompoundCollisionShape)
458    void WorldEntity::detachCollisionShape(CollisionShape* shape)
459    {
460        // Note: The collision shapes may not be detached with this function!
461        this->collisionShape_->detach(shape);
462        // Note: this->collisionShape_ already notifies us of any changes.
463    }
464
465    //! Returns an attached collision Shape of this object (delegated to the internal CompoundCollisionShape)
466    CollisionShape* WorldEntity::getAttachedCollisionShape(unsigned int index)
467    {
468        return this->collisionShape_->getAttachedShape(index);
469    }
470
471    // Note: These functions are placed in WorldEntity.h as inline functions for the release build.
472#ifndef _NDEBUG
473    const Vector3& WorldEntity::getPosition() const
474    {
475        return this->node_->getPosition();
476    }
477
478    const Quaternion& WorldEntity::getOrientation() const
479    {
480        return this->node_->getOrientation();
481    }
482
483    const Vector3& WorldEntity::getScale3D() const
484    {
485        return this->node_->getScale();
486    }
487#endif
488
489    //! Returns the position relative to the root space
490    const Vector3& WorldEntity::getWorldPosition() const
491    {
492        return this->node_->_getDerivedPosition();
493    }
494
495    //! Returns the orientation relative to the root space
496    const Quaternion& WorldEntity::getWorldOrientation() const
497    {
498        return this->node_->_getDerivedOrientation();
499    }
500
501    //! Returns the scaling applied relative to the root space in 3 coordinates
502    const Vector3& WorldEntity::getWorldScale3D() const
503    {
504        return this->node_->_getDerivedScale();
505    }
506
507    /**
508    @brief
509        Returns the scaling applied relative to the root space in 3 coordinates
510    @return
511        Returns the scaling if it is uniform, 1.0f otherwise.
512    */
513    float WorldEntity::getWorldScale() const
514    {
515        Vector3 scale = this->getWorldScale3D();
516        return (scale.x == scale.y && scale.x == scale.z) ? scale.x : 1;
517    }
518
519    /**
520    @brief
521        Sets the three dimensional scaling of this object.
522    @Note
523        Scaling physical objects has not yet been implemented and is therefore forbidden.
524    */
525    void WorldEntity::setScale3D(const Vector3& scale)
526    {
527/*
528HACK HACK HACK
529        if (bScalePhysics && this->hasPhysics() && scale != Vector3::UNIT_SCALE)
530        {
531            CCOUT(2) << "Warning: Cannot set the scale of a physical object: Not yet implemented. Ignoring scaling." << std::endl;
532            return;
533        }
534HACK HACK HACK
535*/
536        this->node_->setScale(scale);
537
538        this->changedScale();
539    }
540
541    /**
542    @brief
543        Translates this WorldEntity by a vector.
544    @param relativeTo
545        @see TransformSpace::Enum
546    */
547    void WorldEntity::translate(const Vector3& distance, TransformSpace::Enum relativeTo)
548    {
549        switch (relativeTo)
550        {
551        case TransformSpace::Local:
552            // position is relative to parent so transform downwards
553            this->setPosition(this->getPosition() + this->getOrientation() * distance);
554            break;
555        case TransformSpace::Parent:
556            this->setPosition(this->getPosition() + distance);
557            break;
558        case TransformSpace::World:
559            // position is relative to parent so transform upwards
560            if (this->node_->getParent())
561                setPosition(getPosition() + (node_->getParent()->_getDerivedOrientation().Inverse() * distance)
562                    / node_->getParent()->_getDerivedScale());
563            else
564                this->setPosition(this->getPosition() + distance);
565            break;
566        }
567    }
568
569    /**
570    @brief
571        Rotates this WorldEntity by a quaternion.
572    @param relativeTo
573        @see TransformSpace::Enum
574    */
575    void WorldEntity::rotate(const Quaternion& rotation, TransformSpace::Enum relativeTo)
576    {
577        switch(relativeTo)
578        {
579        case TransformSpace::Local:
580            this->setOrientation(this->getOrientation() * rotation);
581            break;
582        case TransformSpace::Parent:
583            // Rotations are normally relative to local axes, transform up
584            this->setOrientation(rotation * this->getOrientation());
585            break;
586        case TransformSpace::World:
587            // Rotations are normally relative to local axes, transform up
588            this->setOrientation(this->getOrientation() * this->getWorldOrientation().Inverse()
589                * rotation * this->getWorldOrientation());
590            break;
591        }
592    }
593
594    /**
595    @brief
596        Makes this WorldEntity look a specific target location.
597    @param relativeTo
598        @see TransformSpace::Enum
599    @param localDirectionVector
600        The vector which normally describes the natural direction of the object, usually -Z.
601    */
602    void WorldEntity::lookAt(const Vector3& target, TransformSpace::Enum relativeTo, const Vector3& localDirectionVector)
603    {
604        Vector3 origin;
605        switch (relativeTo)
606        {
607        case TransformSpace::Local:
608            origin = Vector3::ZERO;
609            break;
610        case TransformSpace::Parent:
611            origin = this->getPosition();
612            break;
613        case TransformSpace::World:
614            origin = this->getWorldPosition();
615            break;
616        }
617        this->setDirection(target - origin, relativeTo, localDirectionVector);
618    }
619
620    /**
621    @brief
622        Makes this WorldEntity look in specific direction.
623    @param relativeTo
624        @see TransformSpace::Enum
625    @param localDirectionVector
626        The vector which normally describes the natural direction of the object, usually -Z.
627    */
628    void WorldEntity::setDirection(const Vector3& direction, TransformSpace::Enum relativeTo, const Vector3& localDirectionVector)
629    {
630        Quaternion savedOrientation(this->getOrientation());
631        Ogre::Node::TransformSpace ogreRelativeTo;
632        switch (relativeTo)
633        {
634        case TransformSpace::Local:
635            ogreRelativeTo = Ogre::Node::TS_LOCAL; break;
636        case TransformSpace::Parent:
637            ogreRelativeTo = Ogre::Node::TS_PARENT; break;
638        case TransformSpace::World:
639            ogreRelativeTo = Ogre::Node::TS_WORLD; break;
640        }
641        this->node_->setDirection(direction, ogreRelativeTo, localDirectionVector);
642        Quaternion newOrientation(this->node_->getOrientation());
643        this->node_->setOrientation(savedOrientation);
644        this->setOrientation(newOrientation);
645    }
646
647    //! Activates physics if the CollisionType is not None.
648    void WorldEntity::activatePhysics()
649    {
650        if (this->isActive() && this->hasPhysics() && !this->isPhysicsActive() && !this->parent_)
651        {
652            this->getScene()->addPhysicalObject(this);
653            this->bPhysicsActive_ = true;
654            this->bPhysicsActiveSynchronised_ = true;
655        }
656    }
657
658    //! Deactivates physics but the CollisionType does not change.
659    void WorldEntity::deactivatePhysics()
660    {
661        if (this->isPhysicsActive())
662        {
663            this->getScene()->removePhysicalObject(this);
664            this->bPhysicsActive_ = false;
665            this->bPhysicsActiveSynchronised_ = false;
666        }
667    }
668
669    //! Tells whether the object has already been added to the Bullet physics World.
670    bool WorldEntity::addedToPhysicalWorld() const
671    {
672        return this->physicalBody_ && this->physicalBody_->isInWorld();
673    }
674
675    /**
676    @brief
677        Sets the CollisionType. This alters the object significantly! @see CollisionType.
678    @Note
679        Operation does not work on attached WorldEntities.
680    */
681    void WorldEntity::setCollisionType(CollisionType type)
682    {
683        if (this->collisionType_ == type)
684            return;
685
686        // If we are already attached to a parent, this would be a bad idea..
687        if (this->parent_)
688        {
689            CCOUT(2) << "Warning: Cannot set the collision type of a WorldEntity with a parent." << std::endl;
690            return;
691        }
692
693        // Check for type legality. Could be StaticEntity or MobileEntity.
694        if (!this->isCollisionTypeLegal(type))
695            return;
696
697        if (this->isPhysicsActive())
698            this->deactivatePhysics();
699
700        bool bReactivatePhysics = true;
701        if (this->hasPhysics() && !this->isPhysicsActive())
702            bReactivatePhysics = false;
703
704        // Check whether we have to create or destroy.
705        if (type != None && this->collisionType_ == None)
706        {
707/*
708HACK HACK HACK
709            // Check whether there was some scaling applied.
710            if (!this->node_->getScale().positionEquals(Vector3(1, 1, 1), 0.001))
711            {
712                CCOUT(2) << "Warning: Cannot create a physical body if there is scaling applied to the node: Not yet implemented." << std::endl;
713                return;
714            }
715HACK HACK HACK
716*/
717            // Create new rigid body
718            btRigidBody::btRigidBodyConstructionInfo bodyConstructionInfo(0, this, this->collisionShape_->getCollisionShape());
719            this->physicalBody_ = new btRigidBody(bodyConstructionInfo);
720            this->physicalBody_->setUserPointer(this);
721            this->physicalBody_->setActivationState(DISABLE_DEACTIVATION);
722        }
723        else if (type == None && this->collisionType_ != None)
724        {
725            // Destroy rigid body
726            assert(this->physicalBody_);
727            deactivatePhysics();
728            delete this->physicalBody_;
729            this->physicalBody_ = 0;
730            this->collisionType_ = None;
731            this->collisionTypeSynchronised_ = None;
732            return;
733        }
734
735        // Change type
736        switch (type)
737        {
738        case Dynamic:
739            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !(btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT));
740            break;
741        case Kinematic:
742            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT);
743            break;
744        case Static:
745            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT);
746            break;
747        case None:
748            assert(false); // Doesn't happen
749            return;
750        }
751
752        // Only sets this->collisionType_
753        // However the assertion is to ensure that the internal bullet setting is right
754        updateCollisionType();
755        assert(this->collisionType_ == type);
756
757        // update mass and inertia tensor
758        recalculateMassProps();
759        internalSetPhysicsProps();
760        collisionCallbackActivityChanged();
761        if (bReactivatePhysics)
762            activatePhysics();
763    }
764
765    //! Sets the CollisionType by string (used for the XMLPort)
766    void WorldEntity::setCollisionTypeStr(const std::string& typeStr)
767    {
768        std::string typeStrLower = getLowercase(typeStr);
769        CollisionType type;
770        if (typeStrLower == "dynamic")
771            type = Dynamic;
772        else if (typeStrLower == "static")
773            type = Static;
774        else if (typeStrLower == "kinematic")
775            type = Kinematic;
776        else if (typeStrLower == "none")
777            type = None;
778        else
779            ThrowException(ParseError, std::string("Attempting to set an unknown collision type: '") + typeStr + "'.");
780        this->setCollisionType(type);
781    }
782
783    //! Gets the CollisionType by string (used for the XMLPort)
784    std::string WorldEntity::getCollisionTypeStr() const
785    {
786        switch (this->getCollisionType())
787        {
788            case Dynamic:
789                return "dynamic";
790            case Kinematic:
791                return "kinematic";
792            case Static:
793                return "static";
794            case None:
795                return "none";
796            default:
797                assert(false);
798                return "";
799        }
800    }
801
802    void WorldEntity::updateCollisionType()
803    {
804        if (!this->physicalBody_)
805            this->collisionType_ = None;
806        else if (this->physicalBody_->isKinematicObject())
807            this->collisionType_ = Kinematic;
808        else if (this->physicalBody_->isStaticObject())
809            this->collisionType_ = Static;
810        else
811            this->collisionType_ = Dynamic;
812        this->collisionTypeSynchronised_ = this->collisionType_;
813    }
814
815    /**
816    @brief
817        Recalculates the accumulated child mass and calls recalculateMassProps()
818        and notifies the parent of the change.
819    @Note
820        Called by a child WE
821    */
822    void WorldEntity::notifyChildMassChanged()
823    {
824        // Note: CollisionShape changes of a child get handled over the internal CompoundCollisionShape already
825        // Recalculate mass
826        this->childrenMass_ = 0.0f;
827        for (std::set<WorldEntity*>::const_iterator it = this->children_.begin(); it != this->children_.end(); ++it)
828            this->childrenMass_ += (*it)->getMass();
829        recalculateMassProps();
830        // Notify parent WE
831        if (this->parent_)
832            parent_->notifyChildMassChanged();
833    }
834
835    /**
836    @brief
837        Undertakes the necessary steps to change the collision shape in Bullet, even at runtime.
838    @Note
839        - called by this->collisionShape_
840        - May have a REALLY big overhead when called continuously at runtime, because then we need
841          to remove the physical body from Bullet and add it again.
842    */
843    void WorldEntity::notifyCollisionShapeChanged()
844    {
845        if (hasPhysics())
846        {
847            // Bullet doesn't like sudden changes of the collision shape, so we remove and add it again
848            if (this->addedToPhysicalWorld())
849            {
850                this->deactivatePhysics();
851                this->physicalBody_->setCollisionShape(this->collisionShape_->getCollisionShape());
852                this->activatePhysics();
853            }
854            else
855                this->physicalBody_->setCollisionShape(this->collisionShape_->getCollisionShape());
856        }
857        recalculateMassProps();
858    }
859
860    //! Updates all mass dependent parameters (mass, inertia tensor and child mass)
861    void WorldEntity::recalculateMassProps()
862    {
863        // Store local inertia for faster access. Evaluates to (0,0,0) if there is no collision shape.
864        float totalMass = this->mass_ + this->childrenMass_;
865        this->collisionShape_->calculateLocalInertia(totalMass, this->localInertia_);
866        if (this->hasPhysics())
867        {
868            if (this->isStatic())
869            {
870                // Just set everything to zero
871                this->physicalBody_->setMassProps(0.0f, btVector3(0, 0, 0));
872            }
873            else if ((this->mass_ + this->childrenMass_) == 0.0f)
874            {
875                // Use default values to avoid very large or very small values
876                CCOUT(4) << "Warning: Setting the internal physical mass to 1.0 because mass_ is 0.0" << std::endl;
877                btVector3 inertia(0, 0, 0);
878                this->collisionShape_->calculateLocalInertia(1.0f, inertia);
879                this->physicalBody_->setMassProps(1.0f, inertia);
880            }
881            else
882            {
883                this->physicalBody_->setMassProps(totalMass, this->localInertia_);
884            }
885        }
886    }
887
888    //! Copies our own parameters for restitution, angular factor, dampings and friction to the bullet rigid body.
889    void WorldEntity::internalSetPhysicsProps()
890    {
891        if (this->hasPhysics())
892        {
893            this->physicalBody_->setRestitution(this->restitution_);
894            this->physicalBody_->setAngularFactor(this->angularFactor_);
895            this->physicalBody_->setDamping(this->linearDamping_, this->angularDamping_);
896            this->physicalBody_->setFriction(this->friction_);
897        }
898    }
899}
Note: See TracBrowser for help on using the repository browser.