//===========================================================================//
// File:	HilAdjust.cpp                                                 
// Project: MechWarrior 4
// Contents: Plugin to adjust height of max anmiations
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 04/28/99  JSE  Initial coding, 
// 06/22/99	 jkyle Maintenance and cleanup
//---------------------------------------------------------------------------//
// Copyright (C) 1998, Fasa Interactive, Inc.
// All Rights reserved worldwide
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL
//===========================================================================//


#include "stdafx.h"

#ifdef STRICT							// Already defined by stdafx,
#undef STRICT							// so we avoid warning linking msg
#endif
#ifdef _MBCS							// The same as above
#undef _MBCS
#endif


#include "HillAdjust.hpp"
#include ".\buildnum\curver.h"

#pragma pack(push,8)

const float NAN = (float)fmod(0.0,0.0);
char g_szDir[][6] = {"Up","Down","Left","Right"};
HFONT g_hMyFont = NULL;
int g_bHold = 0;

CMapWordToOb g_mapCtlData;

//#ifdef _DEBUG
//#define new DEBUG_NEW
//#undef THIS_FILE
//static char THIS_FILE[] = __FILE__;
//#endif


HillAdjustPanel g_hillAdjustPanel;

//////////////////
//Local Prototypes

// Class that g_mapCtlData maps to
class CCtlData : public CObject
{
	float m_fDefault,m_fOldValue;
	ISpinnerControl *m_pSpinner;
	int m_idEdit,m_idSpinner,m_idCheck,m_bEnabled;
public:
	CCtlData(HWND hWnd,HKEY hKey,int idCheck,int idSpinner,int idEdit,float min,float max,float inc,float fDefault);
	virtual ~CCtlData();
	ISpinnerControl *GetSpinner() { return m_pSpinner;};
	int GetIdEdit() {return m_idEdit;};
	float SaveValue(float fval);
	float GetDefault() {return m_fDefault;};
	int GetIdSpinner() {return m_idSpinner;};
	int IsEnabled() {return m_bEnabled;};
	void Enable(int i) {m_bEnabled = i;};
};	

CCtlData::CCtlData(HWND hWnd,HKEY hKey,int idCheck,int idSpinner,int idEdit,float min,float max,float inc,float fDefault)
{
	float fcurrent = fDefault;
	int m_bEnabled = 0;
	if (hKey)
	{
		DWORD wType = REG_SZ;
		char szValue[100];
		BYTE *pData = (BYTE *)szValue;
		DWORD size = 100;
		char szInt[20];
		if (ERROR_SUCCESS != RegQueryValueEx(hKey,itoa(idCheck,szInt,10),0,&wType,pData,&size))
		{
		}
		else
			sscanf(szValue,"%i %f",&m_bEnabled,&fcurrent);
	}
	m_pSpinner = SetupFloatSpinner(hWnd,idSpinner,idEdit,min,max,fcurrent,inc);
	m_idEdit = idEdit;
	m_idSpinner = idSpinner;
	m_idCheck = idCheck;
	m_fDefault = fDefault;
	m_fOldValue = fDefault;
	g_mapCtlData.SetAt(idCheck,this);
	//if (!m_bEnabled)
	if (fabs(fDefault - fcurrent)  > 0.0001f)
	{
		SetDlgFont(GetDlgItem(hWnd,idEdit),g_hMyFont);
	}
	else
	{
		SetDlgFont(GetDlgItem(hWnd,idEdit),GetFixedFont());
	}
	InvalidateRect(GetDlgItem(hWnd,idEdit),NULL,false);


//	EnableWindow(GetDlgItem(hWnd,idEdit),bEnabled);
}

CCtlData::~CCtlData()
{
	ReleaseISpinner(m_pSpinner);
}

float CCtlData::SaveValue(float fval)
{
	float oldval = m_fOldValue;
	m_fOldValue = fval;
	return oldval;
}

char g_szDestPath[MAX_PATH];

static int CALLBACK BrowseCallbackProc(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
	RECT rect;
	//
	//Center the browse dialog on the screen...
	//
	switch (uMsg)
	{
	case BFFM_INITIALIZED:
		{
			char szPath[MAX_PATH];
			GetCurrentDirectory(MAX_PATH,szPath);
			SendMessage(hWnd,BFFM_SETSELECTION,TRUE,(LPARAM)szPath);
	
			if (GetWindowRect(hWnd, &rect))
			{
				SetWindowPos(hWnd, 
							 HWND_TOP,
							 (GetSystemMetrics(SM_CXSCREEN) - (rect.right - rect.left)) >> 1,
							 (GetSystemMetrics(SM_CYSCREEN) - (rect.bottom - rect.top)) >> 1,
							 0,
							 0,
							 SWP_NOSIZE);
			}
		}
	}
	return 0;
}

////////////////////////////////////////////////////////////////////////////////
// hillAdjustPanel Dialog Procedure to handle User and System Interactions
static int CALLBACK HillAdjustPanelProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
//	ICustomControl *pControl = NULL;
	
	switch (msg) {
		case WM_QUICKFILE_BEGIN:
			{
				TCHAR        szBuffer[MAX_PATH];
				LPITEMIDLIST pidlBrowse,pidlRoot;
				BROWSEINFO   bi;

				LPMALLOC lpMalloc;
				SHGetMalloc(&lpMalloc);
				ASSERT(lpMalloc);
				bi.hwndOwner = hWnd;
				// Get the ID for the "My Computer" root folder
				SHGetSpecialFolderLocation(hWnd,CSIDL_DRIVES,&pidlRoot);

				bi.pidlRoot  = pidlRoot;
				bi.pszDisplayName = szBuffer;

				// Localize the descriptive text
				bi.lpszTitle = "Select Destination Folder";

				// BIF_EDITBOX and BIF_VALIDATE are for versions 4.71 and later, they
				// might be ignored by older versions
				bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT;//BIF_USENEWUI;//BIF_EDITBOX; //BIF_RETURNONLYFSDIRS | BIF_EDITBOX;// | BIF_VALIDATE;
				bi.lParam = 0;
				bi.iImage = NULL;
				bi.lpfn = BrowseCallbackProc;
				g_szDestPath[0] = '\0';
				//
				//Call the Windows shell folder browsing routine...
				//
				pidlBrowse = SHBrowseForFolder(&bi);
				if (NULL != pidlBrowse)
				{
					if (SHGetPathFromIDList(pidlBrowse, g_szDestPath))
					{

						if ('\\' == szBuffer[lstrlen(szBuffer)-1])
							szBuffer[lstrlen(szBuffer)-1] = '\0';

					}
					else
						g_szDestPath[0] = '\0';
					//
					//Free up shell memory used...
					//
					lpMalloc->Free(pidlBrowse);
				}
				lpMalloc->Free(pidlRoot);
				lpMalloc->Release();
				break;
			}
		case WM_QUICKFILE_END:
			{
				break;
			}
		case WM_QUICKFILE_APPLYFILE:
			{
				char *name = (char *)wParam;
				char *path = (char *)lParam;
				g_hillAdjustPanel.m_ip->LoadFromFile(path);

				theHold.SuperBegin();

				g_hillAdjustPanel.AdjustToHill();

				g_hillAdjustPanel.m_ip->RedrawViews(g_hillAdjustPanel.m_ip->GetTime(),REDRAW_BEGIN);
				g_hillAdjustPanel.m_ip->RedrawViews(g_hillAdjustPanel.m_ip->GetTime(),REDRAW_NORMAL);
				g_hillAdjustPanel.m_ip->RedrawViews(g_hillAdjustPanel.m_ip->GetTime(),REDRAW_END);

				theHold.SuperAccept("HillAdjust");

				char szNewName[MAX_PATH];
				sprintf(szNewName,"%s\\%s%c",g_szDestPath,name,g_szDir[g_hillAdjustPanel.m_angleEnum][0]);
				if (0xFFFFFFFF == GetFileAttributes(szNewName))
				{
					// File already exists
					CFileDialog fd(FALSE,NULL,NULL,0,"Max Files (*.max)|*.max||",CWnd::FromHandle(g_hillAdjustPanel.m_hPanel));
					char *filebuf = new char[MAX_PATH*200];
					filebuf[0] = 0;
					fd.m_ofn.lpstrFile = filebuf;
					fd.m_ofn.nMaxFile = MAX_PATH*200;
					if (fd.DoModal()==IDOK)
					{
						g_hillAdjustPanel.m_ip->SaveToFile(fd.GetPathName());
					}
					break;
				}
				else
				{
					g_hillAdjustPanel.m_ip->SaveToFile(szNewName);
				}
				break;
			}
		case WM_INITDIALOG:						//Panel's extra initialization
			g_hillAdjustPanel.Init(hWnd);
			break;
		case WM_DESTROY:						//Panel's extra destruction
			g_hillAdjustPanel.Destroy(hWnd);
			break;
	/*	case WM_CTLCOLOREDIT:
			{
				HDC hDC = (HDC)wParam;
				HWND hWndEdit = (HWND)lParam;


				POSITION pos = g_mapCtlData.GetStartPosition();
				CCtlData *pData;
				WORD key;
				BOOL bFound = false;
				/*while (pos)
				{
					CObject *pObj;
					g_mapCtlData.GetNextAssoc(pos,key,pObj);
					pData = (CCtlData *)pObj;
					//if (pSpinner == pData->GetSpinner())
					int id = GetWindowLong(hWndEdit,GWL_ID);
					if (pData && (pData->GetIdEdit() == id))
					{
						bFound = true;
						break;
					}
				}
				if (bFound)
				{
				}

*//*

				char sz[MAX_PATH],sz1[MAX_PATH];
				GetWindowText(hWndEdit,sz,MAX_PATH);
				GetWindowText(hWnd,sz1,MAX_PATH);
				static int x = 0;
				x++;
				static int y = 2;
				if (x==y)
					int z=1;

				return DefWindowProc(hWnd,msg,wParam,lParam);
				return (int)GetLTGrayBrush();
			}
*/
		case WM_COMMAND :
			{
				switch (LOWORD(wParam)) 
				{			//Handle Panel's controls
				case IDC_ABOUT: 
					{
						CAbout dlg;
						dlg.DoModal();
						break;
					}
				case IDC_LEAVE_TANG:
					{
						g_hillAdjustPanel.m_leaveOriginalTangents = !g_hillAdjustPanel.m_leaveOriginalTangents;
						break;
					}
				case IDC_LEAVE_CURVE:
					{
						g_hillAdjustPanel.m_leaveOriginalCurves = !g_hillAdjustPanel.m_leaveOriginalCurves;
						break;
					}
				case IDC_HILL_ADJUST: 
					{
						if (g_bHold)
							g_hillAdjustPanel.m_ip->FileFetch();
						theHold.SuperBegin();
						g_hillAdjustPanel.AdjustToHill();
						g_hillAdjustPanel.m_ip->RedrawViews(g_hillAdjustPanel.m_ip->GetTime(),REDRAW_BEGIN);
						g_hillAdjustPanel.m_ip->RedrawViews(g_hillAdjustPanel.m_ip->GetTime(),REDRAW_NORMAL);
						g_hillAdjustPanel.m_ip->RedrawViews(g_hillAdjustPanel.m_ip->GetTime(),REDRAW_END);
						theHold.SuperAccept("HillAdjust");
						break;
					}
				case IDC_HILL_HOLD:
				{
					switch (HIWORD(wParam))
					{
					case BN_CLICKED:
						{
							g_bHold = true;
							g_hillAdjustPanel.m_ip->FileHold();
							/*g_bHold = 1-g_bHold;
							if (!g_bHold)
							{
								g_bHold = false;
								g_hillAdjustPanel.m_ip->FileFetch();
							}
							else
							{
								g_bHold = true;
								g_hillAdjustPanel.m_ip->FileHold();
							}
							SetDlgItemText(hWnd,IDC_HILL_HOLD,g_bHold?"Fetch Saved":"Hold Current State");
							//SendMessage(hWnd,BM_SETSTATE,g_bHold?BST_PUSHED:0,0);*/
							break;
						}
					case BN_PUSHED:
						{
							int x=1;
							break;
						}
					}

					break;
				}
				case IDC_HILL_FETCH:
					{
						switch (HIWORD(wParam))
						{
						case BN_CLICKED:
							{
								g_bHold = false;
								g_hillAdjustPanel.m_ip->FileFetch();
								break;
							}
						}
						break;
					}
				case IDC_COMBO_DIRECTION:
					{
						switch (HIWORD(wParam))
						{
							case CBN_SELENDOK:
							{
								g_hillAdjustPanel.SaveValues();
								int sel = SendDlgItemMessage(hWnd,IDC_COMBO_DIRECTION,CB_GETCURSEL,0,0);
								g_hillAdjustPanel.m_angleEnum =  SendDlgItemMessage(hWnd,IDC_COMBO_DIRECTION,CB_GETITEMDATA,sel,0);
								ReleaseISpinner(g_hillAdjustPanel.m_angleSpinner);
								ReleaseISpinner(g_hillAdjustPanel.m_rootScalePosXControl);
								ReleaseISpinner(g_hillAdjustPanel.m_rootScalePosYControl);
								ReleaseISpinner(g_hillAdjustPanel.m_rootScalePosZControl);
								ReleaseISpinner(g_hillAdjustPanel.m_rootScaleRotXControl);
								ReleaseISpinner(g_hillAdjustPanel.m_rootScaleRotYControl);
								ReleaseISpinner(g_hillAdjustPanel.m_rootScaleRotZControl);

								ReleaseISpinner(g_hillAdjustPanel.m_rootMovePosXControl);
								ReleaseISpinner(g_hillAdjustPanel.m_rootMovePosYControl);
								ReleaseISpinner(g_hillAdjustPanel.m_rootMovePosZControl);
								ReleaseISpinner(g_hillAdjustPanel.m_rootMoveRotXControl);
								ReleaseISpinner(g_hillAdjustPanel.m_rootMoveRotYControl);
								ReleaseISpinner(g_hillAdjustPanel.m_rootMoveRotZControl);

								ReleaseISpinner(g_hillAdjustPanel.m_hipScaleControl);
								ReleaseISpinner(g_hillAdjustPanel.m_hipMoveControl);

								ReleaseISpinner(g_hillAdjustPanel.m_torsoScaleXControl);
								ReleaseISpinner(g_hillAdjustPanel.m_torsoScaleYControl);
								ReleaseISpinner(g_hillAdjustPanel.m_torsoScaleZControl);

								ReleaseISpinner(g_hillAdjustPanel.m_leftFootScaleCloseControl);
								ReleaseISpinner(g_hillAdjustPanel.m_rightFootScaleCloseControl);

								g_hillAdjustPanel.LoadValues(hWnd);
							}
						}
						break;
					} // Case COMBO DIRECTION
				default:
					{
						CObject *pObj;
						if (g_mapCtlData.Lookup(LOWORD(wParam),pObj))
						{
							CCtlData *pData = (CCtlData *)pObj;
							HWND hWindow = GetDlgItem(hWnd,pData->GetIdEdit());
							//if (fabs(pData->GetDefault() - pData->GetSpinner()->GetFVal())  < 0.0001f)
							if (pData->IsEnabled())
							{
								//SetDlgFont(hWindow,g_hMyFont);
								pData->Enable(false);
								//EnableWindow(hWindow,FALSE);
								//float oldval = pData->SaveValue(pData->GetSpinner()->GetFVal());
								//pData->GetSpinner()->SetValue(oldval,TRUE);
	
								SetDlgFont(hWindow,GetFixedFont());
								//pData->GetSpinner()->SetValue(pData->SaveValue(pData->GetDefault()),TRUE);
								float oldval = pData->GetSpinner()->GetFVal();
								pData->GetSpinner()->SetValue(pData->GetDefault(),TRUE);
								pData->SaveValue(oldval);
								InvalidateRect(hWindow,NULL,false);
								// store old value
								// Set value to identity value
							}
							else
							{
								pData->Enable(true);
								//EnableWindow(hWindow,TRUE);
								//SetDlgFont(hWindow,GetFixedFont());
								//pData->GetSpinner()->SetValue(pData->SaveValue(pData->GetDefault()),TRUE);
								
								SetDlgFont(hWindow,g_hMyFont);
								//float oldval = pData->SaveValue(pData->GetDefault());
								float oldval = pData->SaveValue(pData->GetSpinner()->GetFVal());
								pData->GetSpinner()->SetValue(oldval,TRUE);
								InvalidateRect(hWindow,NULL,false);
								// restore old value
								// set old value to identity
							}
						}
						break;

					}
				} //END switch LOPARAM()
				break;
			} // END case WM_COMMAND:

		case CC_SPINNER_CHANGE:
			{
				int ctrlID = LOWORD(wParam);
				//if (HIWORD(wParam))
				{
					ISpinnerControl *pSpinner = (ISpinnerControl *)lParam;
					POSITION pos = g_mapCtlData.GetStartPosition();
					CCtlData *pData;
					WORD key;
					BOOL bFound = false;
					while (pos)
					{
						CObject *pObj;
						g_mapCtlData.GetNextAssoc(pos,key,pObj);
						pData = (CCtlData *)pObj;
						//if (pSpinner == pData->GetSpinner())
						if (pData && (pData->GetIdSpinner() == ctrlID))
						{
							bFound = true;
							break;
						}
					}
					if (bFound)
					{
						HWND hWindow = GetDlgItem(hWnd,pData->GetIdEdit());
						// if it is < 0.0001f it is close enuf to zero
						if (   fabs(pData->GetDefault() - pSpinner->GetFVal())  > 0.0001f)
						{
							//pData->Enable(false);
							//EnableWindow(hWindow,FALSE);
							pData->Enable(true);
							SetDlgFont(hWindow,g_hMyFont);
							float oldval = pData->SaveValue(pData->GetSpinner()->GetFVal());
							//pData->GetSpinner()->SetValue(pData->GetDefault(),TRUE);
							InvalidateRect(hWindow,NULL,false);
							// store old value
							// Set value to identity value
						}
						else
						{
							//pData->Enable(true);
							pData->Enable(false);
							SetDlgFont(hWindow,GetFixedFont());
							//EnableWindow(hWindow,TRUE);
							pData->SaveValue(pData->GetDefault());
							InvalidateRect(hWindow,NULL,false);
							// restore old value
							// set old value to identity
						}
					}
				}
				// if the new spinner value is equal to the default then shade the edit window
				break;
			}
		////////////////////////////////////////////////////////////////////////
		//The following lines are not necessary for MAX2 Plugins
		case WM_LBUTTONDOWN:
		case WM_LBUTTONUP:
		case WM_MOUSEMOVE:
			g_hillAdjustPanel.m_ip->RollupMouseMessage(hWnd, msg, wParam, lParam);
			break;
		////////////////////////////////////////////////////////////////////////

		default:
			return FALSE;
		}
	return TRUE;
}


