doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
CollisionModel_rotate.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 /*
30 ===============================================================================
31 
32  Trace model vs. polygonal model collision detection.
33 
34 ===============================================================================
35 */
36 
37 #include "../idlib/precompiled.h"
38 #pragma hdrstop
39 
40 #include "CollisionModel_local.h"
41 
42 /*
43 ===============================================================================
44 
45 Collision detection for rotational motion
46 
47 ===============================================================================
48 */
49 
50 // epsilon for round-off errors in epsilon calculations
51 #define CM_PL_RANGE_EPSILON 1e-4f
52 // if the collision point is this close to the rotation axis it is not considered a collision
53 #define ROTATION_AXIS_EPSILON (CM_CLIP_EPSILON*0.25f)
54 
55 
56 /*
57 ================
58 CM_RotatePoint
59 
60  rotates a point about an arbitrary axis using the tangent of half the rotation angle
61 ================
62 */
63 void CM_RotatePoint( idVec3 &point, const idVec3 &origin, const idVec3 &axis, const float tanHalfAngle ) {
64  double d, t, s, c;
65  idVec3 proj, v1, v2;
66 
67  point -= origin;
68  proj = axis * ( point * axis );
69  v1 = point - proj;
70  v2 = axis.Cross( v1 );
71 
72  // r = tan( a / 2 );
73  // sin(a) = 2*r/(1+r*r);
74  // cos(a) = (1-r*r)/(1+r*r);
75  t = tanHalfAngle * tanHalfAngle;
76  d = 1.0f / ( 1.0f + t );
77  s = 2.0f * tanHalfAngle * d;
78  c = ( 1.0f - t ) * d;
79 
80  point = v1 * c - v2 * s + proj + origin;
81 }
82 
83 /*
84 ================
85 CM_RotateEdge
86 
87  rotates an edge about an arbitrary axis using the tangent of half the rotation angle
88 ================
89 */
90 void CM_RotateEdge( idVec3 &start, idVec3 &end, const idVec3 &origin, const idVec3 &axis, const float tanHalfAngle ) {
91  double d, t, s, c;
92  idVec3 proj, v1, v2;
93 
94  // r = tan( a / 2 );
95  // sin(a) = 2*r/(1+r*r);
96  // cos(a) = (1-r*r)/(1+r*r);
97  t = tanHalfAngle * tanHalfAngle;
98  d = 1.0f / ( 1.0f + t );
99  s = 2.0f * tanHalfAngle * d;
100  c = ( 1.0f - t ) * d;
101 
102  start -= origin;
103  proj = axis * ( start * axis );
104  v1 = start - proj;
105  v2 = axis.Cross( v1 );
106  start = v1 * c - v2 * s + proj + origin;
107 
108  end -= origin;
109  proj = axis * ( end * axis );
110  v1 = end - proj;
111  v2 = axis.Cross( v1 );
112  end = v1 * c - v2 * s + proj + origin;
113 }
114 
115 /*
116 ================
117 idCollisionModelManagerLocal::CollisionBetweenEdgeBounds
118 
119  verifies if the collision of two edges occurs between the edge bounds
120  also calculates the collision point and collision plane normal if the collision occurs between the bounds
121 ================
122 */
124  const idVec3 &vc, const idVec3 &vd, float tanHalfAngle,
125  idVec3 &collisionPoint, idVec3 &collisionNormal ) {
126  float d1, d2, d;
127  idVec3 at, bt, dir, dir1, dir2;
128  idPluecker pl1, pl2;
129 
130  at = va;
131  bt = vb;
132  if ( tanHalfAngle != 0.0f ) {
133  CM_RotateEdge( at, bt, tw->origin, tw->axis, tanHalfAngle );
134  }
135 
136  dir1 = (at - tw->origin).Cross( tw->axis );
137  dir2 = (bt - tw->origin).Cross( tw->axis );
138  if ( dir1 * dir1 > dir2 * dir2 ) {
139  dir = dir1;
140  }
141  else {
142  dir = dir2;
143  }
144  if ( tw->angle < 0.0f ) {
145  dir = -dir;
146  }
147 
148  pl1.FromLine( at, bt );
149  pl2.FromRay( vc, dir );
150  d1 = pl1.PermutedInnerProduct( pl2 );
151  pl2.FromRay( vd, dir );
152  d2 = pl1.PermutedInnerProduct( pl2 );
153  if ( ( d1 > 0.0f && d2 > 0.0f ) || ( d1 < 0.0f && d2 < 0.0f ) ) {
154  return false;
155  }
156 
157  pl1.FromLine( vc, vd );
158  pl2.FromRay( at, dir );
159  d1 = pl1.PermutedInnerProduct( pl2 );
160  pl2.FromRay( bt, dir );
161  d2 = pl1.PermutedInnerProduct( pl2 );
162  if ( ( d1 > 0.0f && d2 > 0.0f ) || ( d1 < 0.0f && d2 < 0.0f ) ) {
163  return false;
164  }
165 
166  // collision point on the edge at-bt
167  dir1 = (vd - vc).Cross( dir );
168  d = dir1 * vc;
169  d1 = dir1 * at - d;
170  d2 = dir1 * bt - d;
171  if ( d1 == d2 ) {
172  return false;
173  }
174  collisionPoint = at + ( d1 / (d1 - d2) ) * ( bt - at );
175 
176  // normal is cross product of the rotated edge va-vb and the edge vc-vd
177  collisionNormal.Cross( bt-at, vd-vc );
178 
179  return true;
180 }
181 
182 /*
183 ================
184 idCollisionModelManagerLocal::RotateEdgeThroughEdge
185 
186  calculates the tangent of half the rotation angle at which the edges collide
187 ================
188 */
190  const idVec3 &vc, const idVec3 &vd,
191  const float minTan, float &tanHalfAngle ) {
192  double v0, v1, v2, a, b, c, d, sqrtd, q, frac1, frac2;
193  idVec3 ct, dt;
194  idPluecker pl2;
195 
196  /*
197 
198  a = start of line being rotated
199  b = end of line being rotated
200  pl1 = pluecker coordinate for line (a - b)
201  pl2 = pluecker coordinate for edge we might collide with (c - d)
202  t = rotation angle around the z-axis
203  solve pluecker inner product for t of rotating line a-b and line l2
204 
205  // start point of rotated line during rotation
206  an[0] = a[0] * cos(t) + a[1] * sin(t)
207  an[1] = a[0] * -sin(t) + a[1] * cos(t)
208  an[2] = a[2];
209  // end point of rotated line during rotation
210  bn[0] = b[0] * cos(t) + b[1] * sin(t)
211  bn[1] = b[0] * -sin(t) + b[1] * cos(t)
212  bn[2] = b[2];
213 
214  pl1[0] = a[0] * b[1] - b[0] * a[1];
215  pl1[1] = a[0] * b[2] - b[0] * a[2];
216  pl1[2] = a[0] - b[0];
217  pl1[3] = a[1] * b[2] - b[1] * a[2];
218  pl1[4] = a[2] - b[2];
219  pl1[5] = b[1] - a[1];
220 
221  v[0] = (a[0] * cos(t) + a[1] * sin(t)) * (b[0] * -sin(t) + b[1] * cos(t)) - (b[0] * cos(t) + b[1] * sin(t)) * (a[0] * -sin(t) + a[1] * cos(t));
222  v[1] = (a[0] * cos(t) + a[1] * sin(t)) * b[2] - (b[0] * cos(t) + b[1] * sin(t)) * a[2];
223  v[2] = (a[0] * cos(t) + a[1] * sin(t)) - (b[0] * cos(t) + b[1] * sin(t));
224  v[3] = (a[0] * -sin(t) + a[1] * cos(t)) * b[2] - (b[0] * -sin(t) + b[1] * cos(t)) * a[2];
225  v[4] = a[2] - b[2];
226  v[5] = (b[0] * -sin(t) + b[1] * cos(t)) - (a[0] * -sin(t) + a[1] * cos(t));
227 
228  pl2[0] * v[4] + pl2[1] * v[5] + pl2[2] * v[3] + pl2[4] * v[0] + pl2[5] * v[1] + pl2[3] * v[2] = 0;
229 
230  v[0] = (a[0] * cos(t) + a[1] * sin(t)) * (b[0] * -sin(t) + b[1] * cos(t)) - (b[0] * cos(t) + b[1] * sin(t)) * (a[0] * -sin(t) + a[1] * cos(t));
231  v[0] = (a[1] * b[1] - a[0] * b[0]) * cos(t) * sin(t) + (a[0] * b[1] + a[1] * b[0] * cos(t)^2) - (a[1] * b[0]) - ((b[1] * a[1] - b[0] * a[0]) * cos(t) * sin(t) + (b[0] * a[1] + b[1] * a[0]) * cos(t)^2 - (b[1] * a[0]))
232  v[0] = - (a[1] * b[0]) - ( - (b[1] * a[0]))
233  v[0] = (b[1] * a[0]) - (a[1] * b[0])
234 
235  v[0] = (a[0]*b[1]) - (a[1]*b[0]);
236  v[1] = (a[0]*b[2] - b[0]*a[2]) * cos(t) + (a[1]*b[2] - b[1]*a[2]) * sin(t);
237  v[2] = (a[0]-b[0]) * cos(t) + (a[1]-b[1]) * sin(t);
238  v[3] = (b[0]*a[2] - a[0]*b[2]) * sin(t) + (a[1]*b[2] - b[1]*a[2]) * cos(t);
239  v[4] = a[2] - b[2];
240  v[5] = (a[0]-b[0]) * sin(t) + (b[1]-a[1]) * cos(t);
241 
242  v[0] = (a[0]*b[1]) - (a[1]*b[0]);
243  v[1] = (a[0]*b[2] - b[0]*a[2]) * cos(t) + (a[1]*b[2] - b[1]*a[2]) * sin(t);
244  v[2] = (a[0]-b[0]) * cos(t) - (b[1]-a[1]) * sin(t);
245  v[3] = (a[0]*b[2] - b[0]*a[2]) * -sin(t) + (a[1]*b[2] - b[1]*a[2]) * cos(t);
246  v[4] = a[2] - b[2];
247  v[5] = (a[0]-b[0]) * sin(t) + (b[1]-a[1]) * cos(t);
248 
249  v[0] = pl1[0];
250  v[1] = pl1[1] * cos(t) + pl1[3] * sin(t);
251  v[2] = pl1[2] * cos(t) - pl1[5] * sin(t);
252  v[3] = pl1[3] * cos(t) - pl1[1] * sin(t);
253  v[4] = pl1[4];
254  v[5] = pl1[5] * cos(t) + pl1[2] * sin(t);
255 
256  pl2[0] * v[4] + pl2[1] * v[5] + pl2[2] * v[3] + pl2[4] * v[0] + pl2[5] * v[1] + pl2[3] * v[2] = 0;
257 
258  0 = pl2[0] * pl1[4] +
259  pl2[1] * (pl1[5] * cos(t) + pl1[2] * sin(t)) +
260  pl2[2] * (pl1[3] * cos(t) - pl1[1] * sin(t)) +
261  pl2[4] * pl1[0] +
262  pl2[5] * (pl1[1] * cos(t) + pl1[3] * sin(t)) +
263  pl2[3] * (pl1[2] * cos(t) - pl1[5] * sin(t));
264 
265  v2 * cos(t) + v1 * sin(t) + v0 = 0;
266 
267  // rotation about the z-axis
268  v0 = pl2[0] * pl1[4] + pl2[4] * pl1[0];
269  v1 = pl2[1] * pl1[2] - pl2[2] * pl1[1] + pl2[5] * pl1[3] - pl2[3] * pl1[5];
270  v2 = pl2[1] * pl1[5] + pl2[2] * pl1[3] + pl2[5] * pl1[1] + pl2[3] * pl1[2];
271 
272  // rotation about the x-axis
273  //v0 = pl2[3] * pl1[2] + pl2[2] * pl1[3];
274  //v1 = -pl2[5] * pl1[0] + pl2[4] * pl1[1] - pl2[1] * pl1[4] + pl2[0] * pl1[5];
275  //v2 = pl2[4] * pl1[0] + pl2[5] * pl1[1] + pl2[0] * pl1[4] + pl2[1] * pl1[5];
276 
277  r = tan(t / 2);
278  sin(t) = 2*r/(1+r*r);
279  cos(t) = (1-r*r)/(1+r*r);
280 
281  v1 * 2 * r / (1 + r*r) + v2 * (1 - r*r) / (1 + r*r) + v0 = 0
282  (v1 * 2 * r + v2 * (1 - r*r)) / (1 + r*r) = -v0
283  (v1 * 2 * r + v2 - v2 * r*r) / (1 + r*r) = -v0
284  v1 * 2 * r + v2 - v2 * r*r = -v0 * (1 + r*r)
285  v1 * 2 * r + v2 - v2 * r*r = -v0 + -v0 * r*r
286  (v0 - v2) * r * r + (2 * v1) * r + (v0 + v2) = 0;
287 
288  MrE gives Pluecker a banana.. good monkey
289 
290  */
291 
292  tanHalfAngle = tw->maxTan;
293 
294  // transform rotation axis to z-axis
295  ct = (vc - tw->origin) * tw->matrix;
296  dt = (vd - tw->origin) * tw->matrix;
297 
298  pl2.FromLine( ct, dt );
299 
300  v0 = pl2[0] * pl1[4] + pl2[4] * pl1[0];
301  v1 = pl2[1] * pl1[2] - pl2[2] * pl1[1] + pl2[5] * pl1[3] - pl2[3] * pl1[5];
302  v2 = pl2[1] * pl1[5] + pl2[2] * pl1[3] + pl2[5] * pl1[1] + pl2[3] * pl1[2];
303 
304  a = v0 - v2;
305  b = v1;
306  c = v0 + v2;
307  if ( a == 0.0f ) {
308  if ( b == 0.0f ) {
309  return false;
310  }
311  frac1 = -c / ( 2.0f * b );
312  frac2 = 1e10; // = tan( idMath::HALF_PI )
313  }
314  else {
315  d = b * b - c * a;
316  if ( d <= 0.0f ) {
317  return false;
318  }
319  sqrtd = sqrt( d );
320  if ( b > 0.0f ) {
321  q = - b + sqrtd;
322  }
323  else {
324  q = - b - sqrtd;
325  }
326  frac1 = q / a;
327  frac2 = c / q;
328  }
329 
330  if ( tw->angle < 0.0f ) {
331  frac1 = -frac1;
332  frac2 = -frac2;
333  }
334 
335  // get smallest tangent for which a collision occurs
336  if ( frac1 >= minTan && frac1 < tanHalfAngle ) {
337  tanHalfAngle = frac1;
338  }
339  if ( frac2 >= minTan && frac2 < tanHalfAngle ) {
340  tanHalfAngle = frac2;
341  }
342 
343  if ( tw->angle < 0.0f ) {
344  tanHalfAngle = -tanHalfAngle;
345  }
346 
347  return true;
348 }
349 
350 /*
351 ================
352 idCollisionModelManagerLocal::EdgeFurthestFromEdge
353 
354  calculates the direction of motion at the initial position, where dir < 0 means the edges move towards each other
355  if the edges move away from each other the tangent of half the rotation angle at which
356  the edges are furthest apart is also calculated
357 ================
358 */
360  const idVec3 &vc, const idVec3 &vd,
361  float &tanHalfAngle, float &dir ) {
362  double v0, v1, v2, a, b, c, d, sqrtd, q, frac1, frac2;
363  idVec3 ct, dt;
364  idPluecker pl2;
365 
366  /*
367 
368  v2 * cos(t) + v1 * sin(t) + v0 = 0;
369 
370  // rotation about the z-axis
371  v0 = pl2[0] * pl1[4] + pl2[4] * pl1[0];
372  v1 = pl2[1] * pl1[2] - pl2[2] * pl1[1] + pl2[5] * pl1[3] - pl2[3] * pl1[5];
373  v2 = pl2[1] * pl1[5] + pl2[2] * pl1[3] + pl2[5] * pl1[1] + pl2[3] * pl1[2];
374 
375  derivative:
376  v1 * cos(t) - v2 * sin(t) = 0;
377 
378  r = tan(t / 2);
379  sin(t) = 2*r/(1+r*r);
380  cos(t) = (1-r*r)/(1+r*r);
381 
382  -v2 * 2 * r / (1 + r*r) + v1 * (1 - r*r)/(1+r*r);
383  -v2 * 2 * r + v1 * (1 - r*r) / (1 + r*r) = 0;
384  -v2 * 2 * r + v1 * (1 - r*r) = 0;
385  (-v1) * r * r + (-2 * v2) * r + (v1) = 0;
386 
387  */
388 
389  tanHalfAngle = 0.0f;
390 
391  // transform rotation axis to z-axis
392  ct = (vc - tw->origin) * tw->matrix;
393  dt = (vd - tw->origin) * tw->matrix;
394 
395  pl2.FromLine( ct, dt );
396 
397  v0 = pl2[0] * pl1[4] + pl2[4] * pl1[0];
398  v1 = pl2[1] * pl1[2] - pl2[2] * pl1[1] + pl2[5] * pl1[3] - pl2[3] * pl1[5];
399  v2 = pl2[1] * pl1[5] + pl2[2] * pl1[3] + pl2[5] * pl1[1] + pl2[3] * pl1[2];
400 
401  // get the direction of motion at the initial position
402  c = v0 + v2;
403  if ( tw->angle > 0.0f ) {
404  if ( c > 0.0f ) {
405  dir = v1;
406  }
407  else {
408  dir = -v1;
409  }
410  }
411  else {
412  if ( c > 0.0f ) {
413  dir = -v1;
414  }
415  else {
416  dir = v1;
417  }
418  }
419  // negative direction means the edges move towards each other at the initial position
420  if ( dir <= 0.0f ) {
421  return true;
422  }
423 
424  a = -v1;
425  b = -v2;
426  c = v1;
427  if ( a == 0.0f ) {
428  if ( b == 0.0f ) {
429  return false;
430  }
431  frac1 = -c / ( 2.0f * b );
432  frac2 = 1e10; // = tan( idMath::HALF_PI )
433  }
434  else {
435  d = b * b - c * a;
436  if ( d <= 0.0f ) {
437  return false;
438  }
439  sqrtd = sqrt( d );
440  if ( b > 0.0f ) {
441  q = - b + sqrtd;
442  }
443  else {
444  q = - b - sqrtd;
445  }
446  frac1 = q / a;
447  frac2 = c / q;
448  }
449 
450  if ( tw->angle < 0.0f ) {
451  frac1 = -frac1;
452  frac2 = -frac2;
453  }
454 
455  if ( frac1 < 0.0f && frac2 < 0.0f ) {
456  return false;
457  }
458 
459  if ( frac1 > frac2 ) {
460  tanHalfAngle = frac1;
461  }
462  else {
463  tanHalfAngle = frac2;
464  }
465 
466  if ( tw->angle < 0.0f ) {
467  tanHalfAngle = -tanHalfAngle;
468  }
469 
470  return true;
471 }
472 
473 /*
474 ================
475 idCollisionModelManagerLocal::RotateTrmEdgeThroughPolygon
476 ================
477 */
479  int i, j, edgeNum;
480  float f1, f2, startTan, dir, tanHalfAngle;
481  cm_edge_t *edge;
482  cm_vertex_t *v1, *v2;
483  idVec3 collisionPoint, collisionNormal, origin, epsDir;
484  idPluecker epsPl;
485  idBounds bounds;
486 
487  // if the trm is convex and the rotation axis intersects the trm
488  if ( tw->isConvex && tw->axisIntersectsTrm ) {
489  // if both points are behind the polygon the edge cannot collide within a 180 degrees rotation
490  if ( tw->vertices[trmEdge->vertexNum[0]].polygonSide & tw->vertices[trmEdge->vertexNum[1]].polygonSide ) {
491  return;
492  }
493  }
494 
495  // if the trace model edge rotation bounds do not intersect the polygon bounds
496  if ( !trmEdge->rotationBounds.IntersectsBounds( poly->bounds ) ) {
497  return;
498  }
499 
500  // edge rotation bounds should cross polygon plane
501  if ( trmEdge->rotationBounds.PlaneSide( poly->plane ) != SIDE_CROSS ) {
502  return;
503  }
504 
505  // check edges for a collision
506  for ( i = 0; i < poly->numEdges; i++ ) {
507  edgeNum = poly->edges[i];
508  edge = tw->model->edges + abs(edgeNum);
509 
510  // if this edge is already checked
512  continue;
513  }
514 
515  // can never collide with internal edges
516  if ( edge->internal ) {
517  continue;
518  }
519 
520  v1 = tw->model->vertices + edge->vertexNum[INTSIGNBITSET(edgeNum)];
521  v2 = tw->model->vertices + edge->vertexNum[INTSIGNBITNOTSET(edgeNum)];
522 
523  // edge bounds
524  for ( j = 0; j < 3; j++ ) {
525  if ( v1->p[j] > v2->p[j] ) {
526  bounds[0][j] = v2->p[j];
527  bounds[1][j] = v1->p[j];
528  }
529  else {
530  bounds[0][j] = v1->p[j];
531  bounds[1][j] = v2->p[j];
532  }
533  }
534 
535  // if the trace model edge rotation bounds do not intersect the polygon edge bounds
536  if ( !trmEdge->rotationBounds.IntersectsBounds( bounds ) ) {
537  continue;
538  }
539 
540  f1 = trmEdge->pl.PermutedInnerProduct( tw->polygonEdgePlueckerCache[i] );
541 
542  // pluecker coordinate for epsilon expanded edge
543  epsDir = edge->normal * (CM_CLIP_EPSILON+CM_PL_RANGE_EPSILON);
544  epsPl.FromLine( tw->model->vertices[edge->vertexNum[0]].p + epsDir,
545  tw->model->vertices[edge->vertexNum[1]].p + epsDir );
546 
547  f2 = trmEdge->pl.PermutedInnerProduct( epsPl );
548 
549  // if the rotating edge is inbetween the polygon edge and the epsilon expanded edge
550  if ( ( f1 < 0.0f && f2 > 0.0f ) || ( f1 > 0.0f && f2 < 0.0f ) ) {
551 
552  if ( !EdgeFurthestFromEdge( tw, trmEdge->plzaxis, v1->p, v2->p, startTan, dir ) ) {
553  continue;
554  }
555 
556  if ( dir <= 0.0f ) {
557  // moving towards the polygon edge so stop immediately
558  tanHalfAngle = 0.0f;
559  }
560  else if ( idMath::Fabs( startTan ) >= tw->maxTan ) {
561  // never going to get beyond the start tangent during the current rotation
562  continue;
563  }
564  else {
565  // collide with the epsilon expanded edge
566  if ( !RotateEdgeThroughEdge(tw, trmEdge->plzaxis, v1->p + epsDir, v2->p + epsDir, idMath::Fabs( startTan ), tanHalfAngle ) ) {
567  tanHalfAngle = startTan;
568  }
569  }
570  }
571  else {
572  // collide with the epsilon expanded edge
573  epsDir = edge->normal * CM_CLIP_EPSILON;
574  if ( !RotateEdgeThroughEdge(tw, trmEdge->plzaxis, v1->p + epsDir, v2->p + epsDir, 0.0f, tanHalfAngle ) ) {
575  continue;
576  }
577  }
578 
579  if ( idMath::Fabs( tanHalfAngle ) >= tw->maxTan ) {
580  continue;
581  }
582 
583  // check if the collision is between the edge bounds
584  if ( !CollisionBetweenEdgeBounds( tw, trmEdge->start, trmEdge->end, v1->p, v2->p,
585  tanHalfAngle, collisionPoint, collisionNormal ) ) {
586  continue;
587  }
588 
589  // allow rotation if the rotation axis goes through the collisionPoint
590  origin = tw->origin + tw->axis * ( tw->axis * ( collisionPoint - tw->origin ) );
591  if ( ( collisionPoint - origin ).LengthSqr() < ROTATION_AXIS_EPSILON * ROTATION_AXIS_EPSILON ) {
592  continue;
593  }
594 
595  // fill in trace structure
596  tw->maxTan = idMath::Fabs( tanHalfAngle );
597  tw->trace.c.normal = collisionNormal;
598  tw->trace.c.normal.Normalize();
599  tw->trace.c.dist = tw->trace.c.normal * v1->p;
600  // make sure the collision plane faces the trace model
601  if ( (tw->trace.c.normal * trmEdge->start) - tw->trace.c.dist < 0 ) {
602  tw->trace.c.normal = -tw->trace.c.normal;
603  tw->trace.c.dist = -tw->trace.c.dist;
604  }
605  tw->trace.c.contents = poly->contents;
606  tw->trace.c.material = poly->material;
607  tw->trace.c.type = CONTACT_EDGE;
608  tw->trace.c.modelFeature = edgeNum;
609  tw->trace.c.trmFeature = trmEdge - tw->edges;
610  tw->trace.c.point = collisionPoint;
611  // if no collision can be closer
612  if ( tw->maxTan == 0.0f ) {
613  break;
614  }
615  }
616 }
617 
618 /*
619 ================
620 idCollisionModelManagerLocal::RotatePointThroughPlane
621 
622  calculates the tangent of half the rotation angle at which the point collides with the plane
623 ================
624 */
626  const float angle, const float minTan, float &tanHalfAngle ) {
627  double v0, v1, v2, a, b, c, d, sqrtd, q, frac1, frac2;
628  idVec3 p, normal;
629 
630  /*
631 
632  p[0] = point[0] * cos(t) + point[1] * sin(t)
633  p[1] = point[0] * -sin(t) + point[1] * cos(t)
634  p[2] = point[2];
635 
636  normal[0] * (p[0] * cos(t) + p[1] * sin(t)) +
637  normal[1] * (p[0] * -sin(t) + p[1] * cos(t)) +
638  normal[2] * p[2] + dist = 0
639 
640  normal[0] * p[0] * cos(t) + normal[0] * p[1] * sin(t) +
641  -normal[1] * p[0] * sin(t) + normal[1] * p[1] * cos(t) +
642  normal[2] * p[2] + dist = 0
643 
644  v2 * cos(t) + v1 * sin(t) + v0
645 
646  // rotation about the z-axis
647  v0 = normal[2] * p[2] + dist
648  v1 = normal[0] * p[1] - normal[1] * p[0]
649  v2 = normal[0] * p[0] + normal[1] * p[1]
650 
651  r = tan(t / 2);
652  sin(t) = 2*r/(1+r*r);
653  cos(t) = (1-r*r)/(1+r*r);
654 
655  v1 * 2 * r / (1 + r*r) + v2 * (1 - r*r) / (1 + r*r) + v0 = 0
656  (v1 * 2 * r + v2 * (1 - r*r)) / (1 + r*r) = -v0
657  (v1 * 2 * r + v2 - v2 * r*r) / (1 + r*r) = -v0
658  v1 * 2 * r + v2 - v2 * r*r = -v0 * (1 + r*r)
659  v1 * 2 * r + v2 - v2 * r*r = -v0 + -v0 * r*r
660  (v0 - v2) * r * r + (2 * v1) * r + (v0 + v2) = 0;
661 
662  */
663 
664  tanHalfAngle = tw->maxTan;
665 
666  // transform rotation axis to z-axis
667  p = (point - tw->origin) * tw->matrix;
668  d = plane[3] + plane.Normal() * tw->origin;
669  normal = plane.Normal() * tw->matrix;
670 
671  v0 = normal[2] * p[2] + d;
672  v1 = normal[0] * p[1] - normal[1] * p[0];
673  v2 = normal[0] * p[0] + normal[1] * p[1];
674 
675  a = v0 - v2;
676  b = v1;
677  c = v0 + v2;
678  if ( a == 0.0f ) {
679  if ( b == 0.0f ) {
680  return false;
681  }
682  frac1 = -c / ( 2.0f * b );
683  frac2 = 1e10; // = tan( idMath::HALF_PI )
684  }
685  else {
686  d = b * b - c * a;
687  if ( d <= 0.0f ) {
688  return false;
689  }
690  sqrtd = sqrt( d );
691  if ( b > 0.0f ) {
692  q = - b + sqrtd;
693  }
694  else {
695  q = - b - sqrtd;
696  }
697  frac1 = q / a;
698  frac2 = c / q;
699  }
700 
701  if ( angle < 0.0f ) {
702  frac1 = -frac1;
703  frac2 = -frac2;
704  }
705 
706  // get smallest tangent for which a collision occurs
707  if ( frac1 >= minTan && frac1 < tanHalfAngle ) {
708  tanHalfAngle = frac1;
709  }
710  if ( frac2 >= minTan && frac2 < tanHalfAngle ) {
711  tanHalfAngle = frac2;
712  }
713 
714  if ( angle < 0.0f ) {
715  tanHalfAngle = -tanHalfAngle;
716  }
717 
718  return true;
719 }
720 
721 /*
722 ================
723 idCollisionModelManagerLocal::PointFurthestFromPlane
724 
725  calculates the direction of motion at the initial position, where dir < 0 means the point moves towards the plane
726  if the point moves away from the plane the tangent of half the rotation angle at which
727  the point is furthest away from the plane is also calculated
728 ================
729 */
731  const float angle, float &tanHalfAngle, float &dir ) {
732 
733  double v1, v2, a, b, c, d, sqrtd, q, frac1, frac2;
734  idVec3 p, normal;
735 
736  /*
737 
738  v2 * cos(t) + v1 * sin(t) + v0 = 0;
739 
740  // rotation about the z-axis
741  v0 = normal[2] * p[2] + dist
742  v1 = normal[0] * p[1] - normal[1] * p[0]
743  v2 = normal[0] * p[0] + normal[1] * p[1]
744 
745  derivative:
746  v1 * cos(t) - v2 * sin(t) = 0;
747 
748  r = tan(t / 2);
749  sin(t) = 2*r/(1+r*r);
750  cos(t) = (1-r*r)/(1+r*r);
751 
752  -v2 * 2 * r / (1 + r*r) + v1 * (1 - r*r)/(1+r*r);
753  -v2 * 2 * r + v1 * (1 - r*r) / (1 + r*r) = 0;
754  -v2 * 2 * r + v1 * (1 - r*r) = 0;
755  (-v1) * r * r + (-2 * v2) * r + (v1) = 0;
756 
757  */
758 
759  tanHalfAngle = 0.0f;
760 
761  // transform rotation axis to z-axis
762  p = (point - tw->origin) * tw->matrix;
763  normal = plane.Normal() * tw->matrix;
764 
765  v1 = normal[0] * p[1] - normal[1] * p[0];
766  v2 = normal[0] * p[0] + normal[1] * p[1];
767 
768  // the point will always start at the front of the plane, therefore v0 + v2 > 0 is always true
769  if ( angle < 0.0f ) {
770  dir = -v1;
771  }
772  else {
773  dir = v1;
774  }
775  // negative direction means the point moves towards the plane at the initial position
776  if ( dir <= 0.0f ) {
777  return true;
778  }
779 
780  a = -v1;
781  b = -v2;
782  c = v1;
783  if ( a == 0.0f ) {
784  if ( b == 0.0f ) {
785  return false;
786  }
787  frac1 = -c / ( 2.0f * b );
788  frac2 = 1e10; // = tan( idMath::HALF_PI )
789  }
790  else {
791  d = b * b - c * a;
792  if ( d <= 0.0f ) {
793  return false;
794  }
795  sqrtd = sqrt( d );
796  if ( b > 0.0f ) {
797  q = - b + sqrtd;
798  }
799  else {
800  q = - b - sqrtd;
801  }
802  frac1 = q / a;
803  frac2 = c / q;
804  }
805 
806  if ( angle < 0.0f ) {
807  frac1 = -frac1;
808  frac2 = -frac2;
809  }
810 
811  if ( frac1 < 0.0f && frac2 < 0.0f ) {
812  return false;
813  }
814 
815  if ( frac1 > frac2 ) {
816  tanHalfAngle = frac1;
817  }
818  else {
819  tanHalfAngle = frac2;
820  }
821 
822  if ( angle < 0.0f ) {
823  tanHalfAngle = -tanHalfAngle;
824  }
825 
826  return true;
827 }
828 
829 /*
830 ================
831 idCollisionModelManagerLocal::RotatePointThroughEpsilonPlane
832 ================
833 */
835  const idPlane &plane, const float angle, const idVec3 &origin,
836  float &tanHalfAngle, idVec3 &collisionPoint, idVec3 &endDir ) {
837  float d, dir, startTan;
838  idVec3 vec, startDir;
839  idPlane epsPlane;
840 
841  // epsilon expanded plane
842  epsPlane = plane;
843  epsPlane.SetDist( epsPlane.Dist() + CM_CLIP_EPSILON );
844 
845  // if the rotation sphere at the rotation origin is too far away from the polygon plane
846  d = epsPlane.Distance( origin );
847  vec = point - origin;
848  if ( d * d > vec * vec ) {
849  return false;
850  }
851 
852  // calculate direction of motion at vertex start position
853  startDir = ( point - origin ).Cross( tw->axis );
854  if ( angle < 0.0f ) {
855  startDir = -startDir;
856  }
857  // if moving away from plane at start position
858  if ( startDir * epsPlane.Normal() >= 0.0f ) {
859  // if end position is outside epsilon range
860  d = epsPlane.Distance( endPoint );
861  if ( d >= 0.0f ) {
862  return false; // no collision
863  }
864  // calculate direction of motion at vertex end position
865  endDir = ( endPoint - origin ).Cross( tw->axis );
866  if ( angle < 0.0f ) {
867  endDir = -endDir;
868  }
869  // if also moving away from plane at end position
870  if ( endDir * epsPlane.Normal() > 0.0f ) {
871  return false; // no collision
872  }
873  }
874 
875  // if the start position is in the epsilon range
876  d = epsPlane.Distance( point );
877  if ( d <= CM_PL_RANGE_EPSILON ) {
878 
879  // calculate tangent of half the rotation for which the vertex is furthest away from the plane
880  if ( !PointFurthestFromPlane( tw, point, plane, angle, startTan, dir ) ) {
881  return false;
882  }
883 
884  if ( dir <= 0.0f ) {
885  // moving towards the polygon plane so stop immediately
886  tanHalfAngle = 0.0f;
887  }
888  else if ( idMath::Fabs( startTan ) >= tw->maxTan ) {
889  // never going to get beyond the start tangent during the current rotation
890  return false;
891  }
892  else {
893  // calculate collision with epsilon expanded plane
894  if ( !RotatePointThroughPlane( tw, point, epsPlane, angle, idMath::Fabs( startTan ), tanHalfAngle ) ) {
895  tanHalfAngle = startTan;
896  }
897  }
898  }
899  else {
900  // calculate collision with epsilon expanded plane
901  if ( !RotatePointThroughPlane( tw, point, epsPlane, angle, 0.0f, tanHalfAngle ) ) {
902  return false;
903  }
904  }
905 
906  // calculate collision point
907  collisionPoint = point;
908  if ( tanHalfAngle != 0.0f ) {
909  CM_RotatePoint( collisionPoint, tw->origin, tw->axis, tanHalfAngle );
910  }
911  // calculate direction of motion at collision point
912  endDir = ( collisionPoint - origin ).Cross( tw->axis );
913  if ( angle < 0.0f ) {
914  endDir = -endDir;
915  }
916  return true;
917 }
918 
919 /*
920 ================
921 idCollisionModelManagerLocal::RotateTrmVertexThroughPolygon
922 ================
923 */
925  int i;
926  float tanHalfAngle;
927  idVec3 endDir, collisionPoint;
928  idPluecker pl;
929 
930  // if the trm vertex is behind the polygon plane it cannot collide with the polygon within a 180 degrees rotation
931  if ( tw->isConvex && tw->axisIntersectsTrm && v->polygonSide ) {
932  return;
933  }
934 
935  // if the trace model vertex rotation bounds do not intersect the polygon bounds
936  if ( !v->rotationBounds.IntersectsBounds( poly->bounds ) ) {
937  return;
938  }
939 
940  // vertex rotation bounds should cross polygon plane
941  if ( v->rotationBounds.PlaneSide( poly->plane ) != SIDE_CROSS ) {
942  return;
943  }
944 
945  // rotate the vertex through the epsilon plane
946  if ( !RotatePointThroughEpsilonPlane( tw, v->p, v->endp, poly->plane, tw->angle, v->rotationOrigin,
947  tanHalfAngle, collisionPoint, endDir ) ) {
948  return;
949  }
950 
951  if ( idMath::Fabs( tanHalfAngle ) < tw->maxTan ) {
952  // verify if 'collisionPoint' moving along 'endDir' moves between polygon edges
953  pl.FromRay( collisionPoint, endDir );
954  for ( i = 0; i < poly->numEdges; i++ ) {
955  if ( poly->edges[i] < 0 ) {
956  if ( pl.PermutedInnerProduct( tw->polygonEdgePlueckerCache[i] ) > 0.0f ) {
957  return;
958  }
959  }
960  else {
961  if ( pl.PermutedInnerProduct( tw->polygonEdgePlueckerCache[i] ) < 0.0f ) {
962  return;
963  }
964  }
965  }
966  tw->maxTan = idMath::Fabs( tanHalfAngle );
967  // collision plane is the polygon plane
968  tw->trace.c.normal = poly->plane.Normal();
969  tw->trace.c.dist = poly->plane.Dist();
970  tw->trace.c.contents = poly->contents;
971  tw->trace.c.material = poly->material;
973  tw->trace.c.modelFeature = *reinterpret_cast<int *>(&poly);
974  tw->trace.c.trmFeature = v - tw->vertices;
975  tw->trace.c.point = collisionPoint;
976  }
977 }
978 
979 /*
980 ================
981 idCollisionModelManagerLocal::RotateVertexThroughTrmPolygon
982 ================
983 */
985  int i, edgeNum;
986  float tanHalfAngle;
987  idVec3 dir, endp, endDir, collisionPoint;
988  idPluecker pl;
990 
991  // if the polygon vertex is behind the trm plane it cannot collide with the trm polygon within a 180 degrees rotation
992  if ( tw->isConvex && tw->axisIntersectsTrm && trmpoly->plane.Distance( v->p ) < 0.0f ) {
993  return;
994  }
995 
996  // if the model vertex is outside the trm polygon rotation bounds
997  if ( !trmpoly->rotationBounds.ContainsPoint( v->p ) ) {
998  return;
999  }
1000 
1001  // if the rotation axis goes through the polygon vertex
1002  dir = v->p - rotationOrigin;
1003  if ( dir * dir < ROTATION_AXIS_EPSILON * ROTATION_AXIS_EPSILON ) {
1004  return;
1005  }
1006 
1007  // calculate vertex end position
1008  endp = v->p;
1009  tw->modelVertexRotation.RotatePoint( endp );
1010 
1011  // rotate the vertex through the epsilon plane
1012  if ( !RotatePointThroughEpsilonPlane( tw, v->p, endp, trmpoly->plane, -tw->angle, rotationOrigin,
1013  tanHalfAngle, collisionPoint, endDir ) ) {
1014  return;
1015  }
1016 
1017  if ( idMath::Fabs( tanHalfAngle ) < tw->maxTan ) {
1018  // verify if 'collisionPoint' moving along 'endDir' moves between polygon edges
1019  pl.FromRay( collisionPoint, endDir );
1020  for ( i = 0; i < trmpoly->numEdges; i++ ) {
1021  edgeNum = trmpoly->edges[i];
1022  edge = tw->edges + abs(edgeNum);
1023  if ( edgeNum < 0 ) {
1024  if ( pl.PermutedInnerProduct( edge->pl ) > 0.0f ) {
1025  return;
1026  }
1027  }
1028  else {
1029  if ( pl.PermutedInnerProduct( edge->pl ) < 0.0f ) {
1030  return;
1031  }
1032  }
1033  }
1034  tw->maxTan = idMath::Fabs( tanHalfAngle );
1035  // collision plane is the flipped trm polygon plane
1036  tw->trace.c.normal = -trmpoly->plane.Normal();
1037  tw->trace.c.dist = tw->trace.c.normal * v->p;
1038  tw->trace.c.contents = poly->contents;
1039  tw->trace.c.material = poly->material;
1041  tw->trace.c.modelFeature = v - tw->model->vertices;
1042  tw->trace.c.trmFeature = trmpoly - tw->polys;
1043  tw->trace.c.point = v->p;
1044  }
1045 }
1046 
1047 /*
1048 ================
1049 idCollisionModelManagerLocal::RotateTrmThroughPolygon
1050 
1051  returns true if the polygon blocks the complete rotation
1052 ================
1053 */
1055  int i, j, k, edgeNum;
1056  float d;
1057  cm_trmVertex_t *bv;
1058  cm_trmEdge_t *be;
1059  cm_trmPolygon_t *bp;
1060  cm_vertex_t *v;
1061  cm_edge_t *e;
1062  idVec3 *rotationOrigin;
1063 
1064  // if already checked this polygon
1066  return false;
1067  }
1069 
1070  // if this polygon does not have the right contents behind it
1071  if ( !(p->contents & tw->contents) ) {
1072  return false;
1073  }
1074 
1075  // if the the trace bounds do not intersect the polygon bounds
1076  if ( !tw->bounds.IntersectsBounds( p->bounds ) ) {
1077  return false;
1078  }
1079 
1080  // back face culling
1081  if ( tw->isConvex ) {
1082  // if the center of the convex trm is behind the polygon plane
1083  if ( p->plane.Distance( tw->start ) < 0.0f ) {
1084  // if the rotation axis intersects the trace model
1085  if ( tw->axisIntersectsTrm ) {
1086  return false;
1087  }
1088  else {
1089  // if the direction of motion at the start and end position of the
1090  // center of the trm both go towards or away from the polygon plane
1091  // or if the intersections of the rotation axis with the expanded heart planes
1092  // are both in front of the polygon plane
1093  }
1094  }
1095  }
1096 
1097  // if the polygon is too far from the first heart plane
1098  d = p->bounds.PlaneDistance( tw->heartPlane1 );
1099  if ( idMath::Fabs(d) > tw->maxDistFromHeartPlane1 ) {
1100  return false;
1101  }
1102 
1103  // rotation bounds should cross polygon plane
1104  switch( tw->bounds.PlaneSide( p->plane ) ) {
1105  case PLANESIDE_CROSS:
1106  break;
1107  case PLANESIDE_FRONT:
1108  if ( tw->model->isConvex ) {
1109  tw->quickExit = true;
1110  return true;
1111  }
1112  default:
1113  return false;
1114  }
1115 
1116  for ( i = 0; i < tw->numVerts; i++ ) {
1117  bv = tw->vertices + i;
1118  // calculate polygon side this vertex is on
1119  d = p->plane.Distance( bv->p );
1120  bv->polygonSide = FLOATSIGNBITSET( d );
1121  }
1122 
1123  for ( i = 0; i < p->numEdges; i++ ) {
1124  edgeNum = p->edges[i];
1125  e = tw->model->edges + abs(edgeNum);
1126  v = tw->model->vertices + e->vertexNum[INTSIGNBITSET(edgeNum)];
1127 
1128  // pluecker coordinate for edge
1130  tw->model->vertices[e->vertexNum[1]].p );
1131 
1132  // calculate rotation origin projected into rotation plane through the vertex
1133  tw->polygonRotationOriginCache[i] = tw->origin + tw->axis * ( tw->axis * ( v->p - tw->origin ) );
1134  }
1135  // copy first to last so we can easily cycle through
1137 
1138  // fast point rotation
1139  if ( tw->pointTrace ) {
1140  RotateTrmVertexThroughPolygon( tw, p, &tw->vertices[0], 0 );
1141  }
1142  else {
1143  // rotate trm vertices through polygon
1144  for ( i = 0; i < tw->numVerts; i++ ) {
1145  bv = tw->vertices + i;
1146  if ( bv->used ) {
1147  RotateTrmVertexThroughPolygon( tw, p, bv, i );
1148  }
1149  }
1150 
1151  // rotate trm edges through polygon
1152  for ( i = 1; i <= tw->numEdges; i++ ) {
1153  be = tw->edges + i;
1154  if ( be->used ) {
1155  RotateTrmEdgeThroughPolygon( tw, p, be );
1156  }
1157  }
1158 
1159  // rotate all polygon vertices through the trm
1160  for ( i = 0; i < p->numEdges; i++ ) {
1161  edgeNum = p->edges[i];
1162  e = tw->model->edges + abs(edgeNum);
1163 
1165  continue;
1166  }
1167  // set edge check count
1169  // can never collide with internal edges
1170  if ( e->internal ) {
1171  continue;
1172  }
1173  // got to check both vertices because we skip internal edges
1174  for ( k = 0; k < 2; k++ ) {
1175 
1176  v = tw->model->vertices + e->vertexNum[k ^ INTSIGNBITSET(edgeNum)];
1177 
1178  // if this vertex is already checked
1180  continue;
1181  }
1182  // set vertex check count
1184 
1185  // if the vertex is outside the trm rotation bounds
1186  if ( !tw->bounds.ContainsPoint( v->p ) ) {
1187  continue;
1188  }
1189 
1190  rotationOrigin = &tw->polygonRotationOriginCache[i+k];
1191 
1192  for ( j = 0; j < tw->numPolys; j++ ) {
1193  bp = tw->polys + j;
1194  if ( bp->used ) {
1195  RotateVertexThroughTrmPolygon( tw, bp, p, v, *rotationOrigin );
1196  }
1197  }
1198  }
1199  }
1200  }
1201 
1202  return ( tw->maxTan == 0.0f );
1203 }
1204 
1205 /*
1206 ================
1207 idCollisionModelManagerLocal::BoundsForRotation
1208 
1209  only for rotations < 180 degrees
1210 ================
1211 */
1212 void idCollisionModelManagerLocal::BoundsForRotation( const idVec3 &origin, const idVec3 &axis, const idVec3 &start, const idVec3 &end, idBounds &bounds ) {
1213  int i;
1214  float radiusSqr;
1215  idVec3 v1, v2;
1216 
1217  radiusSqr = ( start - origin ).LengthSqr();
1218  v1 = ( start - origin ).Cross( axis );
1219  v2 = ( end - origin ).Cross( axis );
1220 
1221  for ( i = 0; i < 3; i++ ) {
1222  // if the derivative changes sign along this axis during the rotation from start to end
1223  if ( ( v1[i] > 0.0f && v2[i] < 0.0f ) || ( v1[i] < 0.0f && v2[i] > 0.0f ) ) {
1224  if ( ( 0.5f * (start[i] + end[i]) - origin[i] ) > 0.0f ) {
1225  bounds[0][i] = Min( start[i], end[i] );
1226  bounds[1][i] = origin[i] + idMath::Sqrt( radiusSqr * ( 1.0f - axis[i] * axis[i] ) );
1227  }
1228  else {
1229  bounds[0][i] = origin[i] - idMath::Sqrt( radiusSqr * ( 1.0f - axis[i] * axis[i] ) );
1230  bounds[1][i] = Max( start[i], end[i] );
1231  }
1232  }
1233  else if ( start[i] > end[i] ) {
1234  bounds[0][i] = end[i];
1235  bounds[1][i] = start[i];
1236  }
1237  else {
1238  bounds[0][i] = start[i];
1239  bounds[1][i] = end[i];
1240  }
1241  // expand for epsilons
1242  bounds[0][i] -= CM_BOX_EPSILON;
1243  bounds[1][i] += CM_BOX_EPSILON;
1244  }
1245 }
1246 
1247 /*
1248 ================
1249 idCollisionModelManagerLocal::Rotation180
1250 ================
1251 */
1252 void idCollisionModelManagerLocal::Rotation180( trace_t *results, const idVec3 &rorg, const idVec3 &axis,
1253  const float startAngle, const float endAngle, const idVec3 &start,
1254  const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
1255  cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) {
1256  int i, j, edgeNum;
1257  float d, maxErr, initialTan;
1258  bool model_rotated, trm_rotated;
1259  idVec3 dir, dir1, dir2, tmp, vr, vup, org, at, bt;
1260  idMat3 invModelAxis, endAxis, tmpAxis;
1261  idRotation startRotation, endRotation;
1262  idPluecker plaxis;
1264  cm_trmEdge_t *edge;
1265  cm_trmVertex_t *vert;
1266  ALIGN16( static cm_traceWork_t tw );
1267 
1268  if ( model < 0 || model > MAX_SUBMODELS || model > idCollisionModelManagerLocal::maxModels ) {
1269  common->Printf("idCollisionModelManagerLocal::Rotation180: invalid model handle\n");
1270  return;
1271  }
1272  if ( !idCollisionModelManagerLocal::models[model] ) {
1273  common->Printf("idCollisionModelManagerLocal::Rotation180: invalid model\n");
1274  return;
1275  }
1276 
1278 
1279  tw.trace.fraction = 1.0f;
1280  tw.trace.c.contents = 0;
1281  tw.trace.c.type = CONTACT_NONE;
1282  tw.contents = contentMask;
1283  tw.isConvex = true;
1284  tw.rotation = true;
1285  tw.positionTest = false;
1286  tw.axisIntersectsTrm = false;
1287  tw.quickExit = false;
1288  tw.angle = endAngle - startAngle;
1289  assert( tw.angle > -180.0f && tw.angle < 180.0f );
1290  tw.maxTan = initialTan = idMath::Fabs( tan( ( idMath::PI / 360.0f ) * tw.angle ) );
1292  tw.start = start - modelOrigin;
1293  // rotation axis, axis is assumed to be normalized
1294  tw.axis = axis;
1295  assert( tw.axis[0] * tw.axis[0] + tw.axis[1] * tw.axis[1] + tw.axis[2] * tw.axis[2] > 0.99f );
1296  // rotation origin projected into rotation plane through tw.start
1297  tw.origin = rorg - modelOrigin;
1298  d = (tw.axis * tw.origin) - ( tw.axis * tw.start );
1299  tw.origin = tw.origin - d * tw.axis;
1300  // radius of rotation
1301  tw.radius = ( tw.start - tw.origin ).Length();
1302  // maximum error of the circle approximation traced through the axial BSP tree
1304  if ( d > 0.0f ) {
1305  maxErr = tw.radius - idMath::Sqrt( d );
1306  } else {
1307  maxErr = tw.radius;
1308  }
1309 
1310  model_rotated = modelAxis.IsRotated();
1311  if ( model_rotated ) {
1312  invModelAxis = modelAxis.Transpose();
1313  tw.axis *= invModelAxis;
1314  tw.origin *= invModelAxis;
1315  }
1316 
1317  startRotation.Set( tw.origin, tw.axis, startAngle );
1318  endRotation.Set( tw.origin, tw.axis, endAngle );
1319 
1320  // create matrix which rotates the rotation axis to the z-axis
1321  tw.axis.NormalVectors( vr, vup );
1322  tw.matrix[0][0] = vr[0];
1323  tw.matrix[1][0] = vr[1];
1324  tw.matrix[2][0] = vr[2];
1325  tw.matrix[0][1] = -vup[0];
1326  tw.matrix[1][1] = -vup[1];
1327  tw.matrix[2][1] = -vup[2];
1328  tw.matrix[0][2] = tw.axis[0];
1329  tw.matrix[1][2] = tw.axis[1];
1330  tw.matrix[2][2] = tw.axis[2];
1331 
1332  // if optimized point trace
1333  if ( !trm || ( trm->bounds[1][0] - trm->bounds[0][0] <= 0.0f &&
1334  trm->bounds[1][1] - trm->bounds[0][1] <= 0.0f &&
1335  trm->bounds[1][2] - trm->bounds[0][2] <= 0.0f ) ) {
1336 
1337  if ( model_rotated ) {
1338  // rotate trace instead of model
1339  tw.start *= invModelAxis;
1340  }
1341  tw.end = tw.start;
1342  // if we start at a specific angle
1343  if ( startAngle != 0.0f ) {
1344  startRotation.RotatePoint( tw.start );
1345  }
1346  // calculate end position of rotation
1347  endRotation.RotatePoint( tw.end );
1348 
1349  // calculate rotation origin projected into rotation plane through the vertex
1350  tw.numVerts = 1;
1351  tw.vertices[0].p = tw.start;
1352  tw.vertices[0].endp = tw.end;
1353  tw.vertices[0].used = true;
1354  tw.vertices[0].rotationOrigin = tw.origin + tw.axis * ( tw.axis * ( tw.vertices[0].p - tw.origin ) );
1356  // rotation bounds
1357  tw.bounds = tw.vertices[0].rotationBounds;
1358  tw.numEdges = tw.numPolys = 0;
1359 
1360  // collision with single point
1361  tw.pointTrace = true;
1362 
1363  // extents is set to maximum error of the circle approximation traced through the axial BSP tree
1364  tw.extents[0] = tw.extents[1] = tw.extents[2] = maxErr + CM_BOX_EPSILON;
1365 
1366  // setup rotation heart plane
1367  tw.heartPlane1.SetNormal( tw.axis );
1370 
1371  // trace through the model
1373 
1374  // store results
1375  *results = tw.trace;
1376  results->endpos = start;
1377  if ( tw.maxTan == initialTan ) {
1378  results->fraction = 1.0f;
1379  } else {
1380  results->fraction = idMath::Fabs( atan( tw.maxTan ) * ( 2.0f * 180.0f / idMath::PI ) / tw.angle );
1381  }
1382  assert( results->fraction <= 1.0f );
1383  endRotation.Set( rorg, axis, startAngle + (endAngle-startAngle) * results->fraction );
1384  endRotation.RotatePoint( results->endpos );
1385  results->endAxis.Identity();
1386 
1387  if ( results->fraction < 1.0f ) {
1388  // rotate trace plane normal if there was a collision with a rotated model
1389  if ( model_rotated ) {
1390  results->c.normal *= modelAxis;
1391  results->c.point *= modelAxis;
1392  }
1393  results->c.point += modelOrigin;
1394  results->c.dist += modelOrigin * results->c.normal;
1395  }
1396  return;
1397  }
1398 
1399  tw.pointTrace = false;
1400 
1401  // setup trm structure
1403 
1404  trm_rotated = trmAxis.IsRotated();
1405 
1406  // calculate vertex positions
1407  if ( trm_rotated ) {
1408  for ( i = 0; i < tw.numVerts; i++ ) {
1409  // rotate trm around the start position
1410  tw.vertices[i].p *= trmAxis;
1411  }
1412  }
1413  for ( i = 0; i < tw.numVerts; i++ ) {
1414  // set trm at start position
1415  tw.vertices[i].p += tw.start;
1416  }
1417  if ( model_rotated ) {
1418  for ( i = 0; i < tw.numVerts; i++ ) {
1419  tw.vertices[i].p *= invModelAxis;
1420  }
1421  }
1422  for ( i = 0; i < tw.numVerts; i++ ) {
1423  tw.vertices[i].endp = tw.vertices[i].p;
1424  }
1425  // if we start at a specific angle
1426  if ( startAngle != 0.0f ) {
1427  for ( i = 0; i < tw.numVerts; i++ ) {
1428  startRotation.RotatePoint( tw.vertices[i].p );
1429  }
1430  }
1431  for ( i = 0; i < tw.numVerts; i++ ) {
1432  // end position of vertex
1433  endRotation.RotatePoint( tw.vertices[i].endp );
1434  }
1435 
1436  // add offset to start point
1437  if ( trm_rotated ) {
1438  tw.start += trm->offset * trmAxis;
1439  } else {
1440  tw.start += trm->offset;
1441  }
1442  // if the model is rotated
1443  if ( model_rotated ) {
1444  // rotate trace instead of model
1445  tw.start *= invModelAxis;
1446  }
1447  tw.end = tw.start;
1448  // if we start at a specific angle
1449  if ( startAngle != 0.0f ) {
1450  startRotation.RotatePoint( tw.start );
1451  }
1452  // calculate end position of rotation
1453  endRotation.RotatePoint( tw.end );
1454 
1455  // setup trm vertices
1456  for ( vert = tw.vertices, i = 0; i < tw.numVerts; i++, vert++ ) {
1457  // calculate rotation origin projected into rotation plane through the vertex
1458  vert->rotationOrigin = tw.origin + tw.axis * ( tw.axis * ( vert->p - tw.origin ) );
1459  // calculate rotation bounds for this vertex
1460  BoundsForRotation( vert->rotationOrigin, tw.axis, vert->p, vert->endp, vert->rotationBounds );
1461  // if the rotation axis goes through the vertex then the vertex is not used
1462  d = ( vert->p - vert->rotationOrigin ).LengthSqr();
1464  vert->used = true;
1465  }
1466  }
1467 
1468  // setup trm edges
1469  for ( edge = tw.edges + 1, i = 1; i <= tw.numEdges; i++, edge++ ) {
1470  // if the rotation axis goes through both the edge vertices then the edge is not used
1471  if ( tw.vertices[edge->vertexNum[0]].used | tw.vertices[edge->vertexNum[1]].used ) {
1472  edge->used = true;
1473  }
1474  // edge start, end and pluecker coordinate
1475  edge->start = tw.vertices[edge->vertexNum[0]].p;
1476  edge->end = tw.vertices[edge->vertexNum[1]].p;
1477  edge->pl.FromLine( edge->start, edge->end );
1478  // pluecker coordinate for edge being rotated about the z-axis
1479  at = ( edge->start - tw.origin ) * tw.matrix;
1480  bt = ( edge->end - tw.origin ) * tw.matrix;
1481  edge->plzaxis.FromLine( at, bt );
1482  // get edge rotation bounds from the rotation bounds of both vertices
1483  edge->rotationBounds = tw.vertices[edge->vertexNum[0]].rotationBounds;
1485  // used to calculate if the rotation axis intersects the trm
1486  edge->bitNum = 0;
1487  }
1488 
1489  tw.bounds.Clear();
1490 
1491  // rotate trm polygon planes
1492  if ( trm_rotated & model_rotated ) {
1493  tmpAxis = trmAxis * invModelAxis;
1494  for ( poly = tw.polys, i = 0; i < tw.numPolys; i++, poly++ ) {
1495  poly->plane *= tmpAxis;
1496  }
1497  } else if ( trm_rotated ) {
1498  for ( poly = tw.polys, i = 0; i < tw.numPolys; i++, poly++ ) {
1499  poly->plane *= trmAxis;
1500  }
1501  } else if ( model_rotated ) {
1502  for ( poly = tw.polys, i = 0; i < tw.numPolys; i++, poly++ ) {
1503  poly->plane *= invModelAxis;
1504  }
1505  }
1506 
1507  // setup trm polygons
1508  for ( poly = tw.polys, i = 0; i < tw.numPolys; i++, poly++ ) {
1509  poly->used = true;
1510  // set trm polygon plane distance
1511  poly->plane.FitThroughPoint( tw.edges[abs(poly->edges[0])].start );
1512  // get polygon bounds from edge bounds
1513  poly->rotationBounds.Clear();
1514  for ( j = 0; j < poly->numEdges; j++ ) {
1515  // add edge rotation bounds to polygon rotation bounds
1516  edge = &tw.edges[abs( poly->edges[j] )];
1517  poly->rotationBounds.AddBounds( edge->rotationBounds );
1518  }
1519  // get trace bounds from polygon bounds
1520  tw.bounds.AddBounds( poly->rotationBounds );
1521  }
1522 
1523  // extents including the maximum error of the circle approximation traced through the axial BSP tree
1524  for ( i = 0; i < 3; i++ ) {
1525  tw.size[0][i] = tw.bounds[0][i] - tw.start[i];
1526  tw.size[1][i] = tw.bounds[1][i] - tw.start[i];
1527  if ( idMath::Fabs( tw.size[0][i] ) > idMath::Fabs( tw.size[1][i] ) ) {
1528  tw.extents[i] = idMath::Fabs( tw.size[0][i] ) + maxErr + CM_BOX_EPSILON;
1529  } else {
1530  tw.extents[i] = idMath::Fabs( tw.size[1][i] ) + maxErr + CM_BOX_EPSILON;
1531  }
1532  }
1533 
1534  // for back-face culling
1535  if ( tw.isConvex ) {
1536  if ( tw.start == tw.origin ) {
1537  tw.axisIntersectsTrm = true;
1538  } else {
1539  // determine if the rotation axis intersects the trm
1540  plaxis.FromRay( tw.origin, tw.axis );
1541  for ( poly = tw.polys, i = 0; i < tw.numPolys; i++, poly++ ) {
1542  // back face cull polygons
1543  if ( poly->plane.Normal() * tw.axis > 0.0f ) {
1544  continue;
1545  }
1546  // test if the axis goes between the polygon edges
1547  for ( j = 0; j < poly->numEdges; j++ ) {
1548  edgeNum = poly->edges[j];
1549  edge = tw.edges + abs(edgeNum);
1550  if ( !(edge->bitNum & 2) ) {
1551  d = plaxis.PermutedInnerProduct( edge->pl );
1552  edge->bitNum = FLOATSIGNBITSET( d ) | 2;
1553  }
1554  if ( ( edge->bitNum ^ INTSIGNBITSET( edgeNum ) ) & 1 ) {
1555  break;
1556  }
1557  }
1558  if ( j >= poly->numEdges ) {
1559  tw.axisIntersectsTrm = true;
1560  break;
1561  }
1562  }
1563  }
1564  }
1565 
1566  // setup rotation heart plane
1567  tw.heartPlane1.SetNormal( tw.axis );
1569  tw.maxDistFromHeartPlane1 = 0.0f;
1570  for ( i = 0; i < tw.numVerts; i++ ) {
1571  d = idMath::Fabs( tw.heartPlane1.Distance( tw.vertices[i].p ) );
1572  if ( d > tw.maxDistFromHeartPlane1 ) {
1573  tw.maxDistFromHeartPlane1 = d;
1574  }
1575  }
1577 
1578  // inverse rotation to rotate model vertices towards trace model
1579  tw.modelVertexRotation.Set( tw.origin, tw.axis, -tw.angle );
1580 
1581  // trace through the model
1583 
1584  // store results
1585  *results = tw.trace;
1586  results->endpos = start;
1587  if ( tw.maxTan == initialTan ) {
1588  results->fraction = 1.0f;
1589  } else {
1590  results->fraction = idMath::Fabs( atan( tw.maxTan ) * ( 2.0f * 180.0f / idMath::PI ) / tw.angle );
1591  }
1592  assert( results->fraction <= 1.0f );
1593  endRotation.Set( rorg, axis, startAngle + (endAngle-startAngle) * results->fraction );
1594  endRotation.RotatePoint( results->endpos );
1595  results->endAxis = trmAxis * endRotation.ToMat3();
1596 
1597  if ( results->fraction < 1.0f ) {
1598  // rotate trace plane normal if there was a collision with a rotated model
1599  if ( model_rotated ) {
1600  results->c.normal *= modelAxis;
1601  results->c.point *= modelAxis;
1602  }
1603  results->c.point += modelOrigin;
1604  results->c.dist += modelOrigin * results->c.normal;
1605  }
1606 }
1607 
1608 /*
1609 ================
1610 idCollisionModelManagerLocal::Rotation
1611 ================
1612 */
1613 #ifdef _DEBUG
1614 static int entered = 0;
1615 #endif
1616 
1618  const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
1619  cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) {
1620  idVec3 tmp;
1621  float maxa, stepa, a, lasta;
1622 
1623  assert( ((byte *)&start) < ((byte *)results) || ((byte *)&start) > (((byte *)results) + sizeof( trace_t )) );
1624  assert( ((byte *)&trmAxis) < ((byte *)results) || ((byte *)&trmAxis) > (((byte *)results) + sizeof( trace_t )) );
1625 
1626  memset( results, 0, sizeof( *results ) );
1627 
1628  // if special position test
1629  if ( rotation.GetAngle() == 0.0f ) {
1630  idCollisionModelManagerLocal::ContentsTrm( results, start, trm, trmAxis, contentMask, model, modelOrigin, modelAxis );
1631  return;
1632  }
1633 
1634 #ifdef _DEBUG
1635  bool startsolid = false;
1636  // test whether or not stuck to begin with
1637  if ( cm_debugCollision.GetBool() ) {
1638  if ( !entered ) {
1639  entered = 1;
1640  // if already messed up to begin with
1641  if ( idCollisionModelManagerLocal::Contents( start, trm, trmAxis, -1, model, modelOrigin, modelAxis ) & contentMask ) {
1642  startsolid = true;
1643  }
1644  entered = 0;
1645  }
1646  }
1647 #endif
1648 
1649  if ( rotation.GetAngle() >= 180.0f || rotation.GetAngle() <= -180.0f) {
1650  if ( rotation.GetAngle() >= 360.0f ) {
1651  maxa = 360.0f;
1652  stepa = 120.0f; // three steps strictly < 180 degrees
1653  } else if ( rotation.GetAngle() <= -360.0f ) {
1654  maxa = -360.0f;
1655  stepa = -120.0f; // three steps strictly < 180 degrees
1656  } else {
1657  maxa = rotation.GetAngle();
1658  stepa = rotation.GetAngle() * 0.5f; // two steps strictly < 180 degrees
1659  }
1660  for ( lasta = 0.0f, a = stepa; fabs( a ) < fabs( maxa ) + 1.0f; lasta = a, a += stepa ) {
1661  // partial rotation
1662  idCollisionModelManagerLocal::Rotation180( results, rotation.GetOrigin(), rotation.GetVec(), lasta, a, start, trm, trmAxis, contentMask, model, modelOrigin, modelAxis );
1663  // if there is a collision
1664  if ( results->fraction < 1.0f ) {
1665  // fraction of total rotation
1666  results->fraction = (lasta + stepa * results->fraction) / rotation.GetAngle();
1667  return;
1668  }
1669  }
1670  results->fraction = 1.0f;
1671  return;
1672  }
1673 
1674  idCollisionModelManagerLocal::Rotation180( results, rotation.GetOrigin(), rotation.GetVec(), 0.0f, rotation.GetAngle(), start, trm, trmAxis, contentMask, model, modelOrigin, modelAxis );
1675 
1676 #ifdef _DEBUG
1677  // test for missed collisions
1678  if ( cm_debugCollision.GetBool() ) {
1679  if ( !entered ) {
1680  entered = 1;
1681  // if the trm is stuck in the model
1682  if ( idCollisionModelManagerLocal::Contents( results->endpos, trm, results->endAxis, -1, model, modelOrigin, modelAxis ) & contentMask ) {
1683  trace_t tr;
1684 
1685  // test where the trm is stuck in the model
1686  idCollisionModelManagerLocal::Contents( results->endpos, trm, results->endAxis, -1, model, modelOrigin, modelAxis );
1687  // re-run collision detection to find out where it failed
1688  idCollisionModelManagerLocal::Rotation( &tr, start, rotation, trm, trmAxis, contentMask, model, modelOrigin, modelAxis );
1689  }
1690  entered = 0;
1691  }
1692  }
1693 #endif
1694 }
GLdouble GLdouble GLdouble GLdouble q
Definition: glext.h:2959
void SetupTrm(cm_traceWork_t *tw, const idTraceModel *trm)
void RotateTrmEdgeThroughPolygon(cm_traceWork_t *tw, cm_polygon_t *poly, cm_trmEdge_t *trmEdge)
bool RotateTrmThroughPolygon(cm_traceWork_t *tw, cm_polygon_t *p)
bool AddBounds(const idBounds &a)
Definition: Bounds.h:255
float Normalize(void)
Definition: Vector.h:646
assert(prefInfo.fullscreenBtn)
void Rotation180(trace_t *results, const idVec3 &rorg, const idVec3 &axis, const float startAngle, const float endAngle, const idVec3 &start, const idTraceModel *trm, const idMat3 &trmAxis, int contentMask, cmHandle_t model, const idVec3 &origin, const idMat3 &modelAxis)
const idVec3 & Normal(void) const
Definition: Plane.h:239
#define SIDE_CROSS
Definition: Plane.h:50
const GLdouble * v
Definition: glext.h:2936
ID_INLINE T Max(T x, T y)
Definition: Lib.h:158
idMat3 Transpose(void) const
Definition: Matrix.h:677
float Distance(const idVec3 &v) const
Definition: Plane.h:324
idPluecker polygonEdgePlueckerCache[CM_MAX_POLYGON_EDGES]
static const float PI
Definition: Math.h:205
idCVar cm_debugCollision("cm_debugCollision","0", CVAR_GAME|CVAR_BOOL,"debug the collision detection")
#define CM_BOX_EPSILON
unsigned short internal
Definition: Vector.h:316
static float Sqrt(float x)
Definition: Math.h:302
const idMaterial * material
contactType_t type
int ContentsTrm(trace_t *results, const idVec3 &start, const idTraceModel *trm, const idMat3 &trmAxis, int contentMask, cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis)
void Clear(void)
Definition: Bounds.h:201
int cmHandle_t
GLdouble s
Definition: glext.h:2935
void SetNormal(const idVec3 &normal)
Definition: Plane.h:233
idVec3 Cross(const idVec3 &a) const
Definition: Vector.h:619
GLfloat v0
Definition: glext.h:3606
void Identity(void)
Definition: Matrix.h:591
bool IsRotated(void) const
Definition: Matrix.h:624
int i
Definition: process.py:33
contactInfo_t c
void FromLine(const idVec3 &start, const idVec3 &end)
Definition: Pluecker.h:249
idRotation modelVertexRotation
float fraction
idVec3 endpos
#define PLANESIDE_FRONT
Definition: Plane.h:53
idVec3 offset
Definition: TraceModel.h:93
GLfloat GLfloat GLfloat v2
Definition: glext.h:3608
#define MAX_SUBMODELS
const idMaterial * material
float GetAngle(void) const
Definition: Rotation.h:154
cm_vertex_t * vertices
#define FLOATSIGNBITSET(f)
Definition: Math.h:68
const GLubyte * c
Definition: glext.h:4677
void SetDist(const float dist)
Definition: Plane.h:275
void BoundsForRotation(const idVec3 &origin, const idVec3 &axis, const idVec3 &start, const idVec3 &end, idBounds &bounds)
void Rotation(trace_t *results, const idVec3 &start, const idRotation &rotation, const idTraceModel *trm, const idMat3 &trmAxis, int contentMask, cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis)
GLuint GLuint end
Definition: glext.h:2845
cm_trmEdge_t edges[MAX_TRACEMODEL_EDGES+1]
static float Fabs(float f)
Definition: Math.h:779
#define INTSIGNBITNOTSET(i)
Definition: Math.h:72
idCommon * common
Definition: Common.cpp:206
float PlaneDistance(const idPlane &plane) const
Definition: Bounds.cpp:83
void TraceThroughModel(cm_traceWork_t *tw)
#define ROTATION_AXIS_EPSILON
void CM_RotateEdge(idVec3 &start, idVec3 &end, const idVec3 &origin, const idVec3 &axis, const float tanHalfAngle)
Definition: Plane.h:71
#define CM_CLIP_EPSILON
#define CIRCLE_APPROXIMATION_LENGTH
idMat3 endAxis
float PermutedInnerProduct(const idPluecker &a) const
Definition: Pluecker.h:316
int RotatePointThroughPlane(const cm_traceWork_t *tw, const idVec3 &point, const idPlane &plane, const float angle, const float minTan, float &tanHalfAngle)
void CM_RotatePoint(idVec3 &point, const idVec3 &origin, const idVec3 &axis, const float tanHalfAngle)
void RotateTrmVertexThroughPolygon(cm_traceWork_t *tw, cm_polygon_t *poly, cm_trmVertex_t *v, int vertexNum)
void FromRay(const idVec3 &start, const idVec3 &dir)
Definition: Pluecker.h:258
GLubyte GLubyte GLubyte a
Definition: glext.h:4662
virtual void Printf(const char *fmt,...) id_attribute((format(printf
void Set(const idVec3 &rotationOrigin, const idVec3 &rotationVec, const float rotationAngle)
Definition: Rotation.h:108
int EdgeFurthestFromEdge(cm_traceWork_t *tw, const idPluecker &pl1, const idVec3 &vc, const idVec3 &vd, float &tanHalfAngle, float &dir)
GLfloat GLfloat v1
Definition: glext.h:3607
cm_edge_t * edges
GLubyte GLubyte b
Definition: glext.h:4662
const idVec3 & GetVec(void) const
Definition: Rotation.h:150
idVec3 polygonRotationOriginCache[CM_MAX_POLYGON_EDGES]
void RotateVertexThroughTrmPolygon(cm_traceWork_t *tw, cm_trmPolygon_t *trmpoly, cm_polygon_t *poly, cm_vertex_t *v, idVec3 &rotationOrigin)
Definition: Matrix.h:333
bool GetBool(void) const
Definition: CVarSystem.h:142
#define INTSIGNBITSET(i)
Definition: Math.h:71
tuple f
Definition: idal.py:89
const idMat3 & ToMat3(void) const
Definition: Rotation.cpp:60
unsigned char byte
Definition: Lib.h:75
bool IntersectsBounds(const idBounds &a) const
Definition: Bounds.h:361
int Contents(const idVec3 &start, const idTraceModel *trm, const idMat3 &trmAxis, int contentMask, cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis)
int edges[MAX_TRACEMODEL_POLYEDGES]
idRenderSystemLocal tr
const idVec3 & GetOrigin(void) const
Definition: Rotation.h:146
unsigned short bitNum
#define PLANESIDE_CROSS
Definition: Plane.h:56
GLint j
Definition: qgl.h:264
char * va(const char *fmt,...)
Definition: Str.cpp:1568
cm_trmPolygon_t polys[MAX_TRACEMODEL_POLYS]
int PlaneSide(const idPlane &plane, const float epsilon=ON_EPSILON) const
Definition: Bounds.cpp:108
GLfloat GLfloat p
Definition: glext.h:4674
int CollisionBetweenEdgeBounds(cm_traceWork_t *tw, const idVec3 &va, const idVec3 &vb, const idVec3 &vc, const idVec3 &vd, float tanHalfAngle, idVec3 &collisionPoint, idVec3 &collisionNormal)
int RotatePointThroughEpsilonPlane(const cm_traceWork_t *tw, const idVec3 &point, const idVec3 &endPoint, const idPlane &plane, const float angle, const idVec3 &origin, float &tanHalfAngle, idVec3 &collisionPoint, idVec3 &endDir)
int RotateEdgeThroughEdge(cm_traceWork_t *tw, const idPluecker &pl1, const idVec3 &vc, const idVec3 &vd, const float minTan, float &tanHalfAngle)
int PointFurthestFromPlane(const cm_traceWork_t *tw, const idVec3 &point, const idPlane &plane, const float angle, float &tanHalfAngle, float &dir)
#define CM_PL_RANGE_EPSILON
bool ContainsPoint(const idVec3 &p) const
Definition: Bounds.h:353
ID_INLINE T Min(T x, T y)
Definition: Lib.h:159
idBounds bounds
Definition: TraceModel.h:94
void NormalVectors(idVec3 &left, idVec3 &down) const
Definition: Vector.h:727
void RotatePoint(idVec3 &point) const
Definition: Rotation.h:204
GLuint start
Definition: glext.h:2845
float Dist(void) const
Definition: Plane.h:271
cm_trmVertex_t vertices[MAX_TRACEMODEL_VERTS]
void FitThroughPoint(const idVec3 &p)
Definition: Plane.h:297
GLdouble GLdouble t
Definition: glext.h:2943