Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/collisionshapes/CompoundCollisionShape.cc @ 11679

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

merged branch cpp11_v3 back to trunk

  • Property svn:eol-style set to native
File size: 10.6 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 CompoundCollisionShape.cc
31    @brief Implementation of the CompoundCollisionShape class.
32*/
33
34#include "CompoundCollisionShape.h"
35
36#include <BulletCollision/CollisionShapes/btCompoundShape.h>
37
38#include "core/CoreIncludes.h"
39#include "core/XMLPort.h"
40#include "tools/BulletConversions.h"
41
42namespace orxonox
43{
44    RegisterClass(CompoundCollisionShape);
45
46    /**
47    @brief
48        Constructor. Registers and initializes the object.
49    */
50    CompoundCollisionShape::CompoundCollisionShape(Context* context) : CollisionShape(context)
51    {
52        RegisterObject(CompoundCollisionShape);
53
54        this->compoundShape_  = new btCompoundShape();
55    }
56
57    /**
58    @brief
59        Destructor.
60        Deletes all its children.
61    */
62    CompoundCollisionShape::~CompoundCollisionShape()
63    {
64        if (this->isInitialized())
65        {
66            // Delete all children
67            for (const auto& mapEntry : this->attachedShapes_)
68            {
69                // make sure that the child doesn't want to detach itself --> speedup because of the missing update
70                mapEntry.first->notifyDetached();
71                mapEntry.first->destroy();
72                if (this->collisionShape_ == mapEntry.second)
73                    this->collisionShape_ = nullptr; // don't destroy it twice
74            }
75
76            delete this->compoundShape_;
77            if (this->collisionShape_ == this->compoundShape_)
78                this->collisionShape_ = nullptr; // don't destroy it twice
79        }
80    }
81
82    void CompoundCollisionShape::XMLPort(Element& xmlelement, XMLPort::Mode mode)
83    {
84        SUPER(CompoundCollisionShape, XMLPort, xmlelement, mode);
85        // Attached collision shapes
86        XMLPortObject(CompoundCollisionShape, CollisionShape, "", attach, detach, xmlelement, mode);
87    }
88
89    /**
90    @brief
91        Attach the input CollisionShape to the CompoundCollisionShape.
92    @param shape
93        A pointer to the CollisionShape that is to be attached.
94    */
95    void CompoundCollisionShape::attach(CollisionShape* shape)
96    {
97        // If either the input shape is nullptr or we try to attach the CollisionShape to itself.
98        if (!shape || static_cast<CollisionShape*>(this) == shape)
99            return;
100
101        if (this->attachedShapes_.find(shape) != this->attachedShapes_.end())
102        {
103            orxout(internal_warning) << "Attaching a CollisionShape twice is not yet supported." << endl;
104            return;
105        }
106
107        // Notify the CollisionShape that it is being attached to the CompoundCollisionShape.
108        if (!shape->notifyBeingAttached(this))
109            return;
110
111        // Attach it.
112        this->attachedShapes_[shape] = shape->getCollisionShape();
113
114        // Only actually attach if we didn't pick a CompoundCollisionShape with no content.
115        if (shape->getCollisionShape())
116        {
117            btTransform transf(multi_cast<btQuaternion>(shape->getOrientation()), multi_cast<btVector3>(shape->getPosition()));
118            // Add the btCollisionShape of the CollisionShape as a child shape to the btCompoundShape of the CompoundCollisionShape.
119            this->compoundShape_->addChildShape(transf, shape->getCollisionShape());
120
121            this->updatePublicShape();
122        }
123    }
124
125    /**
126    @brief
127        Detach the input CollisionShape form the CompoundCollisionShape.
128    @param shape
129        A pointer to the CollisionShape to be detached.
130    */
131    void CompoundCollisionShape::detach(CollisionShape* shape)
132    {
133        // If the input CollisionShape is actually attached.
134        if (this->attachedShapes_.find(shape) != this->attachedShapes_.end())
135        {
136            this->attachedShapes_.erase(shape);
137            if (shape->getCollisionShape())
138                this->compoundShape_->removeChildShape(shape->getCollisionShape()); // TODO: Apparently this is broken?
139            shape->notifyDetached();
140
141            this->updatePublicShape();
142        }
143        else
144            orxout(internal_warning) << "Cannot detach non child collision shape" << endl;
145    }
146
147    /**
148    @brief
149        Detach all attached CollisionShapes.
150    */
151    void CompoundCollisionShape::detachAll()
152    {
153        while (this->attachedShapes_.size() > 0)
154            this->detach(this->attachedShapes_.begin()->first);
155    }
156
157    /**
158    @brief
159        Update the input CollisionShape that is attached to the CompoundCollisionShape.
160        This is called when the input shape's internal collision shape (a btCollisionShape) has changed.
161    @param shape
162        A pointer to the CollisionShape to be updated.
163    */
164    void CompoundCollisionShape::updateAttachedShape(CollisionShape* shape)
165    {
166        if (!shape)
167            return;
168
169        std::map<CollisionShape*, btCollisionShape*>::iterator it = this->attachedShapes_.find(shape);
170        // Check whether the input shape belongs to this CompoundCollisionShape.
171        if (it == this->attachedShapes_.end())
172        {
173            orxout(internal_warning) << "Cannot update child shape: Instance not a child." << endl;
174            return;
175        }
176
177        // Remove old btCollisionShape, stored in the children map
178        if (it->second)
179            this->compoundShape_->removeChildShape(it->second); // TODO: Apparently this is broken?
180
181        // Only actually attach if we didn't pick a CompoundCollisionShape with no content
182        if (shape->getCollisionShape())
183        {
184            btTransform transf(multi_cast<btQuaternion>(shape->getOrientation()), multi_cast<btVector3>(shape->getPosition()));
185            this->compoundShape_->addChildShape(transf, shape->getCollisionShape());
186            it->second = shape->getCollisionShape();
187        }
188
189        this->updatePublicShape();
190    }
191
192    /**
193    @brief
194        Updates the public shape, the collision shape this CompoundCollisionShape has to the outside.
195    */
196    void CompoundCollisionShape::updatePublicShape()
197    {
198        btCollisionShape* primitive = nullptr; // The primitive shape, if there is one.
199        bool bPrimitive = true; // Whether the CompoundCollisionShape has just one non-empty CollisionShape. And that shape also has no transformation.
200        bool bEmpty = true; // Whether the CompoundCollisionShape is empty.
201        // Iterate over all CollisionShapes that belong to this CompoundCollisionShape.
202        for (const auto& mapEntry : this->attachedShapes_)
203        {
204            // TODO: Make sure this is correct.
205            if (mapEntry.second)
206            {
207                bEmpty = false;
208                if (!mapEntry.first->hasTransform() && bPrimitive)
209                    primitive = mapEntry.second;
210                else
211                {
212                    bPrimitive = false;
213                    break;
214                }
215            }
216        }
217
218        // If there is no non-empty CollisionShape.
219        if (bEmpty)
220        {
221            // If there was none all along, nothing needs to be changed.
222            if (this->collisionShape_ == nullptr)
223                return;
224            this->collisionShape_ = nullptr;
225        }
226        // If the CompoundCollisionShape is just a primitive.
227        // Only one shape to be added, no transform; return it directly.
228        else if (bPrimitive)
229            this->collisionShape_ = primitive;
230        // Make sure we use the compound shape when returning a btCollisionShape.
231        else
232            this->collisionShape_ = this->compoundShape_;
233
234        this->updateParent();
235    }
236
237    /**
238    @brief
239        Get the attached CollisionShape at the given index.
240    @param index
241        The index of the desired CollisionShape.
242    @return
243        Returns a pointer to the attached CollisionShape at the given index.
244    */
245    CollisionShape* CompoundCollisionShape::getAttachedShape(unsigned int index) const
246    {
247        unsigned int i = 0;
248        for (const auto& mapEntry : this->attachedShapes_)
249        {
250            if (i == index)
251                return mapEntry.first;
252            ++i;
253        }
254        return nullptr;
255    }
256
257    /**
258    @brief
259        Is called when the scale of the CompoundCollisionShape has changed.
260        Iterates over all attached CollisionShapes and scales them, then recomputes their compound shape.
261    */
262    void CompoundCollisionShape::changedScale()
263    {
264        CollisionShape::changedScale();
265
266        std::vector<CollisionShape*> shapes;
267        // Iterate through all attached CollisionShapes and add them to the list of shapes.
268        for(const auto& mapEntry : this->attachedShapes_)
269            shapes.push_back(mapEntry.first);
270
271        // Delete the compound shape and create a new one.
272        delete this->compoundShape_;
273        this->compoundShape_ = new btCompoundShape();
274
275        // Re-attach all CollisionShapes.
276        for(CollisionShape* shape : shapes)
277        {
278            shape->setScale3D(this->getScale3D());
279            // Only actually attach if we didn't pick a CompoundCollisionShape with no content.
280            if (shape->getCollisionShape())
281            {
282                btTransform transf(multi_cast<btQuaternion>(shape->getOrientation()), multi_cast<btVector3>(shape->getPosition()));
283                // Add the btCollisionShape of the CollisionShape as a child shape to the btCompoundShape of the CompoundCollisionShape.
284                this->compoundShape_->addChildShape(transf, shape->getCollisionShape());
285            }
286        }
287
288        this->updatePublicShape();
289
290        /*
291        // Iterate through all attached CollisionShapes
292        for(std::map<CollisionShape*, btCollisionShape*>::const_iterator it = this->attachedShapes_.begin(); it != this->attachedShapes_.end(); it++)
293        {
294            // Rescale the CollisionShape.
295            it->first->setScale3D(this->getScale3D());
296            this->updateAttachedShape(it->first);
297        }
298
299        this->updatePublicShape();*/
300    }
301}
Note: See TracBrowser for help on using the repository browser.