コード例 #1
0
bool CFuncBulletShield::TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace )
{
	// ignore unless a shot
	if ((mask & MASK_SHOT)	 == MASK_SHOT)
	{
		// use obb collision
		ICollideable *pCol = GetCollideable();
		Assert(pCol);

		return IntersectRayWithOBB(ray,pCol->GetCollisionOrigin(),pCol->GetCollisionAngles(),
			pCol->OBBMins(),pCol->OBBMaxs(),1.0f,&trace);

		/*
		const model_t *pModel = this->GetCollisionModel();
		if ( pModel && pModel->type == mod_brush )
		{
			int nModelIndex = this->GetCollisionModelIndex();
			cmodel_t *pCModel = CM_InlineModelNumber( nModelIndex - 1 );
			int nHeadNode = pCModel->headnode;

			CM_TransformedBoxTrace( ray, nHeadNode, fMask, this->GetCollisionOrigin(), this->GetCollisionAngles(), *pTrace );
			return true;
		}
		return false;
		*/

		// return BaseClass::TestCollision( ray, mask, trace );
	}
	else
		return false;
}
コード例 #2
0
ファイル: c_triggers.cpp プロジェクト: Au-heppa/swarm-sdk
	FORCEINLINE void Check( T *pEntity )
	{
		// Hmmm.. everything in this list should be a trigger....
		ICollideable *pTriggerCollideable = pEntity->GetCollideable();
		if ( !m_pCollide->ShouldTouchTrigger(pTriggerCollideable->GetSolidFlags()) )
			return;

		if ( pTriggerCollideable->GetSolidFlags() & FSOLID_USE_TRIGGER_BOUNDS )
		{
			Vector vecTriggerMins, vecTriggerMaxs;
			pTriggerCollideable->WorldSpaceTriggerBounds( &vecTriggerMins, &vecTriggerMaxs ); 
			if ( !IsBoxIntersectingRay( vecTriggerMins, vecTriggerMaxs, m_Ray ) )
			{
				return;
			}
		}
		else
		{
			trace_t tr;
			enginetrace->ClipRayToCollideable( m_Ray, MASK_SOLID, pTriggerCollideable, &tr );
			if ( !(tr.contents & MASK_SOLID) )
				return;
		}

		trace_t tr;
		UTIL_ClearTrace( tr );
		tr.endpos = (m_pEnt->GetAbsOrigin() + pEntity->GetAbsOrigin()) * 0.5;
		m_pEnt->PhysicsMarkEntitiesAsTouching( pEntity, tr );
	}
コード例 #3
0
	virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask )
	{
		IClientUnknown *pUnk = (IClientUnknown*)pHandleEntity;
		ICollideable *pCollide = pUnk->GetCollideable();
		if ( pCollide->GetSolid() != SOLID_VPHYSICS && pCollide->GetSolid() != SOLID_BSP )
			return false;
		return BaseClass::ShouldHitEntity( pHandleEntity, contentsMask );
	}
