handle some broken egg files more gracefully

This commit is contained in:
David Rose 2003-07-22 06:32:41 +00:00
parent 6b7baa43d7
commit c9e4bbc9c0
20 changed files with 257 additions and 47 deletions

View File

@ -30,6 +30,17 @@ EggBackPointer::
EggBackPointer() {
}
////////////////////////////////////////////////////////////////////
// Function: EggBackPointer::extend_to
// Access: Public, Virtual
// Description: Extends the table to the indicated number of frames.
////////////////////////////////////////////////////////////////////
void EggBackPointer::
extend_to(int num_frames) {
// Whoops, can't extend this kind of table!
nassertv(false);
}
////////////////////////////////////////////////////////////////////
// Function: EggBackPointer::has_vertices
// Access: Public, Virtual

View File

@ -40,6 +40,8 @@ class EggBackPointer : public TypedObject {
public:
EggBackPointer();
virtual int get_num_frames() const=0;
virtual void extend_to(int num_frames);
virtual bool has_vertices() const;
public:

View File

@ -106,7 +106,7 @@ add_egg(EggData *egg) {
}
egg_info._models.push_back(model_root);
char_data->add_model(model_index, model_root);
char_data->add_model(model_index, model_root, egg);
nassertr(model_index == (int)_characters_by_model_index.size(), -1);
_characters_by_model_index.push_back(char_data);
root_joint->add_back_pointer(model_index, desc._root_node);
@ -663,3 +663,42 @@ write(ostream &out, int indent_level) const {
char_data->write(out, indent_level);
}
}
////////////////////////////////////////////////////////////////////
// Function: EggCharacterCollection::check_errors
// Access: Public
// Description: Can be called after the collection has been
// completely filled up with egg files to output any
// messages from warning conditions that have been
// detected, such as inconsistent animation tables.
//
// In addition to reporting this errors, calling this
// function will also ensure that they are all repaired
// (although certain kinds of errors will be repaired
// regardless).
////////////////////////////////////////////////////////////////////
void EggCharacterCollection::
check_errors(ostream &out) {
Characters::const_iterator ci;
for (ci = _characters.begin(); ci != _characters.end(); ++ci) {
EggCharacterData *char_data = (*ci);
int num_joints = char_data->get_num_joints();
for (int j = 0; j < num_joints; j++) {
EggJointData *joint_data = char_data->get_joint(j);
if (joint_data->_forced_rest_frames_equal) {
out << "Warning: rest frames for " << joint_data->get_name()
<< " were different.\n";
}
}
int num_models = char_data->get_num_models();
for (int mi = 0; mi < num_models; mi++) {
int model_index = char_data->get_model_index(mi);
if (!char_data->check_num_frames(model_index)) {
out << "Warning: animation from "
<< char_data->get_egg_data(model_index)->get_egg_filename().get_basename()
<< " had an inconsistent number of frames.\n";
}
}
}
}

View File

@ -55,6 +55,7 @@ public:
INLINE EggCharacterData *get_character_by_model_index(int model_index) const;
virtual void write(ostream &out, int indent_level = 0) const;
void check_errors(ostream &out);
virtual EggCharacterData *make_character_data();
virtual EggJointData *make_joint_data(EggCharacterData *char_data);

View File

@ -68,6 +68,19 @@ get_model_root(int n) const {
return _models[n]._model_root;
}
////////////////////////////////////////////////////////////////////
// Function: EggCharacterData::get_egg_data
// Access: Public
// Description: Returns the EggData representing the egg file that
// defined this particular model. Note that one egg
// file might contain multiple models.
////////////////////////////////////////////////////////////////////
INLINE EggData *EggCharacterData::
get_egg_data(int n) const {
nassertr(n >= 0 && n < (int)_models.size(), (EggData *)NULL);
return _models[n]._egg_data;
}
////////////////////////////////////////////////////////////////////
// Function: EggCharacterData::get_root_joint
// Access: Public

View File