////////////////////////////////////////////////////////////////////////////////
// Display the Plugin's Panel
void HillAdjustPanel::BeginEditParams(Interface* ip, IUtil* iu)
{
	m_ip = ip;								//Get the Plugin's Interface
	m_iu = iu;								//Get the Utility Plugin's Interface

	//Display the plugin's Rollup Dialog
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	HINSTANCE loc_hInstance = AfxGetResourceHandle ();

	g_hMyFont = CreateFont(15,0,0,0,FW_BOLD,0,0,0,ANSI_CHARSET,0,0,0, DEFAULT_PITCH | FF_SWISS, _T(""));

	m_hPanel = m_ip->AddRollupPage(loc_hInstance, MAKEINTRESOURCE(IDD_HILLADJUST_PANEL),
		HillAdjustPanelProc, GetString(IDS_HILLADJUST_NAME),0);

	m_hQuickFile = EnableQuickFile(m_ip,m_hPanel);
}

////////////////////////////////////////////////////////////////////////////////
// Free the Plugins' Panel
void HillAdjustPanel::EndEditParams(Interface *ip, IUtil *iu)
{
	DeleteObject(g_hMyFont);

	DisableQuickFile(m_ip, m_hQuickFile);
	m_iu = NULL;
	m_ip = NULL;

	//Remove the Rollup Dialog
	ip->DeleteRollupPage(m_hPanel);
	m_hPanel = NULL;
}

////////////////////////////////////////////////////////////////////////////////
// Panel Initialization callback
void HillAdjustPanel::Init(HWND hWnd)
{
	g_bHold = 0;
	//Initialize the direction combo box
	for (int x=0;x<4;x++)
	{
		int index = SendDlgItemMessage(hWnd,IDC_COMBO_DIRECTION,CB_ADDSTRING,0,(LPARAM)g_szDir[x]);
		SendDlgItemMessage(hWnd,IDC_COMBO_DIRECTION,CB_SETITEMDATA,index,x);
	}
	m_angleEnum = -1;	
	LoadValues(hWnd);
}

////////////////////////////////////////////////////////////////////////////////
// Panel Destruction callback
void HillAdjustPanel::Destroy(HWND hWnd)
{
	SaveValues();
	ReleaseISpinner(m_angleSpinner);
	ReleaseISpinner(m_rootScalePosXControl);
	ReleaseISpinner(m_rootScalePosYControl);
	ReleaseISpinner(m_rootScalePosZControl);
	ReleaseISpinner(m_rootScaleRotXControl);
	ReleaseISpinner(m_rootScaleRotYControl);
	ReleaseISpinner(m_rootScaleRotZControl);

	ReleaseISpinner(m_rootMovePosXControl);
	ReleaseISpinner(m_rootMovePosYControl);
	ReleaseISpinner(m_rootMovePosZControl);
	ReleaseISpinner(m_rootMoveRotXControl);
	ReleaseISpinner(m_rootMoveRotYControl);
	ReleaseISpinner(m_rootMoveRotZControl);

	ReleaseISpinner(m_hipScaleControl);
	ReleaseISpinner(m_hipMoveControl);

	ReleaseISpinner(m_torsoScaleXControl);
	ReleaseISpinner(m_torsoScaleYControl);
	ReleaseISpinner(m_torsoScaleZControl);

	ReleaseISpinner(m_leftFootScaleCloseControl);
	ReleaseISpinner(m_rightFootScaleCloseControl);
}

////////////////////////////////////////////////////////////////////////////////
// Called when the Pick Button is pushed
void HillAdjustPanel::AdjustToHill()
{
	// need to check that the model has all of the necessary nodes
	char szCheckNames[] = "joint_VEL handle_lfoot site_lfoot handle_rfoot site_rfoot";
	char *str = strtok(szCheckNames," ");
	while (str)
	{
		if (NULL == m_ip->GetINodeByName(str))
		{
			CString s;
			s.Format("%s node required.  Hill Adjust tool cannot adjust loaded model.",str);
			MessageBox(NULL,s,"Hill Adjust",MB_OK |MB_ICONSTOP);
			return;
		}
		str = strtok(NULL," ");
	}
	

	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	HINSTANCE loc_hInstance = AfxGetResourceHandle ();

	// get the angle..

	m_angleSlope = m_angleSpinner->GetFVal() * Stuff::Radians_Per_Degree;

	m_rootPosScale.x = m_rootScalePosXControl->GetFVal() / 100.0f;
	m_rootPosScale.y = m_rootScalePosYControl->GetFVal() / 100.0f;
	m_rootPosScale.z = m_rootScalePosZControl->GetFVal() / 100.0f;
	m_rootRotScale.x = m_rootScaleRotXControl->GetFVal() / 100.0f;
	m_rootRotScale.y = m_rootScaleRotYControl->GetFVal() / 100.0f;
	m_rootRotScale.z = m_rootScaleRotZControl->GetFVal() / 100.0f;
	m_rootPosMove.x = m_rootMovePosXControl->GetFVal();
	m_rootPosMove.y = m_rootMovePosYControl->GetFVal();
	m_rootPosMove.z = m_rootMovePosZControl->GetFVal();
	
	m_rootRotMove.x = m_rootMoveRotXControl->GetFVal() * Stuff::Radians_Per_Degree;
	m_rootRotMove.y = m_rootMoveRotYControl->GetFVal() * Stuff::Radians_Per_Degree;
	m_rootRotMove.z = m_rootMoveRotZControl->GetFVal() * Stuff::Radians_Per_Degree;
	
	m_hipScale.x = m_hipScaleControl->GetFVal() / 100.0f;
	m_hipScale.y = NAN;
	m_hipScale.z = NAN;

	m_hipMove.x = m_hipMoveControl->GetFVal() * Stuff::Radians_Per_Degree;
	m_hipMove.y = NAN;
	m_hipMove.z = NAN;

	m_torsoScale.x = m_torsoScaleXControl->GetFVal() / 100.0f;
	m_torsoScale.y = m_torsoScaleYControl->GetFVal() / 100.0f;
	m_torsoScale.z = m_torsoScaleZControl->GetFVal() / 100.0f;

	m_leftFootPosScale.x = m_leftFootScaleCloseControl->GetFVal() / 100.0f;
	m_leftFootPosScale.y = NAN;
	m_leftFootPosScale.z = NAN;

	m_rightFootPosScale.x = m_rightFootScaleCloseControl->GetFVal() / 100.0f;
	m_rightFootPosScale.y = NAN;
	m_rightFootPosScale.z = NAN;

	// we have our angle and our up/down/left/right


	
	// we need to check the foot handles turn them into bezeir splines

//	INode *lfoot_node = FindNode(m_ip->GetRootNode(), "handle_lfoot");
//	Check_Pointer(lfoot_node);
//	ConvertTM(lfoot_node->GetTMController());


//	INode *rfoot_node = FindNode(m_ip->GetRootNode(), "handle_rfoot");
//	Check_Pointer(rfoot_node);
//	ConvertTM(rfoot_node->GetTMController());


	// lets rumble...

	switch (m_angleEnum)
	{
		case UpAngleType:
			AdjustGeneral();
			AdjustUpHill();
			break;
		case DownAngleType:
			AdjustGeneral();
			AdjustDownHill();
			break;
		case LeftAngleType:
			AdjustGeneral();
			AdjustLeftHill();
			break;
		case RightAngleType:
			AdjustGeneral();
			AdjustRightHill();
			break;
	}
	

}
//===========================================================================//

