Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/Presentation_HS17/src/orxonox/worldentities/WorldEntity.cc @ 11686

Last change on this file since 11686 was 11686, checked in by patricwi, 6 years ago

merged scriptable controller but not tested

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