Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/pickup3/src/orxonox/worldentities/WorldEntity.cc @ 6486

Last change on this file since 6486 was 6485, checked in by dafrick, 15 years ago

Added changedActivity and changedVisibility method to WorldEntity, such that, when either is changed it is changed for all attached objects as well.
If this is already implemented somehow and somehwere, my mistake, but I looked and found nothing.

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