void HillAdjustPanel::ConvertTM(Control *c)
{
	Check_Pointer(c);


	Control *rotation_controler = c->GetRotationController();
	Check_Pointer(rotation_controler);

		Control *x_rot_controler = rotation_controler->GetXController();
		Check_Pointer(x_rot_controler);

		Convert(rotation_controler, x_rot_controler, 0);

		Control *y_rot_controler = rotation_controler->GetYController();
		Check_Pointer(y_rot_controler);

		Convert(rotation_controler, y_rot_controler, 1);

		Control *z_rot_controler = rotation_controler->GetZController();
		Check_Pointer(z_rot_controler);

		Convert(rotation_controler, z_rot_controler, 2);



	Control *position_controler = c->GetPositionController();
	Check_Pointer(position_controler);

		Control *x_controler = position_controler->GetXController();
		Check_Pointer(x_controler);

		Convert(position_controler, x_controler, 0);

		Control *y_controler = position_controler->GetYController();
		Check_Pointer(y_controler);

		Convert(position_controler, y_controler, 1);

		Control *z_controler = position_controler->GetZController();
		Check_Pointer(z_controler);

		Convert(position_controler, z_controler, 2);

}

//===========================================================================//

void HillAdjustPanel::Convert(Control *parent_c, Control *c, int location)
{

	Check_Pointer(c);

	
	if(c->ClassID().PartA() == HYBRIDINTERP_FLOAT_CLASS_ID)
	{
		return;
	}


	theHold.Begin();
	// replace controler pointer with new controller

	// if the type is known but the sub type isn't 
	// then convert that controller.
	
	// Example is RotationXYZ with a sub controler of SineWave or Noise

	Control *new_controler = NULL;

	
	new_controler = (Control *)m_ip->CreateInstance(
		CTRL_FLOAT_CLASS_ID,
		Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID, 0));
	
		
	SuspendAnimate();
	AnimateOn();

	{
		
		Interval iv;
		int ticks_per_frame = GetTicksPerFrame();
		int num_of_frames = 1;

		TimeValue start = m_ip->GetAnimRange().Start();
		TimeValue end = m_ip->GetAnimRange().End();
		int delta = GetTicksPerFrame();

		for (int time_of_key=start; time_of_key<=end; time_of_key+=delta)
		{
			float value;
			c->GetValue(time_of_key,&value,FOREVER,CTRL_ABSOLUTE);
			new_controler->SetValue(time_of_key,&value,TRUE,CTRL_ABSOLUTE);
		}
	}

	ResumeAnimate();
	theHold.Accept(0);

	new_controler->SetORT(ORT_BEFORE, ORT_LOOP);
	new_controler->SetORT(ORT_AFTER, ORT_LOOP);

	parent_c->AssignController(new_controler, location);
	return;


}
//===========================================================================//

void HillAdjustPanel::SampleController(Control *parent_c, Control *c, int location)
{

	Check_Pointer(c);


	theHold.Begin();
	// replace controler pointer with new controller

	// if the type is known but the sub type isn't 
	// then convert that controller.
	
	// Example is RotationXYZ with a sub controler of SineWave or Noise

	Control *new_controler = NULL;

	
	new_controler = (Control *)m_ip->CreateInstance(
		CTRL_FLOAT_CLASS_ID,
		Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID, 0));
	
		
	SuspendAnimate();
	AnimateOn();

	{
		
		Interval iv;
		int ticks_per_frame = GetTicksPerFrame();
		int num_of_frames = 1;

		TimeValue start = m_ip->GetAnimRange().Start();
		TimeValue end = m_ip->GetAnimRange().End();
		int delta = GetTicksPerFrame();

		for (int time_of_key=start; time_of_key<=end; time_of_key+=delta)
		{
			float value;
			c->GetValue(time_of_key,&value,FOREVER,CTRL_ABSOLUTE);
			new_controler->SetValue(time_of_key,&value,TRUE,CTRL_ABSOLUTE);
		}
	}

	ResumeAnimate();
	theHold.Accept(0);

	new_controler->SetORT(ORT_BEFORE, ORT_LOOP);
	new_controler->SetORT(ORT_AFTER, ORT_LOOP);

	parent_c->AssignController(new_controler, location);
	return;


}

//===========================================================================//

void HillAdjustPanel::AdjustGeneral(void)
{


	INode *root_node = FindNode(m_ip->GetRootNode(), "joint_root");
	Check_Pointer(root_node);

	INode *torso_node = FindNode(m_ip->GetRootNode(), "joint_torso");
	Check_Pointer(torso_node);

	INode *hip_node = FindNode(m_ip->GetRootNode(), "joint_hip");
	Check_Pointer(hip_node);

	INode *lfoot_node = FindNode(m_ip->GetRootNode(), "handle_lfoot");
	Check_Pointer(lfoot_node);

	INode *rfoot_node = FindNode(m_ip->GetRootNode(), "handle_rfoot");
	Check_Pointer(rfoot_node);


	ScaleNodePosition(root_node, m_rootPosScale);
	ScaleNodeRotation(root_node, m_rootRotScale);
	MoveNodePosition(root_node, m_rootPosMove);
	MoveNodeRotation(root_node, m_rootRotMove);

	ScaleNodeRotation(hip_node, m_hipScale);
	MoveNodeRotation(hip_node, m_hipMove);

	ScaleNodeRotation(torso_node, m_torsoScale);

	ScaleNodePosition(lfoot_node, m_leftFootPosScale);
	ScaleNodePosition(rfoot_node, m_rightFootPosScale);

}


//===========================================================================//

void HillAdjustPanel::ScaleNodeAll(Control *c, float scale)
{
	if (_isnan(scale))
		return;

	IKeyControl *keys = GetKeyControlInterface(c);

	if (keys == NULL)
	{
		//SPEW(("jerryeds", "FUCKED UP"));
		ScaleKey(c, keys, scale,0.0, -1);
		return;
	}

	float min = 0.0,max = 0.0;

	for (int i = 0; i < keys->GetNumKeys(); ++i)
	{
		int time = GetKeyTime(c, keys, i);
		float value;
		c->GetValue(time,&value,FOREVER,CTRL_ABSOLUTE);
		if (value < min)
			min = value;
		if (value > max)
			max = value;
	}

	if (keys->GetNumKeys() > 0)
	{
		for (i = 0; i < keys->GetNumKeys(); ++i)
		{
			ScaleKey(c, keys, scale, min+(max-min)/2,i);
		}
	}
	else
	{
		ScaleKey(c, keys, scale, min+(max-min)/2,-1);
	}

}

//===========================================================================//

void HillAdjustPanel::MoveNodeAll(Control *c, float scale)
{
	if (_isnan(scale))
		return;

	IKeyControl *keys = GetKeyControlInterface(c);

	if (keys == NULL)
	{
		//SPEW(("jerryeds", "FUCKED UP"));
		MoveKey(c, keys, scale, -1);
		return;
	}
	
	if (keys->GetNumKeys() > 0)
	{
		for (int i = 0; i < keys->GetNumKeys(); ++i)
		{
			MoveKey(c, keys, scale, i);
		}
	}
	else
	{
		MoveKey(c, keys, scale, -1);
	}
}


//===========================================================================//

void HillAdjustPanel::ScaleNodePosition(INode *node, Stuff::Point3D scale)
{
		
	Control *tm_control = node->GetTMController();
	Check_Pointer(tm_control);

	Control *position_controler = tm_control->GetPositionController();
	Check_Pointer(position_controler);

	
	Control *x_controler = position_controler->GetXController();
	Check_Pointer(x_controler);

	Control *y_controler = position_controler->GetYController();
	Check_Pointer(y_controler);

	Control *z_controler = position_controler->GetZController();
	Check_Pointer(z_controler);

	ScaleNodeAll(x_controler, scale.x);
	ScaleNodeAll(y_controler, scale.y);
	ScaleNodeAll(z_controler, scale.z);
}

//===========================================================================//

void HillAdjustPanel::ScaleNodeRotation(INode *node, Stuff::Point3D scale)
{

	Control *tm_control = node->GetTMController();
	Check_Pointer(tm_control);

	Control *rotation_controler = tm_control->GetRotationController();
	Check_Pointer(rotation_controler);

	Control *x_rot_controler = rotation_controler->GetXController();
	Check_Pointer(x_rot_controler);

	Control *y_rot_controler = rotation_controler->GetYController();
	Check_Pointer(y_rot_controler);

	Control *z_rot_controler = rotation_controler->GetZController();
	Check_Pointer(z_rot_controler);

	ScaleNodeAll(x_rot_controler, scale.x);
	ScaleNodeAll(y_rot_controler, scale.y);
	ScaleNodeAll(z_rot_controler, scale.z);
}

//===========================================================================//

void HillAdjustPanel::MoveNodePosition(INode *node, Stuff::Point3D scale)
{
		
	Control *tm_control = node->GetTMController();
	Check_Pointer(tm_control);

	Control *position_controler = tm_control->GetPositionController();
	Check_Pointer(position_controler);

	
	Control *x_controler = position_controler->GetXController();
	Check_Pointer(x_controler);

	Control *y_controler = position_controler->GetYController();
	Check_Pointer(y_controler);

	Control *z_controler = position_controler->GetZController();
	Check_Pointer(z_controler);

	MoveNodeAll(x_controler, scale.x);
	MoveNodeAll(y_controler, scale.y);
	MoveNodeAll(z_controler, scale.z);
}

//===========================================================================//

void HillAdjustPanel::MoveNodeRotation(INode *node, Stuff::Point3D scale)
{

	Control *tm_control = node->GetTMController();
	Check_Pointer(tm_control);

	Control *rotation_controler = tm_control->GetRotationController();
	Check_Pointer(rotation_controler);

	Control *x_rot_controler = rotation_controler->GetXController();
	Check_Pointer(x_rot_controler);

	Control *y_rot_controler = rotation_controler->GetYController();
	Check_Pointer(y_rot_controler);

	Control *z_rot_controler = rotation_controler->GetZController();
	Check_Pointer(z_rot_controler);

	MoveNodeAll(x_rot_controler, scale.x);
	MoveNodeAll(y_rot_controler, scale.y);
	MoveNodeAll(z_rot_controler, scale.z);
}

//===========================================================================//

