open_toontown_panda3d/panda/src/egg/eggXfmAnimData.cxx

297 lines
8.7 KiB
C++

// Filename: eggXfmAnimData.cxx
// Created by: drose (19Feb99)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "eggXfmAnimData.h"
#include "eggXfmSAnim.h"
#include "eggSAnimData.h"
#include "eggMiscFuncs.h"
#include "config_egg.h"
#include "indent.h"
#include "luse.h"
#include "lmatrix.h"
#include "compose_matrix.h"
#include "dcast.h"
TypeHandle EggXfmAnimData::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: EggXfmAnimData::Conversion constructor
// Access: Public
// Description: Converts the newer-style XfmSAnim table to the
// older-style XfmAnim table.
////////////////////////////////////////////////////////////////////
EggXfmAnimData::
EggXfmAnimData(const EggXfmSAnim &convert_from)
: EggAnimData(convert_from.get_name())
{
if (convert_from.has_order()) {
set_order(convert_from.get_order());
}
if (convert_from.has_fps()) {
set_fps(convert_from.get_fps());
}
_coordsys = convert_from.get_coordinate_system();
// First, get the table names so we know how to build up our
// contents string. Also store up the SAnim tables themselves in a
// temporary vector for convenience.
pvector<EggSAnimData *> subtables;
EggXfmSAnim::const_iterator ci;
for (ci = convert_from.begin(); ci != convert_from.end(); ++ci) {
if ((*ci)->is_of_type(EggSAnimData::get_class_type())) {
EggSAnimData *sanim = DCAST(EggSAnimData, *ci);
nassertv(sanim->get_name().length() == 1);
if (sanim->get_num_rows() > 0) {
subtables.push_back(sanim);
_contents += sanim->get_name()[0];
}
}
}
// Now, go through and extract out all the data.
int num_rows = convert_from.get_num_rows();
for (int row = 0; row < num_rows; row++) {
for (int col = 0; col < (int)subtables.size(); col++) {
EggSAnimData *sanim = subtables[col];
if (sanim->get_num_rows() == 1) {
add_data(sanim->get_value(0));
} else {
nassertv(row < sanim->get_num_rows());
add_data(sanim->get_value(row));
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: EggXfmAnimData::get_value
// Access: Public
// Description: Returns the value of the aggregate row of the table
// as a matrix. This is a convenience function that
// treats the 2-d table as if it were a single table of
// matrices.
////////////////////////////////////////////////////////////////////
void EggXfmAnimData::
get_value(int row, LMatrix4d &mat) const {
LVector3d scale(1.0, 1.0, 1.0);
LVector3d shear(0.0, 0.0, 0.0);
LVector3d hpr(0.0, 0.0, 0.0);
LVector3d translate(0.0, 0.0, 0.0);
for (int col = 0; col < get_num_cols(); col++) {
double value = get_value(row, col);
switch (_contents[col]) {
case 'i':
scale[0] = value;
break;
case 'j':
scale[1] = value;
break;
case 'k':
scale[2] = value;
break;
case 'a':
shear[0] = value;
break;
case 'b':
shear[1] = value;
break;
case 'c':
shear[2] = value;
break;
case 'h':
hpr[0] = value;
break;
case 'p':
hpr[1] = value;
break;
case 'r':
hpr[2] = value;
break;
case 'x':
translate[0] = value;
break;
case 'y':
translate[1] = value;
break;
case 'z':
translate[2] = value;
break;
default:
// The contents string contained an invalid letter.
nassertv(false);
}
}
// So now we've got the twelve components; build a matrix.
EggXfmSAnim::compose_with_order(mat, scale, shear, hpr, translate, get_order(),
_coordsys);
}
////////////////////////////////////////////////////////////////////
// Function: EggXfmAnimData::is_anim_matrix
// Access: Public, Virtual
// Description: Returns true if this node represents a table of
// animation transformation data, false otherwise.
////////////////////////////////////////////////////////////////////
bool EggXfmAnimData::
is_anim_matrix() const {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: EggXfmAnimData::write
// Access: Public, Virtual
// Description: Writes the data to the indicated output stream in Egg
// format.
////////////////////////////////////////////////////////////////////
void EggXfmAnimData::
write(ostream &out, int indent_level) const {
write_header(out, indent_level, "<Xfm$Anim>");
if (has_fps()) {
indent(out, indent_level + 2)
<< "<Scalar> fps { " << get_fps() << " }\n";
}
if (has_order()) {
indent(out, indent_level + 2)
<< "<Char*> order { " << get_order() << " }\n";
}
if (has_contents()) {
indent(out, indent_level + 2)
<< "<Char*> contents { " << get_contents() << " }\n";
}
indent(out, indent_level + 2) << "<V> {\n";
write_long_list(out, indent_level + 4, _data.begin(), _data.end(),
"", "", 72);
indent(out, indent_level + 2) << "}\n";
indent(out, indent_level) << "}\n";
}
////////////////////////////////////////////////////////////////////
// Function: EggXfmAnimData::r_transform
// Access: Protected, Virtual
// Description: Applies the indicated transform to all the rows of
// the table. This actually forces the generation of a
// totally new set of rows.
////////////////////////////////////////////////////////////////////
void EggXfmAnimData::
r_transform(const LMatrix4d &mat, const LMatrix4d &inv,
CoordinateSystem to_cs) {
// We need to build an inverse matrix that doesn't reflect the
// translation component.
LMatrix4d inv1 = inv;
inv1.set_row(3, LVector3d(0.0, 0.0, 0.0));
// Now we build a temporary copy of the table as an EggXfmSAnim. We
// do this because this kind of table is easier to build and
// optimize.
if (to_cs == CS_default) {
to_cs = _coordsys;
}
EggXfmSAnim new_table(get_name(), to_cs);
if (has_fps()) {
new_table.set_fps(get_fps());
}
// We insist on the standard order now.
new_table.set_order(get_standard_order());
// Now build up the data into the new table.
LMatrix4d orig_mat;
for (int r = 0; r < get_num_rows(); r++) {
get_value(r, orig_mat);
bool result = new_table.add_data(inv1 * orig_mat * mat);
if (!result) {
egg_cat.error()
<< "Transform from " << _coordsys << " to " << to_cs
<< " failed!\n";
LVector3d scale, shear, hpr, trans;
bool d = decompose_matrix(orig_mat, scale, shear, hpr, trans, _coordsys);
egg_cat.error(false)
<< "orig:\n" << orig_mat
<< "d = " << d
<< "\n scale: " << scale
<< "\n shear: " << shear
<< "\n hpr: " << hpr
<< "\n trans: " << trans << "\n";
LMatrix4d new_mat = inv1 * orig_mat * mat;
d = decompose_matrix(new_mat, scale, shear, hpr, trans, to_cs);
egg_cat.error(false)
<< "new:\n" << new_mat
<< "d = " << d
<< "\n scale: " << scale
<< "\n shear: " << shear
<< "\n hpr: " << hpr
<< "\n trans: " << trans << "\n";
}
// If this assertion fails, we attempted to transform by non-affine
// matrix or some such thing that cannot be represented in an anim
// file.
nassertv(result);
}
// Now clean out the redundant columns we created.
new_table.optimize();
// And copy that back into EggXfmAnimData table form.
EggXfmAnimData copy_table(new_table);
(*this) = copy_table;
}
////////////////////////////////////////////////////////////////////
// Function: EggXfmAnimData::r_mark_coordsys
// Access: Protected, Virtual
// Description: This is only called immediately after loading an egg
// file from disk, to propagate the value found in the
// CoordinateSystem entry (or the default Y-up
// coordinate system) to all nodes that care about what
// the coordinate system is.
////////////////////////////////////////////////////////////////////
void EggXfmAnimData::
r_mark_coordsys(CoordinateSystem cs) {
_coordsys = cs;
}