Angel 3.2
A 2D Game Prototyping Engine
BoundingShapes.cpp
1 
2 // Copyright (C) 2008-2013, Shane Liesegang
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of the copyright holder nor the names of any
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 // POSSIBILITY OF SUCH DAMAGE.
29 
30 #include "stdafx.h"
31 #include "../AI/BoundingShapes.h"
32 
33 #include "../Infrastructure/Common.h"
34 #include "../Util/MathUtil.h"
35 #include "../AI/Ray2.h"
36 
37 
38 BoundingBox::BoundingBox(const Vector2& min, const Vector2& max)
39 : Min(min)
40 , Max(max)
41 {}
42 
43 /*static*/ BoundingBox BoundingBox::CreateMerged(const BoundingBox& original, const BoundingBox& additional)
44 {
45  return BoundingBox(Vector2::Min(original.Min, additional.Min), Vector2::Max(original.Max, additional.Max));
46 
47 }
48 
49 Vector2 BoundingBox::Centroid() const
50 {
51  return Min + (Max-Min)/2.f;
52 }
53 
54 Vector2 BoundingBox::HalfLength() const
55 {
56  return (Max-Min)/2.f;
57 }
58 
59 
60 void BoundingBox::GetCorners(Vector2 corners[]) const
61 {
62  corners[0] = Vector2(Min.X, Min.Y);
63  corners[1] = Vector2(Min.X, Max.Y);
64  corners[2] = Vector2(Max.X, Max.Y);
65  corners[3] = Vector2(Max.X, Min.Y);
66 }
67 
68 /*static*/ BoundingBox BoundingBox::CreateFromPoints(Vector2 points[], int count)
69 {
70  if( count < 1 )
72 
74  for( int i = 0 ; i < count; ++i )
75  {
76  Vector2& compare = points[i];
77  retVal.Min = Vector2::Min( retVal.Min, compare );
78  retVal.Max = Vector2::Max( retVal.Max, compare );
79  }
80  return retVal;
81 }
82 
83 bool BoundingBox::Intersects(const BoundingBox& box) const
84 {
85  if ((Max.X < box.Min.X) || (Min.X > box.Max.X))
86  {
87  return false;
88  }
89  if ((Max.Y < box.Min.Y) || (Min.Y > box.Max.Y))
90  {
91  return false;
92  }
93 
94  return true;
95 }
96 
97 bool BoundingBox::Intersects(const Ray2& ray, float& distanceAlongRay) const
98 {
99  float distNear = MathUtil::MinFloat;
100  float distFar = MathUtil::MaxFloat;
101 
102  distanceAlongRay = 0.f;
103 
104  if (MathUtil::Abs(ray.Direction.X) < MathUtil::Epsilon)
105  {
106  if ((ray.Position.X < Min.X) || (ray.Position.X > Max.X))
107  {
108  return false;
109  }
110  }
111  else
112  {
113  float invMag = 1.f / ray.Direction.X;
114  float minProj = (Min.X - ray.Position.X) * invMag;
115  float maxProj = (Max.X - ray.Position.X) * invMag;
116  if (minProj > maxProj)
117  {
118  float temp = minProj;
119  minProj = maxProj;
120  maxProj = temp;
121  }
122 
123  if (minProj > distNear)
124  {
125  distNear = minProj;
126  }
127 
128  if (maxProj < distFar)
129  {
130  distFar = maxProj;
131  }
132 
133  if (distNear > distFar || distFar < 0.0)
134  {
135  return false; // ray missed
136  }
137  }
138 
139  if (MathUtil::Abs(ray.Direction.Y) < MathUtil::Epsilon)
140  {
141  if ((ray.Position.Y < Min.Y) || (ray.Position.Y > Max.Y))
142  {
143  return false;
144  }
145  }
146  else
147  {
148  float invMag = 1.f / ray.Direction.Y;
149  float minProj = (Min.Y - ray.Position.Y) * invMag;
150  float maxProj = (Max.Y - ray.Position.Y) * invMag;
151  if (minProj > maxProj)
152  {
153  float temp = minProj;
154  minProj = maxProj;
155  maxProj = temp;
156  }
157 
158  if (minProj > distNear)
159  {
160  distNear = minProj;
161  }
162 
163  if (maxProj < distFar)
164  {
165  distFar = maxProj;
166  }
167 
168  if (distNear > distFar || distFar < 0.0)
169  {
170  return false; // ray missed
171  }
172  }
173 
174  if (distNear > 0.0f)
175  {
176  distanceAlongRay = distNear;
177  }
178  else
179  {
180  distanceAlongRay = distFar;
181  }
182 
183  return true;
184 }
185 
186 bool BoundingBox::Intersects(const Vector2& point, float radius) const
187 {
188  int xZone = point.X < ( Min.X ) ? 0 : ( point.X > ( Max.X ) ? 2 : 1 );
189  int yZone = point.Y < ( Min.Y ) ? 0 : ( point.Y > ( Max.Y ) ? 2 : 1 );
190 
191  int zone = xZone + 3*yZone;
192 
193  Vector2 halfLen(HalfLength());
194  Vector2 center(halfLen+Min);
195 
196  bool bIntersects = false;
197  switch ( zone )
198  {
199  // top and bottom side zones
200  // check vertical distance between centers
201  case 1:
202  case 7:
203  {
204  float distY = fabs( point.Y - center.Y );
205  if ( distY <= ( radius + halfLen.Y ) )
206  {
207  bIntersects = true;
208  }
209  }
210  break;
211  // left and right side zones. check distance between centers
212  // check horizontal distance between centers
213  case 3:
214  case 5:
215  {
216  float distX = fabs( point.X - center.X );
217  if ( distX <= ( radius + halfLen.X ) )
218  {
219  bIntersects = true;
220  }
221  }
222  break;
223  // inside zone. collision for sure
224  case 4:
225  bIntersects = true;
226  break;
227  // corner zone.
228  // get the corner and check if inside the circle
229  default:
230  {
231  float cornerX = ( zone == 0 || zone == 6 ) ? Min.X : Max.X;
232  float cornerY = ( zone == 0 || zone == 2 ) ? Min.Y : Max.Y;
233 
234  float distX = cornerX - point.X;
235  float distY = cornerY - point.Y;
236  float squaredist = distX*distX + distY*distY;
237 
238  if (squaredist <= radius* radius )
239  {
240  // corner is inside circle
241  bIntersects = true;
242  }
243  }
244  break;
245  }
246 
247  return bIntersects;
248 }
249 
250 
251 ContainmentType BoundingBox::Contains(const BoundingBox& box) const
252 {
253  if ((Max.X < box.Min.X) || (Min.X > box.Max.X))
254  {
255  return Disjoint;
256  }
257  if ((Max.Y < box.Min.Y) || (Min.Y > box.Max.Y))
258  {
259  return Disjoint;
260  }
261  if ((((Min.X <= box.Min.X) && (box.Max.X <= Max.X)) && ((Min.Y <= box.Min.Y) && (box.Max.Y <= Max.Y))))
262  {
263  return Within;
264  }
265  return ::Intersects;
266 }
267 
268 bool BoundingBox::Contains(const Vector2& point) const
269 {
270  if ((((Min.X <= point.X) && (point.X <= Max.X)) && ((Min.Y <= point.Y) && (point.Y <= Max.Y))))
271  {
272  return true;
273  }
274  return false;
275 }
276 
277 void BoundingBox::RenderOutline() const
278 {
279  float vertices[] = {
280  Min.X, Min.Y,
281  Min.X, Max.Y,
282  Max.X, Max.Y,
283  Max.X, Min.Y,
284  };
285  glEnableClientState(GL_VERTEX_ARRAY);
286  glVertexPointer(2, GL_FLOAT, 0, vertices);
287  glDrawArrays(GL_LINE_LOOP, 0, 4);
288 }
289 
290 void BoundingBox::RenderBox() const
291 {
292  float vertices[] = {
293  Max.X, Max.Y,
294  Min.X, Max.Y,
295  Max.X, Min.Y,
296  Min.X, Min.Y,
297  };
298  glEnableClientState(GL_VERTEX_ARRAY);
299  glVertexPointer(2, GL_FLOAT, 0, vertices);
300  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
301 }
302 
303 
304 
305 bool operator ==(const BoundingBox& a, const BoundingBox& b)
306 {
307  return a.Max == b.Max && a.Min == b.Min;
308 }
309 
310 bool operator !=(const BoundingBox& a, const BoundingBox& b)
311 {
312  return !operator==(a, b);
313 }
314