CollisionModel_trace.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. 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.
  17. 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.
  18. ===========================================================================
  19. */
  20. /*
  21. ===============================================================================
  22. Trace model vs. polygonal model collision detection.
  23. ===============================================================================
  24. */
  25. #include "../idlib/precompiled.h"
  26. #pragma hdrstop
  27. #include "CollisionModel_local.h"
  28. /*
  29. ===============================================================================
  30. Trace through the spatial subdivision
  31. ===============================================================================
  32. */
  33. /*
  34. ================
  35. idCollisionModelManagerLocal::TraceTrmThroughNode
  36. ================
  37. */
  38. void idCollisionModelManagerLocal::TraceTrmThroughNode( cm_traceWork_t *tw, cm_node_t *node ) {
  39. cm_polygonRef_t *pref;
  40. cm_brushRef_t *bref;
  41. // position test
  42. if ( tw->positionTest ) {
  43. // if already stuck in solid
  44. if ( tw->trace.fraction == 0.0f ) {
  45. return;
  46. }
  47. // test if any of the trm vertices is inside a brush
  48. for ( bref = node->brushes; bref; bref = bref->next ) {
  49. if ( idCollisionModelManagerLocal::TestTrmVertsInBrush( tw, bref->b ) ) {
  50. return;
  51. }
  52. }
  53. // if just testing a point we're done
  54. if ( tw->pointTrace ) {
  55. return;
  56. }
  57. // test if the trm is stuck in any polygons
  58. for ( pref = node->polygons; pref; pref = pref->next ) {
  59. if ( idCollisionModelManagerLocal::TestTrmInPolygon( tw, pref->p ) ) {
  60. return;
  61. }
  62. }
  63. }
  64. else if ( tw->rotation ) {
  65. // rotate through all polygons in this leaf
  66. for ( pref = node->polygons; pref; pref = pref->next ) {
  67. if ( idCollisionModelManagerLocal::RotateTrmThroughPolygon( tw, pref->p ) ) {
  68. return;
  69. }
  70. }
  71. }
  72. else {
  73. // trace through all polygons in this leaf
  74. for ( pref = node->polygons; pref; pref = pref->next ) {
  75. if ( idCollisionModelManagerLocal::TranslateTrmThroughPolygon( tw, pref->p ) ) {
  76. return;
  77. }
  78. }
  79. }
  80. }
  81. /*
  82. ================
  83. idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r
  84. ================
  85. */
  86. //#define NO_SPATIAL_SUBDIVISION
  87. void idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( cm_traceWork_t *tw, cm_node_t *node, float p1f, float p2f, idVec3 &p1, idVec3 &p2) {
  88. float t1, t2, offset;
  89. float frac, frac2;
  90. float idist;
  91. idVec3 mid;
  92. int side;
  93. float midf;
  94. if ( !node ) {
  95. return;
  96. }
  97. if ( tw->quickExit ) {
  98. return; // stop immediately
  99. }
  100. if ( tw->trace.fraction <= p1f ) {
  101. return; // already hit something nearer
  102. }
  103. // if we need to test this node for collisions
  104. if ( node->polygons || (tw->positionTest && node->brushes) ) {
  105. // trace through node with collision data
  106. idCollisionModelManagerLocal::TraceTrmThroughNode( tw, node );
  107. }
  108. // if already stuck in solid
  109. if ( tw->positionTest && tw->trace.fraction == 0.0f ) {
  110. return;
  111. }
  112. // if this is a leaf node
  113. if ( node->planeType == -1 ) {
  114. return;
  115. }
  116. #ifdef NO_SPATIAL_SUBDIVISION
  117. idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[0], p1f, p2f, p1, p2 );
  118. idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[1], p1f, p2f, p1, p2 );
  119. return;
  120. #endif
  121. // distance from plane for trace start and end
  122. t1 = p1[node->planeType] - node->planeDist;
  123. t2 = p2[node->planeType] - node->planeDist;
  124. // adjust the plane distance appropriately for mins/maxs
  125. offset = tw->extents[node->planeType];
  126. // see which sides we need to consider
  127. if ( t1 >= offset && t2 >= offset ) {
  128. idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[0], p1f, p2f, p1, p2 );
  129. return;
  130. }
  131. if ( t1 < -offset && t2 < -offset ) {
  132. idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[1], p1f, p2f, p1, p2 );
  133. return;
  134. }
  135. if ( t1 < t2 ) {
  136. idist = 1.0f / (t1-t2);
  137. side = 1;
  138. frac2 = (t1 + offset) * idist;
  139. frac = (t1 - offset) * idist;
  140. } else if (t1 > t2) {
  141. idist = 1.0f / (t1-t2);
  142. side = 0;
  143. frac2 = (t1 - offset) * idist;
  144. frac = (t1 + offset) * idist;
  145. } else {
  146. side = 0;
  147. frac = 1.0f;
  148. frac2 = 0.0f;
  149. }
  150. // move up to the node
  151. if ( frac < 0.0f ) {
  152. frac = 0.0f;
  153. }
  154. else if ( frac > 1.0f ) {
  155. frac = 1.0f;
  156. }
  157. midf = p1f + (p2f - p1f)*frac;
  158. mid[0] = p1[0] + frac*(p2[0] - p1[0]);
  159. mid[1] = p1[1] + frac*(p2[1] - p1[1]);
  160. mid[2] = p1[2] + frac*(p2[2] - p1[2]);
  161. idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[side], p1f, midf, p1, mid );
  162. // go past the node
  163. if ( frac2 < 0.0f ) {
  164. frac2 = 0.0f;
  165. }
  166. else if ( frac2 > 1.0f ) {
  167. frac2 = 1.0f;
  168. }
  169. midf = p1f + (p2f - p1f)*frac2;
  170. mid[0] = p1[0] + frac2*(p2[0] - p1[0]);
  171. mid[1] = p1[1] + frac2*(p2[1] - p1[1]);
  172. mid[2] = p1[2] + frac2*(p2[2] - p1[2]);
  173. idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[side^1], midf, p2f, mid, p2 );
  174. }
  175. /*
  176. ================
  177. idCollisionModelManagerLocal::TraceThroughModel
  178. ================
  179. */
  180. void idCollisionModelManagerLocal::TraceThroughModel( cm_traceWork_t *tw ) {
  181. float d;
  182. int i, numSteps;
  183. idVec3 start, end;
  184. idRotation rot;
  185. if ( !tw->rotation ) {
  186. // trace through spatial subdivision and then through leafs
  187. idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, tw->model->node, 0, 1, tw->start, tw->end );
  188. }
  189. else {
  190. // approximate the rotation with a series of straight line movements
  191. // total length covered along circle
  192. d = tw->radius * DEG2RAD( tw->angle );
  193. // if more than one step
  194. if ( d > CIRCLE_APPROXIMATION_LENGTH ) {
  195. // number of steps for the approximation
  196. numSteps = (int) (CIRCLE_APPROXIMATION_LENGTH / d);
  197. // start of approximation
  198. start = tw->start;
  199. // trace circle approximation steps through the BSP tree
  200. for ( i = 0; i < numSteps; i++ ) {
  201. // calculate next point on approximated circle
  202. rot.Set( tw->origin, tw->axis, tw->angle * ((float) (i+1) / numSteps) );
  203. end = start * rot;
  204. // trace through spatial subdivision and then through leafs
  205. idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, tw->model->node, 0, 1, start, end );
  206. // no need to continue if something was hit already
  207. if ( tw->trace.fraction < 1.0f ) {
  208. return;
  209. }
  210. start = end;
  211. }
  212. }
  213. else {
  214. start = tw->start;
  215. }
  216. // last step of the approximation
  217. idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, tw->model->node, 0, 1, start, tw->end );
  218. }
  219. }