Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/lastmanstanding2/src/orxonox/worldentities/WorldEntity.cc @ 8526

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

Fixing small bug in Script (regarding number of executions).
Fixed bug in WorldEntity, that caused the visibility and activity to be synchronized incorrectly (since bVisibleMem and bActiveMem are not synchronized).
Some small changed in documentation.
Started "synchronizing" pickups. Seems to work (except GUI), but haven't done any extensive testing yet.

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