pgraph characters

This commit is contained in:
David Rose 2002-03-06 22:15:25 +00:00
parent 1c46006c04
commit 4d552344fe
42 changed files with 1893 additions and 150 deletions

View File

@ -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

View File

@ -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 <renderRelation.h>
#include <traverserVisitor.h>
#include <dftraverser.h>
#include <string_utils.h>
#include <nullLevelState.h>
#include <nullTransitionWrapper.h>
#include "auto_bind.h"
#include "renderRelation.h"
#include "traverserVisitor.h"
#include "dftraverser.h"
#include "nullLevelState.h"
#include "nullTransitionWrapper.h"
typedef pset<AnimBundleNode *> AnimNodes;
typedef pmap<string, AnimNodes> Anims;
@ -36,7 +38,6 @@ typedef pset<PartBundleNode *> PartNodes;
typedef pmap<string, PartNodes> 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<qpAnimBundleNode *> qpAnimNodes;
typedef pmap<string, qpAnimNodes> qpAnims;
typedef pset<qpPartBundleNode *> qpPartNodes;
typedef pmap<string, qpPartNodes> 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.
}
}
}

View File

@ -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

View File

@ -6,6 +6,7 @@
#include "movingPartScalar.cxx"
#include "partBundle.cxx"
#include "partBundleNode.cxx"
#include "qppartBundleNode.cxx"
#include "partGroup.cxx"
#include "vector_PartGroupStar.cxx"

View File

@ -1,6 +1,7 @@
#include "animBundle.cxx"
#include "animBundleNode.cxx"
#include "qpanimBundleNode.cxx"
#include "animChannel.cxx"
#include "animChannelBase.cxx"
#include "animChannelMatrixXfmTable.cxx"

View File

@ -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 <luse.h>
#include <dconfig.h>
#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();
}

View File

@ -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

View File

@ -19,17 +19,18 @@
#ifndef PARTBUNDLE_H
#define PARTBUNDLE_H
#include <pandabase.h>
#include "pandabase.h"
#include "partGroup.h"
#include "animControl.h"
#include "animControlCollection.h"
#include <pointerTo.h>
#include <iterator_types.h>
#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) {

View File

@ -130,6 +130,7 @@ private:
static TypeHandle _type_handle;
friend class Character;
friend class qpCharacter;
};
#include "partGroup.I"

View File

@ -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 &copy) :
PandaNode(copy),
_bundle(copy._bundle)
{
}
////////////////////////////////////////////////////////////////////
// Function: qpAnimBundleNode::get_bundle
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE AnimBundle *qpAnimBundleNode::
get_bundle() const {
return _bundle;
}

View File

@ -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 &params) {
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);
}

View File

@ -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 &copy);
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 &params);
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

View File

@ -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 &copy) :
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;
}

View File

@ -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);
}

View File

@ -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 &copy);
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

View File

@ -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

View File

@ -1,6 +1,7 @@
#include "config_char.cxx"
#include "character.cxx"
#include "qpcharacter.cxx"
#include "characterJoint.cxx"
#include "characterJointBundle.cxx"

View File

@ -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;

View File

@ -20,6 +20,7 @@
#include "computedVertices.h"
#include "characterJoint.h"
#include "character.h"
#include "qpcharacter.h"
#include "config_char.h"
#include <datagram.h>
@ -53,28 +54,29 @@ VertexTransform(const VertexTransform &copy) :
// vertices in the table, according to the values of the
// relevant slider.
////////////////////////////////////////////////////////////////////
template<class ValueType, class MorphType>
// QP
template<class ValueType, class MorphType, class Character>
static void
compute_morphs(ValueType *table, const pvector<MorphType> &morph_list,
Character *character) {
Character *character) {
pvector<MorphType>::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

View File

@ -19,15 +19,16 @@
#ifndef COMPUTEDVERTICES_H
#define COMPUTEDVERTICES_H
#include <pandabase.h>
#include "pandabase.h"
#include "dynamicVertices.h"
#include "computedVerticesMorph.h"
#include <vector_ushort.h>
#include <typedWritableReferenceCount.h>
#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;

View File

@ -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();

View File

@ -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);
}

View File

@ -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 &copy) :
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 &params) {
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
}

View File

