void IVP_Controller_Raycast_Airboat::DoSimulationKeepUprightRoll(IVP_Raycast_Airboat_Impact *pImpacts,
                                                                 IVP_Event_Sim *pEventSim)
{
	IVP_Core *pAirboatCore = m_pAirboatBody->get_core();

	IVP_U_Float_Point dir, temp, cross;
	temp.set(0.0f, -1.0f, 0.0f);
	pAirboatCore->get_m_world_f_core_PSI()->vimult3(&temp, &dir);
	dir.k[1] = -0.9848077f; // -cos(10deg)
	dir.normize();
	temp.set(0.0f, -0.9848077f, 0.17364818f); // 0.0, -cos(10deg), sin(10deg)
	cross.calc_cross_product(&temp, &dir);
	IVP_DOUBLE roll = IVP_Inline_Math::atan2d(cross.real_length_plus_normize(), temp.dot_product(&dir));

	IVP_BOOL bImpact = IVP_FALSE;
	int iPoint;
	for (iPoint = 0; iPoint < n_wheels; ++iPoint, ++pImpacts)
	{
		if (pImpacts->bImpact)
		{
			bImpact = IVP_TRUE;
			break;
		}
	}
	if (bImpact || (fabs(roll) < (10.0 * IVP_PI / 180.0)))
	{
		m_flKeepUprightRoll = roll;
		return;
	}

	IVP_FLOAT mass = pAirboatCore->get_mass();
	temp.set_multiple(&cross, (pEventSim->i_delta_time * 0.3 * (roll - m_flKeepUprightRoll) + roll * 0.2) * mass);
	m_flKeepUprightRoll = roll;
	mass *= (2.0 * IVP_PI / 180.0);
	IVP_FLOAT length = temp.real_length_plus_normize();
	if (length > mass)
		length = mass;
	temp.mult(length);
	pAirboatCore->rot_push_core_cs(&temp);
}
void IVP_Controller_Raycast_Airboat::DoSimulationKeepUprightPitch(IVP_Raycast_Airboat_Impact *pImpacts,
                                                                  IVP_Event_Sim *pEventSim)
{
	if (m_bAirborneIdle)
		return;

	IVP_Core *pAirboatCore = m_pAirboatBody->get_core();

	IVP_U_Float_Point dir, temp, cross;
	temp.set(0.0f, -1.0f, 0.0f);
	pAirboatCore->get_m_world_f_core_PSI()->vimult3(&temp, &dir);
	dir.k[0] = 0.0f;
	dir.normize();
	temp.set(0.0f, -0.9848077f, 0.17364818f); // 0.0, -cos(10deg), sin(10deg)
	cross.calc_cross_product(&temp, &dir);
	IVP_DOUBLE pitch = IVP_Inline_Math::atan2d(cross.real_length_plus_normize(), temp.dot_product(&dir));

	int iPoint;
	for (iPoint = 0; iPoint < n_wheels; ++iPoint, ++pImpacts)
	{
		if (pImpacts->bImpact)
		{
			m_flKeepUprightPitch = pitch;
			return;
		}
	}

	IVP_FLOAT mass = pAirboatCore->get_mass();
	temp.set_multiple(&cross, (pEventSim->i_delta_time * 0.04 * (pitch - m_flKeepUprightPitch) + pitch * 0.1) * mass);
	m_flKeepUprightPitch = pitch;
	mass *= (1.5 * IVP_PI / 180.0);
	IVP_FLOAT length = temp.real_length_plus_normize();
	if (length > mass)
		length = mass;
	temp.mult(length);
	pAirboatCore->rot_push_core_cs(&temp);
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void IVP_Controller_Raycast_Airboat::DoSimulationSteering(IVP_Event_Sim *pEventSim)
{
	IVP_Core *pAirboatCore = m_pAirboatBody->get_core();

	if ((m_SteeringAngle == 0.0f) || (m_flThrust != 0.0f))
	{
		if (m_bAnalogSteering)
		{
			if (m_flThrust < -2.0f)
				m_bReverseSteering = IVP_TRUE;
			else if ((m_flThrust > 2.0f) || (m_LocalVelocity.k[2] > 0.0f))
				m_bReverseSteering = IVP_FALSE;
		}
		else
		{
			if (m_flThrust < 0.0f)
				m_bReverseSteering = IVP_TRUE;
			else if ((m_flThrust > 0.0f) || (m_LocalVelocity.k[2] > 0.0f))
				m_bReverseSteering = IVP_FALSE;
		}
	}

	IVP_FLOAT flForceRotational;
	IVP_FLOAT flSteeringSign;
	IVP_FLOAT flMass = pAirboatCore->get_mass();

	if (fabsf(m_SteeringAngle) > 0.01)
	{
		flSteeringSign = (m_SteeringAngle < 0.0f ? -1.0f : 1.0f);
		if (m_bReverseSteering)
			flSteeringSign = -flSteeringSign;
		IVP_FLOAT flLastSign = (m_LastForwardSteeringAngle < 0.0f ? -1.0f : 1.0f);
		if ((fabsf(m_LastForwardSteeringAngle) < 0.01) || (flSteeringSign != flLastSign))
			m_SteeringSpeed = 0.0f;

		flForceRotational = (m_bAnalogSteering ? fabsf(m_SteeringAngle) : m_SteeringSpeed) * 2.0f;
		if (flForceRotational < 0.0f)
			flForceRotational = 0.0f;
		else if (flForceRotational > 1.0f)
			flForceRotational = 1.0f;
		flForceRotational = flForceRotational * IVP_RAYCAST_AIRBOAT_STEERING_RATE + (IVP_RAYCAST_AIRBOAT_STEERING_RATE * 0.25f);
		flForceRotational *= -(flMass * pEventSim->i_delta_time * flSteeringSign);
		m_SteeringSpeed += pEventSim->delta_time;
	}
	else
	{
		flForceRotational = 0.0f;
	}

	m_LastForwardSteeringAngle = m_SteeringAngle;
	if (m_bReverseSteering)
		m_LastForwardSteeringAngle = -m_LastForwardSteeringAngle;

	IVP_FLOAT flRotSpeed = pAirboatCore->rot_speed.k[1];
	flSteeringSign = (flRotSpeed < 0.0f ? -1.0f : 1.0f);

	IVP_FLOAT flForceImpulse = flMass * pEventSim->i_delta_time * flSteeringSign;
	flForceRotational += 0.0004f * flRotSpeed * flRotSpeed * flForceImpulse;
	flForceRotational += 0.001f * fabsf(flRotSpeed) * flForceImpulse;

	IVP_U_Float_Point vecAngularImpulse;
	vecAngularImpulse.set(0.0f, -flForceRotational, 0.0f);
	pAirboatCore->rot_push_core_cs(&vecAngularImpulse);
}