Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/revampbigships/src/orxonox/worldentities/WorldEntity.cc @ 9873

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

merged core6 back to trunk

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