void C_SpatialEntity::ClientThink()
{
	if( !m_bEnabled && m_flCurWeight == 0.0f )
	{
		m_flWeight = 0.0f;
		return;
	}

	CBaseEntity *pPlayer = C_BasePlayer::GetLocalPlayer( 0 );
	if( !pPlayer )
		return;

	Vector playerOrigin = pPlayer->GetAbsOrigin();

	m_flWeight = 0.0f;

	if ( ( m_minFalloff != -1 ) && ( m_maxFalloff != -1 ) && m_minFalloff != m_maxFalloff )
	{
		float dist = (playerOrigin - m_vecOrigin).Length();
		m_flWeight = (dist-m_minFalloff) / (m_maxFalloff-m_minFalloff);
		m_flWeight = fpmax( 0.0f, m_flWeight );
		m_flWeight = fpmin( 1.0f, m_flWeight );

		m_flInfluence = fpmax( 0.0f, m_minFalloff - dist );
	}

	m_flWeight = m_flCurWeight * ( 1.0f - m_flWeight );

	BaseClass::ClientThink();
}
void RagdollComputeApproximateBbox( const ragdoll_t &ragdoll, const Vector &origin, Vector &outMins, Vector &outMaxs )
{
	Vector mins, maxs;
	ClearBounds(mins,maxs);
	for ( int i = 0; i < ragdoll.listCount; i++ )
	{
		Vector objectOrg;
		ragdoll.list[i].pObject->GetPosition( &objectOrg, NULL );
		float radius = physcollision->CollideGetRadius( ragdoll.list[i].pObject->GetCollide() );
		for ( int k = 0; k < 3; k++ )
		{
			float ext = objectOrg[k] + radius;
			maxs[k] = fpmax( maxs[k], ext );
			ext = objectOrg[k] - radius;
			mins[k] = fpmin( mins[k], ext );
		}
	}
	outMins = mins;
	outMaxs = maxs;
}
void C_SunlightShadowControl::ClientThink()
{
	VPROF("C_SunlightShadowControl::ClientThink");
	if ( m_bEnabled )
	{
		Vector vLinearFloatLightColor( m_LightColor.r, m_LightColor.g, m_LightColor.b );
		float flLinearFloatLightAlpha = m_LightColor.a;

		if ( m_CurrentLinearFloatLightColor != vLinearFloatLightColor || m_flCurrentLinearFloatLightAlpha != flLinearFloatLightAlpha )
		{
			float flColorTransitionSpeed = gpGlobals->frametime * m_flColorTransitionTime * 255.0f;

			m_CurrentLinearFloatLightColor.x = Approach( vLinearFloatLightColor.x, m_CurrentLinearFloatLightColor.x, flColorTransitionSpeed );
			m_CurrentLinearFloatLightColor.y = Approach( vLinearFloatLightColor.y, m_CurrentLinearFloatLightColor.y, flColorTransitionSpeed );
			m_CurrentLinearFloatLightColor.z = Approach( vLinearFloatLightColor.z, m_CurrentLinearFloatLightColor.z, flColorTransitionSpeed );
			m_flCurrentLinearFloatLightAlpha = Approach( flLinearFloatLightAlpha, m_flCurrentLinearFloatLightAlpha, flColorTransitionSpeed );
		}

		FlashlightState_t state;

		Vector vDirection = m_shadowDirection;
		VectorNormalize( vDirection );

		QAngle angView;
		engine->GetViewAngles( angView );

		//Vector vViewUp = Vector( 0.0f, 1.0f, 0.0f );
		Vector vSunDirection2D = vDirection;
		vSunDirection2D.z = 0.0f;

		HACK_GETLOCALPLAYER_GUARD( "C_SunlightShadowControl::ClientThink" );

#ifdef INFESTED_DLL		// shine sun on your current marine, rather than the player entity
		C_ASW_Marine *pMarine = C_ASW_Marine::GetLocalMarine();
		if ( !pMarine )
			return;

		Vector vPos = ( pMarine->GetAbsOrigin() + vSunDirection2D * m_flNorthOffset ) - vDirection * m_flSunDistance;
#else
		if ( !C_BasePlayer::GetLocalPlayer() )
			return;

		Vector vPos = ( C_BasePlayer::GetLocalPlayer()->GetAbsOrigin() + vSunDirection2D * m_flNorthOffset ) - vDirection * m_flSunDistance;
#endif

		QAngle angAngles;
		VectorAngles( vDirection, angAngles );

		Vector vForward, vRight, vUp;
		AngleVectors( angAngles, &vForward, &vRight, &vUp );

		state.m_fHorizontalFOVDegrees = m_flFOV;
		state.m_fVerticalFOVDegrees = m_flFOV;

		state.m_vecLightOrigin = vPos;
		BasisToQuaternion( vForward, vRight, vUp, state.m_quatOrientation );

		state.m_fQuadraticAtten = 0.0f;
		state.m_fLinearAtten = m_flSunDistance / 2.0f;
		state.m_fConstantAtten = 0.0f;
		state.m_FarZAtten = m_flSunDistance + 300.0f;
		state.m_Color[0] = m_CurrentLinearFloatLightColor.x * ( 1.0f / 255.0f ) * m_flCurrentLinearFloatLightAlpha;
		state.m_Color[1] = m_CurrentLinearFloatLightColor.y * ( 1.0f / 255.0f ) * m_flCurrentLinearFloatLightAlpha;
		state.m_Color[2] = m_CurrentLinearFloatLightColor.z * ( 1.0f / 255.0f ) * m_flCurrentLinearFloatLightAlpha;
		state.m_Color[3] = 0.0f; // fixme: need to make ambient work m_flAmbient;
		state.m_NearZ = fpmax( 4.0f, m_flSunDistance - m_flNearZ );
		state.m_FarZ = m_flSunDistance + 300.0f;

		float flOrthoSize = cl_sunlight_ortho_size.GetFloat();

		if ( flOrthoSize > 0 )
		{
			state.m_bOrtho = true;
			state.m_fOrthoLeft = -flOrthoSize;
			state.m_fOrthoTop = -flOrthoSize;
			state.m_fOrthoRight = flOrthoSize;
			state.m_fOrthoBottom = flOrthoSize;
		}
		else
		{
			state.m_bOrtho = false;
		}

		state.m_flShadowSlopeScaleDepthBias = 2;
		state.m_flShadowDepthBias = cl_sunlight_depthbias.GetFloat();
		state.m_bEnableShadows = m_bEnableShadows;
		state.m_pSpotlightTexture = m_SpotlightTexture;
		state.m_pProjectedMaterial = NULL;
		state.m_nSpotlightTextureFrame = 0;

		state.m_nShadowQuality = 1; // Allow entity to affect shadow quality
		state.m_bShadowHighRes = true;

		if ( m_bOldEnableShadows != m_bEnableShadows )
		{
			// If they change the shadow enable/disable, we need to make a new handle
			if ( m_LocalFlashlightHandle != CLIENTSHADOW_INVALID_HANDLE )
			{
				g_pClientShadowMgr->DestroyFlashlight( m_LocalFlashlightHandle );
				m_LocalFlashlightHandle = CLIENTSHADOW_INVALID_HANDLE;
			}

			m_bOldEnableShadows = m_bEnableShadows;
		}

		if( m_LocalFlashlightHandle == CLIENTSHADOW_INVALID_HANDLE )
		{
			m_LocalFlashlightHandle = g_pClientShadowMgr->CreateFlashlight( state );
		}
		else
		{
			g_pClientShadowMgr->UpdateFlashlightState( m_LocalFlashlightHandle, state );
#ifndef INFESTED_DLL
#pragma message("TODO: rebuild sunlight projected texture after sunlight control changes.")
			g_pClientShadowMgr->UpdateProjectedTexture( m_LocalFlashlightHandle, true );
#endif
		}
	}
	else if ( m_LocalFlashlightHandle != CLIENTSHADOW_INVALID_HANDLE )
	{
		g_pClientShadowMgr->DestroyFlashlight( m_LocalFlashlightHandle );
		m_LocalFlashlightHandle = CLIENTSHADOW_INVALID_HANDLE;
	}

	BaseClass::ClientThink();
}