00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "server.h"
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 clipHandle_t SV_ClipHandleForEntity( const sharedEntity_t *ent ) {
00036 if ( ent->r.bmodel ) {
00037
00038 return CM_InlineModel( ent->s.modelindex );
00039 }
00040 if ( ent->r.svFlags & SVF_CAPSULE ) {
00041
00042 return CM_TempBoxModel( ent->r.mins, ent->r.maxs, qtrue );
00043 }
00044
00045
00046 return CM_TempBoxModel( ent->r.mins, ent->r.maxs, qfalse );
00047 }
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064 typedef struct worldSector_s {
00065 int axis;
00066 float dist;
00067 struct worldSector_s *children[2];
00068 svEntity_t *entities;
00069 } worldSector_t;
00070
00071 #define AREA_DEPTH 4
00072 #define AREA_NODES 64
00073
00074 worldSector_t sv_worldSectors[AREA_NODES];
00075 int sv_numworldSectors;
00076
00077
00078
00079
00080
00081
00082
00083 void SV_SectorList_f( void ) {
00084 int i, c;
00085 worldSector_t *sec;
00086 svEntity_t *ent;
00087
00088 for ( i = 0 ; i < AREA_NODES ; i++ ) {
00089 sec = &sv_worldSectors[i];
00090
00091 c = 0;
00092 for ( ent = sec->entities ; ent ; ent = ent->nextEntityInWorldSector ) {
00093 c++;
00094 }
00095 Com_Printf( "sector %i: %i entities\n", i, c );
00096 }
00097 }
00098
00099
00100
00101
00102
00103
00104
00105
00106 worldSector_t *SV_CreateworldSector( int depth, vec3_t mins, vec3_t maxs ) {
00107 worldSector_t *anode;
00108 vec3_t size;
00109 vec3_t mins1, maxs1, mins2, maxs2;
00110
00111 anode = &sv_worldSectors[sv_numworldSectors];
00112 sv_numworldSectors++;
00113
00114 if (depth == AREA_DEPTH) {
00115 anode->axis = -1;
00116 anode->children[0] = anode->children[1] = NULL;
00117 return anode;
00118 }
00119
00120 VectorSubtract (maxs, mins, size);
00121 if (size[0] > size[1]) {
00122 anode->axis = 0;
00123 } else {
00124 anode->axis = 1;
00125 }
00126
00127 anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]);
00128 VectorCopy (mins, mins1);
00129 VectorCopy (mins, mins2);
00130 VectorCopy (maxs, maxs1);
00131 VectorCopy (maxs, maxs2);
00132
00133 maxs1[anode->axis] = mins2[anode->axis] = anode->dist;
00134
00135 anode->children[0] = SV_CreateworldSector (depth+1, mins2, maxs2);
00136 anode->children[1] = SV_CreateworldSector (depth+1, mins1, maxs1);
00137
00138 return anode;
00139 }
00140
00141
00142
00143
00144
00145
00146
00147 void SV_ClearWorld( void ) {
00148 clipHandle_t h;
00149 vec3_t mins, maxs;
00150
00151 Com_Memset( sv_worldSectors, 0, sizeof(sv_worldSectors) );
00152 sv_numworldSectors = 0;
00153
00154
00155 h = CM_InlineModel( 0 );
00156 CM_ModelBounds( h, mins, maxs );
00157 SV_CreateworldSector( 0, mins, maxs );
00158 }
00159
00160
00161
00162
00163
00164
00165
00166
00167 void SV_UnlinkEntity( sharedEntity_t *gEnt ) {
00168 svEntity_t *ent;
00169 svEntity_t *scan;
00170 worldSector_t *ws;
00171
00172 ent = SV_SvEntityForGentity( gEnt );
00173
00174 gEnt->r.linked = qfalse;
00175
00176 ws = ent->worldSector;
00177 if ( !ws ) {
00178 return;
00179 }
00180 ent->worldSector = NULL;
00181
00182 if ( ws->entities == ent ) {
00183 ws->entities = ent->nextEntityInWorldSector;
00184 return;
00185 }
00186
00187 for ( scan = ws->entities ; scan ; scan = scan->nextEntityInWorldSector ) {
00188 if ( scan->nextEntityInWorldSector == ent ) {
00189 scan->nextEntityInWorldSector = ent->nextEntityInWorldSector;
00190 return;
00191 }
00192 }
00193
00194 Com_Printf( "WARNING: SV_UnlinkEntity: not found in worldSector\n" );
00195 }
00196
00197
00198
00199
00200
00201
00202
00203
00204 #define MAX_TOTAL_ENT_LEAFS 128
00205 void SV_LinkEntity( sharedEntity_t *gEnt ) {
00206 worldSector_t *node;
00207 int leafs[MAX_TOTAL_ENT_LEAFS];
00208 int cluster;
00209 int num_leafs;
00210 int i, j, k;
00211 int area;
00212 int lastLeaf;
00213 float *origin, *angles;
00214 svEntity_t *ent;
00215
00216 ent = SV_SvEntityForGentity( gEnt );
00217
00218 if ( ent->worldSector ) {
00219 SV_UnlinkEntity( gEnt );
00220 }
00221
00222
00223 if ( gEnt->r.bmodel ) {
00224 gEnt->s.solid = SOLID_BMODEL;
00225 } else if ( gEnt->r.contents & ( CONTENTS_SOLID | CONTENTS_BODY ) ) {
00226
00227 i = gEnt->r.maxs[0];
00228 if (i<1)
00229 i = 1;
00230 if (i>255)
00231 i = 255;
00232
00233
00234 j = (-gEnt->r.mins[2]);
00235 if (j<1)
00236 j = 1;
00237 if (j>255)
00238 j = 255;
00239
00240
00241 k = (gEnt->r.maxs[2]+32);
00242 if (k<1)
00243 k = 1;
00244 if (k>255)
00245 k = 255;
00246
00247 gEnt->s.solid = (k<<16) | (j<<8) | i;
00248 } else {
00249 gEnt->s.solid = 0;
00250 }
00251
00252
00253 origin = gEnt->r.currentOrigin;
00254 angles = gEnt->r.currentAngles;
00255
00256
00257 if ( gEnt->r.bmodel && (angles[0] || angles[1] || angles[2]) ) {
00258
00259 float max;
00260 int i;
00261
00262 max = RadiusFromBounds( gEnt->r.mins, gEnt->r.maxs );
00263 for (i=0 ; i<3 ; i++) {
00264 gEnt->r.absmin[i] = origin[i] - max;
00265 gEnt->r.absmax[i] = origin[i] + max;
00266 }
00267 } else {
00268
00269 VectorAdd (origin, gEnt->r.mins, gEnt->r.absmin);
00270 VectorAdd (origin, gEnt->r.maxs, gEnt->r.absmax);
00271 }
00272
00273
00274
00275 gEnt->r.absmin[0] -= 1;
00276 gEnt->r.absmin[1] -= 1;
00277 gEnt->r.absmin[2] -= 1;
00278 gEnt->r.absmax[0] += 1;
00279 gEnt->r.absmax[1] += 1;
00280 gEnt->r.absmax[2] += 1;
00281
00282
00283 ent->numClusters = 0;
00284 ent->lastCluster = 0;
00285 ent->areanum = -1;
00286 ent->areanum2 = -1;
00287
00288
00289 num_leafs = CM_BoxLeafnums( gEnt->r.absmin, gEnt->r.absmax,
00290 leafs, MAX_TOTAL_ENT_LEAFS, &lastLeaf );
00291
00292
00293
00294 if ( !num_leafs ) {
00295 return;
00296 }
00297
00298
00299 for (i=0 ; i<num_leafs ; i++) {
00300 area = CM_LeafArea (leafs[i]);
00301 if (area != -1) {
00302
00303
00304 if (ent->areanum != -1 && ent->areanum != area) {
00305 if (ent->areanum2 != -1 && ent->areanum2 != area && sv.state == SS_LOADING) {
00306 Com_DPrintf ("Object %i touching 3 areas at %f %f %f\n",
00307 gEnt->s.number,
00308 gEnt->r.absmin[0], gEnt->r.absmin[1], gEnt->r.absmin[2]);
00309 }
00310 ent->areanum2 = area;
00311 } else {
00312 ent->areanum = area;
00313 }
00314 }
00315 }
00316
00317
00318 ent->numClusters = 0;
00319 for (i=0 ; i < num_leafs ; i++) {
00320 cluster = CM_LeafCluster( leafs[i] );
00321 if ( cluster != -1 ) {
00322 ent->clusternums[ent->numClusters++] = cluster;
00323 if ( ent->numClusters == MAX_ENT_CLUSTERS ) {
00324 break;
00325 }
00326 }
00327 }
00328
00329
00330 if ( i != num_leafs ) {
00331 ent->lastCluster = CM_LeafCluster( lastLeaf );
00332 }
00333
00334 gEnt->r.linkcount++;
00335
00336
00337 node = sv_worldSectors;
00338 while (1)
00339 {
00340 if (node->axis == -1)
00341 break;
00342 if ( gEnt->r.absmin[node->axis] > node->dist)
00343 node = node->children[0];
00344 else if ( gEnt->r.absmax[node->axis] < node->dist)
00345 node = node->children[1];
00346 else
00347 break;
00348 }
00349
00350
00351 ent->worldSector = node;
00352 ent->nextEntityInWorldSector = node->entities;
00353 node->entities = ent;
00354
00355 gEnt->r.linked = qtrue;
00356 }
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368 typedef struct {
00369 const float *mins;
00370 const float *maxs;
00371 int *list;
00372 int count, maxcount;
00373 } areaParms_t;
00374
00375
00376
00377
00378
00379
00380
00381
00382 void SV_AreaEntities_r( worldSector_t *node, areaParms_t *ap ) {
00383 svEntity_t *check, *next;
00384 sharedEntity_t *gcheck;
00385 int count;
00386
00387 count = 0;
00388
00389 for ( check = node->entities ; check ; check = next ) {
00390 next = check->nextEntityInWorldSector;
00391
00392 gcheck = SV_GEntityForSvEntity( check );
00393
00394 if ( gcheck->r.absmin[0] > ap->maxs[0]
00395 || gcheck->r.absmin[1] > ap->maxs[1]
00396 || gcheck->r.absmin[2] > ap->maxs[2]
00397 || gcheck->r.absmax[0] < ap->mins[0]
00398 || gcheck->r.absmax[1] < ap->mins[1]
00399 || gcheck->r.absmax[2] < ap->mins[2]) {
00400 continue;
00401 }
00402
00403 if ( ap->count == ap->maxcount ) {
00404 Com_Printf ("SV_AreaEntities: MAXCOUNT\n");
00405 return;
00406 }
00407
00408 ap->list[ap->count] = check - sv.svEntities;
00409 ap->count++;
00410 }
00411
00412 if (node->axis == -1) {
00413 return;
00414 }
00415
00416
00417 if ( ap->maxs[node->axis] > node->dist ) {
00418 SV_AreaEntities_r ( node->children[0], ap );
00419 }
00420 if ( ap->mins[node->axis] < node->dist ) {
00421 SV_AreaEntities_r ( node->children[1], ap );
00422 }
00423 }
00424
00425
00426
00427
00428
00429
00430 int SV_AreaEntities( const vec3_t mins, const vec3_t maxs, int *entityList, int maxcount ) {
00431 areaParms_t ap;
00432
00433 ap.mins = mins;
00434 ap.maxs = maxs;
00435 ap.list = entityList;
00436 ap.count = 0;
00437 ap.maxcount = maxcount;
00438
00439 SV_AreaEntities_r( sv_worldSectors, &ap );
00440
00441 return ap.count;
00442 }
00443
00444
00445
00446
00447
00448
00449 typedef struct {
00450 vec3_t boxmins, boxmaxs;
00451 const float *mins;
00452 const float *maxs;
00453 const float *start;
00454 vec3_t end;
00455 trace_t trace;
00456 int passEntityNum;
00457 int contentmask;
00458 int capsule;
00459 } moveclip_t;
00460
00461
00462
00463
00464
00465
00466
00467
00468 void SV_ClipToEntity( trace_t *trace, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int entityNum, int contentmask, int capsule ) {
00469 sharedEntity_t *touch;
00470 clipHandle_t clipHandle;
00471 float *origin, *angles;
00472
00473 touch = SV_GentityNum( entityNum );
00474
00475 Com_Memset(trace, 0, sizeof(trace_t));
00476
00477
00478
00479 if ( ! ( contentmask & touch->r.contents ) ) {
00480 trace->fraction = 1.0;
00481 return;
00482 }
00483
00484
00485 clipHandle = SV_ClipHandleForEntity (touch);
00486
00487 origin = touch->r.currentOrigin;
00488 angles = touch->r.currentAngles;
00489
00490 if ( !touch->r.bmodel ) {
00491 angles = vec3_origin;
00492 }
00493
00494 CM_TransformedBoxTrace ( trace, (float *)start, (float *)end,
00495 (float *)mins, (float *)maxs, clipHandle, contentmask,
00496 origin, angles, capsule);
00497
00498 if ( trace->fraction < 1 ) {
00499 trace->entityNum = touch->s.number;
00500 }
00501 }
00502
00503
00504
00505
00506
00507
00508
00509
00510 void SV_ClipMoveToEntities( moveclip_t *clip ) {
00511 int i, num;
00512 int touchlist[MAX_GENTITIES];
00513 sharedEntity_t *touch;
00514 int passOwnerNum;
00515 trace_t trace;
00516 clipHandle_t clipHandle;
00517 float *origin, *angles;
00518
00519 num = SV_AreaEntities( clip->boxmins, clip->boxmaxs, touchlist, MAX_GENTITIES);
00520
00521 if ( clip->passEntityNum != ENTITYNUM_NONE ) {
00522 passOwnerNum = ( SV_GentityNum( clip->passEntityNum ) )->r.ownerNum;
00523 if ( passOwnerNum == ENTITYNUM_NONE ) {
00524 passOwnerNum = -1;
00525 }
00526 } else {
00527 passOwnerNum = -1;
00528 }
00529
00530 for ( i=0 ; i<num ; i++ ) {
00531 if ( clip->trace.allsolid ) {
00532 return;
00533 }
00534 touch = SV_GentityNum( touchlist[i] );
00535
00536
00537 if ( clip->passEntityNum != ENTITYNUM_NONE ) {
00538 if ( touchlist[i] == clip->passEntityNum ) {
00539 continue;
00540 }
00541 if ( touch->r.ownerNum == clip->passEntityNum ) {
00542 continue;
00543 }
00544 if ( touch->r.ownerNum == passOwnerNum ) {
00545 continue;
00546 }
00547 }
00548
00549
00550
00551 if ( ! ( clip->contentmask & touch->r.contents ) ) {
00552 continue;
00553 }
00554
00555
00556 clipHandle = SV_ClipHandleForEntity (touch);
00557
00558 origin = touch->r.currentOrigin;
00559 angles = touch->r.currentAngles;
00560
00561
00562 if ( !touch->r.bmodel ) {
00563 angles = vec3_origin;
00564 }
00565
00566 CM_TransformedBoxTrace ( &trace, (float *)clip->start, (float *)clip->end,
00567 (float *)clip->mins, (float *)clip->maxs, clipHandle, clip->contentmask,
00568 origin, angles, clip->capsule);
00569
00570 if ( trace.allsolid ) {
00571 clip->trace.allsolid = qtrue;
00572 trace.entityNum = touch->s.number;
00573 } else if ( trace.startsolid ) {
00574 clip->trace.startsolid = qtrue;
00575 trace.entityNum = touch->s.number;
00576 }
00577
00578 if ( trace.fraction < clip->trace.fraction ) {
00579 qboolean oldStart;
00580
00581
00582 oldStart = clip->trace.startsolid;
00583
00584 trace.entityNum = touch->s.number;
00585 clip->trace = trace;
00586 clip->trace.startsolid |= oldStart;
00587 }
00588 }
00589 }
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600 void SV_Trace( trace_t *results, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask, int capsule ) {
00601 moveclip_t clip;
00602 int i;
00603
00604 if ( !mins ) {
00605 mins = vec3_origin;
00606 }
00607 if ( !maxs ) {
00608 maxs = vec3_origin;
00609 }
00610
00611 Com_Memset ( &clip, 0, sizeof ( moveclip_t ) );
00612
00613
00614 CM_BoxTrace( &clip.trace, start, end, mins, maxs, 0, contentmask, capsule );
00615 clip.trace.entityNum = clip.trace.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
00616 if ( clip.trace.fraction == 0 ) {
00617 *results = clip.trace;
00618 return;
00619 }
00620
00621 clip.contentmask = contentmask;
00622 clip.start = start;
00623
00624 VectorCopy( end, clip.end );
00625 clip.mins = mins;
00626 clip.maxs = maxs;
00627 clip.passEntityNum = passEntityNum;
00628 clip.capsule = capsule;
00629
00630
00631
00632
00633
00634 for ( i=0 ; i<3 ; i++ ) {
00635 if ( end[i] > start[i] ) {
00636 clip.boxmins[i] = clip.start[i] + clip.mins[i] - 1;
00637 clip.boxmaxs[i] = clip.end[i] + clip.maxs[i] + 1;
00638 } else {
00639 clip.boxmins[i] = clip.end[i] + clip.mins[i] - 1;
00640 clip.boxmaxs[i] = clip.start[i] + clip.maxs[i] + 1;
00641 }
00642 }
00643
00644
00645 SV_ClipMoveToEntities ( &clip );
00646
00647 *results = clip.trace;
00648 }
00649
00650
00651
00652
00653
00654
00655
00656
00657 int SV_PointContents( const vec3_t p, int passEntityNum ) {
00658 int touch[MAX_GENTITIES];
00659 sharedEntity_t *hit;
00660 int i, num;
00661 int contents, c2;
00662 clipHandle_t clipHandle;
00663 float *angles;
00664
00665
00666 contents = CM_PointContents( p, 0 );
00667
00668
00669 num = SV_AreaEntities( p, p, touch, MAX_GENTITIES );
00670
00671 for ( i=0 ; i<num ; i++ ) {
00672 if ( touch[i] == passEntityNum ) {
00673 continue;
00674 }
00675 hit = SV_GentityNum( touch[i] );
00676
00677 clipHandle = SV_ClipHandleForEntity( hit );
00678 angles = hit->s.angles;
00679 if ( !hit->r.bmodel ) {
00680 angles = vec3_origin;
00681 }
00682
00683 c2 = CM_TransformedPointContents (p, clipHandle, hit->s.origin, hit->s.angles);
00684
00685 contents |= c2;
00686 }
00687
00688 return contents;
00689 }
00690
00691