1 /************************************************************************************
2
3 AstroMenace
4 Hardcore 3D space scroll-shooter with spaceship upgrade possibilities.
5 Copyright (c) 2006-2019 Mikhail Kurinnoi, Viewizard
6
7
8 AstroMenace is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 AstroMenace is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with AstroMenace. If not, see <https://www.gnu.org/licenses/>.
20
21
22 Website: https://viewizard.com/
23 Project: https://github.com/viewizard/astromenace
24 E-mail: viewizard@viewizard.com
25
26 *************************************************************************************/
27
28 #include "../math/math.h"
29 #include "../model3d/model3d.h"
30
31 namespace viewizard {
32
33 /*
34 * Check, is point belong triangle.
35 */
PointInTriangle(const sVECTOR3D & point,const sVECTOR3D & pa,const sVECTOR3D & pb,const sVECTOR3D & pc)36 static bool PointInTriangle(const sVECTOR3D &point, const sVECTOR3D &pa,
37 const sVECTOR3D &pb, const sVECTOR3D &pc)
38 {
39 sVECTOR3D V1{point.x - pa.x, point.y - pa.y, point.z - pa.z};
40 sVECTOR3D V2{point.x - pb.x, point.y - pb.y, point.z - pb.z};
41 sVECTOR3D V3{point.x - pc.x, point.y - pc.y, point.z - pc.z};
42
43 V1.NormalizeHi();
44 V2.NormalizeHi();
45 V3.NormalizeHi();
46
47 float TotalAngle{acosf(V1 * V2) + acosf(V2 * V3) + acosf(V3 * V1)};
48 if (fabsf(TotalAngle - 2 * 3.14159265f /* PI */) <= 0.005f /* allowable deviation */)
49 return true;
50
51 return false;
52 }
53
54 /*
55 * AABB-AABB collision detection.
56 */
vw_AABBAABBCollision(const bounding_box & Object1AABB,const sVECTOR3D & Object1Location,const bounding_box & Object2AABB,const sVECTOR3D & Object2Location)57 bool vw_AABBAABBCollision(const bounding_box &Object1AABB, const sVECTOR3D &Object1Location,
58 const bounding_box &Object2AABB, const sVECTOR3D &Object2Location)
59 {
60 // check projection's collisions
61 if (fabsf(Object1Location.x - Object2Location.x) > fabsf(Object1AABB[0].x + Object2AABB[0].x))
62 return false;
63 if (fabsf(Object1Location.y - Object2Location.y) > fabsf(Object1AABB[0].y + Object2AABB[0].y))
64 return false;
65 if (fabsf(Object1Location.z - Object2Location.z) > fabsf(Object1AABB[0].z + Object2AABB[0].z))
66 return false;
67
68 return true;
69 }
70
71 /*
72 * OBB-OBB collision detection.
73 */
vw_OBBOBBCollision(const bounding_box & Object1OBB,const sVECTOR3D & Object1OBBLocation,const sVECTOR3D & Object1Location,const float (& Object1RotationMatrix)[9],const bounding_box & Object2OBB,const sVECTOR3D & Object2OBBLocation,const sVECTOR3D & Object2Location,const float (& Object2RotationMatrix)[9])74 bool vw_OBBOBBCollision(const bounding_box &Object1OBB, const sVECTOR3D &Object1OBBLocation,
75 const sVECTOR3D &Object1Location, const float (&Object1RotationMatrix)[9],
76 const bounding_box &Object2OBB, const sVECTOR3D &Object2OBBLocation,
77 const sVECTOR3D &Object2Location, const float (&Object2RotationMatrix)[9])
78 {
79 // calcuate rotation matrix
80 float TMPInvObject1RotationMatrix[9]{Object1RotationMatrix[0], Object1RotationMatrix[1], Object1RotationMatrix[2],
81 Object1RotationMatrix[3], Object1RotationMatrix[4], Object1RotationMatrix[5],
82 Object1RotationMatrix[6], Object1RotationMatrix[7], Object1RotationMatrix[8]};
83 vw_Matrix33InverseRotate(TMPInvObject1RotationMatrix);
84 // calcuate first box size
85 sVECTOR3D a{(Object1OBB[0] - Object1OBB[6]) ^ 0.5f};
86 vw_Matrix33CalcPoint(a, TMPInvObject1RotationMatrix);
87 // calcuate inverse rotation matrix
88 float TMPInvObject2RotationMatrix[9]{Object2RotationMatrix[0], Object2RotationMatrix[1], Object2RotationMatrix[2],
89 Object2RotationMatrix[3], Object2RotationMatrix[4], Object2RotationMatrix[5],
90 Object2RotationMatrix[6], Object2RotationMatrix[7], Object2RotationMatrix[8]};
91 vw_Matrix33InverseRotate(TMPInvObject2RotationMatrix);
92 // calcuate second box size
93 sVECTOR3D b{(Object2OBB[0] - Object2OBB[6]) ^ 0.5f};
94 vw_Matrix33CalcPoint(b, TMPInvObject2RotationMatrix);
95 // calcuate offset in global coordinate systems
96 sVECTOR3D T{(Object2Location + Object2OBBLocation) -
97 (Object1Location + Object1OBBLocation)};
98 vw_Matrix33CalcPoint(T, TMPInvObject1RotationMatrix);
99 // calcuate transformation matrix
100 vw_Matrix33Mult(TMPInvObject1RotationMatrix, Object2RotationMatrix);
101 float R[3][3]{{TMPInvObject1RotationMatrix[0], TMPInvObject1RotationMatrix[3], TMPInvObject1RotationMatrix[6]},
102 {TMPInvObject1RotationMatrix[1], TMPInvObject1RotationMatrix[4], TMPInvObject1RotationMatrix[7]},
103 {TMPInvObject1RotationMatrix[2], TMPInvObject1RotationMatrix[5], TMPInvObject1RotationMatrix[8]}};
104
105 // 1 (Ra)x
106 if (fabsf(T.x) > a.x + b.x * fabsf(R[0][0]) + b.y * fabsf(R[0][1]) + b.z * fabsf(R[0][2]))
107 return false;
108 // 2 (Ra)y
109 if (fabsf(T.y) > a.y + b.x * fabsf(R[1][0]) + b.y * fabsf(R[1][1]) + b.z * fabsf(R[1][2]))
110 return false;
111 // 3 (Ra)z
112 if (fabsf(T.z) > a.z + b.x * fabsf(R[2][0]) + b.y * fabsf(R[2][1]) + b.z * fabsf(R[2][2]))
113 return false;
114
115 // 4 (Rb)x
116 if (fabsf(T.x * R[0][0] + T.y * R[1][0] + T.z * R[2][0]) >
117 (b.x + a.x * fabsf(R[0][0]) + a.y * fabsf(R[1][0]) + a. z * fabsf(R[2][0])))
118 return false;
119 // 5 (Rb)y
120 if (fabsf(T.x * R[0][1] + T.y * R[1][1] + T.z * R[2][1]) >
121 (b.y + a.x * fabsf(R[0][1]) + a.y * fabsf(R[1][1]) + a.z * fabsf(R[2][1])))
122 return false;
123 // 6 (Rb)z
124 if (fabsf(T.x * R[0][2] + T.y * R[1][2] + T.z * R[2][2]) >
125 (b.z + a.x * fabsf(R[0][2]) + a.y * fabsf(R[1][2]) + a.z * fabsf(R[2][2])))
126 return false;
127
128 // 7 (Ra)x X (Rb)x
129 if (fabsf(T.z * R[1][0] - T.y * R[2][0]) >
130 a.y * fabsf(R[2][0]) + a.z * fabsf(R[1][0]) + b.y * fabsf(R[0][2]) + b.z * fabsf(R[0][1]))
131 return false;
132 // 8 (Ra)x X (Rb)y
133 if (fabsf(T.z * R[1][1] - T.y * R[2][1]) >
134 a.y * fabsf(R[2][1]) + a.z * fabsf(R[1][1]) + b.x * fabsf(R[0][2]) + b.z * fabsf(R[0][0]))
135 return false;
136 // 9 (Ra)x X (Rb)z
137 if (fabsf(T.z * R[1][2]-T.y * R[2][2]) >
138 a.y * fabsf(R[2][2]) + a.z * fabsf(R[1][2]) + b.x * fabsf(R[0][1]) + b.y * fabsf(R[0][0]))
139 return false;
140 // 10 (Ra)y X (Rb)x
141 if (fabsf(T.x * R[2][0]-T.z * R[0][0]) >
142 a.x * fabsf(R[2][0]) + a.z * fabsf(R[0][0]) + b.y * fabsf(R[1][2]) + b.z * fabsf(R[1][1]))
143 return false;
144 // 11 (Ra)y X (Rb)y
145 if (fabsf(T.x * R[2][1]-T.z * R[0][1]) >
146 a.x * fabsf(R[2][1]) + a.z * fabsf(R[0][1]) + b.x * fabsf(R[1][2]) + b.z * fabsf(R[1][0]))
147 return false;
148 // 12 (Ra)y X (Rb)z
149 if (fabsf(T.x*R[2][2]-T.z*R[0][2]) >
150 a.x * fabsf(R[2][2]) + a.z * fabsf(R[0][2]) + b.x * fabsf(R[1][1]) + b.y * fabsf(R[1][0]))
151 return false;
152 // 13 (Ra)z X (Rb)x
153 if (fabsf(T.y * R[0][0]-T.x * R[1][0]) >
154 a.x * fabsf(R[1][0]) + a.y * fabsf(R[0][0]) + b.y * fabsf(R[2][2]) + b.z * fabsf(R[2][1]))
155 return false;
156 // 14 (Ra)z X (Rb)y
157 if (fabsf(T.y * R[0][1]-T.x * R[1][1]) >
158 a.x * fabsf(R[1][1]) + a.y * fabsf(R[0][1]) + b.x * fabsf(R[2][2]) + b.z * fabsf(R[2][0]))
159 return false;
160 // 15 (Ra)z X (Rb)z
161 if (fabsf(T.y * R[0][2]-T.x * R[1][2]) >
162 a.x * fabsf(R[1][2]) + a.y * fabsf(R[0][2]) + b.x * fabsf(R[2][1]) + b.y * fabsf(R[2][0]))
163 return false;
164
165 return true;
166 }
167
168 /*
169 * Sphere-Sphere collision detection.
170 */
vw_SphereSphereCollision(float Object1Radius,const sVECTOR3D & Object1Location,float Object2Radius,const sVECTOR3D & Object2Location,const sVECTOR3D & Object2PrevLocation)171 bool vw_SphereSphereCollision(float Object1Radius, const sVECTOR3D &Object1Location,
172 float Object2Radius, const sVECTOR3D &Object2Location,
173 const sVECTOR3D &Object2PrevLocation)
174 {
175 bool Result{true};
176
177 sVECTOR3D Object1m2Location{Object1Location.x - Object2Location.x,
178 Object1Location.y - Object2Location.y,
179 Object1Location.z - Object2Location.z};
180 float Object1p1Radius{Object1Radius + Object2Radius};
181
182 // fast check cube collisions
183 if ((fabsf(Object1m2Location.x) > Object1p1Radius) ||
184 (fabsf(Object1m2Location.y) > Object1p1Radius) ||
185 (fabsf(Object1m2Location.z) > Object1p1Radius))
186 Result = false;
187
188 // fast check for sphere collision
189 if (Result) {
190 // power of 2 for distance, no reason in sqrt here
191 float Dist2{Object1m2Location.x * Object1m2Location.x +
192 Object1m2Location.y * Object1m2Location.y +
193 Object1m2Location.z * Object1m2Location.z};
194
195 // power of 2 for minimal distance
196 float NeedDist2{Object1p1Radius * Object1p1Radius};
197
198 // if distance less or equal - collision detected
199 if (Dist2 <= NeedDist2)
200 return true;
201 }
202
203 // check for distance from point to line (ray)
204 if (!Result) {
205 sVECTOR3D Ray{Object2Location.x - Object2PrevLocation.x,
206 Object2Location.y - Object2PrevLocation.y,
207 Object2Location.z - Object2PrevLocation.z};
208 Ray.Normalize();
209
210 // calculate closest point on ray
211 float Point{Ray.x * Object1Location.x +
212 Ray.y * Object1Location.y +
213 Ray.z * Object1Location.z - Ray.x * Object2PrevLocation.x +
214 Ray.y * Object2PrevLocation.y +
215 Ray.z * Object2PrevLocation.z};
216
217 // calculate closest point on line segment
218 sVECTOR3D IntercPoint{Object2PrevLocation.x * Point,
219 Object2PrevLocation.y * Point,
220 Object2PrevLocation.z * Point};
221
222 // out of our line segment
223 if ((Object2PrevLocation.x - IntercPoint.x) * (Object2Location.x - IntercPoint.x) +
224 (Object2PrevLocation.y - IntercPoint.y) * (Object2Location.y - IntercPoint.y) +
225 (Object2PrevLocation.z - IntercPoint.z) * (Object2Location.z - IntercPoint.z) >= 0.0f)
226 return false;
227
228 // check distance, same idea with power of 2 as above
229 float NewDist2{(IntercPoint.x - Object1Location.x) * (IntercPoint.x - Object1Location.x) +
230 (IntercPoint.y - Object1Location.y) * (IntercPoint.y - Object1Location.y) +
231 (IntercPoint.z - Object1Location.z) * (IntercPoint.z - Object1Location.z)};
232
233 if (NewDist2 <= Object1Radius * Object1Radius)
234 return true;
235 }
236
237 // objects too far from each other
238 return false;
239 }
240
241 /*
242 * Sphere-AABB collision detection.
243 */
vw_SphereAABBCollision(const bounding_box & Object1AABB,const sVECTOR3D & Object1Location,float Object2Radius,const sVECTOR3D & Object2Location,const sVECTOR3D & Object2PrevLocation)244 bool vw_SphereAABBCollision(const bounding_box &Object1AABB, const sVECTOR3D &Object1Location,
245 float Object2Radius, const sVECTOR3D &Object2Location, const sVECTOR3D &Object2PrevLocation)
246 {
247 bool Result{true};
248
249 // detect distance AABB<->cube
250 if ((fabsf(Object1Location.x - Object2Location.x) > Object1AABB[0].x + Object2Radius) ||
251 (fabsf(Object1Location.y - Object2Location.y) > Object1AABB[0].y + Object2Radius) ||
252 (fabsf(Object1Location.z - Object2Location.z) > Object1AABB[0].z + Object2Radius))
253 Result = false;
254
255 // check for distance to line (ray)
256 if (!Result) {
257 // middle point
258 sVECTOR3D mid{(Object2Location + Object2PrevLocation) / 2.0f};
259 // line (ray) direction
260 sVECTOR3D dir{Object2Location - Object2PrevLocation};
261 // half of line
262 float hl{dir.Length() / 2.0f};
263 dir.Normalize();
264
265 sVECTOR3D T{Object1Location - mid};
266
267 // check axis
268 if ((fabs(T.x) > Object1AABB[0].x + hl * fabs(dir.x)) ||
269 (fabs(T.y) > Object1AABB[0].y + hl * fabs(dir.y)) ||
270 (fabs(T.z) > Object1AABB[0].z + hl * fabs(dir.z)))
271 return false;
272
273 // check X ^ dir
274 double r{Object1AABB[0].y * fabs(dir.z) + Object1AABB[0].z * fabs(dir.y)};
275 if (fabs(T.y * dir.z - T.z * dir.y) > r)
276 return false;
277
278 // check Y ^ dir
279 r = Object1AABB[0].x * fabs(dir.z) + Object1AABB[0].z * fabs(dir.x);
280 if (fabs(T.z * dir.x - T.x * dir.z) > r)
281 return false;
282
283 // check Z ^ dir
284 r = Object1AABB[0].x * fabs(dir.y) + Object1AABB[0].y * fabs(dir.x);
285 if (fabs(T.x * dir.y - T.y * dir.x) > r)
286 return false;
287
288 // collision detected
289 return true;
290 }
291
292 return Result;
293 }
294
295 /*
296 * Sphere-OBB collision detection.
297 */
vw_SphereOBBCollision(const bounding_box & Object1OBB,const sVECTOR3D & Object1OBBLocation,const sVECTOR3D & Object1Location,const float (& Object1RotationMatrix)[9],float Object2Radius,const sVECTOR3D & Object2Location,const sVECTOR3D & Object2PrevLocation)298 bool vw_SphereOBBCollision(const bounding_box &Object1OBB, const sVECTOR3D &Object1OBBLocation,
299 const sVECTOR3D &Object1Location, const float (&Object1RotationMatrix)[9],
300 float Object2Radius, const sVECTOR3D &Object2Location, const sVECTOR3D &Object2PrevLocation)
301 {
302 sVECTOR3D TMPMax{Object1OBB[0]};
303 sVECTOR3D TMPMin{Object1OBB[6]};
304 sVECTOR3D TMPPoint1{Object2Location - (Object1Location + Object1OBBLocation)};
305 sVECTOR3D TMPPoint2{Object2PrevLocation - (Object1Location + Object1OBBLocation)};
306
307 // calculate rotation matrix
308 float TMPInvRotationMatrix[9]{Object1RotationMatrix[0], Object1RotationMatrix[1], Object1RotationMatrix[2],
309 Object1RotationMatrix[3], Object1RotationMatrix[4], Object1RotationMatrix[5],
310 Object1RotationMatrix[6], Object1RotationMatrix[7], Object1RotationMatrix[8]};
311 vw_Matrix33InverseRotate(TMPInvRotationMatrix);
312 // move it to coordinates
313 vw_Matrix33CalcPoint(TMPMax, TMPInvRotationMatrix);
314 vw_Matrix33CalcPoint(TMPMin, TMPInvRotationMatrix);
315 vw_Matrix33CalcPoint(TMPPoint1, TMPInvRotationMatrix);
316 vw_Matrix33CalcPoint(TMPPoint2, TMPInvRotationMatrix);
317
318 // same idea as for Sphere-AABB collision detection
319 bool Result{true};
320 if ((TMPPoint1.x + Object2Radius < TMPMin.x) ||
321 (TMPPoint1.y + Object2Radius < TMPMin.y) ||
322 (TMPPoint1.z + Object2Radius < TMPMin.z) ||
323 (TMPPoint1.x - Object2Radius > TMPMax.x) ||
324 (TMPPoint1.y - Object2Radius > TMPMax.y) ||
325 (TMPPoint1.z - Object2Radius > TMPMax.z))
326 Result = false;
327
328 // check for distance to line (ray)
329 if (!Result) {
330 // middle point
331 sVECTOR3D mid{(Object2Location + Object2PrevLocation) / 2.0f};
332 // line (ray) direction
333 sVECTOR3D dir{Object2Location - Object2PrevLocation};
334 // half of line
335 float hl{dir.Length() / 2.0f};
336 dir.Normalize();
337
338 sVECTOR3D T{Object1Location - mid};
339
340 // check axis
341 if ((fabs(T.x) > TMPMax.x + hl * fabs(dir.x)) ||
342 (fabs(T.y) > TMPMax.y + hl * fabs(dir.y)) ||
343 (fabs(T.z) > TMPMax.z + hl * fabs(dir.z)))
344 return false;
345
346 // check X ^ dir
347 double r{TMPMax.y * fabs(dir.z) + TMPMax.z * fabs(dir.y)};
348 if (fabs(T.y * dir.z - T.z * dir.y) > r)
349 return false;
350
351 // check Y ^ dir
352 r = TMPMax.x * fabs(dir.z) + TMPMax.z * fabs(dir.x);
353 if (fabs(T.z * dir.x - T.x * dir.z) > r)
354 return false;
355
356 // check Z ^ dir
357 r = TMPMax.x * fabs(dir.y) + TMPMax.y * fabs(dir.x);
358 if (fabs(T.x * dir.y - T.y * dir.x) > r)
359 return false;
360
361 // collision detected
362 return true;
363 }
364
365 return Result;
366 }
367
368 /*
369 * Sphere-Mesh collision detection.
370 */
vw_SphereMeshCollision(const sVECTOR3D & Object1Location,const sChunk3D & Object1Chunks,const float (& Object1RotationMatrix)[9],float Object2Radius,const sVECTOR3D & Object2Location,const sVECTOR3D & Object2PrevLocation,sVECTOR3D & CollisionLocation)371 bool vw_SphereMeshCollision(const sVECTOR3D &Object1Location, const sChunk3D &Object1Chunks,
372 const float (&Object1RotationMatrix)[9], float Object2Radius, const sVECTOR3D &Object2Location,
373 const sVECTOR3D &Object2PrevLocation, sVECTOR3D &CollisionLocation)
374 {
375 // translation matrix
376 float TransMat[16]{Object1RotationMatrix[0], Object1RotationMatrix[1], Object1RotationMatrix[2], 0.0f,
377 Object1RotationMatrix[3], Object1RotationMatrix[4], Object1RotationMatrix[5], 0.0f,
378 Object1RotationMatrix[6], Object1RotationMatrix[7], Object1RotationMatrix[8], 0.0f,
379 Object1Location.x, Object1Location.y, Object1Location.z, 1.0f};
380
381 float TransMatTMP[16];
382 vw_Matrix44Identity(TransMatTMP);
383
384 // care about rotation
385 if ((Object1Chunks.Rotation.x != 0.0f) ||
386 (Object1Chunks.Rotation.y != 0.0f) ||
387 (Object1Chunks.Rotation.z != 0.0f))
388 vw_Matrix44CreateRotate(TransMatTMP, Object1Chunks.Rotation);
389
390 // don't care about GeometryAnimation here, for more speed
391
392 // generate final translation matrix
393 vw_Matrix44Translate(TransMatTMP, Object1Chunks.Location);
394 vw_Matrix44Mult(TransMat, TransMatTMP);
395
396 // detect collision with mesh triangles
397 for (unsigned int i = 0; i < Object1Chunks.VertexQuantity; i += 3) {
398 // we use index buffer here in order to find triangle's vertices in mesh
399 unsigned int IndexPos = Object1Chunks.RangeStart + i; // index buffer position
400 unsigned int VertexPos{0}; // vertex buffer position
401 if (Object1Chunks.IndexArray)
402 VertexPos = Object1Chunks.IndexArray.get()[IndexPos] * Object1Chunks.VertexStride;
403 else
404 VertexPos = (IndexPos) * Object1Chunks.VertexStride;
405
406 // translate triangle's vertices in proper coordinates for collision detection
407 sVECTOR3D Point1{Object1Chunks.VertexArray.get()[VertexPos],
408 Object1Chunks.VertexArray.get()[VertexPos + 1],
409 Object1Chunks.VertexArray.get()[VertexPos + 2]};
410 vw_Matrix44CalcPoint(Point1, TransMat);
411
412 if (Object1Chunks.IndexArray)
413 VertexPos = Object1Chunks.IndexArray.get()[IndexPos + 1] * Object1Chunks.VertexStride;
414 else
415 VertexPos = (IndexPos + 1) * Object1Chunks.VertexStride;
416
417 sVECTOR3D Point2{Object1Chunks.VertexArray.get()[VertexPos],
418 Object1Chunks.VertexArray.get()[VertexPos + 1],
419 Object1Chunks.VertexArray.get()[VertexPos + 2]};
420 vw_Matrix44CalcPoint(Point2, TransMat);
421
422 if (Object1Chunks.IndexArray)
423 VertexPos = Object1Chunks.IndexArray.get()[IndexPos + 2] * Object1Chunks.VertexStride;
424 else
425 VertexPos = (IndexPos + 2) * Object1Chunks.VertexStride;
426
427 sVECTOR3D Point3{Object1Chunks.VertexArray.get()[VertexPos],
428 Object1Chunks.VertexArray.get()[VertexPos + 1],
429 Object1Chunks.VertexArray.get()[VertexPos + 2]};
430 vw_Matrix44CalcPoint(Point3, TransMat);
431
432 // calculate 2 vectors for plane
433 sVECTOR3D PlaneVector1{Point2 - Point1};
434 sVECTOR3D PlaneVector2{Point3 - Point1};
435
436 // calculate normal for plane
437 sVECTOR3D NormalVector{PlaneVector1};
438 NormalVector.Multiply(PlaneVector2);
439 NormalVector.Normalize();
440
441 // calculate distance from point to plane
442 float Distance{(Object2Location - Point1) * NormalVector};
443
444 // point close enough to plane for check collision with plane (triangle)
445 if (fabsf(Distance) <= Object2Radius) {
446 // calculate collision point on plane for ray
447 sVECTOR3D IntercPoint{Object2Location - (NormalVector ^ Distance)};
448
449 // return the point data if point belongs to triangle (not just plane)
450 if (PointInTriangle(IntercPoint, Point1, Point2, Point3)) {
451 CollisionLocation = IntercPoint;
452 return true;
453 }
454 }
455
456 // check for distance, do we really close enough
457 // note, we use ^2 and don't calculate the real distance
458 float Object2Radius2{Object2Radius * Object2Radius};
459
460 // check distance to point1
461 sVECTOR3D DistancePoint1{Object2Location - Point1};
462 float Distance2Point1{DistancePoint1.x * DistancePoint1.x +
463 DistancePoint1.y * DistancePoint1.y +
464 DistancePoint1.z * DistancePoint1.z};
465 if (Distance2Point1 <= Object2Radius2) {
466 CollisionLocation = Point1;
467 return true;
468 }
469
470 // check distance to point2
471 sVECTOR3D DistancePoint2{Object2Location - Point2};
472 float Distance2Point2{DistancePoint2.x * DistancePoint2.x +
473 DistancePoint2.y * DistancePoint2.y +
474 DistancePoint2.z * DistancePoint2.z};
475 if (Distance2Point2 <= Object2Radius2) {
476 CollisionLocation = Point2;
477 return true;
478 }
479
480 // check distance to point3
481 sVECTOR3D DistancePoint3{Object2Location - Point3};
482 float Distance2Point3{DistancePoint3.x * DistancePoint3.x +
483 DistancePoint3.y * DistancePoint3.y +
484 DistancePoint3.z * DistancePoint3.z};
485 if (Distance2Point3 <= Object2Radius2) {
486 CollisionLocation = Point3;
487 return true;
488 }
489
490 // check for ray, old object location - current object location
491 // make sure we don't slipped through object (low FPS, fast object, etc)
492
493 // check that this is "front" for triangle, and skip triangles with "back" sided to ray start point
494 sVECTOR3D vDir1{Point1 - Object2PrevLocation};
495 float d1{vDir1 * NormalVector};
496 if (d1 <= 0.001f /* allowable deviation */) {
497 // calculate distance from point to plane
498 float originDistance{NormalVector * Point1};
499
500 sVECTOR3D vLineDir{Object2Location - Object2PrevLocation};
501
502 // Use the plane equation with the normal and the ray
503 float Numerator{ -(NormalVector.x * Object2PrevLocation.x +
504 NormalVector.y * Object2PrevLocation.y +
505 NormalVector.z * Object2PrevLocation.z - originDistance)};
506
507 float Denominator{NormalVector * vLineDir};
508 if (Denominator != 0.0f) {
509 float dist{Numerator / Denominator};
510
511 // calculate collision point on plane for ray
512 sVECTOR3D IntercPoint{Object2PrevLocation + (vLineDir ^ dist)};
513
514 // check, do line (not ray here) cross the plane
515 if (((Object2PrevLocation - IntercPoint) * (Object2Location - IntercPoint) < 0.0f) &&
516 (PointInTriangle(IntercPoint, Point1, Point2, Point3))) {
517 CollisionLocation = IntercPoint;
518 return true;
519 }
520 }
521 }
522 }
523
524 return false;
525 }
526
527 } // viewizard namespace
528