cm_test.c (9848B)
1 /* 2 =========================================================================== 3 Copyright (C) 1999-2005 Id Software, Inc. 4 5 This file is part of Quake III Arena source code. 6 7 Quake III Arena source code is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the License, 10 or (at your option) any later version. 11 12 Quake III Arena source code is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 #include "cm_local.h" 23 24 25 /* 26 ================== 27 CM_PointLeafnum_r 28 29 ================== 30 */ 31 int CM_PointLeafnum_r( const vec3_t p, int num ) { 32 float d; 33 cNode_t *node; 34 cplane_t *plane; 35 36 while (num >= 0) 37 { 38 node = cm.nodes + num; 39 plane = node->plane; 40 41 if (plane->type < 3) 42 d = p[plane->type] - plane->dist; 43 else 44 d = DotProduct (plane->normal, p) - plane->dist; 45 if (d < 0) 46 num = node->children[1]; 47 else 48 num = node->children[0]; 49 } 50 51 c_pointcontents++; // optimize counter 52 53 return -1 - num; 54 } 55 56 int CM_PointLeafnum( const vec3_t p ) { 57 if ( !cm.numNodes ) { // map not loaded 58 return 0; 59 } 60 return CM_PointLeafnum_r (p, 0); 61 } 62 63 64 /* 65 ====================================================================== 66 67 LEAF LISTING 68 69 ====================================================================== 70 */ 71 72 73 void CM_StoreLeafs( leafList_t *ll, int nodenum ) { 74 int leafNum; 75 76 leafNum = -1 - nodenum; 77 78 // store the lastLeaf even if the list is overflowed 79 if ( cm.leafs[ leafNum ].cluster != -1 ) { 80 ll->lastLeaf = leafNum; 81 } 82 83 if ( ll->count >= ll->maxcount) { 84 ll->overflowed = qtrue; 85 return; 86 } 87 ll->list[ ll->count++ ] = leafNum; 88 } 89 90 void CM_StoreBrushes( leafList_t *ll, int nodenum ) { 91 int i, k; 92 int leafnum; 93 int brushnum; 94 cLeaf_t *leaf; 95 cbrush_t *b; 96 97 leafnum = -1 - nodenum; 98 99 leaf = &cm.leafs[leafnum]; 100 101 for ( k = 0 ; k < leaf->numLeafBrushes ; k++ ) { 102 brushnum = cm.leafbrushes[leaf->firstLeafBrush+k]; 103 b = &cm.brushes[brushnum]; 104 if ( b->checkcount == cm.checkcount ) { 105 continue; // already checked this brush in another leaf 106 } 107 b->checkcount = cm.checkcount; 108 for ( i = 0 ; i < 3 ; i++ ) { 109 if ( b->bounds[0][i] >= ll->bounds[1][i] || b->bounds[1][i] <= ll->bounds[0][i] ) { 110 break; 111 } 112 } 113 if ( i != 3 ) { 114 continue; 115 } 116 if ( ll->count >= ll->maxcount) { 117 ll->overflowed = qtrue; 118 return; 119 } 120 ((cbrush_t **)ll->list)[ ll->count++ ] = b; 121 } 122 #if 0 123 // store patches? 124 for ( k = 0 ; k < leaf->numLeafSurfaces ; k++ ) { 125 patch = cm.surfaces[ cm.leafsurfaces[ leaf->firstleafsurface + k ] ]; 126 if ( !patch ) { 127 continue; 128 } 129 } 130 #endif 131 } 132 133 /* 134 ============= 135 CM_BoxLeafnums 136 137 Fills in a list of all the leafs touched 138 ============= 139 */ 140 void CM_BoxLeafnums_r( leafList_t *ll, int nodenum ) { 141 cplane_t *plane; 142 cNode_t *node; 143 int s; 144 145 while (1) { 146 if (nodenum < 0) { 147 ll->storeLeafs( ll, nodenum ); 148 return; 149 } 150 151 node = &cm.nodes[nodenum]; 152 plane = node->plane; 153 s = BoxOnPlaneSide( ll->bounds[0], ll->bounds[1], plane ); 154 if (s == 1) { 155 nodenum = node->children[0]; 156 } else if (s == 2) { 157 nodenum = node->children[1]; 158 } else { 159 // go down both 160 CM_BoxLeafnums_r( ll, node->children[0] ); 161 nodenum = node->children[1]; 162 } 163 164 } 165 } 166 167 /* 168 ================== 169 CM_BoxLeafnums 170 ================== 171 */ 172 int CM_BoxLeafnums( const vec3_t mins, const vec3_t maxs, int *list, int listsize, int *lastLeaf) { 173 leafList_t ll; 174 175 cm.checkcount++; 176 177 VectorCopy( mins, ll.bounds[0] ); 178 VectorCopy( maxs, ll.bounds[1] ); 179 ll.count = 0; 180 ll.maxcount = listsize; 181 ll.list = list; 182 ll.storeLeafs = CM_StoreLeafs; 183 ll.lastLeaf = 0; 184 ll.overflowed = qfalse; 185 186 CM_BoxLeafnums_r( &ll, 0 ); 187 188 *lastLeaf = ll.lastLeaf; 189 return ll.count; 190 } 191 192 /* 193 ================== 194 CM_BoxBrushes 195 ================== 196 */ 197 int CM_BoxBrushes( const vec3_t mins, const vec3_t maxs, cbrush_t **list, int listsize ) { 198 leafList_t ll; 199 200 cm.checkcount++; 201 202 VectorCopy( mins, ll.bounds[0] ); 203 VectorCopy( maxs, ll.bounds[1] ); 204 ll.count = 0; 205 ll.maxcount = listsize; 206 ll.list = (void *)list; 207 ll.storeLeafs = CM_StoreBrushes; 208 ll.lastLeaf = 0; 209 ll.overflowed = qfalse; 210 211 CM_BoxLeafnums_r( &ll, 0 ); 212 213 return ll.count; 214 } 215 216 217 //==================================================================== 218 219 220 /* 221 ================== 222 CM_PointContents 223 224 ================== 225 */ 226 int CM_PointContents( const vec3_t p, clipHandle_t model ) { 227 int leafnum; 228 int i, k; 229 int brushnum; 230 cLeaf_t *leaf; 231 cbrush_t *b; 232 int contents; 233 float d; 234 cmodel_t *clipm; 235 236 if (!cm.numNodes) { // map not loaded 237 return 0; 238 } 239 240 if ( model ) { 241 clipm = CM_ClipHandleToModel( model ); 242 leaf = &clipm->leaf; 243 } else { 244 leafnum = CM_PointLeafnum_r (p, 0); 245 leaf = &cm.leafs[leafnum]; 246 } 247 248 contents = 0; 249 for (k=0 ; k<leaf->numLeafBrushes ; k++) { 250 brushnum = cm.leafbrushes[leaf->firstLeafBrush+k]; 251 b = &cm.brushes[brushnum]; 252 253 // see if the point is in the brush 254 for ( i = 0 ; i < b->numsides ; i++ ) { 255 d = DotProduct( p, b->sides[i].plane->normal ); 256 // FIXME test for Cash 257 // if ( d >= b->sides[i].plane->dist ) { 258 if ( d > b->sides[i].plane->dist ) { 259 break; 260 } 261 } 262 263 if ( i == b->numsides ) { 264 contents |= b->contents; 265 } 266 } 267 268 return contents; 269 } 270 271 /* 272 ================== 273 CM_TransformedPointContents 274 275 Handles offseting and rotation of the end points for moving and 276 rotating entities 277 ================== 278 */ 279 int CM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles) { 280 vec3_t p_l; 281 vec3_t temp; 282 vec3_t forward, right, up; 283 284 // subtract origin offset 285 VectorSubtract (p, origin, p_l); 286 287 // rotate start and end into the models frame of reference 288 if ( model != BOX_MODEL_HANDLE && 289 (angles[0] || angles[1] || angles[2]) ) 290 { 291 AngleVectors (angles, forward, right, up); 292 293 VectorCopy (p_l, temp); 294 p_l[0] = DotProduct (temp, forward); 295 p_l[1] = -DotProduct (temp, right); 296 p_l[2] = DotProduct (temp, up); 297 } 298 299 return CM_PointContents( p_l, model ); 300 } 301 302 303 304 /* 305 =============================================================================== 306 307 PVS 308 309 =============================================================================== 310 */ 311 312 byte *CM_ClusterPVS (int cluster) { 313 if (cluster < 0 || cluster >= cm.numClusters || !cm.vised ) { 314 return cm.visibility; 315 } 316 317 return cm.visibility + cluster * cm.clusterBytes; 318 } 319 320 321 322 /* 323 =============================================================================== 324 325 AREAPORTALS 326 327 =============================================================================== 328 */ 329 330 void CM_FloodArea_r( int areaNum, int floodnum) { 331 int i; 332 cArea_t *area; 333 int *con; 334 335 area = &cm.areas[ areaNum ]; 336 337 if ( area->floodvalid == cm.floodvalid ) { 338 if (area->floodnum == floodnum) 339 return; 340 Com_Error (ERR_DROP, "FloodArea_r: reflooded"); 341 } 342 343 area->floodnum = floodnum; 344 area->floodvalid = cm.floodvalid; 345 con = cm.areaPortals + areaNum * cm.numAreas; 346 for ( i=0 ; i < cm.numAreas ; i++ ) { 347 if ( con[i] > 0 ) { 348 CM_FloodArea_r( i, floodnum ); 349 } 350 } 351 } 352 353 /* 354 ==================== 355 CM_FloodAreaConnections 356 357 ==================== 358 */ 359 void CM_FloodAreaConnections( void ) { 360 int i; 361 cArea_t *area; 362 int floodnum; 363 364 // all current floods are now invalid 365 cm.floodvalid++; 366 floodnum = 0; 367 368 for (i = 0 ; i < cm.numAreas ; i++) { 369 area = &cm.areas[i]; 370 if (area->floodvalid == cm.floodvalid) { 371 continue; // already flooded into 372 } 373 floodnum++; 374 CM_FloodArea_r (i, floodnum); 375 } 376 377 } 378 379 /* 380 ==================== 381 CM_AdjustAreaPortalState 382 383 ==================== 384 */ 385 void CM_AdjustAreaPortalState( int area1, int area2, qboolean open ) { 386 if ( area1 < 0 || area2 < 0 ) { 387 return; 388 } 389 390 if ( area1 >= cm.numAreas || area2 >= cm.numAreas ) { 391 Com_Error (ERR_DROP, "CM_ChangeAreaPortalState: bad area number"); 392 } 393 394 if ( open ) { 395 cm.areaPortals[ area1 * cm.numAreas + area2 ]++; 396 cm.areaPortals[ area2 * cm.numAreas + area1 ]++; 397 } else { 398 cm.areaPortals[ area1 * cm.numAreas + area2 ]--; 399 cm.areaPortals[ area2 * cm.numAreas + area1 ]--; 400 if ( cm.areaPortals[ area2 * cm.numAreas + area1 ] < 0 ) { 401 Com_Error (ERR_DROP, "CM_AdjustAreaPortalState: negative reference count"); 402 } 403 } 404 405 CM_FloodAreaConnections (); 406 } 407 408 /* 409 ==================== 410 CM_AreasConnected 411 412 ==================== 413 */ 414 qboolean CM_AreasConnected( int area1, int area2 ) { 415 #ifndef BSPC 416 if ( cm_noAreas->integer ) { 417 return qtrue; 418 } 419 #endif 420 421 if ( area1 < 0 || area2 < 0 ) { 422 return qfalse; 423 } 424 425 if (area1 >= cm.numAreas || area2 >= cm.numAreas) { 426 Com_Error (ERR_DROP, "area >= cm.numAreas"); 427 } 428 429 if (cm.areas[area1].floodnum == cm.areas[area2].floodnum) { 430 return qtrue; 431 } 432 return qfalse; 433 } 434 435 436 /* 437 ================= 438 CM_WriteAreaBits 439 440 Writes a bit vector of all the areas 441 that are in the same flood as the area parameter 442 Returns the number of bytes needed to hold all the bits. 443 444 The bits are OR'd in, so you can CM_WriteAreaBits from multiple 445 viewpoints and get the union of all visible areas. 446 447 This is used to cull non-visible entities from snapshots 448 ================= 449 */ 450 int CM_WriteAreaBits (byte *buffer, int area) 451 { 452 int i; 453 int floodnum; 454 int bytes; 455 456 bytes = (cm.numAreas+7)>>3; 457 458 #ifndef BSPC 459 if (cm_noAreas->integer || area == -1) 460 #else 461 if ( area == -1) 462 #endif 463 { // for debugging, send everything 464 Com_Memset (buffer, 255, bytes); 465 } 466 else 467 { 468 floodnum = cm.areas[area].floodnum; 469 for (i=0 ; i<cm.numAreas ; i++) 470 { 471 if (cm.areas[i].floodnum == floodnum || area == -1) 472 buffer[i>>3] |= 1<<(i&7); 473 } 474 } 475 476 return bytes; 477 } 478