Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/objects/worldentities/WorldEntity.cc @ 2809

Last change on this file since 2809 was 2787, checked in by rgrieder, 16 years ago

Bugfix: _NDEBUG is never defined.

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