Example #1
0
/*
* GClip_LinkEntity_AreaGrid
*/
static void GClip_LinkEntity_AreaGrid( areagrid_t *areagrid, edict_t *ent )
{
	link_t *grid;
	int igrid[3], igridmins[3], igridmaxs[3], gridnum, entitynumber;
	
	entitynumber = NUM_FOR_EDICT( ent );
	if( entitynumber <= 0 || entitynumber >= game.maxentities || EDICT_NUM( entitynumber ) != ent )
	{
		Com_Printf( "GClip_LinkEntity_AreaGrid: invalid edict %p "
			"(edicts is %p, edict compared to prog->edicts is %i)\n", 
			(void *)ent, game.edicts, entitynumber );
		return;
	}

	igridmins[0] = (int) floor( (ent->r.absmin[0] + areagrid->bias[0]) * areagrid->scale[0] );
	igridmins[1] = (int) floor( (ent->r.absmin[1] + areagrid->bias[1]) * areagrid->scale[1] );
	//igridmins[2] = (int) floor( (ent->r.absmin[2] + areagrid->bias[2]) * areagrid->scale[2] );
	igridmaxs[0] = (int) floor( (ent->r.absmax[0] + areagrid->bias[0]) * areagrid->scale[0] ) + 1;
	igridmaxs[1] = (int) floor( (ent->r.absmax[1] + areagrid->bias[1]) * areagrid->scale[1] ) + 1;
	//igridmaxs[2] = (int) floor( (ent->r.absmax[2] + areagrid->bias[2]) * areagrid->scale[2] ) + 1;
	if( igridmins[0] < 0 || igridmaxs[0] > AREA_GRID 
		|| igridmins[1] < 0 || igridmaxs[1] > AREA_GRID 
		|| ((igridmaxs[0] - igridmins[0]) * (igridmaxs[1] - igridmins[1])) > MAX_ENT_AREAS )
	{
		// wow, something outside the grid, store it as such
		GClip_InsertLinkBefore( &ent->areagrid[0], &areagrid->outside, entitynumber );
		return;
	}

	gridnum = 0;
	for( igrid[1] = igridmins[1]; igrid[1] < igridmaxs[1]; igrid[1]++ ) {
		grid = areagrid->grid + igrid[1] * AREA_GRID + igridmins[0];
		for( igrid[0] = igridmins[0]; igrid[0] < igridmaxs[0]; igrid[0]++, grid++, gridnum++ )
			GClip_InsertLinkBefore( &ent->areagrid[gridnum], grid, entitynumber );
	}
}
Example #2
0
void GClip_LinkEntity( 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->r.area.prev )
		GClip_UnlinkEntity( ent ); // unlink from old position

	if( ent == game.edicts )
		return; // don't add the world

	if( !ent->r.inuse )
		return;

	// set the size
	VectorSubtract( ent->r.maxs, ent->r.mins, ent->r.size );

	if( ent->r.solid == SOLID_NOT || ( ent->r.svflags & SVF_PROJECTILE ) )
	{
		ent->s.solid = 0;
	}
	else if( ISBRUSHMODEL( ent->s.modelindex ) )
	{
		// the only predicted SOLID_TRIGGER entity is ET_PUSH_TRIGGER
		if( ent->r.solid != SOLID_TRIGGER || ent->s.type == ET_PUSH_TRIGGER )
			ent->s.solid = SOLID_BMODEL;
		else
			ent->s.solid = 0;
	}
	else // encode the size into the entity_state for client prediction
	{
		if( ent->r.solid == SOLID_TRIGGER )
		{
			ent->s.solid = 0;
		}
		else
		{
			// assume that x/y are equal and symetric
			i = ent->r.maxs[0]/8;
			clamp( i, 1, 31 );

			// z is not symetric
			j = ( -ent->r.mins[2] )/8;
			clamp( j, 1, 31 );

			// and z maxs can be negative...
			k = ( ent->r.maxs[2]+32 )/8;
			clamp( k, 1, 63 );

			ent->s.solid = ( k<<10 ) | ( j<<5 ) | i;
		}
	}

	// set the abs box
	if( ISBRUSHMODEL( ent->s.modelindex ) &&
		( ent->s.angles[0] || ent->s.angles[1] || ent->s.angles[2] ) )
	{ 
		// expand for rotation
		float radius;

		radius = RadiusFromBounds( ent->r.mins, ent->r.maxs );

		for( i = 0; i < 3; i++ )
		{
			ent->r.absmin[i] = ent->s.origin[i] - radius;
			ent->r.absmax[i] = ent->s.origin[i] + radius;
		}
	}
	else // axis aligned
	{ 
		VectorAdd( ent->s.origin, ent->r.mins, ent->r.absmin );
		VectorAdd( ent->s.origin, ent->r.maxs, ent->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
	ent->r.absmin[0] -= 1;
	ent->r.absmin[1] -= 1;
	ent->r.absmin[2] -= 1;
	ent->r.absmax[0] += 1;
	ent->r.absmax[1] += 1;
	ent->r.absmax[2] += 1;

	// link to PVS leafs
	ent->r.num_clusters = 0;
	ent->r.areanum = ent->r.areanum2 = -1;

	// get all leafs, including solids
	num_leafs = trap_CM_BoxLeafnums( ent->r.absmin, ent->r.absmax,
		leafs, MAX_TOTAL_ENT_LEAFS, &topnode );

	// set areas
	for( i = 0; i < num_leafs; i++ )
	{
		clusters[i] = trap_CM_LeafCluster( leafs[i] );
		area = trap_CM_LeafArea( leafs[i] );
		if( area > -1 )
		{
			// doors may legally straggle two areas,
			// but nothing should ever need more than that
			if( ent->r.areanum > -1 && ent->r.areanum != area )
			{
				if( ent->r.areanum2 > -1 && ent->r.areanum2 != area )
				{
					if( developer->integer )
						G_Printf( "Object %s touching 3 areas at %f %f %f\n",
						( ent->classname ? ent->classname : "" ),
						ent->r.absmin[0], ent->r.absmin[1], ent->r.absmin[2] );
				}
				ent->r.areanum2 = area;
			}
			else
				ent->r.areanum = area;
		}
	}

	if( num_leafs >= MAX_TOTAL_ENT_LEAFS )
	{ // assume we missed some leafs, and mark by headnode
		ent->r.num_clusters = -1;
		ent->r.headnode = topnode;
	}
	else
	{
		ent->r.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->r.num_clusters == MAX_ENT_CLUSTERS )
				{
					// assume we missed some leafs, and mark by headnode
					ent->r.num_clusters = -1;
					ent->r.headnode = topnode;
					break;
				}

				ent->r.clusternums[ent->r.num_clusters++] = clusters[i];
			}
		}
	}

	// if first time, make sure old_origin is valid
	if( !ent->r.linkcount && !( ent->r.svflags & SVF_TRANSMITORIGIN2 ) )
	{
		VectorCopy( ent->s.origin, ent->s.old_origin );
		ent->olds = ent->s;
	}
	ent->r.linkcount++;
	ent->linked = qtrue;

	if( ent->r.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->r.absmin[node->axis] > node->dist )
			node = node->children[0];
		else if( ent->r.absmax[node->axis] < node->dist )
			node = node->children[1];
		else
			break; // crosses the node
	}

	// link it in
	if( ent->r.solid == SOLID_TRIGGER )
		GClip_InsertLinkBefore( &ent->r.area, &node->trigger_edicts, NUM_FOR_EDICT( ent ) );
	else
		GClip_InsertLinkBefore( &ent->r.area, &node->solid_edicts, NUM_FOR_EDICT( ent ) );
}