Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/wagnis_HS18/src/orxonox/worldentities/WorldEntity.cc @ 12035

Last change on this file since 12035 was 12028, checked in by merholzl, 6 years ago

added scriptable controller

  • Property svn:eol-style set to native
File size: 39.8 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *      Reto Grieder (physics)
25 *   Co-authors:
26 *      ...
27 *
28 */
29
30#include "WorldEntity.h"
31
32#include <OgreBillboardSet.h>
33#include <OgreCamera.h>
34#include <OgreEntity.h>
35#include <OgreParticleSystem.h>
36#include <OgreSceneManager.h>
37#include <OgreSceneNode.h>
38#include <BulletDynamics/Dynamics/btRigidBody.h>
39
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#if OGRE_VERSION >= 0x010900
558        object->getUserObjectBindings().setUserAny(Ogre::Any(static_cast<OrxonoxClass*>(this)));
559#else
560        object->setUserAny(Ogre::Any(static_cast<OrxonoxClass*>(this)));
561#endif
562    }
563
564    void WorldEntity::attachOgreObject(Ogre::BillboardSet* object)
565        { this->attachOgreObject(static_cast<Ogre::MovableObject*>(object)); }
566    void WorldEntity::attachOgreObject(Ogre::Camera* object)
567        { this->attachOgreObject(static_cast<Ogre::MovableObject*>(object)); }
568    void WorldEntity::attachOgreObject(Ogre::Entity* object)
569        { this->attachOgreObject(static_cast<Ogre::MovableObject*>(object)); }
570    void WorldEntity::attachOgreObject(Ogre::ParticleSystem* object)
571        { this->attachOgreObject(static_cast<Ogre::MovableObject*>(object)); }
572
573    //! Detaches an Ogre::MovableObject from this WorldEntity.
574    void WorldEntity::detachOgreObject(Ogre::MovableObject* object)
575    {
576#if OGRE_VERSION >= 0x010900
577        object->getUserObjectBindings().setUserAny(Ogre::Any(static_cast<OrxonoxClass*>(nullptr)));
578#else
579        object->setUserAny(Ogre::Any(static_cast<OrxonoxClass*>(nullptr)));
580#endif
581        this->node_->detachObject(object);
582    }
583
584    void WorldEntity::detachOgreObject(Ogre::BillboardSet* object)
585        { this->detachOgreObject(static_cast<Ogre::MovableObject*>(object)); }
586    void WorldEntity::detachOgreObject(Ogre::Camera* object)
587        { this->detachOgreObject(static_cast<Ogre::MovableObject*>(object)); }
588    void WorldEntity::detachOgreObject(Ogre::Entity* object)
589        { this->detachOgreObject(static_cast<Ogre::MovableObject*>(object)); }
590    void WorldEntity::detachOgreObject(Ogre::ParticleSystem* object)
591        { this->detachOgreObject(static_cast<Ogre::MovableObject*>(object)); }
592
593    //! Detaches an Ogre::MovableObject (by string) from this WorldEntity.
594    Ogre::MovableObject* WorldEntity::detachOgreObject(const Ogre::String& name)
595    {
596        return this->node_->detachObject(name);
597    }
598
599    //! Attaches a collision Shape to this object (delegated to the internal CompoundCollisionShape)
600    void WorldEntity::attachCollisionShape(CollisionShape* shape)
601    {
602        this->collisionShape_->attach(shape);
603        // Note: this->collisionShape_ already notifies us of any changes.
604    }
605
606    //! Detaches a collision Shape from this object (delegated to the internal CompoundCollisionShape)
607    void WorldEntity::detachCollisionShape(CollisionShape* shape)
608    {
609        // Note: The collision shapes may not be detached with this function!
610        this->collisionShape_->detach(shape);
611        // Note: this->collisionShape_ already notifies us of any changes.
612    }
613
614    //! Returns an attached collision Shape of this object (delegated to the internal CompoundCollisionShape)
615    CollisionShape* WorldEntity::getAttachedCollisionShape(unsigned int index)
616    {
617        return this->collisionShape_->getAttachedShape(index);
618    }
619
620    // Note: These functions are placed in WorldEntity.h as inline functions for the release build.
621#ifndef ORXONOX_RELEASE
622    const Vector3& WorldEntity::getPosition() const
623    {
624        return this->node_->getPosition();
625    }
626
627    const Quaternion& WorldEntity::getOrientation() const
628    {
629        return this->node_->getOrientation();
630    }
631
632    const Vector3& WorldEntity::getScale3D() const
633    {
634        return this->node_->getScale();
635    }
636#endif
637
638    //! Returns the position relative to the root space
639    const Vector3& WorldEntity::getWorldPosition() const
640    {
641        return this->node_->_getDerivedPosition();
642    }
643
644    //! Returns the orientation relative to the root space
645    const Quaternion& WorldEntity::getWorldOrientation() const
646    {
647        return this->node_->_getDerivedOrientation();
648    }
649
650    //! Returns the scaling applied relative to the root space in 3 coordinates
651    const Vector3& WorldEntity::getWorldScale3D() const
652    {
653        return this->node_->_getDerivedScale();
654    }
655
656    /**
657    @brief
658        Returns the scaling applied relative to the root space in 3 coordinates
659    @return
660        Returns the scaling if it is uniform, 1.0f otherwise.
661    */
662    float WorldEntity::getWorldScale() const
663    {
664        Vector3 scale = this->getWorldScale3D();
665        return (scale.x == scale.y && scale.x == scale.z) ? scale.x : 1;
666    }
667
668    /**
669    @brief
670        Sets the three dimensional scaling of this object.
671    @note
672        Scaling physical objects has not yet been implemented and is therefore forbidden.
673    */
674    void WorldEntity::setScale3D(const Vector3& scale)
675    {
676        // If physics is enabled scale the attached CollisionShape.
677        /*if (this->hasPhysics() && this->collisionShape_ != nullptr)
678        {
679            this->collisionShape_->setScale3D(scale);
680        }*/
681
682        this->node_->setScale(scale);
683
684        this->changedScale();
685    }
686
687    /**
688    @brief
689        Translates this WorldEntity by a vector.
690    @param distance
691        The relative distance of the translation
692    @param relativeTo
693        The TransformSpace of this translation
694    */
695    void WorldEntity::translate(const Vector3& distance, TransformSpace relativeTo)
696    {
697        switch (relativeTo)
698        {
699        case TransformSpace::Local:
700            // position is relative to parent so transform downwards
701            this->setPosition(this->getPosition() + this->getOrientation() * distance);
702            break;
703        case TransformSpace::Parent:
704            this->setPosition(this->getPosition() + distance);
705            break;
706        case TransformSpace::World:
707            // position is relative to parent so transform upwards
708            if (this->node_->getParent())
709                setPosition(getPosition() + (node_->getParent()->_getDerivedOrientation().Inverse() * distance)
710                    / node_->getParent()->_getDerivedScale());
711            else
712                this->setPosition(this->getPosition() + distance);
713            break;
714        }
715    }
716
717    /**
718    @brief
719        Rotates this WorldEntity by a quaternion.
720    @param rotation
721        The desired relative rotation
722    @param relativeTo
723        The TransformSpace of this translation
724    */
725    void WorldEntity::rotate(const Quaternion& rotation, TransformSpace relativeTo)
726    {
727        switch(relativeTo)
728        {
729        case TransformSpace::Local:
730            this->setOrientation(this->getOrientation() * rotation);
731            break;
732        case TransformSpace::Parent:
733            // Rotations are normally relative to local axes, transform up
734            this->setOrientation(rotation * this->getOrientation());
735            break;
736        case TransformSpace::World:
737            // Rotations are normally relative to local axes, transform up
738            this->setOrientation(this->getOrientation() * this->getWorldOrientation().Inverse()
739                * rotation * this->getWorldOrientation());
740            break;
741        }
742    }
743
744    /**
745    @brief
746        Makes this WorldEntity look at a specific target location.
747    @param target
748        An absolute point in the space which defines the direction of the entity
749    @param relativeTo
750        The TransformSpace of this translation
751    @param localDirectionVector
752        The vector which normally describes the natural direction of the object, usually -Z.
753    */
754    void WorldEntity::lookAt(const Vector3& target, TransformSpace relativeTo, const Vector3& localDirectionVector)
755    {
756        Vector3 origin(0, 0, 0);
757        switch (relativeTo)
758        {
759        case TransformSpace::Local:
760            origin = Vector3::ZERO;
761            break;
762        case TransformSpace::Parent:
763            origin = this->getPosition();
764            break;
765        case TransformSpace::World:
766            origin = this->getWorldPosition();
767            break;
768        }
769        this->setDirection(target - origin, relativeTo, localDirectionVector);
770    }
771
772    /**
773    @brief
774        Makes this WorldEntity look in specific direction.
775    @param direction
776        A point relative to the position of the WorldEntity which defines its orientation
777    @param relativeTo
778        The TransformSpace of this translation
779    @param localDirectionVector
780        The vector which normally describes the natural direction of the object, usually -Z.
781    */
782    void WorldEntity::setDirection(const Vector3& direction, TransformSpace relativeTo, const Vector3& localDirectionVector)
783    {
784        Quaternion savedOrientation(this->getOrientation());
785        this->node_->setDirection(direction, static_cast<Ogre::Node::TransformSpace>(relativeTo), localDirectionVector);
786        Quaternion newOrientation(this->node_->getOrientation());
787        this->node_->setOrientation(savedOrientation);
788        this->setOrientation(newOrientation);
789    }
790
791    //! Activates physics if the CollisionType is not None.
792    void WorldEntity::activatePhysics()
793    {
794        if (this->isActive() && this->hasPhysics() && !this->isPhysicsActive() && !this->parent_)
795        {
796            this->getScene()->addPhysicalObject(this);
797            this->bPhysicsActive_ = true;
798            this->bPhysicsActiveSynchronised_ = true;
799        }
800    }
801
802    //! Deactivates physics but the CollisionType does not change.
803    void WorldEntity::deactivatePhysics()
804    {
805        if (this->isPhysicsActive())
806        {
807            this->getScene()->removePhysicalObject(this);
808            this->bPhysicsActive_ = false;
809            this->bPhysicsActiveSynchronised_ = false;
810        }
811    }
812
813    //! Tells whether the object has already been added to the Bullet physics World.
814    bool WorldEntity::addedToPhysicalWorld() const
815    {
816        return this->physicalBody_ && this->physicalBody_->isInWorld();
817    }
818
819    /**
820    @brief
821        Sets the CollisionType. This alters the object significantly!
822    @note
823        Operation does not work on attached WorldEntities.
824    */
825    void WorldEntity::setCollisionType(CollisionType type)
826    {
827        if (this->collisionType_ == type)
828            return;
829
830        // If we are already attached to a parent, this would be a bad idea..
831        if (this->parent_)
832        {
833            orxout(internal_warning) << "Cannot set the collision type of a WorldEntity with a parent." << endl;
834            return;
835        }
836
837        // Check for type legality. Could be StaticEntity or MobileEntity.
838        if (!this->isCollisionTypeLegal(type))
839            return;
840
841        if (this->isPhysicsActive())
842            this->deactivatePhysics();
843
844        bool bReactivatePhysics = true;
845        if (this->hasPhysics() && !this->isPhysicsActive())
846            bReactivatePhysics = false;
847
848        // Check whether we have to create or destroy.
849        if (type != CollisionType::None && this->collisionType_ == CollisionType::None)
850        {
851/*
852HACK HACK HACK
853            // Check whether there was some scaling applied.
854            if (!this->node_->getScale().positionEquals(Vector3(1, 1, 1), 0.001))
855            {
856                orxout(internal_warning) << "Cannot create a physical body if there is scaling applied to the node: Not yet implemented." << endl;
857                return;
858            }
859HACK HACK HACK
860*/
861            // Create new rigid body
862            btRigidBody::btRigidBodyConstructionInfo bodyConstructionInfo(0, this, this->collisionShape_->getCollisionShape());
863            this->physicalBody_ = new btRigidBody(bodyConstructionInfo);
864            this->physicalBody_->setUserPointer(this);
865            this->physicalBody_->setActivationState(DISABLE_DEACTIVATION);
866        }
867        else if (type == CollisionType::None && this->collisionType_ != CollisionType::None)
868        {
869            // Destroy rigid body
870            assert(this->physicalBody_);
871            deactivatePhysics();
872            delete this->physicalBody_;
873            this->physicalBody_ = nullptr;
874            this->collisionType_ = CollisionType::None;
875            this->collisionTypeSynchronised_ = CollisionType::None;
876            return;
877        }
878
879        // Change type
880        switch (type)
881        {
882        case CollisionType::Dynamic:
883            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_STATIC_OBJECT & !btCollisionObject::CF_KINEMATIC_OBJECT);
884            break;
885        case CollisionType::Kinematic:
886            this->physicalBody_->setCollisionFlags((this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_STATIC_OBJECT) | btCollisionObject::CF_KINEMATIC_OBJECT);
887            break;
888        case CollisionType::Static:
889            this->physicalBody_->setCollisionFlags((this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_KINEMATIC_OBJECT) | btCollisionObject::CF_STATIC_OBJECT);
890            break;
891        case CollisionType::None:
892            assert(false); // Doesn't happen
893            return;
894        }
895        this->collisionType_ = type;
896        this->collisionTypeSynchronised_ = type;
897
898        // update mass and inertia tensor
899        recalculateMassProps();
900        internalSetPhysicsProps();
901        collisionCallbackActivityChanged();
902        collisionResponseActivityChanged();
903        if (bReactivatePhysics)
904            activatePhysics();
905    }
906
907    //! Sets the CollisionType by string (used for the XMLPort)
908    void WorldEntity::setCollisionTypeStr(const std::string& typeStr)
909    {
910        const std::string& typeStrLower = getLowercase(typeStr);
911        CollisionType type;
912        if (typeStrLower == "dynamic")
913            type = CollisionType::Dynamic;
914        else if (typeStrLower == "static")
915            type = CollisionType::Static;
916        else if (typeStrLower == "kinematic")
917            type = CollisionType::Kinematic;
918        else if (typeStrLower == "none")
919            type = CollisionType::None;
920        else
921            ThrowException(ParseError, std::string("Attempting to set an unknown collision type: '") + typeStr + "'.");
922        this->setCollisionType(type);
923    }
924
925    //! Gets the CollisionType by string (used for the XMLPort)
926    std::string WorldEntity::getCollisionTypeStr() const
927    {
928        switch (this->getCollisionType())
929        {
930            case CollisionType::Dynamic:
931                return "dynamic";
932            case CollisionType::Kinematic:
933                return "kinematic";
934            case CollisionType::Static:
935                return "static";
936            case CollisionType::None:
937                return "none";
938            default:
939                assert(false);
940                return "";
941        }
942    }
943
944    /**
945    @brief
946        Recalculates the accumulated child mass and calls recalculateMassProps()
947        and notifies the parent of the change.
948    @note
949        Called by a child WE
950    */
951    void WorldEntity::notifyChildMassChanged()
952    {
953        // Note: CollisionShape changes of a child get handled over the internal CompoundCollisionShape already
954        // Recalculate mass
955        this->childrenMass_ = 0.0f;
956        for (WorldEntity* child : this->children_)
957            this->childrenMass_ += child->getMass();
958        recalculateMassProps();
959        // Notify parent WE
960        if (this->parent_)
961            parent_->notifyChildMassChanged();
962    }
963
964    /**
965    @brief
966        Undertakes the necessary steps to change the collision shape in Bullet, even at runtime.
967    @note
968        - called by this->collisionShape_
969        - May have a REALLY big overhead when called continuously at runtime, because then we need
970          to remove the physical body from Bullet and add it again.
971    */
972    void WorldEntity::notifyCollisionShapeChanged()
973    {
974        if (hasPhysics())
975        {
976            // Bullet doesn't like sudden changes of the collision shape, so we remove and add it again
977            if (this->addedToPhysicalWorld())
978            {
979                this->deactivatePhysics();
980                this->physicalBody_->setCollisionShape(this->collisionShape_->getCollisionShape());
981                this->activatePhysics();
982            }
983            else
984                this->physicalBody_->setCollisionShape(this->collisionShape_->getCollisionShape());
985        }
986        recalculateMassProps();
987    }
988
989    //! Updates all mass dependent parameters (mass, inertia tensor and child mass)
990    void WorldEntity::recalculateMassProps()
991    {
992        // Store local inertia for faster access. Evaluates to (0,0,0) if there is no collision shape.
993        float totalMass = this->mass_ + this->childrenMass_;
994        this->collisionShape_->calculateLocalInertia(totalMass, this->localInertia_);
995        if (this->hasPhysics())
996        {
997            if (this->isStatic())
998            {
999                // Just set everything to zero
1000                this->physicalBody_->setMassProps(0.0f, btVector3(0, 0, 0));
1001            }
1002            else if (totalMass == 0.0f)
1003            {
1004                // Use default values to avoid very large or very small values
1005                orxout(internal_warning) << "Setting the internal physical mass to 1.0 because mass_ is 0.0" << endl;
1006                btVector3 inertia(0, 0, 0);
1007                this->collisionShape_->calculateLocalInertia(1.0f, inertia);
1008                this->physicalBody_->setMassProps(1.0f, inertia);
1009            }
1010            else
1011            {
1012                this->physicalBody_->setMassProps(totalMass, this->localInertia_);
1013            }
1014        }
1015    }
1016
1017    //! Copies our own parameters for restitution, angular factor, damping and friction to the bullet rigid body.
1018    void WorldEntity::internalSetPhysicsProps()
1019    {
1020        if (this->hasPhysics())
1021        {
1022            this->physicalBody_->setRestitution(this->restitution_);
1023            this->physicalBody_->setAngularFactor(this->angularFactor_);
1024            this->physicalBody_->setDamping(this->linearDamping_, this->angularDamping_);
1025            this->physicalBody_->setFriction(this->friction_);
1026            this->physicalBody_->setCcdMotionThreshold(this->ccdMotionThreshold_);
1027            this->physicalBody_->setCcdSweptSphereRadius(this->ccdSweptSphereRadius_);
1028        }
1029    }
1030}
Note: See TracBrowser for help on using the repository browser.