Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
276 lines
7.2 KiB
C++
276 lines
7.2 KiB
C++
|
|
#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 ¤t_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;
|
|
}
|