1 /* 2 Copyright (C) 1996-1997 Id Software, Inc. 3 4 This program is free software; you can redistribute it and/or 5 modify it under the terms of the GNU General Public License 6 as published by the Free Software Foundation; either version 2 7 of the License, or (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13 See the GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19 */ 20 #include "quakedef.h" 21 22 static hull_t box_hull; 23 static dclipnode_t box_clipnodes[6]; 24 static mplane_t box_planes[6]; 25 26 extern vec3_t player_mins; 27 extern vec3_t player_maxs; 28 29 /* 30 =================== 31 PM_InitBoxHull 32 33 Set up the planes and clipnodes so that the six floats of a bounding box 34 can just be stored out and get a proper hull_t structure. 35 =================== 36 */ 37 void PM_InitBoxHull (void) 38 { 39 int i; 40 int side; 41 42 box_hull.clipnodes = box_clipnodes; 43 box_hull.planes = box_planes; 44 box_hull.firstclipnode = 0; 45 box_hull.lastclipnode = 5; 46 47 for (i=0 ; i<6 ; i++) 48 { 49 box_clipnodes[i].planenum = i; 50 51 side = i&1; 52 53 box_clipnodes[i].children[side] = CONTENTS_EMPTY; 54 if (i != 5) 55 box_clipnodes[i].children[side^1] = i + 1; 56 else 57 box_clipnodes[i].children[side^1] = CONTENTS_SOLID; 58 59 box_planes[i].type = i>>1; 60 box_planes[i].normal[i>>1] = 1; 61 } 62 63 } 64 65 66 /* 67 =================== 68 PM_HullForBox 69 70 To keep everything totally uniform, bounding boxes are turned into small 71 BSP trees instead of being compared directly. 72 =================== 73 */ 74 hull_t *PM_HullForBox (vec3_t mins, vec3_t maxs) 75 { 76 box_planes[0].dist = maxs[0]; 77 box_planes[1].dist = mins[0]; 78 box_planes[2].dist = maxs[1]; 79 box_planes[3].dist = mins[1]; 80 box_planes[4].dist = maxs[2]; 81 box_planes[5].dist = mins[2]; 82 83 return &box_hull; 84 } 85 86 87 /* 88 ================== 89 PM_HullPointContents 90 91 ================== 92 */ 93 int PM_HullPointContents (hull_t *hull, int num, vec3_t p) 94 { 95 float d; 96 dclipnode_t *node; 97 mplane_t *plane; 98 99 while (num >= 0) 100 { 101 if (num < hull->firstclipnode || num > hull->lastclipnode) 102 Sys_Error ("PM_HullPointContents: bad node number"); 103 104 node = hull->clipnodes + num; 105 plane = hull->planes + node->planenum; 106 107 if (plane->type < 3) 108 d = p[plane->type] - plane->dist; 109 else 110 d = DotProduct (plane->normal, p) - plane->dist; 111 if (d < 0) 112 num = node->children[1]; 113 else 114 num = node->children[0]; 115 } 116 117 return num; 118 } 119 120 /* 121 ================== 122 PM_PointContents 123 124 ================== 125 */ 126 int PM_PointContents (vec3_t p) 127 { 128 float d; 129 dclipnode_t *node; 130 mplane_t *plane; 131 hull_t *hull; 132 int num; 133 134 hull = &pmove.physents[0].model->hulls[0]; 135 136 num = hull->firstclipnode; 137 138 while (num >= 0) 139 { 140 if (num < hull->firstclipnode || num > hull->lastclipnode) 141 Sys_Error ("PM_HullPointContents: bad node number"); 142 143 node = hull->clipnodes + num; 144 plane = hull->planes + node->planenum; 145 146 if (plane->type < 3) 147 d = p[plane->type] - plane->dist; 148 else 149 d = DotProduct (plane->normal, p) - plane->dist; 150 if (d < 0) 151 num = node->children[1]; 152 else 153 num = node->children[0]; 154 } 155 156 return num; 157 } 158 159 /* 160 =============================================================================== 161 162 LINE TESTING IN HULLS 163 164 =============================================================================== 165 */ 166 167 // 1/32 epsilon to keep floating point happy 168 #define DIST_EPSILON (0.03125) 169 170 /* 171 ================== 172 PM_RecursiveHullCheck 173 174 ================== 175 */ 176 qboolean PM_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, pmtrace_t *trace) 177 { 178 dclipnode_t *node; 179 mplane_t *plane; 180 float t1, t2; 181 float frac; 182 int i; 183 vec3_t mid; 184 int side; 185 float midf; 186 187 // check for empty 188 if (num < 0) 189 { 190 if (num != CONTENTS_SOLID) 191 { 192 trace->allsolid = false; 193 if (num == CONTENTS_EMPTY) 194 trace->inopen = true; 195 else 196 trace->inwater = true; 197 } 198 else 199 trace->startsolid = true; 200 return true; // empty 201 } 202 203 if (num < hull->firstclipnode || num > hull->lastclipnode) 204 Sys_Error ("PM_RecursiveHullCheck: bad node number"); 205 206 // 207 // find the point distances 208 // 209 node = hull->clipnodes + num; 210 plane = hull->planes + node->planenum; 211 212 if (plane->type < 3) 213 { 214 t1 = p1[plane->type] - plane->dist; 215 t2 = p2[plane->type] - plane->dist; 216 } 217 else 218 { 219 t1 = DotProduct (plane->normal, p1) - plane->dist; 220 t2 = DotProduct (plane->normal, p2) - plane->dist; 221 } 222 223 #if 1 224 if (t1 >= 0 && t2 >= 0) 225 return PM_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace); 226 if (t1 < 0 && t2 < 0) 227 return PM_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace); 228 #else 229 if ( (t1 >= DIST_EPSILON && t2 >= DIST_EPSILON) || (t2 > t1 && t1 >= 0) ) 230 return PM_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace); 231 if ( (t1 <= -DIST_EPSILON && t2 <= -DIST_EPSILON) || (t2 < t1 && t1 <= 0) ) 232 return PM_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace); 233 #endif 234 235 // put the crosspoint DIST_EPSILON pixels on the near side 236 if (t1 < 0) 237 frac = (t1 + DIST_EPSILON)/(t1-t2); 238 else 239 frac = (t1 - DIST_EPSILON)/(t1-t2); 240 if (frac < 0) 241 frac = 0; 242 if (frac > 1) 243 frac = 1; 244 245 midf = p1f + (p2f - p1f)*frac; 246 for (i=0 ; i<3 ; i++) 247 mid[i] = p1[i] + frac*(p2[i] - p1[i]); 248 249 side = (t1 < 0); 250 251 // move up to the node 252 if (!PM_RecursiveHullCheck (hull, node->children[side], p1f, midf, p1, mid, trace) ) 253 return false; 254 255 #ifdef PARANOID 256 if (PM_HullPointContents (pm_hullmodel, mid, node->children[side]) 257 == CONTENTS_SOLID) 258 { 259 Con_Printf ("mid PointInHullSolid\n"); 260 return false; 261 } 262 #endif 263 264 if (PM_HullPointContents (hull, node->children[side^1], mid) 265 != CONTENTS_SOLID) 266 // go past the node 267 return PM_RecursiveHullCheck (hull, node->children[side^1], midf, p2f, mid, p2, trace); 268 269 if (trace->allsolid) 270 return false; // never got out of the solid area 271 272 //================== 273 // the other side of the node is solid, this is the impact point 274 //================== 275 if (!side) 276 { 277 VectorCopy (plane->normal, trace->plane.normal); 278 trace->plane.dist = plane->dist; 279 } 280 else 281 { 282 VectorSubtract (vec3_origin, plane->normal, trace->plane.normal); 283 trace->plane.dist = -plane->dist; 284 } 285 286 while (PM_HullPointContents (hull, hull->firstclipnode, mid) 287 == CONTENTS_SOLID) 288 { // shouldn't really happen, but does occasionally 289 frac -= 0.1; 290 if (frac < 0) 291 { 292 trace->fraction = midf; 293 VectorCopy (mid, trace->endpos); 294 Con_DPrintf ("backup past 0\n"); 295 return false; 296 } 297 midf = p1f + (p2f - p1f)*frac; 298 for (i=0 ; i<3 ; i++) 299 mid[i] = p1[i] + frac*(p2[i] - p1[i]); 300 } 301 302 trace->fraction = midf; 303 VectorCopy (mid, trace->endpos); 304 305 return false; 306 } 307 308 309 /* 310 ================ 311 PM_TestPlayerPosition 312 313 Returns false if the given player position is not valid (in solid) 314 ================ 315 */ 316 qboolean PM_TestPlayerPosition (vec3_t pos) 317 { 318 int i; 319 physent_t *pe; 320 vec3_t mins, maxs, test; 321 hull_t *hull; 322 323 for (i=0 ; i< pmove.numphysent ; i++) 324 { 325 pe = &pmove.physents[i]; 326 // get the clipping hull 327 if (pe->model) 328 hull = &pmove.physents[i].model->hulls[1]; 329 else 330 { 331 VectorSubtract (pe->mins, player_maxs, mins); 332 VectorSubtract (pe->maxs, player_mins, maxs); 333 hull = PM_HullForBox (mins, maxs); 334 } 335 336 VectorSubtract (pos, pe->origin, test); 337 338 if (PM_HullPointContents (hull, hull->firstclipnode, test) == CONTENTS_SOLID) 339 return false; 340 } 341 342 return true; 343 } 344 345 /* 346 ================ 347 PM_PlayerMove 348 ================ 349 */ 350 pmtrace_t PM_PlayerMove (vec3_t start, vec3_t end) 351 { 352 pmtrace_t trace, total; 353 vec3_t offset; 354 vec3_t start_l, end_l; 355 hull_t *hull; 356 int i; 357 physent_t *pe; 358 vec3_t mins, maxs; 359 360 // fill in a default trace 361 memset (&total, 0, sizeof(pmtrace_t)); 362 total.fraction = 1; 363 total.ent = -1; 364 VectorCopy (end, total.endpos); 365 366 for (i=0 ; i< pmove.numphysent ; i++) 367 { 368 pe = &pmove.physents[i]; 369 // get the clipping hull 370 if (pe->model) 371 hull = &pmove.physents[i].model->hulls[1]; 372 else 373 { 374 VectorSubtract (pe->mins, player_maxs, mins); 375 VectorSubtract (pe->maxs, player_mins, maxs); 376 hull = PM_HullForBox (mins, maxs); 377 } 378 379 // PM_HullForEntity (ent, mins, maxs, offset); 380 VectorCopy (pe->origin, offset); 381 382 VectorSubtract (start, offset, start_l); 383 VectorSubtract (end, offset, end_l); 384 385 // fill in a default trace 386 memset (&trace, 0, sizeof(pmtrace_t)); 387 trace.fraction = 1; 388 trace.allsolid = true; 389 // trace.startsolid = true; 390 VectorCopy (end, trace.endpos); 391 392 // trace a line through the apropriate clipping hull 393 PM_RecursiveHullCheck (hull, hull->firstclipnode, 0, 1, start_l, end_l, &trace); 394 395 if (trace.allsolid) 396 trace.startsolid = true; 397 if (trace.startsolid) 398 trace.fraction = 0; 399 400 // did we clip the move? 401 if (trace.fraction < total.fraction) 402 { 403 // fix trace up by the offset 404 VectorAdd (trace.endpos, offset, trace.endpos); 405 total = trace; 406 total.ent = i; 407 } 408 409 } 410 411 return total; 412 } 413 414 415