Torque3D Documentation / _generateds / quadTreeTracer.cpp

quadTreeTracer.cpp

Engine/source/util/quadTreeTracer.cpp

More...

Public Variables

F32(*
calcInterceptX )(F32, F32, F32)
F32(*
calcInterceptY )(F32, F32, F32)

Public Functions

calcInterceptV(F32 vStart, F32 invDeltaV, F32 intercept)

Detailed Description

Public Variables

F32(* calcInterceptX )(F32, F32, F32)
F32(* calcInterceptY )(F32, F32, F32)

Public Functions

calcInterceptNone(F32 , F32 , F32 )

calcInterceptV(F32 vStart, F32 invDeltaV, F32 intercept)

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "util/quadTreeTracer.h"
 25#include "platform/profiler.h"
 26#include "core/frameAllocator.h"
 27
 28static F32 calcInterceptV(F32 vStart, F32 invDeltaV, F32 intercept)
 29{
 30   return (intercept - vStart) * invDeltaV;
 31}
 32
 33static F32 calcInterceptNone(F32, F32, F32)
 34{
 35   return F32_MAX;
 36}
 37
 38static F32 (*calcInterceptX)(F32, F32, F32);
 39static F32 (*calcInterceptY)(F32, F32, F32);
 40
 41bool QuadTreeTracer::castRay(const Point3F &start, const Point3F &end, RayInfo *info)
 42{
 43   PROFILE_START(QuadTreeTracer_castRay);
 44
 45   // Do some precalculations we'll use for the rest of this routine.
 46   // Set up our intercept calculation methods.
 47   F32 invDeltaX;
 48   if(end.x == start.x)
 49   {
 50      calcInterceptX = calcInterceptNone;
 51      invDeltaX = 0;
 52   }
 53   else
 54   {
 55      invDeltaX = 1.f / (end.x - start.x);
 56      calcInterceptX = calcInterceptV;
 57   }
 58
 59   F32 invDeltaY;
 60   if(end.y == start.y)
 61   {
 62      calcInterceptY = calcInterceptNone;
 63      invDeltaY = 0;
 64   }
 65   else
 66   {
 67      invDeltaY = 1.f / (end.y - start.y);
 68      calcInterceptY = calcInterceptV;
 69   }
 70
 71   // Subdivide our space based on the size of the lowest level of the tree...
 72   const F32 invSize   = 1.f / F32(BIT(mTreeDepth-1));
 73
 74   // Grab this off the frame allocator, we don't want to do a proper alloc
 75   // on every ray!
 76   FrameAllocatorMarker stackAlloc;
 77   RayStackNode *stack = (RayStackNode*)stackAlloc.alloc(sizeof(RayStackNode) * (mTreeDepth * 3 + 1));
 78
 79   U32 stackSize = 1;
 80
 81   // Kick off the stack with the root node.
 82   stack[0].startT   = 0;
 83   stack[0].endT     = 1;
 84   stack[0].squarePos.set(0,0);
 85   stack[0].level    = mTreeDepth - 1;
 86
 87   //Con::printf("QuadTreeTracer::castRay(%x)", this);
 88
 89   // Aright, now let's do some raycasting!
 90   while(stackSize--)
 91   {
 92      // Get the current node for easy access...
 93      RayStackNode *sn = stack + stackSize;
 94
 95      const U32 level         = sn->level;
 96      const F32 startT        = sn->startT;
 97      const F32 endT          = sn->endT;
 98      const Point2I squarePos = sn->squarePos;
 99
100      AssertFatal((startT >= 0.f) && (startT <= 1.f),  "QuadTreeTracer::castRay - out of range startT on stack!");
101      AssertFatal((endT >= 0.f) && (endT <= 1.f),     "QuadTreeTracer::castRay - out of range endT   on stack!");
102
103      //Con::printf(" -- node(%d, %d @ %d), sT=%f, eT=%f", squarePos.x, squarePos.y, level, startT, endT);
104
105      // Figure our start and end Z.
106      const F32 startZ = startT * (end.z - start.z) + start.z;
107      const F32 endZ   = endT   * (end.z - start.z) + start.z;
108
109      // Ok, now let's see if we hit the lower bound
110      const F32 squareMin = getSquareMin(level, squarePos);
111
112      if(startZ < squareMin && endZ < squareMin)
113         continue; //Nope, skip out.
114
115      // Hmm, let's check the upper bound.
116      const F32 squareMax = getSquareMax(level, squarePos);
117
118      if(startZ > squareMax && endZ > squareMax)
119         continue; //Nope, skip out.
120
121      // We might be intersecting something... If we've hit
122      // the tree depth let's deal with the leaf intersection.
123      if(level == 0)
124      {
125         //Con::printf(" ++ check node(%d, %d @ %d), sT=%f, eT=%f", squarePos.x, squarePos.y, level, startT, endT);
126
127         if(castLeafRay(squarePos, start, end, startT, endT, info))
128         {
129            PROFILE_END();
130            return true; // We hit, tell 'em so!
131         }
132         continue; // Otherwise, keep looking.
133      }
134      else
135      {
136         // Ok, we have to push our children as we're an inner node.
137
138         // First, figure out some widths...
139         U32 subSqSize  = BIT(level - 1);
140
141         // Now, calculate intercepts so we know how to deal with this
142         // situation... (intercept = position, int = t value for that pos)
143
144         const F32 xIntercept = (squarePos.x + subSqSize) * invSize;
145         F32 xInt = calcInterceptX(start.x, invDeltaX, xIntercept);
146
147         const F32 yIntercept = (squarePos.y + subSqSize) * invSize;
148         F32 yInt = calcInterceptY(start.y, invDeltaY, yIntercept);
149
150         // Our starting position for this subray...
151         const F32 startX = startT * (end.x - start.x) + start.x;
152         const F32 startY = startT * (end.y - start.y) + start.y;
153
154         // Deal with squares that might be "behind" the ray.
155         if(xInt < startT) xInt = F32_MAX;
156         if(yInt < startT) yInt = F32_MAX;
157
158         // Do a little magic to calculate our next checks...
159         const U32 x0 = (startX > xIntercept) * subSqSize;
160         const U32 y0 = (startY > yIntercept) * subSqSize;
161
162         const U32 x1 = subSqSize - x0;
163         const U32 y1 = subSqSize - y0;
164
165         const U32 nextLevel = level - 1;
166
167         // Ok, now let's figure out what nodes, in what order, need to go
168         // on the stack. We push things on in reverse order of processing.
169         if(xInt > endT && yInt > endT)
170         {
171            stack[stackSize].squarePos.set(squarePos.x + x0, squarePos.y + y0);
172            stack[stackSize].level = nextLevel;
173            stackSize++;
174         }
175         else if(xInt < yInt)
176         {
177            F32 nextIntersect = endT;
178
179            if(yInt <= endT)
180            {
181               stack[stackSize].squarePos.set(squarePos.x + x1, squarePos.y + y1);
182               stack[stackSize].startT = yInt;
183               stack[stackSize].endT   = endT;
184               stack[stackSize].level  = nextLevel;
185               nextIntersect = yInt;
186               stackSize++;
187            }
188
189            // Do middle two, order doesn't matter.
190            stack[stackSize].squarePos.set(squarePos.x + x1, squarePos.y + y0);
191            stack[stackSize].startT = xInt;
192            stack[stackSize].endT   = nextIntersect;
193            stack[stackSize].level  = nextLevel;
194
195            stack[stackSize+1].squarePos.set(squarePos.x + x0, squarePos.y + y0);
196            stack[stackSize+1].startT = startT;
197            stack[stackSize+1].endT   = xInt;
198            stack[stackSize+1].level  = nextLevel;
199            stackSize += 2;
200         }
201         else if(yInt < xInt)
202         {
203            F32 nextIntersect = endT;
204            if(xInt <= endT)
205            {
206               stack[stackSize].squarePos.set(squarePos.x + x1, squarePos.y + y1);
207               stack[stackSize].startT = xInt;
208               stack[stackSize].endT   = endT;
209               stack[stackSize].level  = nextLevel;
210               nextIntersect = xInt;
211               stackSize++;
212            }
213            stack[stackSize].squarePos.set(squarePos.x + x0, squarePos.y + y1);
214            stack[stackSize].startT  = yInt;
215            stack[stackSize].endT    = nextIntersect;
216            stack[stackSize].level   = nextLevel;
217
218            stack[stackSize+1].squarePos.set(squarePos.x + x0, squarePos.y + y0);
219            stack[stackSize+1].startT = startT;
220            stack[stackSize+1].endT   = yInt;
221            stack[stackSize+1].level  = nextLevel;
222            stackSize += 2;
223         }
224         else
225         {
226            stack[stackSize].squarePos.set(squarePos.x + x1, squarePos.y + y1);
227            stack[stackSize].startT = xInt;
228            stack[stackSize].endT   = endT;
229            stack[stackSize].level  = nextLevel;
230
231            stack[stackSize+1].squarePos.set(squarePos.x + x0, squarePos.y + y0);
232            stack[stackSize+1].startT = startT;
233            stack[stackSize+1].endT   = xInt;
234            stack[stackSize+1].level  = nextLevel;
235            stackSize += 2;
236         }
237      }
238   }
239
240   // Nothing found, so give up.
241   PROFILE_END();
242   return false;
243}
244