Panda3D
 All Classes Functions Variables Enumerations
rigidBodyCombiner.cxx
00001 // Filename: rigidBodyCombiner.cxx
00002 // Created by:  drose (22Feb07)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "rigidBodyCombiner.h"
00016 #include "nodePath.h"
00017 #include "geomNode.h"
00018 #include "modelNode.h"
00019 #include "geomVertexData.h"
00020 #include "geomVertexFormat.h"
00021 #include "geomVertexArrayFormat.h"
00022 #include "geomVertexAnimationSpec.h"
00023 #include "sceneGraphReducer.h"
00024 #include "omniBoundingVolume.h"
00025 
00026 TypeHandle RigidBodyCombiner::_type_handle;
00027 
00028 
00029 ////////////////////////////////////////////////////////////////////
00030 //     Function: RigidBodyCombiner::Constructor
00031 //       Access: Published
00032 //  Description:
00033 ////////////////////////////////////////////////////////////////////
00034 RigidBodyCombiner::
00035 RigidBodyCombiner(const string &name) : PandaNode(name) {
00036   set_cull_callback();
00037 
00038   _internal_root = new PandaNode(name);
00039 
00040   // We don't want to perform any additional culling once we get
00041   // within the RigidBodyCombiner.  The internal Geom's bounding
00042   // volume is not updated and might not be accurate.  However, the
00043   // bounding volume of the RigidBodyCombiner itself should be
00044   // accurate, and this is sufficient.
00045   _internal_root->set_bounds(new OmniBoundingVolume);
00046   _internal_root->set_final(true);
00047 }
00048 
00049 ////////////////////////////////////////////////////////////////////
00050 //     Function: RigidBodyCombiner::Copy Constructor
00051 //       Access: Published
00052 //  Description:
00053 ////////////////////////////////////////////////////////////////////
00054 RigidBodyCombiner::
00055 RigidBodyCombiner(const RigidBodyCombiner &copy) : PandaNode(copy) {
00056   set_cull_callback();
00057 
00058   _internal_root = copy._internal_root;
00059   _internal_transforms = copy._internal_transforms;
00060 }
00061 
00062 ////////////////////////////////////////////////////////////////////
00063 //     Function: RigidBodyCombiner::make_copy
00064 //       Access: Public, Virtual
00065 //  Description: Returns a newly-allocated PandaNode that is a shallow
00066 //               copy of this one.  It will be a different pointer,
00067 //               but its internal data may or may not be shared with
00068 //               that of the original PandaNode.  No children will be
00069 //               copied.
00070 ////////////////////////////////////////////////////////////////////
00071 PandaNode *RigidBodyCombiner::
00072 make_copy() const {
00073   return new RigidBodyCombiner(*this);
00074 }
00075 
00076 ////////////////////////////////////////////////////////////////////
00077 //     Function: RigidBodyCombiner::collect
00078 //       Access: Published
00079 //  Description: Walks through the entire subgraph of nodes rooted at
00080 //               this node, accumulates all of the RenderAttribs and
00081 //               Geoms below this node, flattening them into just one
00082 //               Geom (or as few as possible, if there are multiple
00083 //               different states).
00084 //
00085 //               Nodes that have transforms on them at the time of
00086 //               collect(), or any ModelNodes with the
00087 //               preserve_transform flag, will be identified as
00088 //               "moving" nodes, and their transforms will be
00089 //               monitored as they change in future frames and each
00090 //               new transform directly applied to the vertices.
00091 //               
00092 //               This call must be made after adding any nodes to or
00093 //               removing any nodes from the subgraph rooted at this
00094 //               node.  It should not be made too often, as it is a
00095 //               relatively expensive call.  If you need to hide
00096 //               children of this node, consider scaling them to zero
00097 //               (or very near zero), or moving them behind the
00098 //               camera, instead.
00099 ////////////////////////////////////////////////////////////////////
00100 void RigidBodyCombiner::
00101 collect() {
00102   _internal_root = new GeomNode(get_name());
00103   _internal_transforms.clear();
00104   _vd_table.clear();
00105 
00106   Children cr = get_children();
00107   int num_children = cr.get_num_children();
00108   for (int i = 0; i < num_children; i++) {
00109     r_collect(cr.get_child(i), RenderState::make_empty(), NULL);
00110   }
00111 
00112   _vd_table.clear();
00113 
00114   SceneGraphReducer gr;
00115   gr.apply_attribs(_internal_root);
00116   gr.collect_vertex_data(_internal_root, ~(SceneGraphReducer::CVD_format | SceneGraphReducer::CVD_name | SceneGraphReducer::CVD_animation_type));
00117   gr.unify(_internal_root, false);
00118 }
00119 
00120 ////////////////////////////////////////////////////////////////////
00121 //     Function: RigidBodyCombiner::get_internal_scene
00122 //       Access: Published
00123 //  Description: Returns a special NodePath that represents the
00124 //               internal node of this object.  This is the node that
00125 //               is actually sent to the graphics card for rendering;
00126 //               it contains the collection of the children of this
00127 //               node into as few Geoms as possible.  
00128 //
00129 //               This node is filled up by the last call to collect().
00130 ////////////////////////////////////////////////////////////////////
00131 NodePath RigidBodyCombiner::
00132 get_internal_scene() {
00133   return NodePath(_internal_root);
00134 }
00135 
00136 ////////////////////////////////////////////////////////////////////
00137 //     Function: RigidBodyCombiner::cull_callback
00138 //       Access: Protected, Virtual
00139 //  Description: This function will be called during the cull
00140 //               traversal to perform any additional operations that
00141 //               should be performed at cull time.  This may include
00142 //               additional manipulation of render state or additional
00143 //               visible/invisible decisions, or any other arbitrary
00144 //               operation.
00145 //
00146 //               Note that this function will *not* be called unless
00147 //               set_cull_callback() is called in the constructor of
00148 //               the derived class.  It is necessary to call
00149 //               set_cull_callback() to indicated that we require
00150 //               cull_callback() to be called.
00151 //
00152 //               By the time this function is called, the node has
00153 //               already passed the bounding-volume test for the
00154 //               viewing frustum, and the node's transform and state
00155 //               have already been applied to the indicated
00156 //               CullTraverserData object.
00157 //
00158 //               The return value is true if this node should be
00159 //               visible, or false if it should be culled.
00160 ////////////////////////////////////////////////////////////////////
00161 bool RigidBodyCombiner::
00162 cull_callback(CullTraverser *trav, CullTraverserData &data) {
00163   // Pretend that all of our transforms have been modified (since we
00164   // don't really know which ones have).
00165   Thread *current_thread = Thread::get_current_thread();
00166   Transforms::iterator ti;
00167   for (ti = _internal_transforms.begin(); 
00168        ti != _internal_transforms.end(); 
00169        ++ti) {
00170     (*ti)->mark_modified(current_thread);
00171   }
00172 
00173   // Render the internal scene only--this is the optimized scene.
00174   CullTraverserData next_data(data, _internal_root);
00175   trav->traverse(next_data);
00176 
00177   // Do not directly render the nodes beneath this node.
00178   return false;
00179 }
00180 
00181 ////////////////////////////////////////////////////////////////////
00182 //     Function: RigidBodyCombiner::r_collect
00183 //       Access: Private
00184 //  Description: Recursively visits each child or descedant of this
00185 //               node, accumulating state and transform as we go.
00186 //               When GeomNodes are encountered, their Geoms are
00187 //               extracted and added to the _internal_root node.
00188 ////////////////////////////////////////////////////////////////////
00189 void RigidBodyCombiner::
00190 r_collect(PandaNode *node, const RenderState *state, 
00191           const VertexTransform *transform) {
00192   CPT(RenderState) next_state = state->compose(node->get_state());
00193   CPT(VertexTransform) next_transform = transform;
00194   if (!node->get_transform()->is_identity() ||
00195       node->is_of_type(ModelNode::get_class_type()) &&
00196       DCAST(ModelNode, node)->get_preserve_transform() != ModelNode::PT_none) {
00197     // This node has a transform we need to keep.
00198     PT(NodeVertexTransform) new_transform = new NodeVertexTransform(node, transform);
00199     _internal_transforms.push_back(new_transform);
00200     next_transform = new_transform.p();
00201     
00202   }
00203 
00204   if (node->is_geom_node()) {
00205     GeomNode *gnode = DCAST(GeomNode, node);
00206     GeomNode *root_gnode = DCAST(GeomNode, _internal_root);
00207 
00208     int num_geoms = gnode->get_num_geoms();
00209     for (int i = 0; i < num_geoms; ++i) {
00210       PT(Geom) geom = gnode->get_geom(i)->make_copy();
00211       if (next_transform != (const VertexTransform *)NULL) {
00212         geom->set_vertex_data(convert_vd(next_transform, geom->get_vertex_data()));
00213       }
00214       CPT(RenderState) gstate = next_state->compose(gnode->get_geom_state(i));
00215       root_gnode->add_geom(geom, gstate);
00216     }
00217   }
00218 
00219   Children cr = node->get_children();
00220   int num_children = cr.get_num_children();
00221   for (int i = 0; i < num_children; i++) {
00222     r_collect(cr.get_child(i), next_state, next_transform);
00223   }
00224 }
00225 
00226 ////////////////////////////////////////////////////////////////////
00227 //     Function: RigidBodyCombiner::convert_vd
00228 //       Access: Private
00229 //  Description: Converts a GeomVertexData to a new form in which all
00230 //               of the vertices are transformed by the node's
00231 //               transform.
00232 ////////////////////////////////////////////////////////////////////
00233 PT(GeomVertexData) RigidBodyCombiner::
00234 convert_vd(const VertexTransform *transform, const GeomVertexData *orig) {
00235   // First, unify this operation for unique transform/data
00236   // combinations.  If we encounter a given GeomVertexData more than
00237   // once under the same transform, we should return exactly the same
00238   // GeomVertexData.
00239   VDTable::iterator vdti = _vd_table.find(VDUnifier(transform, orig));
00240   if (vdti != _vd_table.end()) {
00241     return (*vdti).second;
00242   }
00243 
00244   PT(GeomVertexFormat) format = new GeomVertexFormat(*orig->get_format());
00245   if (!orig->get_format()->has_column(InternalName::get_transform_blend())) {
00246     PT(GeomVertexArrayFormat) af = 
00247       new GeomVertexArrayFormat(InternalName::get_transform_blend(), 1, 
00248                                 Geom::NT_uint16, Geom::C_index);
00249     format->add_array(af);
00250   }
00251 
00252   GeomVertexAnimationSpec spec;
00253   spec.set_panda();
00254   format->set_animation(spec);
00255   format->maybe_align_columns_for_animation();
00256 
00257   CPT(GeomVertexFormat) new_format = GeomVertexFormat::register_format(format);
00258   CPT(GeomVertexData) converted = orig->convert_to(new_format);
00259   PT(GeomVertexData) new_data = new GeomVertexData(*converted);
00260   
00261   if (new_data->get_transform_blend_table() == (TransformBlendTable *)NULL) {
00262     // Create a new table that has just the one blend: all vertices
00263     // hard-assigned to the indicated transform.
00264     PT(TransformBlendTable) new_table = new TransformBlendTable;
00265     new_table->add_blend(TransformBlend(transform, 1.0f));
00266     new_table->set_rows(SparseArray::range(0, new_data->get_num_rows()));
00267     new_data->set_transform_blend_table(new_table);
00268   } else {
00269     // The GeomVertexData already has a TransformBlendTable.  In this
00270     // case, we'll have to adjust it.  TODO.
00271   }
00272 
00273   // Store the result for the next time.
00274   _vd_table[VDUnifier(transform, orig)] = new_data;
00275 
00276   return new_data;
00277 }
 All Classes Functions Variables Enumerations