Panda3D
|
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 ©) : 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 }