void HillAdjustPanel::AdjustUpHill(void)
{


	//SPEW(("jerryeds", "%f %f", m_angleSlope, 45.0f*Stuff::Radians_Per_Degree));


	INode *root_node = FindNode(m_ip->GetRootNode(), "joint_VEL");
	Check_Pointer(root_node);

	INode *left_foot_handle = FindNode(m_ip->GetRootNode(), "handle_lfoot");
	Check_Pointer(left_foot_handle);

	{
		Control *tm_control = left_foot_handle->GetTMController();
		Check_Pointer(tm_control);

		Control *position_controler = tm_control->GetPositionController();
		Check_Pointer(position_controler);

		Control *rotation_controler = tm_control->GetRotationController();
		Check_Pointer(position_controler);

		Control *x_controler = position_controler->GetXController();
		Check_Pointer(x_controler);

		Control *y_controler = position_controler->GetYController();
		Check_Pointer(y_controler);

		Control *z_controler = position_controler->GetZController();
		Check_Pointer(z_controler);


		Control *x_rot_controler = rotation_controler->GetXController();
		Check_Pointer(x_controler);

		Control *y_rot_controler = rotation_controler->GetYController();
		Check_Pointer(y_controler);

		Control *z_rot_controler = rotation_controler->GetZController();
		Check_Pointer(z_controler);

	
		
		// adjust keyframe to go up in z the correct amount of degrees...
		IKeyControl *z_keys = GetKeyControlInterface(z_controler);
		
		if (z_keys != NULL)
		{

			Stuff::Scalar *y_position_table = new Stuff::Scalar[z_keys->GetNumKeys()];
			Register_Pointer(y_position_table);

			for (int i = 0; i < z_keys->GetNumKeys(); ++i)
			{

		
				// Get the pos and rot from the frame.
				int time_of_key = GetKeyTime(z_controler, z_keys, i);

				AffineParts vel_world;
				decomp_affine(root_node->GetNodeTM(time_of_key), &vel_world);

				AffineParts foot_world;
				decomp_affine(left_foot_handle->GetNodeTM(time_of_key), &foot_world);


				y_position_table[i] = vel_world.t.y - foot_world.t.y;


			}

			Stuff::Scalar *height_table;
			height_table = new Stuff::Scalar[z_keys->GetNumKeys()];
			Register_Pointer(height_table);

			for (i = 0; i < z_keys->GetNumKeys(); ++i)
			{
				
				Stuff::Scalar height = (Stuff::Scalar)tan(m_angleSlope) * y_position_table[i];

				
				if (i > 0)
				{
					height_table[i] = height - height_table[i-1];
				}
				else
				{
					height_table[0] = height;
				}

				//SPEW(("jerryeds", "height : %f", height_table[i]));

				MoveKey(z_controler, z_keys, height, i);

			}


			Unregister_Pointer(y_position_table);
			delete y_position_table;


			// push out the handle just a little more to match the ground...
			INode *foot_site = FindNode(m_ip->GetRootNode(), "site_lfoot");
			Check_Pointer(foot_site);

			// calculate the length of the foot..
			Matrix3 parentTM, nodeTM, localTM;
			nodeTM = foot_site->GetNodeTM(m_ip->GetAnimRange().Start());
			parentTM = foot_site->GetParentTM(m_ip->GetAnimRange().Start());
			//parentTM = left_foot_handle->GetNodeTM(m_ip->GetAnimRange().Start());
			localTM = nodeTM*Inverse(parentTM);

			AffineParts ap;
			decomp_affine(localTM, &ap);

			float foot_length = -ap.t.z;
			
			//SPEW(("jerryeds", "foot_length %f", foot_length));
			
			float ground_adjustment;
		
			{
				//
				//  A
				//   |\
				//   | \ 
				//	b|  \c
				//   |   \
				//  C|____\B
				//      a
				//

				// calculate the foot penetration
				float b,c,A,B;
				c = foot_length;
				B = m_angleSlope;
				A = (90.0f * Stuff::Radians_Per_Degree ) - B;
				b = Cos(A) * c;

				ground_adjustment = foot_length - b;
			}


			{
				float a,c,B;
				a = ground_adjustment;
				B = m_angleSlope;
				c = a / Cos(B);

				ground_adjustment = c;
			}


			// solve the second triangle...


			//SPEW(("jerryeds", "new_length %f", b));
			SPEW(("jerryeds", "ground_adjustment %f", ground_adjustment));

			// push the handle out from the normal of the ground...
			
			Matrix3 axis(MAT_IDENT);

			
			Point3 translate(0.0f, 0.0f, ground_adjustment);

	

			left_foot_handle->Move(0, axis, translate, FALSE, TRUE, PIV_NONE);



			if (!m_leaveOriginalTangents)
			{
				for (int i = 1; i < z_keys->GetNumKeys()-1; ++i)
				{
					RotateTangents(z_controler, z_keys, height_table[i], i);
				}
			}


			Unregister_Pointer(height_table);
			delete height_table;
		}

		// turn the feet to match the ground
		IKeyControl *x_rot_keys = GetKeyControlInterface(x_rot_controler);
		
		if (x_rot_keys != NULL)
		{
			if (x_rot_keys->GetNumKeys() > 0)
			{
				for (int i = 0; i < x_rot_keys->GetNumKeys(); ++i)
				{
					MoveKey(x_rot_controler, x_rot_keys, -45.0f*Stuff::Radians_Per_Degree, i);
				}
			}
			else
			{
				MoveKey(x_rot_controler, x_rot_keys, -45.0f*Stuff::Radians_Per_Degree, -1);
			}

		}


	}	


	INode *right_foot_handle = FindNode(m_ip->GetRootNode(), "handle_rfoot");
	Check_Pointer(right_foot_handle);

	{
		Control *tm_control = right_foot_handle->GetTMController();
		Check_Pointer(tm_control);

		Control *position_controler = tm_control->GetPositionController();
		Check_Pointer(position_controler);

		Control *rotation_controler = tm_control->GetRotationController();
		Check_Pointer(position_controler);

		Control *x_controler = position_controler->GetXController();
		Check_Pointer(x_controler);

		Control *y_controler = position_controler->GetYController();
		Check_Pointer(y_controler);

		Control *z_controler = position_controler->GetZController();
		Check_Pointer(z_controler);


		Control *x_rot_controler = rotation_controler->GetXController();
		Check_Pointer(x_controler);

		Control *y_rot_controler = rotation_controler->GetYController();
		Check_Pointer(y_controler);

		Control *z_rot_controler = rotation_controler->GetZController();
		Check_Pointer(z_controler);

		

		if (!m_leaveOriginalCurves)
		{
			//sample the z_controller
			SampleController(position_controler, z_controler, 2);
			z_controler = position_controler->GetZController();
		}


		
		// adjust keyframe to go up in z the correct amount of degrees...
		IKeyControl *z_keys = GetKeyControlInterface(z_controler);
		
		Stuff::Scalar *y_position_table = new Stuff::Scalar[z_keys->GetNumKeys()];
		Register_Pointer(y_position_table);

		for (int i = 0; i < z_keys->GetNumKeys(); ++i)
		{
			

			int time_of_key = GetKeyTime(z_controler, z_keys, i);
		
			AffineParts vel_world;
			decomp_affine(root_node->GetNodeTM(time_of_key), &vel_world);

			AffineParts foot_world;
			decomp_affine(right_foot_handle->GetNodeTM(time_of_key), &foot_world);


			y_position_table[i] = vel_world.t.y - foot_world.t.y;

			
		}



		Stuff::Scalar *height_table;
		height_table = new Stuff::Scalar[z_keys->GetNumKeys()];
		Register_Pointer(height_table);

		for (i = 0; i < z_keys->GetNumKeys(); ++i)
		{
			
			Stuff::Scalar height = (Stuff::Scalar)tan(m_angleSlope) * y_position_table[i];

			
			if (i > 0)
			{
				height_table[i] = height - height_table[i-1];
			}
			else
			{
				height_table[0] = height;
			}

			//SPEW(("jerryeds", "height : %f", height_table[i]));

			MoveKey(z_controler, z_keys, height, i);

		}





		Unregister_Pointer(y_position_table);
		delete y_position_table;


		IKeyControl *x_rot_keys = GetKeyControlInterface(x_rot_controler);
		
		if (x_rot_keys->GetNumKeys() > 0)
		{
			for (i = 0; i < x_rot_keys->GetNumKeys(); ++i)
			{
				MoveKey(x_rot_controler, x_rot_keys, -45.0f*Stuff::Radians_Per_Degree, i);
			}
		}
		else
		{
			MoveKey(x_rot_controler, x_rot_keys, -45.0f*Stuff::Radians_Per_Degree, -1);
		}


				// push out the handle just a little more to match the ground...
		INode *foot_site = FindNode(m_ip->GetRootNode(), "site_rfoot");
		Check_Pointer(foot_site);

		// calculate the length of the foot..
		Matrix3 parentTM, nodeTM, localTM;
		nodeTM = foot_site->GetNodeTM(m_ip->GetAnimRange().Start());
		parentTM = foot_site->GetParentTM(m_ip->GetAnimRange().Start());
		localTM = nodeTM*Inverse(parentTM);

		AffineParts ap;
		decomp_affine(localTM, &ap);

		float foot_length = -ap.t.z;
		
		float ground_adjustment;
		
		{
			//
			//  A
			//   |\
			//   | \ 
			//	b|  \c
			//   |   \
			//  C|____\B
			//      a
			//

			// calculate the foot penetration
			float b,c,A,B;
			c = foot_length;
			B = m_angleSlope;
			A = (90.0f * Stuff::Radians_Per_Degree ) - B;
			b = Cos(A) * c;

			ground_adjustment = foot_length - b;
		}


		{
			float a,c,B;
			a = ground_adjustment;
			B = m_angleSlope;
			c = a / Cos(B);

			ground_adjustment = c;
		}


		// solve the second triangle...


		//SPEW(("jerryeds", "new_length %f", b));
		SPEW(("jerryeds", "ground_adjustment %f", ground_adjustment));

		// push the handle out from the normal of the ground...
		
		Matrix3 axis(MAT_IDENT);

		
		Point3 translate(0.0f, 0.0f, ground_adjustment);

	
		right_foot_handle->Move(0, axis, translate, FALSE, TRUE, PIV_NONE);


		if (!m_leaveOriginalTangents)
		{
			for (i = 1; i < z_keys->GetNumKeys()-1; ++i)
			{
				RotateTangents(z_controler, z_keys, height_table[i], i);
			}
		}

		Unregister_Pointer(height_table);
		delete height_table;

	}
}

//===========================================================================//

