Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/environment2/src/orxonox/worldentities/WorldEntity.cc @ 8872

Last change on this file since 8872 was 8557, checked in by marwegma, 14 years ago

Godrays: Safety commit. 90017 N8

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