Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/newlevel2012/src/orxonox/worldentities/WorldEntity.cc @ 9193

Last change on this file since 9193 was 9175, checked in by weigeltm, 13 years ago

removed attach-command, got rid of error messages, attached weapons to towers

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