void HillAdjustPanel::AdjustDownHill(void)
{

	INode *root_node = FindNode(m_ip->GetRootNode(), "joint_VEL");
	Check_Pointer(root_node);

	INode *left_foot_handle = FindNode(m_ip->GetRootNode(), "handle_lfoot");
	Check_Pointer(left_foot_handle);

	{
		Control *tm_control = left_foot_handle->GetTMController();
		Check_Pointer(tm_control);

		Control *position_controler = tm_control->GetPositionController();
		Check_Pointer(position_controler);

		Control *rotation_controler = tm_control->GetRotationController();
		Check_Pointer(position_controler);

		Control *x_controler = position_controler->GetXController();
		Check_Pointer(x_controler);

		Control *y_controler = position_controler->GetYController();
		Check_Pointer(y_controler);

		Control *z_controler = position_controler->GetZController();
		Check_Pointer(z_controler);


		Control *x_rot_controler = rotation_controler->GetXController();
		Check_Pointer(x_controler);

		Control *y_rot_controler = rotation_controler->GetYController();
		Check_Pointer(y_controler);

		Control *z_rot_controler = rotation_controler->GetZController();
		Check_Pointer(z_controler);

		
		
		// adjust keyframe to go up in z the correct amount of degrees...
		IKeyControl *z_keys = GetKeyControlInterface(z_controler);
		

		if (z_keys != NULL)
		{

			Stuff::Scalar *y_position_table = new Stuff::Scalar[z_keys->GetNumKeys()];
			Register_Pointer(y_position_table);

			for (int i = 0; i < z_keys->GetNumKeys(); ++i)
			{
				// Get the pos and rot from the frame.
				int time_of_key = GetKeyTime(z_controler, z_keys, i);

				AffineParts vel_world;
				decomp_affine(root_node->GetNodeTM(time_of_key), &vel_world);

				AffineParts foot_world;
				decomp_affine(left_foot_handle->GetNodeTM(time_of_key), &foot_world);


				y_position_table[i] = vel_world.t.y - foot_world.t.y;

			}


		

			Stuff::Scalar *height_table;
			height_table = new Stuff::Scalar[z_keys->GetNumKeys()];
			Register_Pointer(height_table);

			for (i = 0; i < z_keys->GetNumKeys(); ++i)
			{
				
				Stuff::Scalar height = -(Stuff::Scalar)tan(m_angleSlope) * y_position_table[i];

				
				if (i > 0)
				{
					height_table[i] = height - height_table[i-1];
				}
				else
				{
					height_table[0] = height;
				}

				//SPEW(("jerryeds", "height : %f", height_table[i]));

				MoveKey(z_controler, z_keys, height, i);

			}


			// push out the handle just a little more to match the ground...
			INode *foot_site = FindNode(m_ip->GetRootNode(), "site_lfoot");
			Check_Pointer(foot_site);

			// calculate the length of the foot..
			Matrix3 parentTM, nodeTM, localTM;
			nodeTM = foot_site->GetNodeTM(m_ip->GetAnimRange().Start());
			parentTM = foot_site->GetParentTM(m_ip->GetAnimRange().Start());
			//parentTM = left_foot_handle->GetNodeTM(m_ip->GetAnimRange().Start());
			localTM = nodeTM*Inverse(parentTM);

			AffineParts ap;
			decomp_affine(localTM, &ap);

			float foot_length = -ap.t.z;
			
			float ground_adjustment;
		
			{
				//
				//  A
				//   |\
				//   | \ 
				//	b|  \c
				//   |   \
				//  C|____\B
				//      a
				//

				// calculate the foot penetration
				float b,c,A,B;
				c = foot_length;
				B = m_angleSlope;
				A = (90.0f * Stuff::Radians_Per_Degree ) - B;
				b = Cos(A) * c;

				ground_adjustment = foot_length - b;
			}


			{
				float a,c,B;
				a = ground_adjustment;
				B = m_angleSlope;
				c = a / Cos(B);

				ground_adjustment = c;
			}


			// solve the second triangle...


			//SPEW(("jerryeds", "new_length %f", b));
			SPEW(("jerryeds", "ground_adjustment %f", ground_adjustment));

			// push the handle out from the normal of the ground...
			
			Matrix3 axis(MAT_IDENT);

			
			Point3 translate(0.0f, 0.0f, ground_adjustment);

	

			left_foot_handle->Move(0, axis, translate, FALSE, TRUE, PIV_NONE);


			if (!m_leaveOriginalTangents)
			{

				for (i = 1; i < z_keys->GetNumKeys()-1; ++i)
				{
					RotateTangents(z_controler, z_keys, height_table[i], i);
				}
			
			}

			Unregister_Pointer(height_table);
			delete height_table;

			Unregister_Pointer(y_position_table);
			delete y_position_table;


		}

		


		IKeyControl *x_rot_keys = GetKeyControlInterface(x_rot_controler);
		if (x_rot_keys != NULL)
		{
			if (x_rot_keys->GetNumKeys() > 0)
			{
				for (int i = 0; i < x_rot_keys->GetNumKeys(); ++i)
				{
					MoveKey(x_rot_controler, x_rot_keys, 45.0f*Stuff::Radians_Per_Degree, i);
				}
			}
			else
			{
				MoveKey(x_rot_controler, x_rot_keys, 45.0f*Stuff::Radians_Per_Degree, -1);
			}
		}
	}	


	INode *right_foot_handle = FindNode(m_ip->GetRootNode(), "handle_rfoot");
	Check_Pointer(right_foot_handle);

	{
		Control *tm_control = right_foot_handle->GetTMController();
		Check_Pointer(tm_control);

		Control *position_controler = tm_control->GetPositionController();
		Check_Pointer(position_controler);

		Control *rotation_controler = tm_control->GetRotationController();
		Check_Pointer(position_controler);

		Control *x_controler = position_controler->GetXController();
		Check_Pointer(x_controler);

		Control *y_controler = position_controler->GetYController();
		Check_Pointer(y_controler);

		Control *z_controler = position_controler->GetZController();
		Check_Pointer(z_controler);


		Control *x_rot_controler = rotation_controler->GetXController();
		Check_Pointer(x_controler);

		Control *y_rot_controler = rotation_controler->GetYController();
		Check_Pointer(y_controler);

		Control *z_rot_controler = rotation_controler->GetZController();
		Check_Pointer(z_controler);

		
		if (!m_leaveOriginalCurves)
		{
			//sample the z_controller
			SampleController(position_controler, z_controler, 2);
			z_controler = position_controler->GetZController();
		}

		// adjust keyframe to go up in z the correct amount of degrees...
		IKeyControl *z_keys = GetKeyControlInterface(z_controler);
		
		Stuff::Scalar *y_position_table = new Stuff::Scalar[z_keys->GetNumKeys()];
		Register_Pointer(y_position_table);

		for (int i = 0; i < z_keys->GetNumKeys(); ++i)
		{
			// Get the pos and rot from the frame.
			int time_of_key = GetKeyTime(z_controler, z_keys, i);

			AffineParts vel_world;
			decomp_affine(root_node->GetNodeTM(time_of_key), &vel_world);

			AffineParts foot_world;
			decomp_affine(right_foot_handle->GetNodeTM(time_of_key), &foot_world);


			y_position_table[i] = vel_world.t.y - foot_world.t.y;



		}



		Stuff::Scalar *height_table;
		height_table = new Stuff::Scalar[z_keys->GetNumKeys()];
		Register_Pointer(height_table);

		for (i = 0; i < z_keys->GetNumKeys(); ++i)
		{
			
			Stuff::Scalar height = -(Stuff::Scalar)tan(m_angleSlope) * y_position_table[i];

			
			if (i > 0)
			{
				height_table[i] = height - height_table[i-1];
			}
			else
			{
				height_table[0] = height;
			}

			//SPEW(("jerryeds", "height : %f", height_table[i]));

			MoveKey(z_controler, z_keys, height, i);

		}



		Unregister_Pointer(y_position_table);
		delete y_position_table;


		IKeyControl *x_rot_keys = GetKeyControlInterface(x_rot_controler);
		
		if (x_rot_keys->GetNumKeys() > 0)
		{
			for (i = 0; i < x_rot_keys->GetNumKeys(); ++i)
			{
				MoveKey(x_rot_controler, x_rot_keys, 45.0f*Stuff::Radians_Per_Degree, i);
			}
		}
		else
		{
			MoveKey(x_rot_controler, x_rot_keys, 45.0f*Stuff::Radians_Per_Degree, -1);
		}

				// push out the handle just a little more to match the ground...
		INode *foot_site = FindNode(m_ip->GetRootNode(), "site_rfoot");
		Check_Pointer(foot_site);

		// calculate the length of the foot..
		Matrix3 parentTM, nodeTM, localTM;
		nodeTM = foot_site->GetNodeTM(m_ip->GetAnimRange().Start());
		parentTM = foot_site->GetParentTM(m_ip->GetAnimRange().Start());
		//parentTM = left_foot_handle->GetNodeTM(m_ip->GetAnimRange().Start());
		localTM = nodeTM*Inverse(parentTM);

		AffineParts ap;
		decomp_affine(localTM, &ap);

		float foot_length = -ap.t.z;
		
		float ground_adjustment;
		
		{
			//
			//  A
			//   |\
			//   | \ 
			//	b|  \c
			//   |   \
			//  C|____\B
			//      a
			//

			// calculate the foot penetration
			float b,c,A,B;
			c = foot_length;
			B = m_angleSlope;
			A = (90.0f * Stuff::Radians_Per_Degree ) - B;
			b = Cos(A) * c;

			ground_adjustment = foot_length - b;
		}


		{
			float a,c,B;
			a = ground_adjustment;
			B = m_angleSlope;
			c = a / Cos(B);

			ground_adjustment = c;
		}


		// solve the second triangle...


		//SPEW(("jerryeds", "new_length %f", b));
		SPEW(("jerryeds", "ground_adjustment %f", ground_adjustment));

		// push the handle out from the normal of the ground...
		
		Matrix3 axis(MAT_IDENT);

		
		Point3 translate(0.0f, 0.0f, ground_adjustment);

	

		right_foot_handle->Move(0, axis, translate, FALSE, TRUE, PIV_NONE);



		if (!m_leaveOriginalTangents)
		{
			for (i = 1; i < z_keys->GetNumKeys()-1; ++i)
			{
				RotateTangents(z_controler, z_keys, height_table[i], i);
			}
		}

		Unregister_Pointer(height_table);
		delete height_table;

	}	

}

//===========================================================================//

void HillAdjustPanel::AdjustLeftHill(void)
{
	
	INode *left_foot_handle = FindNode(m_ip->GetRootNode(), "handle_lfoot");
	Check_Pointer(left_foot_handle);

	{
		//SPEW(("jerryeds", "LEFT"));

		Control *tm_control = left_foot_handle->GetTMController();
		Check_Pointer(tm_control);

		Control *position_controler = tm_control->GetPositionController();
		Check_Pointer(position_controler);

		Control *rotation_controler = tm_control->GetRotationController();
		Check_Pointer(position_controler);

		Control *x_controler = position_controler->GetXController();
		Check_Pointer(x_controler);

		Control *y_controler = position_controler->GetYController();
		Check_Pointer(y_controler);

		Control *z_controler = position_controler->GetZController();
		Check_Pointer(z_controler);


		Control *x_rot_controler = rotation_controler->GetXController();
		Check_Pointer(x_controler);

		Control *y_rot_controler = rotation_controler->GetYController();
		Check_Pointer(y_controler);

		Control *z_rot_controler = rotation_controler->GetZController();
		Check_Pointer(z_controler);

		
		Convert(position_controler, z_controler, 2);
		z_controler = position_controler->GetZController();

		Convert(rotation_controler, y_rot_controler, 1);
		y_rot_controler = rotation_controler->GetYController();

		// adjust keyframe to go up in z the correct amount of degrees...
		IKeyControl *z_keys = GetKeyControlInterface(z_controler);
		
		Stuff::Scalar *x_position_table = new Stuff::Scalar[z_keys->GetNumKeys()];
		Register_Pointer(x_position_table);

		for (int i = 0; i < z_keys->GetNumKeys(); ++i)
		{
			Quat rot;
			Point3 pos;
			
			// Get the pos and rot from the frame.

			int time_of_key = GetKeyTime(z_controler, z_keys, i);

			// Compute the relative TM
			Matrix3 parentTM, nodeTM, localTM;
			nodeTM = left_foot_handle->GetNodeTM(time_of_key);
			parentTM = left_foot_handle->GetParentTM(time_of_key);
			localTM = nodeTM*Inverse(parentTM);

			AffineParts ap;
			decomp_affine(localTM, &ap);
			
			x_position_table[i] = ap.t.x;

		}


		for (i = 0; i < z_keys->GetNumKeys(); ++i)
		{
			
			Stuff::Scalar height = (Stuff::Scalar)tan(m_angleSlope) * x_position_table[i];

			//SPEW(("jerryeds", "l:%f", height));

			MoveKey(z_controler, z_keys, height, i);


		}


		Unregister_Pointer(x_position_table);
		delete x_position_table;


		

		IKeyControl *y_rot_keys = GetKeyControlInterface(y_rot_controler);
		
		if (y_rot_keys->GetNumKeys() > 0)
		{
			for (i = 0; i < y_rot_keys->GetNumKeys(); ++i)
			{
				MoveKey(y_rot_controler, y_rot_keys, -45.0f*Stuff::Radians_Per_Degree, i);
			}
		}
		else
		{
			MoveKey(y_rot_controler, y_rot_keys, -45.0f*Stuff::Radians_Per_Degree, -1);
		}


		// push out the handle just a little more to match the ground...
		INode *foot_site = FindNode(m_ip->GetRootNode(), "site_lfoot");
		Check_Pointer(foot_site);

		// calculate the length of the foot..
		Matrix3 parentTM, nodeTM, localTM;
		nodeTM = foot_site->GetNodeTM(m_ip->GetAnimRange().Start());
		parentTM = foot_site->GetParentTM(m_ip->GetAnimRange().Start());
		//parentTM = left_foot_handle->GetNodeTM(m_ip->GetAnimRange().Start());
		localTM = nodeTM*Inverse(parentTM);

		AffineParts ap;
		decomp_affine(localTM, &ap);

		float foot_length = -ap.t.z;
		
		//SPEW(("jerryeds", "foot_length %f", foot_length));
		

		float ground_adjustment;
		
		{
			//
			//  A
			//   |\
			//   | \ 
			//	b|  \c
			//   |   \
			//  C|____\B
			//      a
			//

			// calculate the foot penetration
			float b,c,A,B;
			c = foot_length;
			B = m_angleSlope;
			A = (90.0f * Stuff::Radians_Per_Degree ) - B;
			b = Cos(A) * c;

			ground_adjustment = foot_length - b;
		}


		{
			float a,c,B;
			a = ground_adjustment;
			B = m_angleSlope;
			c = a / Cos(B);

			ground_adjustment = c;
		}


		// solve the second triangle...


		//SPEW(("jerryeds", "new_length %f", b));
		SPEW(("jerryeds", "ground_adjustment %f", ground_adjustment));

		// push the handle out from the normal of the ground...
		
		Matrix3 axis(MAT_IDENT);

		
		Point3 translate(0.0f, 0.0f, ground_adjustment);

	

		left_foot_handle->Move(0, axis, translate, FALSE, TRUE, PIV_NONE, TRUE);
	}	



	INode *right_foot_handle = FindNode(m_ip->GetRootNode(), "handle_rfoot");
	Check_Pointer(right_foot_handle);

	{
		//SPEW(("jerryeds", "RIGHT"));


		Control *tm_control = right_foot_handle->GetTMController();
		Check_Pointer(tm_control);

		Control *position_controler = tm_control->GetPositionController();
		Check_Pointer(position_controler);

		Control *rotation_controler = tm_control->GetRotationController();
		Check_Pointer(position_controler);

		Control *x_controler = position_controler->GetXController();
		Check_Pointer(x_controler);

		Control *y_controler = position_controler->GetYController();
		Check_Pointer(y_controler);

		Control *z_controler = position_controler->GetZController();
		Check_Pointer(z_controler);


		Control *x_rot_controler = rotation_controler->GetXController();
		Check_Pointer(x_controler);

		Control *y_rot_controler = rotation_controler->GetYController();
		Check_Pointer(y_controler);

		Control *z_rot_controler = rotation_controler->GetZController();
		Check_Pointer(z_controler);

		Convert(position_controler, z_controler, 2);
		z_controler = position_controler->GetZController();

		Convert(rotation_controler, y_rot_controler, 1);
		y_rot_controler = rotation_controler->GetYController();

		// adjust keyframe to go up in z the correct amount of degrees...
		IKeyControl *z_keys = GetKeyControlInterface(z_controler);
		
		Stuff::Scalar *x_position_table = new Stuff::Scalar[z_keys->GetNumKeys()];
		Register_Pointer(x_position_table);

		for (int i = 0; i < z_keys->GetNumKeys(); ++i)
		{
			Quat rot;
			Point3 pos;
			
			// Get the pos and rot from the frame.

			int time_of_key = GetKeyTime(z_controler, z_keys, i);

			// Compute the relative TM
			Matrix3 parentTM, nodeTM, localTM;
			nodeTM = right_foot_handle->GetNodeTM(time_of_key);
			parentTM = right_foot_handle->GetParentTM(time_of_key);
			localTM = nodeTM*Inverse(parentTM);

			AffineParts ap;
			decomp_affine(localTM, &ap);
			
			x_position_table[i] = ap.t.x;

		}


		for (i = 0; i < z_keys->GetNumKeys(); ++i)
		{
			Stuff::Scalar height = (Stuff::Scalar)tan(m_angleSlope) * x_position_table[i];

			//SPEW(("jerryeds", "r:%f", height));

			MoveKey(z_controler, z_keys, height, i);


		}

		Unregister_Pointer(x_position_table);
		delete x_position_table;

		IKeyControl *y_rot_keys = GetKeyControlInterface(y_rot_controler);
		
		if (y_rot_keys->GetNumKeys() > 0)
		{
			for (i = 0; i < y_rot_keys->GetNumKeys(); ++i)
			{
				MoveKey(y_rot_controler, y_rot_keys, -45.0f*Stuff::Radians_Per_Degree, i);
			}
		}
		else
		{
			MoveKey(y_rot_controler, y_rot_keys, -45.0f*Stuff::Radians_Per_Degree, -1);
		}

		// push out the handle just a little more to match the ground...
		INode *foot_site = FindNode(m_ip->GetRootNode(), "site_rfoot");
		Check_Pointer(foot_site);

		// calculate the length of the foot..
		Matrix3 parentTM, nodeTM, localTM;
		nodeTM = foot_site->GetNodeTM(m_ip->GetAnimRange().Start());
		parentTM = foot_site->GetParentTM(m_ip->GetAnimRange().Start());
		//parentTM = left_foot_handle->GetNodeTM(m_ip->GetAnimRange().Start());
		localTM = nodeTM*Inverse(parentTM);

		AffineParts ap;
		decomp_affine(localTM, &ap);

		float foot_length = -ap.t.z;
		
		//SPEW(("jerryeds", "foot_length %f", foot_length));
		
	
		float ground_adjustment;
		
		{
			//
			//  A
			//   |\
			//   | \ 
			//	b|  \c
			//   |   \
			//  C|____\B
			//      a
			//

			// calculate the foot penetration
			float b,c,A,B;
			c = foot_length;
			B = m_angleSlope;
			A = (90.0f * Stuff::Radians_Per_Degree ) - B;
			b = Cos(A) * c;

			ground_adjustment = foot_length - b;
		}


		{
			float a,c,B;
			a = ground_adjustment;
			B = m_angleSlope;
			c = a / Cos(B);

			ground_adjustment = c;
		}


		// solve the second triangle...


		//SPEW(("jerryeds", "new_length %f", b));
		SPEW(("jerryeds", "ground_adjustment %f", ground_adjustment));

		// push the handle out from the normal of the ground...
		
		Matrix3 axis(MAT_IDENT);

		
		Point3 translate(0.0f, 0.0f, ground_adjustment);

		right_foot_handle->Move(0, axis, translate, FALSE, TRUE, PIV_NONE, TRUE);

	}	


}

