Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/collisionshapes/CollisionShape.cc @ 10624

Last change on this file since 10624 was 10624, checked in by landauf, 9 years ago

merged branch core7 back to trunk

  • Property svn:eol-style set to native
File size: 10.1 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 *      Reto Grieder
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30    @file CollisionShape.cc
31    @brief Implementation of the CollisionShape class.
32*/
33
34#include "CollisionShape.h"
35
36#include <BulletCollision/CollisionShapes/btCollisionShape.h>
37
38#include "core/CoreIncludes.h"
39#include "core/XMLPort.h"
40#include "worldentities/WorldEntity.h"
41#include "CompoundCollisionShape.h"
42#include "WorldEntityCollisionShape.h"
43#include "Scene.h"
44
45namespace orxonox
46{
47    RegisterAbstractClass(CollisionShape).inheritsFrom<BaseObject>().inheritsFrom<Synchronisable>();
48
49    /**
50    @brief
51        Constructor. Registers and initializes the object.
52    */
53    CollisionShape::CollisionShape(Context* context)
54        : BaseObject(context)
55        , Synchronisable(context)
56    {
57        RegisterObject(CollisionShape);
58
59        this->parent_ = 0;
60        this->parentID_ = OBJECTID_UNKNOWN;
61        this->collisionShape_ = 0;
62        this->position_ = Vector3::ZERO;
63        this->orientation_ = Quaternion::IDENTITY;
64        this->scale_ = Vector3::UNIT_SCALE;
65        this->uniformScale_ = true;
66
67        this->registerVariables();
68    }
69
70    /**
71    @brief
72        Destructor. Detaches the CollisionShape from its parent.
73    */
74    CollisionShape::~CollisionShape()
75    {
76        // Detach from parent CompoundCollisionShape.
77        if (this->isInitialized())
78        {
79            if (this->getScene() && this->getScene()->isUpdatingPhysics())
80                orxout(internal_error) << "Don't destroy collision shapes while the physics is updated! This will lead to crashes. Try to use destroyLater() instead" << endl;
81
82            if (this->parent_)
83                this->parent_->detach(this);
84
85            if (this->collisionShape_)
86                delete this->collisionShape_;
87        }
88    }
89
90    void CollisionShape::XMLPort(Element& xmlelement, XMLPort::Mode mode)
91    {
92        SUPER(CollisionShape, XMLPort, xmlelement, mode);
93
94        XMLPortParamTemplate(CollisionShape, "position", setPosition, getPosition, xmlelement, mode, const Vector3&);
95        XMLPortParamTemplate(CollisionShape, "orientation", setOrientation, getOrientation, xmlelement, mode, const Quaternion&);
96        XMLPortParamTemplate(CollisionShape, "scale3D", setScale3D, getScale3D, xmlelement, mode, const Vector3&);
97        XMLPortParamLoadOnly(CollisionShape, "scale", setScale, xmlelement, mode);
98        XMLPortParamLoadOnly(CollisionShape, "yaw",   yaw,   xmlelement, mode);
99        XMLPortParamLoadOnly(CollisionShape, "pitch", pitch, xmlelement, mode);
100        XMLPortParamLoadOnly(CollisionShape, "roll",  roll,  xmlelement, mode);
101    }
102
103    /**
104    @brief
105        Register variables that need synchronizing over the network.
106    */
107    void CollisionShape::registerVariables()
108    {
109        // Keep the shape's parent (can be either a CompoundCollisionShape or a WorldEntity) consistent over the network.
110        registerVariable(this->parentID_, VariableDirection::ToClient, new NetworkCallback<CollisionShape>(this, &CollisionShape::parentChanged));
111    }
112
113    /**
114    @brief
115        Notifies the CollisionShape of being attached to a CompoundCollisionShape.
116    @param newParent
117        A pointer to the CompoundCollisionShape the CollisionShape was attached to.
118    @return
119        Returns
120    */
121    bool CollisionShape::notifyBeingAttached(CompoundCollisionShape* newParent)
122    {
123        // If the CollisionShape is attached to a CompoundCollisionShapes, detach it.
124        if (this->parent_)
125            this->parent_->detach(this);
126
127        this->parent_ = newParent;
128
129        // If the new parent is a WorldEntityCollisionShape, the parentID is set to the objectID of the WorldEntity that is its owner.
130        // TODO: Why?
131        WorldEntityCollisionShape* parentWECCS = orxonox_cast<WorldEntityCollisionShape*>(newParent);
132        if (parentWECCS)
133        {
134            this->parentID_ = parentWECCS->getWorldEntityOwner()->getObjectID();
135
136            // If this shape is not a CompoundCollisionShape (thus an actual physical shape) & the parent is a WorldEntity's CollisionShape,
137            // set it's userPointer to the WorldEntity this CompoundCollisionShape belongs to.
138            if (!orxonox_cast<CompoundCollisionShape*>(this))
139                this->getCollisionShape()->setUserPointer(parentWECCS->getWorldEntityOwner());
140        }
141        else
142        {
143            // Else it is set to the objectID of the CompoundCollisionShape.
144            this->parentID_ = newParent->getObjectID();
145        }
146
147        return true;
148    }
149
150    /**
151    @brief
152        Notifies the CollisionShape of being detached from a CompoundCollisionShape.
153    */
154    void CollisionShape::notifyDetached()
155    {
156        this->parent_ = 0;
157        this->parentID_ = OBJECTID_UNKNOWN;
158    }
159
160    /**
161    @brief
162        Updates the CompoundCollisionShape the CollisionShape belongs to (if it belongs to one), after the CollisionShape has changed.
163    */
164    void CollisionShape::updateParent()
165    {
166        if (this->parent_)
167            this->parent_->updateAttachedShape(this);
168    }
169
170    /**
171    @brief
172        Is called when the parentID of the CollisionShape has changed.
173        Attaches it to the object with the changed parentID, which can either be a CompoundCollisionShape or a WorldEntity.
174    */
175    void CollisionShape::parentChanged()
176    {
177        // Get the parent object from the network.
178        Synchronisable* parent = Synchronisable::getSynchronisable(this->parentID_);
179
180        // Parent can either be a WorldEntity or a CompoundCollisionShape. The reason is that the
181        // internal collision shape (which is compound) of a WE doesn't get synchronised.
182        CompoundCollisionShape* parentCCS = orxonox_cast<CompoundCollisionShape*>(parent);
183
184        // If the parent is a CompoundCollisionShape, attach the CollisionShape to it.
185        if (parentCCS)
186            parentCCS->attach(this);
187        else
188        {
189            // If the parent is a WorldEntity, attach the CollisionShape to its collision shapes.
190            WorldEntity* parentWE = orxonox_cast<WorldEntity*>(parent);
191            if (parentWE)
192                parentWE->attachCollisionShape(this);
193        }
194    }
195
196    /**
197    @brief
198        Check whether the CollisionShape has been either moved or rotated or both. (i.e. it doesn't have position zero and identity orientation any more)
199    @return
200        Returns true if it has been moved.
201    */
202    bool CollisionShape::hasTransform() const
203    {
204        return (!this->position_.positionEquals(Vector3(0, 0, 0), 0.001f) ||
205                !this->orientation_.equals(Quaternion(1,0,0,0), Degree(0.1f)));
206    }
207
208    /**
209    @brief
210        Set the scale of the CollisionShape.
211        Since the scale is a vector the CollisionShape can be scaled independently in each direction, allowing for linear distortions.
212        If the scale changes, this causes the parent CompoundCollisionShape (if there is one) to be updated.
213        Beware, non-uniform scaling (i.e. distortions) might not be supported by all CollisionShapes.
214    @param scale
215        The new scale to be set. Vector3::UNIT_SCALE is the initial scale.
216    */
217    void CollisionShape::setScale3D(const Vector3& scale)
218    {
219        if(this->scale_ == scale)
220            return;
221
222        // If the vectors are not in the same direction, then this is no longer a uniform scaling.
223        if(scale_.crossProduct(scale).squaredLength() != 0.0f)
224        {
225            orxout(internal_warning) << "Non-uniform scaling is not yet supported." << endl;
226            return;
227        }
228
229        this->scale_ = scale;
230
231        this->changedScale();
232        this->updateParent();
233    }
234
235    /**
236    @brief
237        Set the (uniform) scale of the CollisionShape.
238        If the scale changes, this causes the parent CompoundCollisionShape (if there is one) to be updated.
239    @param scale
240        The scale to scale the CollisionShape with. 1.0f is the initial scale.
241    */
242    void CollisionShape::setScale(float scale)
243    {
244        if(this->scale_.length() == scale)
245            return;
246
247        this->scale_ = Vector3::UNIT_SCALE*scale;
248
249        this->changedScale();
250        this->updateParent();
251    }
252
253    /**
254    @brief
255        Is called when the scale of the CollisionShape has changed.
256    */
257    void CollisionShape::changedScale()
258    {
259        // Adjust the position of the CollisionShape.
260        this->position_ *= this->getScale3D();
261    }
262
263    /**
264    @brief
265        Updates the shape.
266        Is called when the internal parameters of the shape have changed such that a new shape needs to be created.
267    */
268    void CollisionShape::updateShape()
269    {
270        btCollisionShape* oldShape = this->collisionShape_;
271        this->collisionShape_ = this->createNewShape();
272        // If the CollisionShape has been rescaled, scale the shape to fit the current scale.
273        if(this->scale_ != Vector3::UNIT_SCALE)
274            this->changedScale();
275        // When we recreate the shape, we have to inform the parent about this to update the shape
276        this->updateParent();
277        if (oldShape)
278            delete oldShape;
279    }
280
281    /**
282    @brief
283        Calculates the local inertia of the collision shape.
284    @todo
285        Document.
286    */
287    void CollisionShape::calculateLocalInertia(float mass, btVector3& inertia) const
288    {
289        if (this->collisionShape_)
290            this->collisionShape_->calculateLocalInertia(mass, inertia);
291        else
292            inertia.setValue(0, 0, 0);
293    }
294}
Note: See TracBrowser for help on using the repository browser.