@ -65,10 +65,11 @@ EggCharacterData::
// file: in either case, a hierarchy of joints.
////////////////////////////////////////////////////////////////////
void EggCharacterData::
add_model(int model_index, EggNode *model_root) {
add_model(int model_index, EggNode *model_root, EggData *egg_data) {
Model m;
m._model_index = model_index;
m._model_root = model_root;
m._egg_data = egg_data;
_models.push_back(m);
}
@ -102,6 +103,49 @@ get_num_frames(int model_index) const {
return max_num_frames;
}
////////////////////////////////////////////////////////////////////
// Function: EggCharacterData::check_num_frames
// Access: Public
// Description: Walks through each component and ensures that all
// have the same number of frames of animation (except
// for those that contain 0 or 1 frames, of course).
// Returns true if all are valid, false if there is a
// discreprency (in which case the shorter component are
// extended).
////////////////////////////////////////////////////////////////////
bool EggCharacterData::
check_num_frames(int model_index) {
int max_num_frames = 0;
bool any_violations = false;
Components::const_iterator ci;
for (ci = _components.begin(); ci != _components.end(); ++ci) {
EggComponentData *component = (*ci);
int num_frames = component->get_num_frames(model_index);
if (num_frames > 1 && max_num_frames > 1 &&
max_num_frames != num_frames) {
// If we have two different opinions about the number of frames
// (other than 0 or 1), we have a discrepency. This is an error
// condition.
any_violations = true;
}
max_num_frames = max(max_num_frames, num_frames);
}
if (any_violations) {
// Now go back through and force all components to the appropriate
// length.
for (ci = _components.begin(); ci != _components.end(); ++ci) {
EggComponentData *component = (*ci);
int num_frames = component->get_num_frames(model_index);
if (num_frames > 1 && max_num_frames != num_frames) {
component->extend_to(model_index, max_num_frames);
}
}
}
return !any_violations;
}
////////////////////////////////////////////////////////////////////
// Function: EggCharacterData::do_reparent
// Access: Public

View File

@ -24,6 +24,7 @@
#include "eggJointData.h"
#include "eggNode.h"
#include "eggData.h"
#include "pointerTo.h"
#include "namable.h"
@ -64,11 +65,13 @@ public:
EggCharacterData(EggCharacterCollection *collection);
virtual ~EggCharacterData();
void add_model(int model_index, EggNode *model_root);
void add_model(int model_index, EggNode *model_root, EggData *egg_data);
INLINE int get_num_models() const;
INLINE int get_model_index(int n) const;
INLINE EggNode *get_model_root(int n) const;
INLINE EggData *get_egg_data(int n) const;
int get_num_frames(int model_index) const;
bool check_num_frames(int model_index);
INLINE EggJointData *get_root_joint() const;
INLINE EggJointData *find_joint(const string &name) const;
@ -91,6 +94,7 @@ protected:
public:
int _model_index;
PT(EggNode) _model_root;
PT(EggData) _egg_data;
};
typedef pvector<Model> Models;
Models _models;

View File

@ -70,6 +70,8 @@ post_command_line() {
}
}
_collection->check_errors(nout);
return true;
}

View File

@ -19,7 +19,7 @@
#ifndef EGGCHARACTERFILTER_H
#define EGGCHARACTERFILTER_H
#include <pandatoolbase.h>
#include "pandatoolbase.h"
#include "eggMultiFilter.h"

View File