//===========================================================================//

void HillAdjustPanel::AdjustRightHill(void)
{
		
	INode *left_foot_handle = FindNode(m_ip->GetRootNode(), "handle_lfoot");
	Check_Pointer(left_foot_handle);

	{
		Control *tm_control = left_foot_handle->GetTMController();
		Check_Pointer(tm_control);

		Control *position_controler = tm_control->GetPositionController();
		Check_Pointer(position_controler);

		Control *rotation_controler = tm_control->GetRotationController();
		Check_Pointer(position_controler);

		Control *x_controler = position_controler->GetXController();
		Check_Pointer(x_controler);

		Control *y_controler = position_controler->GetYController();
		Check_Pointer(y_controler);

		Control *z_controler = position_controler->GetZController();
		Check_Pointer(z_controler);


		Control *x_rot_controler = rotation_controler->GetXController();
		Check_Pointer(x_controler);

		Control *y_rot_controler = rotation_controler->GetYController();
		Check_Pointer(y_controler);

		Control *z_rot_controler = rotation_controler->GetZController();
		Check_Pointer(z_controler);

		
		Convert(position_controler, z_controler, 2);
		z_controler = position_controler->GetZController();

		Convert(rotation_controler, y_rot_controler, 1);
		y_rot_controler = rotation_controler->GetYController();

		// adjust keyframe to go up in z the correct amount of degrees...
		IKeyControl *z_keys = GetKeyControlInterface(z_controler);
		
		Stuff::Scalar *x_position_table = new Stuff::Scalar[z_keys->GetNumKeys()];
		Register_Pointer(x_position_table);

		for (int i = 0; i < z_keys->GetNumKeys(); ++i)
		{
			Quat rot;
			Point3 pos;
			
			// Get the pos and rot from the frame.

			int time_of_key = GetKeyTime(z_controler, z_keys, i);

			// Compute the relative TM
			Matrix3 parentTM, nodeTM, localTM;
			nodeTM = left_foot_handle->GetNodeTM(time_of_key);
			parentTM = left_foot_handle->GetParentTM(time_of_key);
			localTM = nodeTM*Inverse(parentTM);

			AffineParts ap;
			decomp_affine(localTM, &ap);
			
			x_position_table[i] = ap.t.x;

		}


		for (i = 0; i < z_keys->GetNumKeys(); ++i)
		{
			
			Stuff::Scalar height = (Stuff::Scalar)tan(m_angleSlope) * x_position_table[i];

			//SPEW(("jerryeds", "l:%f", height));

			MoveKey(z_controler, z_keys, -height, i);


		}


		Unregister_Pointer(x_position_table);
		delete x_position_table;


		IKeyControl *y_rot_keys = GetKeyControlInterface(y_rot_controler);
		
		if (y_rot_keys->GetNumKeys() > 0)
		{
			for (i = 0; i < y_rot_keys->GetNumKeys(); ++i)
			{
				MoveKey(y_rot_controler, y_rot_keys, 45.0f*Stuff::Radians_Per_Degree, i);
			}
		}
		else
		{
			MoveKey(y_rot_controler, y_rot_keys, 45.0f*Stuff::Radians_Per_Degree, -1);
		}

				// push out the handle just a little more to match the ground...
		INode *foot_site = FindNode(m_ip->GetRootNode(), "site_lfoot");
		Check_Pointer(foot_site);

		// calculate the length of the foot..
		Matrix3 parentTM, nodeTM, localTM;
		nodeTM = foot_site->GetNodeTM(m_ip->GetAnimRange().Start());
		parentTM = foot_site->GetParentTM(m_ip->GetAnimRange().Start());
		//parentTM = left_foot_handle->GetNodeTM(m_ip->GetAnimRange().Start());
		localTM = nodeTM*Inverse(parentTM);

		AffineParts ap;
		decomp_affine(localTM, &ap);

		float foot_length = -ap.t.z;
		
		//SPEW(("jerryeds", "foot_length %f", foot_length));
		
		float ground_adjustment;
		
		{
			//
			//  A
			//   |\
			//   | \ 
			//	b|  \c
			//   |   \
			//  C|____\B
			//      a
			//

			// calculate the foot penetration
			float b,c,A,B;
			c = foot_length;
			B = m_angleSlope;
			A = (90.0f * Stuff::Radians_Per_Degree ) - B;
			b = Cos(A) * c;

			ground_adjustment = foot_length - b;
		}


		{
			float a,c,B;
			a = ground_adjustment;
			B = m_angleSlope;
			c = a / Cos(B);

			ground_adjustment = c;
		}


		// solve the second triangle...


		//SPEW(("jerryeds", "new_length %f", b));
		SPEW(("jerryeds", "ground_adjustment %f", ground_adjustment));

		// push the handle out from the normal of the ground...
		
		Matrix3 axis(MAT_IDENT);

		
		Point3 translate(0.0f, 0.0f, ground_adjustment);

	

		left_foot_handle->Move(0, axis, translate, FALSE, TRUE, PIV_NONE);

	}	


	INode *right_foot_handle = FindNode(m_ip->GetRootNode(), "handle_rfoot");
	Check_Pointer(right_foot_handle);

	{

		Control *tm_control = right_foot_handle->GetTMController();
		Check_Pointer(tm_control);

		Control *position_controler = tm_control->GetPositionController();
		Check_Pointer(position_controler);

		Control *rotation_controler = tm_control->GetRotationController();
		Check_Pointer(position_controler);

		Control *x_controler = position_controler->GetXController();
		Check_Pointer(x_controler);

		Control *y_controler = position_controler->GetYController();
		Check_Pointer(y_controler);

		Control *z_controler = position_controler->GetZController();
		Check_Pointer(z_controler);


		Control *x_rot_controler = rotation_controler->GetXController();
		Check_Pointer(x_controler);

		Control *y_rot_controler = rotation_controler->GetYController();
		Check_Pointer(y_controler);

		Control *z_rot_controler = rotation_controler->GetZController();
		Check_Pointer(z_controler);


		Convert(position_controler, z_controler, 2);
		z_controler = position_controler->GetZController();

		Convert(rotation_controler, y_rot_controler, 1);
		y_rot_controler = rotation_controler->GetYController();


		// adjust keyframe to go up in z the correct amount of degrees...
		IKeyControl *z_keys = GetKeyControlInterface(z_controler);
		
		Stuff::Scalar *x_position_table = new Stuff::Scalar[z_keys->GetNumKeys()];
		Register_Pointer(x_position_table);

		for (int i = 0; i < z_keys->GetNumKeys(); ++i)
		{
			Quat rot;
			Point3 pos;
			
			// Get the pos and rot from the frame.

			int time_of_key = GetKeyTime(z_controler, z_keys, i);

			// Compute the relative TM
			Matrix3 parentTM, nodeTM, localTM;
			nodeTM = right_foot_handle->GetNodeTM(time_of_key);
			parentTM = right_foot_handle->GetParentTM(time_of_key);
			localTM = nodeTM*Inverse(parentTM);

			AffineParts ap;
			decomp_affine(localTM, &ap);
			
			x_position_table[i] = ap.t.x;

		}


		for (i = 0; i < z_keys->GetNumKeys(); ++i)
		{
			Stuff::Scalar height = (Stuff::Scalar)tan(m_angleSlope) * x_position_table[i];

			//SPEW(("jerryeds", "r:%f", height));

			MoveKey(z_controler, z_keys, -height, i);


		}

		Unregister_Pointer(x_position_table);
		delete x_position_table;

		IKeyControl *y_rot_keys = GetKeyControlInterface(y_rot_controler);
		
		if (y_rot_keys->GetNumKeys() > 0)
		{
			for (i = 0; i < y_rot_keys->GetNumKeys(); ++i)
			{
				MoveKey(y_rot_controler, y_rot_keys, 45.0f*Stuff::Radians_Per_Degree, i);
			}
		}
		else
		{
			MoveKey(y_rot_controler, y_rot_keys, 45.0f*Stuff::Radians_Per_Degree, -1);
		}

		// push out the handle just a little more to match the ground...
		INode *foot_site = FindNode(m_ip->GetRootNode(), "site_rfoot");
		Check_Pointer(foot_site);

		// calculate the length of the foot..
		Matrix3 parentTM, nodeTM, localTM;
		nodeTM = foot_site->GetNodeTM(m_ip->GetAnimRange().Start());
		parentTM = foot_site->GetParentTM(m_ip->GetAnimRange().Start());
		//parentTM = left_foot_handle->GetNodeTM(m_ip->GetAnimRange().Start());
		localTM = nodeTM*Inverse(parentTM);

		AffineParts ap;
		decomp_affine(localTM, &ap);

		float foot_length = -ap.t.z;
		
			float ground_adjustment;
		
		{
			//
			//  A
			//   |\
			//   | \ 
			//	b|  \c
			//   |   \
			//  C|____\B
			//      a
			//

			// calculate the foot penetration
			float b,c,A,B;
			c = foot_length;
			B = m_angleSlope;
			A = (90.0f * Stuff::Radians_Per_Degree ) - B;
			b = Cos(A) * c;

			ground_adjustment = foot_length - b;
		}


		{
			float a,c,B;
			a = ground_adjustment;
			B = m_angleSlope;
			c = a / Cos(B);

			ground_adjustment = c;
		}


		// solve the second triangle...


		//SPEW(("jerryeds", "new_length %f", b));
		SPEW(("jerryeds", "ground_adjustment %f", ground_adjustment));

		// push the handle out from the normal of the ground...
		
		Matrix3 axis(MAT_IDENT);

		
		Point3 translate(0.0f, 0.0f, ground_adjustment);

	

		right_foot_handle->Move(0, axis, translate, FALSE, TRUE, PIV_NONE);

	}	
}

//===========================================================================//

void HillAdjustPanel::MoveKey(Control *c, IKeyControl *ikeys, Stuff::Scalar amount, int key_number)
{

	if (key_number == -1)
	{
		SuspendAnimate();
		AnimateOn();

		float old_amount;
	
		c->GetValue(m_ip->GetAnimRange().Start(),&old_amount,FOREVER,CTRL_ABSOLUTE);

		amount += old_amount;
		c->SetValue(m_ip->GetAnimRange().Start(),&amount,TRUE,CTRL_ABSOLUTE);

		ResumeAnimate();
		theHold.Accept(0);

		return;
	}



	{
		SuspendAnimate();
		AnimateOn();

		int time = GetKeyTime(c, ikeys, key_number);


		float old_amount;
	
		c->GetValue(time,&old_amount,FOREVER,CTRL_ABSOLUTE);

		amount += old_amount;
		c->SetValue(time,&amount,TRUE,CTRL_ABSOLUTE);

		ResumeAnimate();
		theHold.Accept(0);

		return;
	}


}

