open_toontown_panda3d/panda/src/egg2pg/animBundleMaker.cxx

342 lines
11 KiB
C++

// Filename: animBundleMaker.cxx
// Created by: drose (22Feb99)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "animBundleMaker.h"
#include "config_egg2pg.h"
#include "eggTable.h"
#include "eggAnimData.h"
#include "eggSAnimData.h"
#include "eggXfmAnimData.h"
#include "eggXfmSAnim.h"
#include "eggGroupNode.h"
#include "animBundle.h"
#include "animBundleNode.h"
#include "animChannelMatrixXfmTable.h"
#include "animChannelScalarTable.h"
////////////////////////////////////////////////////////////////////
// Function: AnimBundleMaker::Construtor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
AnimBundleMaker::
AnimBundleMaker(EggTable *root) : _root(root) {
_fps = 0.0f;
_num_frames = 1;
_ok_fps = true;
_ok_num_frames = true;
inspect_tree(root);
if (!_ok_fps) {
egg2pg_cat.warning()
<< "AnimBundle " << _root->get_name()
<< " specifies contradictory frame rates.\n";
} else if (_fps == 0.0f) {
egg2pg_cat.warning()
<< "AnimBundle " << _root->get_name()
<< " does not specify a frame rate.\n";
_fps = 24.0f;
}
if (!_ok_num_frames) {
egg2pg_cat.warning()
<< "AnimBundle " << _root->get_name()
<< " specifies contradictory number of frames.\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: AnimBundleMaker::make_node
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
AnimBundleNode *AnimBundleMaker::
make_node() {
return new AnimBundleNode("", make_bundle());
}
////////////////////////////////////////////////////////////////////
// Function: AnimBundleMaker::make_bundle
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
AnimBundle *AnimBundleMaker::
make_bundle() {
AnimBundle *bundle = new AnimBundle(_root->get_name(), _fps, _num_frames);
EggTable::const_iterator ci;
for (ci = _root->begin(); ci != _root->end(); ++ci) {
if ((*ci)->is_of_type(EggTable::get_class_type())) {
EggTable *child = DCAST(EggTable, *ci);
build_hierarchy(child, bundle);
}
}
bundle->sort_descendants();
return bundle;
}
////////////////////////////////////////////////////////////////////
// Function: AnimBundleMaker::inspect_tree
// Access: Private
// Description: Walks the egg tree, getting out the fps and the
// number of frames.
////////////////////////////////////////////////////////////////////
void AnimBundleMaker::
inspect_tree(EggNode *egg_node) {
if (egg_node->is_of_type(EggAnimData::get_class_type())) {
// Check frame rate.
EggAnimData *egg_anim = DCAST(EggAnimData, egg_node);
if (egg_anim->has_fps()) {
if (_fps == 0.0f) {
_fps = egg_anim->get_fps();
} else if (_fps != egg_anim->get_fps()) {
// Whoops! This table differs in opinion from the other tables.
_fps = min(_fps, (float)egg_anim->get_fps());
_ok_fps = false;
}
}
}
if (egg_node->is_of_type(EggXfmSAnim::get_class_type())) {
// Check frame rate.
EggXfmSAnim *egg_anim = DCAST(EggXfmSAnim, egg_node);
if (egg_anim->has_fps()) {
if (_fps == 0.0f) {
_fps = egg_anim->get_fps();
} else if (_fps != egg_anim->get_fps()) {
// Whoops! This table differs in opinion from the other tables.
_fps = min(_fps, (float)egg_anim->get_fps());
_ok_fps = false;
}
}
}
if (egg_node->is_of_type(EggSAnimData::get_class_type())) {
// Check number of frames.
EggSAnimData *egg_anim = DCAST(EggSAnimData, egg_node);
int num_frames = egg_anim->get_num_rows();
if (num_frames > 1) {
if (_num_frames == 1) {
_num_frames = num_frames;
} else if (_num_frames != num_frames) {
// Whoops! Another disagreement.
_num_frames = min(_num_frames, num_frames);
_ok_num_frames = false;
}
}
}
if (egg_node->is_of_type(EggXfmAnimData::get_class_type())) {
// Check number of frames.
EggXfmAnimData *egg_anim = DCAST(EggXfmAnimData, egg_node);
int num_frames = egg_anim->get_num_rows();
if (num_frames > 1) {
if (_num_frames == 1) {
_num_frames = num_frames;
} else if (_num_frames != num_frames) {
// Whoops! Another disagreement.
_num_frames = min(_num_frames, num_frames);
_ok_num_frames = false;
}
}
}
if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
// Now recurse.
EggGroupNode *group = DCAST(EggGroupNode, egg_node);
EggGroupNode::const_iterator ci;
for (ci = group->begin(); ci != group->end(); ++ci) {
inspect_tree(*ci);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: AnimBundleMaker::build_hierarchy
// Access: Private
// Description: Walks the egg tree again, creating the AnimChannels
// as appropriate.
////////////////////////////////////////////////////////////////////
void AnimBundleMaker::
build_hierarchy(EggTable *egg_table, AnimGroup *parent) {
AnimGroup *this_node = NULL;
// First, scan the children of egg_table for anim data tables. If
// any of them is named "xform", it's a special case--this one
// stands for the egg_table node itself. Don't ask me why.
EggTable::const_iterator ci;
for (ci = egg_table->begin(); ci != egg_table->end(); ++ci) {
if ((*ci)->get_name() == "xform") {
if (this_node == NULL) {
this_node = create_xfm_channel((*ci), egg_table->get_name(), parent);
} else {
egg2pg_cat.warning()
<< "Duplicate xform table under node "
<< egg_table->get_name() << "\n";
}
}
}
// If none of them were named "xform", just create a plain old
// AnimGroup.
if (this_node == NULL) {
this_node = new AnimGroup(parent, egg_table->get_name());
}
// Now walk the children again, creating any leftover tables, and
// recursing.
for (ci = egg_table->begin(); ci != egg_table->end(); ++ci) {
if ((*ci)->get_name() == "xform") {
// Skip this one. We already got it.
} else if ((*ci)->is_of_type(EggSAnimData::get_class_type())) {
EggSAnimData *egg_anim = DCAST(EggSAnimData, *ci);
create_s_channel(egg_anim, egg_anim->get_name(), this_node);
} else if ((*ci)->is_of_type(EggTable::get_class_type())) {
EggTable *child = DCAST(EggTable, *ci);
build_hierarchy(child, this_node);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: AnimBundleMaker::create_s_channel
// Access: Private
// Description: Creates an AnimChannelScalarTable corresponding to
// the given EggSAnimData structure.
////////////////////////////////////////////////////////////////////
AnimChannelScalarTable *AnimBundleMaker::
create_s_channel(EggSAnimData *egg_anim, const string &name,
AnimGroup *parent) {
AnimChannelScalarTable *table
= new AnimChannelScalarTable(parent, name);
// First we have to copy the table data from PTA_double to
// PTA_float.
PTA_float new_data=PTA_float::empty_array(egg_anim->get_num_rows());
for (int i = 0; i < egg_anim->get_num_rows(); i++) {
new_data[i] = (float)egg_anim->get_value(i);
}
// Now we can assign the table.
table->set_table(new_data);
return table;
}
////////////////////////////////////////////////////////////////////
// Function: AnimBundleMaker::create_xfm_channel (EggNode)
// Access: Private
// Description: Creates an AnimChannelMatrixXfmTable corresponding to
// the given EggNode structure, if possible.
////////////////////////////////////////////////////////////////////
AnimChannelMatrixXfmTable *AnimBundleMaker::
create_xfm_channel(EggNode *egg_node, const string &name,
AnimGroup *parent) {
if (egg_node->is_of_type(EggXfmAnimData::get_class_type())) {
EggXfmAnimData *egg_anim = DCAST(EggXfmAnimData, egg_node);
EggXfmSAnim new_anim(*egg_anim);
return create_xfm_channel(&new_anim, name, parent);
} else if (egg_node->is_of_type(EggXfmSAnim::get_class_type())) {
EggXfmSAnim *egg_anim = DCAST(EggXfmSAnim, egg_node);
return create_xfm_channel(egg_anim, name, parent);
}
egg2pg_cat.warning()
<< "Inappropriate node named xform under node "
<< name << "\n";
return NULL;
}
////////////////////////////////////////////////////////////////////
// Function: AnimBundleMaker::create_xfm_channel (EggXfmSAnim)
// Access: Private
// Description: Creates an AnimChannelMatrixXfmTable corresponding to
// the given EggXfmSAnim structure.
////////////////////////////////////////////////////////////////////
AnimChannelMatrixXfmTable *AnimBundleMaker::
create_xfm_channel(EggXfmSAnim *egg_anim, const string &name,
AnimGroup *parent) {
// Ensure that the anim table is optimal and that it is standard
// order.
egg_anim->optimize_to_standard_order();
AnimChannelMatrixXfmTable *table
= new AnimChannelMatrixXfmTable(parent, name);
// The EggXfmSAnim structure has a number of children which are
// EggSAnimData tables. Each of these represents a separate
// component of the transform data, and will be added to the table.
EggXfmSAnim::const_iterator ci;
for (ci = egg_anim->begin(); ci != egg_anim->end(); ++ci) {
if ((*ci)->is_of_type(EggSAnimData::get_class_type())) {
EggSAnimData *child = DCAST(EggSAnimData, *ci);
if (child->get_name().empty()) {
egg2pg_cat.warning()
<< "Unnamed subtable of <Xfm$Anim_S$> " << name
<< "\n";
} else {
char table_id = child->get_name()[0];
if (child->get_name().length() > 1 ||
!table->is_valid_id(table_id)) {
egg2pg_cat.warning()
<< "Unexpected table name " << child->get_name()
<< ", child of " << name << "\n";
} else if (table->has_table(table_id)) {
egg2pg_cat.warning()
<< "Duplicate table definition for " << table_id
<< " under " << name << "\n";
} else {
// Now we have to copy the table data from PTA_double to
// PTA_float.
PTA_float new_data=PTA_float::empty_array(child->get_num_rows());
for (int i = 0; i < child->get_num_rows(); i++) {
new_data[i] = (float)child->get_value(i);
}
// Now we can assign the table.
table->set_table(table_id, new_data);
}
}
}
}
return table;
}