Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/TowerDefense_HS18/src/orxonox/worldentities/WorldEntity.cc @ 12025

Last change on this file since 12025 was 11795, checked in by landauf, 7 years ago

merged ogre1.9 (including cegui0.8) into new branch

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