Files
BT411/engine/MUNGA/JMOVER.cpp
T
arcattackandClaude Opus 4.8 7b7d465e5e Initial commit: bt411 -- standalone Windows BattleTech (Tesla 4.10 port)
Clean, self-contained extraction of the BattleTech-specific work from the
reverse-engineering workspace -- engine + game + content + build, with nothing
from Red Planet or the raw archive dumps. Builds green (Win32) and runs the
single-player drive->animate->target->fire->damage->destroy loop out of the box.

Layout:
  engine/   MUNGA + MUNGA_L4 shared 2007 engine, carrying our BT render/loader
            work (bgfload/L4D3D/L4VIDEO: BSL bit-slice decode, LOD/ground/shadow
            models) + image codec; the minimal rp/ headers the audio HAL needs
  game/     reconstructed BT logic + surviving-original BT source + fwd shims
            + WinMain launcher
  content/  full runtime tree (BTL4.RES, VIDEO/, GAUGE/, AUDIO/, eggs, BTDPL.INI)
  docs/     format specs + reconstruction ledgers
  reference/ raw Ghidra pseudocode (recon source-of-truth) + decomp exporter
  tools/    MP console emulator + map/resource scanners

One top-level CMake builds munga_engine lib + bt410_l4 game lib + btl4.exe.
All paths relativized (186 fwd shims + ~437 CMake abs paths -> repo-relative);
DXSDK is the one external, overridable via -DDXSDK. Verified: builds to a
byte-identical 2.27MB exe and runs combat (TARGET DESTROYED, 0 crashes) against
the bundled content.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 21:03:40 -05:00

2045 lines
47 KiB
C++

