~ubuntu-branches/debian/sid/ember/sid

« back to all changes in this revision

Viewing changes to src/components/ogre/ogreopcode/src/OgreCollisionObject.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michael Koch
  • Date: 2009-07-23 07:46:40 UTC
  • Revision ID: james.westby@ubuntu.com-20090723074640-wh0ukzis0kda36qv
Tags: upstream-0.5.6
ImportĀ upstreamĀ versionĀ 0.5.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
///////////////////////////////////////////////////////////////////////////////
 
2
///  @file OgreCollisionObject.cpp
 
3
///  @brief <TODO: insert file description here>
 
4
///
 
5
///  @author The OgreOpcode Team
 
6
///
 
7
///////////////////////////////////////////////////////////////////////////////
 
8
///
 
9
///  This file is part of OgreOpcode.
 
10
///
 
11
///  A lot of the code is based on the Nebula Opcode Collision module, see docs/Nebula_license.txt
 
12
///
 
13
///  OgreOpcode is free software; you can redistribute it and/or
 
14
///  modify it under the terms of the GNU Lesser General Public
 
15
///  License as published by the Free Software Foundation; either
 
16
///  version 2.1 of the License, or (at your option) any later version.
 
17
///
 
18
///  OgreOpcode is distributed in the hope that it will be useful,
 
19
///  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
20
///  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
21
///  Lesser General Public License for more details.
 
22
///
 
23
///  You should have received a copy of the GNU Lesser General Public
 
24
///  License along with OgreOpcode; if not, write to the Free Software
 
25
///  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
26
///
 
27
///////////////////////////////////////////////////////////////////////////////
 
28
#include "OgreOpcodeExports.h"
 
29
#include "OgreCollisionObject.h"
 
30
#include "OgreCollisionReporter.h"
 
31
#include "OgreCollisionManager.h"
 
32
#include "OgreOpcodeMath.h"
 
33
#include "OgreOpcodeUtils.h"
 
34
#include "BP_Scene.h"
 
35
#include "BP_Proxy.h"
 
36
 
 
37
using namespace Ogre;
 
38
using namespace OgreOpcode::Details;
 
39
 
 
40
namespace OgreOpcode
 
