Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ode/ode-0.9/ode/src/collision_quadtreespace.cpp @ 216

Last change on this file since 216 was 216, checked in by mathiask, 16 years ago

[Physik] add ode-0.9

File size: 14.1 KB
Line 
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// QuadTreeSpace by Erwin de Vries.
24
25#include <ode/common.h>
26#include <ode/matrix.h>
27#include <ode/collision_space.h>
28#include <ode/collision.h>
29#include "collision_kernel.h"
30
31#include "collision_space_internal.h"
32
33
34#define AXIS0 0
35#define AXIS1 1
36#define UP 2
37
38//#define DRAWBLOCKS
39
40const int SPLITAXIS = 2;
41const int SPLITS = SPLITAXIS * SPLITAXIS;
42
43#define GEOM_ENABLED(g) (g)->gflags & GEOM_ENABLED
44
45class Block{
46public:
47        dReal MinX, MaxX;
48        dReal MinZ, MaxZ;
49
50        dGeomID First;
51        int GeomCount;
52
53        Block* Parent;
54        Block* Children;
55
56        void Create(const dVector3 Center, const dVector3 Extents, Block* Parent, int Depth, Block*& Blocks);
57
58        void Collide(void* UserData, dNearCallback* Callback);
59        void Collide(dGeomID Object, dGeomID g, void* UserData, dNearCallback* Callback);
60
61        void CollideLocal(dGeomID Object, void* UserData, dNearCallback* Callback);
62       
63        void AddObject(dGeomID Object);
64        void DelObject(dGeomID Object);
65        void Traverse(dGeomID Object);
66
67        bool Inside(const dReal* AABB);
68       
69        Block* GetBlock(const dReal* AABB);
70        Block* GetBlockChild(const dReal* AABB);
71};
72
73
74#ifdef DRAWBLOCKS
75#include "..\..\Include\drawstuff\\drawstuff.h"
76
77static void DrawBlock(Block* Block){
78        dVector3 v[8];
79        v[0][AXIS0] = Block->MinX;
80        v[0][UP] = REAL(-1.0);
81        v[0][AXIS1] = Block->MinZ;
82       
83        v[1][AXIS0] = Block->MinX;
84        v[1][UP] = REAL(-1.0);
85        v[1][AXIS1] = Block->MaxZ;
86       
87        v[2][AXIS0] = Block->MaxX;
88        v[2][UP] = REAL(-1.0);
89        v[2][AXIS1] = Block->MinZ;
90       
91        v[3][AXIS0] = Block->MaxX;
92        v[3][UP] = REAL(-1.0);
93        v[3][AXIS1] = Block->MaxZ;
94       
95        v[4][AXIS0] = Block->MinX;
96        v[4][UP] = REAL(1.0);
97        v[4][AXIS1] = Block->MinZ;
98       
99        v[5][AXIS0] = Block->MinX;
100        v[5][UP] = REAL(1.0);
101        v[5][AXIS1] = Block->MaxZ;
102       
103        v[6][AXIS0] = Block->MaxX;
104        v[6][UP] = REAL(1.0);
105        v[6][AXIS1] = Block->MinZ;
106       
107        v[7][AXIS0] = Block->MaxX;
108        v[7][UP] = REAL(1.0);
109        v[7][AXIS1] = Block->MaxZ;
110       
111        // Bottom
112        dsDrawLine(v[0], v[1]);
113        dsDrawLine(v[1], v[3]);
114        dsDrawLine(v[3], v[2]);
115        dsDrawLine(v[2], v[0]);
116       
117        // Top
118        dsDrawLine(v[4], v[5]);
119        dsDrawLine(v[5], v[7]);
120        dsDrawLine(v[7], v[6]);
121        dsDrawLine(v[6], v[4]);
122       
123        // Sides
124        dsDrawLine(v[0], v[4]);
125        dsDrawLine(v[1], v[5]);
126        dsDrawLine(v[2], v[6]);
127        dsDrawLine(v[3], v[7]);
128}
129#endif  //DRAWBLOCKS
130
131
132void Block::Create(const dVector3 Center, const dVector3 Extents, Block* Parent, int Depth, Block*& Blocks){
133        GeomCount = 0;
134        First = 0;
135
136        MinX = Center[AXIS0] - Extents[AXIS0];
137        MaxX = Center[AXIS0] + Extents[AXIS0];
138
139        MinZ = Center[AXIS1] - Extents[AXIS1];
140        MaxZ = Center[AXIS1] + Extents[AXIS1];
141
142        this->Parent = Parent;
143        if (Depth > 0){
144                Children = Blocks;
145                Blocks += SPLITS;
146
147                dVector3 ChildExtents;
148                ChildExtents[AXIS0] = Extents[AXIS0] / SPLITAXIS;
149                ChildExtents[AXIS1] = Extents[AXIS1] / SPLITAXIS;
150                ChildExtents[UP] = Extents[UP];
151
152                for (int i = 0; i < SPLITAXIS; i++){
153                        for (int j = 0; j < SPLITAXIS; j++){
154                                int Index = i * SPLITAXIS + j;
155
156                                dVector3 ChildCenter;
157                                ChildCenter[AXIS0] = Center[AXIS0] - Extents[AXIS0] + ChildExtents[AXIS0] + i * (ChildExtents[AXIS0] * 2);
158                                ChildCenter[AXIS1] = Center[AXIS1] - Extents[AXIS1] + ChildExtents[AXIS1] + j * (ChildExtents[AXIS1] * 2);
159                                ChildCenter[UP] = Center[UP];
160                               
161                                Children[Index].Create(ChildCenter, ChildExtents, this, Depth - 1, Blocks);
162                        }
163                }
164        }
165        else Children = 0;
166}
167
168void Block::Collide(void* UserData, dNearCallback* Callback){
169#ifdef DRAWBLOCKS
170        DrawBlock(this);
171#endif
172        // Collide the local list
173        dxGeom* g = First;
174        while (g){
175                if (GEOM_ENABLED(g)){
176                        Collide(g, g->next, UserData, Callback);
177                }
178                g = g->next;
179        }
180
181        // Recurse for children
182        if (Children){
183                for (int i = 0; i < SPLITS; i++){
184                        if (Children[i].GeomCount <= 1){        // Early out
185                                continue;
186                        }
187                        Children[i].Collide(UserData, Callback);
188                }
189        }
190}
191
192void Block::Collide(dxGeom* g1, dxGeom* g2, void* UserData, dNearCallback* Callback){
193#ifdef DRAWBLOCKS
194        DrawBlock(this);
195#endif
196        // Collide against local list
197        while (g2){
198                if (GEOM_ENABLED(g2)){
199                        collideAABBs (g1, g2, UserData, Callback);
200                }
201                g2 = g2->next;
202        }
203
204        // Collide against children
205        if (Children){
206                for (int i = 0; i < SPLITS; i++){
207                        // Early out for empty blocks
208                        if (Children[i].GeomCount == 0){
209                                continue;
210                        }
211
212                        // Does the geom's AABB collide with the block?
213                        // Dont do AABB tests for single geom blocks.
214                        if (Children[i].GeomCount == 1 && Children[i].First){
215                                //
216                        }
217                        else if (true){
218                                if (g1->aabb[AXIS0 * 2 + 0] > Children[i].MaxX ||
219                                        g1->aabb[AXIS0 * 2 + 1] < Children[i].MinX ||
220                                        g1->aabb[AXIS1 * 2 + 0] > Children[i].MaxZ ||
221                                        g1->aabb[AXIS1 * 2 + 1] < Children[i].MinZ) continue;
222                        }
223                        Children[i].Collide(g1, Children[i].First, UserData, Callback);
224                }
225        }
226}
227
228void Block::CollideLocal(dxGeom* g1, void* UserData, dNearCallback* Callback){
229        // Collide against local list
230        dxGeom* g2 = First;
231        while (g2){
232                if (GEOM_ENABLED(g2)){
233                        collideAABBs (g1, g2, UserData, Callback);
234                }
235                g2 = g2->next;
236        }
237}
238
239void Block::AddObject(dGeomID Object){
240        // Add the geom
241        Object->next = First;
242        First = Object;
243        Object->tome = (dxGeom**)this;
244
245        // Now traverse upwards to tell that we have a geom
246        Block* Block = this;
247        do{
248                Block->GeomCount++;
249                Block = Block->Parent;
250        }
251        while (Block);
252}
253
254void Block::DelObject(dGeomID Object){
255        // Del the geom
256        dxGeom* g = First;
257        dxGeom* Last = 0;
258        while (g){
259                if (g == Object){
260                        if (Last){
261                                Last->next = g->next;
262                        }
263                        else First = g->next;
264
265                        break;
266                }
267                Last = g;
268                g = g->next;
269        }
270
271        Object->tome = 0;
272
273        // Now traverse upwards to tell that we have lost a geom
274        Block* Block = this;
275        do{
276                Block->GeomCount--;
277                Block = Block->Parent;
278        }
279        while (Block);
280}
281
282void Block::Traverse(dGeomID Object){
283        Block* NewBlock = GetBlock(Object->aabb);
284
285        if (NewBlock != this){
286                // Remove the geom from the old block and add it to the new block.
287                // This could be more optimal, but the loss should be very small.
288                DelObject(Object);
289                NewBlock->AddObject(Object);
290        }
291}
292
293bool Block::Inside(const dReal* AABB){
294        return AABB[AXIS0 * 2 + 0] >= MinX && AABB[AXIS0 * 2 + 1] <= MaxX && AABB[AXIS1 * 2 + 0] >= MinZ && AABB[AXIS1 * 2 + 1] <= MaxZ;
295}
296
297Block* Block::GetBlock(const dReal* AABB){
298        if (Inside(AABB)){
299                return GetBlockChild(AABB);     // Child or this will have a good block
300        }
301        else if (Parent){
302                return Parent->GetBlock(AABB);  // Parent has a good block
303        }
304        else return this;       // We are at the root, so we have little choice
305}
306
307Block* Block::GetBlockChild(const dReal* AABB){
308        if (Children){
309                for (int i = 0; i < SPLITS; i++){
310                        if (Children[i].Inside(AABB)){
311                                return Children[i].GetBlockChild(AABB); // Child will have good block
312                        }
313                }
314        }
315        return this;    // This is the best block
316}
317
318//****************************************************************************
319// quadtree space
320
321struct dxQuadTreeSpace : public dxSpace{
322        Block* Blocks;  // Blocks[0] is the root
323
324        dArray<dxGeom*> DirtyList;
325
326        dxQuadTreeSpace(dSpaceID _space, dVector3 Center, dVector3 Extents, int Depth);
327        ~dxQuadTreeSpace();
328
329        dxGeom* getGeom(int i);
330       
331        void add(dxGeom* g);
332        void remove(dxGeom* g);
333        void dirty(dxGeom* g);
334
335        void computeAABB();
336       
337        void cleanGeoms();
338        void collide(void* UserData, dNearCallback* Callback);
339        void collide2(void* UserData, dxGeom* g1, dNearCallback* Callback);
340
341        // Temp data
342        Block* CurrentBlock;    // Only used while enumerating
343        int* CurrentChild;      // Only used while enumerating
344        int CurrentLevel;       // Only used while enumerating
345        dxGeom* CurrentObject;  // Only used while enumerating
346        int CurrentIndex;
347};
348
349dxQuadTreeSpace::dxQuadTreeSpace(dSpaceID _space, dVector3 Center, dVector3 Extents, int Depth) : dxSpace(_space){
350        type = dQuadTreeSpaceClass;
351
352        int BlockCount = 0;
353        for (int i = 0; i <= Depth; i++){
354                BlockCount += (int)pow((dReal)SPLITS, i);
355        }
356
357        Blocks = (Block*)dAlloc(BlockCount * sizeof(Block));
358        Block* Blocks = this->Blocks + 1;       // This pointer gets modified!
359
360        this->Blocks[0].Create(Center, Extents, 0, Depth, Blocks);
361
362        CurrentBlock = 0;
363        CurrentChild = (int*)dAlloc((Depth + 1) * sizeof(int));
364        CurrentLevel = 0;
365        CurrentObject = 0;
366        CurrentIndex = -1;
367
368        // Init AABB. We initialize to infinity because it is not illegal for an object to be outside of the tree. Its simply inserted in the root block
369        aabb[0] = -dInfinity;
370        aabb[1] = dInfinity;
371        aabb[2] = -dInfinity;
372        aabb[3] = dInfinity;
373        aabb[4] = -dInfinity;
374        aabb[5] = dInfinity;
375}
376
377dxQuadTreeSpace::~dxQuadTreeSpace(){
378        int Depth = 0;
379        Block* Current = &Blocks[0];
380        while (Current){
381                Depth++;
382                Current = Current->Children;
383        }
384
385        int BlockCount = 0;
386        for (int i = 0; i < Depth; i++){
387                BlockCount += (int)pow((dReal)SPLITS, i);
388        }
389
390        dFree(Blocks, BlockCount * sizeof(Block));
391        dFree(CurrentChild, (Depth + 1) * sizeof(int));
392}
393
394dxGeom* dxQuadTreeSpace::getGeom(int Index){
395        dUASSERT(Index >= 0 && Index < count, "index out of range");
396
397        //@@@
398        dDebug (0,"dxQuadTreeSpace::getGeom() not yet implemented");
399
400        return 0;
401
402        // This doesnt work
403
404        /*if (CurrentIndex == Index){
405                // Loop through all objects in the local list
406CHILDRECURSE:
407                if (CurrentObject){
408                        dGeomID g = CurrentObject;
409                        CurrentObject = CurrentObject->next;
410                        CurrentIndex++;
411               
412#ifdef DRAWBLOCKS
413                        DrawBlock(CurrentBlock);
414#endif  //DRAWBLOCKS
415                        return g;
416                }
417                else{
418                        // Now lets loop through our children. Starting at index 0.
419                        if (CurrentBlock->Children){
420                                CurrentChild[CurrentLevel] = 0;
421PARENTRECURSE:
422                                for (int& i = CurrentChild[CurrentLevel]; i < SPLITS; i++){
423                                        if (CurrentBlock->Children[i].GeomCount == 0){
424                                                continue;
425                                        }
426                                        CurrentBlock = &CurrentBlock->Children[i];
427                                        CurrentObject = CurrentBlock->First;
428                               
429                                        i++;
430                               
431                                        CurrentLevel++;
432                                        goto CHILDRECURSE;
433                                }
434                        }
435                }
436               
437                // Now lets go back to the parent so it can continue processing its other children.
438                if (CurrentBlock->Parent){
439                        CurrentBlock = CurrentBlock->Parent;
440                        CurrentLevel--;
441                        goto PARENTRECURSE;
442                }
443        }
444        else{
445                CurrentBlock = &Blocks[0];
446                CurrentLevel = 0;
447                CurrentObject = CurrentObject;
448                CurrentIndex = 0;
449
450                // Other states are already set
451                CurrentObject = CurrentBlock->First;
452        }
453
454
455        if (current_geom && current_index == Index - 1){
456                //current_geom = current_geom->next; // next
457                current_index = Index;
458                return current_geom;
459        }
460        else for (int i = 0; i < Index; i++){   // this will be verrrrrrry slow
461                getGeom(i);
462        }*/
463
464        return 0;
465}
466
467void dxQuadTreeSpace::add(dxGeom* g){
468        CHECK_NOT_LOCKED (this);
469        dAASSERT(g);
470        dUASSERT(g->parent_space == 0 && g->next == 0, "geom is already in a space");
471
472        g->gflags |= GEOM_DIRTY | GEOM_AABB_BAD;
473        DirtyList.push(g);
474
475        // add
476        g->parent_space = this;
477        Blocks[0].GetBlock(g->aabb)->AddObject(g);      // Add to best block
478        count++;
479       
480        // enumerator has been invalidated
481        current_geom = 0;
482       
483        dGeomMoved(this);
484}
485
486void dxQuadTreeSpace::remove(dxGeom* g){
487        CHECK_NOT_LOCKED(this);
488        dAASSERT(g);
489        dUASSERT(g->parent_space == this,"object is not in this space");
490       
491        // remove
492        ((Block*)g->tome)->DelObject(g);
493        count--;
494
495        for (int i = 0; i < DirtyList.size(); i++){
496                if (DirtyList[i] == g){
497                        DirtyList.remove(i);
498                        // (mg) there can be multiple instances of a dirty object on stack  be sure to remove ALL and not just first, for this we decrement i
499                        --i;
500                }
501        }
502       
503        // safeguard
504        g->next = 0;
505        g->tome = 0;
506        g->parent_space = 0;
507       
508        // enumerator has been invalidated
509        current_geom = 0;
510       
511        // the bounding box of this space (and that of all the parents) may have
512        // changed as a consequence of the removal.
513        dGeomMoved(this);
514}
515
516void dxQuadTreeSpace::dirty(dxGeom* g){
517        DirtyList.push(g);
518}
519
520void dxQuadTreeSpace::computeAABB(){
521        //
522}
523
524void dxQuadTreeSpace::cleanGeoms(){
525        // compute the AABBs of all dirty geoms, and clear the dirty flags
526        lock_count++;
527       
528        for (int i = 0; i < DirtyList.size(); i++){
529                dxGeom* g = DirtyList[i];
530                if (IS_SPACE(g)){
531                        ((dxSpace*)g)->cleanGeoms();
532                }
533                g->recomputeAABB();
534                g->gflags &= (~(GEOM_DIRTY|GEOM_AABB_BAD));
535
536                ((Block*)g->tome)->Traverse(g);
537        }
538        DirtyList.setSize(0);
539
540        lock_count--;
541}
542
543void dxQuadTreeSpace::collide(void* UserData, dNearCallback* Callback){
544  dAASSERT(Callback);
545
546  lock_count++;
547  cleanGeoms();
548
549  Blocks[0].Collide(UserData, Callback);
550
551  lock_count--;
552}
553
554void dxQuadTreeSpace::collide2(void* UserData, dxGeom* g1, dNearCallback* Callback){
555  dAASSERT(g1 && Callback);
556
557  lock_count++;
558  cleanGeoms();
559  g1->recomputeAABB();
560
561  if (g1->parent_space == this){
562          // The block the geom is in
563          Block* CurrentBlock = (Block*)g1->tome;
564         
565          // Collide against block and its children
566          CurrentBlock->Collide(g1, CurrentBlock->First, UserData, Callback);
567         
568          // Collide against parents
569          while (true){
570                  CurrentBlock = CurrentBlock->Parent;
571                  if (!CurrentBlock){
572                          break;
573                  }
574                  CurrentBlock->CollideLocal(g1, UserData, Callback);
575          }
576  }
577  else Blocks[0].Collide(g1, Blocks[0].First, UserData, Callback);
578
579  lock_count--;
580}
581
582dSpaceID dQuadTreeSpaceCreate(dxSpace* space, dVector3 Center, dVector3 Extents, int Depth){
583        return new dxQuadTreeSpace(space, Center, Extents, Depth);
584}
Note: See TracBrowser for help on using the repository browser.