| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027 |
- /*
- ** Command & Conquer Renegade(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /* $Header: /Commando/Code/Tools/max2w3d/motion.cpp 26 10/30/00 6:56p Greg_h $ */
- /***********************************************************************************************
- *** Confidential - Westwood Studios ***
- ***********************************************************************************************
- * *
- * Project Name : Commando Tools - W3D export *
- * *
- * $Archive:: /Commando/Code/Tools/max2w3d/motion.cpp $*
- * *
- * $Author:: Greg_h $*
- * *
- * $Modtime:: 10/30/00 5:25p $*
- * *
- * $Revision:: 26 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * MotionClass::MotionClass -- constructor *
- * MotionClass::MotionClass -- constructor *
- * MotionClass::init -- initialize *
- * MotionClass::~MotionClass -- destructor *
- * MotionClass::compute_frame_motion -- compute the motion for a specified frame *
- * MotionClass::set_motion_matrix -- save a motin matrix *
- * MotionClass::get_motion_matrix -- retrieve a motion matrix *
- * MotionClass::set_eulers -- store euler angles *
- * MotionClass::get_eulers -- retrieve euler angles *
- * MotionClass::Save -- save the motion to a W3D file *
- * MotionClass::save_header -- save the header *
- * MotionClass::save_channels -- save the motion channels *
- * MotionClass::set_visibility -- store a visibility bit *
- * MotionClass::get_visibility -- retrieve the visibility bit for this node:frame *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "motion.h"
- #include "w3d_file.h"
- #include "vchannel.h"
- #include "bchannel.h"
- #include "euler.h"
- #include "util.h"
- #include "errclass.h"
- #include "w3dutil.h"
- #include "exportlog.h"
- /***********************************************************************************************
- * MotionClass::MotionClass -- constructor *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/26/1997 GH : Created. *
- *=============================================================================================*/
- MotionClass::MotionClass
- (
- IScene * scene,
- INode * rootnode,
- HierarchySaveClass * basepose,
- W3dExportOptionsStruct & options,
- int framerate,
- Progress_Meter_Class * meter,
- HWND MaxHwnd,
- char * name,
- Matrix3 & offset
- ):
- BasePose(basepose),
- Scene(scene),
- RootNode(rootnode),
- RootList(NULL),
- StartFrame(options.StartFrame),
- EndFrame(options.EndFrame),
- ReduceAnimation(options.ReduceAnimation),
- ReduceAnimationPercent(options.ReduceAnimationPercent),
- CompressAnimation(options.CompressAnimation),
- CompressAnimationFlavor(options.CompressAnimationFlavor),
- CompressAnimationTranslationError(options.CompressAnimationTranslationError),
- CompressAnimationRotationError(options.CompressAnimationRotationError),
- FrameRate(framerate),
- Meter(meter),
- Offset(offset)
- {
-
- ExportLog::printf("Initializing Capture....\n");
-
- init();
- Set_W3D_Name(Name,name);
- }
- /***********************************************************************************************
- * MotionClass::MotionClass -- constructor *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/26/1997 GH : Created. *
- *=============================================================================================*/
- MotionClass::MotionClass
- (
- IScene * scene,
- INodeListClass * rootlist,
- HierarchySaveClass * basepose,
- W3dExportOptionsStruct & options,
- int framerate,
- Progress_Meter_Class * meter,
- HWND MaxHwnd,
- char * name,
- Matrix3 & offset
- ):
- BasePose(basepose),
- Scene(scene),
- RootNode(NULL),
- RootList(rootlist),
- StartFrame(options.StartFrame),
- EndFrame(options.EndFrame),
- ReduceAnimation(options.ReduceAnimation),
- ReduceAnimationPercent(options.ReduceAnimationPercent),
- CompressAnimation(options.CompressAnimation),
- CompressAnimationFlavor(options.CompressAnimationFlavor),
- CompressAnimationTranslationError(options.CompressAnimationTranslationError),
- CompressAnimationRotationError(options.CompressAnimationRotationError),
- FrameRate(framerate),
- Meter(meter),
- Offset(offset)
- {
-
- ExportLog::printf("Initializing Capture....\n");
- init();
-
- Set_W3D_Name(Name,name);
- }
- /***********************************************************************************************
- * MotionClass::init -- initialize *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/26/1997 GH : Created. *
- *=============================================================================================*/
- void MotionClass::init(void)
- {
- int i,j;
- NumFrames = (EndFrame - StartFrame + 1);
- ExportLog::printf("Extracting %d frames of animation from Max\n", NumFrames);
- ExportLog::printf("\n");
- /*
- ** Allocate space for a matrix per frame per node
- ** and an XYZEulers per frame per node.
- */
- MotionMatrix = new Matrix3 * [BasePose->Num_Nodes()];
- if (MotionMatrix == NULL) {
- throw (ErrorClass("Out of Memory"));
- }
- EulerDelta = new Point3 * [BasePose->Num_Nodes()];
- if (EulerDelta == NULL) {
- throw (ErrorClass("Out of Memory"));
- }
-
- for (i=0; i<BasePose->Num_Nodes(); i++) {
- MotionMatrix[i] = new Matrix3[NumFrames];
- if (MotionMatrix[i] == NULL) {
- throw (ErrorClass("Out of Memory"));
- }
-
- /*
- ** Initialize all of the matrices to identity.
- */
- for (j=0; j<NumFrames; j++) {
- MotionMatrix[i][j] = Matrix3(1);
- }
- }
- for (i=0; i<BasePose->Num_Nodes(); i++) {
- EulerDelta[i] = new Point3[NumFrames];
- if (EulerDelta[i] == NULL) {
- throw (ErrorClass("Out of Memory"));
- }
- /*
- ** Initialize all of the Euler angles to 0,0,0
- */
- for (j=0; j<NumFrames; j++) {
- EulerDelta[i][j] = Point3(0,0,0);
- }
- }
- /*
- ** allocate boolean vectors for the visiblity data
- */
- VisData = new BooleanVectorClass[BasePose->Num_Nodes()];
- for (i=0; i<BasePose->Num_Nodes(); i++) {
- VisData[i].Resize(NumFrames);
- /*
- ** initialize to always visible
- */
- for (j=0; j<NumFrames; j++) {
- VisData[i][j] = true;
- }
- }
- //
- // allocate boolean vectors for movement data
- //
- BinMoveData = new BooleanVectorClass[BasePose->Num_Nodes()];
- for (i=0; i<BasePose->Num_Nodes(); i++) {
- BinMoveData[i].Resize(NumFrames);
- /*
- ** initialize to always interpolate
- */
- for (j=0; j<NumFrames; j++) {
- BinMoveData[i][j] = false;
- }
- }
- /*
- ** Allocate a bit for each node in the base pose. These
- ** bits indicate whether the node actually appeared in the
- ** scene. If the bit is zero after all of the animation
- ** has been processed, the node can be ignored.
- */
- NodeValidFlags.Resize(BasePose->Num_Nodes());
- for (i=0; i<BasePose->Num_Nodes(); i++) {
- NodeValidFlags[i] = 0;
- }
- /*
- ** Compute motion data for each frame
- */
- for (i=0; i < NumFrames; i++) {
- ExportLog::rprintf("( %d ) ", i);
- ExportLog::updatebar(i, NumFrames);
- compute_frame_motion(i);
- }
- ExportLog::updatebar(1, 1); // 100%
- ExportLog::rprintf("Extraction Complete.\n");
- }
- /***********************************************************************************************
- * MotionClass::~MotionClass -- destructor *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/26/1997 GH : Created. *
- *=============================================================================================*/
- MotionClass::~MotionClass(void)
- {
- int i;
- for (i=0; i<BasePose->Num_Nodes(); i++) {
- if (MotionMatrix[i]) delete[] MotionMatrix[i];
- }
- if (MotionMatrix) {
- delete[] MotionMatrix;
- }
- for (i=0; i<BasePose->Num_Nodes(); i++) {
- if (EulerDelta[i]) delete[] EulerDelta[i];
- }
- if (EulerDelta) {
- delete[] EulerDelta;
- }
- if (VisData) {
- delete[] VisData;
- }
- if (BinMoveData) {
- delete[] BinMoveData;
- }
-
- ExportLog::printf("Destroy Log..%d,%d,%d,%d, %s..\n",1,2,3,4,"go");
- }
- /***********************************************************************************************
- * MotionClass::compute_frame_motion -- compute the motion for a specified frame *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/26/1997 GH : Created. *
- *=============================================================================================*/
- void MotionClass::compute_frame_motion(int frame)
- {
- /*
- ** Compute MAX's time value for this frame
- ** NOTE: the frame index passed in is the offset from StartFrame
- ** to get the original MAX frame number, we add StartFrame.
- */
- TimeValue frametime = (StartFrame + frame) * GetTicksPerFrame();
-
- /*
- ** Create a hierarchy tree object for the scene at this frame
- */
- HierarchySaveClass * tree;
- if (RootNode != NULL) {
- tree = new HierarchySaveClass(RootNode,frametime,*Meter,"NoName",false,BasePose);
- } else {
- tree = new HierarchySaveClass(RootList,frametime,*Meter,"NoName",false,BasePose,Offset);
- }
-
- if (tree == NULL) {
- throw (ErrorClass("Out of memory!"));
- }
- /*
- ** Loop over each node in this frame's tree
- */
- for (int tindex=0; tindex<tree->Num_Nodes(); tindex++) {
- /*
- ** Find the node in the Base Pose corresponding to this node.
- ** If this node is not in the base pose, skip
- */
- int bindex = BasePose->Find_Named_Node(tree->Get_Node_Name(tindex));
- if (bindex != -1) {
- /*
- ** Get the relative transform from the base and from
- ** this frame's tree. Assume that both have already been "fixed";
- ** obviously the base pose has... However, the current tree
- ** needs to be built by passing the basepose in as the "fixup tree"
- **
- ** What are the "fixup" matrices? These are the transforms which
- ** were applied to the base pose when the user wanted to force the
- ** base pose to use only matrices with certain properties. For
- ** example, if we wanted the base pose to use translations only,
- ** the fixup transform for each node is a transform which when
- ** multiplied by the real node's world transform, yeilds a pure
- ** translation matrix. Fixup matrices also show up in the mesh
- ** exporter since all vertices must be transformed by their inverses
- ** in order to make things work...
- */
- Matrix3 basetm = BasePose->Get_Node_Relative_Transform(bindex);
- Matrix3 thistm = tree->Get_Node_Relative_Transform(tindex);
- INode *tree_node = tree->Get_Node(tindex);
-
- Matrix3 motion = thistm * Inverse(basetm);
- motion = Cleanup_Orthogonal_Matrix(motion);
- set_motion_matrix(bindex,frame,motion);
- /*
- ** Also, store the Euler angles for this node
- */
- EulerAnglesClass my_eulers(motion,EulerOrderXYZr);
- float ex = my_eulers.Get_Angle(0);
- float ey = my_eulers.Get_Angle(1);
- float ez = my_eulers.Get_Angle(2);
- set_eulers(bindex,frame,ex,ey,ez);
- /*
- ** Store the visibility bit for this node
- */
- INode * node = tree->Get_Node(tindex);
- bool vis;
- if (node) {
- vis = (node->GetVisibility(frametime) > 0.0f);
- } else {
- vis = 1;
- }
- set_visibility(bindex,frame,vis);
- //
- // Store out binary move or not
- //
- bool binary_move = false;
-
- if ((node)&&(vis)) {
-
- if (frame != 0) {
- // sample previous frame, and an inbetween time
- // to determine if there's a binary movement
- TimeValue frametime_prev = frametime - GetTicksPerFrame();
- TimeValue frametime_mid = (frametime + frametime_prev) / 2;
- // if data at frametime_prev == data at frametime_mid and != data at frametime
- // then we have a binary movement!
-
- Control *c;
-
- c = node->GetTMController()->GetPositionController();
-
- if (c) {
- Interval iValid;
-
- Matrix3 smat1; // sample matrix 1
- Matrix3 smat2; // sample matrix 2
- Matrix3 smat3; // sample matrix 3
-
- iValid = FOREVER;
- smat1 = node->GetParentTM(frametime_prev);
- c->GetValue(frametime_prev, &smat1, iValid, CTRL_RELATIVE);
-
- iValid = FOREVER;
- smat2 = node->GetParentTM(frametime_mid);
- c->GetValue(frametime_mid, &smat2, iValid, CTRL_RELATIVE);
-
- iValid = FOREVER;
- smat3 = node->GetParentTM(frametime);
- c->GetValue(frametime, &smat3, iValid, CTRL_RELATIVE);
-
- if ((smat1 == smat2) && (!(smat2 == smat3))) {
- binary_move = true;
- DebugPrint(_T("Binary Move on Translation\n"));
- }
-
- if (false == binary_move) {
- c = node->GetTMController()->GetRotationController();
-
- if (c) {
- iValid = FOREVER;
- smat1 = node->GetParentTM(frametime_prev);
- c->GetValue(frametime_prev, &smat1, iValid, CTRL_RELATIVE);
-
- iValid = FOREVER;
- smat2 = node->GetParentTM(frametime_mid);
- c->GetValue(frametime_mid, &smat2, iValid, CTRL_RELATIVE);
-
- iValid = FOREVER;
- smat3 = node->GetParentTM(frametime);
- c->GetValue(frametime, &smat3, iValid, CTRL_RELATIVE);
-
- if ((smat1 == smat2) && (!(smat2 == smat3))) {
- binary_move = true;
- DebugPrint(_T("Binary Move on Rotation\n"));
- }
- }
- }
- }
- }
- }
-
-
- set_binary_movement(bindex, frame, binary_move);
-
- } // if(bindex!=-1)
- }
- /*
- ** release allocated memory
- */
- delete tree;
- }
- /***********************************************************************************************
- * MotionClass::set_motion_matrix -- store a motion matrix *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/26/1997 GH : Created. *
- *=============================================================================================*/
- void MotionClass::set_motion_matrix(int node,int frame,const Matrix3 & motion)
- {
- assert(node >= 0);
- assert(frame >= 0);
- assert(node < BasePose->Num_Nodes());
- assert(frame < NumFrames);
- MotionMatrix[node][frame] = motion;
- NodeValidFlags[node] = 1;
- }
- /***********************************************************************************************
- * MotionClass::get_motion_matrix -- retrieve a motion matrix *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/26/1997 GH : Created. *
- *=============================================================================================*/
- Matrix3 MotionClass::get_motion_matrix(int node,int frame)
- {
- assert(node >= 0);
- assert(frame >= 0);
- assert(node < BasePose->Num_Nodes());
- assert(frame < NumFrames);
- return MotionMatrix[node][frame];
- }
- /***********************************************************************************************
- * MotionClass::set_eulers -- store euler angles *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/26/1997 GH : Created. *
- *=============================================================================================*/
- void MotionClass::set_eulers(int node,int frame, float x, float y, float z)
- {
- /*
- ** if we're past the first frame, massage the euler angles to the
- ** representation closest to the previous frame.
- */
- if (frame > 0) {
- /*
- ** First, compute equivalent euler angles
- */
- double x2 = PI + x;
- double y2 = PI - y;
- double z2 = PI + z;
-
- if (x2 > PI) {
- x2 = x2 - 2*PI;
- }
- if (y2 > PI) {
- y2 = y2 - 2*PI;
- }
- if (z2 > PI) {
- z2 = z2 - 2*PI;
- }
- /*
- ** load up the previous frame eulers
- */
- double px,py,pz;
- px = get_eulers(node,frame - 1)[0];
- py = get_eulers(node,frame - 1)[1];
- pz = get_eulers(node,frame - 1)[2];
- // now, pick between the two
- double mag0 = (x - px) * (x - px) + (y - py) * (y - py) + (z - pz) * (z - pz);
- double mag1 = (x2 - px) * (x2 - px) + (y2 - py) * (y2 - py) + (z2 - pz) * (z2 - pz);
- if (mag1 < mag0) {
- x = x2;
- y = y2;
- z = z2;
- }
- }
-
- EulerDelta[node][frame].x = x;
- EulerDelta[node][frame].y = y;
- EulerDelta[node][frame].z = z;
- NodeValidFlags[node] = 1;
- }
- /***********************************************************************************************
- * MotionClass::get_eulers -- retrieve euler angles *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/26/1997 GH : Created. *
- *=============================================================================================*/
- Point3 MotionClass::get_eulers(int node,int frame)
- {
- return Point3(
- EulerDelta[node][frame].x,
- EulerDelta[node][frame].y,
- EulerDelta[node][frame].z
- );
- }
- /***********************************************************************************************
- * MotionClass::set_visibility -- store a visibility bit *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 1/15/98 GTH : Created. *
- *=============================================================================================*/
- void MotionClass::set_visibility(int node,int frame,bool visible)
- {
- VisData[node][frame] = visible;
- NodeValidFlags[node] = 1;
- }
- /***********************************************************************************************
- * MotionClass::get_visibility -- retrieve the visibility bit for this node:frame *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 1/15/98 GTH : Created. *
- *=============================================================================================*/
- bool MotionClass::get_visibility(int node,int frame)
- {
- return VisData[node][frame];
- }
- /***********************************************************************************************
- * MotionClass::set_binary_movement -- store a binary movement bit *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 1/15/98 GTH : Created. *
- *=============================================================================================*/
- void MotionClass::set_binary_movement(int node,int frame,bool visible)
- {
- BinMoveData[node][frame] = visible;
- //NodeValidFlags[node] = 1;
- }
- /***********************************************************************************************
- * MotionClass::get_visibility -- retrieve the movement bit for this node:frame *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 1/15/98 GTH : Created. *
- *=============================================================================================*/
- bool MotionClass::get_binary_movement(int node,int frame)
- {
- return BinMoveData[node][frame];
- }
- /***********************************************************************************************
- * MotionClass::Save -- save the motion to a W3D file *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/26/1997 GH : Created. *
- *=============================================================================================*/
- bool MotionClass::Save(ChunkSaveClass & csave)
- {
- uint32 chunk_anim_type = W3D_CHUNK_ANIMATION;
- ExportLog::printf("\nBegin Save Motion Data\n");
- if (CompressAnimation) {
- chunk_anim_type = W3D_CHUNK_COMPRESSED_ANIMATION;
- }
- if (!csave.Begin_Chunk( chunk_anim_type )) {
- return false;
- }
- if (!save_header(csave)) {
- return false;
- }
- if (!save_channels(csave)) {
- return false;
- }
- if (!csave.End_Chunk()) {
- return false;
- }
-
- return true;
- }
- /***********************************************************************************************
- * MotionClass::save_header -- save the header *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/26/1997 GH : Created. *
- *=============================================================================================*/
- bool MotionClass::save_header(ChunkSaveClass & csave)
- {
- ExportLog::printf("Save Header Type: ");
- if (CompressAnimation) {
- // New Compressed Style
- if (!csave.Begin_Chunk(W3D_CHUNK_COMPRESSED_ANIMATION_HEADER)) {
- return false;
- }
- W3dCompressedAnimHeaderStruct aheader;
- aheader.Version = W3D_CURRENT_COMPRESSED_HANIM_VERSION;
- Set_W3D_Name(aheader.Name,Name);
- Set_W3D_Name(aheader.HierarchyName,BasePose->Get_Name());
- aheader.NumFrames = NumFrames;
- aheader.FrameRate = FrameRate;
- aheader.Flavor = CompressAnimationFlavor; // for future expansion
-
- switch (CompressAnimationFlavor) {
-
- case ANIM_FLAVOR_TIMECODED:
- ExportLog::printf("TimeCoded\n");
- break;
- case ANIM_FLAVOR_ADAPTIVE_DELTA:
- ExportLog::printf("Adaptive Delta\n");
- break;
- default:
- ExportLog::printf("UNKNOWN\n");
- break;
- }
- if (csave.Write(&aheader,sizeof(aheader)) != sizeof(aheader)) {
- return false;
- }
- if (!csave.End_Chunk()) {
- return false;
- }
- }
- else {
-
- ExportLog::printf("Non-Compressed.\n");
- // Classic Non-Compressed Style
- if (!csave.Begin_Chunk(W3D_CHUNK_ANIMATION_HEADER)) {
- return false;
- }
- W3dAnimHeaderStruct aheader;
- aheader.Version = W3D_CURRENT_HANIM_VERSION;
- Set_W3D_Name(aheader.Name,Name);
- Set_W3D_Name(aheader.HierarchyName,BasePose->Get_Name());
- aheader.NumFrames = NumFrames;
- aheader.FrameRate = FrameRate;
-
- if (csave.Write(&aheader,sizeof(aheader)) != sizeof(aheader)) {
- return false;
- }
- if (!csave.End_Chunk()) {
- return false;
- }
- }
-
- return true;
- }
- /***********************************************************************************************
- * MotionClass::save_channels -- save the motion channels *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/26/1997 GH : Created. *
- *=============================================================================================*/
- bool MotionClass::save_channels(ChunkSaveClass & csave)
- {
- int NumNodes = BasePose->Num_Nodes();
- ExportLog::printf("\nSaving Channel Data for %d Nodes\n", NumNodes);
- for (int nodeidx = 0; nodeidx < BasePose->Num_Nodes(); nodeidx++) {
- ExportLog::printf("\nnode: %d ", nodeidx);
- /*
- ** Just ignore this node if it didn't appear in the max scene.
- */
- if (NodeValidFlags[nodeidx]) {
-
- float identity[] = { 0.0f,0.0f,0.0f,1.0f };
- VectorChannelClass xchan (nodeidx, NumFrames, ANIM_CHANNEL_X, 1, identity);
- VectorChannelClass ychan (nodeidx, NumFrames, ANIM_CHANNEL_Y, 1, identity);
- VectorChannelClass zchan (nodeidx, NumFrames, ANIM_CHANNEL_Z, 1, identity);
- VectorChannelClass xrchan(nodeidx, NumFrames, ANIM_CHANNEL_XR, 1, identity);
- VectorChannelClass yrchan(nodeidx, NumFrames, ANIM_CHANNEL_YR, 1, identity);
- VectorChannelClass zrchan(nodeidx, NumFrames, ANIM_CHANNEL_ZR, 1, identity);
- VectorChannelClass qchan (nodeidx, NumFrames, ANIM_CHANNEL_Q, 4, identity);
- xchan.SetSaveOptions(CompressAnimation, CompressAnimationFlavor, CompressAnimationTranslationError, CompressAnimationRotationError, ReduceAnimation, ReduceAnimationPercent);
- ychan.SetSaveOptions(CompressAnimation, CompressAnimationFlavor, CompressAnimationTranslationError, CompressAnimationRotationError, ReduceAnimation, ReduceAnimationPercent);
- zchan.SetSaveOptions(CompressAnimation, CompressAnimationFlavor, CompressAnimationTranslationError, CompressAnimationRotationError, ReduceAnimation, ReduceAnimationPercent);
- xrchan.SetSaveOptions(CompressAnimation, CompressAnimationFlavor, CompressAnimationTranslationError, CompressAnimationRotationError, ReduceAnimation, ReduceAnimationPercent);
- yrchan.SetSaveOptions(CompressAnimation, CompressAnimationFlavor, CompressAnimationTranslationError, CompressAnimationRotationError, ReduceAnimation, ReduceAnimationPercent);
- zrchan.SetSaveOptions(CompressAnimation, CompressAnimationFlavor, CompressAnimationTranslationError, CompressAnimationRotationError, ReduceAnimation, ReduceAnimationPercent);
- qchan.SetSaveOptions(CompressAnimation, CompressAnimationFlavor, CompressAnimationTranslationError, CompressAnimationRotationError, ReduceAnimation, ReduceAnimationPercent);
- BitChannelClass vischan(nodeidx, NumFrames, BIT_CHANNEL_VIS, 1);
- vischan.Set_Bits(VisData[nodeidx]);
- BitChannelClass binmovechan(nodeidx, NumFrames, 0, 0);
- binmovechan.Set_Bits(BinMoveData[nodeidx]);
- for (int frameidx = 0; frameidx < NumFrames; frameidx++) {
- float vec[4];
- Matrix3 tm = get_motion_matrix(nodeidx,frameidx);
- Point3 eulers = get_eulers(nodeidx,frameidx);
- Point3 old_tran = tm.GetTrans();
- Quat old_rot(tm);
-
- Point3 tran;
- Point3 scale;
- Quat rot;
- DecomposeMatrix(tm,tran,rot,scale);
- /*
- ** fixup the quaternion - max's quaternions are different than mine(?)
- */
- rot[0] = -rot[0];
- rot[1] = -rot[1];
- rot[2] = -rot[2];
- rot[3] = rot[3];
- /*
- ** Build the x translation channel
- */
- vec[0] = tran.x;
- xchan.Set_Vector(frameidx,vec);
- /*
- ** Build the y translation channel
- */
- vec[0] = tran.y;
- ychan.Set_Vector(frameidx,vec);
- /*
- ** Build the z translation channel
- */
- vec[0] = tran.z;
- zchan.Set_Vector(frameidx,vec);
- /*
- ** Build the x rotation channel
- */
- vec[0] = eulers.x;
- xrchan.Set_Vector(frameidx,vec);
- /*
- ** Build the y rotation channel
- */
- vec[0] = eulers.y;
- yrchan.Set_Vector(frameidx,vec);
- /*
- ** Build the z rotation channel
- */
- vec[0] = eulers.z;
- zrchan.Set_Vector(frameidx,vec);
- /*
- ** Build the quaternion rotation channel
- */
- vec[0] = rot[0];
- vec[1] = rot[1];
- vec[2] = rot[2];
- vec[3] = rot[3];
- qchan.Set_Vector(frameidx,vec);
- /*
- ** build the visibility channel
- */
- vischan.Set_Bit(frameidx,get_visibility(nodeidx,frameidx));
- //
- // build binarymovement channel
- //
- binmovechan.Set_Bit(frameidx, get_binary_movement(nodeidx, frameidx));
- }
-
- // If objects arn't visible, then the channel data may as well be empty
- if (!vischan.Is_Empty()) {
- if (!xchan.Is_Empty()) xchan.ClearInvisibleData(&vischan);
- if (!ychan.Is_Empty()) ychan.ClearInvisibleData(&vischan);
- if (!zchan.Is_Empty()) zchan.ClearInvisibleData(&vischan);
- if (!qchan.Is_Empty()) qchan.ClearInvisibleData(&vischan);
- }
- if (!xchan.Is_Empty()) {
- ExportLog::printf("x");
- xchan.Save(csave, &binmovechan );
- }
- if (!ychan.Is_Empty()) {
- ExportLog::printf("y");
- ychan.Save(csave, &binmovechan );
- }
- if (!zchan.Is_Empty()) {
- ExportLog::printf("z");
- zchan.Save(csave, &binmovechan );
- }
- // (gth) not saving Euler angles any more since we don't use them
- // if (!xrchan.Is_Empty()) xrchan.Save(csave);
- // if (!yrchan.Is_Empty()) yrchan.Save(csave);
- // if (!zrchan.Is_Empty()) zrchan.Save(csave);
- if (!qchan.Is_Empty()) {
- ExportLog::printf("q");
- qchan.Save(csave, &binmovechan);
- }
- if (!vischan.Is_Empty()) {
- ExportLog::printf("v");
- vischan.Save(csave, CompressAnimation);
- }
- }
- ExportLog::updatebar(nodeidx ,NumNodes);
- }
- ExportLog::updatebar(1,1);
- ExportLog::printf("\n\nSave Channel Data Complete.\n");
- return true;
- }
- // EOF - motion.cpp
|