Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/worldentities/WorldEntity.cc @ 7163

Last change on this file since 7163 was 7163, checked in by dafrick, 14 years ago

Merged presentation3 branch into trunk.

  • Property svn:eol-style set to native
File size: 37.0 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 relativeTo
653        @see WorldEntity::TransformSpace
654    */
655    void WorldEntity::translate(const Vector3& distance, TransformSpace relativeTo)
656    {
657        switch (relativeTo)
658        {
659        case WorldEntity::Local:
660            // position is relative to parent so transform downwards
661            this->setPosition(this->getPosition() + this->getOrientation() * distance);
662            break;
663        case WorldEntity::Parent:
664            this->setPosition(this->getPosition() + distance);
665            break;
666        case WorldEntity::World:
667            // position is relative to parent so transform upwards
668            if (this->node_->getParent())
669                setPosition(getPosition() + (node_->getParent()->_getDerivedOrientation().Inverse() * distance)
670                    / node_->getParent()->_getDerivedScale());
671            else
672                this->setPosition(this->getPosition() + distance);
673            break;
674        }
675    }
676
677    /**
678    @brief
679        Rotates this WorldEntity by a quaternion.
680    @param relativeTo
681        @see WorldEntity::TransformSpace
682    */
683    void WorldEntity::rotate(const Quaternion& rotation, TransformSpace relativeTo)
684    {
685        switch(relativeTo)
686        {
687        case WorldEntity::Local:
688            this->setOrientation(this->getOrientation() * rotation);
689            break;
690        case WorldEntity::Parent:
691            // Rotations are normally relative to local axes, transform up
692            this->setOrientation(rotation * this->getOrientation());
693            break;
694        case WorldEntity::World:
695            // Rotations are normally relative to local axes, transform up
696            this->setOrientation(this->getOrientation() * this->getWorldOrientation().Inverse()
697                * rotation * this->getWorldOrientation());
698            break;
699        }
700    }
701
702    /**
703    @brief
704        Makes this WorldEntity look at a specific target location.
705    @param relativeTo
706        @see WorldEntity::TransformSpace
707    @param localDirectionVector
708        The vector which normally describes the natural direction of the object, usually -Z.
709    */
710    void WorldEntity::lookAt(const Vector3& target, TransformSpace relativeTo, const Vector3& localDirectionVector)
711    {
712        Vector3 origin(0, 0, 0);
713        switch (relativeTo)
714        {
715        case WorldEntity::Local:
716            origin = Vector3::ZERO;
717            break;
718        case WorldEntity::Parent:
719            origin = this->getPosition();
720            break;
721        case WorldEntity::World:
722            origin = this->getWorldPosition();
723            break;
724        }
725        this->setDirection(target - origin, relativeTo, localDirectionVector);
726    }
727
728    /**
729    @brief
730        Makes this WorldEntity look in specific direction.
731    @param relativeTo
732        @see WorldEntity::TransformSpace
733    @param localDirectionVector
734        The vector which normally describes the natural direction of the object, usually -Z.
735    */
736    void WorldEntity::setDirection(const Vector3& direction, TransformSpace relativeTo, const Vector3& localDirectionVector)
737    {
738        Quaternion savedOrientation(this->getOrientation());
739        this->node_->setDirection(direction, static_cast<Ogre::Node::TransformSpace>(relativeTo), localDirectionVector);
740        Quaternion newOrientation(this->node_->getOrientation());
741        this->node_->setOrientation(savedOrientation);
742        this->setOrientation(newOrientation);
743    }
744
745    //! Activates physics if the CollisionType is not None.
746    void WorldEntity::activatePhysics()
747    {
748        if (this->isActive() && this->hasPhysics() && !this->isPhysicsActive() && !this->parent_)
749        {
750            this->getScene()->addPhysicalObject(this);
751            this->bPhysicsActive_ = true;
752            this->bPhysicsActiveSynchronised_ = true;
753        }
754    }
755
756    //! Deactivates physics but the CollisionType does not change.
757    void WorldEntity::deactivatePhysics()
758    {
759        if (this->isPhysicsActive())
760        {
761            this->getScene()->removePhysicalObject(this);
762            this->bPhysicsActive_ = false;
763            this->bPhysicsActiveSynchronised_ = false;
764        }
765    }
766
767    //! Tells whether the object has already been added to the Bullet physics World.
768    bool WorldEntity::addedToPhysicalWorld() const
769    {
770        return this->physicalBody_ && this->physicalBody_->isInWorld();
771    }
772
773    /**
774    @brief
775        Sets the CollisionType. This alters the object significantly! @see CollisionType.
776    @Note
777        Operation does not work on attached WorldEntities.
778    */
779    void WorldEntity::setCollisionType(CollisionType type)
780    {
781        if (this->collisionType_ == type)
782            return;
783
784        // If we are already attached to a parent, this would be a bad idea..
785        if (this->parent_)
786        {
787            CCOUT(2) << "Warning: Cannot set the collision type of a WorldEntity with a parent." << std::endl;
788            return;
789        }
790
791        // Check for type legality. Could be StaticEntity or MobileEntity.
792        if (!this->isCollisionTypeLegal(type))
793            return;
794
795        if (this->isPhysicsActive())
796            this->deactivatePhysics();
797
798        bool bReactivatePhysics = true;
799        if (this->hasPhysics() && !this->isPhysicsActive())
800            bReactivatePhysics = false;
801
802        // Check whether we have to create or destroy.
803        if (type != None && this->collisionType_ == None)
804        {
805/*
806HACK HACK HACK
807            // Check whether there was some scaling applied.
808            if (!this->node_->getScale().positionEquals(Vector3(1, 1, 1), 0.001))
809            {
810                CCOUT(2) << "Warning: Cannot create a physical body if there is scaling applied to the node: Not yet implemented." << std::endl;
811                return;
812            }
813HACK HACK HACK
814*/
815            // Create new rigid body
816            btRigidBody::btRigidBodyConstructionInfo bodyConstructionInfo(0, this, this->collisionShape_->getCollisionShape());
817            this->physicalBody_ = new btRigidBody(bodyConstructionInfo);
818            this->physicalBody_->setUserPointer(this);
819            this->physicalBody_->setActivationState(DISABLE_DEACTIVATION);
820        }
821        else if (type == None && this->collisionType_ != None)
822        {
823            // Destroy rigid body
824            assert(this->physicalBody_);
825            deactivatePhysics();
826            delete this->physicalBody_;
827            this->physicalBody_ = 0;
828            this->collisionType_ = None;
829            this->collisionTypeSynchronised_ = None;
830            return;
831        }
832
833        // Change type
834        switch (type)
835        {
836        case Dynamic:
837            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_STATIC_OBJECT & !btCollisionObject::CF_KINEMATIC_OBJECT);
838            break;
839        case Kinematic:
840            this->physicalBody_->setCollisionFlags((this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_STATIC_OBJECT) | btCollisionObject::CF_KINEMATIC_OBJECT);
841            break;
842        case Static:
843            this->physicalBody_->setCollisionFlags((this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_KINEMATIC_OBJECT) | btCollisionObject::CF_STATIC_OBJECT);
844            break;
845        case None:
846            assert(false); // Doesn't happen
847            return;
848        }
849        this->collisionType_ = type;
850        this->collisionTypeSynchronised_ = type;
851
852        // update mass and inertia tensor
853        recalculateMassProps();
854        internalSetPhysicsProps();
855        collisionCallbackActivityChanged();
856        collisionResponseActivityChanged();
857        if (bReactivatePhysics)
858            activatePhysics();
859    }
860
861    //! Sets the CollisionType by string (used for the XMLPort)
862    void WorldEntity::setCollisionTypeStr(const std::string& typeStr)
863    {
864        const std::string& typeStrLower = getLowercase(typeStr);
865        CollisionType type;
866        if (typeStrLower == "dynamic")
867            type = Dynamic;
868        else if (typeStrLower == "static")
869            type = Static;
870        else if (typeStrLower == "kinematic")
871            type = Kinematic;
872        else if (typeStrLower == "none")
873            type = None;
874        else
875            ThrowException(ParseError, std::string("Attempting to set an unknown collision type: '") + typeStr + "'.");
876        this->setCollisionType(type);
877    }
878
879    //! Gets the CollisionType by string (used for the XMLPort)
880    std::string WorldEntity::getCollisionTypeStr() const
881    {
882        switch (this->getCollisionType())
883        {
884            case Dynamic:
885                return "dynamic";
886            case Kinematic:
887                return "kinematic";
888            case Static:
889                return "static";
890            case None:
891                return "none";
892            default:
893                assert(false);
894                return "";
895        }
896    }
897
898    /**
899    @brief
900        Recalculates the accumulated child mass and calls recalculateMassProps()
901        and notifies the parent of the change.
902    @Note
903        Called by a child WE
904    */
905    void WorldEntity::notifyChildMassChanged()
906    {
907        // Note: CollisionShape changes of a child get handled over the internal CompoundCollisionShape already
908        // Recalculate mass
909        this->childrenMass_ = 0.0f;
910        for (std::set<WorldEntity*>::const_iterator it = this->children_.begin(); it != this->children_.end(); ++it)
911            this->childrenMass_ += (*it)->getMass();
912        recalculateMassProps();
913        // Notify parent WE
914        if (this->parent_)
915            parent_->notifyChildMassChanged();
916    }
917
918    /**
919    @brief
920        Undertakes the necessary steps to change the collision shape in Bullet, even at runtime.
921    @Note
922        - called by this->collisionShape_
923        - May have a REALLY big overhead when called continuously at runtime, because then we need
924          to remove the physical body from Bullet and add it again.
925    */
926    void WorldEntity::notifyCollisionShapeChanged()
927    {
928        if (hasPhysics())
929        {
930            // Bullet doesn't like sudden changes of the collision shape, so we remove and add it again
931            if (this->addedToPhysicalWorld())
932            {
933                this->deactivatePhysics();
934                this->physicalBody_->setCollisionShape(this->collisionShape_->getCollisionShape());
935                this->activatePhysics();
936            }
937            else
938                this->physicalBody_->setCollisionShape(this->collisionShape_->getCollisionShape());
939        }
940        recalculateMassProps();
941    }
942
943    //! Updates all mass dependent parameters (mass, inertia tensor and child mass)
944    void WorldEntity::recalculateMassProps()
945    {
946        // Store local inertia for faster access. Evaluates to (0,0,0) if there is no collision shape.
947        float totalMass = this->mass_ + this->childrenMass_;
948        this->collisionShape_->calculateLocalInertia(totalMass, this->localInertia_);
949        if (this->hasPhysics())
950        {
951            if (this->isStatic())
952            {
953                // Just set everything to zero
954                this->physicalBody_->setMassProps(0.0f, btVector3(0, 0, 0));
955            }
956            else if ((this->mass_ + this->childrenMass_) == 0.0f)
957            {
958                // Use default values to avoid very large or very small values
959                CCOUT(4) << "Warning: Setting the internal physical mass to 1.0 because mass_ is 0.0" << std::endl;
960                btVector3 inertia(0, 0, 0);
961                this->collisionShape_->calculateLocalInertia(1.0f, inertia);
962                this->physicalBody_->setMassProps(1.0f, inertia);
963            }
964            else
965            {
966                this->physicalBody_->setMassProps(totalMass, this->localInertia_);
967            }
968        }
969    }
970
971    //! Copies our own parameters for restitution, angular factor, damping and friction to the bullet rigid body.
972    void WorldEntity::internalSetPhysicsProps()
973    {
974        if (this->hasPhysics())
975        {
976            this->physicalBody_->setRestitution(this->restitution_);
977            this->physicalBody_->setAngularFactor(this->angularFactor_);
978            this->physicalBody_->setDamping(this->linearDamping_, this->angularDamping_);
979            this->physicalBody_->setFriction(this->friction_);
980        }
981    }
982}
Note: See TracBrowser for help on using the repository browser.