Files
firestorm/Gameleap/code/mw4/Code/MW4/AnimFormat.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

608 lines
15 KiB
C++

//===========================================================================//
// File: AnimFormat.cpp
// Project: MechWarrior 4
// Contents:
// This is the base animation player source file.
// This file defines Keyframes and Animation Player classes
// PLEASE NOTE!!!! THIS FILE IS USED BY THE PLUGIN :
// 3dsplugins/AnimationExport
// If you change this you must also change the plugin!!!!
//
// THIS IS A THREAT!
// All the animations that have been exported rely on this format
// If you change this format, you better know what you are doing!
// If you don't support multiple versions when you change this
// Then you HAVE TO EXPORT ALL THE ANIMATIONS AGAIN!!!!!
// The max plugin environment allows for this.
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// 07/01/98 JSE Initial coding,
//---------------------------------------------------------------------------//
// Copyright (C) 1998, Fasa Interactive, Inc.
// All Rights reserved worldwide
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL
//===========================================================================//
#include <MW4\MW4AnimationSystem.hpp>
#include <Adept\Resource.hpp>
using namespace MW4Animation;
//
//#############################################################################
//#############################################################################
//
AnimData::AnimData()
{
startOfBlocks = NULL;
animHeaderBlock = NULL;
animJointBlock = NULL;
animNameBlock = NULL;
animKeyTimeBlock = NULL;
animKeyBlock = NULL;
animChannelBlock = NULL;
animHeaderBlockSize = 0;
animJointBlockSize = 0;
animKeyTimeBlockSize = 0;
animKeyBlockSize = 0;
animNameBlockSize = 0;
animChannelBlockSize = 0;
}
AnimData::~AnimData()
{
// I don't actually delete any of the extra arrays.
// The reason is that it is allocated as one LARGE piece
// of memory. I do, however register the memory as a
// "precaution"
if (animKeyBlock != NULL)
{
Unregister_Pointer(animKeyBlock);
// delete[] animKeyBlock;
}
if (animKeyTimeBlock != NULL)
{
Unregister_Pointer(animKeyTimeBlock);
// delete[] animKeyTimeBlock;
}
if (animChannelBlock != NULL)
{
Unregister_Pointer(animChannelBlock);
// delete[] animChannelBlock;
}
if (animNameBlock != NULL)
{
Unregister_Pointer(animNameBlock);
// delete[] animNameBlock;
}
if (animJointBlock != NULL)
{
Unregister_Pointer(animJointBlock);
// delete[] animJointBlock;
}
if (animHeaderBlock != NULL)
{
Unregister_Pointer(animHeaderBlock);
// delete animHeaderBlock;
}
if (startOfBlocks != NULL)
{
Unregister_Pointer(startOfBlocks);
delete[] startOfBlocks;
}
}
//
//#############################################################################
//#############################################################################
//
bool AnimData::Save(const char *file_name)
{
Stuff::FileStream file_stream(file_name, Stuff::FileStream::WriteOnly);
Save(&file_stream);
return true;
}
//
//#############################################################################
//#############################################################################
//
bool AnimData::Load(const char *file_name)
{
Stuff::FileStream file_stream(file_name);
if (!Load(&file_stream))
{
SPEW((0, "Anim is corrupt or wrong format : "));
SPEW((0, file_name));
return false;
}
return true;
}
//
//#############################################################################
//#############################################################################
//
bool AnimData::Load(Adept::Resource *resource)
{
resource->LoadData();
resource->AdvancePointer(sizeof(BYTE));
AnimHeader temp_header_block;
resource->ReadBytes(&temp_header_block, sizeof(AnimHeader));
resource->RewindPointer(sizeof(BYTE) + sizeof(AnimHeader));
if (temp_header_block.majorVersion == MAJOR_ANIM_VERSION_1_0 && temp_header_block.minorVersion == MINOR_ANIM_VERSION_1_0)
{
return Load_1_0((Stuff::MemoryStream*)resource);
}
if (temp_header_block.majorVersion == MAJOR_ANIM_VERSION_2_0 && temp_header_block.minorVersion == MINOR_ANIM_VERSION_2_0)
{
return Load_2_0((Stuff::MemoryStream*)resource);
}
if (temp_header_block.majorVersion == MAJOR_ANIM_VERSION_2_1 && temp_header_block.minorVersion == MINOR_ANIM_VERSION_2_1)
{
return Load_2_1((Stuff::MemoryStream*)resource);
}
return false;
}
//
//#############################################################################
//#############################################################################
//
bool AnimData::Save(Stuff::FileStream *stream)
{
return Save((Stuff::MemoryStream*)stream);
}
//
//#############################################################################
//#############################################################################
//
bool AnimData::Load(Stuff::FileStream *stream)
{
return CopyAndLoad(stream);
}
//
//#############################################################################
//#############################################################################
//
bool AnimData::CopyAndLoad(Stuff::MemoryStream *stream)
{
// copy the file into a memory chunk and make a stream out of it.
// then pass it to the load function.
// skip the null byte and get the header
// we are getting the header since this format can
// be munged together inside of a bigger file
// still try to verify this is a good file
stream->AdvancePointer(sizeof(BYTE));
AnimHeader temp_header_block;
stream->ReadBytes(&temp_header_block, sizeof(AnimHeader));
stream->RewindPointer(sizeof(BYTE) + sizeof(AnimHeader));
if (temp_header_block.majorVersion == MAJOR_ANIM_VERSION_1_0 && temp_header_block.minorVersion == MINOR_ANIM_VERSION_1_0)
{
// since it is a file and it will be closed we are going to buffer it
// to memory
gos_PushCurrentHeap(g_AnimDataHeap);
startOfBlocks = new BYTE[temp_header_block.totalSizeOfAnimation + 1];
Register_Pointer(startOfBlocks);
gos_PopCurrentHeap();
Stuff::MemoryStream mem_stream(startOfBlocks, temp_header_block.totalSizeOfAnimation + 1);
stream->ReadBytes(mem_stream.GetPointer(), temp_header_block.totalSizeOfAnimation);
return Load_1_0(&mem_stream);
}
if (temp_header_block.majorVersion == MAJOR_ANIM_VERSION_2_0 && temp_header_block.minorVersion == MINOR_ANIM_VERSION_2_0)
{
// since it is a file and it will be closed we are going to buffer it
// to memory
gos_PushCurrentHeap(g_AnimDataHeap);
startOfBlocks = new BYTE[temp_header_block.totalSizeOfAnimation + 1];
Register_Pointer(startOfBlocks);
gos_PopCurrentHeap();
Stuff::MemoryStream mem_stream(startOfBlocks, temp_header_block.totalSizeOfAnimation + 1);
stream->ReadBytes(mem_stream.GetPointer(), temp_header_block.totalSizeOfAnimation);
return Load_2_0(&mem_stream);
}
if (temp_header_block.majorVersion == MAJOR_ANIM_VERSION_2_1 && temp_header_block.minorVersion == MINOR_ANIM_VERSION_2_1)
{
// since it is a file and it will be closed we are going to buffer it
// to memory
gos_PushCurrentHeap(g_AnimDataHeap);
startOfBlocks = new BYTE[temp_header_block.totalSizeOfAnimation + 1];
Register_Pointer(startOfBlocks);
gos_PopCurrentHeap();
Stuff::MemoryStream mem_stream(startOfBlocks, temp_header_block.totalSizeOfAnimation + 1);
stream->ReadBytes(mem_stream.GetPointer(), temp_header_block.totalSizeOfAnimation);
return Load_2_1(&mem_stream);
}
return false;
}
//
//#############################################################################
//#############################################################################
//
bool AnimData::Save(Stuff::MemoryStream *stream)
{
BYTE null_byte = NULL;
stream->WriteBytes(&null_byte, sizeof(BYTE));
// write the rest of the data out
Verify(animHeaderBlock->offsetToHeaderBlock == stream->GetBytesUsed()-1);
stream->WriteBytes(animHeaderBlock,animHeaderBlockSize);
Verify(animHeaderBlock->offsetToJointBlock == stream->GetBytesUsed()-1);
stream->WriteBytes(animJointBlock,animJointBlockSize);
Verify(animHeaderBlock->offsetToNameBlock == stream->GetBytesUsed()-1);
stream->WriteBytes(animNameBlock,animNameBlockSize);
Verify(animHeaderBlock->offsetToKeyBlock == stream->GetBytesUsed()-1);
stream->WriteBytes(animKeyBlock,animKeyBlockSize);
Verify(animHeaderBlock->offsetToKeyTimeBlock == stream->GetBytesUsed()-1);
stream->WriteBytes(animKeyTimeBlock, animKeyTimeBlockSize);
Verify(animHeaderBlock->offsetToChannelBlock == stream->GetBytesUsed()-1);
stream->WriteBytes(animChannelBlock,animChannelBlockSize);
return true;
}
//#############################################################################
//#############################################################################
//
bool AnimData::Load_2_1(Stuff::MemoryStream *stream)
{
// skip the null byte
BYTE *null_byte;
null_byte = (BYTE *)stream->GetPointer();
if (*null_byte != NULL)
{
return false;
}
Verify(*null_byte == NULL);
stream->AdvancePointer(sizeof(BYTE));
size_t start_index = stream->GetIndex();
// load the header
animHeaderBlock = (AnimHeader *)stream->GetPointer();
Register_Pointer(animHeaderBlock);
if (animHeaderBlock->majorVersion != MAJOR_ANIM_VERSION_2_1)
{
return false;
}
if (animHeaderBlock->minorVersion != MINOR_ANIM_VERSION_2_1)
{
return false;
}
Verify(
(animHeaderBlock->offsetToJointBlock - animHeaderBlock->offsetToHeaderBlock)
== sizeof(AnimHeader)
);
Verify(animHeaderBlock->majorVersion == MAJOR_ANIM_VERSION_2_1);
Verify(animHeaderBlock->minorVersion == MINOR_ANIM_VERSION_2_1);
// register the rest of the arrays
stream->SetPointer(animHeaderBlock->offsetToJointBlock + start_index);
animJointBlock = (JointAnimData *)stream->GetPointer();
Register_Pointer(animJointBlock);
stream->SetPointer(animHeaderBlock->offsetToNameBlock + start_index);
animNameBlock = (char *)stream->GetPointer();
Register_Pointer(animNameBlock);
stream->SetPointer(animHeaderBlock->offsetToKeyBlock + start_index);
animKeyBlock = (void *)stream->GetPointer();
Register_Pointer(animKeyBlock);
stream->SetPointer(animHeaderBlock->offsetToKeyTimeBlock + start_index);
animKeyTimeBlock = (void *)stream->GetPointer();
Register_Pointer(animKeyTimeBlock);
stream->SetPointer(animHeaderBlock->offsetToChannelBlock + start_index);
animChannelBlock = (ChannelAnimData *)stream->GetPointer();
Register_Pointer(animChannelBlock);
stream->SetPointer(animHeaderBlock->totalSizeOfAnimation + start_index);
animHeaderBlockSize = animHeaderBlock->offsetToJointBlock - start_index;
animJointBlockSize = animHeaderBlock->offsetToNameBlock - animHeaderBlock->offsetToJointBlock;
animNameBlockSize = animHeaderBlock->offsetToKeyBlock - animHeaderBlock->offsetToNameBlock;
animKeyBlockSize = animHeaderBlock->offsetToKeyTimeBlock - animHeaderBlock->offsetToKeyBlock;
animKeyTimeBlockSize = animHeaderBlock->offsetToChannelBlock - animHeaderBlock->offsetToKeyTimeBlock;
animChannelBlockSize = animHeaderBlock->totalSizeOfAnimation - animHeaderBlock->offsetToChannelBlock;
// check that keyframe counts are lower than 256
#ifdef _ARMOR
int count = GetChannelCount();
for (int i = 0; i < count; ++i)
{
Verify(animChannelBlock[i].keyframeCount < AnimIterator::MaxKeyFrame);
}
#endif
return true;
}
//
//#############################################################################
//#############################################################################
//
bool AnimData::Load_1_0(Stuff::MemoryStream *stream)
{
// skip the null byte
BYTE *null_byte;
null_byte = (BYTE *)stream->GetPointer();
if (*null_byte != NULL)
{
return false;
}
Verify(*null_byte == NULL);
stream->AdvancePointer(sizeof(BYTE));
// load the header
animHeaderBlock = (AnimHeader *)stream->GetPointer();
Register_Pointer(animHeaderBlock);
if (animHeaderBlock->majorVersion != MAJOR_ANIM_VERSION_1_0)
{
return false;
}
if (animHeaderBlock->minorVersion != MINOR_ANIM_VERSION_1_0)
{
return false;
}
STOP (("Animformat 1.0 Not Supported"));
return false;
}
//
//#############################################################################
//#############################################################################
//
bool AnimData::Load_2_0(Stuff::MemoryStream *stream)
{
// skip the null byte
BYTE *null_byte;
null_byte = (BYTE *)stream->GetPointer();
if (*null_byte != NULL)
{
return false;
}
Verify(*null_byte == NULL);
stream->AdvancePointer(sizeof(BYTE));
// load the header
animHeaderBlock = (AnimHeader *)stream->GetPointer();
Register_Pointer(animHeaderBlock);
if (animHeaderBlock->majorVersion != MAJOR_ANIM_VERSION_1_0)
{
return false;
}
if (animHeaderBlock->minorVersion != MINOR_ANIM_VERSION_1_0)
{
return false;
}
STOP (("Animformat 2.0 Not Supported"));
return false;
}
//
//#############################################################################
//#############################################################################
//
char *Joint_Name_Compression_Table[COMPRESS_JOINT_COUNT] =
{
"joint_cage",
"joint_centertorsofront",
"joint_centertorsorear",
"joint_head",
"joint_hip",
"joint_hipabove",
"joint_hipbelow",
"joint_lankle",
"joint_lbelowankle",
"joint_lbtoe",
"joint_ldleg",
"joint_lefttorsofront",
"joint_lfoot",
"joint_lftoe",
"joint_lgun",
"joint_lgunabove",
"joint_litoe",
"joint_lmissile",
"joint_lmleg",
"joint_lotoe",
"joint_ltoe",
"joint_luarm",
"joint_luleg",
"joint_rankle",
"joint_rbelowankle",
"joint_rbtoe",
"joint_rdleg",
"joint_rfoot",
"joint_rftoe",
"joint_rgun",
"joint_rgunabove",
"joint_righttorsofront",
"joint_ritoe",
"joint_rmissile",
"joint_rmleg",
"joint_root",
"joint_rotoe",
"joint_rtoe",
"joint_ruarm",
"joint_ruleg",
"joint_specialone",
"joint_specialtwo",
"joint_torso",
"joint_torsoabove",
"joint_torsobelow",
"joint_vel",
"joint_world"
};
int MW4Animation::CompressName(const char *source, Stuff::MString &dest)
{
for (BYTE i = 0; i < COMPRESS_JOINT_COUNT; ++i)
{
if (!stricmp(source, Joint_Name_Compression_Table[i]))
{
BYTE index = (BYTE)(128 + i);
dest = "#";
dest += (char)index;
dest += "\0";
return i;
}
}
dest = source;
return -1;
}
int MW4Animation::UncompressName(const char *source, Stuff::MString &dest)
{
const char *test = source;
if (*test == '#')
{
++test;
BYTE index = (BYTE)*test;
index -= (BYTE)128;
dest = Joint_Name_Compression_Table[index];
return index;
}
dest = source;
return -1;
}