2 CDTestFramework http://codercorner.com
3 Copyright (c) 2007-2008 Pierre Terdiman, pierre@codercorner.com
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose,
8 including commercial applications, and to alter it and redistribute it freely,
9 subject to the following restrictions:
11 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
17 #include "IceHelpers.h"
19 // Misc functions borrowed & adapted from ICE
21 void RotX(Matrix3x3& m, float angle)
23 float Cos = cosf(angle);
24 float Sin = sinf(angle);
26 m.m[1][1] = m.m[2][2] = Cos;
31 void RotY(Matrix3x3& m, float angle)
33 float Cos = cosf(angle);
34 float Sin = sinf(angle);
36 m.m[0][0] = m.m[2][2] = Cos;
41 void RotZ(Matrix3x3& m, float angle)
43 float Cos = cosf(angle);
44 float Sin = sinf(angle);
46 m.m[0][0] = m.m[1][1] = Cos;
51 bool SegmentSphere(const Point& origin, const Point& dir, float length, const Point& center, float radius, float& dist, Point& hit_pos)
53 // get the offset vector
54 Point offset = center - origin;
56 // get the distance along the ray to the center point of the sphere
57 float ray_dist = dir | offset;
59 // get the squared distances
60 float off2 = offset | offset;
61 float rd2 = radius * radius;
64 // we're in the sphere
70 if(ray_dist <= 0 || (ray_dist - length) > radius)
72 // moving away from object or too far away
76 // find hit distance squared
77 float d = rd2 - (off2 - ray_dist * ray_dist);
80 // ray passes by sphere without hitting
84 // get the distance along the ray
85 dist = ray_dist - sqrtf(d);
88 // hit point beyond length
92 // sort out the details
93 hit_pos = origin + dir * dist;
97 bool /*Ctc::*/RayAABB2(const Point& min, const Point& max, const Point& origin, const Point& dir, Point& coord)
101 MaxT.x=MaxT.y=MaxT.z=-1.0f;
103 // Find candidate planes.
104 for(udword i=0;i<3;i++)
106 if(origin[i] < min[i])
111 // Calculate T distances to candidate planes
112 if(IR(dir[i])) MaxT[i] = (min[i] - origin[i]) / dir[i];
114 else if(origin[i] > max[i])
119 // Calculate T distances to candidate planes
120 if(IR(dir[i])) MaxT[i] = (max[i] - origin[i]) / dir[i];
124 // Ray origin inside bounding box
131 // Get largest of the maxT's for final choice of intersection
132 udword WhichPlane = 0;
133 if(MaxT[1] > MaxT[WhichPlane]) WhichPlane = 1;
134 if(MaxT[2] > MaxT[WhichPlane]) WhichPlane = 2;
136 // Check final candidate actually inside box
137 if(IR(MaxT[WhichPlane])&0x80000000) return false;
139 for(udword i=0;i<3;i++)
143 coord[i] = origin[i] + MaxT[WhichPlane] * dir[i];
144 #ifdef RAYAABB_EPSILON
145 if(coord[i] < min[i] - RAYAABB_EPSILON || coord[i] > max[i] + RAYAABB_EPSILON) return false;
147 if(coord[i] < min[i] || coord[i] > max[i]) return false;
151 return true; // ray hits box
154 static const bool gNormalize = true;
156 udword /*Ctc::*/RayCapsuleOverlap(const Point& origin, const Point& dir, const LSS& capsule, float s[2])
158 // set up quadratic Q(t) = a*t^2 + 2*b*t + c
159 Point kU, kV, kW, capsDir;
160 capsule.ComputeDirection(capsDir);
163 float fWLength = kW.Magnitude();
166 // generate orthonormal basis
169 if ( fabsf(kW.x) >= fabsf(kW.y) )
171 // W.x or W.z is the largest magnitude component, swap them
172 fInvLength = 1.0f/sqrtf(kW.x*kW.x + kW.z*kW.z);
173 kU.x = -kW.z*fInvLength;
175 kU.z = +kW.x*fInvLength;
179 // W.y or W.z is the largest magnitude component, swap them
180 fInvLength = 1.0f/sqrtf(kW.y*kW.y + kW.z*kW.z);
182 kU.y = +kW.z*fInvLength;
183 kU.z = -kW.y*fInvLength;
190 // compute intersection
192 Point kD(kU|dir, kV|dir, kW|dir);
193 float fDLength = kD.Magnitude();
196 float fInvDLength = 1.0f/fDLength;
197 Point kDiff = origin - capsule.mP0;
198 Point kP(kU|kDiff, kV|kDiff, kW|kDiff);
199 float fRadiusSqr = capsule.mRadius*capsule.mRadius;
201 float fInv, fA, fB, fC, fDiscr, fRoot, fT, fTmp;
203 // Is the velocity parallel to the capsule direction? (or zero)
204 if ( fabsf(kD.z) >= 1.0f - FLT_EPSILON || fDLength < FLT_EPSILON )
207 float fAxisDir = dir|capsDir;
209 fDiscr = fRadiusSqr - kP.x*kP.x - kP.y*kP.y;
210 if ( fAxisDir < 0 && fDiscr >= 0.0f )
212 // Velocity anti-parallel to the capsule direction
213 fRoot = sqrtf(fDiscr);
214 s[0] = (kP.z + fRoot)*fInvDLength;
215 s[1] = -(fWLength - kP.z + fRoot)*fInvDLength;
218 else if ( fAxisDir > 0 && fDiscr >= 0.0f )
220 // Velocity parallel to the capsule direction
221 fRoot = sqrtf(fDiscr);
222 s[0] = -(kP.z + fRoot)*fInvDLength;
223 s[1] = (fWLength - kP.z + fRoot)*fInvDLength;
228 // sphere heading wrong direction, or no velocity at all
233 // test intersection with infinite cylinder
234 fA = kD.x*kD.x + kD.y*kD.y;
235 fB = kP.x*kD.x + kP.y*kD.y;
236 fC = kP.x*kP.x + kP.y*kP.y - fRadiusSqr;
237 fDiscr = fB*fB - fA*fC;
240 // line does not intersect infinite cylinder
248 // line intersects infinite cylinder in two places
249 fRoot = sqrtf(fDiscr);
251 fT = (-fB - fRoot)*fInv;
252 fTmp = kP.z + fT*kD.z;
253 if ( 0.0f <= fTmp && fTmp <= fWLength )
254 s[iQuantity++] = fT*fInvDLength;
256 fT = (-fB + fRoot)*fInv;
257 fTmp = kP.z + fT*kD.z;
258 if ( 0.0f <= fTmp && fTmp <= fWLength )
259 s[iQuantity++] = fT*fInvDLength;
261 if ( iQuantity == 2 )
263 // line intersects capsule wall in two places
269 // line is tangent to infinite cylinder
271 fTmp = kP.z + fT*kD.z;
272 if ( 0.0f <= fTmp && fTmp <= fWLength )
274 s[0] = fT*fInvDLength;
279 // test intersection with bottom hemisphere
286 fRoot = sqrtf(fDiscr);
288 fTmp = kP.z + fT*kD.z;
291 s[iQuantity++] = fT*fInvDLength;
292 if ( iQuantity == 2 )
297 fTmp = kP.z + fT*kD.z;
300 s[iQuantity++] = fT*fInvDLength;
301 if ( iQuantity == 2 )
305 else if ( fDiscr == 0.0f )
308 fTmp = kP.z + fT*kD.z;
311 s[iQuantity++] = fT*fInvDLength;
312 if ( iQuantity == 2 )
317 // test intersection with top hemisphere
320 fC += fWLength*(fWLength - 2.0f*kP.z);
325 fRoot = sqrtf(fDiscr);
327 fTmp = kP.z + fT*kD.z;
328 if ( fTmp >= fWLength )
330 s[iQuantity++] = fT*fInvDLength;
331 if ( iQuantity == 2 )
336 fTmp = kP.z + fT*kD.z;
337 if ( fTmp >= fWLength )
339 s[iQuantity++] = fT*fInvDLength;
340 if ( iQuantity == 2 )
344 else if ( fDiscr == 0.0f )
347 fTmp = kP.z + fT*kD.z;
348 if ( fTmp >= fWLength )
350 s[iQuantity++] = fT*fInvDLength;
351 if ( iQuantity == 2 )