Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Feb 14, 2009, 10:17:35 PM (16 years ago)
Author:
rgrieder
Message:

Merged presentation branch back to trunk.

Location:
code/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • code/trunk

  • code/trunk/src/orxonox/objects/worldentities/WorldEntity.cc

    r2171 r2662  
    2222 *   Author:
    2323 *      Fabian 'x3n' Landau
     24 *      Reto Grieder (physics)
    2425 *   Co-authors:
    2526 *      ...
     
    3132
    3233#include <cassert>
     34#include <OgreSceneNode.h>
    3335#include <OgreSceneManager.h>
    34 
     36#include "BulletDynamics/Dynamics/btRigidBody.h"
     37
     38#include "util/Exception.h"
     39#include "util/Convert.h"
    3540#include "core/CoreIncludes.h"
    3641#include "core/XMLPort.h"
    37 #include "util/Convert.h"
    38 #include "util/Exception.h"
    3942
    4043#include "objects/Scene.h"
     44#include "objects/collisionshapes/WorldEntityCollisionShape.h"
    4145
    4246namespace orxonox
     
    4953    const Vector3 WorldEntity::UP    = Vector3::UNIT_Y;
    5054
     55    /**
     56    @brief
     57        Creates a new WorldEntity that may immediately be used.
     58        All the default values are being set here.
     59    */
    5160    WorldEntity::WorldEntity(BaseObject* creator) : BaseObject(creator), Synchronisable(creator)
    5261    {
     
    6473        this->node_->setOrientation(Quaternion::IDENTITY);
    6574
     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
    6695        this->registerVariables();
    6796    }
    6897
     98    /**
     99    @brief
     100        Destroys the WorldEntity AND ALL its children with it.
     101    */
    69102    WorldEntity::~WorldEntity()
    70103    {
    71104        if (this->isInitialized())
    72105        {
     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
    73119            this->node_->detachAllObjects();
    74             if (this->getScene()->getSceneManager())
    75                 this->getScene()->getSceneManager()->destroySceneNode(this->node_->getName());
     120            this->node_->removeAllChildren();
     121
     122            OrxAssert(this->getScene()->getSceneManager(), "No SceneManager defined in a WorldEntity.");
     123            this->getScene()->getSceneManager()->destroySceneNode(this->node_->getName());
    76124        }
    77125    }
     
    81129        SUPER(WorldEntity, XMLPort, xmlelement, mode);
    82130
    83         XMLPortParamTemplate(WorldEntity, "position", setPosition, getPosition, xmlelement, mode, const Vector3&);
     131        XMLPortParamTemplate(WorldEntity, "position",    setPosition,    getPosition,    xmlelement, mode, const Vector3&);
    84132        XMLPortParamTemplate(WorldEntity, "orientation", setOrientation, getOrientation, xmlelement, mode, const Quaternion&);
    85         XMLPortParamLoadOnly(WorldEntity, "lookat", lookAt_xmlport, xmlelement, mode);
    86         XMLPortParamLoadOnly(WorldEntity, "direction", setDirection_xmlport, xmlelement, mode);
    87         XMLPortParamLoadOnly(WorldEntity, "yaw", yaw_xmlport, xmlelement, mode);
    88         XMLPortParamLoadOnly(WorldEntity, "pitch", pitch_xmlport, xmlelement, mode);
    89         XMLPortParamLoadOnly(WorldEntity, "roll", roll_xmlport, xmlelement, mode);
    90         XMLPortParamTemplate(WorldEntity, "scale3D", setScale3D, getScale3D, xmlelement, mode, const Vector3&);
    91         XMLPortParam(WorldEntity, "scale", setScale, getScale, xmlelement, mode);
    92 
     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
    93152        XMLPortObject(WorldEntity, WorldEntity, "attached", attach, getAttachedObject, xmlelement, mode);
     153        // Attached collision shapes
     154        XMLPortObject(WorldEntity, CollisionShape, "collisionShapes", attachCollisionShape, getAttachedCollisionShape, xmlelement, mode);
    94155    }
    95156
    96157    void WorldEntity::registerVariables()
    97158    {
    98         REGISTERDATA(this->bActive_,  direction::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::changedActivity));
    99         REGISTERDATA(this->bVisible_, direction::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::changedVisibility));
    100 
    101         REGISTERDATA(this->getScale3D().x, direction::toclient);
    102         REGISTERDATA(this->getScale3D().y, direction::toclient);
    103         REGISTERDATA(this->getScale3D().z, direction::toclient);
    104 
    105         REGISTERDATA(this->parentID_, direction::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::updateParent));
    106     }
    107 
    108     void WorldEntity::updateParent()
     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::parentChanged));
     184    }
     185
     186    /**
     187    @brief
     188        Network function that object this instance to its correct parent.
     189    */
     190    void WorldEntity::parentChanged()
    109191    {
    110192        if (this->parentID_ != OBJECTID_UNKNOWN)
     
    116198    }
    117199
     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    */
    118297    void WorldEntity::attach(WorldEntity* object)
    119298    {
    120         if (object->getParent())
    121             object->detachFromParent();
    122         else
    123         {
    124             Ogre::Node* parent = object->node_->getParent();
    125             if (parent)
    126                 parent->removeChild(object->node_);
    127         }
    128 
    129         this->node_->addChild(object->node_);
     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_);
    130309        this->children_.insert(object);
    131         object->parent_ = this;
    132         object->parentID_ = this->getObjectID();
    133     }
    134 
     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        // apply transform to collision shape
     365        this->collisionShape_->setPosition(this->getPosition());
     366        this->collisionShape_->setOrientation(this->getOrientation());
     367        // TODO: Scale
     368       
     369        return true;
     370    }
     371
     372    /**
     373    @brief
     374        Detaches a child WorldEntity from this instance.
     375    */
    135376    void WorldEntity::detach(WorldEntity* object)
    136377    {
    137         this->node_->removeChild(object->node_);
     378        if (this->children_.find(object) == this->children_.end())
     379        {
     380            CCOUT(2) << "Warning: Cannot detach an object that is not a child." << std::endl;
     381            return;
     382        }
     383
     384        // collision shapes
     385        this->detachCollisionShape(object->collisionShape_);
     386
     387        // mass
     388        if (object->getMass() > 0.0f)
     389        {
     390            this->childrenMass_ -= object->getMass();
     391            recalculateMassProps();
     392        }
     393
     394        this->detachNode(object->node_);
    138395        this->children_.erase(object);
    139         object->parent_ = 0;
    140         object->parentID_ = OBJECTID_UNKNOWN;
    141 
    142 //        this->getScene()->getRootSceneNode()->addChild(object->node_);
    143     }
    144 
    145     WorldEntity* WorldEntity::getAttachedObject(unsigned int index) const
     396
     397        object->notifyDetached();
     398    }
     399
     400    /**
     401    @brief
     402        Function gets called when the object has been detached from its parent.
     403    */
     404    void WorldEntity::notifyDetached()
     405    {
     406        this->parent_ = 0;
     407        this->parentID_ = OBJECTID_UNKNOWN;
     408
     409        // reset orientation of the collisionShape (cannot be set within a WE usually)
     410        this->collisionShape_->setPosition(Vector3::ZERO);
     411        this->collisionShape_->setOrientation(Quaternion::IDENTITY);
     412        // TODO: Scale
     413
     414        if (this->bPhysicsActiveBeforeAttaching_)
     415        {
     416            this->activatePhysics();
     417            this->bPhysicsActiveBeforeAttaching_ = false;
     418        }
     419    }
     420
     421    //! Returns an attached object (merely for XMLPort).
     422    WorldEntity* WorldEntity::getAttachedObject(unsigned int index)
    146423    {
    147424        unsigned int i = 0;
     
    154431        return 0;
    155432    }
     433
     434    //! Attaches an Ogre::SceneNode to this WorldEntity.
     435    void WorldEntity::attachNode(Ogre::SceneNode* node)
     436    {
     437        Ogre::Node* parent = node->getParent();
     438        if (parent)
     439            parent->removeChild(node);
     440        this->node_->addChild(node);
     441    }
     442
     443    //! Detaches an Ogre::SceneNode from this WorldEntity.
     444    void WorldEntity::detachNode(Ogre::SceneNode* node)
     445    {
     446        this->node_->removeChild(node);
     447//        this->getScene()->getRootSceneNode()->addChild(node);
     448    }
     449
     450    //! Attaches an Ogre::MovableObject to this WorldEntity.
     451    void WorldEntity::attachOgreObject(Ogre::MovableObject* object)
     452    {
     453        this->node_->attachObject(object);
     454    }
     455
     456    //! Detaches an Ogre::MovableObject from this WorldEntity.
     457    void WorldEntity::detachOgreObject(Ogre::MovableObject* object)
     458    {
     459        this->node_->detachObject(object);
     460    }
     461
     462    //! Detaches an Ogre::MovableObject (by string) from this WorldEntity.
     463    Ogre::MovableObject* WorldEntity::detachOgreObject(const Ogre::String& name)
     464    {
     465        return this->node_->detachObject(name);
     466    }
     467
     468    //! Attaches a collision Shape to this object (delegated to the internal CompoundCollisionShape)
     469    void WorldEntity::attachCollisionShape(CollisionShape* shape)
     470    {
     471        this->collisionShape_->attach(shape);
     472        // Note: this->collisionShape_ already notifies us of any changes.
     473    }
     474
     475    //! Detaches a collision Shape from this object (delegated to the internal CompoundCollisionShape)
     476    void WorldEntity::detachCollisionShape(CollisionShape* shape)
     477    {
     478        // Note: The collision shapes may not be detached with this function!
     479        this->collisionShape_->detach(shape);
     480        // Note: this->collisionShape_ already notifies us of any changes.
     481    }
     482
     483    //! Returns an attached collision Shape of this object (delegated to the internal CompoundCollisionShape)
     484    CollisionShape* WorldEntity::getAttachedCollisionShape(unsigned int index)
     485    {
     486        return this->collisionShape_->getAttachedShape(index);
     487    }
     488
     489    // Note: These functions are placed in WorldEntity.h as inline functions for the release build.
     490#ifndef _NDEBUG
     491    const Vector3& WorldEntity::getPosition() const
     492    {
     493        return this->node_->getPosition();
     494    }
     495
     496    const Quaternion& WorldEntity::getOrientation() const
     497    {
     498        return this->node_->getOrientation();
     499    }
     500
     501    const Vector3& WorldEntity::getScale3D() const
     502    {
     503        return this->node_->getScale();
     504    }
     505#endif
     506
     507    //! Returns the position relative to the root space
     508    const Vector3& WorldEntity::getWorldPosition() const
     509    {
     510        return this->node_->_getDerivedPosition();
     511    }
     512
     513    //! Returns the orientation relative to the root space
     514    const Quaternion& WorldEntity::getWorldOrientation() const
     515    {
     516        return this->node_->_getDerivedOrientation();
     517    }
     518
     519    //! Returns the scaling applied relative to the root space in 3 coordinates
     520    const Vector3& WorldEntity::getWorldScale3D() const
     521    {
     522        return this->node_->_getDerivedScale();
     523    }
     524
     525    /**
     526    @brief
     527        Returns the scaling applied relative to the root space in 3 coordinates
     528    @return
     529        Returns the scaling if it is uniform, 1.0f otherwise.
     530    */
     531    float WorldEntity::getWorldScale() const
     532    {
     533        Vector3 scale = this->getWorldScale3D();
     534        return (scale.x == scale.y && scale.x == scale.z) ? scale.x : 1;
     535    }
     536
     537    /**
     538    @brief
     539        Sets the three dimensional scaling of this object.
     540    @Note
     541        Scaling physical objects has not yet been implemented and is therefore forbidden.
     542    */
     543    void WorldEntity::setScale3D(const Vector3& scale)
     544    {
     545/*
     546HACK HACK HACK
     547        if (bScalePhysics && this->hasPhysics() && scale != Vector3::UNIT_SCALE)
     548        {
     549            CCOUT(2) << "Warning: Cannot set the scale of a physical object: Not yet implemented. Ignoring scaling." << std::endl;
     550            return;
     551        }
     552HACK HACK HACK
     553*/
     554        this->node_->setScale(scale);
     555
     556        this->changedScale();
     557    }
     558
     559    /**
     560    @brief
     561        Translates this WorldEntity by a vector.
     562    @param relativeTo
     563        @see TransformSpace::Enum
     564    */
     565    void WorldEntity::translate(const Vector3& distance, TransformSpace::Enum relativeTo)
     566    {
     567        switch (relativeTo)
     568        {
     569        case TransformSpace::Local:
     570            // position is relative to parent so transform downwards
     571            this->setPosition(this->getPosition() + this->getOrientation() * distance);
     572            break;
     573        case TransformSpace::Parent:
     574            this->setPosition(this->getPosition() + distance);
     575            break;
     576        case TransformSpace::World:
     577            // position is relative to parent so transform upwards
     578            if (this->node_->getParent())
     579                setPosition(getPosition() + (node_->getParent()->_getDerivedOrientation().Inverse() * distance)
     580                    / node_->getParent()->_getDerivedScale());
     581            else
     582                this->setPosition(this->getPosition() + distance);
     583            break;
     584        }
     585    }
     586
     587    /**
     588    @brief
     589        Rotates this WorldEntity by a quaternion.
     590    @param relativeTo
     591        @see TransformSpace::Enum
     592    */
     593    void WorldEntity::rotate(const Quaternion& rotation, TransformSpace::Enum relativeTo)
     594    {
     595        switch(relativeTo)
     596        {
     597        case TransformSpace::Local:
     598            this->setOrientation(this->getOrientation() * rotation);
     599            break;
     600        case TransformSpace::Parent:
     601            // Rotations are normally relative to local axes, transform up
     602            this->setOrientation(rotation * this->getOrientation());
     603            break;
     604        case TransformSpace::World:
     605            // Rotations are normally relative to local axes, transform up
     606            this->setOrientation(this->getOrientation() * this->getWorldOrientation().Inverse()
     607                * rotation * this->getWorldOrientation());
     608            break;
     609        }
     610    }
     611
     612    /**
     613    @brief
     614        Makes this WorldEntity look a specific target location.
     615    @param relativeTo
     616        @see TransformSpace::Enum
     617    @param localDirectionVector
     618        The vector which normally describes the natural direction of the object, usually -Z.
     619    */
     620    void WorldEntity::lookAt(const Vector3& target, TransformSpace::Enum relativeTo, const Vector3& localDirectionVector)
     621    {
     622        Vector3 origin;
     623        switch (relativeTo)
     624        {
     625        case TransformSpace::Local:
     626            origin = Vector3::ZERO;
     627            break;
     628        case TransformSpace::Parent:
     629            origin = this->getPosition();
     630            break;
     631        case TransformSpace::World:
     632            origin = this->getWorldPosition();
     633            break;
     634        }
     635        this->setDirection(target - origin, relativeTo, localDirectionVector);
     636    }
     637
     638    /**
     639    @brief
     640        Makes this WorldEntity look in specific direction.
     641    @param relativeTo
     642        @see TransformSpace::Enum
     643    @param localDirectionVector
     644        The vector which normally describes the natural direction of the object, usually -Z.
     645    */
     646    void WorldEntity::setDirection(const Vector3& direction, TransformSpace::Enum relativeTo, const Vector3& localDirectionVector)
     647    {
     648        Quaternion savedOrientation(this->getOrientation());
     649        Ogre::Node::TransformSpace ogreRelativeTo;
     650        switch (relativeTo)
     651        {
     652        case TransformSpace::Local:
     653            ogreRelativeTo = Ogre::Node::TS_LOCAL; break;
     654        case TransformSpace::Parent:
     655            ogreRelativeTo = Ogre::Node::TS_PARENT; break;
     656        case TransformSpace::World:
     657            ogreRelativeTo = Ogre::Node::TS_WORLD; break;
     658        }
     659        this->node_->setDirection(direction, ogreRelativeTo, localDirectionVector);
     660        Quaternion newOrientation(this->node_->getOrientation());
     661        this->node_->setOrientation(savedOrientation);
     662        this->setOrientation(newOrientation);
     663    }
     664
     665    //! Activates physics if the CollisionType is not None.
     666    void WorldEntity::activatePhysics()
     667    {
     668        if (this->isActive() && this->hasPhysics() && !this->isPhysicsActive() && !this->parent_)
     669        {
     670            this->getScene()->addPhysicalObject(this);
     671            this->bPhysicsActive_ = true;
     672            this->bPhysicsActiveSynchronised_ = true;
     673        }
     674    }
     675
     676    //! Deactivates physics but the CollisionType does not change.
     677    void WorldEntity::deactivatePhysics()
     678    {
     679        if (this->isPhysicsActive())
     680        {
     681            this->getScene()->removePhysicalObject(this);
     682            this->bPhysicsActive_ = false;
     683            this->bPhysicsActiveSynchronised_ = false;
     684        }
     685    }
     686
     687    //! Tells whether the object has already been added to the Bullet physics World.
     688    bool WorldEntity::addedToPhysicalWorld() const
     689    {
     690        return this->physicalBody_ && this->physicalBody_->isInWorld();
     691    }
     692
     693    /**
     694    @brief
     695        Sets the CollisionType. This alters the object significantly! @see CollisionType.
     696    @Note
     697        Operation does not work on attached WorldEntities.
     698    */
     699    void WorldEntity::setCollisionType(CollisionType type)
     700    {
     701        if (this->collisionType_ == type)
     702            return;
     703
     704        // If we are already attached to a parent, this would be a bad idea..
     705        if (this->parent_)
     706        {
     707            CCOUT(2) << "Warning: Cannot set the collision type of a WorldEntity with a parent." << std::endl;
     708            return;
     709        }
     710
     711        // Check for type legality. Could be StaticEntity or MobileEntity.
     712        if (!this->isCollisionTypeLegal(type))
     713            return;
     714
     715        if (this->isPhysicsActive())
     716            this->deactivatePhysics();
     717
     718        bool bReactivatePhysics = true;
     719        if (this->hasPhysics() && !this->isPhysicsActive())
     720            bReactivatePhysics = false;
     721
     722        // Check whether we have to create or destroy.
     723        if (type != None && this->collisionType_ == None)
     724        {
     725/*
     726HACK HACK HACK
     727            // Check whether there was some scaling applied.
     728            if (!this->node_->getScale().positionEquals(Vector3(1, 1, 1), 0.001))
     729            {
     730                CCOUT(2) << "Warning: Cannot create a physical body if there is scaling applied to the node: Not yet implemented." << std::endl;
     731                return;
     732            }
     733HACK HACK HACK
     734*/
     735            // Create new rigid body
     736            btRigidBody::btRigidBodyConstructionInfo bodyConstructionInfo(0, this, this->collisionShape_->getCollisionShape());
     737            this->physicalBody_ = new btRigidBody(bodyConstructionInfo);
     738            this->physicalBody_->setUserPointer(this);
     739            this->physicalBody_->setActivationState(DISABLE_DEACTIVATION);
     740        }
     741        else if (type == None && this->collisionType_ != None)
     742        {
     743            // Destroy rigid body
     744            assert(this->physicalBody_);
     745            deactivatePhysics();
     746            delete this->physicalBody_;
     747            this->physicalBody_ = 0;
     748            this->collisionType_ = None;
     749            this->collisionTypeSynchronised_ = None;
     750            return;
     751        }
     752
     753        // Change type
     754        switch (type)
     755        {
     756        case Dynamic:
     757            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !(btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT));
     758            break;
     759        case Kinematic:
     760            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT);
     761            break;
     762        case Static:
     763            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT);
     764            break;
     765        case None:
     766            assert(false); // Doesn't happen
     767            return;
     768        }
     769        this->collisionType_ = type;
     770        this->collisionTypeSynchronised_ = type;
     771
     772        // update mass and inertia tensor
     773        recalculateMassProps();
     774        internalSetPhysicsProps();
     775        collisionCallbackActivityChanged();
     776        collisionResponseActivityChanged();
     777        if (bReactivatePhysics)
     778            activatePhysics();
     779    }
     780
     781    //! Sets the CollisionType by string (used for the XMLPort)
     782    void WorldEntity::setCollisionTypeStr(const std::string& typeStr)
     783    {
     784        std::string typeStrLower = getLowercase(typeStr);
     785        CollisionType type;
     786        if (typeStrLower == "dynamic")
     787            type = Dynamic;
     788        else if (typeStrLower == "static")
     789            type = Static;
     790        else if (typeStrLower == "kinematic")
     791            type = Kinematic;
     792        else if (typeStrLower == "none")
     793            type = None;
     794        else
     795            ThrowException(ParseError, std::string("Attempting to set an unknown collision type: '") + typeStr + "'.");
     796        this->setCollisionType(type);
     797    }
     798
     799    //! Gets the CollisionType by string (used for the XMLPort)
     800    std::string WorldEntity::getCollisionTypeStr() const
     801    {
     802        switch (this->getCollisionType())
     803        {
     804            case Dynamic:
     805                return "dynamic";
     806            case Kinematic:
     807                return "kinematic";
     808            case Static:
     809                return "static";
     810            case None:
     811                return "none";
     812            default:
     813                assert(false);
     814                return "";
     815        }
     816    }
     817
     818    /**
     819    @brief
     820        Recalculates the accumulated child mass and calls recalculateMassProps()
     821        and notifies the parent of the change.
     822    @Note
     823        Called by a child WE
     824    */
     825    void WorldEntity::notifyChildMassChanged()
     826    {
     827        // Note: CollisionShape changes of a child get handled over the internal CompoundCollisionShape already
     828        // Recalculate mass
     829        this->childrenMass_ = 0.0f;
     830        for (std::set<WorldEntity*>::const_iterator it = this->children_.begin(); it != this->children_.end(); ++it)
     831            this->childrenMass_ += (*it)->getMass();
     832        recalculateMassProps();
     833        // Notify parent WE
     834        if (this->parent_)
     835            parent_->notifyChildMassChanged();
     836    }
     837
     838    /**
     839    @brief
     840        Undertakes the necessary steps to change the collision shape in Bullet, even at runtime.
     841    @Note
     842        - called by this->collisionShape_
     843        - May have a REALLY big overhead when called continuously at runtime, because then we need
     844          to remove the physical body from Bullet and add it again.
     845    */
     846    void WorldEntity::notifyCollisionShapeChanged()
     847    {
     848        if (hasPhysics())
     849        {
     850            // Bullet doesn't like sudden changes of the collision shape, so we remove and add it again
     851            if (this->addedToPhysicalWorld())
     852            {
     853                this->deactivatePhysics();
     854                this->physicalBody_->setCollisionShape(this->collisionShape_->getCollisionShape());
     855                this->activatePhysics();
     856            }
     857            else
     858                this->physicalBody_->setCollisionShape(this->collisionShape_->getCollisionShape());
     859        }
     860        recalculateMassProps();
     861    }
     862
     863    //! Updates all mass dependent parameters (mass, inertia tensor and child mass)
     864    void WorldEntity::recalculateMassProps()
     865    {
     866        // Store local inertia for faster access. Evaluates to (0,0,0) if there is no collision shape.
     867        float totalMass = this->mass_ + this->childrenMass_;
     868        this->collisionShape_->calculateLocalInertia(totalMass, this->localInertia_);
     869        if (this->hasPhysics())
     870        {
     871            if (this->isStatic())
     872            {
     873                // Just set everything to zero
     874                this->physicalBody_->setMassProps(0.0f, btVector3(0, 0, 0));
     875            }
     876            else if ((this->mass_ + this->childrenMass_) == 0.0f)
     877            {
     878                // Use default values to avoid very large or very small values
     879                CCOUT(4) << "Warning: Setting the internal physical mass to 1.0 because mass_ is 0.0" << std::endl;
     880                btVector3 inertia(0, 0, 0);
     881                this->collisionShape_->calculateLocalInertia(1.0f, inertia);
     882                this->physicalBody_->setMassProps(1.0f, inertia);
     883            }
     884            else
     885            {
     886                this->physicalBody_->setMassProps(totalMass, this->localInertia_);
     887            }
     888        }
     889    }
     890
     891    //! Copies our own parameters for restitution, angular factor, dampings and friction to the bullet rigid body.
     892    void WorldEntity::internalSetPhysicsProps()
     893    {
     894        if (this->hasPhysics())
     895        {
     896            this->physicalBody_->setRestitution(this->restitution_);
     897            this->physicalBody_->setAngularFactor(this->angularFactor_);
     898            this->physicalBody_->setDamping(this->linearDamping_, this->angularDamping_);
     899            this->physicalBody_->setFriction(this->friction_);
     900        }
     901    }
    156902}
Note: See TracChangeset for help on using the changeset viewer.