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.
696 lines
17 KiB
C++
696 lines
17 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 <GameOS\GameOS.hpp>
|
|
|
|
#if !defined(DLLPLATFORM_DLLPLATFORM_HPP)
|
|
#include "DLLPlatform\DLLPlatform.hpp"
|
|
#endif
|
|
|
|
#if !defined(STUFF_STUFF_HPP)
|
|
#include "Stuff\Stuff.hpp"
|
|
#endif
|
|
|
|
#if !defined(MW4ANIMATIONSYSTEM_HPP)
|
|
#include <MW4\MW4AnimationSystem.hpp>
|
|
#endif
|
|
|
|
#undef Min
|
|
#undef Max
|
|
|
|
|
|
#pragma pack(push,8)
|
|
#include "Max.h" // Include MAX's main header file
|
|
#pragma pack(pop)
|
|
|
|
#include <Stuff\StuffHeaders.hpp>
|
|
#include "MaxProxies\MaxProxyHeaders.hpp"
|
|
#include <adept\collisionvolume.hpp>
|
|
|
|
#include "AnimationSuite.h"
|
|
#include "About.h"
|
|
#include "JointEditDialog.h"
|
|
|
|
#include "ArmatureExport.h"
|
|
#include "siteobject.h"
|
|
#include "cvobject.h"
|
|
#include "AnimationExport.h"
|
|
#include "ErfExport.h"
|
|
#include "MLRExport.h"
|
|
#include "EBFExport.h"
|
|
#include "BatchExport.h"
|
|
#include "CvExport.h"
|
|
#include "lightexport.h"
|
|
#include "erfimport.h"
|
|
#include "missionimp.h"
|
|
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
#define DLLEXPORT __declspec(dllexport) // Facilite Function's Exportation Declaration
|
|
|
|
|
|
CAnimExpApp theApp; // Global Object representing the application
|
|
AnimExpClassDesc animExpDesc;
|
|
|
|
JointPreferenceClassDesc jointPreferenceDesc;
|
|
OptimizeKeyframeClassDesc optimizeKeyframeDesc;
|
|
ReplicateClassDesc replicateExpDesc;
|
|
SiteObjectClassDesc siteObjectClassDesc;
|
|
LegMirrorClassDesc legmirrorDesc;
|
|
HillAdjustClassDesc hillAdjustDesc;
|
|
ErfExpClassDesc erfExpDesc;
|
|
MLRExpClassDesc MLRExpDesc;
|
|
EBFExpClassDesc EBFExpDesc;
|
|
BatchExpClassDesc batchExpDesc;
|
|
ArmatureExpClassDesc armatureExpDesc;
|
|
FallToolClassDesc fallToolDesc;
|
|
SkeletonVerifyClassDesc skeletonVerifyDesc;
|
|
CvObjectClassDesc cvObjectClassDesc;
|
|
CvExpClassDesc cvExpDesc;
|
|
CvToolClassDesc cvToolDesc;
|
|
LightExpClassDesc lightExpDesc;
|
|
ErfImpClassDesc erfImpDesc;
|
|
MissionImpClassDesc missionImpDesc;
|
|
//HINSTANCE hInstance;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Prototypes
|
|
static BOOL CALLBACK QuickFileProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CAnimExpApp
|
|
|
|
BEGIN_MESSAGE_MAP(CAnimExpApp, CWinApp)
|
|
//{{AFX_MSG_MAP(CAnimExpApp)
|
|
// NOTE - the ClassWizard will add and remove mapping macros here.
|
|
// DO NOT EDIT what you see in these blocks of generated code!
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CAnimExpApp construction
|
|
|
|
void TurnOnExceptions()
|
|
{
|
|
gos_MathExceptions( 1, 1 );
|
|
}
|
|
|
|
void TurnOffExceptions()
|
|
{
|
|
gos_MathExceptions( 0, 0 );
|
|
}
|
|
|
|
|
|
CAnimExpApp::CAnimExpApp()
|
|
{
|
|
}
|
|
|
|
HGOSHEAP AnimSuiteHeap;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// DLL's InitInstance, called when the DLL is being linked to a client
|
|
BOOL CAnimExpApp::InitInstance()
|
|
{
|
|
TurnOnExceptions();
|
|
//_clear87();
|
|
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
//Get the DLL's HINSTANCE
|
|
hInstance = AfxGetResourceHandle();
|
|
|
|
//Init 3DS Max Custom Controls
|
|
InitCustomControls(hInstance);
|
|
|
|
//Init Win32 Controls
|
|
InitCommonControls();
|
|
|
|
InitGameOS( hInstance, NULL, "\0" );
|
|
|
|
|
|
Stuff::ArmorLevel = 4;
|
|
|
|
|
|
Stuff::InitializeClasses();
|
|
Proxies::InitializeClasses();
|
|
MAXProxies::InitializeClasses();
|
|
MidLevelRenderer::InitializeClasses();
|
|
gosFX::InitializeClasses();
|
|
ElementRenderer::InitializeClasses();
|
|
ElementProxies::InitializeClasses();
|
|
|
|
// Initialize_MAXStuff();
|
|
|
|
TurnOffExceptions();
|
|
|
|
AnimSuiteHeap = gos_CreateMemoryHeap("AnimSuiteHeap");
|
|
Check_Pointer(AnimSuiteHeap);
|
|
gos_PushCurrentHeap(AnimSuiteHeap);
|
|
|
|
|
|
return TRUE; //CWinApp::InitInstance();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// DLL's ExitInstance, called when the DLL is being unlinked from a client
|
|
int CAnimExpApp::ExitInstance()
|
|
{
|
|
gos_PopCurrentHeap();
|
|
|
|
TurnOnExceptions();
|
|
|
|
//_clear87();
|
|
|
|
ElementRenderer::TerminateClasses();
|
|
gosFX::TerminateClasses();
|
|
MidLevelRenderer::TerminateClasses();
|
|
ElementProxies::TerminateClasses();
|
|
MAXProxies::TerminateClasses();
|
|
Proxies::TerminateClasses();
|
|
Stuff::TerminateClasses();
|
|
|
|
TurnOffExceptions();
|
|
|
|
ExitGameOS();
|
|
|
|
return CWinApp::ExitInstance();
|
|
}
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// 3DS Max Identification Callbacks
|
|
DLLEXPORT const TCHAR* LibDescription ()
|
|
{
|
|
return GetString(IDS_LIBDESCRIPTION);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Return the Number of Classes present in the DLLs
|
|
DLLEXPORT int LibNumberClasses ()
|
|
{
|
|
// Return the number of plugins in the DLL
|
|
return 20;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Return the i'th Class Description Object
|
|
DLLEXPORT ClassDesc* LibClassDesc(int i)
|
|
{
|
|
switch(i) {
|
|
case 0:
|
|
return &animExpDesc;
|
|
case 1:
|
|
return &jointPreferenceDesc;
|
|
case 2:
|
|
return &optimizeKeyframeDesc;
|
|
case 3:
|
|
return &replicateExpDesc;
|
|
case 4:
|
|
return &siteObjectClassDesc;
|
|
case 5:
|
|
return &legmirrorDesc;
|
|
case 6:
|
|
return &hillAdjustDesc;
|
|
case 7:
|
|
return &erfExpDesc;
|
|
case 8:
|
|
return &batchExpDesc;
|
|
case 9:
|
|
return &armatureExpDesc;
|
|
case 10:
|
|
return &fallToolDesc;
|
|
case 11:
|
|
return &skeletonVerifyDesc;
|
|
case 12:
|
|
return &cvObjectClassDesc;
|
|
case 13:
|
|
return &cvExpDesc;
|
|
case 14:
|
|
return &cvToolDesc;
|
|
case 15:
|
|
return &MLRExpDesc;
|
|
case 16:
|
|
return &EBFExpDesc;
|
|
case 17:
|
|
return &lightExpDesc;
|
|
case 18:
|
|
return &erfImpDesc;
|
|
case 19:
|
|
return &missionImpDesc;
|
|
default:
|
|
return 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
void *SiteObjectClassDesc::Create(BOOL loading)
|
|
{
|
|
return new SiteObject();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
void *AnimExpClassDesc::Create(BOOL loading)
|
|
{
|
|
return new AnimExp();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
void *ErfExpClassDesc::Create(BOOL loading)
|
|
{
|
|
return new ErfExp();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
void *MLRExpClassDesc::Create(BOOL loading)
|
|
{
|
|
return new MLRExp();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
void *EBFExpClassDesc::Create(BOOL loading)
|
|
{
|
|
return new EBFExp();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
void *ArmatureExpClassDesc::Create(BOOL loading)
|
|
{
|
|
return new ArmatureExp();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
void *BatchExpClassDesc::Create(BOOL loading)
|
|
{
|
|
return new BatchExp();
|
|
}
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
void *CvObjectClassDesc::Create(BOOL loading)
|
|
{
|
|
return new CvObject();
|
|
}
|
|
|
|
void *CvExpClassDesc::Create(BOOL loading)
|
|
{
|
|
return new CvExp();
|
|
}
|
|
|
|
void *LightExpClassDesc::Create(BOOL loading)
|
|
{
|
|
return new LightExp();
|
|
}
|
|
|
|
void *ErfImpClassDesc::Create(BOOL loading)
|
|
{
|
|
return new ErfImp();
|
|
}
|
|
|
|
void *MissionImpClassDesc::Create(BOOL loading)
|
|
{
|
|
return new MissionImp();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
TCHAR *GetString(int id)
|
|
{
|
|
static TCHAR buf[256];
|
|
|
|
if (hInstance)
|
|
return LoadString(hInstance, id, buf, sizeof(buf)) ? buf : NULL;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// MAX API Version
|
|
DLLEXPORT ULONG LibVersion ()
|
|
{
|
|
return (VERSION_3DSMAX);
|
|
}
|
|
|
|
//===========================================================================//
|
|
|
|
DWORD WINAPI fn(LPVOID arg) {
|
|
return(0);
|
|
}
|
|
|
|
|
|
//===========================================================================//
|
|
|
|
void __stdcall GetGameOSEnvironment(char* CommandLine)
|
|
{
|
|
//
|
|
//----------------------------------------------------------
|
|
// This is where to set GOS environment settings.
|
|
//----------------------------------------------------------
|
|
//
|
|
Environment.applicationName = "AnimationSuite";
|
|
Environment.screenWidth = 640;
|
|
Environment.screenHeight = 480;
|
|
Environment.bitDepth = 16;
|
|
}
|
|
|
|
HWND EnableQuickFile(Interface *ip,HWND hWnd)
|
|
{
|
|
//Display the plugin's Rollup Dialog
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
HINSTANCE loc_hInstance = AfxGetResourceHandle ();
|
|
|
|
HWND hRet = ip->AddRollupPage(loc_hInstance, MAKEINTRESOURCE(IDD_QUICKFILE_PANEL),
|
|
QuickFileProc, _T("Quick File"),(LPARAM)hWnd);
|
|
|
|
|
|
char szKey[100] = "SOFTWARE\\Autodesk\\3D Studio MAX\\Plugins\\QuickFile";
|
|
HKEY hKey;
|
|
if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE,szKey,&hKey))
|
|
{
|
|
DWORD wType = REG_SZ;
|
|
char szValue[100];
|
|
BYTE *pData = (BYTE *)szValue;
|
|
DWORD size = 100;
|
|
RegQueryValueEx(hKey,"Enabled",0,&wType,(BYTE *)szValue,&size);
|
|
|
|
// Disable the drop down
|
|
if ('0' == szValue[0])
|
|
{
|
|
IRollupWindow *pRoll = ip->GetCommandPanelRollup();
|
|
pRoll->SetPanelOpen(pRoll->GetNumPanels()-1,false);
|
|
}
|
|
size = 100;
|
|
RegQueryValueEx(hKey,"NumFiles",0,&wType,(BYTE *)szValue,&size);
|
|
|
|
int maxfiles;
|
|
sscanf(szValue,"%d",&maxfiles);
|
|
for (int x=0;x<maxfiles;x++)
|
|
{
|
|
char szKey[100];
|
|
size = 100;
|
|
sprintf(szKey,"%d",x);
|
|
RegQueryValueEx(hKey,szKey,0,&wType,(BYTE *)szValue,&size);
|
|
|
|
char fname[20];
|
|
_splitpath((LPCTSTR)szValue,NULL,NULL,fname,NULL);
|
|
if (LB_ERR == SendDlgItemMessage(hRet,IDC_QUICKFILE_LISTBOX,LB_FINDSTRINGEXACT,0,(LPARAM)fname))
|
|
{
|
|
char *psz = strdup((LPCTSTR)szValue);
|
|
int index = SendDlgItemMessage(hRet,IDC_QUICKFILE_LISTBOX,LB_ADDSTRING,0,(LPARAM)fname);
|
|
SendDlgItemMessage(hRet,IDC_QUICKFILE_LISTBOX,LB_SETITEMDATA,index,(LPARAM)psz);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IRollupWindow *pRoll = ip->GetCommandPanelRollup();
|
|
pRoll->SetPanelOpen(pRoll->GetNumPanels()-1,false);
|
|
}
|
|
return hRet;
|
|
}
|
|
|
|
void DisableQuickFile(Interface * ip,HWND hWnd)
|
|
{
|
|
char szKey[100] = "SOFTWARE\\Autodesk\\3D Studio MAX\\Plugins\\QuickFile";
|
|
HKEY hKey;
|
|
RegCreateKey(HKEY_LOCAL_MACHINE,szKey,&hKey);
|
|
|
|
IRollupWindow *pRoll = ip->GetCommandPanelRollup();
|
|
char *strOpen = pRoll->IsPanelOpen(pRoll->GetNumPanels()-1)?"1":"0";
|
|
|
|
RegSetValueEx(hKey,"Enabled",0,REG_SZ,(BYTE *)strOpen,strlen(strOpen));
|
|
|
|
char szValue[MAX_PATH];
|
|
int count = SendDlgItemMessage(hWnd,IDC_QUICKFILE_LISTBOX,LB_GETCOUNT,0,0);
|
|
sprintf(szValue,"%d",count);
|
|
RegSetValueEx(hKey,"NumFiles",0,REG_SZ,(BYTE *)szValue,strlen(szValue));
|
|
|
|
|
|
for (int x = 0;x<count;x++)
|
|
{
|
|
//SendDlgItemMessage(hWnd,IDC_QUICKFILE_LISTBOX,LB_GETTEXT,x,(LPARAM)buf);
|
|
LPARAM lpPath = SendDlgItemMessage(hWnd,IDC_QUICKFILE_LISTBOX,LB_GETITEMDATA,x,0);
|
|
char *pPath = (char *)lpPath;
|
|
char szKey[100];
|
|
sprintf(szKey,"%d",x);
|
|
RegSetValueEx(hKey,szKey,0,REG_SZ,(BYTE *)pPath,strlen(pPath));
|
|
}
|
|
|
|
|
|
ip->DeleteRollupPage(hWnd);
|
|
}
|
|
|
|
static BOOL CALLBACK QuickFileProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
//static HWND hotherWnd = NULL;
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
switch (msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
//hotherWnd = (HWND)lParam;
|
|
SetWindowLong(GetDlgItem(hWnd,IDC_QUICKFILE_APPLY),GWL_USERDATA,lParam);
|
|
break;
|
|
}
|
|
case WM_DESTROY:
|
|
{
|
|
//hotherWnd = NULL;
|
|
break;
|
|
}
|
|
case WM_COMMAND:
|
|
{
|
|
switch (LOWORD(wParam)) //Handle Panel's controls
|
|
{
|
|
case IDC_QUICKFILE_LISTBOX:
|
|
{
|
|
switch (HIWORD(wParam))
|
|
{
|
|
case LBN_SELCHANGE:
|
|
{
|
|
HWND hListBox = (HWND)lParam;
|
|
HWND hTarget = (HWND)GetWindowLong(GetDlgItem(hWnd,IDC_QUICKFILE_APPLY),GWL_USERDATA);
|
|
SendMessage(hTarget,msg,wParam,lParam);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case IDC_QUICKFILE_ADD:
|
|
{
|
|
HWND hTarget = (HWND)GetWindowLong(GetDlgItem(hWnd,IDC_QUICKFILE_APPLY),GWL_USERDATA);
|
|
CFileDialog fd(TRUE,NULL,NULL,OFN_ALLOWMULTISELECT,"Max Files (*.max)|*.max||",CWnd::FromHandle(hTarget));
|
|
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)
|
|
{
|
|
POSITION pos = fd.GetStartPosition();
|
|
while (pos)
|
|
{
|
|
CString path = fd.GetNextPathName(pos);
|
|
char fname[20];
|
|
_splitpath((LPCTSTR)path,NULL,NULL,fname,NULL);
|
|
if (LB_ERR == SendDlgItemMessage(hWnd,IDC_QUICKFILE_LISTBOX,LB_FINDSTRINGEXACT,0,(LPARAM)fname))
|
|
{
|
|
char *psz = strdup((LPCTSTR)path);
|
|
int index = SendDlgItemMessage(hWnd,IDC_QUICKFILE_LISTBOX,LB_ADDSTRING,0,(LPARAM)fname);
|
|
SendDlgItemMessage(hWnd,IDC_QUICKFILE_LISTBOX,LB_SETITEMDATA,index,(LPARAM)psz);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case IDC_QUICKFILE_REMOVE:
|
|
{
|
|
int count = SendDlgItemMessage(hWnd,IDC_QUICKFILE_LISTBOX,LB_GETSELCOUNT,0,0);
|
|
int *items = new int[count];
|
|
int icount = SendDlgItemMessage(hWnd,IDC_QUICKFILE_LISTBOX,LB_GETSELITEMS,count,(LPARAM)items);
|
|
// Start from highest index and count down because indices may change from deletion
|
|
for (;icount;icount--)
|
|
{
|
|
char *psz = (char *)SendDlgItemMessage(hWnd,IDC_QUICKFILE_LISTBOX,LB_GETITEMDATA,icount-1,0);
|
|
if (psz)
|
|
free(psz);
|
|
SendDlgItemMessage(hWnd,IDC_QUICKFILE_LISTBOX,LB_DELETESTRING,items[icount],0);
|
|
}
|
|
delete items;
|
|
break;
|
|
}
|
|
case IDC_QUICKFILE_APPLY:
|
|
{
|
|
HWND hTarget = (HWND)GetWindowLong(GetDlgItem(hWnd,IDC_QUICKFILE_APPLY),GWL_USERDATA);
|
|
|
|
SendMessage(hTarget,WM_QUICKFILE_BEGIN,0,0);
|
|
int count = SendDlgItemMessage(hWnd,IDC_QUICKFILE_LISTBOX,LB_GETCOUNT,0,0);
|
|
char buf[100];
|
|
for (;count;count--)
|
|
{
|
|
SendDlgItemMessage(hWnd,IDC_QUICKFILE_LISTBOX,LB_GETTEXT,count-1,(LPARAM)buf);
|
|
LPARAM lpPath = SendDlgItemMessage(hWnd,IDC_QUICKFILE_LISTBOX,LB_GETITEMDATA,count-1,0);
|
|
SendMessage(hTarget,WM_QUICKFILE_APPLYFILE,(WPARAM)buf,lpPath);
|
|
}
|
|
SendMessage(hTarget,WM_QUICKFILE_END,0,0);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#define NUM_STAT_UPDATES 20
|
|
static float ErrorAmount(Point3 v1, Point3 v2)
|
|
{
|
|
return LengthSquared(v1-v2);
|
|
}
|
|
|
|
static float ErrorAmount(float v1, float v2)
|
|
{
|
|
float res = v1-v2;
|
|
return res*res;
|
|
}
|
|
|
|
static float ErrorAmount(Quat v1, Quat v2)
|
|
{
|
|
AngAxis res(v2/v1);
|
|
return res.angle * res.angle;
|
|
}
|
|
|
|
static float ErrorAmount(ScaleValue v1, ScaleValue v2)
|
|
{
|
|
return LengthSquared(v1.s-v2.s);
|
|
}
|
|
|
|
template <class T> int ReduceKeys_MW4(
|
|
Control *cont,Interval range,float thresh,TimeValue step,
|
|
KeyReduceStatus *status, T xx)
|
|
{
|
|
Interval valid;
|
|
Tab<TimeValue> times;
|
|
int i,j,offset = cont->GetKeyTimes(times,range,0);
|
|
TimeValue t;
|
|
int statUp, res;
|
|
//if (times.Count() <3) return KEYREDUCE_CONTINUE;
|
|
if (!times.Count()) return KEYREDUCE_CONTINUE;
|
|
|
|
// Init the status callback if we got one.
|
|
if (status) status->Init(times.Count()-1);
|
|
|
|
// The number of keys to process inbetween each update
|
|
statUp = times.Count()/NUM_STAT_UPDATES;
|
|
if (statUp==0) statUp = 1;
|
|
|
|
// Square the threshold.
|
|
thresh = thresh*thresh;
|
|
|
|
// Build a table of the origanal values
|
|
Tab<T> vals;
|
|
vals.SetCount((range.End()-range.Start())/step + 1);
|
|
for (t=range.Start(),i=0; t<range.End(); t+=step,i++) {
|
|
cont->GetValue(t,&vals[i],valid);
|
|
}
|
|
|
|
// Start at the last key and see if each key can be deleted.
|
|
for (i = times.Count()-1; i>=0; i--) {
|
|
//theHold.Begin();
|
|
Control *old_cont = (Control *)cont->Clone();
|
|
|
|
// Delete the key..
|
|
cont->DeleteKeyByIndex(i+offset);
|
|
|
|
// Check to see if the path is still within threshold.
|
|
BOOL ok = TRUE;
|
|
for (t=range.Start(),j=0; t<range.End(); t+=step,j++) {
|
|
T val;
|
|
cont->GetValue(t,&val,valid);
|
|
if (ErrorAmount(val,vals[j]) > thresh) {
|
|
ok = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If it was ok to delete this key, great! otherwise put it back
|
|
if (ok) {
|
|
//theHold.Accept(0);
|
|
|
|
} else {
|
|
//theHold.Cancel();
|
|
cont->Copy(old_cont);
|
|
}
|
|
delete old_cont;
|
|
|
|
// Maybe update the status
|
|
if (status && !(i%statUp)) {
|
|
switch (res = status->Progress(times.Count()-1-i)) {
|
|
case KEYREDUCE_ABORT:
|
|
case KEYREDUCE_STOP:
|
|
return res;
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
int ApplyKeyReduction_MW4(
|
|
Control *cont,Interval range,float thresh,TimeValue step,
|
|
KeyReduceStatus *status)
|
|
{
|
|
if (!cont->NumKeys()) return TRUE;
|
|
int res = KEYREDUCE_CONTINUE;
|
|
|
|
switch (cont->SuperClassID()) {
|
|
case CTRL_FLOAT_CLASS_ID:
|
|
res = ReduceKeys_MW4(cont,range,thresh,step,status,float(0));
|
|
break;
|
|
|
|
case CTRL_POSITION_CLASS_ID:
|
|
case CTRL_POINT3_CLASS_ID:
|
|
res = ReduceKeys_MW4(cont,range,thresh,step,status,Point3(0,0,0));
|
|
break;
|
|
|
|
case CTRL_ROTATION_CLASS_ID:
|
|
res = ReduceKeys_MW4(cont,range,thresh,step,status,Quat(0.0f,0.0f,0.0f,1.0f));
|
|
break;
|
|
|
|
case CTRL_SCALE_CLASS_ID:
|
|
res = ReduceKeys_MW4(cont,range,thresh,step,status,ScaleValue(Point3(1,1,1)));
|
|
break;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|