diff --git a/pandatool/src/eggcharbase/eggBackPointer.cxx b/pandatool/src/eggcharbase/eggBackPointer.cxx index ad9cd8358b..700579a38f 100644 --- a/pandatool/src/eggcharbase/eggBackPointer.cxx +++ b/pandatool/src/eggcharbase/eggBackPointer.cxx @@ -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 diff --git a/pandatool/src/eggcharbase/eggBackPointer.h b/pandatool/src/eggcharbase/eggBackPointer.h index 830eddd2b9..d03e418ac8 100644 --- a/pandatool/src/eggcharbase/eggBackPointer.h +++ b/pandatool/src/eggcharbase/eggBackPointer.h @@ -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: diff --git a/pandatool/src/eggcharbase/eggCharacterCollection.cxx b/pandatool/src/eggcharbase/eggCharacterCollection.cxx index f5900b8a6f..cd546fc8ae 100644 --- a/pandatool/src/eggcharbase/eggCharacterCollection.cxx +++ b/pandatool/src/eggcharbase/eggCharacterCollection.cxx @@ -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"; + } + } + } +} diff --git a/pandatool/src/eggcharbase/eggCharacterCollection.h b/pandatool/src/eggcharbase/eggCharacterCollection.h index 9ca703aa55..85600b305c 100644 --- a/pandatool/src/eggcharbase/eggCharacterCollection.h +++ b/pandatool/src/eggcharbase/eggCharacterCollection.h @@ -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); diff --git a/pandatool/src/eggcharbase/eggCharacterData.I b/pandatool/src/eggcharbase/eggCharacterData.I index 630d5a4711..b71a4a5476 100644 --- a/pandatool/src/eggcharbase/eggCharacterData.I +++ b/pandatool/src/eggcharbase/eggCharacterData.I @@ -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 diff --git a/pandatool/src/eggcharbase/eggCharacterData.cxx b/pandatool/src/eggcharbase/eggCharacterData.cxx index 1788eff12b..baa2e089f0 100644 --- a/pandatool/src/eggcharbase/eggCharacterData.cxx +++ b/pandatool/src/eggcharbase/eggCharacterData.cxx @@ -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 diff --git a/pandatool/src/eggcharbase/eggCharacterData.h b/pandatool/src/eggcharbase/eggCharacterData.h index f5a6a95f81..0c53e1bb81 100644 --- a/pandatool/src/eggcharbase/eggCharacterData.h +++ b/pandatool/src/eggcharbase/eggCharacterData.h @@ -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 Models; Models _models; diff --git a/pandatool/src/eggcharbase/eggCharacterFilter.cxx b/pandatool/src/eggcharbase/eggCharacterFilter.cxx index aa19afd08b..77ffde1bc8 100644 --- a/pandatool/src/eggcharbase/eggCharacterFilter.cxx +++ b/pandatool/src/eggcharbase/eggCharacterFilter.cxx @@ -70,6 +70,8 @@ post_command_line() { } } + _collection->check_errors(nout); + return true; } diff --git a/pandatool/src/eggcharbase/eggCharacterFilter.h b/pandatool/src/eggcharbase/eggCharacterFilter.h index 6fb8b6ee53..607f3aac68 100644 --- a/pandatool/src/eggcharbase/eggCharacterFilter.h +++ b/pandatool/src/eggcharbase/eggCharacterFilter.h @@ -19,7 +19,7 @@ #ifndef EGGCHARACTERFILTER_H #define EGGCHARACTERFILTER_H -#include +#include "pandatoolbase.h" #include "eggMultiFilter.h" diff --git a/pandatool/src/eggcharbase/eggComponentData.cxx b/pandatool/src/eggcharbase/eggComponentData.cxx index 82e96fe5cb..dd991625eb 100644 --- a/pandatool/src/eggcharbase/eggComponentData.cxx +++ b/pandatool/src/eggcharbase/eggComponentData.cxx @@ -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 diff --git a/pandatool/src/eggcharbase/eggComponentData.h b/pandatool/src/eggcharbase/eggComponentData.h index 6a1db3abcd..1c063f0d24 100644 --- a/pandatool/src/eggcharbase/eggComponentData.h +++ b/pandatool/src/eggcharbase/eggComponentData.h @@ -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; diff --git a/pandatool/src/eggcharbase/eggJointData.I b/pandatool/src/eggcharbase/eggJointData.I index 8385916325..2046de71ea 100644 --- a/pandatool/src/eggcharbase/eggJointData.I +++ b/pandatool/src/eggcharbase/eggJointData.I @@ -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 diff --git a/pandatool/src/eggcharbase/eggJointData.cxx b/pandatool/src/eggcharbase/eggJointData.cxx index 93bff10443..7e43cff6b7 100644 --- a/pandatool/src/eggcharbase/eggJointData.cxx +++ b/pandatool/src/eggcharbase/eggJointData.cxx @@ -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 . 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 with an "xform" child beneath it. diff --git a/pandatool/src/eggcharbase/eggJointData.h b/pandatool/src/eggcharbase/eggJointData.h index 8955e7e758..e2506be24b 100644 --- a/pandatool/src/eggcharbase/eggJointData.h +++ b/pandatool/src/eggcharbase/eggJointData.h @@ -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; diff --git a/pandatool/src/eggcharbase/eggMatrixTablePointer.cxx b/pandatool/src/eggcharbase/eggMatrixTablePointer.cxx index 05d3eb7281..98281cb6b5 100644 --- a/pandatool/src/eggcharbase/eggMatrixTablePointer.cxx +++ b/pandatool/src/eggcharbase/eggMatrixTablePointer.cxx @@ -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 diff --git a/pandatool/src/eggcharbase/eggMatrixTablePointer.h b/pandatool/src/eggcharbase/eggMatrixTablePointer.h index f3470b3c77..4ed4c2b253 100644 --- a/pandatool/src/eggcharbase/eggMatrixTablePointer.h +++ b/pandatool/src/eggcharbase/eggMatrixTablePointer.h @@ -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); diff --git a/pandatool/src/eggcharbase/eggScalarTablePointer.cxx b/pandatool/src/eggcharbase/eggScalarTablePointer.cxx index cee0512284..a8f3d34367 100644 --- a/pandatool/src/eggcharbase/eggScalarTablePointer.cxx +++ b/pandatool/src/eggcharbase/eggScalarTablePointer.cxx @@ -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 diff --git a/pandatool/src/eggcharbase/eggScalarTablePointer.h b/pandatool/src/eggcharbase/eggScalarTablePointer.h index 2a6567fedf..23b42c635b 100644 --- a/pandatool/src/eggcharbase/eggScalarTablePointer.h +++ b/pandatool/src/eggcharbase/eggScalarTablePointer.h @@ -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: diff --git a/pandatool/src/eggcharbase/eggSliderData.cxx b/pandatool/src/eggcharbase/eggSliderData.cxx index 56146b468e..d1b667d205 100644 --- a/pandatool/src/eggcharbase/eggSliderData.cxx +++ b/pandatool/src/eggcharbase/eggSliderData.cxx @@ -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 diff --git a/pandatool/src/eggcharbase/eggSliderData.h b/pandatool/src/eggcharbase/eggSliderData.h index f6edec7d78..e8524b1283 100644 --- a/pandatool/src/eggcharbase/eggSliderData.h +++ b/pandatool/src/eggcharbase/eggSliderData.h @@ -19,7 +19,7 @@ #ifndef EGGSLIDERDATA_H #define EGGSLIDERDATA_H -#include +#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);