//===========================================================================// // 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 #include 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; }