Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/pch/src/orxonox/objects/worldentities/WorldEntity.cc @ 3164

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

The usual convention with our headers is to use ≠ for all third party libraries.

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