//===========================================================================//

void HillAdjustPanel::ScaleKey(Control *c, IKeyControl *ikeys, Stuff::Scalar amount, float median,int key_number)
{

	if (key_number == -1)
	{
		SuspendAnimate();
		AnimateOn();

		float old_amount;
		c->GetValue(m_ip->GetAnimRange().Start(),&old_amount,FOREVER,CTRL_ABSOLUTE);

		// amount *= old_amount;
		amount = ((old_amount-median)*amount)+median;
		c->SetValue(m_ip->GetAnimRange().Start(),&amount,TRUE,CTRL_ABSOLUTE);

		ResumeAnimate();
		theHold.Accept(0);

		return;
	}


	
	{
		SuspendAnimate();
		AnimateOn();


		int time = GetKeyTime(c, ikeys, key_number);

		float old_amount;
		c->GetValue(time,&old_amount,FOREVER,CTRL_ABSOLUTE);

		//amount *= old_amount;
		amount = ((old_amount-median)*amount)+median;
		c->SetValue(time,&amount,TRUE,CTRL_ABSOLUTE);

		ResumeAnimate();
		theHold.Accept(0);

		return;
	}


}


//===========================================================================//

#if 0
void HillAdjustPanel::RotateTangents(Control *c, IKeyControl *ikeys, Stuff::Scalar amount, int key_number)
{

	//SPEW(("jerryeds", "adjust tangent by %f", amount));

	if (key_number == -1)
	{
		

		return;
	}


	if (c->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0))
	{
		return;
	}
	else if (c->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0))
	{
		return;
	}

	else if(c->ClassID() == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0))
	{
		IBezFloatKey key;
		ikeys->GetKey(key_number, &key);
		
		
		

		if (GetOutTanType(key.flags) == BEZKEY_USER && key_number < ikeys->GetNumKeys()-1)
		{

			int int_key_time_dif = GetKeyTime(c, ikeys, key_number) - GetKeyTime(c, ikeys, key_number + 1);

			int frame_diff = int_key_time_dif/3;

			Stuff::Scalar new_outtan = (key.outtan * frame_diff);

			Stuff::Scalar angle = 0.0f;

			Stuff::Scalar a = new_outtan;
			Stuff::Scalar b = TicksToSec(frame_diff)*GetFrameRate();

			angle = Stuff::Arctan(a,b);


			// tan(A) = a/b
			a = Stuff::Tan(angle + amount) * b;


			key.outtan = a / frame_diff;

			//SPEW(("jerryeds", "intan old : new %f : %f", angle * Stuff::Degrees_Per_Radian, (angle+amount) * Stuff::Degrees_Per_Radian));
			

		}

		if (GetInTanType(key.flags) == BEZKEY_USER && key_number > 0)
		{

			int int_key_time_dif = GetKeyTime(c, ikeys, key_number) - GetKeyTime(c, ikeys, key_number - 1);

			int frame_diff = int_key_time_dif/3; 

			Stuff::Scalar new_intan = (key.intan * frame_diff);

			Stuff::Scalar angle = 0.0f;

			Stuff::Scalar a = new_intan;
			Stuff::Scalar b = TicksToSec(frame_diff)*GetFrameRate();

			angle = Stuff::Arctan(a,b);

			a = Stuff::Tan(angle - amount) * b;

		
			key.intan = a / frame_diff;

			//SPEW(("jerryeds", "outtan old : new %f : %f", angle * Stuff::Degrees_Per_Radian, angle-amount * Stuff::Degrees_Per_Radian));
			
			
			
		}

		ikeys->SetKey(key_number, &key);
	}
}
#endif



void HillAdjustPanel::RotateTangents(Control *c, IKeyControl *ikeys, Stuff::Scalar height, int key_number)
{

	//SPEW(("jerryeds", "adjust tangent by %f", amount));

	if (key_number == -1)
	{
		

		return;
	}


	if (c->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0))
	{
		return;
	}
	else if (c->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0))
	{
		return;
	}

	else if(c->ClassID() == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0))
	{
		
		
		if (key_number > 0)
		{

			IBezFloatKey last_key;
			IBezFloatKey now_key;
			ikeys->GetKey(key_number, &now_key);
			ikeys->GetKey(key_number-1, &last_key);

			float angle_of_adjustment;
			float time_diff = TicksToSec(now_key.time - last_key.time)*GetFrameRate();

			angle_of_adjustment = Stuff::Arctan(height, time_diff);


			

			if (GetInTanType(now_key.flags) == BEZKEY_USER)
			{
				//SPEW(("jerryeds", "in angle %f", -angle_of_adjustment*Stuff::Degrees_Per_Radian));
				
				int int_key_time_dif = now_key.time - last_key.time;
				int frame_diff = int_key_time_dif/3;

				Stuff::Scalar new_intan = (now_key.intan * frame_diff);
				Stuff::Scalar a = new_intan;
				Stuff::Scalar b = TicksToSec(frame_diff)*GetFrameRate();

				Stuff::Scalar angle = Stuff::Arctan(a,b);


				// tan(A) = a/b
				a = Stuff::Tan(angle - angle_of_adjustment) * b;


				now_key.intan = a / frame_diff;


				ikeys->SetKey(key_number, &now_key);
			}
			if (GetOutTanType(last_key.flags) == BEZKEY_USER)
			{

				//SPEW(("jerryeds", "out angle %f", angle_of_adjustment*Stuff::Degrees_Per_Radian));

				int int_key_time_dif = now_key.time - last_key.time;
				int frame_diff = int_key_time_dif/3;

				Stuff::Scalar new_outtan = (last_key.outtan * frame_diff);
				Stuff::Scalar a = new_outtan;
				Stuff::Scalar b = TicksToSec(frame_diff)*GetFrameRate();

				Stuff::Scalar angle = Stuff::Arctan(a,b);


				// tan(A) = a/b
				a = Stuff::Tan(angle + angle_of_adjustment) * b;


				last_key.outtan = a / frame_diff;



				ikeys->SetKey(key_number-1, &last_key);
			}
		}
	}
}





//===========================================================================//

Stuff::Scalar HillAdjustPanel::GetKeyValue(Control *c, IKeyControl *ikeys, int key_number)
{


	Stuff::Scalar value = 0.0f;

	if (c->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0))
	{
		ILinFloatKey key;
		ikeys->GetKey(key_number, &key);

		value = key.val;
	}
	else if (c->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0))
	{
		ITCBFloatKey key;
		ikeys->GetKey(key_number, &key);

		value = key.val;
	}

	else if(c->ClassID() == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0))
	{
		IBezFloatKey key;
		ikeys->GetKey(key_number, &key);

		value = key.val;
	}

	return value;
}

//===========================================================================//

int HillAdjustPanel::GetKeyTime(Control *c, IKeyControl *ikeys, int key_number)
{

	

	int value = 0;

	if (c->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0))
	{
		ILinFloatKey key;
		ikeys->GetKey(key_number, &key);

		value = key.time;
	}
	else if (c->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0))
	{
		ITCBFloatKey key;
		ikeys->GetKey(key_number, &key);

		value = key.time;
	}

	else if(c->ClassID() == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0))
	{
		IBezFloatKey key;
		ikeys->GetKey(key_number, &key);

		value = key.time;
	}

	return value;
}


//===========================================================================//

INode* HillAdjustPanel::FindNode(INode* node, const char *name_of_joint)
{
	
	if (!_stricmp(node->GetName(), name_of_joint))
	{
		return node;
	}

	for (int c = 0; c < node->NumberOfChildren(); c++) 
	{
		INode *new_node = FindNode(node->GetChildNode(c), name_of_joint);

		if (new_node != NULL)
		{
			return new_node;
		}
	}

	return NULL;
}