@ -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 &copy);
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<NodeRelation *, NodeRelation *> 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 &params);
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

View File

@ -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

View File

@ -17,18 +17,19 @@
////////////////////////////////////////////////////////////////////
#include "animBundleMaker.h"
#include "config_egg2sg.h"
#include "config_egg2pg.h"
#include <eggTable.h>
#include <eggAnimData.h>
#include <eggSAnimData.h>
#include <eggXfmAnimData.h>
#include <eggXfmSAnim.h>
#include <eggGroupNode.h>
#include <animBundle.h>
#include <animBundleNode.h>
#include <animChannelMatrixXfmTable.h>
#include <animChannelScalarTable.h>
#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 <Xfm$Anim_S$> " << 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";

View File

@ -19,11 +19,8 @@
#ifndef ANIMBUNDLEMAKER_H
#define ANIMBUNDLEMAKER_H
#include <pandabase.h>
#include <typedef.h>
#include <string>
#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();

View File

@ -17,19 +17,19 @@
////////////////////////////////////////////////////////////////////
#include "characterMaker.h"
#include "eggLoader.h"
#include "config_egg2sg.h"
#include "qpeggLoader.h"
#include "config_egg2pg.h"
#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>
#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());

View File

@ -19,14 +19,12 @@
#ifndef CHARACTERMAKER_H
#define CHARACTERMAKER_H
#include <pandabase.h>
#include "pandabase.h"
#include "computedVerticesMaker.h"
#include <vector_PartGroupStar.h>
#include <typedef.h>
#include <string>
#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;

View File

@ -19,12 +19,12 @@
#include "computedVerticesMaker.h"
#include "characterMaker.h"
#include <characterJoint.h>
#include <character.h>
#include <computedVertices.h>
#include <eggNode.h>
#include <eggGroup.h>
#include <eggVertex.h>
#include "characterJoint.h"
#include "character.h"
#include "computedVertices.h"
#include "eggNode.h"
#include "eggGroup.h"
#include "eggVertex.h"
#include <algorithm>
@ -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<ComputedVertices::VertexTransform> 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

View File

@ -19,25 +19,26 @@
#ifndef COMPUTEDVERTICESMAKER_H
#define COMPUTEDVERTICESMAKER_H
#include <pandabase.h>
#include "pandabase.h"
#include "computedVerticesMakerEntity.h"
#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 "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:

View File

@ -16,7 +16,6 @@
//
////////////////////////////////////////////////////////////////////
#include <math.h>
////////////////////////////////////////////////////////////////////
// Function: ComputedVerticesMakerEntity::Constructor

View File

@ -19,14 +19,15 @@
#ifndef COMPUTEDVERTICESMAKERENTITY_H
#define COMPUTEDVERTICESMAKERENTITY_H
#include <pandabase.h>
#include "pandabase.h"
#include <luse.h>
#include <eggMorphList.h>
#include <typedef.h>
#include <pointerToArray.h>
#include "luse.h"
#include "eggMorphList.h"
#include "typedef.h"
#include "pointerToArray.h"
#include "pmap.h"
#include <math.h>
///////////////////////////////////////////////////////////////////
// Class : ComputedVerticesMakerEntity

View File

@ -1,2 +1,4 @@
#include "config_egg2pg.cxx"
#include "eggBinner.cxx"
#include "animBundleMaker.cxx"
#include "characterMaker.cxx"
#include "qpcharacterMaker.cxx"
#include "computedVerticesMaker.cxx"

View File

@ -1,3 +1,5 @@
#include "config_egg2pg.cxx"
#include "eggBinner.cxx"
#include "qpeggLoader.cxx"
#include "qpload_egg_file.cxx"

View File

@ -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 <ctype.h>
#include <algorithm>
@ -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 <Dart> 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;
}

View File

@ -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);

View File

@ -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

View File

@ -1,6 +1,3 @@
#include "animBundleMaker.cxx"
#include "characterMaker.cxx"
#include "computedVerticesMaker.cxx"
#include "deferredArcProperty.cxx"
#include "deferredArcTraverser.cxx"

View File

@ -22,6 +22,7 @@
#include <pandabase.h>
#include "deferredArcTraverser.h"
#include "eggLoaderBase.h"
#include <eggData.h>
#include <eggTexture.h>
@ -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);

View File

@ -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();