diff options
author | dan miller | 2007-10-19 05:24:38 +0000 |
---|---|---|
committer | dan miller | 2007-10-19 05:24:38 +0000 |
commit | f205de7847da7ae1c10212d82e7042d0100b4ce0 (patch) | |
tree | 9acc9608a6880502aaeda43af52c33e278e95b9c /libraries/ode-0.9/ode/src/collision_space.cpp | |
parent | trying to fix my screwup part deux (diff) | |
download | opensim-SC-f205de7847da7ae1c10212d82e7042d0100b4ce0.zip opensim-SC-f205de7847da7ae1c10212d82e7042d0100b4ce0.tar.gz opensim-SC-f205de7847da7ae1c10212d82e7042d0100b4ce0.tar.bz2 opensim-SC-f205de7847da7ae1c10212d82e7042d0100b4ce0.tar.xz |
from the start... checking in ode-0.9
Diffstat (limited to 'libraries/ode-0.9/ode/src/collision_space.cpp')
-rw-r--r-- | libraries/ode-0.9/ode/src/collision_space.cpp | 790 |
1 files changed, 790 insertions, 0 deletions
diff --git a/libraries/ode-0.9/ode/src/collision_space.cpp b/libraries/ode-0.9/ode/src/collision_space.cpp new file mode 100644 index 0000000..1a8fc81 --- /dev/null +++ b/libraries/ode-0.9/ode/src/collision_space.cpp | |||
@@ -0,0 +1,790 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | |||
25 | spaces | ||
26 | |||
27 | */ | ||
28 | |||
29 | #include <ode/common.h> | ||
30 | #include <ode/matrix.h> | ||
31 | #include <ode/collision_space.h> | ||
32 | #include <ode/collision.h> | ||
33 | #include "collision_kernel.h" | ||
34 | |||
35 | #include "collision_space_internal.h" | ||
36 | |||
37 | #ifdef _MSC_VER | ||
38 | #pragma warning(disable:4291) // for VC++, no complaints about "no matching operator delete found" | ||
39 | #endif | ||
40 | |||
41 | //**************************************************************************** | ||
42 | // make the geom dirty by setting the GEOM_DIRTY and GEOM_BAD_AABB flags | ||
43 | // and moving it to the front of the space's list. all the parents of a | ||
44 | // dirty geom also become dirty. | ||
45 | |||
46 | void dGeomMoved (dxGeom *geom) | ||
47 | { | ||
48 | dAASSERT (geom); | ||
49 | |||
50 | // if geom is offset, mark it as needing a calculate | ||
51 | if (geom->offset_posr) { | ||
52 | geom->gflags |= GEOM_POSR_BAD; | ||
53 | } | ||
54 | |||
55 | // from the bottom of the space heirarchy up, process all clean geoms | ||
56 | // turning them into dirty geoms. | ||
57 | dxSpace *parent = geom->parent_space; | ||
58 | |||
59 | while (parent && (geom->gflags & GEOM_DIRTY)==0) { | ||
60 | CHECK_NOT_LOCKED (parent); | ||
61 | geom->gflags |= GEOM_DIRTY | GEOM_AABB_BAD; | ||
62 | parent->dirty (geom); | ||
63 | geom = parent; | ||
64 | parent = parent->parent_space; | ||
65 | } | ||
66 | |||
67 | // all the remaining dirty geoms must have their AABB_BAD flags set, to | ||
68 | // ensure that their AABBs get recomputed | ||
69 | while (geom) { | ||
70 | geom->gflags |= GEOM_DIRTY | GEOM_AABB_BAD; | ||
71 | CHECK_NOT_LOCKED (geom->parent_space); | ||
72 | geom = geom->parent_space; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | #define GEOM_ENABLED(g) ((g)->gflags & GEOM_ENABLED) | ||
77 | |||
78 | //**************************************************************************** | ||
79 | // dxSpace | ||
80 | |||
81 | dxSpace::dxSpace (dSpaceID _space) : dxGeom (_space,0) | ||
82 | { | ||
83 | count = 0; | ||
84 | first = 0; | ||
85 | cleanup = 1; | ||
86 | current_index = 0; | ||
87 | current_geom = 0; | ||
88 | lock_count = 0; | ||
89 | } | ||
90 | |||
91 | |||
92 | dxSpace::~dxSpace() | ||
93 | { | ||
94 | CHECK_NOT_LOCKED (this); | ||
95 | if (cleanup) { | ||
96 | // note that destroying each geom will call remove() | ||
97 | dxGeom *g,*n; | ||
98 | for (g = first; g; g=n) { | ||
99 | n = g->next; | ||
100 | dGeomDestroy (g); | ||
101 | } | ||
102 | } | ||
103 | else { | ||
104 | dxGeom *g,*n; | ||
105 | for (g = first; g; g=n) { | ||
106 | n = g->next; | ||
107 | remove (g); | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | |||
112 | |||
113 | void dxSpace::computeAABB() | ||
114 | { | ||
115 | if (first) { | ||
116 | int i; | ||
117 | dReal a[6]; | ||
118 | a[0] = dInfinity; | ||
119 | a[1] = -dInfinity; | ||
120 | a[2] = dInfinity; | ||
121 | a[3] = -dInfinity; | ||
122 | a[4] = dInfinity; | ||
123 | a[5] = -dInfinity; | ||
124 | for (dxGeom *g=first; g; g=g->next) { | ||
125 | g->recomputeAABB(); | ||
126 | for (i=0; i<6; i += 2) if (g->aabb[i] < a[i]) a[i] = g->aabb[i]; | ||
127 | for (i=1; i<6; i += 2) if (g->aabb[i] > a[i]) a[i] = g->aabb[i]; | ||
128 | } | ||
129 | memcpy(aabb,a,6*sizeof(dReal)); | ||
130 | } | ||
131 | else { | ||
132 | dSetZero (aabb,6); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | |||
137 | void dxSpace::setCleanup (int mode) | ||
138 | { | ||
139 | cleanup = (mode != 0); | ||
140 | } | ||
141 | |||
142 | |||
143 | int dxSpace::getCleanup() | ||
144 | { | ||
145 | return cleanup; | ||
146 | } | ||
147 | |||
148 | |||
149 | int dxSpace::query (dxGeom *geom) | ||
150 | { | ||
151 | dAASSERT (geom); | ||
152 | return (geom->parent_space == this); | ||
153 | } | ||
154 | |||
155 | |||
156 | int dxSpace::getNumGeoms() | ||
157 | { | ||
158 | return count; | ||
159 | } | ||
160 | |||
161 | |||
162 | // the dirty geoms are numbered 0..k, the clean geoms are numbered k+1..count-1 | ||
163 | |||
164 | dxGeom *dxSpace::getGeom (int i) | ||
165 | { | ||
166 | dUASSERT (i >= 0 && i < count,"index out of range"); | ||
167 | if (current_geom && current_index == i-1) { | ||
168 | current_geom = current_geom->next; | ||
169 | current_index = i; | ||
170 | return current_geom; | ||
171 | } | ||
172 | else { | ||
173 | dxGeom *g=first; | ||
174 | for (int j=0; j<i; j++) { | ||
175 | if (g) g = g->next; else return 0; | ||
176 | } | ||
177 | current_geom = g; | ||
178 | current_index = i; | ||
179 | return g; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | |||
184 | void dxSpace::add (dxGeom *geom) | ||
185 | { | ||
186 | CHECK_NOT_LOCKED (this); | ||
187 | dAASSERT (geom); | ||
188 | dUASSERT (geom->parent_space == 0 && geom->next == 0, | ||
189 | "geom is already in a space"); | ||
190 | |||
191 | // add | ||
192 | geom->parent_space = this; | ||
193 | geom->spaceAdd (&first); | ||
194 | count++; | ||
195 | |||
196 | // enumerator has been invalidated | ||
197 | current_geom = 0; | ||
198 | |||
199 | // new geoms are added to the front of the list and are always | ||
200 | // considered to be dirty. as a consequence, this space and all its | ||
201 | // parents are dirty too. | ||
202 | geom->gflags |= GEOM_DIRTY | GEOM_AABB_BAD; | ||
203 | dGeomMoved (this); | ||
204 | } | ||
205 | |||
206 | |||
207 | void dxSpace::remove (dxGeom *geom) | ||
208 | { | ||
209 | CHECK_NOT_LOCKED (this); | ||
210 | dAASSERT (geom); | ||
211 | dUASSERT (geom->parent_space == this,"object is not in this space"); | ||
212 | |||
213 | // remove | ||
214 | geom->spaceRemove(); | ||
215 | count--; | ||
216 | |||
217 | // safeguard | ||
218 | geom->next = 0; | ||
219 | geom->tome = 0; | ||
220 | geom->parent_space = 0; | ||
221 | |||
222 | // enumerator has been invalidated | ||
223 | current_geom = 0; | ||
224 | |||
225 | // the bounding box of this space (and that of all the parents) may have | ||
226 | // changed as a consequence of the removal. | ||
227 | dGeomMoved (this); | ||
228 | } | ||
229 | |||
230 | |||
231 | void dxSpace::dirty (dxGeom *geom) | ||
232 | { | ||
233 | geom->spaceRemove(); | ||
234 | geom->spaceAdd (&first); | ||
235 | } | ||
236 | |||
237 | //**************************************************************************** | ||
238 | // simple space - reports all n^2 object intersections | ||
239 | |||
240 | struct dxSimpleSpace : public dxSpace { | ||
241 | dxSimpleSpace (dSpaceID _space); | ||
242 | void cleanGeoms(); | ||
243 | void collide (void *data, dNearCallback *callback); | ||
244 | void collide2 (void *data, dxGeom *geom, dNearCallback *callback); | ||
245 | }; | ||
246 | |||
247 | |||
248 | dxSimpleSpace::dxSimpleSpace (dSpaceID _space) : dxSpace (_space) | ||
249 | { | ||
250 | type = dSimpleSpaceClass; | ||
251 | } | ||
252 | |||
253 | |||
254 | void dxSimpleSpace::cleanGeoms() | ||
255 | { | ||
256 | // compute the AABBs of all dirty geoms, and clear the dirty flags | ||
257 | lock_count++; | ||
258 | for (dxGeom *g=first; g && (g->gflags & GEOM_DIRTY); g=g->next) { | ||
259 | if (IS_SPACE(g)) { | ||
260 | ((dxSpace*)g)->cleanGeoms(); | ||
261 | } | ||
262 | g->recomputeAABB(); | ||
263 | g->gflags &= (~(GEOM_DIRTY|GEOM_AABB_BAD)); | ||
264 | } | ||
265 | lock_count--; | ||
266 | } | ||
267 | |||
268 | |||
269 | void dxSimpleSpace::collide (void *data, dNearCallback *callback) | ||
270 | { | ||
271 | dAASSERT (callback); | ||
272 | |||
273 | lock_count++; | ||
274 | cleanGeoms(); | ||
275 | |||
276 | // intersect all bounding boxes | ||
277 | for (dxGeom *g1=first; g1; g1=g1->next) { | ||
278 | if (GEOM_ENABLED(g1)){ | ||
279 | for (dxGeom *g2=g1->next; g2; g2=g2->next) { | ||
280 | if (GEOM_ENABLED(g2)){ | ||
281 | collideAABBs (g1,g2,data,callback); | ||
282 | } | ||
283 | } | ||
284 | } | ||
285 | } | ||
286 | |||
287 | lock_count--; | ||
288 | } | ||
289 | |||
290 | |||
291 | void dxSimpleSpace::collide2 (void *data, dxGeom *geom, | ||
292 | dNearCallback *callback) | ||
293 | { | ||
294 | dAASSERT (geom && callback); | ||
295 | |||
296 | lock_count++; | ||
297 | cleanGeoms(); | ||
298 | geom->recomputeAABB(); | ||
299 | |||
300 | // intersect bounding boxes | ||
301 | for (dxGeom *g=first; g; g=g->next) { | ||
302 | if (GEOM_ENABLED(g)){ | ||
303 | collideAABBs (g,geom,data,callback); | ||
304 | } | ||
305 | } | ||
306 | |||
307 | lock_count--; | ||
308 | } | ||
309 | |||
310 | //**************************************************************************** | ||
311 | // utility stuff for hash table space | ||
312 | |||
313 | // kind of silly, but oh well... | ||
314 | #ifndef MAXINT | ||
315 | #define MAXINT ((int)((((unsigned int)(-1)) << 1) >> 1)) | ||
316 | #endif | ||
317 | |||
318 | |||
319 | // prime[i] is the largest prime smaller than 2^i | ||
320 | #define NUM_PRIMES 31 | ||
321 | static long int prime[NUM_PRIMES] = {1L,2L,3L,7L,13L,31L,61L,127L,251L,509L, | ||
322 | 1021L,2039L,4093L,8191L,16381L,32749L,65521L,131071L,262139L, | ||
323 | 524287L,1048573L,2097143L,4194301L,8388593L,16777213L,33554393L, | ||
324 | 67108859L,134217689L,268435399L,536870909L,1073741789L}; | ||
325 | |||
326 | |||
327 | // an axis aligned bounding box in the hash table | ||
328 | struct dxAABB { | ||
329 | dxAABB *next; // next in the list of all AABBs | ||
330 | int level; // the level this is stored in (cell size = 2^level) | ||
331 | int dbounds[6]; // AABB bounds, discretized to cell size | ||
332 | dxGeom *geom; // corresponding geometry object (AABB stored here) | ||
333 | int index; // index of this AABB, starting from 0 | ||
334 | }; | ||
335 | |||
336 | |||
337 | // a hash table node that represents an AABB that intersects a particular cell | ||
338 | // at a particular level | ||
339 | struct Node { | ||
340 | Node *next; // next node in hash table collision list, 0 if none | ||
341 | int x,y,z; // cell position in space, discretized to cell size | ||
342 | dxAABB *aabb; // axis aligned bounding box that intersects this cell | ||
343 | }; | ||
344 | |||
345 | |||
346 | // return the `level' of an AABB. the AABB will be put into cells at this | ||
347 | // level - the cell size will be 2^level. the level is chosen to be the | ||
348 | // smallest value such that the AABB occupies no more than 8 cells, regardless | ||
349 | // of its placement. this means that: | ||
350 | // size/2 < q <= size | ||
351 | // where q is the maximum AABB dimension. | ||
352 | |||
353 | static int findLevel (dReal bounds[6]) | ||
354 | { | ||
355 | if (bounds[0] <= -dInfinity || bounds[1] >= dInfinity || | ||
356 | bounds[2] <= -dInfinity || bounds[3] >= dInfinity || | ||
357 | bounds[4] <= -dInfinity || bounds[5] >= dInfinity) { | ||
358 | return MAXINT; | ||
359 | } | ||
360 | |||
361 | // compute q | ||
362 | dReal q,q2; | ||
363 | q = bounds[1] - bounds[0]; // x bounds | ||
364 | q2 = bounds[3] - bounds[2]; // y bounds | ||
365 | if (q2 > q) q = q2; | ||
366 | q2 = bounds[5] - bounds[4]; // z bounds | ||
367 | if (q2 > q) q = q2; | ||
368 | |||
369 | // find level such that 0.5 * 2^level < q <= 2^level | ||
370 | int level; | ||
371 | frexp (q,&level); // q = (0.5 .. 1.0) * 2^level (definition of frexp) | ||
372 | return level; | ||
373 | } | ||
374 | |||
375 | |||
376 | // find a virtual memory address for a cell at the given level and x,y,z | ||
377 | // position. | ||
378 | // @@@ currently this is not very sophisticated, e.g. the scaling | ||
379 | // factors could be better designed to avoid collisions, and they should | ||
380 | // probably depend on the hash table physical size. | ||
381 | |||
382 | static unsigned long getVirtualAddress (int level, int x, int y, int z) | ||
383 | { | ||
384 | return level*1000 + x*100 + y*10 + z; | ||
385 | } | ||
386 | |||
387 | //**************************************************************************** | ||
388 | // hash space | ||
389 | |||
390 | struct dxHashSpace : public dxSpace { | ||
391 | int global_minlevel; // smallest hash table level to put AABBs in | ||
392 | int global_maxlevel; // objects that need a level larger than this will be | ||
393 | // put in a "big objects" list instead of a hash table | ||
394 | |||
395 | dxHashSpace (dSpaceID _space); | ||
396 | void setLevels (int minlevel, int maxlevel); | ||
397 | void getLevels (int *minlevel, int *maxlevel); | ||
398 | void cleanGeoms(); | ||
399 | void collide (void *data, dNearCallback *callback); | ||
400 | void collide2 (void *data, dxGeom *geom, dNearCallback *callback); | ||
401 | }; | ||
402 | |||
403 | |||
404 | dxHashSpace::dxHashSpace (dSpaceID _space) : dxSpace (_space) | ||
405 | { | ||
406 | type = dHashSpaceClass; | ||
407 | global_minlevel = -3; | ||
408 | global_maxlevel = 10; | ||
409 | } | ||
410 | |||
411 | |||
412 | void dxHashSpace::setLevels (int minlevel, int maxlevel) | ||
413 | { | ||
414 | dAASSERT (minlevel <= maxlevel); | ||
415 | global_minlevel = minlevel; | ||
416 | global_maxlevel = maxlevel; | ||
417 | } | ||
418 | |||
419 | |||
420 | void dxHashSpace::getLevels (int *minlevel, int *maxlevel) | ||
421 | { | ||
422 | if (minlevel) *minlevel = global_minlevel; | ||
423 | if (maxlevel) *maxlevel = global_maxlevel; | ||
424 | } | ||
425 | |||
426 | |||
427 | void dxHashSpace::cleanGeoms() | ||
428 | { | ||
429 | // compute the AABBs of all dirty geoms, and clear the dirty flags | ||
430 | lock_count++; | ||
431 | for (dxGeom *g=first; g && (g->gflags & GEOM_DIRTY); g=g->next) { | ||
432 | if (IS_SPACE(g)) { | ||
433 | ((dxSpace*)g)->cleanGeoms(); | ||
434 | } | ||
435 | g->recomputeAABB(); | ||
436 | g->gflags &= (~(GEOM_DIRTY|GEOM_AABB_BAD)); | ||
437 | } | ||
438 | lock_count--; | ||
439 | } | ||
440 | |||
441 | |||
442 | void dxHashSpace::collide (void *data, dNearCallback *callback) | ||
443 | { | ||
444 | dAASSERT(this && callback); | ||
445 | dxGeom *geom; | ||
446 | dxAABB *aabb; | ||
447 | int i,maxlevel; | ||
448 | |||
449 | // 0 or 1 geoms can't collide with anything | ||
450 | if (count < 2) return; | ||
451 | |||
452 | lock_count++; | ||
453 | cleanGeoms(); | ||
454 | |||
455 | // create a list of auxiliary information for all geom axis aligned bounding | ||
456 | // boxes. set the level for all AABBs. put AABBs larger than the space's | ||
457 | // global_maxlevel in the big_boxes list, check everything else against | ||
458 | // that list at the end. for AABBs that are not too big, record the maximum | ||
459 | // level that we need. | ||
460 | |||
461 | int n = 0; // number of AABBs in main list | ||
462 | dxAABB *first_aabb = 0; // list of AABBs in hash table | ||
463 | dxAABB *big_boxes = 0; // list of AABBs too big for hash table | ||
464 | maxlevel = global_minlevel - 1; | ||
465 | for (geom = first; geom; geom=geom->next) { | ||
466 | if (!GEOM_ENABLED(geom)){ | ||
467 | continue; | ||
468 | } | ||
469 | dxAABB *aabb = (dxAABB*) ALLOCA (sizeof(dxAABB)); | ||
470 | aabb->geom = geom; | ||
471 | // compute level, but prevent cells from getting too small | ||
472 | int level = findLevel (geom->aabb); | ||
473 | if (level < global_minlevel) level = global_minlevel; | ||
474 | if (level <= global_maxlevel) { | ||
475 | // aabb goes in main list | ||
476 | aabb->next = first_aabb; | ||
477 | first_aabb = aabb; | ||
478 | aabb->level = level; | ||
479 | if (level > maxlevel) maxlevel = level; | ||
480 | // cellsize = 2^level | ||
481 | dReal cellsize = (dReal) ldexp (1.0,level); | ||
482 | // discretize AABB position to cell size | ||
483 | for (i=0; i < 6; i++) aabb->dbounds[i] = (int) | ||
484 | floor (geom->aabb[i]/cellsize); | ||
485 | // set AABB index | ||
486 | aabb->index = n; | ||
487 | n++; | ||
488 | } | ||
489 | else { | ||
490 | // aabb is too big, put it in the big_boxes list. we don't care about | ||
491 | // setting level, dbounds, index, or the maxlevel | ||
492 | aabb->next = big_boxes; | ||
493 | big_boxes = aabb; | ||
494 | } | ||
495 | } | ||
496 | |||
497 | // for `n' objects, an n*n array of bits is used to record if those objects | ||
498 | // have been intersection-tested against each other yet. this array can | ||
499 | // grow large with high n, but oh well... | ||
500 | int tested_rowsize = (n+7) >> 3; // number of bytes needed for n bits | ||
501 | unsigned char *tested = (unsigned char *) ALLOCA (n * tested_rowsize); | ||
502 | memset (tested,0,n * tested_rowsize); | ||
503 | |||
504 | // create a hash table to store all AABBs. each AABB may take up to 8 cells. | ||
505 | // we use chaining to resolve collisions, but we use a relatively large table | ||
506 | // to reduce the chance of collisions. | ||
507 | |||
508 | // compute hash table size sz to be a prime > 8*n | ||
509 | for (i=0; i<NUM_PRIMES; i++) { | ||
510 | if (prime[i] >= (8*n)) break; | ||
511 | } | ||
512 | if (i >= NUM_PRIMES) i = NUM_PRIMES-1; // probably pointless | ||
513 | int sz = prime[i]; | ||
514 | |||
515 | // allocate and initialize hash table node pointers | ||
516 | Node **table = (Node **) ALLOCA (sizeof(Node*) * sz); | ||
517 | for (i=0; i<sz; i++) table[i] = 0; | ||
518 | |||
519 | // add each AABB to the hash table (may need to add it to up to 8 cells) | ||
520 | for (aabb=first_aabb; aabb; aabb=aabb->next) { | ||
521 | int *dbounds = aabb->dbounds; | ||
522 | for (int xi = dbounds[0]; xi <= dbounds[1]; xi++) { | ||
523 | for (int yi = dbounds[2]; yi <= dbounds[3]; yi++) { | ||
524 | for (int zi = dbounds[4]; zi <= dbounds[5]; zi++) { | ||
525 | // get the hash index | ||
526 | unsigned long hi = getVirtualAddress (aabb->level,xi,yi,zi) % sz; | ||
527 | // add a new node to the hash table | ||
528 | Node *node = (Node*) ALLOCA (sizeof (Node)); | ||
529 | node->x = xi; | ||
530 | node->y = yi; | ||
531 | node->z = zi; | ||
532 | node->aabb = aabb; | ||
533 | node->next = table[hi]; | ||
534 | table[hi] = node; | ||
535 | } | ||
536 | } | ||
537 | } | ||
538 | } | ||
539 | |||
540 | // now that all AABBs are loaded into the hash table, we do the actual | ||
541 | // collision detection. for all AABBs, check for other AABBs in the | ||
542 | // same cells for collisions, and then check for other AABBs in all | ||
543 | // intersecting higher level cells. | ||
544 | |||
545 | int db[6]; // discrete bounds at current level | ||
546 | for (aabb=first_aabb; aabb; aabb=aabb->next) { | ||
547 | // we are searching for collisions with aabb | ||
548 | for (i=0; i<6; i++) db[i] = aabb->dbounds[i]; | ||
549 | for (int level = aabb->level; level <= maxlevel; level++) { | ||
550 | for (int xi = db[0]; xi <= db[1]; xi++) { | ||
551 | for (int yi = db[2]; yi <= db[3]; yi++) { | ||
552 | for (int zi = db[4]; zi <= db[5]; zi++) { | ||
553 | // get the hash index | ||
554 | unsigned long hi = getVirtualAddress (level,xi,yi,zi) % sz; | ||
555 | // search all nodes at this index | ||
556 | Node *node; | ||
557 | for (node = table[hi]; node; node=node->next) { | ||
558 | // node points to an AABB that may intersect aabb | ||
559 | if (node->aabb == aabb) continue; | ||
560 | if (node->aabb->level == level && | ||
561 | node->x == xi && node->y == yi && node->z == zi) { | ||
562 | // see if aabb and node->aabb have already been tested | ||
563 | // against each other | ||
564 | unsigned char mask; | ||
565 | if (aabb->index <= node->aabb->index) { | ||
566 | i = (aabb->index * tested_rowsize)+(node->aabb->index >> 3); | ||
567 | mask = 1 << (node->aabb->index & 7); | ||
568 | } | ||
569 | else { | ||
570 | i = (node->aabb->index * tested_rowsize)+(aabb->index >> 3); | ||
571 | mask = 1 << (aabb->index & 7); | ||
572 | } | ||
573 | dIASSERT (i >= 0 && i < (tested_rowsize*n)); | ||
574 | if ((tested[i] & mask)==0) { | ||
575 | collideAABBs (aabb->geom,node->aabb->geom,data,callback); | ||
576 | } | ||
577 | tested[i] |= mask; | ||
578 | } | ||
579 | } | ||
580 | } | ||
581 | } | ||
582 | } | ||
583 | // get the discrete bounds for the next level up | ||
584 | for (i=0; i<6; i++) db[i] >>= 1; | ||
585 | } | ||
586 | } | ||
587 | |||
588 | // every AABB in the normal list must now be intersected against every | ||
589 | // AABB in the big_boxes list. so let's hope there are not too many objects | ||
590 | // in the big_boxes list. | ||
591 | for (aabb=first_aabb; aabb; aabb=aabb->next) { | ||
592 | for (dxAABB *aabb2=big_boxes; aabb2; aabb2=aabb2->next) { | ||
593 | collideAABBs (aabb->geom,aabb2->geom,data,callback); | ||
594 | } | ||
595 | } | ||
596 | |||
597 | // intersected all AABBs in the big_boxes list together | ||
598 | for (aabb=big_boxes; aabb; aabb=aabb->next) { | ||
599 | for (dxAABB *aabb2=aabb->next; aabb2; aabb2=aabb2->next) { | ||
600 | collideAABBs (aabb->geom,aabb2->geom,data,callback); | ||
601 | } | ||
602 | } | ||
603 | |||
604 | lock_count--; | ||
605 | } | ||
606 | |||
607 | |||
608 | void dxHashSpace::collide2 (void *data, dxGeom *geom, | ||
609 | dNearCallback *callback) | ||
610 | { | ||
611 | dAASSERT (geom && callback); | ||
612 | |||
613 | // this could take advantage of the hash structure to avoid | ||
614 | // O(n2) complexity, but it does not yet. | ||
615 | |||
616 | lock_count++; | ||
617 | cleanGeoms(); | ||
618 | geom->recomputeAABB(); | ||
619 | |||
620 | // intersect bounding boxes | ||
621 | for (dxGeom *g=first; g; g=g->next) { | ||
622 | if (GEOM_ENABLED(g)) collideAABBs (g,geom,data,callback); | ||
623 | } | ||
624 | |||
625 | lock_count--; | ||
626 | } | ||
627 | |||
628 | //**************************************************************************** | ||
629 | // space functions | ||
630 | |||
631 | dxSpace *dSimpleSpaceCreate (dxSpace *space) | ||
632 | { | ||
633 | return new dxSimpleSpace (space); | ||
634 | } | ||
635 | |||
636 | |||
637 | dxSpace *dHashSpaceCreate (dxSpace *space) | ||
638 | { | ||
639 | return new dxHashSpace (space); | ||
640 | } | ||
641 | |||
642 | |||
643 | void dHashSpaceSetLevels (dxSpace *space, int minlevel, int maxlevel) | ||
644 | { | ||
645 | dAASSERT (space); | ||
646 | dUASSERT (minlevel <= maxlevel,"must have minlevel <= maxlevel"); | ||
647 | dUASSERT (space->type == dHashSpaceClass,"argument must be a hash space"); | ||
648 | dxHashSpace *hspace = (dxHashSpace*) space; | ||
649 | hspace->setLevels (minlevel,maxlevel); | ||
650 | } | ||
651 | |||
652 | |||
653 | void dHashSpaceGetLevels (dxSpace *space, int *minlevel, int *maxlevel) | ||
654 | { | ||
655 | dAASSERT (space); | ||
656 | dUASSERT (space->type == dHashSpaceClass,"argument must be a hash space"); | ||
657 | dxHashSpace *hspace = (dxHashSpace*) space; | ||
658 | hspace->getLevels (minlevel,maxlevel); | ||
659 | } | ||
660 | |||
661 | |||
662 | void dSpaceDestroy (dxSpace *space) | ||
663 | { | ||
664 | dAASSERT (space); | ||
665 | dUASSERT (dGeomIsSpace(space),"argument not a space"); | ||
666 | dGeomDestroy (space); | ||
667 | } | ||
668 | |||
669 | |||
670 | void dSpaceSetCleanup (dxSpace *space, int mode) | ||
671 | { | ||
672 | dAASSERT (space); | ||
673 | dUASSERT (dGeomIsSpace(space),"argument not a space"); | ||
674 | space->setCleanup (mode); | ||
675 | } | ||
676 | |||
677 | |||
678 | int dSpaceGetCleanup (dxSpace *space) | ||
679 | { | ||
680 | dAASSERT (space); | ||
681 | dUASSERT (dGeomIsSpace(space),"argument not a space"); | ||
682 | return space->getCleanup(); | ||
683 | } | ||
684 | |||
685 | |||
686 | void dSpaceAdd (dxSpace *space, dxGeom *g) | ||
687 | { | ||
688 | dAASSERT (space); | ||
689 | dUASSERT (dGeomIsSpace(space),"argument not a space"); | ||
690 | CHECK_NOT_LOCKED (space); | ||
691 | space->add (g); | ||
692 | } | ||
693 | |||
694 | |||
695 | void dSpaceRemove (dxSpace *space, dxGeom *g) | ||
696 | { | ||
697 | dAASSERT (space); | ||
698 | dUASSERT (dGeomIsSpace(space),"argument not a space"); | ||
699 | CHECK_NOT_LOCKED (space); | ||
700 | space->remove (g); | ||
701 | } | ||
702 | |||
703 | |||
704 | int dSpaceQuery (dxSpace *space, dxGeom *g) | ||
705 | { | ||
706 | dAASSERT (space); | ||
707 | dUASSERT (dGeomIsSpace(space),"argument not a space"); | ||
708 | return space->query (g); | ||
709 | } | ||
710 | |||
711 | void dSpaceClean (dxSpace *space){ | ||
712 | dAASSERT (space); | ||
713 | dUASSERT (dGeomIsSpace(space),"argument not a space"); | ||
714 | |||
715 | space->cleanGeoms(); | ||
716 | } | ||
717 | |||
718 | int dSpaceGetNumGeoms (dxSpace *space) | ||
719 | { | ||
720 | dAASSERT (space); | ||
721 | dUASSERT (dGeomIsSpace(space),"argument not a space"); | ||
722 | return space->getNumGeoms(); | ||
723 | } | ||
724 | |||
725 | |||
726 | dGeomID dSpaceGetGeom (dxSpace *space, int i) | ||
727 | { | ||
728 | dAASSERT (space); | ||
729 | dUASSERT (dGeomIsSpace(space),"argument not a space"); | ||
730 | return space->getGeom (i); | ||
731 | } | ||
732 | |||
733 | |||
734 | void dSpaceCollide (dxSpace *space, void *data, dNearCallback *callback) | ||
735 | { | ||
736 | dAASSERT (space && callback); | ||
737 | dUASSERT (dGeomIsSpace(space),"argument not a space"); | ||
738 | space->collide (data,callback); | ||
739 | } | ||
740 | |||
741 | |||
742 | void dSpaceCollide2 (dxGeom *g1, dxGeom *g2, void *data, | ||
743 | dNearCallback *callback) | ||
744 | { | ||
745 | dAASSERT (g1 && g2 && callback); | ||
746 | dxSpace *s1,*s2; | ||
747 | |||
748 | // see if either geom is a space | ||
749 | if (IS_SPACE(g1)) s1 = (dxSpace*) g1; else s1 = 0; | ||
750 | if (IS_SPACE(g2)) s2 = (dxSpace*) g2; else s2 = 0; | ||
751 | |||
752 | // handle the four space/geom cases | ||
753 | if (s1) { | ||
754 | if (s2) { | ||
755 | // g1 and g2 are spaces. | ||
756 | if (s1==s2) { | ||
757 | // collide a space with itself --> interior collision | ||
758 | s1->collide (data,callback); | ||
759 | } | ||
760 | else { | ||
761 | // iterate through the space that has the fewest geoms, calling | ||
762 | // collide2 in the other space for each one. | ||
763 | if (s1->count < s2->count) { | ||
764 | for (dxGeom *g = s1->first; g; g=g->next) { | ||
765 | s2->collide2 (data,g,callback); | ||
766 | } | ||
767 | } | ||
768 | else { | ||
769 | for (dxGeom *g = s2->first; g; g=g->next) { | ||
770 | s1->collide2 (data,g,callback); | ||
771 | } | ||
772 | } | ||
773 | } | ||
774 | } | ||
775 | else { | ||
776 | // g1 is a space, g2 is a geom | ||
777 | s1->collide2 (data,g2,callback); | ||
778 | } | ||
779 | } | ||
780 | else { | ||
781 | if (s2) { | ||
782 | // g1 is a geom, g2 is a space | ||
783 | s2->collide2 (data,g1,callback); | ||
784 | } | ||
785 | else { | ||
786 | // g1 and g2 are geoms, call the callback directly | ||
787 | callback (data,g1,g2); | ||
788 | } | ||
789 | } | ||
790 | } | ||