Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core7/src/orxonox/collisionshapes/CollisionShape.cc @ 10415

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

added check to detect if a collision shape is destroyed during a simulation step of bullet. this usually happens if a collision (or a 'hit') triggers an event which deletes an object. this yields undefined behavior and often leads to crashes.

  • Property svn:eol-style set to native
File size: 10.0 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      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" << endl;
81
82            if (this->parent_)
83                this->parent_->detach(this);
84        }
85    }
86
87    void CollisionShape::XMLPort(Element& xmlelement, XMLPort::Mode mode)
88    {
89        SUPER(CollisionShape, XMLPort, xmlelement, mode);
90
91        XMLPortParamTemplate(CollisionShape, "position", setPosition, getPosition, xmlelement, mode, const Vector3&);
92        XMLPortParamTemplate(CollisionShape, "orientation", setOrientation, getOrientation, xmlelement, mode, const Quaternion&);
93        XMLPortParamTemplate(CollisionShape, "scale3D", setScale3D, getScale3D, xmlelement, mode, const Vector3&);
94        XMLPortParamLoadOnly(CollisionShape, "scale", setScale, xmlelement, mode);
95        XMLPortParamLoadOnly(CollisionShape, "yaw",   yaw,   xmlelement, mode);
96        XMLPortParamLoadOnly(CollisionShape, "pitch", pitch, xmlelement, mode);
97        XMLPortParamLoadOnly(CollisionShape, "roll",  roll,  xmlelement, mode);
98    }
99
100    /**
101    @brief
102        Register variables that need synchronizing over the network.
103    */
104    void CollisionShape::registerVariables()
105    {
106        // Keep the shape's parent (can be either a CompoundCollisionShape or a WorldEntity) consistent over the network.
107        registerVariable(this->parentID_, VariableDirection::ToClient, new NetworkCallback<CollisionShape>(this, &CollisionShape::parentChanged));
108    }
109
110    /**
111    @brief
112        Notifies the CollisionShape of being attached to a CompoundCollisionShape.
113    @param newParent
114        A pointer to the CompoundCollisionShape the CollisionShape was attached to.
115    @return
116        Returns
117    */
118    bool CollisionShape::notifyBeingAttached(CompoundCollisionShape* newParent)
119    {
120        // If the CollisionShape is attached to a CompoundCollisionShapes, detach it.
121        if (this->parent_)
122            this->parent_->detach(this);
123
124        this->parent_ = newParent;
125
126        // If the new parent is a WorldEntityCollisionShape, the parentID is set to the objectID of the WorldEntity that is its owner.
127        // TODO: Why?
128        WorldEntityCollisionShape* parentWECCS = orxonox_cast<WorldEntityCollisionShape*>(newParent);
129        if (parentWECCS)
130        {
131            this->parentID_ = parentWECCS->getWorldEntityOwner()->getObjectID();
132
133            // If this shape is not a CompoundCollisionShape (thus an actual physical shape) & the parent is a WorldEntity's CollisionShape,
134            // set it's userPointer to the WorldEntity this CompoundCollisionShape belongs to.
135            if (!orxonox_cast<CompoundCollisionShape*>(this))
136                this->getCollisionShape()->setUserPointer(parentWECCS->getWorldEntityOwner());
137        }
138        else
139        {
140            // Else it is set to the objectID of the CompoundCollisionShape.
141            this->parentID_ = newParent->getObjectID();
142        }
143
144        return true;
145    }
146
147    /**
148    @brief
149        Notifies the CollisionShape of being detached from a CompoundCollisionShape.
150    */
151    void CollisionShape::notifyDetached()
152    {
153        this->parent_ = 0;
154        this->parentID_ = OBJECTID_UNKNOWN;
155    }
156
157    /**
158    @brief
159        Updates the CompoundCollisionShape the CollisionShape belongs to (if it belongs to one), after the CollisionShape has changed.
160    */
161    void CollisionShape::updateParent()
162    {
163        if (this->parent_)
164            this->parent_->updateAttachedShape(this);
165    }
166
167    /**
168    @brief
169        Is called when the parentID of the CollisionShape has changed.
170        Attaches it to the object with the changed parentID, which can either be a CompoundCollisionShape or a WorldEntity.
171    */
172    void CollisionShape::parentChanged()
173    {
174        // Get the parent object from the network.
175        Synchronisable* parent = Synchronisable::getSynchronisable(this->parentID_);
176
177        // Parent can either be a WorldEntity or a CompoundCollisionShape. The reason is that the
178        // internal collision shape (which is compound) of a WE doesn't get synchronised.
179        CompoundCollisionShape* parentCCS = orxonox_cast<CompoundCollisionShape*>(parent);
180
181        // If the parent is a CompoundCollisionShape, attach the CollisionShape to it.
182        if (parentCCS)
183            parentCCS->attach(this);
184        else
185        {
186            // If the parent is a WorldEntity, attach the CollisionShape to its collision shapes.
187            WorldEntity* parentWE = orxonox_cast<WorldEntity*>(parent);
188            if (parentWE)
189                parentWE->attachCollisionShape(this);
190        }
191    }
192
193    /**
194    @brief
195        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)
196    @return
197        Returns true if it has been moved.
198    */
199    bool CollisionShape::hasTransform() const
200    {
201        return (!this->position_.positionEquals(Vector3(0, 0, 0), 0.001f) ||
202                !this->orientation_.equals(Quaternion(1,0,0,0), Degree(0.1f)));
203    }
204
205    /**
206    @brief
207        Set the scale of the CollisionShape.
208        Since the scale is a vector the CollisionShape can be scaled independently in each direction, allowing for linear distortions.
209        If the scale changes, this causes the parent CompoundCollisionShape (if there is one) to be updated.
210        Beware, non-uniform scaling (i.e. distortions) might not be supported by all CollisionShapes.
211    @param scale
212        The new scale to be set. Vector3::UNIT_SCALE is the initial scale.
213    */
214    void CollisionShape::setScale3D(const Vector3& scale)
215    {
216        if(this->scale_ == scale)
217            return;
218
219        // If the vectors are not in the same direction, then this is no longer a uniform scaling.
220        if(scale_.crossProduct(scale).squaredLength() != 0.0f)
221        {
222            orxout(internal_warning) << "Non-uniform scaling is not yet supported." << endl;
223            return;
224        }
225
226        this->scale_ = scale;
227
228        this->changedScale();
229        this->updateParent();
230    }
231
232    /**
233    @brief
234        Set the (uniform) scale of the CollisionShape.
235        If the scale changes, this causes the parent CompoundCollisionShape (if there is one) to be updated.
236    @param scale
237        The scale to scale the CollisionShape with. 1.0f is the initial scale.
238    */
239    void CollisionShape::setScale(float scale)
240    {
241        if(this->scale_.length() == scale)
242            return;
243
244        this->scale_ = Vector3::UNIT_SCALE*scale;
245
246        this->changedScale();
247        this->updateParent();
248    }
249
250    /**
251    @brief
252        Is called when the scale of the CollisionShape has changed.
253    */
254    void CollisionShape::changedScale()
255    {
256        // Adjust the position of the CollisionShape.
257        this->position_ *= this->getScale3D();
258    }
259
260    /**
261    @brief
262        Updates the shape.
263        Is called when the internal parameters of the shape have changed such that a new shape needs to be created.
264    */
265    void CollisionShape::updateShape()
266    {
267        btCollisionShape* oldShape = this->collisionShape_;
268        this->collisionShape_ = this->createNewShape();
269        // If the CollisionShape has been rescaled, scale the shape to fit the current scale.
270        if(this->scale_ != Vector3::UNIT_SCALE)
271            this->changedScale();
272        // When we recreate the shape, we have to inform the parent about this to update the shape
273        this->updateParent();
274        if (oldShape)
275            delete oldShape;
276    }
277
278    /**
279    @brief
280        Calculates the local inertia of the collision shape.
281    @todo
282        Document.
283    */
284    void CollisionShape::calculateLocalInertia(float mass, btVector3& inertia) const
285    {
286        if (this->collisionShape_)
287            this->collisionShape_->calculateLocalInertia(mass, inertia);
288        else
289            inertia.setValue(0, 0, 0);
290    }
291}
Note: See TracBrowser for help on using the repository browser.