Panda3D
|
00001 // Filename: geomNode.cxx 00002 // Created by: drose (23eb02) 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 "geomNode.h" 00016 #include "geom.h" 00017 #include "geomTransformer.h" 00018 #include "sceneGraphReducer.h" 00019 #include "accumulatedAttribs.h" 00020 #include "colorAttrib.h" 00021 #include "colorScaleAttrib.h" 00022 #include "texMatrixAttrib.h" 00023 #include "textureAttrib.h" 00024 #include "bamReader.h" 00025 #include "bamWriter.h" 00026 #include "datagram.h" 00027 #include "datagramIterator.h" 00028 #include "indent.h" 00029 #include "pset.h" 00030 #include "config_pgraph.h" 00031 #include "graphicsStateGuardianBase.h" 00032 #include "boundingBox.h" 00033 #include "config_mathutil.h" 00034 00035 00036 bool allow_flatten_color = ConfigVariableBool 00037 ("allow-flatten-color", false, 00038 PRC_DESC("allows color to always be flattened to vertices")); 00039 00040 TypeHandle GeomNode::_type_handle; 00041 00042 //////////////////////////////////////////////////////////////////// 00043 // Function: GeomNode::Constructor 00044 // Access: Published 00045 // Description: 00046 //////////////////////////////////////////////////////////////////// 00047 GeomNode:: 00048 GeomNode(const string &name) : 00049 PandaNode(name) 00050 { 00051 _preserved = preserve_geom_nodes; 00052 00053 // GeomNodes have a certain set of bits on by default. 00054 set_into_collide_mask(get_default_collide_mask()); 00055 } 00056 00057 //////////////////////////////////////////////////////////////////// 00058 // Function: GeomNode::Copy Constructor 00059 // Access: Protected 00060 // Description: 00061 //////////////////////////////////////////////////////////////////// 00062 GeomNode:: 00063 GeomNode(const GeomNode ©) : 00064 PandaNode(copy), 00065 _preserved(copy._preserved), 00066 _cycler(copy._cycler) 00067 { 00068 } 00069 00070 //////////////////////////////////////////////////////////////////// 00071 // Function: GeomNode::Destructor 00072 // Access: Public, Virtual 00073 // Description: 00074 //////////////////////////////////////////////////////////////////// 00075 GeomNode:: 00076 ~GeomNode() { 00077 } 00078 00079 //////////////////////////////////////////////////////////////////// 00080 // Function: GeomNode::make_copy 00081 // Access: Public, Virtual 00082 // Description: Returns a newly-allocated PandaNode that is a shallow 00083 // copy of this one. It will be a different pointer, 00084 // but its internal data may or may not be shared with 00085 // that of the original PandaNode. No children will be 00086 // copied. 00087 //////////////////////////////////////////////////////////////////// 00088 PandaNode *GeomNode:: 00089 make_copy() const { 00090 return new GeomNode(*this); 00091 } 00092 00093 //////////////////////////////////////////////////////////////////// 00094 // Function: GeomNode::apply_attribs_to_vertices 00095 // Access: Public, Virtual 00096 // Description: Applies whatever attributes are specified in the 00097 // AccumulatedAttribs object (and by the attrib_types 00098 // bitmask) to the vertices on this node, if 00099 // appropriate. If this node uses geom arrays like a 00100 // GeomNode, the supplied GeomTransformer may be used to 00101 // unify shared arrays across multiple different nodes. 00102 // 00103 // This is a generalization of xform(). 00104 //////////////////////////////////////////////////////////////////// 00105 void GeomNode:: 00106 apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, 00107 GeomTransformer &transformer) { 00108 if (pgraph_cat.is_debug()) { 00109 pgraph_cat.debug() 00110 << "Transforming geometry:\n"; 00111 attribs.write(pgraph_cat.debug(false), attrib_types, 2); 00112 } 00113 00114 if ((attrib_types & SceneGraphReducer::TT_transform) != 0) { 00115 if (!attribs._transform->is_identity()) { 00116 transformer.transform_vertices(this, attribs._transform->get_mat()); 00117 } 00118 } 00119 00120 Thread *current_thread = Thread::get_current_thread(); 00121 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 00122 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 00123 GeomList::iterator gi; 00124 PT(GeomList) geoms = cdata->modify_geoms(); 00125 00126 // Iterate based on the number of geoms, not using STL iterators. 00127 // This allows us to append to the list in the code below (which 00128 // we might do when doublesiding polys) without visiting those new 00129 // nodes during the traversal. 00130 size_t num_geoms = geoms->size(); 00131 for (size_t i = 0; i < num_geoms; ++i) { 00132 GeomEntry *entry = &(*geoms)[i]; 00133 PT(Geom) new_geom = entry->_geom.get_read_pointer()->make_copy(); 00134 00135 AccumulatedAttribs geom_attribs = attribs; 00136 entry->_state = geom_attribs.collect(entry->_state, attrib_types); 00137 00138 bool any_changed = false; 00139 00140 if ((attrib_types & SceneGraphReducer::TT_color) != 0) { 00141 CPT(RenderAttrib) ra = geom_attribs._color; 00142 if (ra != (const RenderAttrib *)NULL) { 00143 int override = geom_attribs._color_override; 00144 entry->_state = entry->_state->add_attrib(ra, override); 00145 } 00146 00147 ra = entry->_state->get_attrib_def(ColorAttrib::get_class_slot()); 00148 CPT (ColorAttrib) ca = DCAST(ColorAttrib, ra); 00149 if (ca->get_color_type() != ColorAttrib::T_vertex) { 00150 if(allow_flatten_color) { 00151 if(transformer.set_color(new_geom, ca->get_color())) { 00152 any_changed = true; 00153 entry->_state = entry->_state->set_attrib(ColorAttrib::make_vertex()); 00154 } 00155 } else { 00156 if (transformer.remove_column(new_geom, InternalName::get_color())) { 00157 any_changed = true; 00158 } 00159 } 00160 } 00161 } 00162 if ((attrib_types & SceneGraphReducer::TT_color_scale) != 0) { 00163 if (geom_attribs._color_scale != (const RenderAttrib *)NULL) { 00164 CPT(ColorScaleAttrib) csa = DCAST(ColorScaleAttrib, geom_attribs._color_scale); 00165 if (csa->get_scale() != LVecBase4(1.0f, 1.0f, 1.0f, 1.0f)) { 00166 00167 00168 // Now, if we have an "off" or "flat" color attribute, we 00169 // simply modify the color attribute, and leave the 00170 // vertices alone. 00171 CPT(RenderAttrib) ra = entry->_state->get_attrib_def(ColorAttrib::get_class_slot()); 00172 CPT(ColorAttrib) ca = DCAST(ColorAttrib, ra); 00173 if(allow_flatten_color) { 00174 if (transformer.transform_colors(new_geom, csa->get_scale())) { 00175 any_changed = true; 00176 } 00177 } else { 00178 if (ca->get_color_type() == ColorAttrib::T_off) { 00179 entry->_state = entry->_state->set_attrib(ColorAttrib::make_vertex()); 00180 // ColorAttrib::T_off means the color scale becomes 00181 // the new color. 00182 entry->_state = entry->_state->set_attrib(ColorAttrib::make_flat(csa->get_scale())); 00183 00184 } else if (ca->get_color_type() == ColorAttrib::T_flat) { 00185 // ColorAttrib::T_flat means the color scale modulates 00186 // the specified color to produce a new color. 00187 const LColor &c1 = ca->get_color(); 00188 const LVecBase4 &c2 = csa->get_scale(); 00189 LColor color(c1[0] * c2[0], c1[1] * c2[1], 00190 c1[2] * c2[2], c1[3] * c2[3]); 00191 entry->_state = entry->_state->set_attrib(ColorAttrib::make_flat(color)); 00192 00193 } else { 00194 // Otherwise, we have vertex color, and we just scale 00195 // it normally. 00196 if (transformer.transform_colors(new_geom, csa->get_scale())) { 00197 any_changed = true; 00198 } 00199 entry->_state = entry->_state->set_attrib(ColorAttrib::make_vertex()); 00200 } 00201 } 00202 } 00203 } 00204 } 00205 00206 if ((attrib_types & SceneGraphReducer::TT_tex_matrix) != 0) { 00207 if (geom_attribs._tex_matrix != (const RenderAttrib *)NULL) { 00208 // Determine which texture coordinate names are used more than 00209 // once. This assumes we have discovered all of the textures 00210 // that are in effect on the GeomNode; this may not be true if 00211 // there is a texture that has been applied at a node above 00212 // that from which we started the flatten operation, but 00213 // caveat programmer. 00214 NameCount name_count; 00215 00216 if (geom_attribs._texture != (RenderAttrib *)NULL) { 00217 const TextureAttrib *ta = DCAST(TextureAttrib, geom_attribs._texture); 00218 int num_on_stages = ta->get_num_on_stages(); 00219 for (int si = 0; si < num_on_stages; si++) { 00220 TextureStage *stage = ta->get_on_stage(si); 00221 const InternalName *name = stage->get_texcoord_name(); 00222 count_name(name_count, name); 00223 } 00224 } 00225 00226 const TexMatrixAttrib *tma = 00227 DCAST(TexMatrixAttrib, geom_attribs._tex_matrix); 00228 00229 CPT(TexMatrixAttrib) new_tma = DCAST(TexMatrixAttrib, TexMatrixAttrib::make()); 00230 00231 int num_stages = tma->get_num_stages(); 00232 for (int i = 0; i < num_stages; i++) { 00233 TextureStage *stage = tma->get_stage(i); 00234 InternalName *name = stage->get_texcoord_name(); 00235 if (get_name_count(name_count, name) > 1) { 00236 // We can't transform these texcoords, since the name is 00237 // used by more than one active stage. 00238 new_tma = DCAST(TexMatrixAttrib, new_tma->add_stage(stage, tma->get_transform(stage))); 00239 00240 } else { 00241 // It's safe to transform these texcoords; the name is 00242 // used by no more than one active stage. 00243 if (transformer.transform_texcoords(new_geom, name, name, tma->get_mat(stage))) { 00244 any_changed = true; 00245 } 00246 } 00247 } 00248 00249 if (!new_tma->is_empty()) { 00250 entry->_state = entry->_state->add_attrib(new_tma); 00251 } 00252 } 00253 } 00254 00255 if ((attrib_types & SceneGraphReducer::TT_other) != 0) { 00256 entry->_state = geom_attribs._other->compose(entry->_state); 00257 } 00258 00259 // We handle cull_face last, since that might involve 00260 // duplicating the geom, and we'd also like to duplicate all of 00261 // the changes we may have applied in the above. 00262 00263 if ((attrib_types & SceneGraphReducer::TT_cull_face) != 0) { 00264 if (geom_attribs._cull_face != (const RenderAttrib *)NULL) { 00265 const CullFaceAttrib *cfa = DCAST(CullFaceAttrib, geom_attribs._cull_face); 00266 CullFaceAttrib::Mode mode = cfa->get_effective_mode(); 00267 switch (mode) { 00268 case CullFaceAttrib::M_cull_none: 00269 // Doublesided polys. Duplicate them. 00270 { 00271 bool has_normals = (new_geom->get_vertex_data()->has_column(InternalName::get_normal())); 00272 if (has_normals) { 00273 // If the geometry has normals, we have to duplicate 00274 // it to reverse the normals on the duplicate copy. 00275 PT(Geom) dup_geom = new_geom->reverse(); 00276 transformer.reverse_normals(dup_geom); 00277 00278 geoms->push_back(GeomEntry(dup_geom, entry->_state)); 00279 00280 // The above push_back() operation might have 00281 // invalidated our old pointer into the list, so we 00282 // reassign it now. 00283 entry = &(*geoms)[i]; 00284 00285 } else { 00286 // If there are no normals, we can just doubleside it in 00287 // place. This is preferable because we can share vertices. 00288 new_geom->doubleside_in_place(); 00289 any_changed = true; 00290 } 00291 } 00292 break; 00293 00294 case CullFaceAttrib::M_cull_counter_clockwise: 00295 // Reverse winding order. 00296 new_geom->reverse_in_place(); 00297 transformer.reverse_normals(new_geom); 00298 any_changed = true; 00299 break; 00300 00301 default: 00302 break; 00303 } 00304 } 00305 } 00306 00307 if (any_changed) { 00308 entry->_geom = new_geom; 00309 } 00310 } 00311 } 00312 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 00313 00314 if ((attrib_types & SceneGraphReducer::TT_apply_texture_color) != 0) { 00315 transformer.apply_texture_colors(this, attribs._other); 00316 } 00317 00318 transformer.register_vertices(this, false); 00319 } 00320 00321 //////////////////////////////////////////////////////////////////// 00322 // Function: GeomNode::xform 00323 // Access: Public, Virtual 00324 // Description: Transforms the contents of this node by the indicated 00325 // matrix, if it means anything to do so. For most 00326 // kinds of nodes, this does nothing. 00327 // 00328 // For a GeomNode, this does the right thing, but it is 00329 // better to use a GeomTransformer instead, since it 00330 // will share the new arrays properly between different 00331 // GeomNodes. 00332 //////////////////////////////////////////////////////////////////// 00333 void GeomNode:: 00334 xform(const LMatrix4 &mat) { 00335 GeomTransformer transformer; 00336 transformer.transform_vertices(this, mat); 00337 } 00338 00339 00340 //////////////////////////////////////////////////////////////////// 00341 // Function: GeomNode::safe_to_flatten 00342 // Access: Public, Virtual 00343 // Description: Returns true if it is generally safe to flatten out 00344 // this particular kind of PandaNode by duplicating 00345 // instances (by calling dupe_for_flatten()), false 00346 // otherwise (for instance, a Camera cannot be safely 00347 // flattened, because the Camera pointer itself is 00348 // meaningful). 00349 //////////////////////////////////////////////////////////////////// 00350 bool GeomNode:: 00351 safe_to_flatten() const { 00352 if (_preserved) { 00353 return false; 00354 } 00355 00356 return true; 00357 } 00358 00359 //////////////////////////////////////////////////////////////////// 00360 // Function: GeomNode::safe_to_combine 00361 // Access: Public, Virtual 00362 // Description: Returns true if it is generally safe to combine this 00363 // particular kind of PandaNode with other kinds of 00364 // PandaNodes of compatible type, adding children or 00365 // whatever. For instance, an LODNode should not be 00366 // combined with any other PandaNode, because its set of 00367 // children is meaningful. 00368 //////////////////////////////////////////////////////////////////// 00369 bool GeomNode:: 00370 safe_to_combine() const { 00371 if (_preserved) { 00372 return false; 00373 } 00374 00375 return true; 00376 } 00377 00378 //////////////////////////////////////////////////////////////////// 00379 // Function: GeomNode::r_prepare_scene 00380 // Access: Protected, Virtual 00381 // Description: The recursive implementation of prepare_scene(). 00382 // Don't call this directly; call 00383 // PandaNode::prepare_scene() or 00384 // NodePath::prepare_scene() instead. 00385 //////////////////////////////////////////////////////////////////// 00386 void GeomNode:: 00387 r_prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state, 00388 GeomTransformer &transformer, Thread *current_thread) { 00389 PreparedGraphicsObjects *prepared_objects = gsg->get_prepared_objects(); 00390 00391 CDReader cdata(_cycler, current_thread); 00392 GeomList::const_iterator gi; 00393 CPT(GeomList) geoms = cdata->get_geoms(); 00394 for (gi = geoms->begin(); gi != geoms->end(); ++gi) { 00395 const GeomEntry &entry = (*gi); 00396 CPT(RenderState) geom_state = node_state->compose(entry._state); 00397 CPT(Geom) geom = entry._geom.get_read_pointer(); 00398 00399 // Munge the geom as required by the GSG. 00400 PT(GeomMunger) munger = gsg->get_geom_munger(geom_state, current_thread); 00401 geom = transformer.premunge_geom(geom, munger); 00402 00403 // Prepare each of the vertex arrays in the munged Geom. 00404 CPT(GeomVertexData) vdata = geom->get_vertex_data(current_thread); 00405 vdata = vdata->animate_vertices(false, current_thread); 00406 GeomVertexDataPipelineReader vdata_reader(vdata, current_thread); 00407 int num_arrays = vdata_reader.get_num_arrays(); 00408 for (int i = 0; i < num_arrays; ++i) { 00409 CPT(GeomVertexArrayData) array = vdata_reader.get_array(i); 00410 ((GeomVertexArrayData *)array.p())->prepare(prepared_objects); 00411 } 00412 00413 // And also each of the index arrays. 00414 int num_primitives = geom->get_num_primitives(); 00415 for (int i = 0; i < num_primitives; ++i) { 00416 CPT(GeomPrimitive) prim = geom->get_primitive(i); 00417 ((GeomPrimitive *)prim.p())->prepare(prepared_objects); 00418 } 00419 00420 // And now prepare each of the textures. 00421 const RenderAttrib *attrib = 00422 geom_state->get_attrib(TextureAttrib::get_class_slot()); 00423 if (attrib != (const RenderAttrib *)NULL) { 00424 const TextureAttrib *ta; 00425 DCAST_INTO_V(ta, attrib); 00426 int num_stages = ta->get_num_on_stages(); 00427 for (int i = 0; i < num_stages; ++i) { 00428 Texture *texture = ta->get_on_texture(ta->get_on_stage(i)); 00429 if (texture != (Texture *)NULL) { 00430 texture->prepare(prepared_objects); 00431 } 00432 } 00433 } 00434 } 00435 00436 PandaNode::r_prepare_scene(gsg, node_state, transformer, current_thread); 00437 } 00438 00439 00440 //////////////////////////////////////////////////////////////////// 00441 // Function: GeomNode::combine_with 00442 // Access: Public, Virtual 00443 // Description: Collapses this node with the other node, if possible, 00444 // and returns a pointer to the combined node, or NULL 00445 // if the two nodes cannot safely be combined. 00446 // 00447 // The return value may be this, other, or a new node 00448 // altogether. 00449 // 00450 // This function is called from GraphReducer::flatten(), 00451 // and need not deal with children; its job is just to 00452 // decide whether to collapse the two nodes and what the 00453 // collapsed node should look like. 00454 //////////////////////////////////////////////////////////////////// 00455 PandaNode *GeomNode:: 00456 combine_with(PandaNode *other) { 00457 if (is_exact_type(get_class_type()) && 00458 other->is_exact_type(get_class_type())) { 00459 // Two GeomNodes can combine by moving Geoms from one to the other. 00460 GeomNode *gother = DCAST(GeomNode, other); 00461 add_geoms_from(gother); 00462 return this; 00463 } 00464 00465 return PandaNode::combine_with(other); 00466 } 00467 00468 //////////////////////////////////////////////////////////////////// 00469 // Function: GeomNode::calc_tight_bounds 00470 // Access: Public, Virtual 00471 // Description: This is used to support 00472 // NodePath::calc_tight_bounds(). It is not intended to 00473 // be called directly, and it has nothing to do with the 00474 // normal Panda bounding-volume computation. 00475 // 00476 // If the node contains any geometry, this updates 00477 // min_point and max_point to enclose its bounding box. 00478 // found_any is to be set true if the node has any 00479 // geometry at all, or left alone if it has none. This 00480 // method may be called over several nodes, so it may 00481 // enter with min_point, max_point, and found_any 00482 // already set. 00483 //////////////////////////////////////////////////////////////////// 00484 CPT(TransformState) GeomNode:: 00485 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, bool &found_any, 00486 const TransformState *transform, Thread *current_thread) const { 00487 CPT(TransformState) next_transform = 00488 PandaNode::calc_tight_bounds(min_point, max_point, found_any, transform, 00489 current_thread); 00490 00491 const LMatrix4 &mat = next_transform->get_mat(); 00492 00493 CDReader cdata(_cycler, current_thread); 00494 GeomList::const_iterator gi; 00495 CPT(GeomList) geoms = cdata->get_geoms(); 00496 for (gi = geoms->begin(); gi != geoms->end(); ++gi) { 00497 CPT(Geom) geom = (*gi)._geom.get_read_pointer(); 00498 geom->calc_tight_bounds(min_point, max_point, found_any, 00499 geom->get_vertex_data(current_thread)->animate_vertices(true, current_thread), 00500 !next_transform->is_identity(), mat, 00501 current_thread); 00502 } 00503 00504 return next_transform; 00505 } 00506 00507 //////////////////////////////////////////////////////////////////// 00508 // Function: GeomNode::is_renderable 00509 // Access: Public, Virtual 00510 // Description: Returns true if there is some value to visiting this 00511 // particular node during the cull traversal for any 00512 // camera, false otherwise. This will be used to 00513 // optimize the result of get_net_draw_show_mask(), so 00514 // that any subtrees that contain only nodes for which 00515 // is_renderable() is false need not be visited. 00516 //////////////////////////////////////////////////////////////////// 00517 bool GeomNode:: 00518 is_renderable() const { 00519 return true; 00520 } 00521 00522 //////////////////////////////////////////////////////////////////// 00523 // Function: GeomNode::add_for_draw 00524 // Access: Public, Virtual 00525 // Description: Adds the node's contents to the CullResult we are 00526 // building up during the cull traversal, so that it 00527 // will be drawn at render time. For most nodes other 00528 // than GeomNodes, this is a do-nothing operation. 00529 //////////////////////////////////////////////////////////////////// 00530 void GeomNode:: 00531 add_for_draw(CullTraverser *trav, CullTraverserData &data) { 00532 trav->_geom_nodes_pcollector.add_level(1); 00533 00534 if (pgraph_cat.is_spam()) { 00535 pgraph_cat.spam() 00536 << "Found " << *this << " in state " << *data._state 00537 << " draw_mask = " << data._draw_mask << "\n"; 00538 } 00539 00540 // Get all the Geoms, with no decalling. 00541 Geoms geoms = get_geoms(trav->get_current_thread()); 00542 int num_geoms = geoms.get_num_geoms(); 00543 trav->_geoms_pcollector.add_level(num_geoms); 00544 CPT(TransformState) net_transform = data.get_net_transform(trav); 00545 CPT(TransformState) modelview_transform = data.get_modelview_transform(trav); 00546 CPT(TransformState) internal_transform = trav->get_gsg()->get_cs_transform()->compose(modelview_transform); 00547 00548 for (int i = 0; i < num_geoms; i++) { 00549 const Geom *geom = geoms.get_geom(i); 00550 if (geom->is_empty()) { 00551 continue; 00552 } 00553 00554 CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i)); 00555 if (state->has_cull_callback() && !state->cull_callback(trav, data)) { 00556 // Cull. 00557 continue; 00558 } 00559 00560 // Cull the Geom bounding volume against the view frustum 00561 // and/or the cull planes. Don't bother unless we've got more 00562 // than one Geom, since otherwise the bounding volume of the 00563 // GeomNode is (probably) the same as that of the one Geom, 00564 // and we've already culled against that. 00565 if (num_geoms > 1) { 00566 if (data._view_frustum != (GeometricBoundingVolume *)NULL) { 00567 // Cull the individual Geom against the view frustum. 00568 CPT(BoundingVolume) geom_volume = geom->get_bounds(); 00569 const GeometricBoundingVolume *geom_gbv = 00570 DCAST(GeometricBoundingVolume, geom_volume); 00571 00572 int result = data._view_frustum->contains(geom_gbv); 00573 if (result == BoundingVolume::IF_no_intersection) { 00574 // Cull this Geom. 00575 continue; 00576 } 00577 } 00578 if (!data._cull_planes->is_empty()) { 00579 // Also cull the Geom against the cull planes. 00580 CPT(BoundingVolume) geom_volume = geom->get_bounds(); 00581 const GeometricBoundingVolume *geom_gbv = 00582 DCAST(GeometricBoundingVolume, geom_volume); 00583 int result; 00584 data._cull_planes->do_cull(result, state, geom_gbv); 00585 if (result == BoundingVolume::IF_no_intersection) { 00586 // Cull. 00587 continue; 00588 } 00589 } 00590 } 00591 00592 CullableObject *object = 00593 new CullableObject(geom, state, net_transform, 00594 modelview_transform, internal_transform); 00595 trav->get_cull_handler()->record_object(object, trav); 00596 } 00597 } 00598 00599 //////////////////////////////////////////////////////////////////// 00600 // Function: GeomNode::get_legal_collide_mask 00601 // Access: Published, Virtual 00602 // Description: Returns the subset of CollideMask bits that may be 00603 // set for this particular type of PandaNode. For most 00604 // nodes, this is 0; it doesn't make sense to set a 00605 // CollideMask for most kinds of nodes. 00606 // 00607 // For nodes that can be collided with, such as GeomNode 00608 // and CollisionNode, this returns all bits on. 00609 //////////////////////////////////////////////////////////////////// 00610 CollideMask GeomNode:: 00611 get_legal_collide_mask() const { 00612 return CollideMask::all_on(); 00613 } 00614 00615 //////////////////////////////////////////////////////////////////// 00616 // Function: GeomNode::add_geom 00617 // Access: Published 00618 // Description: Adds a new Geom to the node. The geom is given the 00619 // indicated state (which may be 00620 // RenderState::make_empty(), to completely inherit its 00621 // state from the scene graph). 00622 //////////////////////////////////////////////////////////////////// 00623 void GeomNode:: 00624 add_geom(Geom *geom, const RenderState *state) { 00625 nassertv(geom != (Geom *)NULL); 00626 nassertv(geom->check_valid()); 00627 nassertv(state != (RenderState *)NULL); 00628 00629 Thread *current_thread = Thread::get_current_thread(); 00630 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 00631 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 00632 00633 cdata->modify_geoms()->push_back(GeomEntry(geom, state)); 00634 } 00635 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 00636 00637 mark_internal_bounds_stale(); 00638 } 00639 00640 //////////////////////////////////////////////////////////////////// 00641 // Function: GeomNode::add_geoms_from 00642 // Access: Published 00643 // Description: Copies the Geoms (and their associated RenderStates) 00644 // from the indicated GeomNode into this one. 00645 //////////////////////////////////////////////////////////////////// 00646 void GeomNode:: 00647 add_geoms_from(const GeomNode *other) { 00648 Thread *current_thread = Thread::get_current_thread(); 00649 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 00650 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 00651 CDStageReader cdata_other(other->_cycler, pipeline_stage, current_thread); 00652 00653 GeomList::const_iterator gi; 00654 CPT(GeomList) other_geoms = cdata_other->get_geoms(); 00655 PT(GeomList) this_geoms = cdata->modify_geoms(); 00656 for (gi = other_geoms->begin(); gi != other_geoms->end(); ++gi) { 00657 const GeomEntry &entry = (*gi); 00658 nassertv(entry._geom.get_read_pointer()->check_valid()); 00659 this_geoms->push_back(entry); 00660 } 00661 } 00662 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 00663 00664 mark_internal_bounds_stale(); 00665 } 00666 00667 //////////////////////////////////////////////////////////////////// 00668 // Function: GeomNode::set_geom 00669 // Access: Public 00670 // Description: Replaces the nth Geom of the node with a new pointer. 00671 // There must already be a Geom in this slot. 00672 // 00673 // Note that if this method is called in a downstream 00674 // stage (for instance, during cull or draw), then it 00675 // will propagate the new list of Geoms upstream all the 00676 // way to pipeline stage 0, which may step on changes 00677 // that were made independently in pipeline stage 0. 00678 // Use with caution. 00679 //////////////////////////////////////////////////////////////////// 00680 void GeomNode:: 00681 set_geom(int n, Geom *geom) { 00682 nassertv(geom != (Geom *)NULL); 00683 nassertv(geom->check_valid()); 00684 00685 CDWriter cdata(_cycler, true); 00686 PT(GeomList) geoms = cdata->modify_geoms(); 00687 nassertv(n >= 0 && n < (int)geoms->size()); 00688 (*geoms)[n]._geom = geom; 00689 00690 mark_internal_bounds_stale(); 00691 } 00692 00693 //////////////////////////////////////////////////////////////////// 00694 // Function: GeomNode::check_valid 00695 // Access: Published 00696 // Description: Verifies that the each Geom within the GeomNode 00697 // reference vertices that actually exist within its 00698 // GeomVertexData. Returns true if the GeomNode appears 00699 // to be valid, false otherwise. 00700 //////////////////////////////////////////////////////////////////// 00701 bool GeomNode:: 00702 check_valid() const { 00703 int num_geoms = get_num_geoms(); 00704 for (int i = 0; i < num_geoms; i++) { 00705 const Geom *geom = get_geom(i); 00706 if (!geom->check_valid()) { 00707 return false; 00708 } 00709 } 00710 00711 return true; 00712 } 00713 00714 //////////////////////////////////////////////////////////////////// 00715 // Function: GeomNode::decompose 00716 // Access: Published 00717 // Description: Calls decompose() on each Geom with the GeomNode. 00718 // This decomposes higher-order primitive types, like 00719 // triangle strips, into lower-order types like indexed 00720 // triangles. Normally there is no reason to do this, 00721 // but it can be useful as an early preprocessing step, 00722 // to allow a later call to unify() to proceed more 00723 // quickly. 00724 // 00725 // See also SceneGraphReducer::decompose(), which is the 00726 // normal way this is called. 00727 //////////////////////////////////////////////////////////////////// 00728 void GeomNode:: 00729 decompose() { 00730 Thread *current_thread = Thread::get_current_thread(); 00731 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 00732 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 00733 00734 GeomList::iterator gi; 00735 PT(GeomList) geoms = cdata->modify_geoms(); 00736 for (gi = geoms->begin(); gi != geoms->end(); ++gi) { 00737 GeomEntry &entry = (*gi); 00738 nassertv(entry._geom.test_ref_count_integrity()); 00739 PT(Geom) geom = entry._geom.get_write_pointer(); 00740 geom->decompose_in_place(); 00741 } 00742 } 00743 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 00744 } 00745 00746 //////////////////////////////////////////////////////////////////// 00747 // Function: GeomNode::unify 00748 // Access: Published 00749 // Description: Attempts to unify all of the Geoms contained within 00750 // this node into a single Geom, or at least as few 00751 // Geoms as possible. In turn, the individual 00752 // GeomPrimitives contained within each resulting Geom 00753 // are also unified. The goal is to reduce the number 00754 // of GeomPrimitives within the node as far as possible. 00755 // This may result in composite primitives, such as 00756 // triangle strips and triangle fans, being decomposed 00757 // into triangles. See also Geom::unify(). 00758 // 00759 // max_indices represents the maximum number of indices 00760 // that will be put in any one GeomPrimitive. If 00761 // preserve_order is true, then the primitives will not 00762 // be reordered during the operation, even if this 00763 // results in a suboptimal result. 00764 // 00765 // In order for this to be successful, the primitives 00766 // must reference the same GeomVertexData, have the same 00767 // fundamental primitive type, and have compatible shade 00768 // models. 00769 //////////////////////////////////////////////////////////////////// 00770 void GeomNode:: 00771 unify(int max_indices, bool preserve_order) { 00772 bool any_changed = false; 00773 00774 Thread *current_thread = Thread::get_current_thread(); 00775 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 00776 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 00777 00778 PT(GeomList) new_geoms = new GeomList; 00779 00780 // Try to unify each Geom with each preceding Geom. This is an n^2 00781 // operation, but usually there are only a handful of Geoms to 00782 // consider, so that's not a big deal. 00783 GeomList::const_iterator gi; 00784 CPT(GeomList) old_geoms = cdata->get_geoms(); 00785 for (gi = old_geoms->begin(); gi != old_geoms->end(); ++gi) { 00786 const GeomEntry &old_entry = (*gi); 00787 00788 bool unified = false; 00789 00790 // Go from back to front, to minimize damage to the primitive ordering. 00791 GeomList::reverse_iterator gj; 00792 for (gj = new_geoms->rbegin(); gj != new_geoms->rend() && !unified; ++gj) { 00793 GeomEntry &new_entry = (*gj); 00794 if (old_entry._state == new_entry._state) { 00795 // Both states match, so try to combine the primitives. 00796 CPT(Geom) old_geom = old_entry._geom.get_read_pointer(); 00797 PT(Geom) new_geom = new_entry._geom.get_write_pointer(); 00798 if (new_geom->copy_primitives_from(old_geom)) { 00799 // Successfully combined! 00800 unified = true; 00801 any_changed = true; 00802 } 00803 } 00804 00805 if (preserve_order) { 00806 // If we're insisting on preserving the order, we can only 00807 // attempt to merge with the tail of the list. 00808 break; 00809 } 00810 } 00811 00812 if (!unified) { 00813 // Couldn't unify this Geom with anything, so just add it to the 00814 // output list. 00815 new_geoms->push_back(old_entry); 00816 } 00817 } 00818 00819 // Done! We'll keep whatever's left in the output list. 00820 cdata->set_geoms(new_geoms); 00821 00822 // Finally, go back through and unify the resulting geom(s). 00823 GeomList::iterator wgi; 00824 for (wgi = new_geoms->begin(); wgi != new_geoms->end(); ++wgi) { 00825 GeomEntry &entry = (*wgi); 00826 nassertv(entry._geom.test_ref_count_integrity()); 00827 PT(Geom) geom = entry._geom.get_write_pointer(); 00828 geom->unify_in_place(max_indices, preserve_order); 00829 } 00830 } 00831 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 00832 00833 if (any_changed) { 00834 mark_internal_bounds_stale(); 00835 } 00836 } 00837 00838 //////////////////////////////////////////////////////////////////// 00839 // Function: GeomNode::write_geoms 00840 // Access: Published 00841 // Description: Writes a short description of all the Geoms in the 00842 // node. 00843 //////////////////////////////////////////////////////////////////// 00844 void GeomNode:: 00845 write_geoms(ostream &out, int indent_level) const { 00846 CDReader cdata(_cycler); 00847 write(out, indent_level); 00848 GeomList::const_iterator gi; 00849 CPT(GeomList) geoms = cdata->get_geoms(); 00850 for (gi = geoms->begin(); gi != geoms->end(); ++gi) { 00851 const GeomEntry &entry = (*gi); 00852 indent(out, indent_level + 2) 00853 << *entry._geom.get_read_pointer() << " " << *entry._state << "\n"; 00854 } 00855 } 00856 00857 //////////////////////////////////////////////////////////////////// 00858 // Function: GeomNode::write_verbose 00859 // Access: Published 00860 // Description: Writes a detailed description of all the Geoms in the 00861 // node. 00862 //////////////////////////////////////////////////////////////////// 00863 void GeomNode:: 00864 write_verbose(ostream &out, int indent_level) const { 00865 CDReader cdata(_cycler); 00866 write(out, indent_level); 00867 GeomList::const_iterator gi; 00868 CPT(GeomList) geoms = cdata->get_geoms(); 00869 for (gi = geoms->begin(); gi != geoms->end(); ++gi) { 00870 const GeomEntry &entry = (*gi); 00871 CPT(Geom) geom = entry._geom.get_read_pointer(); 00872 indent(out, indent_level + 2) 00873 << *geom << " " << *entry._state << "\n"; 00874 geom->write(out, indent_level + 4); 00875 } 00876 } 00877 00878 //////////////////////////////////////////////////////////////////// 00879 // Function: GeomNode::output 00880 // Access: Public, Virtual 00881 // Description: 00882 //////////////////////////////////////////////////////////////////// 00883 void GeomNode:: 00884 output(ostream &out) const { 00885 // Accumulate the total set of RenderAttrib types that are applied 00886 // to any of our Geoms, so we can output them too. The result will 00887 // be the list of attrib types that might be applied to some Geoms, 00888 // but not necessarily to all Geoms. 00889 00890 CDReader cdata(_cycler); 00891 00892 pset<TypeHandle> attrib_types; 00893 00894 GeomList::const_iterator gi; 00895 CPT(RenderState) common = RenderState::make_empty(); 00896 00897 CPT(GeomList) geoms = cdata->get_geoms(); 00898 for (gi = geoms->begin(); gi != geoms->end(); ++gi) { 00899 const GeomEntry &entry = (*gi); 00900 common = common->compose(entry._state); 00901 } 00902 00903 PandaNode::output(out); 00904 out << " (" << geoms->size() << " geoms"; 00905 00906 if (!common->is_empty()) { 00907 out << ": " << *common; 00908 } 00909 00910 out << ")"; 00911 } 00912 00913 //////////////////////////////////////////////////////////////////// 00914 // Function: GeomNode::is_geom_node 00915 // Access: Public, Virtual 00916 // Description: A simple downcast check. Returns true if this kind 00917 // of node happens to inherit from GeomNode, false 00918 // otherwise. 00919 // 00920 // This is provided as a a faster alternative to calling 00921 // is_of_type(GeomNode::get_class_type()), since this 00922 // test is so important to rendering. 00923 //////////////////////////////////////////////////////////////////// 00924 bool GeomNode:: 00925 is_geom_node() const { 00926 return true; 00927 } 00928 00929 //////////////////////////////////////////////////////////////////// 00930 // Function: GeomNode::do_premunge 00931 // Access: Public 00932 // Description: Uses the indicated GSG to premunge the Geoms in this 00933 // node to optimize them for eventual rendering. See 00934 // SceneGraphReducer::premunge(). 00935 //////////////////////////////////////////////////////////////////// 00936 void GeomNode:: 00937 do_premunge(GraphicsStateGuardianBase *gsg, 00938 const RenderState *node_state, 00939 GeomTransformer &transformer) { 00940 Thread *current_thread = Thread::get_current_thread(); 00941 00942 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 00943 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 00944 00945 GeomList::iterator gi; 00946 PT(GeomList) geoms = cdata->modify_geoms(); 00947 for (gi = geoms->begin(); gi != geoms->end(); ++gi) { 00948 GeomEntry &entry = (*gi); 00949 CPT(RenderState) geom_state = node_state->compose(entry._state); 00950 CPT(Geom) geom = entry._geom.get_read_pointer(); 00951 PT(GeomMunger) munger = gsg->get_geom_munger(geom_state, current_thread); 00952 entry._geom = transformer.premunge_geom(geom, munger); 00953 } 00954 } 00955 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 00956 } 00957 00958 //////////////////////////////////////////////////////////////////// 00959 // Function: GeomNode::r_mark_geom_bounds_stale 00960 // Access: Protected, Virtual 00961 // Description: Recursively calls Geom::mark_bounds_stale() on every 00962 // Geom at this node and below. 00963 //////////////////////////////////////////////////////////////////// 00964 void GeomNode:: 00965 r_mark_geom_bounds_stale(Thread *current_thread) { 00966 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 00967 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 00968 00969 GeomList::iterator gi; 00970 PT(GeomList) geoms = cdata->modify_geoms(); 00971 for (gi = geoms->begin(); gi != geoms->end(); ++gi) { 00972 GeomEntry &entry = (*gi); 00973 entry._geom.get_read_pointer()->mark_bounds_stale(); 00974 } 00975 } 00976 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 00977 mark_internal_bounds_stale(); 00978 00979 PandaNode::r_mark_geom_bounds_stale(current_thread); 00980 } 00981 00982 //////////////////////////////////////////////////////////////////// 00983 // Function: GeomNode::compute_internal_bounds 00984 // Access: Protected, Virtual 00985 // Description: Returns a newly-allocated BoundingVolume that 00986 // represents the internal contents of the node. Should 00987 // be overridden by PandaNode classes that contain 00988 // something internally. 00989 //////////////////////////////////////////////////////////////////// 00990 void GeomNode:: 00991 compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, 00992 int &internal_vertices, 00993 int pipeline_stage, 00994 Thread *current_thread) const { 00995 int num_vertices = 0; 00996 00997 CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread); 00998 00999 pvector<const BoundingVolume *> child_volumes; 01000 pvector<CPT(BoundingVolume) > child_volumes_ref; 01001 bool all_box = true; 01002 01003 GeomList::const_iterator gi; 01004 CPT(GeomList) geoms = cdata->get_geoms(); 01005 child_volumes.reserve(geoms->size()); 01006 child_volumes_ref.reserve(geoms->size()); 01007 01008 for (gi = geoms->begin(); gi != geoms->end(); ++gi) { 01009 const GeomEntry &entry = (*gi); 01010 CPT(Geom) geom = entry._geom.get_read_pointer(); 01011 CPT(BoundingVolume) volume = geom->get_bounds(); 01012 01013 if (!volume->is_empty()) { 01014 child_volumes.push_back(volume); 01015 child_volumes_ref.push_back(volume); 01016 if (!volume->is_exact_type(BoundingBox::get_class_type())) { 01017 all_box = false; 01018 } 01019 } 01020 num_vertices += geom->get_nested_vertices(); 01021 } 01022 01023 PT(GeometricBoundingVolume) gbv; 01024 01025 BoundingVolume::BoundsType btype = get_bounds_type(); 01026 if (btype == BoundingVolume::BT_default) { 01027 btype = bounds_type; 01028 } 01029 01030 if (btype == BoundingVolume::BT_box || 01031 (btype != BoundingVolume::BT_sphere && all_box)) { 01032 // If all of the child volumes are a BoundingBox, then our volume 01033 // is also a BoundingBox. 01034 gbv = new BoundingBox; 01035 } else { 01036 // Otherwise, it's a sphere. 01037 gbv = new BoundingSphere; 01038 } 01039 01040 if (child_volumes.size() > 0) { 01041 const BoundingVolume **child_begin = &child_volumes[0]; 01042 const BoundingVolume **child_end = child_begin + child_volumes.size(); 01043 ((BoundingVolume *)gbv)->around(child_begin, child_end); 01044 } 01045 01046 internal_bounds = gbv; 01047 internal_vertices = num_vertices; 01048 } 01049 01050 //////////////////////////////////////////////////////////////////// 01051 // Function: GeomNode::register_with_read_factory 01052 // Access: Public, Static 01053 // Description: Tells the BamReader how to create objects of type 01054 // GeomNode. 01055 //////////////////////////////////////////////////////////////////// 01056 void GeomNode:: 01057 register_with_read_factory() { 01058 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); 01059 } 01060 01061 //////////////////////////////////////////////////////////////////// 01062 // Function: GeomNode::write_datagram 01063 // Access: Public, Virtual 01064 // Description: Writes the contents of this object to the datagram 01065 // for shipping out to a Bam file. 01066 //////////////////////////////////////////////////////////////////// 01067 void GeomNode:: 01068 write_datagram(BamWriter *manager, Datagram &dg) { 01069 PandaNode::write_datagram(manager, dg); 01070 manager->write_cdata(dg, _cycler); 01071 } 01072 01073 //////////////////////////////////////////////////////////////////// 01074 // Function: GeomNode::finalize 01075 // Access: Public, Virtual 01076 // Description: Called by the BamReader to perform any final actions 01077 // needed for setting up the object after all objects 01078 // have been read and all pointers have been completed. 01079 //////////////////////////////////////////////////////////////////// 01080 void GeomNode:: 01081 finalize(BamReader *manager) { 01082 if (manager->get_file_minor_ver() < 14) { 01083 // With version 6.14, we changed the default ColorAttrib 01084 // behavior from make_vertex() to make_flat(). This means that 01085 // every Geom that contains vertex colors now needs to have an 01086 // explicit ColorAttrib::make_vertex() on its state. 01087 01088 // Since we shouldn't override a different ColorAttrib inherited 01089 // from above, we create this new attrib with an override of -1. 01090 01091 CPT(InternalName) color = InternalName::get_color(); 01092 CPT(RenderAttrib) vertex_color = ColorAttrib::make_vertex(); 01093 01094 Thread *current_thread = Thread::get_current_thread(); 01095 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 01096 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 01097 01098 GeomList::iterator gi; 01099 PT(GeomList) geoms = cdata->modify_geoms(); 01100 for (gi = geoms->begin(); gi != geoms->end(); ++gi) { 01101 GeomEntry &entry = (*gi); 01102 CPT(Geom) geom = entry._geom.get_read_pointer(); 01103 01104 // Force the various GeomVertexArrayFormat objects to finalize 01105 // themselves. We have to do this before we can reliably call 01106 // GeomVertexData::has_column(). 01107 CPT(GeomVertexData) vdata = geom->get_vertex_data(current_thread); 01108 CPT(GeomVertexFormat) vformat = vdata->get_format(); 01109 for (int i = 0; i < vformat->get_num_arrays(); ++i) { 01110 const GeomVertexArrayFormat *varray = vformat->get_array(i); 01111 manager->finalize_now((GeomVertexArrayFormat *)varray); 01112 } 01113 01114 if (vdata->has_column(color) && 01115 !entry._state->has_attrib(ColorAttrib::get_class_slot())) { 01116 // We'll be reassigning the RenderState. Therefore, save it 01117 // temporarily to increment its reference count. 01118 PT(BamAuxData) aux_data = new BamAuxData; 01119 aux_data->_hold_state = entry._state; 01120 manager->set_aux_data((RenderState *)entry._state.p(), "hold_state", aux_data); 01121 01122 entry._state = entry._state->add_attrib(vertex_color, -1); 01123 } 01124 } 01125 } 01126 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 01127 } 01128 } 01129 01130 //////////////////////////////////////////////////////////////////// 01131 // Function: GeomNode::make_from_bam 01132 // Access: Protected, Static 01133 // Description: This function is called by the BamReader's factory 01134 // when a new object of type GeomNode is encountered 01135 // in the Bam file. It should create the GeomNode 01136 // and extract its information from the file. 01137 //////////////////////////////////////////////////////////////////// 01138 TypedWritable *GeomNode:: 01139 make_from_bam(const FactoryParams ¶ms) { 01140 GeomNode *node = new GeomNode(""); 01141 DatagramIterator scan; 01142 BamReader *manager; 01143 01144 parse_params(params, scan, manager); 01145 node->fillin(scan, manager); 01146 01147 if (manager->get_file_minor_ver() < 14) { 01148 manager->register_finalize(node); 01149 } 01150 01151 return node; 01152 } 01153 01154 //////////////////////////////////////////////////////////////////// 01155 // Function: GeomNode::fillin 01156 // Access: Protected 01157 // Description: This internal function is called by make_from_bam to 01158 // read in all of the relevant data from the BamFile for 01159 // the new GeomNode. 01160 //////////////////////////////////////////////////////////////////// 01161 void GeomNode:: 01162 fillin(DatagramIterator &scan, BamReader *manager) { 01163 PandaNode::fillin(scan, manager); 01164 manager->read_cdata(scan, _cycler); 01165 } 01166 01167 //////////////////////////////////////////////////////////////////// 01168 // Function: GeomNode::CData::Copy Constructor 01169 // Access: Public 01170 // Description: 01171 //////////////////////////////////////////////////////////////////// 01172 GeomNode::CData:: 01173 CData(const GeomNode::CData ©) : 01174 _geoms(copy._geoms) 01175 { 01176 } 01177 01178 //////////////////////////////////////////////////////////////////// 01179 // Function: GeomNode::CData::make_copy 01180 // Access: Public, Virtual 01181 // Description: 01182 //////////////////////////////////////////////////////////////////// 01183 CycleData *GeomNode::CData:: 01184 make_copy() const { 01185 return new CData(*this); 01186 } 01187 01188 //////////////////////////////////////////////////////////////////// 01189 // Function: GeomNode::CData::write_datagram 01190 // Access: Public, Virtual 01191 // Description: Writes the contents of this object to the datagram 01192 // for shipping out to a Bam file. 01193 //////////////////////////////////////////////////////////////////// 01194 void GeomNode::CData:: 01195 write_datagram(BamWriter *manager, Datagram &dg) const { 01196 CPT(GeomList) geoms = _geoms.get_read_pointer(); 01197 int num_geoms = geoms->size(); 01198 nassertv(num_geoms == (int)(PN_uint16)num_geoms); 01199 dg.add_uint16(num_geoms); 01200 01201 GeomList::const_iterator gi; 01202 for (gi = geoms->begin(); gi != geoms->end(); ++gi) { 01203 const GeomEntry &entry = (*gi); 01204 manager->write_pointer(dg, entry._geom.get_read_pointer()); 01205 manager->write_pointer(dg, entry._state); 01206 } 01207 } 01208 01209 //////////////////////////////////////////////////////////////////// 01210 // Function: GeomNode::CData::complete_pointers 01211 // Access: Public, Virtual 01212 // Description: Receives an array of pointers, one for each time 01213 // manager->read_pointer() was called in fillin(). 01214 // Returns the number of pointers processed. 01215 //////////////////////////////////////////////////////////////////// 01216 int GeomNode::CData:: 01217 complete_pointers(TypedWritable **p_list, BamReader *manager) { 01218 int pi = CycleData::complete_pointers(p_list, manager); 01219 01220 // Get the geom and state pointers. 01221 GeomList::iterator gi; 01222 PT(GeomList) geoms = _geoms.get_write_pointer(); 01223 for (gi = geoms->begin(); gi != geoms->end(); ++gi) { 01224 GeomEntry &entry = (*gi); 01225 entry._geom = DCAST(Geom, p_list[pi++]); 01226 entry._state = DCAST(RenderState, p_list[pi++]); 01227 } 01228 01229 return pi; 01230 } 01231 01232 //////////////////////////////////////////////////////////////////// 01233 // Function: GeomNode::CData::fillin 01234 // Access: Public, Virtual 01235 // Description: This internal function is called by make_from_bam to 01236 // read in all of the relevant data from the BamFile for 01237 // the new GeomNode. 01238 //////////////////////////////////////////////////////////////////// 01239 void GeomNode::CData:: 01240 fillin(DatagramIterator &scan, BamReader *manager) { 01241 int num_geoms = scan.get_uint16(); 01242 // Read the list of geoms and states. Push back a NULL for each one. 01243 PT(GeomList) geoms = new GeomList; 01244 geoms->reserve(num_geoms); 01245 for (int i = 0; i < num_geoms; i++) { 01246 manager->read_pointer(scan); 01247 manager->read_pointer(scan); 01248 geoms->push_back(GeomEntry(NULL, NULL)); 01249 } 01250 _geoms = geoms; 01251 }