Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ScriptableController_HS17/src/orxonox/worldentities/WorldEntity.cc @ 11518

Last change on this file since 11518 was 11518, checked in by kohlia, 7 years ago

Nothing to see yet, really.

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