コード例 #4
0
ファイル: util.cpp プロジェクト: kila58/sourceop
void UTIL_TraceEntity( CBaseEntity *pEntity, const Vector &vecAbsStart, const Vector &vecAbsEnd, 
                      unsigned int mask, ITraceFilter *pFilter, trace_t *ptr )
{
    ICollideable *pCollision = VFuncs::GetCollideable(pEntity);

    // Adding this assertion here so game code catches it, but really the assertion belongs in the engine
    // because one day, rotated collideables will work!
    Assert( pCollision->GetCollisionAngles() == vec3_angle );

    enginetrace->SweepCollideable( pCollision, vecAbsStart, vecAbsEnd, pCollision->GetCollisionAngles(), mask, pFilter, ptr );
}
コード例 #5
0
	IterationRetval_t EnumElement( IHandleEntity *pHandleEntity )
	{
		// Static props should never be in the trigger list 
		Assert( !StaticPropMgr()->IsStaticProp( pHandleEntity ) );

		IServerNetworkable *pNetworkable = static_cast<IServerNetworkable*>( pHandleEntity );
		Assert( pNetworkable );

		// Convert the IHandleEntity to an edict_t*...
		// Context is the thing we're testing everything against		
		edict_t* pTouch = pNetworkable->GetEdict();

		// Can't bump against itself
		if ( pTouch == m_pEnt )
			return ITERATION_CONTINUE;

		IServerEntity *serverEntity = pTouch->GetIServerEntity();
		if ( !serverEntity )
			return ITERATION_CONTINUE;

		// Hmmm.. everything in this list should be a trigger....
		ICollideable *pCollideable = serverEntity->GetCollideable();
		Assert(pCollideable->GetSolidFlags() & FSOLID_TRIGGER );
		if ( (pCollideable->GetSolidFlags() & FSOLID_TRIGGER) == 0 )
			return ITERATION_CONTINUE;

		model_t* pModel = sv.GetModel( pCollideable->GetCollisionModelIndex() );
		if ( pModel && pModel->type == mod_brush )
		{
			int headnode = SV_HullForEntity( pTouch );

			int contents;
			if (!m_Ray.m_IsSwept)
			{
				contents = CM_TransformedBoxContents( m_Ray.m_Start, m_mins, m_maxs,
					headnode, serverEntity->GetAbsOrigin(), serverEntity->GetAbsAngles() );
			}
			else
			{
				trace_t trace;
				CM_TransformedBoxTrace( m_Ray, headnode, MASK_ALL, serverEntity->GetAbsOrigin(), 
					serverEntity->GetAbsAngles(), trace );
				contents = trace.contents;
			}

			if ( !(contents & MASK_SOLID) )
				return ITERATION_CONTINUE;
		}

		m_TouchedEntities.AddToTail( pTouch );

		return ITERATION_CONTINUE;
	}
