/** 
 * @file lljointsolverrp3.h
 * @brief Implementation of LLJointSolverRP3 class
 *
 * $LicenseInfo:firstyear=2001&license=viewergpl$
 * 
 * Copyright (c) 2001-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$
 */

#ifndef LL_LLJOINTSOLVERRP3_H
#define LL_LLJOINTSOLVERRP3_H

//-----------------------------------------------------------------------------
// Header Files
//-----------------------------------------------------------------------------
#include "lljoint.h"

/* -some compilers don't like line continuation chars-
//-----------------------------------------------------------------------------
// class LLJointSolverRP3
//
// This class is a "poor man's" IK for simple 3 joint kinematic chains.
// It is modeled after the 'ikRPSolver' in Maya.
// This class takes 4 LLJoints:
//   jointA
//   jointB
//   jointC
//   jointGoal
//
// Such that jointA is the parent of jointB, jointB is the parent of jointC.
// When invoked, this class modifies the rotations of jointA and jointB such
// that the position of the jointC attempts to reach the position of jointGoal.
//
// At object initialization time, the distances between jointA - jointB and
// jointB - jointC are cached.  During evaluation these bone lengths are
// preserved.
//
//  A          A 
//  |          |
//  |          |
//  B          B---CG     A---B---C...G
//   \
//    \
//     CG
//
//
// In addition a "poleVector" is specified that does two things:
//
// a) defines the plane in which the solution occurs, thus
//    reducing an infinite number of solutions, down to 2.
//
// b) disambiguates the resulting two solutions as follows:
//
//  A             A            A--->poleVector
//  |              \            \
//  |               \            \
//  B       vs.      B   ==>      B
//   \               |            |
//    \              |            |
//     CG            CG           CG
//
// A "twist" setting allows the solution plane to be rotated about the
// line between A and C.  A handy animation feature.
//
// For "smarter" results for non-coplanar limbs, specify the joints axis
// of bend in the B's local frame (see setBAxis())
//-----------------------------------------------------------------------------
*/

class LLJointSolverRP3
{
protected:
	LLJoint		*mJointA;
	LLJoint		*mJointB;
	LLJoint		*mJointC;
	LLJoint		*mJointGoal;

	F32			mLengthAB;
	F32			mLengthBC;

	LLVector3	mPoleVector;
	LLVector3	mBAxis;
	BOOL		mbUseBAxis;

	F32			mTwist;

	BOOL		mFirstTime;
	LLMatrix4	mSavedJointAMat;
	LLMatrix4	mSavedInvPlaneMat;

	LLQuaternion	mJointABaseRotation;
	LLQuaternion	mJointBBaseRotation;

public:
	//-------------------------------------------------------------------------
	// Constructor/Destructor
	//-------------------------------------------------------------------------
	LLJointSolverRP3();
	virtual ~LLJointSolverRP3();

	//-------------------------------------------------------------------------
	// setupJoints()
	// This must be called one time to setup the solver.
	// This must be called AFTER the skeleton has been created, all parent/child
	// relationships are established, and after the joints are placed in
	// a valid configuration (as distances between them will be cached).
	//-------------------------------------------------------------------------
	void setupJoints(	LLJoint* jointA,
						LLJoint* jointB,
						LLJoint* jointC,
						LLJoint* jointGoal );

	//-------------------------------------------------------------------------
	// getPoleVector()
	// Returns the current pole vector.
	//-------------------------------------------------------------------------
	const LLVector3& getPoleVector();

	//-------------------------------------------------------------------------
	// setPoleVector()
	// Sets the pole vector.
	// The pole vector is defined relative to (in the space of) jointA's parent.
	// The default pole vector is (1,0,0), and this is used if this function
	// is never called.
	// This vector is normalized when set.
	//-------------------------------------------------------------------------
	void setPoleVector( const LLVector3& poleVector );

	//-------------------------------------------------------------------------
	// setBAxis()
	// Sets the joint's axis in B's local frame, and enable "smarter" solve(). 
	// This allows for smarter IK when for twisted limbs.
	//-------------------------------------------------------------------------
	void setBAxis( const LLVector3& bAxis );

	//-------------------------------------------------------------------------
	// getTwist()
	// Returns the current twist in radians.
	//-------------------------------------------------------------------------
	F32 getTwist();

	//-------------------------------------------------------------------------
	// setTwist()
	// Sets the twist value.
	// The default is 0.0.
	//-------------------------------------------------------------------------
	void setTwist( F32 twist );

	//-------------------------------------------------------------------------
	// solve()
	// This is the "work" function.
	// When called, the rotations of jointA and jointB will be modified
	// such that jointC attempts to reach jointGoal.
	//-------------------------------------------------------------------------
	void solve();
};

#endif // LL_LLJOINTSOLVERRP3_H

