Files
firestorm/Gameleap/code/mw4/Tools/Max43DSPlugins/AnimationSuite/Replicate.cpp
T
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
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.
2026-06-24 21:28:16 -05:00

1134 lines
30 KiB
C++

/***************************************************************************
* *
* 3DS Max Test Plugin *
* *
***************************************************************************
* *
* Version : 1.0ß, March 11th, 1998 *
* *
* Written By Loic Baumann from Fatal Design, specially for Gamasutra *
* *
***************************************************************************
* *
* This Plugin demonstrates how to write a simple 3DS MAX Plugin, using MFCs *
* *
***************************************************************************/
#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 "Replicate.h"
#include "CvObject.h"
#pragma pack(push,8)
#include <dummy.h>
#pragma pack(pop)
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
ReplicatePanel g_replicatePanel;
////////////////////////////////////////////////////////////////////////////////
// PlugPanel Dialog Procedure to handle User and System Interactions
static BOOL CALLBACK ReplicatePanelProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
switch (msg) {
case WM_INITDIALOG: //Panel's extra initialization
g_replicatePanel.Init(hWnd);
break;
case WM_DESTROY: //Panel's extra destruction
g_replicatePanel.Destroy(hWnd);
break;
case WM_COMMAND :
switch (LOWORD(wParam)) { //Handle Panel's controls
case IDC_ABOUT: {
CAbout dlg;
dlg.DoModal();
break;
}
case IDC_REPLICATE: {
g_replicatePanel.Replicate();
break;
}
case IDC_BAKE: {
g_replicatePanel.Bake();
break;
}
}
break;
////////////////////////////////////////////////////////////////////////
//The following lines are not necessary for MAX2 Plugins
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MOUSEMOVE:
g_replicatePanel.m_ip->RollupMouseMessage(hWnd, msg, wParam, lParam);
break;
////////////////////////////////////////////////////////////////////////
default:
return FALSE;
}
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////
// Display the Plugin's Panel
void ReplicatePanel::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_REP_PANEL),
ReplicatePanelProc, GetString(IDS_REPLICATE_NAME),0);
}
////////////////////////////////////////////////////////////////////////////////
// Free the Plugins' Panel
void ReplicatePanel::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 ReplicatePanel::Init(HWND hWnd)
{
}
////////////////////////////////////////////////////////////////////////////////
// Panel Destruction callback
void ReplicatePanel::Destroy(HWND hWnd)
{
}
////////////////////////////////////////////////////////////////////////////////
// Called when the Optimize Button is pushed
void ReplicatePanel::Replicate()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// Notes for undo:
// all I have to do is store the new
// parent nodes pointer in the hold
// the delete is already in the hold
// cuz max is nice like that
// all I have to do is delete my creation
// and I can do that by keeping a pointer to
// the node and just delete it!
// Sticky point: Interaction between deleting
// while in restore mode, since deleting actualy
// stores the undo info? hmmm no idea.
INode* theNode;
//Display the HitByName dialog
TestHitByNameDlgCallback myCallback;
if (!m_ip->DoHitByNameDialog(&myCallback)) return;
//Get the Selected Node Table and the nodes' number
if (!myCallback.NodeTab.Count()) return;
theNode = *myCallback.NodeTab.Addr(0);
ThresholdDialog thresh_dialog;
if (thresh_dialog.DoModal() == IDOK)
{
//Display the Node's Info Dialog
// Get the threshold...
JointEditDialog edit_dialog(theNode, m_ip);
if (edit_dialog.DoModal() == IDOK)
{
theHold.SuperBegin();
// no modal this time!
// use the Max progress bar... Interface::Progressthingamagiggy
// keyframe reduction is fast enough so for now just use
// the joint count and how far it has gone.
INode *new_copy = CopyMeAndMyChildren(theNode); // the root
// copy the animation is now done in the copy routine
CopyAnimation(theNode, new_copy, &edit_dialog);
// try drawing first...
// Redraw the display
m_ip->RedrawViews(m_ip->GetTime(),REDRAW_BEGIN);
m_ip->RedrawViews(m_ip->GetTime(),REDRAW_NORMAL);
m_ip->RedrawViews(m_ip->GetTime(),REDRAW_END);
// strip the temp bones and helpers out...
StripBones(new_copy);
if (thresh_dialog.m_deleteOriginal)
{
//delete original
DeleteMeAndMyChildren(theNode);
}
int node_count = JointEditDialog::CountChildren(new_copy);
LPVOID arg = NULL;
m_ip->ProgressStart(_T("Optimizing Joints"), TRUE, fn, arg);
int current_node = 0;
OptimizeAnimation(new_copy, current_node, node_count,&edit_dialog);
m_ip->ProgressEnd();
// Move the new node over and tell it's kids to do the same.
if (thresh_dialog.m_offsetModelFlag)
{
// make sure we are not animating this...oy how emarassing
SuspendAnimate();
AnimateOff();
Matrix3 axis(MAT_IDENT);
Point3 translate(thresh_dialog.m_offsetX, thresh_dialog.m_offsetY, thresh_dialog.m_offsetZ);
new_copy->Move(0, axis, translate, FALSE, TRUE, PIV_NONE);
ResumeAnimate();
}
// Close out the undo
theHold.SuperAccept("Replicate");
// Redraw the display
m_ip->RedrawViews(m_ip->GetTime(),REDRAW_BEGIN);
m_ip->RedrawViews(m_ip->GetTime(),REDRAW_NORMAL);
m_ip->RedrawViews(m_ip->GetTime(),REDRAW_END);
}
}
}
void ReplicatePanel::DeleteMeAndMyChildren(INode *parent_node)
{
// Recursuvly Delete all the children
while (parent_node->NumberOfChildren() != 0)
{
INode *child_node = parent_node->GetChildNode(0);
assert(child_node != NULL);
DeleteMeAndMyChildren(child_node);
}
// delete me!
parent_node->Delete(m_ip->GetTime(), true);
}
INode *
ReplicatePanel::CopyMeAndMyChildren(INode *copy_node)
{
//MessageBox(NULL, copy_node->GetName(), "Just say OK", MB_OK|MB_APPLMODAL );
INode *new_node = NULL;
if (!copy_node->IsRootNode())
{
new_node = CopyNode(copy_node);
assert(new_node != NULL);
//CopyAnimation(copy_node, new_node);
}
int maxcount = copy_node->NumberOfChildren();
for (int i = 0; i < maxcount; i++)
{
INode *child_node = copy_node->GetChildNode(i);
assert(child_node != NULL);
INode *copy_child_node = CopyMeAndMyChildren(child_node);
assert(copy_child_node != NULL);
// attach the copy_child_node to new_node
if (!copy_node->IsRootNode())
{
new_node->AttachChild(copy_child_node, 1);
}
}
return new_node;
}
INode *
ReplicatePanel::CopyNode(INode *copy_node)
{
INode *new_node = NULL;
SClass_ID SCID;
Class_ID CID;
ObjectState os;
os = copy_node->EvalWorldState(m_ip->GetTime());
ViewExp *vpt = m_ip->GetViewport(NULL);
// new node = copy_node
if (os.obj)
{
SCID = os.obj->SuperClassID();
CID = os.obj->ClassID();
switch (SCID)
{
case GEOMOBJECT_CLASS_ID :
// We support this!!!
// I'm going to convert it to a mesh some day
// but right now go to a dummie with a bound the same size...
{
GeomObject* obj = (GeomObject*)os.obj;
GeomObject* cloned_obj = (GeomObject*)obj->Clone();
assert(cloned_obj != NULL);
new_node = m_ip->CreateObjectNode(cloned_obj);
// clone the refrences...
// damn this is a bitch...
// Transfer the material.. All of the other refs are copied
if (copy_node->GetMtl() != NULL)
{
new_node->SetMtl(copy_node->GetMtl());
}
// Transfer the wireframe color...
new_node->SetWireColor(copy_node->GetWireColor());
TSTR name(copy_node->GetName());
name = "_"+name;
//m_ip->MakeNameUnique(name);
new_node->SetName(name);
//Set the object offset transform
Point3 offset_trans = copy_node->GetObjOffsetPos();
Quat offset_rot_quat = copy_node->GetObjOffsetRot();
new_node->SetObjOffsetPos(offset_trans);
new_node->SetObjOffsetRot(offset_rot_quat);
// Set world transform
TimeValue t(0);
Matrix3 position = copy_node->GetNodeTM(t);
new_node->SetNodeTM(t, position);
}
break;
//case SHAPE_CLASS_ID:
// 2D Shapes not supported right now
// break;
case HELPER_CLASS_ID:
{
// copy dummies and turn Bones into dummies
// We support this!!!
// I'm going to convert it to a mesh some day
// but right now go to a dummie with a bound the same size...
// We only support bones and dummies...
if (CID == Class_ID(DUMMY_CLASS_ID,0) || CID == Class_ID(BONE_CLASS_ID, 0))
{
DummyObject *dummy = (DummyObject *)m_ip->CreateInstance(
HELPER_CLASS_ID,
Class_ID(DUMMY_CLASS_ID, 0)
);
assert(dummy != NULL);
new_node = m_ip->CreateObjectNode(dummy);
dummy->EnableDisplay();
GeomObject* obj = (GeomObject*)os.obj;
Box3 bound_box;
obj->GetLocalBoundBox(m_ip->GetTime(), copy_node, vpt, bound_box);
dummy->SetBox(bound_box);
}
if (CID == SITEOBJECT_CLASS_ID)
{
Object* obj = (Object*)os.obj;
Object* cloned_obj = (Object*)obj->Clone();
assert(cloned_obj != NULL);
new_node = m_ip->CreateObjectNode(cloned_obj);
// clone the refrences...
// damn this is a bitch...
// Transfer the material.. All of the other refs are copied
if (copy_node->GetMtl() != NULL)
{
new_node->SetMtl(copy_node->GetMtl());
}
// Transfer the wireframe color...
new_node->SetWireColor(copy_node->GetWireColor());
}
if (CID == CVOBJECT_CLASS_ID)
{
CvObject* obj = (CvObject*)os.obj;
CvObject* cloned_obj = (CvObject*)obj->Clone();
assert(cloned_obj != NULL);
new_node = m_ip->CreateObjectNode(cloned_obj);
// clone the refrences...
// damn this is a bitch...
// Transfer the material.. All of the other refs are copied
if (copy_node->GetMtl() != NULL)
{
new_node->SetMtl(copy_node->GetMtl());
}
// Transfer the wireframe color...
new_node->SetWireColor(copy_node->GetWireColor());
}
TSTR name(copy_node->GetName());
name = "_"+name;
//m_ip->MakeNameUnique(name);
new_node->SetName(name);
//Set the object offset transform
Point3 offset_trans = copy_node->GetObjOffsetPos();
Quat offset_rot_quat = copy_node->GetObjOffsetRot();
new_node->SetObjOffsetPos(offset_trans);
new_node->SetObjOffsetRot(offset_rot_quat);
// Set world transform
TimeValue t(0);
Matrix3 position = copy_node->GetNodeTM(t);
new_node->SetNodeTM(t, position);
}
break;
default:
assert(0);
break;
}
}
Verify(new_node != NULL);
// copy the pref data over...
JointEditDialog::CopyJointPrefrence(copy_node, new_node);
return new_node;
}
void
ReplicatePanel::StripBones(INode * /*parent_node*/)
{
// strip bones...
// Only strip helper if it has geometry that can sub for it and that geometry doesn't
// have it's own animation. If there is more than one geometry set directly attached to
// the bone, don't disolve the bone since it is an optimization to animate two nodes with
// one channel...Or combine the nodes, but only if they don't have animation.
// Maybe don't disolve the bones if the artist is planing on having animation on both the bones
// and the geometry attached to the bone. Is that possible to do? I'm not sure.
// Anyway. To disolve a bone, detach the geometry from the bone and attach it to it's parent
// Here is the tricky part. Redefining the animation and Transform Matrix.
// Try not to change the animation, IE: attach the geometry to the same TM as the bone TM, then
// make the object offset TM be the original objects offset transform times
// the original objects local origin!!!! =) HEHEHEHEHE
// IF not then we have to do weird stuff to the animation to make it correct again.
}
static void SetKeys(Control *control,DWORD tantype)
{
Control *con = control->GetXController();
IKeyControl *ikc = NULL;
if (con) {
ikc = GetKeyControlInterface(con);
if (ikc)
{
int maxkeys=ikc->GetNumKeys();
for (int x=0;x<maxkeys;x++)
{
IKey *key=(IKey *)new IBezFloatKey;
ikc->GetKey(x,key);
SetInTanType(key->flags,tantype);
SetOutTanType(key->flags,tantype);
ikc->SetKey(x,key);
}
}
}
con = control->GetYController();
if (con) {
ikc = GetKeyControlInterface(con);
if (ikc)
{
int maxkeys=ikc->GetNumKeys();
for (int x=0;x<maxkeys;x++)
{
IKey *key=(IKey *)new IBezFloatKey;
ikc->GetKey(x,key);
SetInTanType(key->flags,tantype);
SetOutTanType(key->flags,tantype);
ikc->SetKey(x,key);
}
}
}
con = control->GetZController();
if (con) {
ikc = GetKeyControlInterface(con);
if (ikc)
{
int maxkeys=ikc->GetNumKeys();
for (int x=0;x<maxkeys;x++)
{
IKey *key=(IKey *)new IBezFloatKey;
ikc->GetKey(x,key);
SetInTanType(key->flags,tantype);
SetOutTanType(key->flags,tantype);
ikc->SetKey(x,key);
}
}
}
}
void
ReplicatePanel::CopyAnimation(INode * source_node, INode * target_node, JointEditDialog *dialog,int converttype)
{
// Copyies controlers in order
// If the controler is procedural or this is a bone
// turn it into something we know and add the controler
// Simplify the keyframes future should ask the user which joints to optimize
// or optimize procedural/bones and anything that has a one for one rate
//afxDump << "Copying Animation : " << source_node->GetName() << "\n";
//MessageBox(NULL, source_node->GetName(), "COPY ANIM", MB_OK|MB_APPLMODAL );
// copy this anim...
//If everything is known than just clone this puppy...
JointPreference *pref = JointEditDialog::GetJointPrefrence(source_node);
if (pref)
{
Verify(pref != NULL);
Control *tm_controller = source_node->GetTMController();
int include_joint = true;
if (pref->m_excludeJoint == JointPreference::ExcludeJoint)
{
include_joint = false;
}
if (pref->m_excludeJoint == JointPreference::AutoJoint)
{
if(!dialog->NodeAnimated(source_node))
{
include_joint = false;
}
}
if (tm_controller != NULL && include_joint)
{
if (pref->m_convertRotationJoint)
{
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 *rotation_controler = NULL;
if (converttype)
{
switch(pref->m_rotationConvertType)
{
case JointPreference::LinearKeyframeType:
rotation_controler = (Control *)m_ip->CreateInstance(
CTRL_ROTATION_CLASS_ID,
Class_ID(LININTERP_ROTATION_CLASS_ID, 0)
);
break;
case JointPreference::EulerXYZKeyframeType:
rotation_controler = (Control *)m_ip->CreateInstance(
CTRL_ROTATION_CLASS_ID,
Class_ID(EULER_CONTROL_CLASS_ID, 0)
);
break;
case JointPreference::PositionXYZKeyframeType:
rotation_controler = (Control *)m_ip->CreateInstance(
CTRL_ROTATION_CLASS_ID,
Class_ID(EULER_CONTROL_CLASS_ID, 0)
);
break;
}
}
else
{
rotation_controler = (Control *)m_ip->CreateInstance(
CTRL_ROTATION_CLASS_ID,
Class_ID(EULER_CONTROL_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)
{
Quat rot;
Point3 pos;
// Get the pos and rot from the frame.
// Compute the relative TM
Matrix3 parentTM, nodeTM, localTM;
nodeTM = source_node->GetNodeTM(time_of_key);
parentTM = source_node->GetParentTM(time_of_key);
localTM = nodeTM*Inverse(parentTM);
AffineParts ap;
decomp_affine(localTM, &ap);
pos = ap.t;
rot = ap.q;
rotation_controler->SetValue(time_of_key,&rot,TRUE,CTRL_ABSOLUTE);
}
}
ResumeAnimate();
theHold.Accept(0);
Control *target_master_control;
target_master_control = target_node->GetTMController();
target_master_control->SetRotationController(rotation_controler);
SetKeys(rotation_controler,BEZKEY_LINEAR);
}
else
{
// clone the animation
// Get the source control
Control *source_master_control;
Control *source_new_rotation_control = NULL;
source_master_control = source_node->GetTMController();
source_new_rotation_control = source_master_control->GetRotationController();
assert(source_new_rotation_control != NULL);
// Clone the source to the targets
Control *target_master_control;
Control *target_new_rotation_control = NULL;
target_master_control = target_node->GetTMController();
target_new_rotation_control = (Control *)source_new_rotation_control->Clone();
// Paste them in
// The help file said I didn't have to delete the old ones, but it doesn't
// say if I should dereference them . I'm assuming, for now, that the new
// position control is being deleted by the derefrencing method ( ie, nothing
// is left looking at them so they are deleted ). But it doesn't say if I am
// the one to have to delete it. I guess they are and I don't have to.
assert(target_new_rotation_control != NULL);
target_master_control->SetRotationController(target_new_rotation_control);
}
if (pref->m_convertTranslationJoint)
{
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 PositionXYZ with a sub controler of SineWave or Noise
Control *translation_controler = NULL;
Control *posc = tm_controller->GetPositionController();
if (posc)
{
Control *c=posc->GetXController();
if (c)
Class_ID cl = c->ClassID();
Class_ID cl2 = posc->ClassID();
}
Class_ID cl1 = Class_ID(0x118f7e02,0xffee238a);
if (converttype)
{
switch(pref->m_translationConvertType)
{
case JointPreference::LinearKeyframeType:
translation_controler = (Control *)m_ip->CreateInstance(
CTRL_POSITION_CLASS_ID,
Class_ID(LININTERP_POSITION_CLASS_ID, 0)
);
break;
case JointPreference::EulerXYZKeyframeType:
translation_controler =
(Control *)m_ip->CreateInstance(
CTRL_POSITION_CLASS_ID,
cl1
);
break;
case JointPreference::PositionXYZKeyframeType:
//translation_controler = NewDefaultPoint3Controller();
translation_controler = (Control *)m_ip->CreateInstance(
CTRL_POSITION_CLASS_ID,
cl1
);
break;
}
}
else
{
translation_controler =
(Control *)m_ip->CreateInstance(
CTRL_POSITION_CLASS_ID,
cl1);
}
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)
{
Quat rot;
Point3 pos;
// Get the pos and rot from the frame.
// Compute the relative TM
Matrix3 parentTM, nodeTM, localTM;
nodeTM = source_node->GetNodeTM(time_of_key);
parentTM = source_node->GetParentTM(time_of_key);
localTM = nodeTM*Inverse(parentTM);
AffineParts ap;
decomp_affine(localTM, &ap);
pos = ap.t;
rot = ap.q;
translation_controler->SetValue(time_of_key,&pos,TRUE,CTRL_ABSOLUTE);
}
}
ResumeAnimate();
theHold.Accept(0);
Control *target_master_control;
target_master_control = target_node->GetTMController();
target_master_control->SetPositionController(translation_controler);
SetKeys(translation_controler,BEZKEY_LINEAR);
}
else
{
// clone the animation
// Get the source control
Control *source_master_control;
Control *source_new_position_control = NULL;
source_master_control = source_node->GetTMController();
source_new_position_control = source_master_control->GetPositionController();
assert(source_new_position_control != NULL);
// Clone the source to the targets
Control *target_master_control;
Control *target_new_position_control = NULL;
target_master_control = target_node->GetTMController();
target_new_position_control = (Control *)source_new_position_control->Clone();
// Paste them in
// The help file said I didn't have to delete the old ones, but it doesn't
// say if I should dereference them . I'm assuming, for now, that the new
// position control is being deleted by the derefrencing method ( ie, nothing
// is left looking at them so they are deleted ). But it doesn't say if I am
// the one to have to delete it. I guess they are and I don't have to.
assert(target_new_position_control != NULL);
target_master_control->SetPositionController(target_new_position_control);
}
}
}
// do my children..
assert(source_node->NumberOfChildren() == target_node->NumberOfChildren());
for (int i = 0; i < source_node->NumberOfChildren(); i++)
{
INode *child_node_source = source_node->GetChildNode(i);
assert(child_node_source != NULL);
INode *child_node_target = target_node->GetChildNode(i);
assert(child_node_target != NULL);
CopyAnimation(child_node_source, child_node_target, dialog,converttype);
}
}
////////////////////////////////////////////////////////////////////////////////
void
ReplicatePanel::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 = JointEditDialog::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);
RepReduceStatus 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);
RepReduceStatus 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;
}
static void FixNames(INode *pNode)
{
CString str = pNode->GetName();
if ('_' == str[0])
{
str.Delete(0,1);
pNode->SetName((char *)(LPCTSTR)str);
}
for (int x=0;x<pNode->NumberOfChildren();x++)
{
INode *pChild = pNode->GetChildNode(x);
FixNames(pChild);
}
}
void ReplicatePanel::Bake()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
INode* theNode =m_ip->GetRootNode();
// ThresholdDialog thresh_dialog;
// if (thresh_dialog.DoModal() == IDOK)
{
//Display the Node's Info Dialog
// Get the threshold...
// JointEditDialog edit_dialog(theNode, m_ip);
// if (edit_dialog.DoModal() == IDOK)
{
theHold.SuperBegin();
// no modal this time!
// use the Max progress bar... Interface::Progressthingamagiggy
// keyframe reduction is fast enough so for now just use
// the joint count and how far it has gone.
int count = theNode->NumberOfChildren();
for (int x=0;x<count;x++)
{
INode *pChild = theNode->GetChildNode(x);
JointEditDialog edit_dialog(theNode, m_ip);
edit_dialog.AddJointPreference(pChild);
INode *new_copy = CopyMeAndMyChildren(pChild); // the root
// copy the animation is now done in the copy routine
//CopyAnimation(theNode, new_copy, &edit_dialog);
CopyAnimation(pChild, new_copy, &edit_dialog,0);
// try drawing first...
// Redraw the display
m_ip->RedrawViews(m_ip->GetTime(),REDRAW_BEGIN);
m_ip->RedrawViews(m_ip->GetTime(),REDRAW_NORMAL);
m_ip->RedrawViews(m_ip->GetTime(),REDRAW_END);
// strip the temp bones and helpers out...
StripBones(new_copy);
// if (thresh_dialog.deleteOriginal)
{
//delete original
DeleteMeAndMyChildren(pChild);
}
FixNames(new_copy);
}
// TODO: Rename the nodes to get the names right
// Move the new node over and tell it's kids to do the same.
/*
if (thresh_dialog.offsetModelFlag)
{
// make sure we are not animating this...oy how emarassing
SuspendAnimate();
AnimateOff();
Matrix3 axis(MAT_IDENT);
Point3 translate(thresh_dialog.offsetX, thresh_dialog.offsetY, thresh_dialog.offsetZ);
new_copy->Move(0, axis, translate, FALSE, TRUE, PIV_NONE);
ResumeAnimate();
}
*/
// Close out the undo
theHold.SuperAccept("Replicate");
// Redraw the display
m_ip->RedrawViews(m_ip->GetTime(),REDRAW_BEGIN);
m_ip->RedrawViews(m_ip->GetTime(),REDRAW_NORMAL);
m_ip->RedrawViews(m_ip->GetTime(),REDRAW_END);
}
}
}