@ -82,6 +82,35 @@ matches_name(const string &name) const {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: EggComponentData::get_num_frames
// Access: Public, Virtual
// Description: Returns the number of frames of animation for this
// particular component in the indicated model.
////////////////////////////////////////////////////////////////////
int EggComponentData::
get_num_frames(int model_index) const {
EggBackPointer *back = get_model(model_index);
if (back == (EggBackPointer *)NULL) {
return 0;
}
return back->get_num_frames();
}
////////////////////////////////////////////////////////////////////
// Function: EggComponentData::extend_to
// Access: Public, Virtual
// Description: Extends the number of frames in the indicated model
// (presumably an animation table model) to the given
// number.
////////////////////////////////////////////////////////////////////
void EggComponentData::
extend_to(int model_index, int num_frames) const {
EggBackPointer *back = get_model(model_index);
nassertv(back != (EggBackPointer *)NULL);
return back->extend_to(num_frames);
}
////////////////////////////////////////////////////////////////////
// Function: EggComponentData::set_model
// Access: Public

View File

@ -45,7 +45,8 @@ public:
void add_name(const string &name);
bool matches_name(const string &name) const;
virtual int get_num_frames(int model_index) const=0;
int get_num_frames(int model_index) const;
void extend_to(int model_index, int num_frames) const;
virtual void add_back_pointer(int model_index, EggObject *egg_object)=0;
virtual void write(ostream &out, int indent_level = 0) const=0;

View File

@ -48,6 +48,32 @@ get_child(int n) const {
return _children[n];
}
////////////////////////////////////////////////////////////////////
// Function: EggJointData::has_rest_frame
// Access: Public
// Description: Returns true if the joint knows its rest frame, false
// otherwise. In general, this will be true as long as
// the joint is included in at least one model file, or
// false if it appears only in animation files.
////////////////////////////////////////////////////////////////////
INLINE bool EggJointData::
has_rest_frame() const {
return _has_rest_frame;
}
////////////////////////////////////////////////////////////////////
// Function: EggJointData::get_rest_frame
// Access: Public
// Description: Returns the rest frame of the joint. This is the
// matrix value that appears for the joint in each model
// file; it should be the same transform in each model.
////////////////////////////////////////////////////////////////////
INLINE const LMatrix4d &EggJointData::
get_rest_frame() const {
nassertr(has_rest_frame(), LMatrix4d::ident_mat());
return _rest_frame;
}
////////////////////////////////////////////////////////////////////
// Function: EggJointData::reparent_to
// Access: Public

View File

@ -40,6 +40,8 @@ EggJointData(EggCharacterCollection *collection,
{
_parent = (EggJointData *)NULL;
_new_parent = (EggJointData *)NULL;
_has_rest_frame = false;
_forced_rest_frames_equal = false;
}
////////////////////////////////////////////////////////////////////
@ -65,25 +67,6 @@ find_joint(const string &name) {
return (EggJointData *)NULL;
}
////////////////////////////////////////////////////////////////////
// Function: EggJointData::get_num_frames
// Access: Public, Virtual
// Description: Returns the number of frames of animation for this
// particular joint in the indicated model.
////////////////////////////////////////////////////////////////////
int EggJointData::
get_num_frames(int model_index) const {
EggBackPointer *back = get_model(model_index);
if (back == (EggBackPointer *)NULL) {
return 0;
}
EggJointPointer *joint;
DCAST_INTO_R(joint, back, 0);
return joint->get_num_frames();
}
////////////////////////////////////////////////////////////////////
// Function: EggJointData::get_frame
// Access: Public
@ -262,6 +245,30 @@ add_back_pointer(int model_index, EggObject *egg_object) {
// It must be a <Joint>.
EggJointNodePointer *joint = new EggJointNodePointer(egg_object);
set_model(model_index, joint);
if (!_has_rest_frame) {
_rest_frame = joint->get_frame(0);
_has_rest_frame = true;
} else {
// If this new node doesn't come within an acceptable tolerance
// of our first reading of this joint's rest frame, set a
// warning flag.
if (!_rest_frame.almost_equal(joint->get_frame(0), 0.001)) {
_forced_rest_frames_equal = true;
}
// In any case, ensure the rest frames are exactly equal.
// Actually, this may not be a good idea; it is, in fact, valid
// (although unusual) for different models to have different
// rest frames, provided their vertices appriopriately reflect
// the different rest frames. But we do have at least one
// character, Mickey, for which some of the lower-level LOD's
// have different rest frames that are in fact completely wrong,
// so forcing them all to the same value is correct in that
// case. Maybe this should be a command-line option.
joint->set_frame(0, _rest_frame);
}
} else if (egg_object->is_of_type(EggTable::get_class_type())) {
// It's a <Table> with an "xform" child beneath it.

View File

@ -43,10 +43,12 @@ public:
INLINE EggJointData *get_child(int n) const;
EggJointData *find_joint(const string &name);
virtual int get_num_frames(int model_index) const;
LMatrix4d get_frame(int model_index, int n) const;
LMatrix4d get_net_frame(int model_index, int n) const;
INLINE bool has_rest_frame() const;
INLINE const LMatrix4d &get_rest_frame() const;
INLINE void reparent_to(EggJointData *new_parent);
void move_vertices_to(EggJointData *new_owner);
@ -69,6 +71,10 @@ private:
const LMatrix4d &get_new_net_frame_inv(int model_index, int n);
LMatrix4d get_new_frame(int model_index, int n);
bool _has_rest_frame;
bool _forced_rest_frames_equal;
LMatrix4d _rest_frame;
// These are used to cache the above results for optimizing
// do_compute_reparent().
LMatrix4d _new_net_frame, _new_net_frame_inv;

View File

@ -74,6 +74,28 @@ get_num_frames() const {
}
}
////////////////////////////////////////////////////////////////////
// Function: EggMatrixTablePointer::extend_to
// Access: Public, Virtual
// Description: Extends the table to the indicated number of frames.
////////////////////////////////////////////////////////////////////
void EggMatrixTablePointer::
extend_to(int num_frames) {
nassertv(_xform != (EggXfmSAnim *)NULL);
_xform->normalize();
int num_rows = _xform->get_num_rows();
LMatrix4d last_mat;
if (num_rows == 0) {
last_mat = LMatrix4d::ident_mat();
} else {
_xform->get_value(num_rows - 1, last_mat);
}
while (num_rows < num_frames) {
_xform->add_data(last_mat);
}
}
////////////////////////////////////////////////////////////////////
// Function: EggMatrixTablePointer::get_frame
// Access: Public, Virtual

View File

@ -38,7 +38,8 @@ class EggMatrixTablePointer : public EggJointPointer {
public:
EggMatrixTablePointer(EggObject *object);
virtual int get_num_frames() const;
virtual int get_num_frames() const;
virtual void extend_to(int num_frames);
virtual LMatrix4d get_frame(int n) const;
virtual void set_frame(int n, const LMatrix4d &mat);
virtual bool add_frame(const LMatrix4d &mat);

View File

@ -47,6 +47,27 @@ get_num_frames() const {
}
}
////////////////////////////////////////////////////////////////////
// Function: EggScalarTablePointer::extend_to
// Access: Public, Virtual
// Description: Extends the table to the indicated number of frames.
////////////////////////////////////////////////////////////////////
void EggScalarTablePointer::
extend_to(int num_frames) {
nassertv(_data != (EggSAnimData *)NULL);
int num_rows = _data->get_num_rows();
double last_value;
if (num_rows == 0) {
last_value = 0.0;
} else {
last_value = _data->get_value(num_rows - 1);
}
while (num_rows < num_frames) {
_data->add_data(last_value);
}
}
////////////////////////////////////////////////////////////////////
// Function: EggScalarTablePointer::get_frame
// Access: Public, Virtual

View File

@ -38,6 +38,7 @@ public:
EggScalarTablePointer(EggObject *object);
virtual int get_num_frames() const;
virtual void extend_to(int num_frames);
virtual double get_frame(int n) const;
private:

View File

@ -40,25 +40,6 @@ EggSliderData(EggCharacterCollection *collection,
{
}
////////////////////////////////////////////////////////////////////
// Function: EggSliderData::get_num_frames
// Access: Public, Virtual
// Description: Returns the number of frames of animation for this
// particular slider in the indicated model.
////////////////////////////////////////////////////////////////////
int EggSliderData::
get_num_frames(int model_index) const {
EggBackPointer *back = get_model(model_index);
if (back == (EggBackPointer *)NULL) {
return 0;
}
EggSliderPointer *slider;
DCAST_INTO_R(slider, back, 0);
return slider->get_num_frames();
}
////////////////////////////////////////////////////////////////////
// Function: EggSliderData::get_frame
// Access: Public

View File

@ -19,7 +19,7 @@
#ifndef EGGSLIDERDATA_H
#define EGGSLIDERDATA_H
#include <pandatoolbase.h>
#include "pandatoolbase.h"
#include "eggComponentData.h"
@ -37,7 +37,6 @@ public:
EggSliderData(EggCharacterCollection *collection,
EggCharacterData *char_data);
virtual int get_num_frames(int model_index) const;
double get_frame(int model_index, int n) const;
virtual void add_back_pointer(int model_index, EggObject *egg_object);