diff --git a/panda/src/chan/Sources.pp b/panda/src/chan/Sources.pp index ea3aa62887..27f8bebee0 100644 --- a/panda/src/chan/Sources.pp +++ b/panda/src/chan/Sources.pp @@ -9,30 +9,37 @@ #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx #define SOURCES \ - animBundle.I animBundle.h animBundleNode.I animBundleNode.h \ - animChannel.I animChannel.h animChannelBase.I \ - animChannelBase.h animChannelMatrixXfmTable.I \ - animChannelMatrixXfmTable.h animChannelScalarTable.I \ - animChannelScalarTable.h animControl.I animControl.N \ - animControl.h animControlCollection.I \ - animControlCollection.h animGroup.I animGroup.h auto_bind.h \ - config_chan.h movingPartBase.I movingPartBase.h \ - movingPartMatrix.I movingPartMatrix.h movingPartScalar.I \ - movingPartScalar.h partBundle.I partBundle.N partBundle.h \ - partBundleNode.I partBundleNode.h partGroup.I partGroup.h \ - vector_PartGroupStar.h + animBundle.I animBundle.h animBundleNode.I animBundleNode.h \ + qpanimBundleNode.I qpanimBundleNode.h \ + animChannel.I animChannel.h animChannelBase.I \ + animChannelBase.h animChannelMatrixXfmTable.I \ + animChannelMatrixXfmTable.h animChannelScalarTable.I \ + animChannelScalarTable.h animControl.I animControl.N \ + animControl.h animControlCollection.I \ + animControlCollection.h animGroup.I animGroup.h auto_bind.h \ + config_chan.h movingPartBase.I movingPartBase.h \ + movingPartMatrix.I movingPartMatrix.h movingPartScalar.I \ + movingPartScalar.h partBundle.I partBundle.N partBundle.h \ + partBundleNode.I partBundleNode.h \ + qppartBundleNode.I qppartBundleNode.h \ + partGroup.I partGroup.h \ + vector_PartGroupStar.h #define INCLUDED_SOURCES \ - animBundle.cxx animBundleNode.cxx animChannel.cxx \ - animChannelBase.cxx animChannelMatrixXfmTable.cxx \ - animChannelScalarTable.cxx animControl.cxx \ - animControlCollection.cxx animGroup.cxx auto_bind.cxx \ - config_chan.cxx movingPartBase.cxx movingPartMatrix.cxx \ - movingPartScalar.cxx partBundle.cxx partBundleNode.cxx \ - partGroup.cxx vector_PartGroupStar.cxx + animBundle.cxx animBundleNode.cxx \ + qpanimBundleNode.cxx \ + animChannel.cxx \ + animChannelBase.cxx animChannelMatrixXfmTable.cxx \ + animChannelScalarTable.cxx animControl.cxx \ + animControlCollection.cxx animGroup.cxx auto_bind.cxx \ + config_chan.cxx movingPartBase.cxx movingPartMatrix.cxx \ + movingPartScalar.cxx partBundle.cxx partBundleNode.cxx \ + qppartBundleNode.cxx \ + partGroup.cxx vector_PartGroupStar.cxx #define INSTALL_HEADERS \ animBundle.I animBundle.h animBundleNode.I animBundleNode.h \ + qpanimBundleNode.I qpanimBundleNode.h \ animChannel.I animChannel.h animChannelBase.I animChannelBase.h \ animChannelFixed.I animChannelFixed.h animChannelMatrixXfmTable.I \ animChannelMatrixXfmTable.h animChannelScalarTable.I \ @@ -42,7 +49,9 @@ movingPart.I movingPart.h movingPartBase.I \ movingPartBase.h movingPartMatrix.I movingPartMatrix.h \ movingPartScalar.I movingPartScalar.h partBundle.I partBundle.h \ - partBundleNode.I partBundleNode.h partGroup.I partGroup.h \ + partBundleNode.I partBundleNode.h \ + qppartBundleNode.I qppartBundleNode.h \ + partGroup.I partGroup.h \ vector_PartGroupStar.h #define IGATESCAN all diff --git a/panda/src/chan/auto_bind.cxx b/panda/src/chan/auto_bind.cxx index e3c3d5b593..42413742ab 100644 --- a/panda/src/chan/auto_bind.cxx +++ b/panda/src/chan/auto_bind.cxx @@ -17,17 +17,19 @@ //////////////////////////////////////////////////////////////////// +#include "auto_bind.h" +#include "qpanimBundleNode.h" +#include "qppartBundleNode.h" +#include "config_chan.h" +#include "string_utils.h" + #include "animBundleNode.h" #include "partBundleNode.h" -#include "config_chan.h" - -#include -#include -#include -#include -#include -#include -#include "auto_bind.h" +#include "renderRelation.h" +#include "traverserVisitor.h" +#include "dftraverser.h" +#include "nullLevelState.h" +#include "nullTransitionWrapper.h" typedef pset AnimNodes; typedef pmap Anims; @@ -36,7 +38,6 @@ typedef pset PartNodes; typedef pmap Parts; - //////////////////////////////////////////////////////////////////// // Class : CollectNodes // Description : This is a traverser visitor that locates bundle nodes @@ -133,8 +134,9 @@ bind_anims(const PartNodes &parts, const AnimNodes &anims, // The list of all resulting AnimControls created is // filled into controls. //////////////////////////////////////////////////////////////////// -void auto_bind(Node *root_node, AnimControlCollection &controls, - int hierarchy_match_flags) { +void +auto_bind(Node *root_node, AnimControlCollection &controls, + int hierarchy_match_flags) { // First, locate all the bundles in the subgraph. CollectNodes cn; @@ -169,3 +171,139 @@ void auto_bind(Node *root_node, AnimControlCollection &controls, } +typedef pset qpAnimNodes; +typedef pmap qpAnims; + +typedef pset qpPartNodes; +typedef pmap qpParts; + + +//////////////////////////////////////////////////////////////////// +// Function: bind_anims +// Description: A support function for auto_bind(), below. Given a +// set of AnimBundles and a set of PartBundles that all +// share the same name, perform whatever bindings make +// sense. +//////////////////////////////////////////////////////////////////// +static void +qpbind_anims(const qpPartNodes &parts, const qpAnimNodes &anims, + AnimControlCollection &controls, + int hierarchy_match_flags) { + + qpPartNodes::const_iterator pni; + + for (pni = parts.begin(); pni != parts.end(); ++pni) { + PartBundle *part = (*pni)->get_bundle(); + + qpAnimNodes::const_iterator ani; + for (ani = anims.begin(); ani != anims.end(); ++ani) { + AnimBundle *anim = (*ani)->get_bundle(); + + if (chan_cat.is_info()) { + chan_cat.info() + << "Attempting to bind " << *part << " to " << *anim << "\n"; + } + + PT(AnimControl) control = + part->bind_anim(anim, hierarchy_match_flags); + string name = anim->get_name(); + if (control != (AnimControl *)NULL) { + if (controls.find_anim(name) != (AnimControl *)NULL) { + // That name's already used; synthesize another one. + int index = 0; + string new_name; + do { + index++; + new_name = name + '.' + format_string(index); + } while (controls.find_anim(new_name) != (AnimControl *)NULL); + name = new_name; + } + + controls.store_anim(control, name); + } + + if (chan_cat.is_info()) { + if (control == NULL) { + chan_cat.info() + << "Bind failed.\n"; + } else { + chan_cat.info() + << "Bind succeeded, index " + << control->get_channel_index() << "; accessible as " + << name << "\n"; + } + } + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: r_find_bundles +// Description: A support function for auto_bind(), below. Walks +// through the hierarchy and finds all of the +// PartBundles and AnimBundles. +//////////////////////////////////////////////////////////////////// +static void +r_find_bundles(PandaNode *node, qpAnims &anims, qpParts &parts) { + if (node->is_of_type(qpAnimBundleNode::get_class_type())) { + qpAnimBundleNode *bn = DCAST(qpAnimBundleNode, node); + anims[bn->get_bundle()->get_name()].insert(bn); + + } else if (node->is_of_type(qpPartBundleNode::get_class_type())) { + qpPartBundleNode *bn = DCAST(qpPartBundleNode, node); + parts[bn->get_bundle()->get_name()].insert(bn); + } + + PandaNode::Children cr = node->get_children(); + int num_children = cr.get_num_children(); + for (int i = 0; i < num_children; i++) { + r_find_bundles(cr.get_child(i), anims, parts); + } +} + + +//////////////////////////////////////////////////////////////////// +// Function: auto_bind +// Description: Walks the scene graph or subgraph beginning at the +// indicated node, and attempts to bind any AnimBundles +// found to their matching PartBundles, when possible. +// +// The list of all resulting AnimControls created is +// filled into controls. +//////////////////////////////////////////////////////////////////// +void +auto_bind(PandaNode *root_node, AnimControlCollection &controls, + int hierarchy_match_flags) { + // First, locate all the bundles in the subgraph. + qpAnims anims; + qpParts parts; + r_find_bundles(root_node, anims, parts); + + // Now, match up the bundles by name. + + qpAnims::const_iterator ai = anims.begin(); + qpParts::const_iterator pi = parts.begin(); + + while (ai != anims.end() && pi != parts.end()) { + if ((*ai).first < (*pi).first) { + // Here's an anim with no matching parts. + ++ai; + + } else if ((*pi).first < (*ai).first) { + // And here's a part with no matching anims. + ++pi; + + } else { + // But here we have (at least one) match! + qpbind_anims((*pi).second, (*ai).second, controls, + hierarchy_match_flags); + ++pi; + + // We don't increment the anim counter yet. That way, the same + // anim may bind to multiple parts, if they all share the same + // name. + } + } +} + + diff --git a/panda/src/chan/auto_bind.h b/panda/src/chan/auto_bind.h index d8c50c149e..dc6fe88ac9 100644 --- a/panda/src/chan/auto_bind.h +++ b/panda/src/chan/auto_bind.h @@ -25,6 +25,7 @@ #include "animControlCollection.h" class Node; +class PandaNode; BEGIN_PUBLISH //////////////////////////////////////////////////////////////////// @@ -39,6 +40,10 @@ BEGIN_PUBLISH EXPCL_PANDA void auto_bind(Node *root_node, AnimControlCollection &controls, int hierarchy_match_flags = 0); + +EXPCL_PANDA void +auto_bind(PandaNode *root_node, AnimControlCollection &controls, + int hierarchy_match_flags = 0); END_PUBLISH #endif diff --git a/panda/src/chan/chan_composite1.cxx b/panda/src/chan/chan_composite1.cxx index b88ac72832..3bdb0a8e75 100644 --- a/panda/src/chan/chan_composite1.cxx +++ b/panda/src/chan/chan_composite1.cxx @@ -6,6 +6,7 @@ #include "movingPartScalar.cxx" #include "partBundle.cxx" #include "partBundleNode.cxx" +#include "qppartBundleNode.cxx" #include "partGroup.cxx" #include "vector_PartGroupStar.cxx" diff --git a/panda/src/chan/chan_composite2.cxx b/panda/src/chan/chan_composite2.cxx index c501eca931..04ce04840d 100644 --- a/panda/src/chan/chan_composite2.cxx +++ b/panda/src/chan/chan_composite2.cxx @@ -1,6 +1,7 @@ #include "animBundle.cxx" #include "animBundleNode.cxx" +#include "qpanimBundleNode.cxx" #include "animChannel.cxx" #include "animChannelBase.cxx" #include "animChannelMatrixXfmTable.cxx" diff --git a/panda/src/chan/config_chan.cxx b/panda/src/chan/config_chan.cxx index 9ae0e2e6f9..af3933fa52 100644 --- a/panda/src/chan/config_chan.cxx +++ b/panda/src/chan/config_chan.cxx @@ -20,6 +20,7 @@ #include "config_chan.h" #include "animBundle.h" #include "animBundleNode.h" +#include "qpanimBundleNode.h" #include "animChannelBase.h" #include "animChannelMatrixXfmTable.h" #include "animChannelScalarTable.h" @@ -30,10 +31,11 @@ #include "movingPartScalar.h" #include "partBundle.h" #include "partBundleNode.h" +#include "qppartBundleNode.h" #include "partGroup.h" -#include -#include +#include "luse.h" +#include "dconfig.h" Configure(config_chan); NotifyCategoryDef(chan, ""); @@ -79,6 +81,7 @@ bool read_compressed_channels = config_chan.GetBool("read-compressed-channels", ConfigureFn(config_chan) { AnimBundle::init_type(); AnimBundleNode::init_type(); + qpAnimBundleNode::init_type(); AnimChannelBase::init_type(); AnimChannelMatrixXfmTable::init_type(); AnimChannelScalarTable::init_type(); @@ -89,6 +92,7 @@ ConfigureFn(config_chan) { MovingPartScalar::init_type(); PartBundle::init_type(); PartBundleNode::init_type(); + qpPartBundleNode::init_type(); PartGroup::init_type(); // This isn't defined in this package, but it *is* essential that it @@ -107,6 +111,7 @@ ConfigureFn(config_chan) { AnimGroup::register_with_read_factory(); AnimBundle::register_with_read_factory(); AnimBundleNode::register_with_read_factory(); + qpAnimBundleNode::register_with_read_factory(); AnimChannelMatrixXfmTable::register_with_read_factory(); AnimChannelScalarTable::register_with_read_factory(); } diff --git a/panda/src/chan/partBundle.I b/panda/src/chan/partBundle.I index b63aabb11b..f78889eb7d 100644 --- a/panda/src/chan/partBundle.I +++ b/panda/src/chan/partBundle.I @@ -39,6 +39,17 @@ get_node() const { return _node; } +//////////////////////////////////////////////////////////////////// +// Function: PartBundle::get_qpnode +// Access: Published +// Description: Returns the PartBundleNode associated with this +// PartBundle. +//////////////////////////////////////////////////////////////////// +INLINE qpPartBundleNode *PartBundle:: +get_qpnode() const { + return _qpnode; +} + //////////////////////////////////////////////////////////////////// // Function: PartBundle::control_begin // Access: Public diff --git a/panda/src/chan/partBundle.h b/panda/src/chan/partBundle.h index 5aa7e16f64..607078f3cf 100644 --- a/panda/src/chan/partBundle.h +++ b/panda/src/chan/partBundle.h @@ -19,17 +19,18 @@ #ifndef PARTBUNDLE_H #define PARTBUNDLE_H -#include +#include "pandabase.h" #include "partGroup.h" #include "animControl.h" #include "animControlCollection.h" -#include -#include +#include "pointerTo.h" +#include "iterator_types.h" class AnimBundle; class PartBundleNode; +class qpPartBundleNode; //////////////////////////////////////////////////////////////////// // Class : PartBundle @@ -93,6 +94,7 @@ PUBLISHED: INLINE BlendType get_blend_type() const; INLINE PartBundleNode *get_node() const; + INLINE qpPartBundleNode *get_qpnode() const; void clear_control_effects(); void set_control_effect(AnimControl *control, float effect); @@ -131,6 +133,7 @@ protected: BlendType _blend_type; PartBundleNode *_node; + qpPartBundleNode *_qpnode; AnimControl *_last_control_set; ChannelBlend _blend; @@ -162,6 +165,7 @@ private: static TypeHandle _type_handle; friend class PartBundleNode; + friend class qpPartBundleNode; }; inline ostream &operator <<(ostream &out, const PartBundle &bundle) { diff --git a/panda/src/chan/partGroup.h b/panda/src/chan/partGroup.h index a4a24a6cac..3a3fae91ff 100644 --- a/panda/src/chan/partGroup.h +++ b/panda/src/chan/partGroup.h @@ -130,6 +130,7 @@ private: static TypeHandle _type_handle; friend class Character; + friend class qpCharacter; }; #include "partGroup.I" diff --git a/panda/src/chan/qpanimBundleNode.I b/panda/src/chan/qpanimBundleNode.I new file mode 100644 index 0000000000..207b17330b --- /dev/null +++ b/panda/src/chan/qpanimBundleNode.I @@ -0,0 +1,67 @@ +// Filename: qpanimBundleNode.I +// Created by: drose (06Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// 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 . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: qpAnimBundleNode::Constructor +// Access: Public +// Description: The AnimBundle and its node should be constructed +// together. Generally, the derived classes of +// qpAnimBundleNode will automatically create a AnimBundle +// of the appropriate type, and pass it up to this +// constructor. +//////////////////////////////////////////////////////////////////// +INLINE qpAnimBundleNode:: +qpAnimBundleNode(const string &name, AnimBundle *bundle) : + PandaNode(name), + _bundle(bundle) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: qpAnimBundleNode::Default Constructor +// Access: Protected +// Description: For internal use only. +//////////////////////////////////////////////////////////////////// +INLINE qpAnimBundleNode:: +qpAnimBundleNode() : PandaNode("") { +} + +//////////////////////////////////////////////////////////////////// +// Function: qpAnimBundleNode::Copy Constructor +// Access: Protected +// Description: Use make_copy() or copy_subgraph() to copy one of +// these. Copying a qpAnimBundleNode will always force a +// deep copy of the PartGroup hierarchy. +//////////////////////////////////////////////////////////////////// +INLINE qpAnimBundleNode:: +qpAnimBundleNode(const qpAnimBundleNode ©) : + PandaNode(copy), + _bundle(copy._bundle) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: qpAnimBundleNode::get_bundle +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE AnimBundle *qpAnimBundleNode:: +get_bundle() const { + return _bundle; +} diff --git a/panda/src/chan/qpanimBundleNode.cxx b/panda/src/chan/qpanimBundleNode.cxx new file mode 100644 index 0000000000..47d183db17 --- /dev/null +++ b/panda/src/chan/qpanimBundleNode.cxx @@ -0,0 +1,110 @@ +// Filename: qpanimBundleNode.cxx +// Created by: drose (06Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// 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 "qpanimBundleNode.h" +#include "datagram.h" +#include "datagramIterator.h" +#include "bamReader.h" +#include "bamWriter.h" + +TypeHandle qpAnimBundleNode::_type_handle; + + +//////////////////////////////////////////////////////////////////// +// Function: qpAnimBundleNode::safe_to_flatten +// Access: Public, Virtual +// Description: Returns true if it is generally safe to flatten out +// this particular kind of Node by duplicating +// instances, false otherwise (for instance, a Camera +// cannot be safely flattened, because the Camera +// pointer itself is meaningful). +//////////////////////////////////////////////////////////////////// +bool qpAnimBundleNode:: +safe_to_flatten() const { + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpAnimBundleNode::register_with_read_factory +// Access: Public, Static +// Description: Tells the BamReader how to create objects of type +// qpAnimBundleNode. +//////////////////////////////////////////////////////////////////// +void qpAnimBundleNode:: +register_with_read_factory() { + BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpAnimBundleNode::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void qpAnimBundleNode:: +write_datagram(BamWriter *manager, Datagram &dg) { + PandaNode::write_datagram(manager, dg); + manager->write_pointer(dg, _bundle); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpAnimBundleNode::complete_pointers +// Access: Public, Virtual +// Description: Receives an array of pointers, one for each time +// manager->read_pointer() was called in fillin(). +// Returns the number of pointers processed. +//////////////////////////////////////////////////////////////////// +int qpAnimBundleNode:: +complete_pointers(TypedWritable **p_list, BamReader* manager) { + int pi = PandaNode::complete_pointers(p_list, manager); + _bundle = DCAST(AnimBundle, p_list[pi++]); + return pi; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpAnimBundleNode::make_from_bam +// Access: Protected, Static +// Description: This function is called by the BamReader's factory +// when a new object of this type is encountered +// in the Bam file. It should create the object +// and extract its information from the file. +//////////////////////////////////////////////////////////////////// +TypedWritable *qpAnimBundleNode:: +make_from_bam(const FactoryParams ¶ms) { + qpAnimBundleNode *node = new qpAnimBundleNode; + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + node->fillin(scan, manager); + + return node; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpAnimBundleNode::fillin +// Access: Protected +// Description: This internal function is called by make_from_bam to +// read in all of the relevant data from the BamFile for +// the new PandaNode. +//////////////////////////////////////////////////////////////////// +void qpAnimBundleNode:: +fillin(DatagramIterator &scan, BamReader* manager) { + PandaNode::fillin(scan, manager); + manager->read_pointer(scan, this); +} diff --git a/panda/src/chan/qpanimBundleNode.h b/panda/src/chan/qpanimBundleNode.h new file mode 100644 index 0000000000..96e8011cfe --- /dev/null +++ b/panda/src/chan/qpanimBundleNode.h @@ -0,0 +1,82 @@ +// Filename: qpanimBundleNode.h +// Created by: drose (06Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// 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 . +// +//////////////////////////////////////////////////////////////////// + +#ifndef qpANIMBUNDLENODE_H +#define qpANIMBUNDLENODE_H + +#include "pandabase.h" + +#include "animBundle.h" + +#include "pandaNode.h" +#include "dcast.h" + +//////////////////////////////////////////////////////////////////// +// Class : qpAnimBundleNode +// Description : This is a node that contains a pointer to an +// AnimBundle. Like AnimBundleNode, it exists solely to +// make it easy to store AnimBundles in the scene graph. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA qpAnimBundleNode : public PandaNode { +public: + INLINE qpAnimBundleNode(const string &name, AnimBundle *bundle); + +protected: + INLINE qpAnimBundleNode(); + INLINE qpAnimBundleNode(const qpAnimBundleNode ©); + +public: + virtual bool safe_to_flatten() const; + +PUBLISHED: + INLINE AnimBundle *get_bundle() const; + +private: + PT(AnimBundle) _bundle; + +public: + static void register_with_read_factory(); + virtual void write_datagram(BamWriter* manager, Datagram &me); + virtual int complete_pointers(TypedWritable **p_list, + BamReader *manager); + +protected: + static TypedWritable *make_from_bam(const FactoryParams ¶ms); + void fillin(DatagramIterator& scan, BamReader* manager); + +public: + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + PandaNode::init_type(); + register_type(_type_handle, "qpAnimBundleNode", + PandaNode::get_class_type()); + } + +private: + static TypeHandle _type_handle; +}; + +#include "qpanimBundleNode.I" + +#endif diff --git a/panda/src/chan/qppartBundleNode.I b/panda/src/chan/qppartBundleNode.I new file mode 100644 index 0000000000..d3ed25305a --- /dev/null +++ b/panda/src/chan/qppartBundleNode.I @@ -0,0 +1,69 @@ +// Filename: qppartBundleNode.I +// Created by: drose (06Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// 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 . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: qpPartBundleNode::Constructor +// Access: Public +// Description: The PartBundle and its node should be constructed +// together. Generally, the derived classes of +// qpPartBundleNode will automatically create a PartBundle +// of the appropriate type, and pass it up to this +// constructor. +//////////////////////////////////////////////////////////////////// +INLINE qpPartBundleNode:: +qpPartBundleNode(const string &name, PartBundle *bundle) : + PandaNode(name), + _bundle(bundle) +{ + _bundle->_qpnode = this; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpPartBundleNode::Default Constructor +// Access: Protected +// Description: For internal use only. +//////////////////////////////////////////////////////////////////// +INLINE qpPartBundleNode:: +qpPartBundleNode() : PandaNode("") { +} + +//////////////////////////////////////////////////////////////////// +// Function: qpPartBundleNode::Copy Constructor +// Access: Protected +// Description: Use make_copy() or copy_subgraph() to copy one of +// these. Copying a qpPartBundleNode will always force a +// deep copy of the PartGroup hierarchy. +//////////////////////////////////////////////////////////////////// +INLINE qpPartBundleNode:: +qpPartBundleNode(const qpPartBundleNode ©) : + PandaNode(copy), + _bundle(DCAST(PartBundle, copy._bundle->copy_subgraph())) +{ + _bundle->_qpnode = this; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpPartBundleNode::get_bundle +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PartBundle *qpPartBundleNode:: +get_bundle() const { + return _bundle; +} diff --git a/panda/src/chan/qppartBundleNode.cxx b/panda/src/chan/qppartBundleNode.cxx new file mode 100644 index 0000000000..9b93119878 --- /dev/null +++ b/panda/src/chan/qppartBundleNode.cxx @@ -0,0 +1,80 @@ +// Filename: qppartBundleNode.cxx +// Created by: drose (06Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// 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 "qppartBundleNode.h" +#include "datagram.h" +#include "datagramIterator.h" +#include "bamReader.h" +#include "bamWriter.h" + +TypeHandle qpPartBundleNode::_type_handle; + + +//////////////////////////////////////////////////////////////////// +// Function: qpPartBundleNode::safe_to_flatten +// Access: Public, Virtual +// Description: Returns true if it is generally safe to flatten out +// this particular kind of Node by duplicating +// instances, false otherwise (for instance, a Camera +// cannot be safely flattened, because the Camera +// pointer itself is meaningful). +//////////////////////////////////////////////////////////////////// +bool qpPartBundleNode:: +safe_to_flatten() const { + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpPartBundleNode::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void qpPartBundleNode:: +write_datagram(BamWriter *manager, Datagram &dg) { + PandaNode::write_datagram(manager, dg); + manager->write_pointer(dg, _bundle); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpPartBundleNode::complete_pointers +// Access: Public, Virtual +// Description: Receives an array of pointers, one for each time +// manager->read_pointer() was called in fillin(). +// Returns the number of pointers processed. +//////////////////////////////////////////////////////////////////// +int qpPartBundleNode:: +complete_pointers(TypedWritable **p_list, BamReader* manager) { + int pi = PandaNode::complete_pointers(p_list, manager); + _bundle = DCAST(PartBundle, p_list[pi++]); + _bundle->_qpnode = this; + return pi; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpPartBundleNode::fillin +// Access: Protected +// Description: This internal function is called by make_from_bam to +// read in all of the relevant data from the BamFile for +// the new PandaNode. +//////////////////////////////////////////////////////////////////// +void qpPartBundleNode:: +fillin(DatagramIterator &scan, BamReader* manager) { + PandaNode::fillin(scan, manager); + manager->read_pointer(scan, this); +} diff --git a/panda/src/chan/qppartBundleNode.h b/panda/src/chan/qppartBundleNode.h new file mode 100644 index 0000000000..5f4e6daf89 --- /dev/null +++ b/panda/src/chan/qppartBundleNode.h @@ -0,0 +1,80 @@ +// Filename: qppartBundleNode.h +// Created by: drose (06Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// 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 . +// +//////////////////////////////////////////////////////////////////// + +#ifndef qpPARTBUNDLENODE_H +#define qpPARTBUNDLENODE_H + +#include "pandabase.h" + +#include "partBundle.h" + +#include "pandaNode.h" +#include "dcast.h" + +//////////////////////////////////////////////////////////////////// +// Class : qpPartBundleNode +// Description : This is a node that contains a pointer to an +// PartBundle. Like AnimBundleNode, it exists solely to +// make it easy to store PartBundles in the scene graph. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA qpPartBundleNode : public PandaNode { +public: + INLINE qpPartBundleNode(const string &name, PartBundle *bundle); + +protected: + INLINE qpPartBundleNode(); + INLINE qpPartBundleNode(const qpPartBundleNode ©); + +public: + virtual bool safe_to_flatten() const; + +PUBLISHED: + INLINE PartBundle *get_bundle() const; + +private: + PT(PartBundle) _bundle; + +public: + virtual void write_datagram(BamWriter* manager, Datagram &me); + virtual int complete_pointers(TypedWritable **p_list, + BamReader *manager); + +protected: + void fillin(DatagramIterator& scan, BamReader* manager); + +public: + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + PandaNode::init_type(); + register_type(_type_handle, "qpPartBundleNode", + PandaNode::get_class_type()); + } + +private: + static TypeHandle _type_handle; +}; + +#include "qppartBundleNode.I" + +#endif diff --git a/panda/src/char/Sources.pp b/panda/src/char/Sources.pp index ccc163fea4..bed5800523 100644 --- a/panda/src/char/Sources.pp +++ b/panda/src/char/Sources.pp @@ -10,19 +10,25 @@ #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx #define SOURCES \ - character.I character.h characterJoint.h characterJointBundle.I \ - characterJointBundle.h characterSlider.h computedVertices.I \ - computedVertices.h computedVerticesMorph.I \ - computedVerticesMorph.h config_char.h dynamicVertices.h + character.I character.h \ + qpcharacter.I qpcharacter.h \ + characterJoint.h characterJointBundle.I \ + characterJointBundle.h characterSlider.h computedVertices.I \ + computedVertices.h computedVerticesMorph.I \ + computedVerticesMorph.h config_char.h dynamicVertices.h #define INCLUDED_SOURCES \ - character.cxx characterJoint.cxx characterJointBundle.cxx \ - characterSlider.cxx computedVertices.cxx \ - computedVerticesMorph.cxx config_char.cxx \ - dynamicVertices.cxx + character.cxx \ + qpcharacter.cxx \ + characterJoint.cxx characterJointBundle.cxx \ + characterSlider.cxx computedVertices.cxx \ + computedVerticesMorph.cxx config_char.cxx \ + dynamicVertices.cxx #define INSTALL_HEADERS \ - character.I character.h characterJoint.h characterJointBundle.I \ + character.I character.h \ + qpcharacter.I qpcharacter.h \ + characterJoint.h characterJointBundle.I \ characterJointBundle.h characterSlider.h computedVertices.I \ computedVertices.h computedVerticesMorph.I computedVerticesMorph.h \ config_char.h dynamicVertices.h diff --git a/panda/src/char/char_composite1.cxx b/panda/src/char/char_composite1.cxx index 1fc52363d8..588f214fba 100644 --- a/panda/src/char/char_composite1.cxx +++ b/panda/src/char/char_composite1.cxx @@ -1,6 +1,7 @@ #include "config_char.cxx" #include "character.cxx" +#include "qpcharacter.cxx" #include "characterJoint.cxx" #include "characterJointBundle.cxx" diff --git a/panda/src/char/characterJoint.h b/panda/src/char/characterJoint.h index 1925f4ae73..569b4f5406 100644 --- a/panda/src/char/characterJoint.h +++ b/panda/src/char/characterJoint.h @@ -82,6 +82,7 @@ public: // character. It does not store any meaningful value after // creation is complete. PT_NamedNode _geom_node; + PT(PandaNode) _qpgeom_node; // These are filled in as the joint animates. LMatrix4f _net_transform; diff --git a/panda/src/char/computedVertices.cxx b/panda/src/char/computedVertices.cxx index 0ad061bc10..d4a258944e 100644 --- a/panda/src/char/computedVertices.cxx +++ b/panda/src/char/computedVertices.cxx @@ -20,6 +20,7 @@ #include "computedVertices.h" #include "characterJoint.h" #include "character.h" +#include "qpcharacter.h" #include "config_char.h" #include @@ -53,28 +54,29 @@ VertexTransform(const VertexTransform ©) : // vertices in the table, according to the values of the // relevant slider. //////////////////////////////////////////////////////////////////// -template +// QP +template static void compute_morphs(ValueType *table, const pvector &morph_list, - Character *character) { + Character *character) { pvector::const_iterator mli; for (mli = morph_list.begin(); mli != morph_list.end(); ++mli) { const MorphType &morph = (*mli); const CharacterSlider *slider; DCAST_INTO_V(slider, character->get_part(morph._slider_index)); - + float slider_value = slider->_value; - + if (slider_value != 0.0f) { typedef TYPENAME MorphType::Morphs Morphs; typedef TYPENAME MorphType::MorphValue MorphValue; TYPENAME Morphs::const_iterator mi; for (mi = morph._morphs.begin(); mi != morph._morphs.end(); ++mi) { - typedef typename MorphValue::VecType VecType; - ushort index = (*mi)._index; - const VecType &v = (*mi)._vector; - - table[index] += v * slider_value; + typedef typename MorphValue::VecType VecType; + ushort index = (*mi)._index; + const VecType &v = (*mi)._vector; + + table[index] += v * slider_value; } } } @@ -229,6 +231,108 @@ update(Character *character) { } } +//////////////////////////////////////////////////////////////////// +// Function: ComputedVertices::update +// Access: Public +// Description: Recomputes all of the _coords, _norms, etc. values +// based on the values in _orig_coords, _orig_norms, +// etc., and the current positions of all of the joints. +//////////////////////////////////////////////////////////////////// +void ComputedVertices:: +update(qpCharacter *character) { + nassertv(character != (qpCharacter *)NULL); + nassertv(character->_cv._coords.size() == _orig_coords.size()); + nassertv(character->_cv._norms.size() == _orig_norms.size()); + nassertv(character->_cv._texcoords.size() == _orig_texcoords.size()); + nassertv(character->_cv._colors.size() == _orig_colors.size()); + + const Vertexf *orig_coords = _orig_coords; + const Normalf *orig_norms = _orig_norms; + + memset(character->_cv._coords, 0, sizeof(Vertexf) * character->_cv._coords.size()); + memset(character->_cv._norms, 0, sizeof(Normalf) * character->_cv._norms.size()); + + if (!_vertex_morphs.empty()) { + // We have some vertex morphs. Compute them first. + int table_size = sizeof(Vertexf) * _orig_coords.size(); + Vertexf *morphed_coords = (Vertexf *)alloca(table_size); + memcpy(morphed_coords, _orig_coords, table_size); + + compute_morphs(morphed_coords, _vertex_morphs, character); + orig_coords = morphed_coords; + } + + if (!_normal_morphs.empty()) { + // We also have some normal morphs. Compute them too. + int table_size = sizeof(Normalf) * _orig_norms.size(); + Normalf *morphed_norms = (Normalf *)alloca(table_size); + memcpy(morphed_norms, _orig_norms, table_size); + + compute_morphs(morphed_norms, _normal_morphs, character); + orig_norms = morphed_norms; + } + + if (!_texcoord_morphs.empty()) { + // We have some uv morphs. These don't particularly need to be + // done before the joints are computed, but do them now anyway. + int table_size = sizeof(TexCoordf) * _orig_texcoords.size(); + + // **** Is this right? Test it! + // TexCoordf *morphed_texcoords = (TexCoordf *)alloca(table_size); + memcpy(character->_cv._texcoords, _orig_texcoords, table_size); + + compute_morphs(character->_cv._texcoords.p(), _texcoord_morphs, character); + } + + if (!_color_morphs.empty()) { + // We have some color morphs. Do these now too. + int table_size = sizeof(Colorf) * _orig_colors.size(); + + // **** Is this right? Test it! + // Colorf *morphed_colors = (Colorf *)alloca(table_size); + memcpy(character->_cv._colors, _orig_colors, table_size); + + compute_morphs(character->_cv._colors.p(), _color_morphs, character); + } + + // Now that we've computed all the morphs, it's safe to transform + // vertices into their proper coordinate space, according to the + // current positions of all the joints. + + LMatrix4f mat = LMatrix4f::ident_mat(); + int last_joint_index = -1; + + VertexTransforms::const_iterator vti; + for (vti = _transforms.begin(); vti != _transforms.end(); ++vti) { + const VertexTransform &vt = (*vti); + + // We cache the matrix from the last joint, because we are likely + // to encounter the same joint several times in a row. + if (vt._joint_index != last_joint_index) { + last_joint_index = vt._joint_index; + + // We won't encounter -1 after the first few joints. + nassertv(vt._joint_index >= 0); + CharacterJoint *joint; + DCAST_INTO_V(joint, character->get_part(vt._joint_index)); + + mat = + joint->_initial_net_transform_inverse * + joint->_net_transform; + } + + Vertices::const_iterator vi; + for (vi = vt._vindex.begin(); vi != vt._vindex.end(); ++vi) { + int i = (*vi); + character->_cv._coords[i] += (orig_coords[i] * mat) * vt._effect; + } + for (vi = vt._nindex.begin(); vi != vt._nindex.end(); ++vi) { + int i = (*vi); + character->_cv._norms[i] += (orig_norms[i] * mat) * vt._effect; + } + } +} + //////////////////////////////////////////////////////////////////// // Function: ComputedVertices::make_orig // Access: Public @@ -269,6 +373,46 @@ make_orig(Character *character) { } } +//////////////////////////////////////////////////////////////////// +// Function: ComputedVertices::make_orig +// Access: Public +// Description: Copies all the values loaded in the _coords, _norms, +// etc. arrays into the corresponding _orig_coords, +// etc. arrays. +//////////////////////////////////////////////////////////////////// +void ComputedVertices:: +make_orig(qpCharacter *character) { + nassertv(character != (qpCharacter *)NULL); + + if (character->_cv._coords.empty()) { + _orig_coords.clear(); + } else { + _orig_coords = PTA_Vertexf::empty_array(0); + _orig_coords.v() = character->_cv._coords.v(); + } + + if (character->_cv._norms.empty()) { + _orig_norms.clear(); + } else { + _orig_norms = PTA_Normalf::empty_array(0); + _orig_norms.v() = character->_cv._norms.v(); + } + + if (character->_cv._colors.empty()) { + _orig_colors.clear(); + } else { + _orig_colors = PTA_Colorf::empty_array(0); + _orig_colors.v() = character->_cv._colors.v(); + } + + if (character->_cv._texcoords.empty()) { + _orig_texcoords.clear(); + } else { + _orig_texcoords = PTA_TexCoordf::empty_array(0); + _orig_texcoords.v() = character->_cv._texcoords.v(); + } +} + //////////////////////////////////////////////////////////////////// // Function: ComputedVertices::write // Access: Public diff --git a/panda/src/char/computedVertices.h b/panda/src/char/computedVertices.h index 1f425dc982..5a81d09148 100644 --- a/panda/src/char/computedVertices.h +++ b/panda/src/char/computedVertices.h @@ -19,15 +19,16 @@ #ifndef COMPUTEDVERTICES_H #define COMPUTEDVERTICES_H -#include +#include "pandabase.h" #include "dynamicVertices.h" #include "computedVerticesMorph.h" -#include -#include +#include "vector_ushort.h" +#include "typedWritableReferenceCount.h" class Character; +class qpCharacter; class CharacterJoint; //////////////////////////////////////////////////////////////////// @@ -42,7 +43,9 @@ public: INLINE ComputedVertices(); void update(Character *character); + void update(qpCharacter *character); void make_orig(Character *character); + void make_orig(qpCharacter *character); void write(ostream &out, Character *character) const; diff --git a/panda/src/char/config_char.cxx b/panda/src/char/config_char.cxx index 6d6af7d0f9..02cec32870 100644 --- a/panda/src/char/config_char.cxx +++ b/panda/src/char/config_char.cxx @@ -19,6 +19,7 @@ #include "config_char.h" #include "character.h" +#include "qpcharacter.h" #include "characterJoint.h" #include "characterJointBundle.h" #include "characterSlider.h" @@ -67,6 +68,7 @@ init_libchar() { initialized = true; Character::init_type(); + qpCharacter::init_type(); CharacterJoint::init_type(); CharacterJointBundle::init_type(); CharacterSlider::init_type(); @@ -82,6 +84,7 @@ init_libchar() { //Registration of writeable object's creation //functions with BamReader's factory Character::register_with_read_factory(); + qpCharacter::register_with_read_factory(); CharacterJoint::register_with_read_factory(); CharacterJointBundle::register_with_read_factory(); CharacterSlider::register_with_read_factory(); diff --git a/panda/src/char/qpcharacter.I b/panda/src/char/qpcharacter.I new file mode 100644 index 0000000000..ae4cc3654e --- /dev/null +++ b/panda/src/char/qpcharacter.I @@ -0,0 +1,87 @@ +// Filename: qpcharacter.I +// Created by: drose (06Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// 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 "characterJointBundle.h" + +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::get_bundle +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE CharacterJointBundle *qpCharacter:: +get_bundle() const { + return DCAST(CharacterJointBundle, qpPartBundleNode::get_bundle()); +} + + +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::get_computed_vertices +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE ComputedVertices *qpCharacter:: +get_computed_vertices() const { + return _computed_vertices; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::get_num_parts +// Access: Public +// Description: Returns the total number of moving parts (e.g. joints +// and sliders) associated with the qpCharacter. +//////////////////////////////////////////////////////////////////// +INLINE int qpCharacter:: +get_num_parts() const { + return _parts.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::get_part +// Access: Public +// Description: Returns the nth moving part associated with the +// qpCharacter. +//////////////////////////////////////////////////////////////////// +INLINE PartGroup *qpCharacter:: +get_part(int n) const { + nassertr(n >= 0 && n < (int)_parts.size(), NULL); + return _parts[n]; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::write_parts +// Access: Public +// Description: Writes a list of the qpCharacter's joints and sliders, +// in their hierchical structure, to the indicated +// output stream. +//////////////////////////////////////////////////////////////////// +INLINE void qpCharacter:: +write_parts(ostream &out) const { + get_bundle()->write(out, 0); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::write_part_values +// Access: Public +// Description: Writes a list of the qpCharacter's joints and sliders, +// along with each current position, in their hierchical +// structure, to the indicated output stream. +//////////////////////////////////////////////////////////////////// +INLINE void qpCharacter:: +write_part_values(ostream &out) const { + get_bundle()->write_with_value(out, 0); +} diff --git a/panda/src/char/qpcharacter.cxx b/panda/src/char/qpcharacter.cxx new file mode 100644 index 0000000000..5fc9076f1b --- /dev/null +++ b/panda/src/char/qpcharacter.cxx @@ -0,0 +1,538 @@ +// Filename: qpcharacter.cxx +// Created by: drose (06Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// 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 "qpcharacter.h" +#include "characterJoint.h" +#include "computedVertices.h" +#include "config_char.h" + +#include "geomNode.h" +#include "datagram.h" +#include "datagramIterator.h" +#include "bamReader.h" +#include "bamWriter.h" +#include "pStatTimer.h" +#include "geomNode.h" +#include "animControl.h" +#include "clockObject.h" +#include "pStatTimer.h" + +TypeHandle qpCharacter::_type_handle; + +#ifndef CPPPARSER +PStatCollector qpCharacter::_anim_pcollector("App:Animation"); +#endif + +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::Copy Constructor +// Access: Protected +// Description: Use make_copy() or copy_subgraph() to copy a qpCharacter. +//////////////////////////////////////////////////////////////////// +qpCharacter:: +qpCharacter(const qpCharacter ©) : + qpPartBundleNode(copy.get_name(), new CharacterJointBundle(copy.get_bundle()->get_name())), + _cv(DynamicVertices::deep_copy(copy._cv)), + _computed_vertices(copy._computed_vertices), + _parts(copy._parts), + _char_pcollector(copy._char_pcollector) +{ + // Now make a copy of the joint/slider hierarchy. We could just use + // the PartBundleNode's copy constructor, but if we do it ourselves + // we can simultaneously update our _parts list. + + copy_joints(get_bundle(), copy.get_bundle()); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +qpCharacter:: +qpCharacter(const string &name) : + qpPartBundleNode(name, new CharacterJointBundle(name)), + _char_pcollector(_anim_pcollector, name) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +qpCharacter:: +~qpCharacter() { +} + +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::make_copy +// Access: Public, Virtual +// Description: The qpCharacter make_copy() function will make a new +// copy of the qpCharacter, with all of its joints copied, +// and with a new set of dynamic vertex arrays all ready +// to go, but it will not copy any of the original +// qpCharacter's geometry, so the new qpCharacter won't look +// like much. Use copy_subgraph() to make a full copy +// of the qpCharacter. +//////////////////////////////////////////////////////////////////// +PandaNode *qpCharacter:: +make_copy() const { + return new qpCharacter(*this); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::safe_to_transform +// Access: Public, Virtual +// Description: Returns true if it is generally safe to transform +// this particular kind of Node by calling the xform() +// method, false otherwise. For instance, it's usually +// a bad idea to attempt to xform a qpCharacter. +//////////////////////////////////////////////////////////////////// +bool qpCharacter:: +safe_to_transform() const { + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::has_cull_callback +// Access: Public, Virtual +// Description: Should be overridden by derived classes to return +// true if cull_callback() has been defined. Otherwise, +// returns false to indicate cull_callback() does not +// need to be called for this node during the cull +// traversal. +//////////////////////////////////////////////////////////////////// +bool qpCharacter:: +has_cull_callback() const { + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::cull_callback +// Access: Public, Virtual +// Description: If has_cull_callback() returns true, this function +// will be called during the cull traversal to perform +// any additional operations that should be performed at +// cull time. This may include additional manipulation +// of render state or additional visible/invisible +// decisions, or any other arbitrary operation. +// +// By the time this function is called, the node has +// already passed the bounding-volume test for the +// viewing frustum, and the node's transform and state +// have already been applied to the indicated +// CullTraverserData object. +// +// The return value is true if this node should be +// visible, or false if it should be culled. +//////////////////////////////////////////////////////////////////// +bool qpCharacter:: +cull_callback(CullTraverserData &) { + // For now, we update the character during the cull traversal; this + // prevents us from needlessly updating characters that aren't in + // the view frustum. We may need a better way to do this + // optimization later, to handle characters that might animate + // themselves in front of the view frustum. + double now = ClockObject::get_global_clock()->get_frame_time(); + get_bundle()->advance_time(now); + + if (char_cat.is_spam()) { + char_cat.spam() << "Animating " << *this << " at time " << now << "\n"; + } + + update(); + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::update +// Access: Public +// Description: Recalculates the qpCharacter's joints and vertices for +// the current frame. Normally this is performed +// automatically during the render and need not be +// called explicitly. +//////////////////////////////////////////////////////////////////// +void qpCharacter:: +update() { + // Statistics + PStatTimer timer(_char_pcollector); + + // First, update all the joints and sliders. + bool any_changed = get_bundle()->update(); + + // Now update the vertices, if we need to. This is likely to be a + // slow operation. + if (any_changed || even_animation) { + if (_computed_vertices != (ComputedVertices *)NULL) { + _computed_vertices->update(this); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::copy_joints +// Access: Private +// Description: Recursively walks the joint/slider hierarchy and +// creates a new copy of the hierarchy. +//////////////////////////////////////////////////////////////////// +void qpCharacter:: +copy_joints(PartGroup *copy, PartGroup *orig) { + if (copy->get_type() != orig->get_type()) { + char_cat.warning() + << "Don't know how to copy " << orig->get_type() << "\n"; + } + + PartGroup::Children::const_iterator ci; + for (ci = orig->_children.begin(); ci != orig->_children.end(); ++ci) { + PartGroup *orig_child = (*ci); + PartGroup *copy_child = orig_child->make_copy(); + copy->_children.push_back(copy_child); + copy_joints(copy_child, orig_child); + } + + Parts::iterator pi = find(_parts.begin(), _parts.end(), orig); + if (pi != _parts.end()) { + (*pi) = copy; + } +} + +/* +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::r_copy_subgraph +// Access: Private, Virtual +// Description: This is a virtual function inherited from Node. It's +// called when a copy_subgraph() operation reaches the +// qpCharacter node. In the case of a qpCharacter, it's +// overridden to do the all right things to copy the +// dynamic geometry to the new qpCharacter. +// +// Note that it includes the parameter inst_map, which +// is a map type, and is not (and cannot be) exported +// from PANDA.DLL. Thus, any derivative of Node that is +// not also a member of PANDA.DLL *cannot* access this +// map. +//////////////////////////////////////////////////////////////////// +Node *qpCharacter:: +r_copy_subgraph(TypeHandle graph_type, Node::InstanceMap &) const { + Node *copy = make_copy(); + nassertr(copy != (Node *)NULL, NULL); + if (copy->get_type() != get_type()) { + graph_cat.warning() + << "Don't know how to copy nodes of type " << get_type() << "\n"; + } + + // We assume there will be no instancing going on below the + // qpCharacter node. If there is, too bad; it will get flattened out. + + // Now we preempt the node's r_copy_subgraph() operation with our + // own function that keeps track of the old vs. new arcs and also + // updates any Geoms we find with our new dynamic vertices. + + qpCharacter *char_copy; + DCAST_INTO_R(char_copy, copy, NULL); + ArcMap arc_map; + char_copy->r_copy_char(char_copy, this, graph_type, this, arc_map); + char_copy->copy_arc_pointers(this, arc_map); + + return copy; +} +*/ + + +/* +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::r_copy_char +// Access: Private +// Description: Recursively walks the scene graph hierarchy below the +// qpCharacter node, duplicating it while noting the +// orig:copy arc mappings, and also updates any +// GeomNodes found. +//////////////////////////////////////////////////////////////////// +void qpCharacter:: +r_copy_char(Node *dest, const Node *source, TypeHandle graph_type, + const qpCharacter *from, qpCharacter::ArcMap &arc_map) { + if (source->is_of_type(GeomNode::get_class_type())) { + const GeomNode *source_gnode; + GeomNode *dest_gnode; + DCAST_INTO_V(source_gnode, source); + DCAST_INTO_V(dest_gnode, dest); + + dest_gnode->clear(); + int num_geoms = source_gnode->get_num_geoms(); + for (int i = 0; i < num_geoms; i++) { + dDrawable *d = source_gnode->get_geom(i); + if (d->is_of_type(Geom::get_class_type())) { + dest_gnode->add_geom(copy_geom(DCAST(Geom, d), from)); + } else { + dest_gnode->add_geom(d); + } + } + } + + int num_children = source->get_num_children(graph_type); + for (int i = 0; i < num_children; i++) { + NodeRelation *source_arc = source->get_child(graph_type, i); + const Node *source_child = source_arc->get_child(); + nassertv(source_child != (Node *)NULL); + + Node *dest_child; + if (source_child->is_of_type(qpCharacter::get_class_type())) { + // We make a special case for nodes of type qpCharacter. If we + // encounter one of these, we have a qpCharacter under a + // qpCharacter, and the nested qpCharacter's copy should be called + // instead of ours. + dest_child = source_child->copy_subgraph(graph_type); + + } else { + // Otherwise, we assume that make_copy() will make a suitable + // copy of the node. This does limit the sorts of things we can + // have parented to a qpCharacter and expect copy_subgraph() to + // work correctly. Too bad. + dest_child = source_child->make_copy(); + r_copy_char(dest_child, source_child, graph_type, from, arc_map); + } + + NodeRelation *dest_arc = + NodeRelation::create_typed_arc(graph_type, dest, dest_child); + nassertv(dest_arc != (NodeRelation *)NULL); + nassertv(dest_arc->is_exact_type(graph_type)); + + dest_arc->copy_transitions_from(source_arc); + arc_map[source_arc] = dest_arc; + } +} +*/ + +/* +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::copy_geom +// Access: Private +// Description: Makes a new copy of the Geom with the dynamic vertex +// arrays replaced to reference this qpCharacter instead +// of the other one. If no arrays have changed, simply +// returns the same Geom. +//////////////////////////////////////////////////////////////////// +PT(Geom) qpCharacter:: +copy_geom(Geom *source, const qpCharacter *from) { + GeomBindType bind; + PTA_ushort index; + + PTA_Vertexf coords; + PTA_Normalf norms; + PTA_Colorf colors; + PTA_TexCoordf texcoords; + + PT(Geom) dest = source; + + source->get_coords(coords, index); + if ((coords != (void *)NULL) && (coords == (from->_cv._coords))) { + if (dest == source) { + dest = source->make_copy(); + } + dest->set_coords(_cv._coords, index); + } + + source->get_normals(norms, bind, index); + if (bind != G_OFF && norms == from->_cv._norms) { + if (dest == source) { + dest = source->make_copy(); + } + dest->set_normals(_cv._norms, bind, index); + } + + source->get_colors(colors, bind, index); + if (bind != G_OFF && colors == from->_cv._colors) { + if (dest == source) { + dest = source->make_copy(); + } + dest->set_colors(_cv._colors, bind, index); + } + + source->get_texcoords(texcoords, bind, index); + if (bind != G_OFF && texcoords == from->_cv._texcoords) { + if (dest == source) { + dest = source->make_copy(); + } + dest->set_texcoords(_cv._texcoords, bind, index); + } + + return dest; +} +*/ + +/* +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::copy_arc_pointers +// Access: Public +// Description: Creates _net_transform_arcs and _local_transform_arcs +// as appropriate in each of the qpCharacter's joints, as +// copied from the other qpCharacter. +//////////////////////////////////////////////////////////////////// +void qpCharacter:: +copy_arc_pointers(const qpCharacter *from, const qpCharacter::ArcMap &arc_map) { + nassertv(_parts.size() == from->_parts.size()); + for (int i = 0; i < (int)_parts.size(); i++) { + if (_parts[i]->is_of_type(CharacterJoint::get_class_type())) { + nassertv(_parts[i] != from->_parts[i]); + CharacterJoint *source_joint; + CharacterJoint *dest_joint; + DCAST_INTO_V(source_joint, from->_parts[i]); + DCAST_INTO_V(dest_joint, _parts[i]); + + CharacterJoint::ArcList::const_iterator ai; + for (ai = source_joint->_net_transform_arcs.begin(); + ai != source_joint->_net_transform_arcs.end(); + ++ai) { + NodeRelation *source_arc = (*ai); + + ArcMap::const_iterator mi; + mi = arc_map.find(source_arc); + if (mi != arc_map.end()) { + NodeRelation *dest_arc = (*mi).second; + + // Here's an internal joint that the source qpCharacter was + // animating directly. We'll animate our corresponding + // joint the same way. + dest_joint->add_net_transform(dest_arc); + } + } + + for (ai = source_joint->_local_transform_arcs.begin(); + ai != source_joint->_local_transform_arcs.end(); + ++ai) { + NodeRelation *source_arc = (*ai); + + ArcMap::const_iterator mi; + mi = arc_map.find(source_arc); + if (mi != arc_map.end()) { + NodeRelation *dest_arc = (*mi).second; + + // Here's an internal joint that the source qpCharacter was + // animating directly. We'll animate our corresponding + // joint the same way. + dest_joint->add_local_transform(dest_arc); + } + } + } + } +} +*/ + + +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::register_with_read_factory +// Access: Public, Static +// Description: Tells the BamReader how to create objects of type +// qpCharacter. +//////////////////////////////////////////////////////////////////// +void qpCharacter:: +register_with_read_factory() { + BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void qpCharacter:: +write_datagram(BamWriter *manager, Datagram &dg) { + qpPartBundleNode::write_datagram(manager, dg); + _cv.write_datagram(manager, dg); + manager->write_pointer(dg, _computed_vertices); + + dg.add_uint16(_parts.size()); + Parts::const_iterator pi; + for (pi = _parts.begin(); pi != _parts.end(); pi++) { + manager->write_pointer(dg, (*pi)); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::complete_pointers +// Access: Public, Virtual +// Description: Receives an array of pointers, one for each time +// manager->read_pointer() was called in fillin(). +// Returns the number of pointers processed. +//////////////////////////////////////////////////////////////////// +int qpCharacter:: +complete_pointers(TypedWritable **p_list, BamReader *manager) { + int pi = qpPartBundleNode::complete_pointers(p_list, manager); + _computed_vertices = DCAST(ComputedVertices, p_list[pi++]); + + int num_parts = _parts.size(); + for (int i = 0; i < num_parts; i++) { + _parts[i] = DCAST(PartGroup, p_list[pi++]); + } + + return pi; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::make_from_bam +// Access: Protected, Static +// Description: This function is called by the BamReader's factory +// when a new object of type qpCharacter is encountered +// in the Bam file. It should create the qpCharacter +// and extract its information from the file. +//////////////////////////////////////////////////////////////////// +TypedWritable *qpCharacter:: +make_from_bam(const FactoryParams ¶ms) { + qpCharacter *node = new qpCharacter(""); + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + node->fillin(scan, manager); + + return node; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpCharacter::fillin +// Access: Protected +// Description: This internal function is called by make_from_bam to +// read in all of the relevant data from the BamFile for +// the new qpCharacter. +//////////////////////////////////////////////////////////////////// +void qpCharacter:: +fillin(DatagramIterator &scan, BamReader *manager) { + qpPartBundleNode::fillin(scan, manager); + _cv.fillin(scan, manager); + manager->read_pointer(scan, this); + + // Read the number of parts to expect in the _parts list, and then + // fill the array up with NULLs. We'll fill in the actual values in + // complete_pointers, later. + int num_parts = scan.get_uint16(); + _parts.clear(); + _parts.reserve(num_parts); + for (int i = 0; i < num_parts; i++) { + manager->read_pointer(scan, this); + _parts.push_back((PartGroup *)NULL); + } + +#ifdef DO_PSTATS + // Reinitialize our collector with our name, now that we know it. + if (has_name()) { + _char_pcollector = + PStatCollector(_anim_pcollector, get_name()); + } +#endif +} diff --git a/panda/src/char/qpcharacter.h b/panda/src/char/qpcharacter.h new file mode 100644 index 0000000000..4819be4bee --- /dev/null +++ b/panda/src/char/qpcharacter.h @@ -0,0 +1,134 @@ +// Filename: qpcharacter.h +// Created by: drose (06Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// 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 . +// +//////////////////////////////////////////////////////////////////// + +#ifndef qpCHARACTER_H +#define qpCHARACTER_H + +#include "pandabase.h" + +#include "computedVertices.h" + +#include "qppartBundleNode.h" +#include "vector_PartGroupStar.h" +#include "pointerTo.h" +#include "geom.h" +#include "pStatCollector.h" + +class CharacterJointBundle; +class ComputedVertices; + +//////////////////////////////////////////////////////////////////// +// Class : qpCharacter +// Description : An animated character, with skeleton-morph animation +// and either soft-skinned or hard-skinned vertices. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA qpCharacter : public qpPartBundleNode { +protected: + qpCharacter(const qpCharacter ©); + +public: + qpCharacter(const string &name); + virtual ~qpCharacter(); + + virtual PandaNode *make_copy() const; + + virtual bool safe_to_transform() const; + virtual bool has_cull_callback() const; + virtual bool cull_callback(CullTraverserData &data); + +PUBLISHED: + INLINE CharacterJointBundle *get_bundle() const; + + INLINE ComputedVertices *get_computed_vertices() const; + INLINE int get_num_parts() const; + INLINE PartGroup *get_part(int n) const; + + INLINE void write_parts(ostream &out) const; + INLINE void write_part_values(ostream &out) const; + + void update(); + +private: + void copy_joints(PartGroup *copy, PartGroup *orig); + + /* + typedef pmap ArcMap; + virtual Node *r_copy_subgraph(TypeHandle graph_type, + InstanceMap &inst_map) const; + void r_copy_char(Node *dest, const Node *source, TypeHandle graph_type, + const qpCharacter *from, ArcMap &arc_map); + PT(Geom) copy_geom(Geom *source, const qpCharacter *from); + void copy_arc_pointers(const qpCharacter *from, const ArcMap &arc_map); + */ + + // These are the actual dynamic vertex pools for this qpCharacter's + // ComputedVertices--the vertices that it will recompute each frame + // based on the soft-skinning and morphing requirements. Note that + // we store this concretely, instead of as a pointer, just because + // we don't really need to make it a pointer. + DynamicVertices _cv; + + // And this is the object that animates them. It *is* a pointer, so + // it can be shared between multiple instances of this qpCharacter. + PT(ComputedVertices) _computed_vertices; + + // This vector is used by the ComputedVertices object to index back + // into our joints and sliders. + typedef vector_PartGroupStar Parts; + Parts _parts; + + // Statistics + PStatCollector _char_pcollector; + static PStatCollector _anim_pcollector; + +public: + static void register_with_read_factory(); + virtual void write_datagram(BamWriter *manager, Datagram &dg); + virtual int complete_pointers(TypedWritable **plist, + BamReader *manager); + +protected: + static TypedWritable *make_from_bam(const FactoryParams ¶ms); + void fillin(DatagramIterator &scan, BamReader *manager); + +public: + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + qpPartBundleNode::init_type(); + register_type(_type_handle, "qpCharacter", + qpPartBundleNode::get_class_type()); + } + +private: + static TypeHandle _type_handle; + + friend class qpCharacterMaker; + friend class ComputedVerticesMaker; + friend class ComputedVertices; +}; + +#include "qpcharacter.I" + +#endif + diff --git a/panda/src/egg2pg/Sources.pp b/panda/src/egg2pg/Sources.pp index 4fa891cb28..4719dd2ad0 100644 --- a/panda/src/egg2pg/Sources.pp +++ b/panda/src/egg2pg/Sources.pp @@ -9,12 +9,22 @@ #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx #define SOURCES \ + animBundleMaker.h \ + characterMaker.h \ + qpcharacterMaker.h \ + computedVerticesMaker.I computedVerticesMaker.h \ + computedVerticesMakerEntity.I computedVerticesMakerEntity.h \ config_egg2pg.h \ eggBinner.h \ + eggLoaderBase.h \ qpeggLoader.h \ qpload_egg_file.h #define INCLUDED_SOURCES \ + animBundleMaker.cxx \ + characterMaker.cxx \ + qpcharacterMaker.cxx \ + computedVerticesMaker.cxx \ config_egg2pg.cxx \ eggBinner.cxx \ qpeggLoader.cxx \ @@ -27,9 +37,6 @@ #endif #define INSTALL_HEADERS \ - config_egg2pg.h \ - eggBinner.h \ - qpeggLoader.h \ - qpload_egg_file.h + qpload_egg_file.h config_egg2pg.h #end lib_target diff --git a/panda/src/egg2sg/animBundleMaker.cxx b/panda/src/egg2pg/animBundleMaker.cxx similarity index 92% rename from panda/src/egg2sg/animBundleMaker.cxx rename to panda/src/egg2pg/animBundleMaker.cxx index 730d763606..f095e90623 100644 --- a/panda/src/egg2sg/animBundleMaker.cxx +++ b/panda/src/egg2pg/animBundleMaker.cxx @@ -17,18 +17,19 @@ //////////////////////////////////////////////////////////////////// #include "animBundleMaker.h" -#include "config_egg2sg.h" +#include "config_egg2pg.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#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 "qpanimBundleNode.h" +#include "animChannelMatrixXfmTable.h" +#include "animChannelScalarTable.h" //////////////////////////////////////////////////////////////////// // Function: AnimBundleMaker::Construtor @@ -46,18 +47,18 @@ AnimBundleMaker(EggTable *root) : _root(root) { inspect_tree(root); if (!_ok_fps) { - egg2sg_cat.warning() + egg2pg_cat.warning() << "AnimBundle " << _root->get_name() << " specifies contradictory frame rates.\n"; } else if (_fps == 0.0f) { - egg2sg_cat.warning() + egg2pg_cat.warning() << "AnimBundle " << _root->get_name() << " does not specify a frame rate.\n"; _fps = 24.0f; } if (!_ok_num_frames) { - egg2sg_cat.warning() + egg2pg_cat.warning() << "AnimBundle " << _root->get_name() << " specifies contradictory number of frames.\n"; } @@ -74,6 +75,16 @@ make_node() { return new AnimBundleNode(make_bundle()); } +//////////////////////////////////////////////////////////////////// +// Function: AnimBundleMaker::make_qpnode +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +qpAnimBundleNode *AnimBundleMaker:: +make_qpnode() { + return new qpAnimBundleNode("", make_bundle()); +} + //////////////////////////////////////////////////////////////////// // Function: AnimBundleMaker::make_bundle // Access: Private @@ -196,7 +207,7 @@ build_hierarchy(EggTable *egg_table, AnimGroup *parent) { if (this_node == NULL) { this_node = create_xfm_channel((*ci), egg_table->get_name(), parent); } else { - egg2sg_cat.warning() + egg2pg_cat.warning() << "Duplicate xform table under node " << egg_table->get_name() << "\n"; } @@ -271,7 +282,7 @@ create_xfm_channel(EggNode *egg_node, const string &name, return create_xfm_channel(egg_anim, name, parent); } - egg2sg_cat.warning() + egg2pg_cat.warning() << "Inappropriate node named xform under node " << name << "\n"; return NULL; @@ -304,7 +315,7 @@ create_xfm_channel(EggXfmSAnim *egg_anim, const string &name, EggSAnimData *child = DCAST(EggSAnimData, *ci); if (child->get_name().empty()) { - egg2sg_cat.warning() + egg2pg_cat.warning() << "Unnamed subtable of " << name << "\n"; } else { @@ -312,12 +323,12 @@ create_xfm_channel(EggXfmSAnim *egg_anim, const string &name, if (child->get_name().length() > 1 || !table->is_valid_id(table_id)) { - egg2sg_cat.warning() + egg2pg_cat.warning() << "Unexpected table name " << child->get_name() << ", child of " << name << "\n"; } else if (table->has_table(table_id)) { - egg2sg_cat.warning() + egg2pg_cat.warning() << "Duplicate table definition for " << table_id << " under " << name << "\n"; diff --git a/panda/src/egg2sg/animBundleMaker.h b/panda/src/egg2pg/animBundleMaker.h similarity index 95% rename from panda/src/egg2sg/animBundleMaker.h rename to panda/src/egg2pg/animBundleMaker.h index ef903e6285..a1e9c855be 100644 --- a/panda/src/egg2sg/animBundleMaker.h +++ b/panda/src/egg2pg/animBundleMaker.h @@ -19,11 +19,8 @@ #ifndef ANIMBUNDLEMAKER_H #define ANIMBUNDLEMAKER_H -#include - -#include - -#include +#include "pandabase.h" +#include "typedef.h" class EggNode; class EggGroupNode; @@ -33,6 +30,7 @@ class EggSAnimData; class AnimGroup; class AnimBundle; class AnimBundleNode; +class qpAnimBundleNode; class AnimChannelScalarTable; class AnimChannelMatrixXfmTable; @@ -46,6 +44,7 @@ public: AnimBundleMaker(EggTable *root); AnimBundleNode *make_node(); + qpAnimBundleNode *make_qpnode(); private: AnimBundle *make_bundle(); diff --git a/panda/src/egg2sg/characterMaker.cxx b/panda/src/egg2pg/characterMaker.cxx similarity index 97% rename from panda/src/egg2sg/characterMaker.cxx rename to panda/src/egg2pg/characterMaker.cxx index 0a12f50dc6..214beb1059 100644 --- a/panda/src/egg2sg/characterMaker.cxx +++ b/panda/src/egg2pg/characterMaker.cxx @@ -17,19 +17,19 @@ //////////////////////////////////////////////////////////////////// #include "characterMaker.h" -#include "eggLoader.h" -#include "config_egg2sg.h" +#include "qpeggLoader.h" +#include "config_egg2pg.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "computedVertices.h" +#include "eggGroup.h" +#include "eggPrimitive.h" +#include "partGroup.h" +#include "characterJoint.h" +#include "characterJointBundle.h" +#include "characterSlider.h" +#include "character.h" +#include "renderRelation.h" +#include "transformTransition.h" //////////////////////////////////////////////////////////////////// // Function: CharacterMaker::Construtor @@ -37,7 +37,7 @@ // Description: //////////////////////////////////////////////////////////////////// CharacterMaker:: -CharacterMaker(EggGroup *root, EggLoader &loader) +CharacterMaker(EggGroup *root, EggLoaderBase &loader) : _loader(loader), _egg_root(root) { _character_node = new Character(_egg_root->get_name()); diff --git a/panda/src/egg2sg/characterMaker.h b/panda/src/egg2pg/characterMaker.h similarity index 92% rename from panda/src/egg2sg/characterMaker.h rename to panda/src/egg2pg/characterMaker.h index ee06de8540..cf53d50dca 100644 --- a/panda/src/egg2sg/characterMaker.h +++ b/panda/src/egg2pg/characterMaker.h @@ -19,14 +19,12 @@ #ifndef CHARACTERMAKER_H #define CHARACTERMAKER_H -#include +#include "pandabase.h" #include "computedVerticesMaker.h" -#include -#include - -#include +#include "vector_PartGroupStar.h" +#include "typedef.h" #include "pmap.h" class EggNode; @@ -39,7 +37,7 @@ class Character; class CharacterSlider; class MovingPartBase; class NamedNode; -class EggLoader; +class EggLoaderBase; /////////////////////////////////////////////////////////////////// // Class : CharacterMaker @@ -49,7 +47,7 @@ class EggLoader; //////////////////////////////////////////////////////////////////// class EXPCL_PANDAEGG CharacterMaker { public: - CharacterMaker(EggGroup *root, EggLoader &loader); + CharacterMaker(EggGroup *root, EggLoaderBase &loader); Character *make_node(); @@ -78,7 +76,7 @@ private: typedef vector_PartGroupStar Parts; Parts _parts; - EggLoader &_loader; + EggLoaderBase &_loader; EggGroup *_egg_root; Character *_character_node; CharacterJointBundle *_bundle; diff --git a/panda/src/egg2sg/computedVerticesMaker.I b/panda/src/egg2pg/computedVerticesMaker.I similarity index 100% rename from panda/src/egg2sg/computedVerticesMaker.I rename to panda/src/egg2pg/computedVerticesMaker.I diff --git a/panda/src/egg2sg/computedVerticesMaker.cxx b/panda/src/egg2pg/computedVerticesMaker.cxx similarity index 78% rename from panda/src/egg2sg/computedVerticesMaker.cxx rename to panda/src/egg2pg/computedVerticesMaker.cxx index d1c5dce17b..e011091368 100644 --- a/panda/src/egg2sg/computedVerticesMaker.cxx +++ b/panda/src/egg2pg/computedVerticesMaker.cxx @@ -19,12 +19,12 @@ #include "computedVerticesMaker.h" #include "characterMaker.h" -#include -#include -#include -#include -#include -#include +#include "characterJoint.h" +#include "character.h" +#include "computedVertices.h" +#include "eggNode.h" +#include "eggGroup.h" +#include "eggVertex.h" #include @@ -447,6 +447,141 @@ make_computed_vertices(Character *character, CharacterMaker &char_maker) { return comp_verts; } +//////////////////////////////////////////////////////////////////// +// Function: ComputedVerticesMaker::make_computed_vertices +// Access: Public +// Description: After all spaces have been defined and all vertices +// added, creates a new ComputedVertices object and +// returns it. +//////////////////////////////////////////////////////////////////// +ComputedVertices *ComputedVerticesMaker:: +make_computed_vertices(qpCharacter *character, qpCharacterMaker &char_maker) { + // We must first build up a set of all the unique kinds of vertex + // transforms. + typedef pset VertexTransforms; + VertexTransforms transforms; + + TransformSpaces::const_iterator tsi; + for (tsi = _transforms.begin(); + tsi != _transforms.end(); + ++tsi) { + const JointWeights &jw = (*tsi).first; + const VertexCollection &vc = (*tsi).second; + + JointWeights::const_iterator jwi; + for (jwi = jw.begin(); jwi != jw.end(); ++jwi) { + double weight = (*jwi).second; + EggNode *egg_joint = (*jwi).first; + int joint_index = char_maker.egg_to_index(egg_joint); + + // Look for a VertexTransform that matches this template. + ComputedVertices::VertexTransform new_vt; + new_vt._joint_index = joint_index; + new_vt._effect = (float)weight; + + // This will either insert the VertexTransform into the set and + // return its newly-created iterator, or it will return the + // iterator referring to the previously-inserted VertexTransform + // like this. + VertexTransforms::iterator vti = transforms.insert(new_vt).first; + + // We can discard the const-ness of the set's iterator, because + // we will only be changing a part of the VertexTransform that + // doesn't affect its sort order within the set. + ComputedVertices::VertexTransform &insert_vt = + (ComputedVertices::VertexTransform &)*vti; + + // Now add in all the vertices and normals. + copy(vc._vindex.begin(), vc._vindex.end(), + back_inserter(insert_vt._vindex)); + copy(vc._nindex.begin(), vc._nindex.end(), + back_inserter(insert_vt._nindex)); + } + } + + // Ok, now we have the set of all VertexTransforms. Create a + // ComputedVertices object that reflects this. + ComputedVertices *comp_verts = new ComputedVertices; + copy(transforms.begin(), transforms.end(), + back_inserter(comp_verts->_transforms)); + + character->_cv._coords = _coords; + character->_cv._norms = _norms; + character->_cv._colors = _colors; + character->_cv._texcoords = _texcoords; + + // Finally, add in all the morph definitions. + Morphs::const_iterator mi; + for (mi = _morphs.begin(); mi != _morphs.end(); ++mi) { + const string &name = (*mi).first; + const MorphList &mlist = (*mi).second; + + int slider_index = char_maker.create_slider(name); + + if (!mlist._vmorphs.empty()) { + // We push an empty MorphVertex object and then modify it, + // rather than filling it first and then pushing it, just to + // avoid unnecessary copying of data. + comp_verts->_vertex_morphs.push_back(ComputedVerticesMorphVertex()); + ComputedVerticesMorphVertex &mv = comp_verts->_vertex_morphs.back(); + mv._slider_index = slider_index; + + VertexMorphList::const_iterator vmi; + for (vmi = mlist._vmorphs.begin(); + vmi != mlist._vmorphs.end(); + ++vmi) { + mv._morphs.push_back(ComputedVerticesMorphValue3((*vmi).first, + (*vmi).second)); + } + } + + if (!mlist._nmorphs.empty()) { + comp_verts->_normal_morphs.push_back(ComputedVerticesMorphNormal()); + ComputedVerticesMorphNormal &mv = comp_verts->_normal_morphs.back(); + mv._slider_index = slider_index; + + NormalMorphList::const_iterator vmi; + for (vmi = mlist._nmorphs.begin(); + vmi != mlist._nmorphs.end(); + ++vmi) { + mv._morphs.push_back(ComputedVerticesMorphValue3((*vmi).first, + (*vmi).second)); + } + } + + if (!mlist._tmorphs.empty()) { + comp_verts->_texcoord_morphs.push_back(ComputedVerticesMorphTexCoord()); + ComputedVerticesMorphTexCoord &mv = comp_verts->_texcoord_morphs.back(); + mv._slider_index = slider_index; + + TexCoordMorphList::const_iterator vmi; + for (vmi = mlist._tmorphs.begin(); + vmi != mlist._tmorphs.end(); + ++vmi) { + mv._morphs.push_back(ComputedVerticesMorphValue2((*vmi).first, + (*vmi).second)); + } + } + + if (!mlist._cmorphs.empty()) { + comp_verts->_color_morphs.push_back(ComputedVerticesMorphColor()); + ComputedVerticesMorphColor &mv = comp_verts->_color_morphs.back(); + mv._slider_index = slider_index; + + ColorMorphList::const_iterator vmi; + for (vmi = mlist._cmorphs.begin(); + vmi != mlist._cmorphs.end(); + ++vmi) { + mv._morphs.push_back(ComputedVerticesMorphValue4((*vmi).first, + (*vmi).second)); + } + } + } + + comp_verts->make_orig(character); + return comp_verts; +} + //////////////////////////////////////////////////////////////////// // Function: ComputedVerticesMaker::write diff --git a/panda/src/egg2sg/computedVerticesMaker.h b/panda/src/egg2pg/computedVerticesMaker.h similarity index 91% rename from panda/src/egg2sg/computedVerticesMaker.h rename to panda/src/egg2pg/computedVerticesMaker.h index f6699a5b26..82ba3aeed0 100644 --- a/panda/src/egg2sg/computedVerticesMaker.h +++ b/panda/src/egg2pg/computedVerticesMaker.h @@ -19,25 +19,26 @@ #ifndef COMPUTEDVERTICESMAKER_H #define COMPUTEDVERTICESMAKER_H -#include +#include "pandabase.h" #include "computedVerticesMakerEntity.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "computedVerticesMorph.h" +#include "pointerToArray.h" +#include "luse.h" +#include "typedef.h" +#include "eggMorphList.h" +#include "pta_Vertexf.h" +#include "pta_Normalf.h" +#include "pta_Colorf.h" +#include "pta_TexCoordf.h" #include "pset.h" #include "pmap.h" class ComputedVertices; class CharacterMaker; +class qpCharacterMaker; class EggNode; class EggVertex; @@ -81,6 +82,9 @@ public: ComputedVertices *make_computed_vertices(Character *character, CharacterMaker &char_maker); + ComputedVertices *make_computed_vertices(qpCharacter *character, + qpCharacterMaker &char_maker); + void write(ostream &out) const; public: diff --git a/panda/src/egg2sg/computedVerticesMakerEntity.I b/panda/src/egg2pg/computedVerticesMakerEntity.I similarity index 99% rename from panda/src/egg2sg/computedVerticesMakerEntity.I rename to panda/src/egg2pg/computedVerticesMakerEntity.I index fed50ac4e2..a34acf6990 100644 --- a/panda/src/egg2sg/computedVerticesMakerEntity.I +++ b/panda/src/egg2pg/computedVerticesMakerEntity.I @@ -16,7 +16,6 @@ // //////////////////////////////////////////////////////////////////// -#include //////////////////////////////////////////////////////////////////// // Function: ComputedVerticesMakerEntity::Constructor diff --git a/panda/src/egg2sg/computedVerticesMakerEntity.h b/panda/src/egg2pg/computedVerticesMakerEntity.h similarity index 95% rename from panda/src/egg2sg/computedVerticesMakerEntity.h rename to panda/src/egg2pg/computedVerticesMakerEntity.h index aa3b93bbdb..299243521d 100644 --- a/panda/src/egg2sg/computedVerticesMakerEntity.h +++ b/panda/src/egg2pg/computedVerticesMakerEntity.h @@ -19,14 +19,15 @@ #ifndef COMPUTEDVERTICESMAKERENTITY_H #define COMPUTEDVERTICESMAKERENTITY_H -#include +#include "pandabase.h" -#include -#include -#include -#include +#include "luse.h" +#include "eggMorphList.h" +#include "typedef.h" +#include "pointerToArray.h" #include "pmap.h" +#include /////////////////////////////////////////////////////////////////// // Class : ComputedVerticesMakerEntity diff --git a/panda/src/egg2pg/egg2pg_composite1.cxx b/panda/src/egg2pg/egg2pg_composite1.cxx index 8feb78b7ec..46967d58d8 100644 --- a/panda/src/egg2pg/egg2pg_composite1.cxx +++ b/panda/src/egg2pg/egg2pg_composite1.cxx @@ -1,2 +1,4 @@ -#include "config_egg2pg.cxx" -#include "eggBinner.cxx" +#include "animBundleMaker.cxx" +#include "characterMaker.cxx" +#include "qpcharacterMaker.cxx" +#include "computedVerticesMaker.cxx" diff --git a/panda/src/egg2pg/egg2pg_composite2.cxx b/panda/src/egg2pg/egg2pg_composite2.cxx index d1946167eb..13c48f9b20 100644 --- a/panda/src/egg2pg/egg2pg_composite2.cxx +++ b/panda/src/egg2pg/egg2pg_composite2.cxx @@ -1,3 +1,5 @@ +#include "config_egg2pg.cxx" +#include "eggBinner.cxx" #include "qpeggLoader.cxx" #include "qpload_egg_file.cxx" diff --git a/panda/src/egg2pg/qpeggLoader.cxx b/panda/src/egg2pg/qpeggLoader.cxx index 7e73b328a7..0719250e11 100644 --- a/panda/src/egg2pg/qpeggLoader.cxx +++ b/panda/src/egg2pg/qpeggLoader.cxx @@ -20,6 +20,7 @@ #include "qpeggLoader.h" #include "config_egg2pg.h" +#include "nodeChain.h" #include "renderState.h" #include "transformState.h" #include "textureAttrib.h" @@ -48,7 +49,10 @@ #include "eggBin.h" #include "eggTable.h" #include "eggBinner.h" -#include "nodeChain.h" +#include "qpcharacterMaker.h" +#include "qpcharacter.h" +#include "animBundleMaker.h" +#include "qpanimBundleNode.h" #include #include @@ -283,7 +287,6 @@ void qpEggLoader:: make_indexed_primitive(EggPrimitive *egg_prim, PandaNode *parent, const LMatrix4d *transform, ComputedVerticesMaker &_comp_verts_maker) { - /* BuilderBucket bucket; setup_bucket(bucket, parent, egg_prim); @@ -396,7 +399,6 @@ make_indexed_primitive(EggPrimitive *egg_prim, PandaNode *parent, } _builder.add_prim(bucket, bprim); - */ } //////////////////////////////////////////////////////////////////// @@ -1338,11 +1340,9 @@ make_node(EggGroup *egg_group, PandaNode *parent) { } if (egg_group->get_dart_type() != EggGroup::DT_none) { - /* // A group with the flag set means to create a character. - CharacterMaker char_maker(egg_group, *this); + qpCharacterMaker char_maker(egg_group, *this); node = char_maker.make_node(); - */ } else if (egg_group->get_cs_type() != EggGroup::CST_none && egg_group->get_cs_type() != EggGroup::CST_geode) { @@ -1493,8 +1493,6 @@ create_group_arc(EggGroup *egg_group, PandaNode *parent, PandaNode *node) { //////////////////////////////////////////////////////////////////// PandaNode *qpEggLoader:: make_node(EggTable *egg_table, PandaNode *parent) { - return (PandaNode *)NULL; - /* if (egg_table->get_table_type() != EggTable::TT_bundle) { // We only do anything with bundles. Isolated tables are treated // as ordinary groups. @@ -1504,9 +1502,9 @@ make_node(EggTable *egg_table, PandaNode *parent) { // It's an actual bundle, so make an AnimBundle from it and its // descendants. AnimBundleMaker bundle_maker(egg_table); - AnimBundleNode *node = bundle_maker.make_node(); - return new PandaNode(parent, node); - */ + qpAnimBundleNode *node = bundle_maker.make_qpnode(); + parent->add_child(node); + return node; } diff --git a/panda/src/egg2pg/qpeggLoader.h b/panda/src/egg2pg/qpeggLoader.h index 2a307e6735..62c75d4da5 100644 --- a/panda/src/egg2pg/qpeggLoader.h +++ b/panda/src/egg2pg/qpeggLoader.h @@ -35,6 +35,8 @@ #include "indirectCompareTo.h" #include "textureAttrib.h" +#include "eggLoaderBase.h" + class EggNode; class EggBin; class EggTable; @@ -57,7 +59,7 @@ class CollisionPolygon; // // This class isn't exported from this package. //////////////////////////////////////////////////////////////////// -class qpEggLoader { +class qpEggLoader : public EggLoaderBase { public: qpEggLoader(); qpEggLoader(const EggData &data); diff --git a/panda/src/egg2sg/Sources.pp b/panda/src/egg2sg/Sources.pp index 3a0e515a95..ee67767ef7 100644 --- a/panda/src/egg2sg/Sources.pp +++ b/panda/src/egg2sg/Sources.pp @@ -11,13 +11,11 @@ #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx #define SOURCES \ - animBundleMaker.h characterMaker.h computedVerticesMaker.I \ - computedVerticesMaker.h config_egg2sg.h \ + config_egg2sg.h \ deferredArcProperty.h deferredArcTraverser.h \ eggLoader.h load_egg_file.h loaderFileTypeEgg.h #define INCLUDED_SOURCES \ - animBundleMaker.cxx characterMaker.cxx computedVerticesMaker.cxx \ config_egg2sg.cxx deferredArcProperty.cxx \ deferredArcTraverser.cxx eggLoader.cxx \ load_egg_file.cxx loaderFileTypeEgg.cxx diff --git a/panda/src/egg2sg/egg2sg_composite1.cxx b/panda/src/egg2sg/egg2sg_composite1.cxx index 471e9826d0..75e05341b9 100644 --- a/panda/src/egg2sg/egg2sg_composite1.cxx +++ b/panda/src/egg2sg/egg2sg_composite1.cxx @@ -1,6 +1,3 @@ -#include "animBundleMaker.cxx" -#include "characterMaker.cxx" -#include "computedVerticesMaker.cxx" #include "deferredArcProperty.cxx" #include "deferredArcTraverser.cxx" diff --git a/panda/src/egg2sg/eggLoader.h b/panda/src/egg2sg/eggLoader.h index 69b8b5c540..cbe3eab9b6 100644 --- a/panda/src/egg2sg/eggLoader.h +++ b/panda/src/egg2sg/eggLoader.h @@ -22,6 +22,7 @@ #include #include "deferredArcTraverser.h" +#include "eggLoaderBase.h" #include #include @@ -62,7 +63,7 @@ class CollisionPolygon; // // This class isn't exported from this package. //////////////////////////////////////////////////////////////////// -class EggLoader { +class EggLoader : public EggLoaderBase { public: EggLoader(); EggLoader(const EggData &data); diff --git a/panda/src/testbed/pview.cxx b/panda/src/testbed/pview.cxx index eeea89e9d9..d077da3dfb 100644 --- a/panda/src/testbed/pview.cxx +++ b/panda/src/testbed/pview.cxx @@ -34,6 +34,7 @@ #include "texturePool.h" #include "dSearchPath.h" #include "loader.h" +#include "auto_bind.h" // These are in support of legacy data graph operations. #include "namedNode.h" @@ -294,6 +295,14 @@ main(int argc, char *argv[]) { // Put something in the scene graph to look at. get_models(render, argc, argv); + // If we happened to load up both a character file and its matching + // animation file, attempt to bind them together now and start the + // animations looping. + AnimControlCollection anim_controls; + auto_bind(render, anim_controls, ~0); + anim_controls.loop_all(true); + + // Tick the clock once so we won't count the time spent loading up // files, above, in our frame rate average. ClockObject::get_global_clock()->tick();