/** 
 * @file llanimalcontrols.cpp
 * @brief LLAnimalControl class implementation
 *
 * $LicenseInfo:firstyear=2005&license=viewergpl$
 * 
 * Copyright (c) 2005-2008, Linden Research, Inc.
 * 
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 * 
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
 * 
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 * 
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "llanimalcontrols.h"
#include "llglheaders.h"
#include "llsphere.h"
#include "llrand.h"
#include "llviewerobject.h"

/*
//const F32 ANIMAL_CONTROLS_MAX_TENSION_FORCE = 0.99f;// I'll explain in a minute...
//const F32 ANIMAL_CONTROLS_MINIMUM_RADIUS	= 0.005f;

const F32 OPACITY		= 1.0f;
const int _X_			= 0;
const int _Y_			= 1;
const int _Z_			= 2;
const F32 BODY_RADIUS	= 0.2f;
const F32 HEAD_RADIUS	= 0.1f;
const F32 ONE_HALF		= 0.5f;

//-----------------------------------------------
// constructor
//-----------------------------------------------
LLHUDAnimalControls::LLHUDAnimalControls()
: LLHUDObject( LL_HUD_ANIMAL_CONTROLS )// cal the base class and pass this in, K?
{
	mParentObject = NULL;

}//------------------------------------------------------------------------------




//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
// Virtual Server methods...
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
LLAnimalControlsVirtualServer::LLAnimalControlsVirtualServer()
{
	focusPosition.setVec( 0.0f, 0.0f, 0.0f );
	animalPosition.setVec( 0.0f, 0.0f, 0.0f );
	animalRotation			= LLQuaternion::DEFAULT;
	fakeClock				= 0;
	settingFocusPosition	= false;

}//---------------------------------------------------------------------------------



//---------------------------------------------------------------------------------
void LLAnimalControlsVirtualServer::update()
{
	fakeClock ++;

	if ( settingFocusPosition )
	{
		settingFocusPosition = false;
	}

	if ( fakeClock == 20 )
	{
		fakeClock = 0;

		settingFocusPosition = true;

		LLMatrix3 bodyRotationMatrix = animalRotation.getMatrix3();

		LLVector3 forwardDirection	= bodyRotationMatrix.getLeftRow();
		LLVector3 leftDirection		= bodyRotationMatrix.getFwdRow();

		forwardDirection.mV[_Z_] = 0.0f;
		forwardDirection.normVec();
		
		focusPosition = animalPosition + forwardDirection * 5.0f;

		F32 leftRightSpan = 5.0f;

		F32 randomSpan = ll_frand( leftRightSpan );

		focusPosition += leftDirection * ( - leftRightSpan * ONE_HALF + randomSpan );
	}

}//------------------------------------------------------------------------------



//---------------------------------------------------------------------------------
bool LLAnimalControlsVirtualServer::getSettingFocusPosition()
{
	return settingFocusPosition;

}//------------------------------------------------------------------------------

//---------------------------------------------------------------------------------
LLVector3 LLAnimalControlsVirtualServer::getFocusPosition()
{
	return focusPosition;

}//------------------------------------------------------------------------------


//---------------------------------------------------------------------------------
void LLAnimalControlsVirtualServer::setParentPositionAndRotation( LLVector3 p, LLQuaternion r )
{
	animalPosition	= p;
	animalRotation	= r;

}//------------------------------------------------------------------------------

//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
// End of Virtual Server methods...
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------




//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
// Head behavior methods...
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
LLAnimalControlsHeadBehavior::LLAnimalControlsHeadBehavior()
{
	mPosition.setVec		( 0.0f, 0.0f, 0.0f );
	mFocusPosition.setVec	( 0.0f, 0.0f, 0.0f );
	mBodyPosition.setVec	( 0.0f, 0.0f, 0.0f );
	mRotation		= LLQuaternion::DEFAULT;
	mEyesBlinking	= true;
	mEyeBlinkRate	= 0.1f;
	mBodyRotation	= LLQuaternion::DEFAULT;

	LLFlexibleObjectAttributes headFeatherAttributes;
	headFeatherAttributes.mAnchorPositionOffset.setVec( 0.0f, 0.0f, 0.1f );
	headFeatherAttributes.mAnchorDirection.setVec( 0.0f, 1.0f, 1.0f );
	headFeatherAttributes.mAnchorDirection.normVec();
	headFeatherAttributes.mColor = LLColor4( 1.0f, 0.4f, 0.0f, 1.0f );
	headFeatherAttributes.mAnchorRadius = 0.01f;
	headFeatherAttributes.mLength = 0.4f;
	headFeatherAttributes.mEndRadius = 0.06f;
	headFeatherAttributes.mRenderStyle = "tube";

	mFeather.setAttributes( headFeatherAttributes );

}//------------------------------------------------------------------

//------------------------------------------------------------------
void LLAnimalControlsHeadBehavior::setBodyPositionAndRotation( LLVector3 p, LLQuaternion r )
{
	mBodyPosition = p;
	mBodyRotation = r;

}//------------------------------------------------------------------

//------------------------------------------------------------------
void LLAnimalControlsHeadBehavior::setFocusPosition( LLVector3 f )
{
	mFocusPosition = f;

}//------------------------------------------------------------------


//------------------------------------------------------------------
void LLAnimalControlsHeadBehavior::update()
{
	//--------------------------------------------------------------------------
	// Let's get the parent orientation and associated components
	//--------------------------------------------------------------------------
	LLQuaternion	parentOrientation		= mBodyRotation;
	LLMatrix3		parentMatrix			= parentOrientation.getMatrix3();
	LLVector3		parentForwardDirection	= parentMatrix.getLeftRow();
	LLVector3		parentUpwardDirection	= parentMatrix.getUpRow();

	//--------------------------------------------------------------------------
	// head position is based on this
	//--------------------------------------------------------------------------
	mPosition = mBodyPosition + parentForwardDirection * 0.5f + parentUpwardDirection * 0.5f;

	//--------------------------------------------------------------------------------------------------
	// let's figure out how the head would have to rotate in order to aim in the focus direction
	//--------------------------------------------------------------------------------------------------
	LLVector3 headFocusDirection = mFocusPosition - mPosition;
	LLQuaternion headRotationToFocusDirection;
	headRotationToFocusDirection.shortestArc( parentForwardDirection, headFocusDirection );

	//--------------------------------------------------------------------------------------------------
	// Now we rotate the head towards its focus direction
	//--------------------------------------------------------------------------------------------------
	mRotation = parentOrientation * headRotationToFocusDirection;

	//--------------------------------------------------------------------------------------------------
	// now, setting the head feather position and orientation, and updating it...
	//--------------------------------------------------------------------------------------------------
	mFeather.setParentPositionAndRotationDirectly( mPosition, mRotation );
	mFeather.update();

}//------------------------------------------------------------------

//------------------------------------------------------------------


{
	//--------------------------------------------------------------------------------------------------
	// let's get the head rotation components...
	//--------------------------------------------------------------------------------------------------
	LLMatrix3	headMatrix				= mRotation.getMatrix3();
	LLVector3	headForwardDirection	= headMatrix.getLeftRow();
	LLVector3	headUpwardDirection		= headMatrix.getUpRow();
	LLVector3	headLeftDirection		= headMatrix.getFwdRow();

	//------------------------------------------------------
	// show head ball
	//------------------------------------------------------
	glColor4fv( LLColor4( 1.0f, 1.0f, 1.0f, OPACITY ).mV );
	glPushMatrix();
	glTranslatef( mPosition.mV[_X_], mPosition.mV[_Y_], mPosition.mV[_Z_] );
	glScalef( HEAD_RADIUS, HEAD_RADIUS, HEAD_RADIUS );
	gSphere.render();
	glPopMatrix();

	//------------------------------------------------------
	// show head direction
	//------------------------------------------------------
	LLVector3 end = mPosition + headForwardDirection * 0.4f;
	glBegin( GL_LINES );
		glVertex3fv( mPosition.mV );
		glVertex3fv( end.mV );
	glEnd();


	//------------------------------------------------------
	// show eye behavior
	//------------------------------------------------------
	LLVector3 leftEyePosition	= mPosition + headForwardDirection * HEAD_RADIUS + headUpwardDirection * HEAD_RADIUS + headLeftDirection * HEAD_RADIUS * ONE_HALF;
	LLVector3 rightEyePosition	= mPosition + headForwardDirection * HEAD_RADIUS + headUpwardDirection * HEAD_RADIUS - headLeftDirection * HEAD_RADIUS * ONE_HALF;
	glColor4fv( LLColor4( 0.0f, 0.0f, 0.0f, 1.0f ).mV );

	glPushMatrix();
	glTranslatef( leftEyePosition.mV[_X_], leftEyePosition.mV[_Y_], leftEyePosition.mV[_Z_] );
	glScalef( 0.03f, 0.03f, 0.03f );
	gSphere.render();
	glPopMatrix();

	glPushMatrix();
	glTranslatef( rightEyePosition.mV[_X_], rightEyePosition.mV[_Y_], rightEyePosition.mV[_Z_] );
	glScalef( 0.03f, 0.03f, 0.03f );
	gSphere.render();
	glPopMatrix();

	//------------------------------------------------------------------
	// render feather
	//------------------------------------------------------------------
	mFeather.render();

}//------------------------------------------------------------------

//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
// End of head behavior methods...
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------




//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
// Leg behavior methods...
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
LLAnimalControlsLegBehavior::LLAnimalControlsLegBehavior()
{
	mBodyPosition.setVec		( 0.0f, 0.0f, 0.0f );
	mHipAnchorPosition.setVec	( 0.0f, 0.0f, 0.0f ); 
	mBodyRotation		= LLQuaternion::DEFAULT;
	mWalking			= false;
	mIsLeft				= true;

}//-------------------------------------------------------------


//------------------------------------------------------------------
void LLAnimalControlsLegBehavior::setBodyPositionAndRotation( LLVector3 p, LLQuaternion r )
{
	mBodyPosition = p;
	mBodyRotation = r;

}//------------------------------------------------------------------


//---------------------------------------------------------------------------------
void LLAnimalControlsLegBehavior::update()
{

}//-------------------------------------------------------------


//---------------------------------------------------------------------------------
void LLAnimalControlsLegBehavior::render()
{
}//-------------------------------------------------------------








//---------------------------------------------------------------------------------
void LLHUDAnimalControls::update()
{
	if ( ! mParentObject )
	{
		return;
	}

	//-----------------------------------------------------------------------------------
	// To help in development of this client-side functionality, 
	// we are pretending that the server is periodically sending us information,
	// such as focus position (what we want the animal head to look at)
	//-----------------------------------------------------------------------------------
	mVirtualServer.setParentPositionAndRotation( mParentObject->getRenderPosition(), mParentObject->getRenderRotation() ); // fake, hacky, temporary, just ignore this.
	mVirtualServer.update();

	// here is where we ask the virtual server stuff.
	if ( mVirtualServer.getSettingFocusPosition() )
	{
		mHeadBehavior.setFocusPosition( mVirtualServer.getFocusPosition() );
	}

	updateBodyBehavior();

	mHeadBehavior.setBodyPositionAndRotation	( mParentObject->getPosition(), mParentObject->getRenderRotation() );
	mLeftLegBehavior.setBodyPositionAndRotation	( mParentObject->getPosition(), mParentObject->getRenderRotation() );
	mRightLegBehavior.setBodyPositionAndRotation( mParentObject->getPosition(), mParentObject->getRenderRotation() );

	mHeadBehavior.update();
	mLeftLegBehavior.update();
	mRightLegBehavior.update();

}//------------------------------------------------------------------





//------------------------------------------------------------------
void LLHUDAnimalControls::updateBodyBehavior()
{

}//------------------------------------------------------------------




//------------------------------------------------------------------
void LLHUDAnimalControls::render()
{
	mHeadBehavior.render();
	mLeftLegBehavior.render();
	mRightLegBehavior.render();

}//------------------------------------------------------------------









//------------------------------------------------------------------
void LLHUDAnimalControls::setAttributes( LLAnimalControlsAttributes a )
{
	//mAttributes = a; // ???? // how do I do this?

	//mAttributes.mAnchorPositionOffset	= a.mAnchorPositionOffset;
	//mAttributes.mAnchorDirection		= a.mAnchorDirection;
	//mAttributes.mAnchorRadius			= a.mAnchorRadius;	
	//mAttributes.mNumSections			= a.mNumSections;			
	//mAttributes.mLength					= a.mLength;			
	//mAttributes.mGravity				= a.mGravity;			
	//mAttributes.mAirFriction			= a.mAirFriction;		
	//mAttributes.mTension				= a.mTension;			
	//mAttributes.mRadiusChange			= a.mRadiusChange;	

}//------------------------------------------------------------------



//------------------------------------------------------------------
void LLHUDAnimalControls::setParentObject( LLViewerObject * p )
{
	printf( "Setting parent of animal controls %x to object %x \n", this, p );
	mParentObject = p;

}//------------------------------------------------------------------


//------------------------------------------------------------------
LLViewerObject * LLHUDAnimalControls::getParentObject()
{
 return mParentObject;

}//------------------------------------------------------------------



//------------------------------------------------------------------
void LLHUDAnimalControls::markAsDead()
{
	mDead = TRUE;
	mParentObject = NULL;

}//------------------------------------------------------------------




*/