Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core6/src/orxonox/worldentities/WorldEntity.cc @ 9629

Last change on this file since 9629 was 9629, checked in by landauf, 11 years ago

BaseObject now requires a Context instead of a creator (BaseObject*) in its constructor.
Namespace, Level, and Scene inherit from Context

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