/*****************************************************************************
 * $Id: game_pony_craft.cc,v 1.16 2006/08/21 23:48:18 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	Craft derivative class.
 *//*
 * LEGAL:	COPYRIGHT (C) 2004 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 *****************************************************************************/

#define GAME_PONY_CRAFT_CC 1
#include "game_pony_common.hh"
#include "game_base_craft.hh"
#include "game_pony_craft.hh"

////////////////////////////////////////////////////////////////////////////////
//////////////////////////////  CraftF14Tomcat  ////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// Sweeping wings:
// In the Blender model, the wings were marked as "Vertex Groups".
// The Python script export-palomino.py exports Vertex Groups.
// Two Vertex Groups define a wing, two more Vertex Groups define
// a single vertex around which the wing will be rotated (wing sweep).
// When this program starts, the base DynaModel imports those Vertex Groups
// into an Importation object, which becomes available here
// as CraftF14Tomcat::mModels[].GetVertexGroupVixs().
// Two matrixs are positioned at a vertex on each each wing,
// and the matrix is used to transform the vertexs of the wing.
// The vertexs are indexed by the vixs (vertex indexs).
// -----------------------------------------------------------------------------

const Percent F14_WING_SWEEP_SPEED		= 20;		// min speed when wings will sweep back
const fp	  F14_WING_SWEEP_DEGREE		= 45.0;		// max wing sweep-back (delta configuration)
const fp      F14_GLOVE_VANE_DEGREE		= 43.0;		// wing sweep threshold when vanes will extend
const uint	  F14_ADJUST_WINGS_MILSEC	= 100;		// to smoothly adjust wings
const uint	  F14_ADJUST_GEARS_MILSEC	= 100;
const fp	  F14_DEG_WINGS_SPREAD      = 0.0;
const fp      F14_DEG_GEARS_RETRACTED   = 90.0;
const fp      F14_DEG_GEARS_EXTENDED    = 0.0;

/*****************************************************************************
 * Constructor.
 *****************************************************************************/
CraftF14Tomcat::CraftF14Tomcat( QuadrantPtrc q, const Position& pos, const vector<string>& fnameModelVec )
:   Craft(q,pos,fnameModelVec),
	mDegSweep(0.0),
	mDegGloveVanes(0.0),
	mDegGears(0.0),
	mAdjustWingsMilsec(0),
	mAdjustGearsMilsec(0),
	mGearState(eGear_DOWN),
    mPartLeftWing(       *this, mModels[0].mImportation.GetVertexGroupVixs("LeftWing"),       mModels[0].mImportation.GetVertexGroupVixs("LeftWingPivot")[0] ),
    mPartRightWing(      *this, mModels[0].mImportation.GetVertexGroupVixs("RightWing"),      mModels[0].mImportation.GetVertexGroupVixs("RightWingPivot")[0] ),
    mPartLeftGloveVane(  *this, mModels[0].mImportation.GetVertexGroupVixs("LeftGloveVane"),  mModels[0].mImportation.GetVertexGroupVixs("LeftGloveVanePivot")[0] ),
    mPartRightGloveVane( *this, mModels[0].mImportation.GetVertexGroupVixs("RightGloveVane"), mModels[0].mImportation.GetVertexGroupVixs("RightGloveVanePivot")[0] ),
    mPartLeftTailplane(  *this, mModels[0].mImportation.GetVertexGroupVixs("LeftTailplane"),  mModels[0].mImportation.GetVertexGroupVixs("LeftTailplanePivot")[0] ),
    mPartRightTailplane( *this, mModels[0].mImportation.GetVertexGroupVixs("RightTailplane"), mModels[0].mImportation.GetVertexGroupVixs("RightTailplanePivot")[0] ),
    mPartFrontGear(      *this, mModels[0].mImportation.GetVertexGroupVixs("FrontGear"),      mModels[0].mImportation.GetVertexGroupVixs("FrontGearPivot")[0] ),
    mPartLeftGear(       *this, mModels[0].mImportation.GetVertexGroupVixs("LeftGear"),      mModels[0].mImportation.GetVertexGroupVixs("LeftGearPivot")[0] ),
    mPartRightGear(      *this, mModels[0].mImportation.GetVertexGroupVixs("RightGear"),      mModels[0].mImportation.GetVertexGroupVixs("RightGearPivot")[0] )
{
	DEBUG_CODE( CheckObjectCtor(); )

	// Blender model has both wings spread and glove vanes extended.
	// Retract glove vanes initially.
	AdjustGloveVanes( F14_DEG_WINGS_SPREAD );

    // If game mode, Tomcats are flying, so retract landing gears.
    if ( gGame.IfGameMode() )
    {
        RetractLandingGears();
    }
}
CraftF14Tomcat::~CraftF14Tomcat()
{
	DEBUG_CODE( CheckObjectDtor(); )
}

/*****************************************************************************
 * Reset.
 *****************************************************************************/
void
CraftF14Tomcat::Reset( void )
{
    // Spread wings and lower landing gears immediately.
    AdjustWings2( 0 );
    ExtendLandingGears();
    Parent::Reset();
}

/*****************************************************************************
 * Animation is driven by a timer.
 * See eng_dyna.hh about relationship of Animate() methods.
 *****************************************************************************/