41
{
 
42
        void CollisionObject::getSAPMinMax(Vector3& sapMin, Vector3& sapMax) const
 
43
        {
 
44
                //sapMin = Vector3(n_min(old_minv.x,minv.x),
 
45
                //      n_min(old_minv.y,minv.y),
 
46
                //      n_min(old_minv.z,minv.z));
 
47
                //sapMax = Vector3(n_max(old_maxv.x,maxv.x),
 
48
                //      n_max(old_maxv.y,maxv.y),
 
49
                //      n_max(old_maxv.z,maxv.z));
 
50
                sapMin = minv;
 
51
                sapMax = maxv;
 
52
        }
 
53
 
 
54
        void CollisionObject::update(Real t, Matrix4& m)
 
55
        {
 
56
                assert(is_attached);
 
57
 
 
58
                mForcedUpdate = true; ///FIXME Blah. Do we really need this?
 
59
 
 
60
                if(mForcedUpdate)
 
61
                {
 
62
                        mNeedsUpdating = true;
 
63
                }
 
64
                else
 
65
                {
 
66
                        Vector3 p0(old_matrix[0][3], old_matrix[1][3], old_matrix[2][3]);
 
67
                        Vector3 v0(new_matrix[0][3], new_matrix[1][3], new_matrix[2][3]);
 
68
                        Vector3 moved = p0 - v0;
 
69
 
 
70
                        bool hasMoved = (moved != Vector3::ZERO);
 
71
 
 
72
                        mNeedsUpdating = hasMoved;
 
73
                }
 
74
 
 
75
                //if(mNeedsUpdating)
 
76
                //{
 
77
                //      getShape()->computeIceABB();
 
78
                //}
 
79
 
 
80
                old_matrix = new_matrix;
 
81
                old_pos = new_pos;
 
82
                new_matrix = m;
 
83
 
 
84
                new_pos = getShape()->getParentSceneNode()->_getDerivedPosition();
 
85
                // Get center in world space.
 
86
                Vector3 lMin,lMax;
 
87
                getShape()->getMinMax(lMin,lMax);
 
88
                lMax-=lMin;
 
89
                mRadius = lMax.length()*0.5;
 
90
 
 
91
                old_minv = minv;
 
92
                old_maxv = maxv;
 
93
                getShape()->getMinMax(minv,maxv);
 
94
 
 
95
                // if old_matrix etc are not yet valid,
 
96
                // initialize with the current values, to prevent "startup popping"
 
97
                bool oldValsInvalid = (m_tdelta <= 0.0);
 
98
                if (oldValsInvalid)
 
99
                {
 
100
                        old_matrix = new_matrix;
 
101
                        old_pos = new_pos;
 
102
                        old_minv = minv;
 
103
                        old_maxv = maxv;
 
104
                }
 
105
                m_tdelta = t;
 
106
 
 
107
        }
 
108
 
 
109
        bool CollisionObject::contact(CollisionObject *other,     // the other object
 
110
                CollisionType ct,
 
111
                CollisionPair& cr)
 
112
        {
 
113
                // This object moved from p0 to p0+v0, the other from p1 to p1+v1.
 
114
                Vector3 p0(old_matrix[0][3], old_matrix[1][3], old_matrix[2][3]);
 
115
                Vector3 p1(other->old_matrix[0][3], other->old_matrix[1][3], other->old_matrix[2][3]);
 
116
                Vector3 v0(new_matrix[0][3], new_matrix[1][3], new_matrix[2][3]);
 
117
                //Vector3 p0 = old_pos;
 
118
                //Vector3 p1 = other->old_pos;
 
119
                //Vector3 v0 = new_pos;
 
120
                v0 -= p0;
 
121
                Vector3 v1(Vector3(other->new_matrix[0][3], other->new_matrix[1][3], other->new_matrix[2][3]) - p1);
 
122
                //Vector3 v1(other->new_pos - p1);
 
123
 
 
124
                bool has_contact = false;
 
125
                switch (ct)
 
126
                {
 
127
                case COLLTYPE_QUICK:
 
128
                        {
 
129
                                // do a contact check between 'moving spheres'
 
130
                                sphere s0(p0,mRadius);
 
131
                                sphere s1(p1,other->mRadius);
 
132
                                Real u0,u1;
 
133
                                if (s0.intersect_sweep(v0,s1,v1,u0,u1))
 
134
                                {
 
135
                                        // there may be a valid contact somewhere along the path
 
136
                                        if ((u0>=0.0f) && (u0<1.0f))
 
137
                                        {
 
138
                                                // compute the 2 midpoints at the time of collision
 
139
                                                Vector3 c0(p0 + v0*u0);
 
140
                                                Vector3 c1(p1 + v1*u0);
 
141
 
 
142
                                                // compute the collide normal
 
143
                                                Vector3 d(c1-c0);
 
144
                                                if (d.length() > TINY)
 
145
                                                {
 
146
                                                        d.normalise();
 
147
                                                } else
 
148
                                                {
 
149
                                                        d = Vector3(0.0f, 1.0f, 0.0f);
 
150
                                                }
 
151
 
 
152
                                                // compute the contact point
 
153
                                                CollisionInfo collInfo;
 
154
                                                collInfo.contact = (d*mRadius) + c0;
 
155
 
 
156
                                                // compute the collide normals
 
157
                                                collInfo.this_normal = d;
 
158
                                                collInfo.other_normal = -d;
 
159
                                                cr.collInfos.push_back(collInfo);
 
160
 
 
161
                                                // compute the timestamp where the collision happened
 
162
                                                cr.tstamp = m_tdelta*u0;
 
163
                                                has_contact = true;
 
164
                                        }
 
165
                                }
 
166
                        }
 
167
                        break;
 
168
 
 
169
                case COLLTYPE_EXACT:
 
170
                case COLLTYPE_CONTACT:
 
171
                        {
 
172
                                // If distance traveled is more then 1/8 then each of the object's
 
173
                                // radii, then we do several tests along the line
 
174
                                // of movements.
 
175
 
 
176
                                // WVB:
 
177
                                // This isn't likely to work particularly well for objects
 
178
                                // with large rotational motion.  For that it would be better
 
179
                                // to blend the transformations along the path as well,
 
180
                                // and to also use amount of rotation in determining how many
 
181
                                // steps are necessary.  That would bring this another step closer
 
182
                                // to being a true continuous collision detection system.
 
183
 
 
184
                                Real rq0 = mRadius * 0.125f;
 
185
                                Real rq1 = other->mRadius * 0.125f;
 
186
                                Real v0_len = v0.length();
 
187
                                Real v1_len = v1.length();
 
188
                                int num = (int) n_max((v0_len/rq0), (v1_len/rq1));
 
189
                                const int maxChecks = 16;
 
190
                                if (num == 0)
 
191
                                {
 
192
                                        num = 1;
 
193
                                } else if (num > maxChecks)
 
194
                                {
 
195
                                        num = maxChecks;
 
196
                                }
 
197
                                Vector3 d0(v0 / float(num));
 
198
                                Vector3 d1(v1 / float(num));
 
199
                                Matrix4 self_matrix = old_matrix;
 
200
                                Matrix4 other_matrix = other->old_matrix;
 
201
                                int i;
 
202
 
 
203
                                for (i=0; i<num; i++)
 
204
                                {
 
205
                                        p0 += d0;
 
206
                                        p1 += d1;
 
207
                                        self_matrix[0][3] = p0.x;
 
208
                                        self_matrix[1][3] = p0.y;
 
209
                                        self_matrix[2][3] = p0.z;
 
210
                                        other_matrix[0][3] = p1.x;
 
211
                                        other_matrix[1][3] = p1.y;
 
212
                                        other_matrix[2][3] = p1.z;
 
213
                                        if (mShape->collide(ct, self_matrix, other->getShape(), other_matrix, cr))
 
214
                                        {
 
215
                                                // CONTACT!!!
 
216
                                                double dt = (m_tdelta) / num;
 
217
                                                cr.tstamp = dt*i;
 
218
                                                return true;
 
219
                                        }
 
220
                                }
 
221
                        }
 
222
                        break;
 
223
 
 
224
                default:
 
225
                        break;
 
226
                }
 
227
                return has_contact;
 
228
        }
 
229
 
 
230
        void CollisionObject::addToCollideList(CollisionObject* collObj)
 
231
        {
 
232
                collideList.push_back(collObj);
 
233
        }
 
234
 
 
235
        void CollisionObject::collide(void)
 
236
        {
 
237
                assert(is_attached);
 
238
                assert(mContext);
 
239
 
 
240
                CollisionReporter *crh = &(mContext->collideReportHandler);
 
241
 
 
242
                //LogManager::getSingleton().logMessage(getName() + " is about to test collisions.");
 
243
 
 
244
                for (collideListIterator i = collideList.begin(); i != collideList.end(); ++i)
 
245
                {
 
246
                        // is the candidate in the ignore types set?
 
247
                        CollisionObject *other = (*i);
 
248
 
 
249
                        //LogManager::getSingleton().logMessage(getName() + " is testing against " + other->getName());
 
250
 
 
251
                        // am I trying to collide with myself?
 
252
                        if ( id == other->id ) continue;
 
253
 
 
254
                        // query the collision type defined for those two objects
 
255
                        CollisionType ct = CollisionManager::getSingletonPtr()->queryCollType(getCollClass(),other->getCollClass());
 
256
 
 
257
                        // ignore collision?
 
258
                        if (COLLTYPE_IGNORE == ct) continue;
 
259
 
 
260
                        // has this collision already been checked by the other object?
 
261
                        if (!crh->collisionTested(id,other->id))
 
262
                        {
 
263
                                // no, we're first...
 
264
                                crh->mTotalObjObjTests++;
 
265
                                crh->addCollisionTest(id,other->id);
 
266
 
 
267
                                // ask objects whether they collide...
 
268
                                // FIXME: probably do velocity-based finer
 
269
                                // grained control here ?!?!?!
 
270
                                CollisionPair cr;
 
271
                                bool ret = contact(other,ct,cr);
 
272
                                crh->mTotalBVBVTests += cr.numBVBVTests;
 
273
                                crh->mTotalBVPrimTests += cr.numBVPrimTests;
 
274
                                crh->mTotalPrimPrimTests += cr.numPrimPrimTests;
 
275
                                if (ret)
 
276
                                {
 
277
                                        cr.this_object = this;
 
278
                                        cr.other_object = other;
 
279
                                        crh->addCollision(cr,id,other->id);
 
280
                                        num_colls++;
 
281
                                        other->num_colls++;
 
282
                                }
 
283
                        }
 
284
                }
 
285
                collideList.clear();
 
286
                mNeedsUpdating = false;
 
287
        }
 
288
 
 
289
        void CollisionObject::visualizeRadii()
 
290
        {
 
291
                // render the objects radii
 
292
                int dim;
 
293
                Real dr = Ogre::Math::DegreesToRadians(5.0f);
 
294
                Vector3 ctr = getShape()->getCenter();
 
295
                for (dim=0; dim<3; dim++)
 
296
                {
 
297
                        Real r;
 
298
                        for (r=0.0f; r< Ogre::Math::DegreesToRadians(360.0f); r+=dr)
 
299
                        {
 
300
                                Real sin_r0 = (Real) sin(r);
 
301
                                Real cos_r0 = (Real) cos(r);
 
302
                                float sin_r1 = (Real) sin(r+dr);
 
303
                                Real cos_r1 = (Real) cos(r+dr);
 
304
                                Vector3 v0_x(0.0f, sin_r0*mRadius, cos_r0*mRadius); v0_x+=ctr;
 
305
                                Vector3 v1_x(0.0f, sin_r1*mRadius, cos_r1*mRadius); v1_x+=ctr;
 
306
                                Vector3 v0_y(sin_r0*mRadius, 0.0f, cos_r0*mRadius); v0_y+=ctr;
 
307
                                Vector3 v1_y(sin_r1*mRadius, 0.0f, cos_r1*mRadius); v1_y+=ctr;
 
308
                                Vector3 v0_z(sin_r0*mRadius, cos_r0*mRadius, 0.0f); v0_z+=ctr;
 
309
                                Vector3 v1_z(sin_r1*mRadius, cos_r1*mRadius, 0.0f); v1_z+=ctr;
 
310
 
 
311
                                getContext()->getVisualDebugger()->addRadiiLine(v0_x.x,v0_x.y,v0_x.z, v1_x.x,v1_x.y,v1_x.z);
 
312
                                getContext()->getVisualDebugger()->addRadiiLine(v0_y.x,v0_y.y,v0_y.z, v1_y.x,v1_y.y,v1_y.z);
 
313
                                getContext()->getVisualDebugger()->addRadiiLine(v0_z.x,v0_z.y,v0_z.z, v1_z.x,v1_z.y,v1_z.z);
 
314
                        }
 
315
                }
 
316
        }
 
317
 
 
318
        void CollisionObject::visualizeContacts()
 
319
        {
 
320
                static int contactCount = 0;
 
321
                static bool bufferContacts = true;
 
322
 
 
323
                if (num_colls > 0)
 
324
                {
 
325
                        // Retrieve collision contact information and store them in mRecentContactList.
 
326
 
 
327
                        CollisionPair **pcr;
 
328
                        int num = mContext->getCollisions(this,pcr);
 
329
                        int i;
 
330
                        for (i = 0; i < num; i++)
 
331
                        {
 
332
                                CollisionPair *cr = pcr[i];
 
333
                                for (int currColl = 0; currColl < static_cast<int>(cr->collInfos.size()); currColl++)
 
334
                                {
 
335
                                        if(bufferContacts)
 
336
                                                contactCount++;
 
337
 
 
338
                                        CollisionInfo collInfo;
 
339
                                        collInfo.contact = cr->collInfos[currColl].contact;
 
340
                                        collInfo.this_normal = cr->collInfos[currColl].this_normal * 5;
 
341
                                        collInfo.other_normal = cr->collInfos[currColl].other_normal * 5;
 
342
                                        mRecentContactList.push_back(collInfo);
 
343
                                        if(!bufferContacts)
 
344
                                                mRecentContactList.pop_front();
 
345
                                }
 
346
                        }
 
347
                }
 
348
 
 
349
                // render any collision contact points
 
350
                if (mRecentContactList.size() > 0)
 
351
                {
 
352
                        std::list<CollisionInfo>::iterator contactIter;
 
353
                        for (contactIter = mRecentContactList.begin(); contactIter != mRecentContactList.end(); ++contactIter)
 
354
                        {
 
355
                                        Vector3 cnt = (*contactIter).contact;
 
356
                                        getContext()->getVisualDebugger()->addContactLine(cnt.x-0.5f,cnt.y,cnt.z, cnt.x+0.5f,cnt.y,cnt.z);
 
357
                                        getContext()->getVisualDebugger()->addContactLine(cnt.x,cnt.y-0.5f,cnt.z, cnt.x,cnt.y+0.5f,cnt.z);
 
358
                                        getContext()->getVisualDebugger()->addContactLine(cnt.x,cnt.y,cnt.z-0.5f, cnt.x,cnt.y,cnt.z+0.5f);
 
359
 
 
360
                                        Vector3 n = (*contactIter).this_normal * 5;
 
361
                                        getContext()->getVisualDebugger()->addContactNormalsLine(cnt.x,cnt.y,cnt.z, cnt.x+n.x,cnt.y+n.y,cnt.z+n.z);
 
362
                                        n = (*contactIter).other_normal * 5;
 
363
                                        getContext()->getVisualDebugger()->addContactNormalsLine(cnt.x,cnt.y,cnt.z, cnt.x+n.x,cnt.y+n.y,cnt.z+n.z);
 
364
                        }
 
365
                }
 
366
 
 
367
                if(contactCount > 10)
 
368
                        bufferContacts = false;
 
369
        }
 
370
 
 
371
        void CollisionObject::visualizeBoundingBoxes()
 
372
        {
 
373
                // render the objects bounding boxes (stretched by their movement)
 
374
                Vector3 v0, v1;
 
375
                getShape()->getMinMax(v0,v1);
 
376
 
 
377
                getContext()->getVisualDebugger()->addBBLine(v0.x,v0.y,v0.z, v1.x,v0.y,v0.z);
 
378
                getContext()->getVisualDebugger()->addBBLine(v1.x,v0.y,v0.z, v1.x,v1.y,v0.z);
 
379
                getContext()->getVisualDebugger()->addBBLine(v1.x,v1.y,v0.z, v0.x,v1.y,v0.z);
 
380
                getContext()->getVisualDebugger()->addBBLine(v0.x,v1.y,v0.z, v0.x,v0.y,v0.z);
 
381
                getContext()->getVisualDebugger()->addBBLine(v0.x,v0.y,v1.z, v1.x,v0.y,v1.z);
 
382
                getContext()->getVisualDebugger()->addBBLine(v1.x,v0.y,v1.z, v1.x,v1.y,v1.z);
 
383
                getContext()->getVisualDebugger()->addBBLine(v1.x,v1.y,v1.z, v0.x,v1.y,v1.z);
 
384
                getContext()->getVisualDebugger()->addBBLine(v0.x,v1.y,v1.z, v0.x,v0.y,v1.z);
 
385
                getContext()->getVisualDebugger()->addBBLine(v0.x,v0.y,v0.z, v0.x,v0.y,v1.z);
 
386
                getContext()->getVisualDebugger()->addBBLine(v1.x,v0.y,v0.z, v1.x,v0.y,v1.z);
 
387
                getContext()->getVisualDebugger()->addBBLine(v1.x,v1.y,v0.z, v1.x,v1.y,v1.z);
 
388
                getContext()->getVisualDebugger()->addBBLine(v0.x,v1.y,v0.z, v0.x,v1.y,v1.z);
 
389
        }
 
390
 
 
391
        void CollisionObject::nodeUpdated(const Node* node)
 
392
        {
 
393
                mNeedsUpdating = true;
 
394
        }
 
395
 
 
396
        void CollisionObject::do_broadphase()
 
397
        {
 
398
                if (mProxy)
 
399
                {
 
400
                        mProxy->setBBox(minv, maxv);
 
401
                }
 
402
                else
 
403
                {
 
404
                        mProxy = mContext->getBroadPhase()->createProxy(this, minv, maxv);
 
405
                }
 
406
        }
 
407
 
 
408
        void CollisionObject::remove_broadphase()
 
409
        {
 
410
                if(mProxy)
 
411
                {
 
412
                        mContext->getBroadPhase()->deleteProxy(mProxy);
 
413
                        mProxy = 0;
 
414
                }
 
415
        }
 
416
}
 
417
 
 
418
//------------------------------------------------------------------------