コード例 #6
0
//-----------------------------------------------------------------------------
// Sweeps a particular entity through the world 
//-----------------------------------------------------------------------------
void UTIL_TraceEntity( CBaseEntity *pEntity, const Vector &vecAbsStart, const Vector &vecAbsEnd, unsigned int mask, trace_t *ptr )
{
	ICollideable *pCollision = pEntity->GetCollideable();

	// Adding this assertion here so game code catches it, but really the assertion belongs in the engine
	// because one day, rotated collideables will work!
	Assert( pCollision->GetCollisionAngles() == vec3_angle );

	CTraceFilterEntity traceFilter( pEntity, pCollision->GetCollisionGroup() );

#ifdef PORTAL
	UTIL_Portal_TraceEntity( pEntity, vecAbsStart, vecAbsEnd, mask, &traceFilter, ptr );
#else
	enginetrace->SweepCollideable( pCollision, vecAbsStart, vecAbsEnd, pCollision->GetCollisionAngles(), mask, &traceFilter, ptr );
#endif
}
コード例 #7
0
//-----------------------------------------------------------------------------
// Purpose: Returns the color given trace information
// Input  : *trace - trace to get results for
//			*color - return color, gamma corrected (0.0f to 1.0f)
//-----------------------------------------------------------------------------
void GetColorForSurface( trace_t *trace, Vector *color )
{
	Vector	baseColor, diffuseColor;
	Vector	end = trace->startpos + ( ( Vector )trace->endpos - ( Vector )trace->startpos ) * 1.1f;
	
	if ( trace->DidHitWorld() )
	{
		if ( trace->hitbox == 0 )
		{
			// If we hit the world, then ask the world for the fleck color
			engine->TraceLineMaterialAndLighting( trace->startpos, end, diffuseColor, baseColor );
		}
		else
		{
			// In this case we hit a static prop.
			staticpropmgr->GetStaticPropMaterialColorAndLighting( trace, trace->hitbox - 1, diffuseColor, baseColor );
		}
	}
	else
	{
		// In this case, we hit an entity. Find out the model associated with it
		C_BaseEntity *pEnt = trace->m_pEnt;
		if ( !pEnt )
		{
			Msg("Couldn't find surface in GetColorForSurface()\n");
			color->x = 255;
			color->y = 255;
			color->z = 255;
			return;
		}

		ICollideable *pCollide = pEnt->GetCollideable();
		int modelIndex = pCollide->GetCollisionModelIndex();
		model_t* pModel = const_cast<model_t*>(modelinfo->GetModel( modelIndex ));

		// Ask the model info about what we need to know
		modelinfo->GetModelMaterialColorAndLighting( pModel, pCollide->GetCollisionOrigin(),
			pCollide->GetCollisionAngles(), trace, diffuseColor, baseColor );
	}

	//Get final light value
	color->x = pow( diffuseColor[0], 1.0f/2.2f ) * baseColor[0];
	color->y = pow( diffuseColor[1], 1.0f/2.2f ) * baseColor[1];
	color->z = pow( diffuseColor[2], 1.0f/2.2f ) * baseColor[2];
}
コード例 #8
0
//-----------------------------------------------------------------------------
// Purpose: returns a headnode that can be used to collide against this entity
// Input  : *ent - 
// Output : int
//-----------------------------------------------------------------------------
int SV_HullForEntity( edict_t *ent )
{
	model_t		*model;
	IServerEntity *serverEntity = ent->GetIServerEntity();
	Assert( serverEntity );
	if ( !serverEntity )
		return -1;

	int modelindex = serverEntity->GetModelIndex();
	model = sv.GetModel( modelindex );

	if (model->type == mod_brush)
	{
		cmodel_t *pCModel = CM_InlineModelNumber( modelindex - 1 );

		return pCModel->headnode;
	}

	ICollideable *pCollideable = serverEntity->GetCollideable();
	Vector vecMins = pCollideable->WorldAlignMins();
	Vector vecMaxs = pCollideable->WorldAlignMaxs();
	return CM_HeadnodeForBoxHull( vecMins, vecMaxs );
}
コード例 #9
0
	IterationRetval_t EnumElement( IHandleEntity *pHandleEntity )
	{
		ICollideable *pCollide;
		const char *pDbgName;
		m_pEngineTrace->HandleEntityToCollideable( pHandleEntity, &pCollide, &pDbgName );
		if (!pCollide)
			return ITERATION_CONTINUE;

		// Deal with static props
		// NOTE: I could have added static props to a different list and
		// enumerated them separately, but that would have been less efficient
		if ( StaticPropMgr()->IsStaticProp( pHandleEntity ) )
		{
			Ray_t ray;
			trace_t trace;
			ray.Init( m_Pos, m_Pos );
			m_pEngineTrace->ClipRayToCollideable( ray, MASK_ALL, pCollide, &trace );
			if (trace.startsolid)
			{
				// We're in a static prop; that's solid baby
				// Pretend we hit the world
				m_Contents = CONTENTS_SOLID;
				m_pCollide = m_pEngineTrace->GetWorldCollideable();
				return ITERATION_STOP;
			}
			return ITERATION_CONTINUE;
		}
		
		// We only care about solid volumes
		if ((pCollide->GetSolidFlags() & FSOLID_VOLUME_CONTENTS) == 0)
			return ITERATION_CONTINUE;

		model_t* pModel = (model_t*)pCollide->GetCollisionModel();
		if ( pModel && pModel->type == mod_brush )
		{
			Assert( pCollide->GetCollisionModelIndex() < MAX_MODELS && pCollide->GetCollisionModelIndex() >= 0 );
			int nHeadNode = GetModelHeadNode( pCollide );
			int contents = CM_TransformedPointContents( m_Pos, nHeadNode, 
				pCollide->GetCollisionOrigin(), pCollide->GetCollisionAngles() );

			if (contents != CONTENTS_EMPTY)
			{
				// Return the contents of the first thing we hit
				m_Contents = contents;
				m_pCollide = pCollide;
				return ITERATION_STOP;
			}
		}

		return ITERATION_CONTINUE;
	}