int
CraftF14Tomcat::Animate( void )
{
	int redisplay = 0;

	redisplay |= AdjustWings();			// Tomcat wing-sweep changes with speed
	redisplay |= AdjustGears();
	redisplay |= Parent::Animate();

	return redisplay;
}

/*****************************************************************************
 * Sweep F-14 Tomcat wings.
 * @return True if wings were adjusted.
 *****************************************************************************/
bool
CraftF14Tomcat::AdjustWings( void )
{
	// TODO: Speed should be a Mach float value, not a simple percent.
	// TODO: A real F-14 sweeps its wings according to speed, not throttle.

	// Adjust wings according to time (try to avoid flutter).
	const uint milsec = gEng.GetMilsecTotal();
	if ( milsec - mAdjustWingsMilsec < F14_ADJUST_WINGS_MILSEC )
	{
		return false;
	}
	mAdjustWingsMilsec = milsec;  // remember

	// Gradually adjust wings by a small degree every frame until
	// the desired sweep is reached.
	const fp inc = 1.5;
	const Percent speed = GetThrottle();
	const fp degSweep = (speed <= F14_WING_SWEEP_SPEED) ? 0.0 : fp(speed) / 100.0 * F14_WING_SWEEP_DEGREE;
	AdjustGloveVanes( mDegSweep );  // current wing sweep
	if ( degSweep - mDegSweep < -inc )
	{
		// Sweep back.
		mDegSweep -= inc;
        AdjustWings2( mDegSweep );
    	return true;
	}
	else if ( degSweep - mDegSweep > inc )
	{
		// Sweep forward.
		mDegSweep += inc;
        AdjustWings2( mDegSweep );
    	return true;
	}
	else
	{
		// Desired sweep was reached.
		return false;
	}
}
// Adjust wings directly.
void
CraftF14Tomcat::AdjustWings2( const fp deg )
{
    mDegSweep = deg;
    mPartLeftWing.Rotate(  AXIS_Y, -mDegSweep );
    mPartRightWing.Rotate( AXIS_Y,  mDegSweep );
}

/*****************************************************************************
 * Adjust glove vanes based on wing sweep.
 *****************************************************************************/
bool
CraftF14Tomcat::AdjustGloveVanes( const fp degSweep )
{
	// Gradually adjust glove vanes.
	const fp inc = 2.5;
    const fp degGloveVane = degSweep >= F14_GLOVE_VANE_DEGREE ? 0.0 : 45.0;
	if ( degGloveVane - mDegGloveVanes < -inc)
	{
		mDegGloveVanes -= inc;
	}
	else if ( degGloveVane - mDegGloveVanes > inc)
	{
		mDegGloveVanes += inc;
	}
	else
	{
		return false;
	}

    // Rotate glove vanes.
	mPartLeftGloveVane.Rotate(  AXIS_Y, -mDegGloveVanes );
	mPartRightGloveVane.Rotate( AXIS_Y,  mDegGloveVanes );
	return true;
}

/*****************************************************************************
 * Adjust tailplanes
 *****************************************************************************/
bool
CraftF14Tomcat::AdjustTailplanes( const fp deg )
{
    // TODO
    return false;
}

/*****************************************************************************
 * Adjust landing gear.
 * @return True if gears were adjusted.
 *****************************************************************************/
bool
CraftF14Tomcat::AdjustGears( void )
{
	const uint milsec = gEng.GetMilsecTotal();
	if ( milsec - mAdjustGearsMilsec < F14_ADJUST_GEARS_MILSEC )
	{
		return false;
	}
	mAdjustGearsMilsec = milsec;  // remember

	// Gradually adjust by a small degree every frame.
	const fp inc = 2.0;
	const fp degGears = (mGearState == eGear_DOWN) ? F14_DEG_GEARS_EXTENDED : F14_DEG_GEARS_RETRACTED;
	if ( degGears - mDegGears < -inc )
	{
		mDegGears -= inc;
        AdjustGears2( mDegGears );
    	return true;
	}
	else if ( degGears - mDegGears > inc )
	{
		mDegGears += inc;
        AdjustGears2( mDegGears );
    	return true;
	}
	else
	{
		// Desired rotation was reached.
		return false;
	}
}
// Adjust landing gears directly.
void
CraftF14Tomcat::AdjustGears2( const fp deg )
{
    mDegGears = deg;
    if ( deg >= F14_DEG_GEARS_RETRACTED * 0.9 )  // nearly at extreme retraction?
    {
        // A reliable way to make the gears disappear
        // is to write (0,0,0) to each vertex so gear
        // is just a tiny point in center of craft.
        const static LocalVertex point(0,0,0);
        mPartFrontGear.Implode( point );
        mPartLeftGear.Implode( point );
        mPartRightGear.Implode( point );
    }
    else
    {
        mPartFrontGear.Rotate(  AXIS_X, mDegGears );
        mPartLeftGear.Rotate(   AXIS_X, mDegGears );
        mPartRightGear.Rotate(  AXIS_X, mDegGears );
    }
}
void
CraftF14Tomcat::RetractLandingGears( void )
{
    mGearState = eGear_UP;
    AdjustGears2( F14_DEG_GEARS_RETRACTED );
}
void
CraftF14Tomcat::ExtendLandingGears( void )
{
    mGearState = eGear_DOWN;
    AdjustGears2( F14_DEG_GEARS_EXTENDED );
}
