CollisionModel_trace.cpp (7817B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition 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 BFG Edition 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 #pragma hdrstop 38 #include "../idlib/precompiled.h" 39 40 41 #include "CollisionModel_local.h" 42 43 /* 44 =============================================================================== 45 46 Trace through the spatial subdivision 47 48 =============================================================================== 49 */ 50 51 /* 52 ================ 53 idCollisionModelManagerLocal::TraceTrmThroughNode 54 ================ 55 */ 56 void idCollisionModelManagerLocal::TraceTrmThroughNode( cm_traceWork_t *tw, cm_node_t *node ) { 57 cm_polygonRef_t *pref; 58 cm_brushRef_t *bref; 59 60 // position test 61 if ( tw->positionTest ) { 62 // if already stuck in solid 63 if ( tw->trace.fraction == 0.0f ) { 64 return; 65 } 66 // test if any of the trm vertices is inside a brush 67 for ( bref = node->brushes; bref; bref = bref->next ) { 68 if ( idCollisionModelManagerLocal::TestTrmVertsInBrush( tw, bref->b ) ) { 69 return; 70 } 71 } 72 // if just testing a point we're done 73 if ( tw->pointTrace ) { 74 return; 75 } 76 // test if the trm is stuck in any polygons 77 for ( pref = node->polygons; pref; pref = pref->next ) { 78 if ( idCollisionModelManagerLocal::TestTrmInPolygon( tw, pref->p ) ) { 79 return; 80 } 81 } 82 } 83 else if ( tw->rotation ) { 84 // rotate through all polygons in this leaf 85 for ( pref = node->polygons; pref; pref = pref->next ) { 86 if ( idCollisionModelManagerLocal::RotateTrmThroughPolygon( tw, pref->p ) ) { 87 return; 88 } 89 } 90 } 91 else { 92 // trace through all polygons in this leaf 93 for ( pref = node->polygons; pref; pref = pref->next ) { 94 if ( idCollisionModelManagerLocal::TranslateTrmThroughPolygon( tw, pref->p ) ) { 95 return; 96 } 97 } 98 } 99 } 100 101 /* 102 ================ 103 idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r 104 ================ 105 */ 106 //#define NO_SPATIAL_SUBDIVISION 107 108 void idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( cm_traceWork_t *tw, cm_node_t *node, float p1f, float p2f, idVec3 &p1, idVec3 &p2) { 109 float t1, t2, offset; 110 float frac, frac2; 111 float idist; 112 idVec3 mid; 113 int side; 114 float midf; 115 116 if ( !node ) { 117 return; 118 } 119 120 if ( tw->quickExit ) { 121 return; // stop immediately 122 } 123 124 if ( tw->trace.fraction <= p1f ) { 125 return; // already hit something nearer 126 } 127 128 // if we need to test this node for collisions 129 if ( node->polygons || (tw->positionTest && node->brushes) ) { 130 // trace through node with collision data 131 idCollisionModelManagerLocal::TraceTrmThroughNode( tw, node ); 132 } 133 // if already stuck in solid 134 if ( tw->positionTest && tw->trace.fraction == 0.0f ) { 135 return; 136 } 137 // if this is a leaf node 138 if ( node->planeType == -1 ) { 139 return; 140 } 141 #ifdef NO_SPATIAL_SUBDIVISION 142 idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[0], p1f, p2f, p1, p2 ); 143 idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[1], p1f, p2f, p1, p2 ); 144 return; 145 #endif 146 // distance from plane for trace start and end 147 t1 = p1[node->planeType] - node->planeDist; 148 t2 = p2[node->planeType] - node->planeDist; 149 // adjust the plane distance appropriately for mins/maxs 150 offset = tw->extents[node->planeType]; 151 // see which sides we need to consider 152 if ( t1 >= offset && t2 >= offset ) { 153 idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[0], p1f, p2f, p1, p2 ); 154 return; 155 } 156 157 if ( t1 < -offset && t2 < -offset ) { 158 idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[1], p1f, p2f, p1, p2 ); 159 return; 160 } 161 162 if ( t1 < t2 ) { 163 idist = 1.0f / (t1-t2); 164 side = 1; 165 frac2 = (t1 + offset) * idist; 166 frac = (t1 - offset) * idist; 167 } else if (t1 > t2) { 168 idist = 1.0f / (t1-t2); 169 side = 0; 170 frac2 = (t1 - offset) * idist; 171 frac = (t1 + offset) * idist; 172 } else { 173 side = 0; 174 frac = 1.0f; 175 frac2 = 0.0f; 176 } 177 178 // move up to the node 179 if ( frac < 0.0f ) { 180 frac = 0.0f; 181 } 182 else if ( frac > 1.0f ) { 183 frac = 1.0f; 184 } 185 186 midf = p1f + (p2f - p1f)*frac; 187 188 mid[0] = p1[0] + frac*(p2[0] - p1[0]); 189 mid[1] = p1[1] + frac*(p2[1] - p1[1]); 190 mid[2] = p1[2] + frac*(p2[2] - p1[2]); 191 192 idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[side], p1f, midf, p1, mid ); 193 194 195 // go past the node 196 if ( frac2 < 0.0f ) { 197 frac2 = 0.0f; 198 } 199 else if ( frac2 > 1.0f ) { 200 frac2 = 1.0f; 201 } 202 203 midf = p1f + (p2f - p1f)*frac2; 204 205 mid[0] = p1[0] + frac2*(p2[0] - p1[0]); 206 mid[1] = p1[1] + frac2*(p2[1] - p1[1]); 207 mid[2] = p1[2] + frac2*(p2[2] - p1[2]); 208 209 idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[side^1], midf, p2f, mid, p2 ); 210 } 211 212 /* 213 ================ 214 idCollisionModelManagerLocal::TraceThroughModel 215 ================ 216 */ 217 void idCollisionModelManagerLocal::TraceThroughModel( cm_traceWork_t *tw ) { 218 float d; 219 int i, numSteps; 220 idVec3 start, end; 221 idRotation rot; 222 223 if ( !tw->rotation ) { 224 // trace through spatial subdivision and then through leafs 225 idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, tw->model->node, 0, 1, tw->start, tw->end ); 226 } 227 else { 228 // approximate the rotation with a series of straight line movements 229 // total length covered along circle 230 d = tw->radius * DEG2RAD( tw->angle ); 231 // if more than one step 232 if ( d > CIRCLE_APPROXIMATION_LENGTH ) { 233 // number of steps for the approximation 234 numSteps = (int) (CIRCLE_APPROXIMATION_LENGTH / d); 235 // start of approximation 236 start = tw->start; 237 // trace circle approximation steps through the BSP tree 238 for ( i = 0; i < numSteps; i++ ) { 239 // calculate next point on approximated circle 240 rot.Set( tw->origin, tw->axis, tw->angle * ((float) (i+1) / numSteps) ); 241 end = start * rot; 242 // trace through spatial subdivision and then through leafs 243 idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, tw->model->node, 0, 1, start, end ); 244 // no need to continue if something was hit already 245 if ( tw->trace.fraction < 1.0f ) { 246 return; 247 } 248 start = end; 249 } 250 } 251 else { 252 start = tw->start; 253 } 254 // last step of the approximation 255 idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, tw->model->node, 0, 1, start, tw->end ); 256 } 257 }