//-----------------------------------------------------------------------------
// Purpose: Calculates the physics shake values
//-----------------------------------------------------------------------------
void CASWEnvShake::Think( void )
{
	int i;

	if ( gpGlobals->curtime > m_nextShake )
	{
		// Higher frequency means we recalc the extents more often and perturb the display again
		m_nextShake = gpGlobals->curtime + (1.0f / Frequency());

		// Compute random shake extents (the shake will settle down from this)
		for (i = 0; i < 2; i++ )
		{
			m_maxForce[i] = random->RandomFloat( -1, 1 );
		}
		// make the force it point mostly up
		m_maxForce.z = 4;
		VectorNormalize( m_maxForce );
		m_maxForce *= m_currentAmp * 400;	// amplitude is the acceleration of a 100kg object
	}

	float fraction = ( m_stopTime - gpGlobals->curtime ) / Duration();

	if ( fraction < 0 )
	{
		m_pShakeController->ClearObjects();
		return;
	}

	float freq = 0;
	// Ramp up frequency over duration
	if ( fraction )
	{
		freq = (Frequency() / fraction);
	}

	// square fraction to approach zero more quickly
	fraction *= fraction;

	// Sine wave that slowly settles to zero
	fraction = fraction * sin( gpGlobals->curtime * freq );

	// Add to view origin
	for ( i = 0; i < 3; i++ )
	{
		// store the force in the controller callback
		m_shakeCallback.m_force[i] = m_maxForce[i] * fraction;
	}

	// Drop amplitude a bit, less for higher frequency shakes
	m_currentAmp -= m_currentAmp * ( gpGlobals->frametime / (Duration() * Frequency()) );
	SetNextThink( gpGlobals->curtime );
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CASWEnvShake::ApplyShake( ShakeCommand_t command )
{
	if ( !HasSpawnFlags( SF_ASW_SHAKE_NO_VIEW ) )
	{
		bool air = (GetSpawnFlags() & SF_ASW_SHAKE_INAIR) ? true : false;
		UTIL_ASW_ScreenShake( GetAbsOrigin(), Amplitude(), Frequency(), Duration(), Radius(), command, air );
	}
		
	if ( GetSpawnFlags() & SF_ASW_SHAKE_ROPES )
	{
		CRopeKeyframe::ShakeRopes( GetAbsOrigin(), Radius(), Frequency() );
	}

	if ( GetSpawnFlags() & SF_ASW_SHAKE_PHYSICS )
	{
		if ( !m_pShakeController )
		{
			m_pShakeController = physenv->CreateMotionController( &m_shakeCallback );
		}
		// do physics shake
		switch( command )
		{
		case SHAKE_START:
			{
				m_stopTime = gpGlobals->curtime + Duration();
				m_nextShake = 0;
				m_pShakeController->ClearObjects();
				SetNextThink( gpGlobals->curtime );
				m_currentAmp = Amplitude();
				CBaseEntity *list[1024];
				float radius = Radius();
				
				// probably checked "Shake Everywhere" do a big radius
				if ( !radius )
				{
					radius = MAX_COORD_INTEGER;
				}
				Vector extents = Vector(radius, radius, radius);
				Vector mins = GetAbsOrigin() - extents;
				Vector maxs = GetAbsOrigin() + extents;
				int count = UTIL_EntitiesInBox( list, 1024, mins, maxs, 0 );

				for ( int i = 0; i < count; i++ )
				{
					//
					// Only shake physics entities that players can see. This is one frame out of date
					// so it's possible that we could miss objects if a player changed PVS this frame.
					//
					if ( ( list[i]->GetMoveType() == MOVETYPE_VPHYSICS ) )
					{
						IPhysicsObject *pPhys = list[i]->VPhysicsGetObject();
						if ( pPhys && pPhys->IsMoveable() )
						{
							m_pShakeController->AttachObject( pPhys, false );
							pPhys->Wake();
						}
					}
				}
			}
			break;
		case SHAKE_STOP:
			m_pShakeController->ClearObjects();
			break;
		case SHAKE_AMPLITUDE:
			m_currentAmp = Amplitude();
		case SHAKE_FREQUENCY:
			m_pShakeController->WakeObjects();
			break;
		}
	}
}