
#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 "OptimizeKeyframe.h"


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

OptimizeKeyframePanel g_optimizeKeyframePanel;
CCriticalSection g_threadLock;
ThreadData g_threadInfo;


////////////////////////////////////////////////////////////////////////////////
// PlugPanel Dialog Procedure to handle User and System Interactions
static BOOL CALLBACK OptimizeKeyframePanelProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	switch (msg) {
		case WM_INITDIALOG:						//Panel's extra initialization
			g_optimizeKeyframePanel.Init(hWnd);
			break;
		case WM_DESTROY:						//Panel's extra destruction
			g_optimizeKeyframePanel.Destroy(hWnd);
			break;
		case WM_COMMAND :
			switch (LOWORD(wParam)) {			//Handle Panel's controls
				case IDC_ABOUT: {
					CAbout dlg;
					dlg.DoModal();
					break;
				}
				case IDC_OPTIMIZE: {
					g_optimizeKeyframePanel.Optimize();
					break;
				}
			}
			break;

		////////////////////////////////////////////////////////////////////////
		//The following lines are not necessary for MAX2 Plugins
		case WM_LBUTTONDOWN:
		case WM_LBUTTONUP:
		case WM_MOUSEMOVE:
			g_optimizeKeyframePanel.m_ip->RollupMouseMessage(hWnd, msg, wParam, lParam);
			break;
		////////////////////////////////////////////////////////////////////////

		default:
			return FALSE;
		}
	return TRUE;
}


////////////////////////////////////////////////////////////////////////////////
// Display the Plugin's Panel
void OptimizeKeyframePanel::BeginEditParams(Interface* ip, IUtil* iu)
{
	m_ip = ip;								//Get the Plugin's Interface
	m_iu = iu;								//Get the Utility Plugin's Interface
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	HINSTANCE loc_hInstance = AfxGetResourceHandle ();

	//Display the plugin's Rollup Dialog
	m_hPanel = m_ip->AddRollupPage(loc_hInstance, MAKEINTRESOURCE(IDD_OPT_PANEL),
		OptimizeKeyframePanelProc, GetString(IDS_OPTIMIZEKEY_NAME),0);
}

////////////////////////////////////////////////////////////////////////////////
// Free the Plugins' Panel
void OptimizeKeyframePanel::EndEditParams(Interface *ip, IUtil *iu)
{
	m_iu = NULL;
	m_ip = NULL;

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

////////////////////////////////////////////////////////////////////////////////
// Panel Initialization callback
void OptimizeKeyframePanel::Init(HWND hWnd)
{
}

////////////////////////////////////////////////////////////////////////////////
// Panel Destruction callback
void OptimizeKeyframePanel::Destroy(HWND hWnd)
{
}



////////////////////////////////////////////////////////////////////////////////
// Called when the Optimize Button is pushed
void OptimizeKeyframePanel::Optimize()
{


	AFX_MANAGE_STATE(AfxGetStaticModuleState());


	JointEditDialog dialog(m_ip->GetRootNode(), m_ip);
	if (dialog.DoModal() == IDOK)
	{

		// now optimize...
		int total_nodes = JointEditDialog::CountChildren(m_ip->GetRootNode());
		int current_node = 0;

		theHold.SuperBegin();
		LPVOID arg = NULL;
		m_ip->ProgressStart(_T("Optimizing Joints"), TRUE, fn, arg);
		OptimizeAnimation(m_ip->GetRootNode(), current_node, total_nodes, &dialog);
		m_ip->ProgressEnd();

		// Close out the undo
		theHold.SuperAccept("Replicate");
	}
}



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

void
	OptimizeKeyframePanel::OptimizeAnimation(INode *copy_node, int &current_node, int total_nodes, JointEditDialog *dialog)
{

	
	Control *position_control = NULL;
	Control *rotation_control = NULL;

	Control *tm_controller = copy_node->GetTMController();

	if (tm_controller != NULL)
	{

		position_control = tm_controller->GetPositionController();
		rotation_control = tm_controller->GetRotationController();

		JointPreference *pref = dialog->GetJointPrefrence(copy_node);
		Verify(pref != NULL);

		int include_joint = true;

		if (pref->m_excludeJoint == JointPreference::ExcludeJoint)
		{
			include_joint = false;
		}

		if (pref->m_excludeJoint == JointPreference::AutoJoint)
		{
			if(dialog->NodeAnimated(copy_node))
			{
				include_joint = false;
			}
		}

		if (include_joint)
		{
			if (pref->m_optimizeRotation)
			{
				if (rotation_control != NULL)
				{
					int num_keys = rotation_control->NumKeys();

					if (num_keys > 0)
					{

						TimeValue start = rotation_control->GetKeyTime(0);
						TimeValue end = rotation_control->GetKeyTime(num_keys-1);

						if (pref->m_rotationRange)
						{
							start = (TimeValue)pref->m_rotationSampleStartFrame * GetTicksPerFrame();
							end = (TimeValue)pref->m_rotationSampleEndFrame * GetTicksPerFrame();
						}

						Interval range;
						start = (rotation_control->GetKeyTime(0) > start)   ? rotation_control->GetKeyTime(0):start;
						end = (rotation_control->GetKeyTime(num_keys-1) < end) ? rotation_control->GetKeyTime(num_keys-1):end;
						
						// adjust the optimization to not include the last frame... tehehehehehe
						if ((end - GetTicksPerFrame()) > start)
						{
							end -= GetTicksPerFrame();
						}
						range.Set(start , end);
						
						OptKeyReduceStatus rot_progress;
						
						ApplyKeyReduction_MW4(
								rotation_control, 
								range, 
								pref->m_rotationThreshold * Stuff::Radians_Per_Degree, 
								GetTicksPerFrame(), 
								&rot_progress
							);
					}
				}
			}

			if (pref->m_optimizeTranslation)
			{
				if (position_control != NULL)
				{
					int num_keys = position_control->NumKeys();
				
					if (num_keys > 0)
					{
						TimeValue start = position_control->GetKeyTime(0);
						TimeValue end = position_control->GetKeyTime(num_keys-1);

						if (pref->m_translationRange)
						{
							start = (TimeValue)pref->m_translationSampleStartFrame * GetTicksPerFrame();
							end = (TimeValue)pref->m_translationSampleEndFrame * GetTicksPerFrame();
						}

						Interval range;
						start = (position_control->GetKeyTime(0) > start)   ? position_control->GetKeyTime(0):start;
						end = (position_control->GetKeyTime(num_keys-1) < end) ? position_control->GetKeyTime(num_keys-1):end;
						
						// adjust the optimization to not include the last frame... tehehehehehe
						if ((end - GetTicksPerFrame()) > start)
						{
							end -= GetTicksPerFrame();
						}
						range.Set(start , end);
						
						OptKeyReduceStatus tran_progress;
						
						ApplyKeyReduction_MW4(
								position_control, 
								range, 
								pref->m_translationThreshold, 
								GetTicksPerFrame(), 
								&tran_progress
							);
					}
				}
			}
		}
	}
	
	++current_node;
	
	int total_done = (int)(((float)current_node/(float)total_nodes)*100.0f);
	m_ip->ProgressUpdate(total_done);
		

	for (int i = 0; i < copy_node->NumberOfChildren(); i++)
	{
		INode *child_node = copy_node->GetChildNode(i);
		assert(child_node != NULL);
		OptimizeAnimation(child_node, current_node, total_nodes, dialog);	
	}

	return;
}
