static inline int TV_Module_CM_BoxLeafnums( relay_t *relay, vec3_t mins, vec3_t maxs, int *list, int listsize, int *topnode ) { if( !relay ) { Com_Printf( "Error: TV_Module_CM_BoxLeafnums: Relay not set\n" ); return 0; } return CM_BoxLeafnums( relay->cms, mins, maxs, list, listsize, topnode ); }
/* * CM_MergePVS * Merge PVS at origin into out */ void CM_MergePVS( cmodel_state_t *cms, vec3_t org, qbyte *out ) { int leafs[128]; int i, j, count; int longs; qbyte *src; vec3_t mins, maxs; for( i = 0; i < 3; i++ ) { mins[i] = org[i] - 9; maxs[i] = org[i] + 9; } count = CM_BoxLeafnums( cms, mins, maxs, leafs, sizeof( leafs )/sizeof( int ), NULL ); if( count < 1 ) Com_Error( ERR_FATAL, "CM_MergePVS: count < 1" ); longs = CM_ClusterRowLongs( cms ); // convert leafs to clusters for( i = 0; i < count; i++ ) leafs[i] = CM_LeafCluster( cms, leafs[i] ); // or in all the other leaf bits for( i = 0; i < count; i++ ) { for( j = 0; j < i; j++ ) if( leafs[i] == leafs[j] ) break; if( j != i ) continue; // already have the cluster we want src = CM_ClusterPVS( cms, leafs[i] ); for( j = 0; j < longs; j++ ) ( (int *)out )[j] |= ( (int *)src )[j]; } }
void SV_LinkEntity( sharedEntity_t *gEnt ) { worldSector_t *node; int leafs[MAX_TOTAL_ENT_LEAFS]; int cluster; int num_leafs; int i, j, k; int area; int lastLeaf; float *origin, *angles; svEntity_t *ent; ent = SV_SvEntityForGentity( gEnt ); if ( ent->worldSector ) { SV_UnlinkEntity( gEnt ); // unlink from old position } // encode the size into the entityState_t for client prediction if ( gEnt->r.bmodel ) { gEnt->s.solid = SOLID_BMODEL; // a solid_box will never create this value } else if ( gEnt->r.contents & ( CONTENTS_SOLID | CONTENTS_BODY ) ) { // assume that x/y are equal and symetric i = gEnt->r.maxs[0]; if (i<1) i = 1; if (i>255) i = 255; // z is not symetric j = (-gEnt->r.mins[2]); if (j<1) j = 1; if (j>255) j = 255; // and z maxs can be negative... k = (gEnt->r.maxs[2]+32); if (k<1) k = 1; if (k>255) k = 255; gEnt->s.solid = (k<<16) | (j<<8) | i; } else { gEnt->s.solid = 0; } // get the position origin = gEnt->r.currentOrigin; angles = gEnt->r.currentAngles; // set the abs box if ( gEnt->r.bmodel && (angles[0] || angles[1] || angles[2]) ) { // expand for rotation float max; int i; max = RadiusFromBounds( gEnt->r.mins, gEnt->r.maxs ); for (i=0 ; i<3 ; i++) { gEnt->r.absmin[i] = origin[i] - max; gEnt->r.absmax[i] = origin[i] + max; } } else { // normal VectorAdd (origin, gEnt->r.mins, gEnt->r.absmin); VectorAdd (origin, gEnt->r.maxs, gEnt->r.absmax); } // because movement is clipped an epsilon away from an actual edge, // we must fully check even when bounding boxes don't quite touch gEnt->r.absmin[0] -= 1; gEnt->r.absmin[1] -= 1; gEnt->r.absmin[2] -= 1; gEnt->r.absmax[0] += 1; gEnt->r.absmax[1] += 1; gEnt->r.absmax[2] += 1; // link to PVS leafs ent->numClusters = 0; ent->lastCluster = 0; ent->areanum = -1; ent->areanum2 = -1; //get all leafs, including solids num_leafs = CM_BoxLeafnums( gEnt->r.absmin, gEnt->r.absmax, leafs, MAX_TOTAL_ENT_LEAFS, &lastLeaf ); // if none of the leafs were inside the map, the // entity is outside the world and can be considered unlinked if ( !num_leafs ) { return; } // set areas, even from clusters that don't fit in the entity array for (i=0 ; i<num_leafs ; i++) { area = CM_LeafArea (leafs[i]); if (area != -1) { // doors may legally straggle two areas, // but nothing should evern need more than that if (ent->areanum != -1 && ent->areanum != area) { if (ent->areanum2 != -1 && ent->areanum2 != area && sv.state == SS_LOADING) { Com_DPrintf ("Object %i touching 3 areas at %f %f %f\n", gEnt->s.number, gEnt->r.absmin[0], gEnt->r.absmin[1], gEnt->r.absmin[2]); } ent->areanum2 = area; } else { ent->areanum = area; } } } // store as many explicit clusters as we can ent->numClusters = 0; for (i=0 ; i < num_leafs ; i++) { cluster = CM_LeafCluster( leafs[i] ); if ( cluster != -1 ) { ent->clusternums[ent->numClusters++] = cluster; if ( ent->numClusters == MAX_ENT_CLUSTERS ) { break; } } } // store off a last cluster if we need to if ( i != num_leafs ) { ent->lastCluster = CM_LeafCluster( lastLeaf ); } gEnt->r.linkcount++; // find the first world sector node that the ent's box crosses node = sv_worldSectors; while (1) { if (node->axis == -1) break; if ( gEnt->r.absmin[node->axis] > node->dist) node = node->children[0]; else if ( gEnt->r.absmax[node->axis] < node->dist) node = node->children[1]; else break; // crosses the node } // link it in ent->worldSector = node; ent->nextEntityInWorldSector = node->entities; node->entities = ent; gEnt->r.linked = qtrue; }
void SV_LinkEdict (edict_t *ent) { areanode_t *node; int leafs[MAX_TOTAL_ENT_LEAFS]; int clusters[MAX_TOTAL_ENT_LEAFS]; int num_leafs; int i, j, k; int area; int topnode; if (ent->area.prev) SV_UnlinkEdict (ent); // unlink from old position if (ent == ge->edicts) return; // don't add the world if (!ent->inuse) return; // set the size VectorSubtract (ent->maxs, ent->mins, ent->size); // encode the size into the entity_state for client prediction if (ent->solid == SOLID_BBOX && !(ent->svflags & SVF_DEADMONSTER)) { // assume that x/y are equal and symetric i = ent->maxs[0]/8; if (i<1) i = 1; if (i>31) i = 31; // z is not symetric j = (-ent->mins[2])/8; if (j<1) j = 1; if (j>31) j = 31; // and z maxs can be negative... k = (ent->maxs[2]+32)/8; if (k<1) k = 1; if (k>63) k = 63; ent->s.solid = (k<<10) | (j<<5) | i; } else if (ent->solid == SOLID_BSP) { ent->s.solid = 31; // a solid_bbox will never create this value } else ent->s.solid = 0; // set the abs box if (ent->solid == SOLID_BSP && (ent->s.angles[0] || ent->s.angles[1] || ent->s.angles[2]) ) { // expand for rotation float max, v; int i; max = 0; for (i=0 ; i<3 ; i++) { v =fabs( ent->mins[i]); if (v > max) max = v; v =fabs( ent->maxs[i]); if (v > max) max = v; } for (i=0 ; i<3 ; i++) { ent->absmin[i] = ent->s.origin[i] - max; ent->absmax[i] = ent->s.origin[i] + max; } } else { // normal VectorAdd (ent->s.origin, ent->mins, ent->absmin); VectorAdd (ent->s.origin, ent->maxs, ent->absmax); } // because movement is clipped an epsilon away from an actual edge, // we must fully check even when bounding boxes don't quite touch ent->absmin[0] -= 1; ent->absmin[1] -= 1; ent->absmin[2] -= 1; ent->absmax[0] += 1; ent->absmax[1] += 1; ent->absmax[2] += 1; // link to PVS leafs ent->num_clusters = 0; ent->areanum = 0; ent->areanum2 = 0; //get all leafs, including solids num_leafs = CM_BoxLeafnums (ent->absmin, ent->absmax, leafs, MAX_TOTAL_ENT_LEAFS, &topnode); // set areas for (i=0 ; i<num_leafs ; i++) { clusters[i] = CM_LeafCluster (leafs[i]); area = CM_LeafArea (leafs[i]); if (area) { // doors may legally straggle two areas, // but nothing should evern need more than that if (ent->areanum && ent->areanum != area) { if (ent->areanum2 && ent->areanum2 != area && sv.state == ss_loading) Com_DPrintf ("Object touching 3 areas at %f %f %f\n", ent->absmin[0], ent->absmin[1], ent->absmin[2]); ent->areanum2 = area; } else ent->areanum = area; } } if (num_leafs >= MAX_TOTAL_ENT_LEAFS) { // assume we missed some leafs, and mark by headnode ent->num_clusters = -1; ent->headnode = topnode; } else { ent->num_clusters = 0; for (i=0 ; i<num_leafs ; i++) { if (clusters[i] == -1) continue; // not a visible leaf for (j=0 ; j<i ; j++) if (clusters[j] == clusters[i]) break; if (j == i) { if (ent->num_clusters == MAX_ENT_CLUSTERS) { // assume we missed some leafs, and mark by headnode ent->num_clusters = -1; ent->headnode = topnode; break; } ent->clusternums[ent->num_clusters++] = clusters[i]; } } } // if first time, make sure old_origin is valid if (!ent->linkcount) { VectorCopy (ent->s.origin, ent->s.old_origin); } ent->linkcount++; if (ent->solid == SOLID_NOT) return; // find the first node that the ent's box crosses node = sv_areanodes; while (1) { if (node->axis == -1) break; if (ent->absmin[node->axis] > node->dist) node = node->children[0]; else if (ent->absmax[node->axis] < node->dist) node = node->children[1]; else break; // crosses the node } // link it in if (ent->solid == SOLID_TRIGGER) InsertLinkBefore (&ent->area, &node->trigger_edicts); else InsertLinkBefore (&ent->area, &node->solid_edicts); }
//----------------------------------------------------------------------------- // Purpose: Builds the cluster list for an entity // Input : *pEdict - //----------------------------------------------------------------------------- void SV_BuildEntityClusterList( edict_t *pEdict ) { int i, j; int topnode; int leafCount; int leafs[MAX_TOTAL_ENT_LEAFS], clusters[MAX_TOTAL_ENT_LEAFS]; int area; IServerEntity *serverEntity = pEdict->GetIServerEntity(); Assert( serverEntity ); if ( !serverEntity ) return; pEdict->clusterCount = 0; topnode = -1; pEdict->areanum = 0; pEdict->areanum2 = 0; //get all leafs, including solids leafCount = CM_BoxLeafnums( serverEntity->GetAbsMins(), serverEntity->GetAbsMaxs(), leafs, MAX_TOTAL_ENT_LEAFS, &topnode ); // set areas for ( i = 0; i < leafCount; i++ ) { clusters[i] = CM_LeafCluster( leafs[i] ); area = CM_LeafArea( leafs[i] ); if ( area ) { // doors may legally straggle two areas, // but nothing should evern need more than that if ( pEdict->areanum && pEdict->areanum != area ) { if ( pEdict->areanum2 && pEdict->areanum2 != area && sv.state == ss_loading ) { Con_DPrintf ("Object touching 3 areas at %f %f %f\n", serverEntity->GetAbsMins()[0], serverEntity->GetAbsMins()[1], serverEntity->GetAbsMins()[2]); } pEdict->areanum2 = area; } else { pEdict->areanum = area; } } } pEdict->headnode = topnode; // save headnode if ( leafCount >= MAX_TOTAL_ENT_LEAFS ) { // assume we missed some leafs, and mark by headnode pEdict->clusterCount = -1; } else { for ( i = 0; i < leafCount; i++ ) { if (clusters[i] == -1) continue; // not a visible leaf for ( j = 0; j < i; j++ ) { if (clusters[j] == clusters[i]) break; } if ( j == i ) { if ( pEdict->clusterCount == MAX_ENT_CLUSTERS ) { // assume we missed some leafs, and mark by headnode pEdict->clusterCount = -1; break; } pEdict->clusters[pEdict->clusterCount++] = clusters[i]; } } } }
static inline int PF_CM_BoxLeafnums( vec3_t mins, vec3_t maxs, int *list, int listsize, int *topnode ) { return CM_BoxLeafnums( svs.cms, mins, maxs, list, listsize, topnode ); }