#include "munga.h"
#pragma hdrstop
#include "jmover.h"
#include "fileutil.h"
#include "app.h"
#include "notation.h"
#include "namelist.h"
//#############################################################################
//############################ JointedMover #############################
//#############################################################################
//#############################################################################
// Shared Data Support
//
Derivation* JointedMover::GetClassDerivations()
{ static Derivation classDerivations(Mover::GetClassDerivations(), "JointedMover");
return &classDerivations;
}
JointedMover::SharedData
JointedMover::DefaultData(
JointedMover::GetClassDerivations(),
JointedMover::GetMessageHandlers(),
JointedMover::GetAttributeIndex(),
JointedMover::StateCount,
(Entity::MakeHandler)JointedMover::Make
);
//#############################################################################
// Attribute Support
//
const JointedMover::IndexEntry
JointedMover::AttributePointers[]=
{
{
JointedMover::SegmentCountAttributeID,
"SegmentCount",
(Simulation::AttributePointer)&JointedMover::segmentCount
},
{
JointedMover::SegmentTableAttributeID,
"SegmentTable",
(Simulation::AttributePointer)&JointedMover::segmentTable
},
{
JointedMover::JointSubsystemAttributeID,
"JointSubsystem",
(Simulation::AttributePointer)&JointedMover::jointSubsystem
}
};
JointedMover::AttributeIndexSet& JointedMover::GetAttributeIndex()
{
static JointedMover::AttributeIndexSet attributeIndex(ELEMENTS(JointedMover::AttributePointers),
JointedMover::AttributePointers,
Mover::GetAttributeIndex()
);
return attributeIndex;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
EntitySegment*
JointedMover::GetSegment(CString segment_name)
{
Check(this);
Check_Pointer(segment_name);
EntitySegment::SegmentTableIterator iterator(segmentTable);
EntitySegment *current_segment;
while( (current_segment = iterator.ReadAndNext() ) != NULL)
{
if(segment_name.Compare(current_segment->GetName()) == 0)
{
return current_segment;
}
}
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
EntitySegment*
JointedMover::GetSegmentFromDamageZone(CString damage_zone)
{
EntitySegment::SegmentTableIterator iterator(segmentTable);
EntitySegment *current_segment;
while ((current_segment = iterator.ReadAndNext() ) != NULL)
{
EntitySegment::IntegerTableIterator *damage_iterator;
damage_iterator = current_segment->MakeDamageZoneIndexTable();
Register_Object(damage_iterator);
EntitySegment::IntegerPlug *index_plug;
while ((index_plug = damage_iterator->ReadAndNext() ) != NULL)
{
CString current_name;
Verify(index_plug->GetItem() >= 0);
Verify(index_plug->GetItem() <= damageZoneCount);
current_name = damageZones[index_plug->GetItem()]->damageZoneName;
Check_Pointer(&current_name);
if(current_name.Compare(damage_zone) == 0)
{
Unregister_Object(damage_iterator);
delete damage_iterator;
return current_segment;
}
}
Unregister_Object(damage_iterator);
delete damage_iterator;
}
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
JointedMover::GetSegmentToWorld(
EntitySegment &my_segment,
LinearMatrix *transform
)
{
Check(this);
JointSubsystem *joints = GetJointSubsystem();
Check(joints);
//
//---------------------------------------------------------------
// Check to see if the segment transforms need to be recalculated
//---------------------------------------------------------------
//
if (joints->AreJointsModified())
{
EntitySegment::SegmentTableIterator iterator(segmentTable);
EntitySegment *current_segment;
while( (current_segment = iterator.ReadAndNext() ) != NULL)
{
current_segment->ModifySegment();
}
joints->ModifyJoints(False);
}
//
//-----------------------------
// Compute the actual transform
//-----------------------------
//
transform->Multiply(
my_segment.GetSegmentToEntity(),
localToWorld
);
Check_Fpu();
}
//#############################################################################
// Construction and Destruction
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
JointedMover::JointedMover(
JointedMover::MakeMessage *creation_message,
JointedMover::SharedData &virtual_data
):
Mover(creation_message, virtual_data),
jointSubsystem(NULL),
segmentTable(this, True)
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create the JointSubsystem
//~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
JointSubsystem *joint_subsystem = new JointSubsystem(
(Entity*) this,
Entity::EntitySubsystemID
);
Register_Object(joint_subsystem);
jointSubsystem.Add(joint_subsystem);
Check(joint_subsystem);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Get Resource Description
//~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceDescription *skl_resource =
application->GetResourceFile()->SearchList(
creation_message->resourceID,
ResourceDescription::SkeletonStreamResourceType
);
Check(skl_resource);
skl_resource->Lock();
DynamicMemoryStream segment_stream(
skl_resource->resourceAddress,
skl_resource->resourceSize);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// read in segmentCount and jointCount
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int joint_count;
segment_stream >> segmentCount >> joint_count;
int current_joint_type;
int current_joint_index = 0;
CString segment_name;
EntitySegment *parent_segment;
EntitySegment *current_segment;
int segment_joint_index;
Joint *segment_joint_pointer;
int parent_index;
CString video_object_name;
LinearMatrix segment_offset(LinearMatrix::Identity);
Logical site_segment;
int ii;
for(ii=0;ii<segmentCount;ii++)
{
//
//~~~~~~~~~~~~~~~~~~
// Read segment name
//~~~~~~~~~~~~~~~~~~
//
segment_stream >> segment_name >> parent_index;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// read parent index & find parentSegment ptr
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
if(parent_index == -1)
{
parent_segment = NULL;
}
else
{
EntitySegment::SegmentTableIterator iterator(segmentTable);
parent_segment = iterator.GetNth(parent_index);
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Determine if this segment is a site
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
segment_stream >> site_segment >> current_joint_type;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Get the joint type & init the joint
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
if(current_joint_type != Joint::NULLJointType)
{
segment_joint_index = current_joint_index;
segment_joint_pointer =
new Joint(
joint_subsystem,
(Joint::JointType)current_joint_type
);
Register_Object(segment_joint_pointer);
joint_subsystem->AddJoint(current_joint_index, segment_joint_pointer);
++current_joint_index;
}
else
{
segment_joint_pointer = NULL;
segment_joint_index = -1;
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Read in the segment offset matrix
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
segment_stream >> segment_offset;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Get The Primary Damage Zone
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int primary_dzone_index;
segment_stream >> primary_dzone_index;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create this segment and add
// add it to the segment table
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
current_segment = new EntitySegment(
segment_name,
ii, // my_index
parent_index,
segment_joint_index,
segment_joint_pointer,
segment_offset,
parent_segment,
site_segment,
primary_dzone_index
);
Register_Object(current_segment);
segmentTable.AddValue(current_segment, ii);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Read in ALL VideoObjectNames
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int video_object_count;
EntitySegment::SkeletonType skl_type;
segment_stream >> video_object_count;
Verify(video_object_count);
int jj;
for(jj=0;jj<video_object_count;++jj)
{
segment_stream >> skl_type >> video_object_name;
if(video_object_name.Compare("None"))
{
current_segment->AddVideoObjectName(
video_object_name,
skl_type,
DamageZone::ExistsGraphicState
);
}
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Read in ALL DESTROYED VideoObjectNames
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int destroyed_video_object_count;
segment_stream >> destroyed_video_object_count;
for(jj=0;jj<destroyed_video_object_count;++jj)
{
segment_stream >> skl_type >> video_object_name;
if(video_object_name.Compare("None"))
{
current_segment->AddVideoObjectName(
video_object_name,
skl_type,
DamageZone::DestroyedGraphicState
);
}
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Read in DamageZone information
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int damage_zone_count;
int damage_zone_index;
segment_stream >> damage_zone_count;
if(damage_zone_count)
{
for(int dd=0;dd<damage_zone_count;++dd)
{
segment_stream >> damage_zone_index;
current_segment->AddDamageZone(damage_zone_index, dd);
}
}
//
// Read in the Children Information
//
int children_count;
int child_index;
segment_stream >> children_count;
if(children_count)
{
for(int jj=0;jj<children_count;++jj)
{
segment_stream >> child_index;
current_segment->AddChildIndex(child_index, jj);
}
}
}
skl_resource->Unlock();
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Initialize all the child Pointers for each segment
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
for(ii=0;ii<segmentCount;++ii)
{
EntitySegment::SegmentTableIterator iterator(segmentTable);
InitializeChildPointers(iterator.GetNth(ii));
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
JointedMover::InitializeChildPointers(EntitySegment *current_segment)
{
EntitySegment::IntegerTableIterator *iterator;
EntitySegment::SegmentTableIterator segment_iterator(segmentTable);
iterator = current_segment->MakeChildIndexTable();
Register_Object(iterator);
EntitySegment::IntegerPlug *current_index;
int child_count=0;
while((current_index = iterator->ReadAndNext()) != NULL)
{
EntitySegment *child_segment;
child_segment = segment_iterator.GetNth(current_index->GetItem());
Check(child_segment);
current_segment->AddChildPointer(child_segment, child_count);
++child_count;
}
Unregister_Object(iterator);
delete iterator;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
JointedMover::~JointedMover()
{
EntitySegment::SegmentTableIterator iterator(segmentTable);
iterator.DeletePlugs();
//
//---------------------------------------------------------------------
// This should be deleted by the entity subsystemArray[jointSubsystem]
//---------------------------------------------------------------------
//
#if 0
JointSubsystem *joint_subsystem = jointSubsystem.GetCurrent();
Unregister_Object(joint_subsystem);
delete joint_subsystem;
#endif
}
//########################################################################
// DamageZone Support
//
ResourceDescription::ResourceID
JointedMover::CreateDamageZoneStream(
ResourceFile *resource_file,
const char *model_name,
NotationFile *model_file,
const ResourceDirectories *directories
)
{
Check(resource_file);
Check_Pointer(model_name);
Check(model_file);
Check_Pointer(directories);
//
//-------------------
// Find the .skl file
//-------------------
//
const char* skl_entry;
if (
!model_file->GetEntry(
"video",
"skeleton",
&skl_entry
)
)
{
DEBUG_STREAM << model_name << " is missing .skl file specification!\n" << std::flush;
return -1;
}
char *skl_filename =
MakePathedFilename(directories->videoDirectory, skl_entry);
Register_Pointer(skl_filename);
NotationFile *skl_file = new NotationFile(skl_filename);
Register_Object(skl_file);
if (!skl_file->PageCount())
{
DEBUG_STREAM << skl_filename << " is empty or missing!\n" << std::flush;
Dump_And_Die_1:
Unregister_Pointer(skl_filename);
delete[] skl_filename;
Unregister_Object(skl_file);
delete skl_file;
return ResourceDescription::NullResourceID;
}
//
//-------------------
// Find the .dmg file
//-------------------
//
const char* dmg_entry;
if (
!model_file->GetEntry(
"gamedata",
"DamageZones",
&dmg_entry
)
)
{
DEBUG_STREAM << model_name << " is missing .dmg file specification!\n" << std::flush;
goto Dump_And_Die_1;
}
char *dmg_filename =
MakePathedFilename(directories->modelDirectory, dmg_entry);
Register_Pointer(dmg_filename);
NotationFile *dmg_file = new NotationFile(dmg_filename);
Register_Object(dmg_file);
if (!dmg_file->PageCount())
{
DEBUG_STREAM << dmg_filename << " is empty or missing!\n" << std::flush;
Dump_And_Die_2:
Unregister_Pointer(dmg_filename);
delete[] dmg_filename;
Unregister_Object(dmg_file);
delete dmg_file;
goto Dump_And_Die_1;
}
//
// Get the number of Damage zones
//
int dzone_count;
if (
!skl_file->GetEntry(
"ROOT",
"DZoneCount",
&dzone_count
)
)
{
DEBUG_STREAM << model_name << " is missing DZoneCount \n" << std::flush;
goto Dump_And_Die_2;
}
DynamicMemoryStream damage_zone_stream;
//
// write the Damage Zone Count Info from the
// .dmg file to the stream
//
damage_zone_stream << dzone_count;
//
// Make an entry list of all the entries in the damage zone page
//
NameList *dzone_namelist =
skl_file->MakeEntryList("DamageZones","dz_");
Register_Object(dzone_namelist);
if (dzone_namelist->EntryCount() == 0)
{
DEBUG_STREAM << "No dZones listed in DamageZones Page"<<std::endl << std::flush;
Dump_And_Die:
Unregister_Pointer(skl_filename);
delete skl_filename;
Unregister_Object(skl_file);
delete skl_file;
Unregister_Pointer(dmg_filename);
delete dmg_filename;
Unregister_Object(dmg_file);
delete dmg_file;
return -1;
}
NameList::Entry *dzone_entry;
char current_dzone_name[32];
int num_dzones_found = 0;
dzone_entry = dzone_namelist->GetFirstEntry();
while (dzone_entry)
{
++num_dzones_found;
//
// Get dzone name in .skl file
//
Str_Copy(
current_dzone_name,
dzone_entry->GetName(),
sizeof(current_dzone_name)
);
//
// Create the stream for this damage zone
//
DamageZone::CreateStreamedDamageZone(
model_file,
model_name,
skl_file,
current_dzone_name,
&damage_zone_stream,
dmg_file,
directories
);
//
// Get next dzone entry in this segment page
//
dzone_entry = dzone_entry->GetNextEntry();
} // End while more dzone_entries
if(dzone_count != num_dzones_found)
{
DEBUG_STREAM <<"DZoneCount != damage zones found in Page DamageZones"<<std::endl << std::flush;
goto Dump_And_Die;
}
//
//--------------------------------------------------------------------
// Write the stream out to disk. Size is equal to the byte difference
// between stream and damage zone buffer
//--------------------------------------------------------------------
//
ResourceDescription *new_res =
resource_file->AddResourceMemoryStream(
model_name,
ResourceDescription::DamageZoneStreamResourceType,
1,
ResourceDescription::Preload,
&damage_zone_stream
);
Check(new_res);
//
// Free mem
//
Unregister_Pointer(skl_filename);
delete skl_filename;
Unregister_Object(skl_file);
delete skl_file;
Unregister_Pointer(dmg_filename);
delete dmg_filename;
Unregister_Object(dmg_file);
delete dmg_file;
Unregister_Object(dzone_namelist);
delete dzone_namelist;
return new_res->resourceID;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceDescription::ResourceID
JointedMover::CreateSkeletonStream(
ResourceFile *resource_file,
const char *model_name,
NotationFile *model_file,
const ResourceDirectories *directories
)
{
Check_Pointer(model_name);
Check(model_file);
Check_Pointer(directories);
//
//-------------------
// Find the .skl file
//-------------------
//
const char *entry_data;
if (
!model_file->GetEntry(
"video",
"skeleton",
&entry_data
)
)
{
DEBUG_STREAM << model_name << " is missing .skl file specification!\n" << std::flush;
return -1;
}
//
// Get the name of the SKL File
//
char *filename = MakePathedFilename(directories->videoDirectory, entry_data);
Register_Pointer(filename);
//
// Create a Notation file from the skl ASCII File
//
NotationFile *skl_file = new NotationFile(filename);
Register_Object(skl_file);
//
// Get number of Segments(or Pages)
//
int segment_count = skl_file->PageCount();
//
// Do not count Lab_Only and DamageZones they are not included
//
if (skl_file->PageExists("LAB_ONLY"))
--segment_count;
if(skl_file->PageExists("DamageZones"))
--segment_count;
if (!segment_count)
{
DEBUG_STREAM << model_name << " has no Segments!\n" << std::flush;
Dump_And_Die:
Unregister_Pointer(filename);
delete filename;
Unregister_Object(skl_file);
delete skl_file;
return -1;
}
int joint_count;
if (
!skl_file->GetEntry(
"ROOT",
"JointCount",
&joint_count
)
)
{
DEBUG_STREAM << model_name << " is missing JointCount \n" << std::flush;
goto Dump_And_Die;
}
DynamicMemoryStream segment_stream;
//
// Write Segment Count to the stream
//
segment_stream << segment_count << joint_count;
//
// Create a list of the pages and get the first entry
//
NameList *segment_namelist = skl_file->MakePageList();
Register_Object(segment_namelist);
NameList::Entry *segment_entry = segment_namelist->GetFirstEntry();
int
parent_index = -1,
children_count;
CString
segment_page_name;
EulerAngles
rotation;
Point3D
translation;
LinearMatrix
base_offset(LinearMatrix::Identity);
while(segment_entry)
{
segment_page_name = segment_entry->GetName();
if(
(strcmp(segment_page_name, "LAB_ONLY") == 0) ||
(strcmp(segment_page_name,"DamageZones") ==0)
)
{
segment_entry = segment_entry->GetNextEntry();
continue;
}
segment_stream << segment_page_name;
//
// Get the information about the parent
//
const char *parent_name;
if(
skl_file->GetEntry(
segment_page_name,
"parent",
&parent_name
)
)
{
parent_index = GetSegmentIndex(parent_name, skl_file);
if(parent_index == -1)
{
DEBUG_STREAM<<model_file<<":"<<parent_name<<" Not Found!"<<std::endl << std::flush;
goto Dump_And_Die;
}
}
segment_stream << parent_index;
//
// Get the joint Type, NULL Joint Type (-1) if no joint
//
const char *joint_name;
int joint_type = Joint::NULLJointType;
Logical is_site(False);
if(!skl_file->GetEntry(
segment_page_name,
"Type",
&joint_name)
)
{
if( strcmp("ROOT", segment_page_name) != 0)
{
is_site = True;
}
}
else
{
if(strcmp(joint_name,"static")==0)
{
joint_type = Joint::StaticJointType;
}
else
if(strcmp(joint_name, "hingex")==0)
{
joint_type = Joint::HingeXJointType;
}
else
if(strcmp(joint_name,"hingey")==0)
{
joint_type = Joint::HingeYJointType;
}
else
if(strcmp(joint_name,"hingez")==0)
{
joint_type = Joint::HingeZJointType;
}
else
if(strcmp(joint_name,"ball")==0)
{
joint_type = Joint::BallJointType;
}
else
if(strcmp(joint_name,"balltranslate")==0)
{
joint_type = Joint::BallTranslationJointType;
}
}
segment_stream << is_site << joint_type;
//
// Get offsets
//
skl_file->GetEntry(segment_page_name, "tranx" ,&translation.x);
skl_file->GetEntry(segment_page_name, "trany" ,&translation.y);
skl_file->GetEntry(segment_page_name, "tranz" ,&translation.z);
skl_file->GetEntry(segment_page_name, "pitch" ,&rotation.pitch.angle);
skl_file->GetEntry(segment_page_name, "yaw" ,&rotation.yaw.angle);
skl_file->GetEntry(segment_page_name, "roll" ,&rotation.roll.angle);
base_offset = translation;
base_offset = rotation;
//
// Write out the base offset
//
segment_stream << base_offset;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Get the Primary Damage Zone
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char* skl_entry;
if (!model_file->GetEntry(
"video",
"skeleton",
&skl_entry
)
)
{
goto Dump_And_Die;
}
else
{
CString skl_filename =
MakePathedFilename(directories->videoDirectory, skl_entry);
NotationFile *skl_file = new NotationFile(skl_filename);
Register_Object(skl_file);
if (!skl_file->PageCount())
{
DEBUG_STREAM << skl_filename << " is empty or missing!"<<std::endl << std::flush;
Unregister_Object(skl_file);
delete skl_file;
goto Dump_And_Die;
}
int primary_damage_zone;
const char *dzone_name;
if (skl_file->GetEntry(
segment_page_name,
"dzone",
&dzone_name
)
)
{
primary_damage_zone = GetDamageZoneIndex(dzone_name, skl_file);
}
else
{
primary_damage_zone = -1;
}
segment_stream << primary_damage_zone;
Unregister_Object(skl_file);
delete skl_file;
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Read in ALL VideoObjectNames
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
if (!
InitVideoObjectNames(
&segment_stream,
model_file,
segment_page_name,
directories
)
)
{
goto Dump_And_Die;
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Read in ALL DESTROYED VideoObjectNames
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
if (!
InitDestroyedVideoObjectNames(
&segment_stream,
model_file,
segment_page_name,
directories
)
)
{
goto Dump_And_Die;
}
//
// Get the damageZones associated with this segment
//
NameList *damage_zone_list =
skl_file->MakeEntryList(segment_entry->GetName(), "dzone");
Register_Object(damage_zone_list);
NameList::Entry *damage_zone_entry = damage_zone_list->GetFirstEntry();
int damage_zone_count = damage_zone_list->EntryCount();
segment_stream << damage_zone_count;
if (damage_zone_count)
{
for (int dd=0;dd<damage_zone_count;++dd)
{
CString damage_zone_name;
damage_zone_name = damage_zone_entry->GetChar();
int damage_zone_index;
damage_zone_index =
GetDamageZoneIndex(damage_zone_name, skl_file);
if(damage_zone_index == -1)
{
DEBUG_STREAM<<model_file<<":"<<damage_zone_name<<" Not Found!"<<std::endl << std::flush;
goto Dump_And_Die;
}
segment_stream << damage_zone_index;
damage_zone_entry = damage_zone_entry->GetNextEntry();
}
}
Unregister_Object(damage_zone_list);
delete damage_zone_list;
//
// Get the number of children, 0 if no children
//
NameList *children_list =
skl_file->MakeEntryList(segment_entry->GetName(),"joint");
Register_Object(children_list);
NameList::Entry *child_entry = children_list->GetFirstEntry();
children_count = 0;
while(child_entry)
{
++children_count;
child_entry = child_entry->GetNextEntry();
}
//
// Write how many children
//
segment_stream << children_count;
if(children_count)
{
child_entry = children_list->GetFirstEntry();
//
// Write out the segment index for every child
//
for(int cc=0;cc<children_count;++cc)
{
int child_index = GetSegmentIndex(child_entry->GetChar(), skl_file);
if(child_index == -1)
{
DEBUG_STREAM<<model_name<<":"<<child_entry->GetName()<<" Not Found!!"<<std::endl << std::flush;
goto Dump_And_Die;
}
segment_stream << child_index;
child_entry = child_entry->GetNextEntry();
}
}
Unregister_Object(children_list);
delete children_list;
segment_entry = segment_entry->GetNextEntry();
}
//
//--------------------------------------------------------------------
// Write the stream out to disk.
//--------------------------------------------------------------------
//
ResourceDescription *new_res =
resource_file->AddResourceMemoryStream(
model_name,
ResourceDescription::SkeletonStreamResourceType,
1,
ResourceDescription::Preload,
&segment_stream
);
Check(new_res);
//
// Fre Mem
//
Unregister_Pointer(filename);
delete filename;
Unregister_Object(skl_file);
delete skl_file;
Unregister_Object(segment_namelist);
delete segment_namelist;
return new_res->resourceID;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
JointedMover::InitDestroyedVideoObjectNames(
MemoryStream *mem_stream,
NotationFile *model_file,
CString page_name,
const ResourceDirectories *directories
)
{
Check(model_file);
Check(mem_stream);
NameList *skl_namelist = model_file->MakeEntryList("video","destroyed");
Register_Object(skl_namelist);
int entry_count = skl_namelist->EntryCount();
*mem_stream << entry_count;
if (!entry_count)
{
Unregister_Object(skl_namelist);
delete skl_namelist;
return True;
}
Verify(entry_count);
NameList::Entry *skl_entry = skl_namelist->GetFirstEntry();
while(skl_entry)
{
CString entry_name = skl_entry->GetName();
EntitySegment::SkeletonType skeleton_type;
if (! entry_name.Compare("destroyed") )
{
skeleton_type = EntitySegment::SkeletonType_N;
}
else if (! entry_name.Compare("destroyeds") )
{
skeleton_type = EntitySegment::SkeletonType_S;
}
else if (! entry_name.Compare("destroyedt") )
{
skeleton_type = EntitySegment::SkeletonType_T;
}
else if (! entry_name.Compare("destroyedo") )
{
skeleton_type = EntitySegment::SkeletonType_O;
}
else if (! entry_name.Compare("destroyeda") )
{
skeleton_type = EntitySegment::SkeletonType_A;
}
else if (! entry_name.Compare("destroyedb") )
{
skeleton_type = EntitySegment::SkeletonType_B;
}
else if (! entry_name.Compare("destroyedc") )
{
skeleton_type = EntitySegment::SkeletonType_C;
}
else if (! entry_name.Compare("destroyedd") )
{
skeleton_type = EntitySegment::SkeletonType_D;
}
*mem_stream << skeleton_type;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Get the video object filename
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CString short_skl_filename = skl_entry->GetChar();
CString skl_filename =
MakePathedFilename(directories->videoDirectory, short_skl_filename);
NotationFile *skl_file = new NotationFile(skl_filename);
Register_Object(skl_file);
if (!skl_file->PageCount())
{
DEBUG_STREAM << skl_filename << " is empty or missing!"<<std::endl << std::flush;
Dump_And_Die:
Unregister_Object(skl_namelist);
delete skl_namelist;
Unregister_Object(skl_file);
delete skl_file;
return ResourceDescription::NullResourceID;
}
CString video_object_name;
const char *c_name;
if (skl_file->GetEntry(
page_name,
"Object",
&c_name
)
)
{
video_object_name = c_name;
}
else
{
video_object_name = "None";
}
*mem_stream << video_object_name;
Unregister_Object(skl_file);
delete skl_file;
skl_entry = skl_entry->GetNextEntry();
}
Unregister_Object(skl_namelist);
delete skl_namelist;
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
JointedMover::InitVideoObjectNames(
MemoryStream *mem_stream,
NotationFile *model_file,
CString page_name,
const ResourceDirectories *directories
)
{
Check(model_file);
Check(mem_stream);
NameList *skl_namelist = model_file->MakeEntryList("video","skeleton");
Register_Object(skl_namelist);
int entry_count = skl_namelist->EntryCount();
Verify(entry_count);
*mem_stream << entry_count;
NameList::Entry *skl_entry = skl_namelist->GetFirstEntry();
while(skl_entry)
{
CString entry_name = skl_entry->GetName();
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Write out the skeleton type
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
EntitySegment::SkeletonType skeleton_type;
if (! entry_name.Compare("skeleton") )
{
skeleton_type = EntitySegment::SkeletonType_N;
}
else if (! entry_name.Compare("skeletons") )
{
skeleton_type = EntitySegment::SkeletonType_S;
}
else if (! entry_name.Compare("skeletont") )
{
skeleton_type = EntitySegment::SkeletonType_T;
}
else if (! entry_name.Compare("skeletono") )
{
skeleton_type = EntitySegment::SkeletonType_O;
}
else if (! entry_name.Compare("skeletona") )
{
skeleton_type = EntitySegment::SkeletonType_A;
}
else if (! entry_name.Compare("skeletonb") )
{
skeleton_type = EntitySegment::SkeletonType_B;
}
else if (! entry_name.Compare("skeletonc") )
{
skeleton_type = EntitySegment::SkeletonType_C;
}
else if (! entry_name.Compare("skeletond") )
{
skeleton_type = EntitySegment::SkeletonType_D;
}
*mem_stream << skeleton_type;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Get the video object filename
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CString short_skl_filename = skl_entry->GetChar();
CString skl_filename =
MakePathedFilename(directories->videoDirectory, short_skl_filename);
NotationFile *skl_file = new NotationFile(skl_filename);
Register_Object(skl_file);
if (!skl_file->PageCount())
{
DEBUG_STREAM << skl_filename << " is empty or missing!"<<std::endl << std::flush;
Dump_And_Die:
Unregister_Object(skl_namelist);
delete skl_namelist;
Unregister_Object(skl_file);
delete skl_file;
return ResourceDescription::NullResourceID;
}
CString video_object_name;
const char *c_name;
if (skl_file->GetEntry(
page_name,
"Object",
&c_name
)
)
{
video_object_name = c_name;
}
else
{
video_object_name = "None";
}
*mem_stream << video_object_name;
Unregister_Object(skl_file);
delete skl_file;
skl_entry = skl_entry->GetNextEntry();
}
Unregister_Object(skl_namelist);
delete skl_namelist;
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
JointedMover::GetDamageZoneIndex(
CString damage_zone_name,
NotationFile *skl_file
)
{
int damage_zone_index = -1;
NameList *name_list = skl_file->MakeEntryList("DamageZones", "dz_");
Register_Object(name_list);
if (name_list->EntryCount() == 0)
{
DEBUG_STREAM << "No dZones listed in DamageZones Page"<<std::endl << std::flush;
Unregister_Object(name_list);
delete name_list;
return -1;
}
NameList::Entry *damage_zone = name_list->GetFirstEntry();
while(damage_zone)
{
if(strcmp(damage_zone->GetName(), damage_zone_name) == 0)
{
Convert_From_Ascii(damage_zone->GetChar(), &damage_zone_index);
Unregister_Object(name_list);
delete name_list;
return damage_zone_index;
}
damage_zone = damage_zone->GetNextEntry();
}
Unregister_Object(name_list);
delete name_list;
return damage_zone_index;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
JointedMover::GetSegmentIndex(
CString segment_name,
NotationFile *skl_file
)
{
int segment_index=-1;
char page_name[128];
NameList *page_list = skl_file->MakePageList();
Register_Object(page_list);
NameList::Entry *current_entry = page_list->GetFirstEntry();
while(current_entry)
{
Str_Copy(
page_name,
current_entry->GetName(),
sizeof(page_name)
);
if(
(strcmp(page_name, "LAB_ONLY") == 0) ||
(strcmp(page_name,"DamageZones") == 0)
)
{
current_entry = current_entry->GetNextEntry();
continue;
}
++segment_index;
if((strcmp(page_name, segment_name) == 0))
{
Unregister_Object(page_list);
delete page_list;
return segment_index;
}
current_entry = current_entry->GetNextEntry();
}
Unregister_Object(page_list);
delete page_list;
return -1;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
JointedMover*
JointedMover::Make(JointedMover::MakeMessage *creation_message)
{
return new JointedMover(creation_message, DefaultData);
}
//##########################################################################
//########################## Animation ###############################
//##########################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AnimationInstance::AnimationInstance(JointedMover *jointed_mover)
{
Check_Pointer(this);
Check(jointed_mover);
lerpToZero = False;
moverToAnimate = jointed_mover;
jointSubToAnimate = jointed_mover->GetJointSubsystem();
animationResource = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
AnimationInstance::SetAnimation(
ResourceDescription::ResourceID animation_number,
JointedMover::AnimationCallback finished_callback
)
{
Check_Pointer(this);
finishedCallback = finished_callback;
currentTime = 0.0f;
currentFrame = 0;
if (animationResource)
{
Check(animationResource);
animationResource->Unlock();
}
animationResource =
application->GetResourceFile()->FindResourceDescription(
animation_number
);
Check(animationResource);
animationResource->Lock();
int *animation_data = (int*)animationResource->resourceAddress;
Check_Pointer(animation_data);
frameCount = animation_data[0];
jointCount = animation_data[1];
footStepThreshold = (float *)&animation_data[2];
jointIndices = &animation_data[3];
frameStart = (Scalar*)(jointIndices + jointCount);
keyFrames = frameStart + frameCount;
currentFrameTo = keyFrames;
void* to;
to = keyFrames;
//
//-----------------------------------
// find the end of the keyframes data
//-----------------------------------
//
for(int ii=0;ii<frameCount;++ii)
for(int jj=0;jj<jointCount;++jj)
{
switch(jointSubToAnimate->GetJoint(jointIndices[jj])->GetJointType())
{
case Joint::BallTranslationJointType:
{
to = (void *)((char *)to+sizeof(EulerAngles));
to = (void *)((char *)to+sizeof(Vector3D));
break;
}
case Joint::HingeXJointType:
case Joint::HingeYJointType:
case Joint::HingeZJointType:
{
to = (void *)((char *)to+sizeof(Hinge));
break;
}
case Joint::BallJointType:
to = (void *)((char *)to+sizeof(EulerAngles));
break;
}
}
//
//
// This should be contained in the keyframes
//
// keyJointPos = (Vector3D*)(keyFrames + jointCount*frameCount);
rootTranslations = (Vector3D*)(to);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AnimationInstance::~AnimationInstance()
{
if (animationResource)
{
Check(animationResource);
animationResource->Unlock();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
AnimationInstance::Animate(Scalar time_slice, Logical move_joints)
{
Check(this);
//
//--------------------------------------------------------------------------
// Find the frame to lerp towards. As each frame boundary is crossed, set
// the joints to the position of that boundary and adjust the remaining time
// to lerp
//--------------------------------------------------------------------------
//
int i;
//
//-----------------------------------------
// This void * can point to any joint type
//-----------------------------------------
//
void
*to;
Scalar frame_time = currentTime + time_slice;
Scalar movement = 0.0f;
//
//-------------------------------------------------------------
// to points to the place in the memory stream we left off at
// last time we were on this loop
//-------------------------------------------------------------
//
to = currentFrameTo;
Joint *current_joint;
while (currentFrame < frameCount)
{
if (frame_time < frameStart[currentFrame])
{
break;
}
for (i=0; i<jointCount; ++i)
{
current_joint = jointSubToAnimate->GetJoint(jointIndices[i]);
Check(current_joint);
switch(current_joint->GetJointType())
{
case Joint::BallTranslationJointType:
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Only modify the joint if the value has changed
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
if (current_joint->GetEulerAngles() != *(EulerAngles*)to)
{
if (move_joints)
{
current_joint->SetRotation(*(EulerAngles*)to);
}
}
to = (void *)((char *)to+sizeof(EulerAngles));
if (current_joint->GetTranslation() != *(Point3D*)to)
{
if (move_joints)
{
current_joint->SetTranslation(*(Point3D*)to);
}
}
to = (void *)((char *)to+sizeof(Vector3D));
break;
}
case Joint::HingeXJointType:
case Joint::HingeYJointType:
case Joint::HingeZJointType:
{
if (current_joint->GetHinge() != *(Hinge*) to)
{
if (move_joints)
{
current_joint->SetHinge(*(Hinge*) to);
}
}
to = (void *)((char *)to+sizeof(Hinge));
break;
}
case Joint::BallJointType:
if (current_joint->GetEulerAngles() != *(EulerAngles*)to)
{
if (move_joints)
{
current_joint->SetRotation(*(EulerAngles*)to);
}
}
to = (void *)((char *)to+sizeof(EulerAngles));
break;
case Joint::StaticJointType:
break;
}
}
movement +=
(frameStart[currentFrame] - currentTime)
* rootTranslations[currentFrame].z;
currentTime = frameStart[currentFrame];
++currentFrame;
}
//
//----------------------------------------------------------------------
// We we have run off the end of the animation, trigger the callback and
// return
//----------------------------------------------------------------------
//
if (currentFrame == frameCount)
{
movement +=
(moverToAnimate->*finishedCallback)(
animationResource->resourceID,
frame_time - frameStart[frameCount - 1],
move_joints
);
return movement;
}
currentFrameTo = to;
//
//-------------------------------------------------------
// Set up to lerp the rotations between to two key frames
//-------------------------------------------------------
//
Verify(!Small_Enough(frameStart[currentFrame] - currentTime));
Scalar delta =
(frame_time - currentTime)/(frameStart[currentFrame] - currentTime);
for (i=0; i<jointCount; ++i)
{
current_joint =
jointSubToAnimate->GetJoint(jointIndices[i]);
Check(current_joint);
switch(current_joint->GetJointType())
{
case Joint::BallTranslationJointType:
{
Point3D new_trans;
EulerAngles new_angles;
new_angles.Lerp(
current_joint->GetEulerAngles(),
*(EulerAngles*)to,
delta
);
if (current_joint->GetEulerAngles() != new_angles)
{
if (move_joints)
{
current_joint->SetRotation(new_angles);
}
}
to = (void *)((char *)to+sizeof(EulerAngles));
new_trans.Lerp(
current_joint->GetTranslation(),
*(Vector3D*)to,
delta
);
if (current_joint->GetTranslation() != new_trans)
{
if (move_joints)
{
current_joint->SetTranslation(new_trans);
}
}
to = (void *)((char *)to+sizeof(Vector3D));
break;
}
case Joint::HingeZJointType:
case Joint::HingeYJointType:
case Joint::HingeXJointType:
{
Hinge new_hinge;
new_hinge.Lerp(
current_joint->GetHinge(),
*(Hinge*)to,
delta
);
if (current_joint->GetRadians() != new_hinge.rotationAmount)
{
if (move_joints)
{
current_joint->SetRotation(new_hinge.rotationAmount);
}
}
to = (void *)((char *)to+sizeof(Hinge));
break;
}
case Joint::BallJointType:
{
EulerAngles new_angles;
new_angles.Lerp(
current_joint->GetEulerAngles(),
*(EulerAngles*)to,
delta
);
if (current_joint->GetEulerAngles() != new_angles)
{
if (move_joints)
{
current_joint->SetRotation(new_angles);
}
}
to = (void *)((char *)to+sizeof(EulerAngles));
break;
}
case Joint::StaticJointType:
break;
}
}
movement += (frame_time - currentTime) * rootTranslations[currentFrame].z;
currentTime = frame_time;
return movement;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
AnimationInstance::LerpToPose(Scalar time_slice, Scalar time_to_lerp, Logical move_joints)
{
Check(this);
int i;
//
//-----------------------------------------
// This void * can point to any joint type
//-----------------------------------------
//
void
*to;
if (!lerpToZero)
{
lerpToZero = True;
deltaTime = time_to_lerp;
}
Scalar delta = time_slice / deltaTime;
//
//-------------------------------------------------------------
// to points to the place in the memory stream we left off at
// last time we were on this loop
//-------------------------------------------------------------
//
to = currentFrameTo;
Joint *current_joint;
if (move_joints)
{
for (i=0; i<jointCount; ++i)
{
current_joint =
jointSubToAnimate->GetJoint(jointIndices[i]);
Check(current_joint);
switch(current_joint->GetJointType())
{
case Joint::BallTranslationJointType:
{
Point3D new_trans;
EulerAngles new_angles;
new_angles.Lerp(
current_joint->GetEulerAngles(),
*(EulerAngles*)to,
delta
);
if (current_joint->GetEulerAngles() != new_angles)
{
current_joint->SetRotation(new_angles);
}
to = (void *)((char *)to+sizeof(EulerAngles));
new_trans.Lerp(
current_joint->GetTranslation(),
*(Vector3D*)to,
delta
);
if (current_joint->GetTranslation() != new_trans)
{
current_joint->SetTranslation(new_trans);
}
to = (void *)((char *)to+sizeof(Vector3D));
break;
}
case Joint::HingeZJointType:
case Joint::HingeYJointType:
case Joint::HingeXJointType:
{
Hinge new_hinge;
new_hinge.Lerp(
current_joint->GetHinge(),
*(Hinge*)to,
delta
);
if (current_joint->GetRadians() != new_hinge.rotationAmount)
{
current_joint->SetRotation(new_hinge.rotationAmount);
}
to = (void *)((char *)to+sizeof(Hinge));
break;
}
case Joint::BallJointType:
{
EulerAngles new_angles;
new_angles.Lerp(
current_joint->GetEulerAngles(),
*(EulerAngles*)to,
delta
);
if (current_joint->GetEulerAngles() != new_angles)
{
current_joint->SetRotation(new_angles);
}
to = (void *)((char *)to+sizeof(EulerAngles));
break;
}
case Joint::StaticJointType:
break;
}
}
}
deltaTime -= time_slice;
if (deltaTime <= 0.0f)
{
lerpToZero = False;
return False;
}
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
AnimationInstance::LerpToRest(Scalar time_slice, Scalar time_to_lerp, Logical move_joints)
{
if (!lerpToZero)
{
lerpToZero = True;
deltaTime = time_to_lerp;
}
Scalar delta = time_slice / deltaTime;
if (move_joints)
{
EulerAngles zero_euler(0.0f, 0.0f, 0.0f);
Hinge zero_hingeX(0.0f, X_Axis);
Hinge zero_hingeY(0.0f, Y_Axis);
Hinge zero_hingeZ(0.0f, Z_Axis);
Vector3D zero_vector(0.0f, 0.0f, 0.0f);
for (int i=0; i<jointCount; ++i)
{
Joint *current_joint =
jointSubToAnimate->GetJoint(jointIndices[i]);
Check(current_joint);
switch(current_joint->GetJointType())
{
case Joint::BallTranslationJointType:
{
EulerAngles new_angles;
new_angles.Lerp(
current_joint->GetEulerAngles(),
zero_euler,
delta
);
if (current_joint->GetEulerAngles() != new_angles)
{
current_joint->SetRotation(new_angles);
}
Point3D new_trans;
new_trans.Lerp(
current_joint->GetTranslation(),
zero_vector,
delta
);
if (current_joint->GetTranslation() != new_trans)
{
current_joint->SetTranslation(new_trans);
}
break;
}
case Joint::HingeXJointType:
{
Hinge new_hinge;
new_hinge.Lerp(
current_joint->GetHinge(),
zero_hingeX,
delta
);
if(current_joint->GetRadians() != new_hinge.rotationAmount)
{
current_joint->SetRotation(new_hinge.rotationAmount);
}
break;
}
case Joint::HingeYJointType:
{
Hinge new_hinge;
new_hinge.Lerp(
current_joint->GetHinge(),
zero_hingeY,
delta
);
if(current_joint->GetRadians() != new_hinge.rotationAmount)
{
current_joint->SetRotation(new_hinge.rotationAmount);
}
break;
}
case Joint::HingeZJointType:
{
Hinge new_hinge;
new_hinge.Lerp(
current_joint->GetHinge(),
zero_hingeZ,
delta
);
if(current_joint->GetRadians() != new_hinge.rotationAmount)
{
current_joint->SetRotation(new_hinge.rotationAmount);
}
break;
}
case Joint::BallJointType:
{
EulerAngles new_angles;
new_angles.Lerp(
current_joint->GetEulerAngles(),
zero_euler,
delta
);
if (current_joint->GetEulerAngles() != new_angles)
{
current_joint->SetRotation(new_angles);
}
break;
}
case Joint::StaticJointType:
break;
}
}
}
deltaTime -= time_slice;
if (deltaTime <= 0.0f)
{
lerpToZero = False;
return False;
}
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
AnimationInstance::SnapToRest(Logical move_joints)
{
if (!move_joints)
{
return;
}
EulerAngles zero_euler(0.0f, 0.0f, 0.0f);
Hinge zero_hingeX(0.0f, X_Axis);
Hinge zero_hingeY(0.0f, Y_Axis);
Hinge zero_hingeZ(0.0f, Z_Axis);
Point3D zero_point(0.0f, 0.0f, 0.0f);
for (int i=0; i<jointCount; ++i)
{
Joint *current_joint =
jointSubToAnimate->GetJoint(jointIndices[i]);
Check(current_joint);
switch(current_joint->GetJointType())
{
case Joint::BallTranslationJointType:
{
current_joint->SetRotation(zero_euler);
current_joint->SetTranslation(zero_point);
break;
}
case Joint::HingeXJointType:
{
current_joint->SetHinge(zero_hingeX);
break;
}
case Joint::HingeYJointType:
{
current_joint->SetHinge(zero_hingeY);
break;
}
case Joint::HingeZJointType:
{
current_joint->SetHinge(zero_hingeZ);
break;
}
case Joint::BallJointType:
{
current_joint->SetRotation(zero_euler);
break;
}
case Joint::StaticJointType:
break;
}
}
}
//##########################################################################
//############## Sketon Notation file utilities ####################
//##########################################################################
int
Get_Active_Joint_Count(NotationFile *skl_file)
{
NameList *namelist = skl_file->MakePageList("joint");
Register_Object(namelist);
NameList::Entry *entry = namelist->GetFirstEntry();
int count = 0;
while (entry)
{
++count;
entry = entry->GetNextEntry();
}
Unregister_Object(namelist);
delete namelist;
return count;
}
Logical
JointedMover::TestInstance() const
{
return IsDerivedFrom(*GetClassDerivations());
}