Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 2851 was 2851, checked in by landauf, 15 years ago

Fixed attachment of "absolute" CameraPosition-Nodes in the Network (this refers to the top-down camera in Pong)

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