From 33e3ae85ab7a7b364176bce2be72abdb19539cae Mon Sep 17 00:00:00 2001 From: David Rose Date: Fri, 23 Feb 2007 00:34:06 +0000 Subject: [PATCH] RigidBodyCombiner --- panda/src/gobj/userVertexTransform.cxx | 2 +- panda/src/grutil/Sources.pp | 17 +- panda/src/grutil/config_grutil.cxx | 5 + panda/src/grutil/grutil_composite1.cxx | 2 + panda/src/grutil/nodeVertexTransform.I | 40 ++++ panda/src/grutil/nodeVertexTransform.cxx | 68 ++++++ panda/src/grutil/nodeVertexTransform.h | 74 +++++++ panda/src/grutil/rigidBodyCombiner.I | 18 ++ panda/src/grutil/rigidBodyCombiner.cxx | 258 +++++++++++++++++++++++ panda/src/grutil/rigidBodyCombiner.h | 103 +++++++++ 10 files changed, 581 insertions(+), 6 deletions(-) create mode 100644 panda/src/grutil/nodeVertexTransform.I create mode 100644 panda/src/grutil/nodeVertexTransform.cxx create mode 100644 panda/src/grutil/nodeVertexTransform.h create mode 100644 panda/src/grutil/rigidBodyCombiner.I create mode 100644 panda/src/grutil/rigidBodyCombiner.cxx create mode 100644 panda/src/grutil/rigidBodyCombiner.h diff --git a/panda/src/gobj/userVertexTransform.cxx b/panda/src/gobj/userVertexTransform.cxx index 7c875a9783..7048e2cca5 100644 --- a/panda/src/gobj/userVertexTransform.cxx +++ b/panda/src/gobj/userVertexTransform.cxx @@ -36,7 +36,7 @@ UserVertexTransform(const string &name) : //////////////////////////////////////////////////////////////////// // Function: UserVertexTransform::get_matrix // Access: Published, Virtual -// Description: Stores the transform's matrix in the indicated object. +// Description: Returns the transform's matrix. //////////////////////////////////////////////////////////////////// void UserVertexTransform:: get_matrix(LMatrix4f &matrix) const { diff --git a/panda/src/grutil/Sources.pp b/panda/src/grutil/Sources.pp index f252323426..205b961761 100644 --- a/panda/src/grutil/Sources.pp +++ b/panda/src/grutil/Sources.pp @@ -12,34 +12,41 @@ #define SOURCES \ cardMaker.I cardMaker.h \ - fisheyeMaker.I fisheyeMaker.h \ config_grutil.h \ + ffmpegTexture.I ffmpegTexture.h \ + fisheyeMaker.I fisheyeMaker.h \ frameRateMeter.I frameRateMeter.h \ heightfieldTesselator.I heightfieldTesselator.h \ lineSegs.I lineSegs.h \ multitexReducer.I multitexReducer.h multitexReducer.cxx \ - openCVTexture.h openCVTexture.I ffmpegTexture.h ffmpegTexture.I + nodeVertexTransform.I nodeVertexTransform.h \ + openCVTexture.I openCVTexture.h \ + rigidBodyCombiner.I rigidBodyCombiner.h #define INCLUDED_SOURCES \ cardMaker.cxx \ + ffmpegTexture.cxx \ fisheyeMaker.cxx \ config_grutil.cxx \ frameRateMeter.cxx \ heightfieldTesselator.cxx \ + nodeVertexTransform.cxx \ openCVTexture.cxx \ lineSegs.cxx \ - ffmpegTexture.cxx + rigidBodyCombiner.cxx #define INSTALL_HEADERS \ cardMaker.I cardMaker.h \ + ffmpegTexture.I ffmpegTexture.h \ fisheyeMaker.I fisheyeMaker.h \ frameRateMeter.I frameRateMeter.h \ heightfieldTesselator.I heightfieldTesselator.h \ lineSegs.I lineSegs.h \ multitexReducer.I multitexReducer.h \ - openCVTexture.I openCVTexture.h\ - ffmpegTexture.I ffmpegTexture.h + nodeVertexTransform.I nodeVertexTransform.h \ + openCVTexture.I openCVTexture.h \ + rigidBodyCombiner.I rigidBodyCombiner.h #define IGATESCAN all diff --git a/panda/src/grutil/config_grutil.cxx b/panda/src/grutil/config_grutil.cxx index ff2a560a71..b9b7e33733 100644 --- a/panda/src/grutil/config_grutil.cxx +++ b/panda/src/grutil/config_grutil.cxx @@ -22,6 +22,8 @@ #include "ffmpegTexture.h" #include "pandaSystem.h" #include "texturePool.h" +#include "nodeVertexTransform.h" +#include "rigidBodyCombiner.h" #include "dconfig.h" @@ -65,6 +67,9 @@ init_libgrutil() { initialized = true; FrameRateMeter::init_type(); + NodeVertexTransform::init_type(); + RigidBodyCombiner::init_type(); + #ifdef HAVE_OPENCV { diff --git a/panda/src/grutil/grutil_composite1.cxx b/panda/src/grutil/grutil_composite1.cxx index e8273b6a2c..f0d3bb91bc 100644 --- a/panda/src/grutil/grutil_composite1.cxx +++ b/panda/src/grutil/grutil_composite1.cxx @@ -6,4 +6,6 @@ #include "frameRateMeter.cxx" #include "openCVTexture.cxx" #include "ffmpegTexture.cxx" +#include "nodeVertexTransform.cxx" +#include "rigidBodyCombiner.cxx" diff --git a/panda/src/grutil/nodeVertexTransform.I b/panda/src/grutil/nodeVertexTransform.I new file mode 100644 index 0000000000..35e12ff318 --- /dev/null +++ b/panda/src/grutil/nodeVertexTransform.I @@ -0,0 +1,40 @@ +// Filename: nodeVertexTransform.I +// Created by: drose (22Feb07) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: NodeVertexTransform::get_node +// Access: Published +// Description: Returns the PandaNode whose transform supplies this +// object. +//////////////////////////////////////////////////////////////////// +INLINE const PandaNode *NodeVertexTransform:: +get_node() const { + return _node; +} + +//////////////////////////////////////////////////////////////////// +// Function: NodeVertexTransform::get_prev +// Access: Published +// Description: Returns the VertexTransform object whose matrix will +// be composed with the result of this node's transform. +//////////////////////////////////////////////////////////////////// +INLINE const VertexTransform *NodeVertexTransform:: +get_prev() const { + return _prev; +} diff --git a/panda/src/grutil/nodeVertexTransform.cxx b/panda/src/grutil/nodeVertexTransform.cxx new file mode 100644 index 0000000000..bf9acd2e44 --- /dev/null +++ b/panda/src/grutil/nodeVertexTransform.cxx @@ -0,0 +1,68 @@ +// Filename: nodeVertexTransform.cxx +// Created by: drose (22Feb07) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "nodeVertexTransform.h" + +TypeHandle NodeVertexTransform::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: NodeVertexTransform::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +NodeVertexTransform:: +NodeVertexTransform(const PandaNode *node, + const VertexTransform *prev) : + _node(node), + _prev(prev) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: NodeVertexTransform::get_matrix +// Access: Published, Virtual +// Description: Returns the transform of the associated node, +// composed with the previous VertexTransform if any, +// expressed as a matrix. +//////////////////////////////////////////////////////////////////// +void NodeVertexTransform:: +get_matrix(LMatrix4f &matrix) const { + if (_prev != (const VertexTransform *)NULL) { + LMatrix4f prev_matrix; + _prev->get_matrix(prev_matrix); + matrix.multiply(_node->get_transform()->get_mat(), prev_matrix); + + } else { + matrix = _node->get_transform()->get_mat(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: NodeVertexTransform::output +// Access: Published, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void NodeVertexTransform:: +output(ostream &out) const { + if (_prev != (const VertexTransform *)NULL) { + _prev->output(out); + out << " * "; + } + + out << "NodeVertexTransform(" << _node->get_name() << ")"; +} diff --git a/panda/src/grutil/nodeVertexTransform.h b/panda/src/grutil/nodeVertexTransform.h new file mode 100644 index 0000000000..32c7f81e10 --- /dev/null +++ b/panda/src/grutil/nodeVertexTransform.h @@ -0,0 +1,74 @@ +// Filename: nodeVertexTransform.h +// Created by: drose (22Feb07) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef NODEVERTEXTRANSFORM_H +#define NODEVERTEXTRANSFORM_H + +#include "pandabase.h" +#include "vertexTransform.h" + +class FactoryParams; + +//////////////////////////////////////////////////////////////////// +// Class : NodeVertexTransform +// Description : This VertexTransform gets its matrix from the +// Transform stored on a node. It can also compose its +// node's transform with another VertexTransform, +// allowing you to build up a chain of +// NodeVertexTransforms that represent a list of +// composed matrices. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA NodeVertexTransform : public VertexTransform { +PUBLISHED: + NodeVertexTransform(const PandaNode *node, + const VertexTransform *prev = NULL); + + INLINE const PandaNode *get_node() const; + INLINE const VertexTransform *get_prev() const; + + virtual void get_matrix(LMatrix4f &matrix) const; + + virtual void output(ostream &out) const; + +private: + CPT(PandaNode) _node; + CPT(VertexTransform) _prev; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + VertexTransform::init_type(); + register_type(_type_handle, "NodeVertexTransform", + VertexTransform::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; + + friend class RigidBodyCombiner; +}; + +#include "nodeVertexTransform.I" + +#endif diff --git a/panda/src/grutil/rigidBodyCombiner.I b/panda/src/grutil/rigidBodyCombiner.I new file mode 100644 index 0000000000..f1e6f6f012 --- /dev/null +++ b/panda/src/grutil/rigidBodyCombiner.I @@ -0,0 +1,18 @@ +// Filename: rigidBodyCombiner.I +// Created by: drose (22Feb07) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + diff --git a/panda/src/grutil/rigidBodyCombiner.cxx b/panda/src/grutil/rigidBodyCombiner.cxx new file mode 100644 index 0000000000..a4cf34287b --- /dev/null +++ b/panda/src/grutil/rigidBodyCombiner.cxx @@ -0,0 +1,258 @@ +// Filename: rigidBodyCombiner.cxx +// Created by: drose (22Feb07) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "rigidBodyCombiner.h" +#include "nodePath.h" +#include "geomNode.h" +#include "modelNode.h" +#include "geomVertexData.h" +#include "geomVertexFormat.h" +#include "geomVertexArrayFormat.h" +#include "geomVertexAnimationSpec.h" +#include "sceneGraphReducer.h" + +TypeHandle RigidBodyCombiner::_type_handle; + + +//////////////////////////////////////////////////////////////////// +// Function: RigidBodyCombiner::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +RigidBodyCombiner:: +RigidBodyCombiner(const string &name) : PandaNode(name) { + set_cull_callback(); + + _internal_root = new PandaNode(name); +} + +//////////////////////////////////////////////////////////////////// +// Function: RigidBodyCombiner::Copy Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +RigidBodyCombiner:: +RigidBodyCombiner(const RigidBodyCombiner ©) : PandaNode(copy) { + set_cull_callback(); + + _internal_root = copy._internal_root; + _internal_transforms = copy._internal_transforms; +} + +//////////////////////////////////////////////////////////////////// +// Function: RigidBodyCombiner::make_copy +// Access: Public, Virtual +// Description: Returns a newly-allocated PandaNode that is a shallow +// copy of this one. It will be a different pointer, +// but its internal data may or may not be shared with +// that of the original PandaNode. No children will be +// copied. +//////////////////////////////////////////////////////////////////// +PandaNode *RigidBodyCombiner:: +make_copy() const { + return new RigidBodyCombiner(*this); +} + +//////////////////////////////////////////////////////////////////// +// Function: RigidBodyCombiner::collect +// Access: Published +// Description: Walks through the entire subgraph of nodes rooted at +// this node, accumulates all of the RenderAttribs and +// Geoms below this node, flattening them into just one +// Geom (or as few as possible, if there are multiple +// different states). +// +// Nodes that have transforms on them at the time of +// collect(), or any ModelNodes with the +// preserve_transform flag, will be identified as +// "moving" nodes, and their transforms will be +// monitored as they change in future frames and each +// new transform directly applied to the vertices. +// +// This call must be made after adding any nodes to or +// removing any nodes from the subgraph rooted at this +// node. It should not be made too often, as it is a +// relatively expensive call. If you need to hide +// children of this node, consider scaling them to zero +// (or very near zero), or moving them behind the +// camera, instead. +//////////////////////////////////////////////////////////////////// +void RigidBodyCombiner:: +collect() { + _internal_root = new GeomNode(get_name()); + _internal_transforms.clear(); + + Children cr = get_children(); + int num_children = cr.get_num_children(); + for (int i = 0; i < num_children; i++) { + r_collect(cr.get_child(i), RenderState::make_empty(), NULL); + } + + SceneGraphReducer gr; + gr.apply_attribs(_internal_root); + gr.collect_vertex_data(_internal_root, ~(SceneGraphReducer::CVD_format | SceneGraphReducer::CVD_name | SceneGraphReducer::CVD_animation_type)); + gr.unify(_internal_root); +} + +//////////////////////////////////////////////////////////////////// +// Function: RigidBodyCombiner::get_internal_scene +// Access: Published +// Description: Returns a special NodePath that represents the +// internal node of this object. This is the node that +// is actually sent to the graphics card for rendering; +// it contains the collection of the children of this +// node into as few Geoms as possible. +// +// This node is filled up by the last call to collect(). +//////////////////////////////////////////////////////////////////// +NodePath RigidBodyCombiner:: +get_internal_scene() { + return NodePath(_internal_root); +} + +//////////////////////////////////////////////////////////////////// +// Function: RigidBodyCombiner::cull_callback +// Access: Protected, Virtual +// Description: 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. +// +// Note that this function will *not* be called unless +// set_cull_callback() is called in the constructor of +// the derived class. It is necessary to call +// set_cull_callback() to indicated that we require +// cull_callback() to be called. +// +// 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 RigidBodyCombiner:: +cull_callback(CullTraverser *trav, CullTraverserData &data) { + // Pretend that all of our transforms have been modified (since we + // don't really know which ones have). + Thread *current_thread = Thread::get_current_thread(); + Transforms::iterator ti; + for (ti = _internal_transforms.begin(); + ti != _internal_transforms.end(); + ++ti) { + (*ti)->mark_modified(current_thread); + } + + // Render the internal scene only--this is the optimized scene. + CullTraverserData next_data(data, _internal_root); + trav->traverse(next_data); + + // Do not directly render the nodes beneath this node. + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: RigidBodyCombiner::r_collect +// Access: Private +// Description: Recursively visits each child or descedant of this +// node, accumulating state and transform as we go. +// When GeomNodes are encountered, their Geoms are +// extracted and added to the _internal_root node. +//////////////////////////////////////////////////////////////////// +void RigidBodyCombiner:: +r_collect(PandaNode *node, const RenderState *state, + const VertexTransform *transform) { + CPT(RenderState) next_state = state->compose(node->get_state()); + CPT(VertexTransform) next_transform = transform; + if (!node->get_transform()->is_identity() || + node->is_of_type(ModelNode::get_class_type()) && + DCAST(ModelNode, node)->get_preserve_transform() != ModelNode::PT_none) { + // This node has a transform we need to keep. + PT(NodeVertexTransform) new_transform = new NodeVertexTransform(node, transform); + _internal_transforms.push_back(new_transform); + next_transform = new_transform.p(); + + } + + if (node->is_geom_node()) { + GeomNode *gnode = DCAST(GeomNode, node); + GeomNode *root_gnode = DCAST(GeomNode, _internal_root); + + int num_geoms = gnode->get_num_geoms(); + for (int i = 0; i < num_geoms; ++i) { + PT(Geom) geom = gnode->get_geom(i)->make_copy(); + if (transform != (const VertexTransform *)NULL) { + geom->set_vertex_data(convert_vd(transform, geom->get_vertex_data())); + } + CPT(RenderState) gstate = next_state->compose(gnode->get_geom_state(i)); + root_gnode->add_geom(geom, gstate); + } + } + + Children cr = node->get_children(); + int num_children = cr.get_num_children(); + for (int i = 0; i < num_children; i++) { + r_collect(cr.get_child(i), next_state, next_transform); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: RigidBodyCombiner::convert_vd +// Access: Private +// Description: Converts a GeomVertexData to a new form in which all +// of the vertices are transformed by the node's +// transform. +//////////////////////////////////////////////////////////////////// +PT(GeomVertexData) RigidBodyCombiner:: +convert_vd(const VertexTransform *transform, const GeomVertexData *orig) { + // TODO: unify this operation for unique transform/data combinations. + + PT(GeomVertexFormat) format = new GeomVertexFormat(*orig->get_format()); + if (!orig->get_format()->has_column(InternalName::get_transform_blend())) { + PT(GeomVertexArrayFormat) af = + new GeomVertexArrayFormat(InternalName::get_transform_blend(), 1, + Geom::NT_uint16, Geom::C_index); + format->add_array(af); + } + + GeomVertexAnimationSpec spec; + spec.set_panda(); + format->set_animation(spec); + + CPT(GeomVertexFormat) new_format = GeomVertexFormat::register_format(format); + CPT(GeomVertexData) converted = orig->convert_to(new_format); + PT(GeomVertexData) new_data = new GeomVertexData(*converted); + + if (new_data->get_transform_blend_table() == (TransformBlendTable *)NULL) { + // Create a new table that has just the one blend: all vertices + // hard-assigned to the indicated transform. + PT(TransformBlendTable) new_table = new TransformBlendTable; + new_table->add_blend(TransformBlend(transform, 1.0f)); + new_table->set_rows(SparseArray::range(0, new_data->get_num_rows())); + new_data->set_transform_blend_table(new_table); + } else { + // The GeomVertexData already has a TransformBlendTable. In this + // case, we'll have to adjust it. TODO. + } + + return new_data; +} diff --git a/panda/src/grutil/rigidBodyCombiner.h b/panda/src/grutil/rigidBodyCombiner.h new file mode 100644 index 0000000000..88bad213f9 --- /dev/null +++ b/panda/src/grutil/rigidBodyCombiner.h @@ -0,0 +1,103 @@ +// Filename: rigidBodyCombiner.h +// Created by: drose (22Feb07) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef RIGIDBODYCOMBINER_H +#define RIGIDBODYCOMBINER_H + +#include "pandabase.h" + +#include "pandaNode.h" +#include "nodeVertexTransform.h" +#include "pvector.h" + +class NodePath; + +//////////////////////////////////////////////////////////////////// +// Class : RigidBodyCombiner +// Description : This is a special node that combines multiple +// independently-moving rigid nodes into one Geom +// internally (or as few Geoms as possible), for the +// purposes of improving rendering performance. +// +// To use it, parent a number of moving objects to this +// node and call collect(). A child node is identified +// as "moving" if (a) it has a non-identity transform +// initially, or (b) it is a ModelNode with the +// preserve_transform flag set. Any other nodes will be +// considered static, and later transforms applied to +// them will not be identified. +// +// You should call collect() only at startup or if you +// change the set of children; it is a relatively +// expensive call. +// +// Once you call collect(), you may change the +// transforms on the child nodes freely without having +// to call collect() again. +// +// RenderEffects such as Billboards are not supported +// below this node. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA RigidBodyCombiner : public PandaNode { +PUBLISHED: + RigidBodyCombiner(const string &name); +protected: + RigidBodyCombiner(const RigidBodyCombiner ©); + virtual PandaNode *make_copy() const; + +PUBLISHED: + void collect(); + + NodePath get_internal_scene(); + +public: + // From parent class PandaNode + virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data); + +private: + void r_collect(PandaNode *node, const RenderState *state, + const VertexTransform *transform); + PT(GeomVertexData) convert_vd(const VertexTransform *transform, + const GeomVertexData *orig); + + PT(PandaNode) _internal_root; + + typedef pvector< PT(NodeVertexTransform) > Transforms; + Transforms _internal_transforms; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + PandaNode::init_type(); + register_type(_type_handle, "RigidBodyCombiner", + PandaNode::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +#include "rigidBodyCombiner.I" + +#endif