コード例 #10
0
void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
{
#if defined MENU_DEBUG
	g_Logger.LogMessage("[SM_MENU] ClientPressedKey() (client %d) (key_press %d)", client, key_press);
#endif
	CBaseMenuPlayer *player = GetMenuPlayer(client);

	/* First question: Are we in a menu? */
	if (!player->bInMenu)
	{
		return;
	}

	bool cancel = false;
	unsigned int item = 0;
	MenuCancelReason reason = MenuCancel_Exit;
	MenuEndReason end_reason = MenuEnd_Selected;
	menu_states_t &states = player->states;

	/* Save variables */
	IMenuHandler *mh = states.mh;
	IBaseMenu *menu = states.menu;

	unsigned int item_on_page = states.item_on_page;

	assert(mh != NULL);

	if (menu == NULL)
	{
		item = key_press;
	} else if (key_press < 1 || key_press > GetMaxPageItems()) {
		cancel = true;
	} else {
		ItemSelection type = states.slots[key_press].type;

		/* Check if we should play a sound about the type */
		if (g_Menus.MenuSoundsEnabled() && 
			(!menu || (menu->GetMenuOptionFlags() & MENUFLAG_NO_SOUND) != MENUFLAG_NO_SOUND))
		{
			CellRecipientFilter filter;
			cell_t clients[1];

			clients[0] = client;
			filter.Initialize(clients, 1);

			const char *sound = g_Menus.GetMenuSound(type);

			if (sound != NULL)
			{
				edict_t *pEdict = PEntityOfEntIndex(client);
				if (pEdict)
				{
					ICollideable *pCollideable = pEdict->GetCollideable();

					if (pCollideable)
					{
						const Vector & pos = pCollideable->GetCollisionOrigin();
						enginesound->EmitSound(filter, 
							client, 
							CHAN_AUTO, 
#if SOURCE_ENGINE >= SE_PORTAL2
							sound, 
							-1, 
#endif
							sound, 
							VOL_NORM, 
							ATTN_NORM, 
#if SOURCE_ENGINE >= SE_PORTAL2
							0, 
#endif
							0, 
							PITCH_NORM, 
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS \
	|| SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_TF2
							0,
#endif
							&pos);
					}
				}
			}
		}

		/* For navigational items, we're going to redisplay */
		if (type == ItemSel_Back)
		{
			if (!RedoClientMenu(client, ItemOrder_Descending))
			{
				cancel = true;
				reason = MenuCancel_NoDisplay;
				end_reason = MenuEnd_Cancelled;
			} else {
				return;
			}
		} else if (type == ItemSel_Next) {
			if (!RedoClientMenu(client, ItemOrder_Ascending))
			{
				cancel = true;						/* I like Saltines. */
				reason = MenuCancel_NoDisplay;
				end_reason = MenuEnd_Cancelled;
			} else {
				return;
			}
		} else if (type == ItemSel_Exit || type == ItemSel_None) {
			cancel = true;
			reason = MenuCancel_Exit;
			end_reason = MenuEnd_Exit;
		} else if (type == ItemSel_ExitBack) {
			cancel = true;
			reason = MenuCancel_ExitBack;
			end_reason = MenuEnd_ExitBack;
		} else {
			item = states.slots[key_press].item;
		}
	}

	/* Clear states */
	player->bInMenu = false;
	if (player->menuHoldTime)
	{
		RemoveClientFromWatch(client);
	}

	Handle_t hndl = menu ? menu->GetHandle() : BAD_HANDLE;
	AutoHandleRooter ahr(hndl);

	if (cancel)
	{
		mh->OnMenuCancel(menu, client, reason);
	} else {
		mh->OnMenuSelect(menu, client, item);
		if (mh->GetMenuAPIVersion2() >= 13)
		{
			mh->OnMenuSelect2(menu, client, item, item_on_page);
		}
	}

	/* Only fire end for valid menus */
	if (menu)
	{
		mh->OnMenuEnd(menu, end_reason);
	}
}
コード例 #11
0
int SEditModelRender::MaterialPicker( char ***szMat )
{
	int mx, my;
#ifdef SOURCE_2006
	vgui::input()->GetCursorPos( mx, my );
#else
	vgui::input()->GetCursorPosition( mx, my );
#endif

	Vector ray;
	const CViewSetup *pViewSetup = view->GetPlayerViewSetup();
	float ratio =engine->GetScreenAspectRatio(
#ifdef SWARM_DLL
		pViewSetup->width, pViewSetup->height
#endif
		);

	ratio = ( 1.0f / ratio ) * (4.0f/3.0f);
	float flFov = ScaleFOVByWidthRatio( pViewSetup->fov, ratio );
	ScreenToWorld( mx, my, flFov, pViewSetup->origin, pViewSetup->angles, ray );

	Vector start = pViewSetup->origin;
	Vector end = start + ray * MAX_TRACE_LENGTH;
	trace_t tr;
	C_BaseEntity *pIgnore = input->CAM_IsThirdPerson() ? NULL : C_BasePlayer::GetLocalPlayer();
	UTIL_TraceLine( start, end, MASK_SOLID, pIgnore, COLLISION_GROUP_NONE, &tr );

	if ( !tr.DidHit() )
		return 0;

	int numMaterials = 0;
	IMaterial **MatList = NULL;
	studiohdr_t *pSHdr = NULL;

	if ( tr.DidHitWorld() )
	{
		if ( tr.hitbox == 0 )
		{
			Vector dummy;
			IMaterial *pMat = engine->TraceLineMaterialAndLighting( start, end, dummy, dummy );
			if ( pMat )
			{
				numMaterials = 1;
				MatList = new IMaterial*[1];
				MatList[0] = pMat;
			}
		}
		else
		{
			ICollideable *prop = staticpropmgr->GetStaticPropByIndex( tr.hitbox - 1 );
			if ( prop )
			{
				IClientRenderable *pRenderProp = prop->GetIClientUnknown()->GetClientRenderable();
				if ( pRenderProp )
				{
					const model_t *pModel = pRenderProp->GetModel();
					if ( pModel )
						pSHdr = modelinfo->GetStudiomodel( pModel );
				}
			}
		}
	}
	else if ( tr.m_pEnt )
	{
		const model_t *pModel = tr.m_pEnt->GetModel();
		if ( pModel )
			pSHdr = modelinfo->GetStudiomodel( pModel );
	}

	if ( pSHdr )
	{
		Assert( !numMaterials && !MatList );
		numMaterials = pSHdr->numtextures;
		const int numPaths = pSHdr->numcdtextures;

		if ( numMaterials )
		{
			CUtlVector< IMaterial* >hValidMaterials;
			for ( int i = 0; i < numMaterials; i++ )
			{
				mstudiotexture_t *pStudioTex = pSHdr->pTexture( i );
				const char *matName = pStudioTex->pszName();

				for ( int p = 0; p < numPaths; p++ )
				{
					char tmpPath[MAX_PATH];
					Q_snprintf( tmpPath, MAX_PATH, "%s%s\0", pSHdr->pCdtexture( p ), matName );
					Q_FixSlashes( tmpPath );
					IMaterial *pTempMat = materials->FindMaterial( tmpPath, TEXTURE_GROUP_MODEL );
					if ( !IsErrorMaterial( pTempMat ) )
					{
						hValidMaterials.AddToTail( pTempMat );
						break;
					}
				}
			}

			numMaterials = hValidMaterials.Count();
			if ( numMaterials )
			{
				MatList = new IMaterial*[ numMaterials ];
				for ( int i = 0; i < numMaterials; i++ )
					MatList[i] = hValidMaterials[i];
			}

			hValidMaterials.Purge();
		}
	}

	*szMat = new char*[ numMaterials ];

	int iTotalLength = 0;
	for ( int i = 0; i < numMaterials; i++ )
		iTotalLength += Q_strlen( MatList[i]->GetName() ) + 1;

	**szMat = new char[ iTotalLength ];

	int curpos = 0;
	for ( int i = 0; i < numMaterials; i++ )
	{
		const char *pszName = MatList[i]->GetName();

		int curLength = Q_strlen( pszName ) + 1;
		(*szMat)[ i ] = **szMat + curpos;
		Q_strcpy( (*szMat)[ i ], pszName );
		curpos += curLength;
	}

	if ( MatList )
		delete [] MatList;

	return numMaterials;
}
コード例 #12
0
/*
===============
SV_LinkEdict

===============
*/
void SV_LinkEdict( edict_t *ent, qboolean touch_triggers, const Vector* pPrevAbsOrigin )
{
	IServerEntity *pServerEntity = ent->GetIServerEntity();
	if ( !pServerEntity )
		return;		
	
	// Remove it from whatever lists it may be in at the moment
	// We'll re-add it below if we need to.
	if (ent->partition != PARTITION_INVALID_HANDLE)
	{
		SpatialPartition()->Remove( ent->partition );
	}

	if (ent->free)
		return;

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

	pServerEntity->CalcAbsolutePosition();

	// set the abs box
	pServerEntity->SetObjectCollisionBox();
	
	// link to PVS leafs
	SV_BuildEntityClusterList( ent );

	// Update KD tree information
	ICollideable *pCollide = pServerEntity->GetCollideable();
	if (ent->partition == PARTITION_INVALID_HANDLE)
	{
		// Here, we haven't added the entity to the partition before
		// So we have to make a new partition handle.
		ent->partition = SpatialPartition()->CreateHandle( pCollide->GetEntityHandle() );
	}

	// Here, we indicate the entity has moved. Note that this call does
	// some fast early-outing to prevent unnecessary work
	SpatialPartition()->ElementMoved( ent->partition, pServerEntity->GetAbsMins(), pServerEntity->GetAbsMaxs() );

	// Make sure it's in the list of all entities
	SpatialPartition()->Insert( PARTITION_ENGINE_NON_STATIC_EDICTS, ent->partition );

	SolidType_t iSolid = pCollide->GetSolid();
	int nSolidFlags = pCollide->GetSolidFlags();
	bool bIsSolid = IsSolid( iSolid, nSolidFlags ) || ((nSolidFlags & FSOLID_TRIGGER) != 0);
	if ( !bIsSolid )
	{
		// If this ent's touch list isn't empty, it's transitioning to not solid
		if ( pServerEntity->IsCurrentlyTouching() )
		{
			// mark ent so that at the end of frame it will check to see if it's no longer touch ents
			pServerEntity->SetCheckUntouch( true );
		}
		return;
	}

	// Insert it into the appropriate lists.
	// We have to continually reinsert it because its solid type may have changed
	SpatialPartitionListMask_t mask = 0;
	if (( nSolidFlags & FSOLID_NOT_SOLID ) == 0)
	{
		mask |=	PARTITION_ENGINE_SOLID_EDICTS;
	}
	if (( nSolidFlags & FSOLID_TRIGGER ) != 0 )
	{
		mask |=	PARTITION_ENGINE_TRIGGER_EDICTS;
	}
	Assert( mask != 0 );
	SpatialPartition()->Insert( mask, ent->partition );

	if ( iSolid == SOLID_BSP ) 
	{
		model_t	*model = sv.GetModel( pServerEntity->GetModelIndex() );
		if ( !model && strlen( STRING( pServerEntity->GetModelName() ) ) == 0 ) 
		{
			Con_DPrintf( "Inserted %s with no model\n", STRING( ent->classname ) );
			return;
		}
	}

	// if touch_triggers, touch all entities at this node and descend for more
	if (touch_triggers)
	{
		// mark ent so that at the end of frame it will check to see if it's no longer touch ents
		pServerEntity->SetCheckUntouch( true );

		// If this is a trigger that's moved, then query the solid list instead
		if ( mask == PARTITION_ENGINE_TRIGGER_EDICTS )
		{
			CTriggerMoved triggerEnum( ent );

			SpatialPartition()->EnumerateElementsInBox( PARTITION_ENGINE_SOLID_EDICTS,
				pServerEntity->GetAbsMins(), pServerEntity->GetAbsMaxs(), false, &triggerEnum );

			triggerEnum.HandleTouchedEntities( );
		}
		else
		{
			if (!pPrevAbsOrigin)
			{
				CTouchLinks touchEnumerator(ent, NULL);

				SpatialPartition()->EnumerateElementsInBox( PARTITION_ENGINE_TRIGGER_EDICTS,
					pServerEntity->GetAbsMins(), pServerEntity->GetAbsMaxs(), false, &touchEnumerator );

				touchEnumerator.HandleTouchedEntities( );
			}
			else
			{
				CTouchLinks touchEnumerator(ent, pPrevAbsOrigin);

				// A version that checks against an extruded ray indicating the motion
				SpatialPartition()->EnumerateElementsAlongRay( PARTITION_ENGINE_TRIGGER_EDICTS,
					touchEnumerator.m_Ray, false, &touchEnumerator );

				touchEnumerator.HandleTouchedEntities( );
			}
		}
	}
}
コード例 #13
0
//-----------------------------------------------------------------------------
// A version that simply accepts a ray (can work as a traceline or tracehull)
//-----------------------------------------------------------------------------
void CEngineTrace::TraceRay( const Ray_t &ray, unsigned int fMask, ITraceFilter *pTraceFilter, trace_t *pTrace )
{
	CTraceFilterHitAll traceFilter;
	if ( !pTraceFilter )
	{
		pTraceFilter = &traceFilter;
	}

	// Gather statistics.
	g_EngineStats.IncrementCountedStat( ENGINE_STATS_NUM_TRACE_LINES, 1 );
	MEASURE_TIMED_STAT( ENGINE_STATS_TRACE_LINE_TIME );
	
	CM_ClearTrace( pTrace );

	// Collide with the world.
	if ( pTraceFilter->GetTraceType() != TRACE_ENTITIES_ONLY )
	{
		ICollideable *pCollide = GetWorldCollideable();

		// Make sure the world entity is unrotated
		// FIXME: BAH! The !pCollide test here is because of
		// CStaticProp::PrecacheLighting.. it's occurring too early
		// need to fix that later
		Assert(!pCollide || pCollide->GetCollisionOrigin() == vec3_origin );
		Assert(!pCollide || pCollide->GetCollisionAngles() == vec3_angle );

		CM_BoxTrace( ray, 0, fMask, true, *pTrace );
		SetTraceEntity( pCollide, pTrace );

		// Blocked by the world.
		if ( pTrace->fraction == 0 )
			return;

		// Early out if we only trace against the world
		if ( pTraceFilter->GetTraceType() == TRACE_WORLD_ONLY )
			return;
	}

	// Save the world collision fraction.
	float flWorldFraction = pTrace->fraction;

	// Create a ray that extends only until we hit the world
	// and adjust the trace accordingly
	Ray_t entityRay = ray;
	entityRay.m_Delta *= pTrace->fraction;

	// We know this is safe because if pTrace->fraction == 0
	// we would have exited above
	pTrace->fractionleftsolid /= pTrace->fraction;
 	pTrace->fraction = 1.0;

	// Collide with entities along the ray
	// FIXME: Hitbox code causes this to be re-entrant for the IK stuff.
	// If we could eliminate that, this could be static and therefore
	// not have to reallocate memory all the time
	CEntitiesAlongRay enumerator;
	enumerator.Reset();
	SpatialPartition()->EnumerateElementsAlongRay( SpatialPartitionMask(), entityRay, false, &enumerator );

	bool bNoStaticProps = pTraceFilter->GetTraceType() == TRACE_ENTITIES_ONLY;
	bool bFilterStaticProps = pTraceFilter->GetTraceType() == TRACE_EVERYTHING_FILTER_PROPS;

	trace_t tr;
	ICollideable *pCollideable;
	const char *pDebugName;
	int nCount = enumerator.m_EntityHandles.Count();
	for ( int i = 0; i < nCount; ++i )
	{
		// Generate a collideable
		IHandleEntity *pHandleEntity = enumerator.m_EntityHandles[i];
		HandleEntityToCollideable( pHandleEntity, &pCollideable, &pDebugName );

		// Check for error condition
		if ( !IsSolid( pCollideable->GetSolid(), pCollideable->GetSolidFlags() ) )
		{
			char temp[1024];
			Q_snprintf(temp, sizeof( temp ), "%s in solid list (not solid)\n", pDebugName );
			Sys_Error (temp);
		}

		if ( !StaticPropMgr()->IsStaticProp( pHandleEntity ) )
		{
			if ( !pTraceFilter->ShouldHitEntity( pHandleEntity, fMask ) )
				continue;
		}
		else
		{
			// FIXME: Could remove this check here by
			// using a different spatial partition mask. Look into it
			// if we want more speedups here.
			if ( bNoStaticProps )
				continue;

			if ( bFilterStaticProps )
			{
				if ( !pTraceFilter->ShouldHitEntity( pHandleEntity, fMask ) )
					continue;
			}
		}

		ClipRayToCollideable( entityRay, fMask, pCollideable, &tr );

		// Make sure the ray is always shorter than it currently is
		ClipTraceToTrace( tr, pTrace );

		// Stop if we're in allsolid
		if (pTrace->allsolid)
			break;
	}

	// Fix up the fractions so they are appropriate given the original
	// unclipped-to-world ray
	pTrace->fraction *= flWorldFraction;
	pTrace->fractionleftsolid *= flWorldFraction;

#ifdef _DEBUG
	Vector vecOffset, vecEndTest;
	VectorAdd( ray.m_Start, ray.m_StartOffset, vecOffset );
	VectorMA( vecOffset, pTrace->fractionleftsolid, ray.m_Delta, vecEndTest );
	Assert( VectorsAreEqual( vecEndTest, pTrace->startpos, 0.1f ) );
	VectorMA( vecOffset, pTrace->fraction, ray.m_Delta, vecEndTest );
	Assert( VectorsAreEqual( vecEndTest, pTrace->endpos, 0.1f ) );
//	Assert( !ray.m_IsRay || pTrace->allsolid || pTrace->fraction >= pTrace->fractionleftsolid );
#endif

	if ( !ray.m_IsRay )
	{
		// Make sure no fractionleftsolid can be used with box sweeps
		VectorAdd( ray.m_Start, ray.m_StartOffset, pTrace->startpos );
		pTrace->fractionleftsolid = 0;

#ifdef _DEBUG
		pTrace->fractionleftsolid = VEC_T_NAN;
#endif
	}
}