void HillAdjustPanel::LoadValues(HWND hWnd)
{
	DWORD wType = REG_SZ;
	char szValue[100];
	BYTE *pData = (BYTE *)szValue;

	char keybase[100] = "SOFTWARE\\Autodesk\\3D Studio MAX";
	HKEY hMax;
	if (ERROR_SUCCESS != RegOpenKey(HKEY_LOCAL_MACHINE,keybase,&hMax))
		// 3dStudio is not installed??
		return;

	char szKey[50] = "Plugins\\HillAdjust";
	HKEY hKey;
	if (ERROR_SUCCESS != RegCreateKey(hMax,szKey,&hKey))
		return;
	DWORD size = 10;
	char szLast[10];
	int i=0;
	BOOL bReset = FALSE;
	if (-1 == m_angleEnum)
	{
		if (ERROR_SUCCESS != RegQueryValueEx(hKey,"Last",0,&wType,(BYTE *)szLast,&size))
		{
			m_angleEnum = 0;
			strcpy(szLast,g_szDir[m_angleEnum]);
		}
		else
			for (i=0;(i<4)&&(strcmp(g_szDir[i],szLast));i++);
		if (-1 == m_angleEnum)
		{
			m_angleEnum = i;
			SendDlgItemMessage(hWnd,IDC_COMBO_DIRECTION,CB_SETCURSEL,i,0);
		}

		size = 20;
		char szVersion[20];
		if (ERROR_SUCCESS != RegQueryValueEx(hKey,"Version",0,&wType,(BYTE *)szVersion,&size))
		{
			bReset = TRUE;
		}
	}
	else
		strcpy(szLast,g_szDir[m_angleEnum]);
	RegCloseKey(hKey);

	strcat(szKey,"\\");
	strcat(szKey,szLast);
	if (ERROR_SUCCESS != RegCreateKey(hMax,szKey,&hKey))
		return;

/*
	char szKey[20];
	sprintf(szKey,"Plugins\\HillAdjust\\%s",g_szDir[m_angleEnum]);
	HKEY hKey;
	if (ERROR_SUCCESS != RegCreateKey(hMax,szKey,&hKey))
		// error creating key
		return;
*/
	float fValue;
	size = 100;
	if (ERROR_SUCCESS != RegQueryValueEx(hKey,"angle",0,&wType,pData,&size))
		strcpy(szValue,"45.0f");
	sscanf(szValue,"%f",&fValue);
	m_angleSpinner = SetupFloatSpinner(hWnd, IDC_SPIN_ANGLE, IDC_EDIT_ANGLE, 0.0f, 90.0f, fValue, 1.0f);

	// Load the control values
	////////////////////
	m_rootScalePosXControl = (new CCtlData(hWnd,hKey,IDC_CHECK_SCALE_ROOT_POS_X,IDC_SPIN_SCALE_ROOT_POS_X,IDC_EDIT_SCALE_ROOT_POS_X,-500.0f,500.0f,1.0f,100.0f))->GetSpinner();
	m_rootScalePosYControl = (new CCtlData(hWnd,hKey,IDC_CHECK_SCALE_ROOT_POS_Y,IDC_SPIN_SCALE_ROOT_POS_Y,IDC_EDIT_SCALE_ROOT_POS_Y,-500.0f,500.0f,1.0f,100.0f))->GetSpinner();
	m_rootScalePosZControl = (new CCtlData(hWnd,hKey,IDC_CHECK_SCALE_ROOT_POS_Z,IDC_SPIN_SCALE_ROOT_POS_Z,IDC_EDIT_SCALE_ROOT_POS_Z,-500.0f,500.0f,1.0f,100.0f))->GetSpinner();

	////////////////////

	m_rootScaleRotXControl = (new CCtlData(hWnd,hKey,IDC_CHECK_SCALE_ROOT_ROT_X,IDC_SPIN_SCALE_ROOT_ROT_X,IDC_EDIT_SCALE_ROOT_ROT_X,-500.0f,500.0f,1.0f,100.0f))->GetSpinner();
	m_rootScaleRotYControl = (new CCtlData(hWnd,hKey,IDC_CHECK_SCALE_ROOT_ROT_Y,IDC_SPIN_SCALE_ROOT_ROT_Y,IDC_EDIT_SCALE_ROOT_ROT_Y,-500.0f,500.0f,1.0f,100.0f))->GetSpinner();
	m_rootScaleRotZControl = (new CCtlData(hWnd,hKey,IDC_CHECK_SCALE_ROOT_ROT_Z,IDC_SPIN_SCALE_ROOT_ROT_Z,IDC_EDIT_SCALE_ROOT_ROT_Z,-500.0f,500.0f,1.0f,100.0f))->GetSpinner();

	////////////////////

	m_rootMovePosXControl = (new CCtlData(hWnd,hKey,IDC_CHECK_MOVE_ROOT_POS_X,IDC_SPIN_MOVE_ROOT_POS_X,IDC_EDIT_MOVE_ROOT_POS_X,-50.0f,50.0f,0.1f,0.0f))->GetSpinner();
	m_rootMovePosYControl = (new CCtlData(hWnd,hKey,IDC_CHECK_MOVE_ROOT_POS_Y,IDC_SPIN_MOVE_ROOT_POS_Y,IDC_EDIT_MOVE_ROOT_POS_Y,-50.0f,50.0f,0.1f,0.0f))->GetSpinner();
	m_rootMovePosZControl = (new CCtlData(hWnd,hKey,IDC_CHECK_MOVE_ROOT_POS_Z,IDC_SPIN_MOVE_ROOT_POS_Z,IDC_EDIT_MOVE_ROOT_POS_Z,-50.0f,50.0f,0.1f,0.0f))->GetSpinner();

	/*size = 100;
	if (ERROR_SUCCESS != RegQueryValueEx(hKey,"RootMoveRot",0,&wType,pData,&size))
		strcpy(szValue,"1,1,1,0.0,0.0,0.0");
	sscanf(szValue,"%i,%i,%i,%f,%f,%f",&x,&y,&z,&fx,&fy,&fz);*/
	m_rootMoveRotXControl = (new CCtlData(hWnd,hKey,IDC_CHECK_MOVE_ROOT_ROT_X,IDC_SPIN_MOVE_ROOT_ROT_X,IDC_EDIT_MOVE_ROOT_ROT_X,-50.0f,50.0f,0.1f,0.0f))->GetSpinner();
	m_rootMoveRotYControl = (new CCtlData(hWnd,hKey,IDC_CHECK_MOVE_ROOT_ROT_Y,IDC_SPIN_MOVE_ROOT_ROT_Y,IDC_EDIT_MOVE_ROOT_ROT_Y,-50.0f,50.0f,0.1f,0.0f))->GetSpinner();
	m_rootMoveRotZControl = (new CCtlData(hWnd,hKey,IDC_CHECK_MOVE_ROOT_ROT_Z,IDC_SPIN_MOVE_ROOT_ROT_Z,IDC_EDIT_MOVE_ROOT_ROT_Z,-50.0f,50.0f,0.1f,0.0f))->GetSpinner();

	/*size = 100;
	if (ERROR_SUCCESS != RegQueryValueEx(hKey,"HipScalePosX",0,&wType,pData,&size))
		strcpy(szValue,"1,100.0f");
	sscanf(szValue,"%i,%f",&x,&fValue);*/
	m_hipScaleControl = (new CCtlData(hWnd,hKey,IDC_CHECK_SCALE_HIP,IDC_SPIN_SCALE_HIP_POS_X,IDC_EDIT_SCALE_HIP_POS_X,-500.0f,500.0f,1.0f,100.0f))->GetSpinner();

/*	size = 100;
	if (ERROR_SUCCESS != RegQueryValueEx(hKey,"HipMoveX",0,&wType,pData,&size))
		strcpy(szValue,"1,0.0f");
	sscanf(szValue,"%i,%f",&x,&fValue);*/
	m_hipMoveControl = (new CCtlData(hWnd,hKey,IDC_CHECK_MOVE_HIP,IDC_SPIN_MOVE_HIP_Y,IDC_EDIT_MOVE_HIP_Y,-179.0f,179.0f,0.1f,0.0f))->GetSpinner();

/*	size = 100;
	if (ERROR_SUCCESS != RegQueryValueEx(hKey,"TorsoScale",0,&wType,pData,&size))
		strcpy(szValue,"1,1,1,100.0,100.0,100.0");
	sscanf(szValue,"%i,%i,%i,%f,%f,%f",&x,&y,&z,&fx,&fy,&fz);*/
	m_torsoScaleXControl = (new CCtlData(hWnd,hKey,IDC_CHECK_SCALE_TORSO_X,IDC_SPIN_SCALE_TORSO_X,IDC_EDIT_SCALE_TORSO_X,-500.0f,500.0f,1.0f,100.0f))->GetSpinner();
	m_torsoScaleYControl = (new CCtlData(hWnd,hKey,IDC_CHECK_SCALE_TORSO_Y,IDC_SPIN_SCALE_TORSO_Y,IDC_EDIT_SCALE_TORSO_Y,-500.0f,500.0f,1.0f,100.0f))->GetSpinner();
	m_torsoScaleZControl = (new CCtlData(hWnd,hKey,IDC_CHECK_SCALE_TORSO_Z,IDC_SPIN_SCALE_TORSO_Z,IDC_EDIT_SCALE_TORSO_Z,-500.0f,500.0f,1.0f,100.0f))->GetSpinner();

/*	size = 100;
	if (ERROR_SUCCESS != RegQueryValueEx(hKey,"FeetCloseness",0,&wType,pData,&size))
		strcpy(szValue,"1,1,100.0f 100.0f");
	sscanf(szValue,"%i,%i,%f %f",&x,&y,&fx,&fy);*/
	m_leftFootScaleCloseControl = (new CCtlData(hWnd,hKey,IDC_CHECK_SCALE_FEET_L,IDC_SPIN_SCALE_FEET_CLOSENESS_LEFT,IDC_EDIT_SCALE_FEET_CLOSENESS_LEFT,-500.0f,500.0f,1.0f,100.0f))->GetSpinner();
	m_rightFootScaleCloseControl = (new CCtlData(hWnd,hKey,IDC_CHECK_SCALE_FEET_R,IDC_SPIN_SCALE_FEET_CLOSENESS_RIGHT,IDC_EDIT_SCALE_FEET_CLOSENESS_RIGHT,-500.0f,500.0f,1.0f,100.0f))->GetSpinner();

	size = 100;
	if (ERROR_SUCCESS != RegQueryValueEx(hKey,"LeaveOriginalTangents",0,&wType,pData,&size))
		strcpy(szValue,"0");
	sscanf(szValue,"%i",&m_leaveOriginalTangents);
	SendDlgItemMessage(hWnd,IDC_LEAVE_TANG,BM_SETCHECK,m_leaveOriginalTangents?BST_CHECKED:BST_UNCHECKED,0);

	size = 100;
	if (ERROR_SUCCESS != RegQueryValueEx(hKey,"LeaveOriginalCurves",0,&wType,pData,&size))
		strcpy(szValue,"0");
	sscanf(szValue,"%i",&m_leaveOriginalCurves);
	SendDlgItemMessage(hWnd,IDC_LEAVE_CURVE,BM_SETCHECK,m_leaveOriginalCurves?BST_CHECKED:BST_UNCHECKED,0);

	RegCloseKey(hKey);
	RegCloseKey(hMax);
}

void HillAdjustPanel::SaveValues()
{
	char keybase[100] = "SOFTWARE\\Autodesk\\3D Studio MAX";
	HKEY hMax;
	if (ERROR_SUCCESS != RegOpenKey(HKEY_LOCAL_MACHINE,keybase,&hMax))
		// 3dStudio is not installed??
		return;
	char szKey[50] = "Plugins\\HillAdjust";
	HKEY hKey;
	if (ERROR_SUCCESS != RegCreateKey(hMax,szKey,&hKey))
		return;

	DWORD size = 100;
	{
		bool bReset = FALSE;
		size = 20;
		DWORD wType = REG_SZ;
		char szVersion[20];
		if (ERROR_SUCCESS != RegQueryValueEx(hKey,"Version",0,&wType,(BYTE *)szVersion,&size))
		{
			bReset = TRUE;
		}
		// is the current version newer
/*		int iVersion = atoi(szVersion);
		if (0219 > iVersion)		CURRENT_BUILD_COUNT
		{
			bReset = TRUE;
		}

		if (bReset)
		{
			for (int x=0;x<4;x++)
				RegDeleteKey(hKey,g_szDir[x]);
		}*/
	}

	RegSetValueEx(hKey,"Version",0,REG_SZ,(BYTE *)CURRENT_BUILD_FULL_STRING,strlen(CURRENT_BUILD_FULL_STRING));
	RegSetValueEx(hKey,"Last",0,REG_SZ,(BYTE *)g_szDir[m_angleEnum],strlen(g_szDir[m_angleEnum]));
	RegCloseKey(hKey);

	strcat(szKey,"\\");
	strcat(szKey,g_szDir[m_angleEnum]);

	if (ERROR_SUCCESS != RegCreateKey(hMax,szKey,&hKey))
		return;

	char szValue[100];
	BYTE *pData = (BYTE *)szValue;
	// xyz used for enabled buttons
//	int x,y,z;

	size = 100;
	size = sprintf(szValue,"%f",m_angleSpinner->GetFVal());
	int err;
	err = RegSetValueEx(hKey,"angle",0,REG_SZ,pData,size);
	Verify(ERROR_SUCCESS ==err);

	POSITION pos = g_mapCtlData.GetStartPosition();
	WORD key;
	while (pos)
	{
		CObject *pObj;
		g_mapCtlData.GetNextAssoc(pos,key,pObj);
		CCtlData *pCtlData = (CCtlData *)pObj;
		
		int bEnabled = pCtlData->IsEnabled();  //IsWindowEnabled(GetDlgItem(this->m_hPanel,pCtlData->GetIdEdit()));
		size = sprintf(szValue,"%i %f",bEnabled,pCtlData->GetSpinner()->GetFVal());
		char szKey[10];
		sprintf(szKey,"%i",key);
		err = RegSetValueEx(hKey,szKey,0,REG_SZ,pData,size);
		Verify(ERROR_SUCCESS ==err);
	}

/*
	x = rootScalePosXControl->IsEnabled();
	y = rootScalePosYControl->IsEnabled();
	z = rootScalePosZControl->IsEnabled();
	size = sprintf(szValue,"%i,%i,%i,%f,%f,%f",x,y,z,rootScalePosXControl->GetFVal(),rootScalePosYControl->GetFVal(),rootScalePosZControl->GetFVal());
	Verify(ERROR_SUCCESS ==RegSetValueEx(hKey,"RootScalePos",0,REG_SZ,pData,size));
	
	x = rootScaleRotXControl->IsEnabled();
	y = rootScaleRotYControl->IsEnabled();
	z = rootScaleRotZControl->IsEnabled();
	size = sprintf(szValue,"%i,%i,%i,%f,%f,%f",x,y,z,rootScaleRotXControl->GetFVal(),rootScaleRotYControl->GetFVal(),rootScaleRotZControl->GetFVal());
	Verify(ERROR_SUCCESS ==RegSetValueEx(hKey,"RootScaleRot",0,REG_SZ,pData,size));

	x = rootMovePosXControl->IsEnabled();
	y = rootMovePosYControl->IsEnabled();
	z = rootMovePosZControl->IsEnabled();
	size = sprintf(szValue,"%i,%i,%i,%f,%f,%f",x,y,z,rootMovePosXControl->GetFVal(),rootMovePosYControl->GetFVal(),rootMovePosZControl->GetFVal());
	Verify(ERROR_SUCCESS ==RegSetValueEx(hKey,"RootMovePos",0,REG_SZ,pData,size));
	
	x = rootMoveRotXControl->IsEnabled();
	y = rootMoveRotYControl->IsEnabled();
	z = rootMoveRotZControl->IsEnabled();
	size = sprintf(szValue,"%i,%i,%i,%f,%f,%f",x,y,z,rootMoveRotXControl->GetFVal(),rootMoveRotYControl->GetFVal(),rootMoveRotZControl->GetFVal());
	Verify(ERROR_SUCCESS ==RegSetValueEx(hKey,"RootMoveRot",0,REG_SZ,pData,size));

	x = hipScaleControl->IsEnabled();
	size = sprintf(szValue,"%i,%f",x,hipScaleControl->GetFVal());
	Verify(ERROR_SUCCESS ==RegSetValueEx(hKey,"HipScalePosX",0,REG_SZ,pData,size));

	x = hipMoveControl->IsEnabled();
	size = sprintf(szValue,"%i,%f",x,hipMoveControl->GetFVal());
	Verify(ERROR_SUCCESS ==RegSetValueEx(hKey,"HipMoveX",0,REG_SZ,pData,size));

	x = torsoScaleXControl->IsEnabled();
	y = torsoScaleYControl->IsEnabled();
	z = torsoScaleZControl->IsEnabled();
	size = sprintf(szValue,"%i,%i,%i,%f,%f,%f",x,y,z,torsoScaleXControl->GetFVal(),torsoScaleYControl->GetFVal(),torsoScaleZControl->GetFVal());
	Verify(ERROR_SUCCESS ==RegSetValueEx(hKey,"TorsoScale",0,REG_SZ,pData,size));

	x = m_leftFootScaleCloseControl->IsEnabled();
	y = rightFootScaleCloseControl->IsEnabled();
	size = sprintf(szValue,"%i,%i,%f %f",x,y,m_leftFootScaleCloseControl->GetFVal(),rightFootScaleCloseControl->GetFVal());
	Verify(ERROR_SUCCESS ==RegSetValueEx(hKey,"FeetCloseness",0,REG_SZ,pData,size));
*/
	size = sprintf(szValue,"%i",m_leaveOriginalTangents);
	err = RegSetValueEx(hKey,"LeaveOriginalTangents",0,REG_SZ,pData,size);
	Verify(ERROR_SUCCESS == err);

	size = sprintf(szValue,"%i",m_leaveOriginalCurves);
	err = RegSetValueEx(hKey,"LeaveOriginalCurves",0,REG_SZ,pData,size);
	Verify(ERROR_SUCCESS == err);
	RegCloseKey(hKey);
	RegCloseKey(hMax);
}

#pragma pack(pop)
