Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 11071 was 11071, checked in by landauf, 8 years ago

merged branch cpp11_v3 back to trunk

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