Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/lastmanstanding/src/orxonox/worldentities/WorldEntity.cc @ 7549

Last change on this file since 7549 was 7401, checked in by landauf, 14 years ago

merged doc branch back to trunk

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