Panda3D

geomNode.cxx

00001 // Filename: geomNode.cxx
00002 // Created by:  drose (23Feb02)
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 &copy) :
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() != LVecBase4f(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 Colorf &c1 = ca->get_color();
00188                 const LVecBase4f &c2 = csa->get_scale();
00189                 Colorf 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 LMatrix4f &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(const RenderState *state,
00388                 PreparedGraphicsObjects *prepared_objects,
00389                 Thread *current_thread) {
00390   CDReader cdata(_cycler, current_thread);
00391   GeomList::const_iterator gi;
00392   CPT(GeomList) geoms = cdata->get_geoms();
00393   for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
00394     CPT(RenderState) geom_state = state->compose((*gi)._state);
00395     const RenderAttrib *attrib = 
00396       geom_state->get_attrib(TextureAttrib::get_class_slot());
00397     if (attrib != (const RenderAttrib *)NULL) {
00398       const TextureAttrib *ta;
00399       DCAST_INTO_V(ta, attrib);
00400       int num_stages = ta->get_num_on_stages();
00401       for (int i = 0; i < num_stages; ++i) {
00402         Texture *texture = ta->get_on_texture(ta->get_on_stage(i));
00403         if (texture != (Texture *)NULL) {
00404           texture->prepare(prepared_objects);
00405         }
00406       }
00407     }
00408   }
00409   
00410   PandaNode::r_prepare_scene(state, prepared_objects, current_thread);
00411 }
00412 
00413 
00414 ////////////////////////////////////////////////////////////////////
00415 //     Function: GeomNode::combine_with
00416 //       Access: Public, Virtual
00417 //  Description: Collapses this node with the other node, if possible,
00418 //               and returns a pointer to the combined node, or NULL
00419 //               if the two nodes cannot safely be combined.
00420 //
00421 //               The return value may be this, other, or a new node
00422 //               altogether.
00423 //
00424 //               This function is called from GraphReducer::flatten(),
00425 //               and need not deal with children; its job is just to
00426 //               decide whether to collapse the two nodes and what the
00427 //               collapsed node should look like.
00428 ////////////////////////////////////////////////////////////////////
00429 PandaNode *GeomNode::
00430 combine_with(PandaNode *other) {
00431   if (is_exact_type(get_class_type()) &&
00432       other->is_exact_type(get_class_type())) {
00433     // Two GeomNodes can combine by moving Geoms from one to the other.
00434     GeomNode *gother = DCAST(GeomNode, other);
00435     add_geoms_from(gother);
00436     return this;
00437   }
00438 
00439   return PandaNode::combine_with(other);
00440 }
00441 
00442 ////////////////////////////////////////////////////////////////////
00443 //     Function: GeomNode::calc_tight_bounds
00444 //       Access: Public, Virtual
00445 //  Description: This is used to support
00446 //               NodePath::calc_tight_bounds().  It is not intended to
00447 //               be called directly, and it has nothing to do with the
00448 //               normal Panda bounding-volume computation.
00449 //
00450 //               If the node contains any geometry, this updates
00451 //               min_point and max_point to enclose its bounding box.
00452 //               found_any is to be set true if the node has any
00453 //               geometry at all, or left alone if it has none.  This
00454 //               method may be called over several nodes, so it may
00455 //               enter with min_point, max_point, and found_any
00456 //               already set.
00457 ////////////////////////////////////////////////////////////////////
00458 CPT(TransformState) GeomNode::
00459 calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, bool &found_any,
00460                   const TransformState *transform, Thread *current_thread) const {
00461   CPT(TransformState) next_transform = 
00462     PandaNode::calc_tight_bounds(min_point, max_point, found_any, transform,
00463                                  current_thread);
00464 
00465   const LMatrix4f &mat = next_transform->get_mat();
00466 
00467   CDReader cdata(_cycler, current_thread);
00468   GeomList::const_iterator gi;
00469   CPT(GeomList) geoms = cdata->get_geoms();
00470   for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
00471     CPT(Geom) geom = (*gi)._geom.get_read_pointer();
00472     geom->calc_tight_bounds(min_point, max_point, found_any,
00473                             geom->get_vertex_data(current_thread)->animate_vertices(true, current_thread),
00474                             !next_transform->is_identity(), mat,
00475                             current_thread);
00476   }
00477 
00478   return next_transform;
00479 }
00480 
00481 ////////////////////////////////////////////////////////////////////
00482 //     Function: GeomNode::is_renderable
00483 //       Access: Public, Virtual
00484 //  Description: Returns true if there is some value to visiting this
00485 //               particular node during the cull traversal for any
00486 //               camera, false otherwise.  This will be used to
00487 //               optimize the result of get_net_draw_show_mask(), so
00488 //               that any subtrees that contain only nodes for which
00489 //               is_renderable() is false need not be visited.
00490 ////////////////////////////////////////////////////////////////////
00491 bool GeomNode::
00492 is_renderable() const {
00493   return true;
00494 }
00495 
00496 ////////////////////////////////////////////////////////////////////
00497 //     Function: GeomNode::add_for_draw
00498 //       Access: Public, Virtual
00499 //  Description: Adds the node's contents to the CullResult we are
00500 //               building up during the cull traversal, so that it
00501 //               will be drawn at render time.  For most nodes other
00502 //               than GeomNodes, this is a do-nothing operation.
00503 ////////////////////////////////////////////////////////////////////
00504 void GeomNode::
00505 add_for_draw(CullTraverser *trav, CullTraverserData &data) {
00506   trav->_geom_nodes_pcollector.add_level(1);
00507 
00508   if (pgraph_cat.is_spam()) {
00509     pgraph_cat.spam()
00510       << "Found " << *this << " in state " << *data._state 
00511       << " draw_mask = " << data._draw_mask << "\n";
00512   }
00513   
00514   // Get all the Geoms, with no decalling.
00515   Geoms geoms = get_geoms(trav->get_current_thread());
00516   int num_geoms = geoms.get_num_geoms();
00517   trav->_geoms_pcollector.add_level(num_geoms);
00518   CPT(TransformState) net_transform = data.get_net_transform(trav);
00519   CPT(TransformState) modelview_transform = data.get_modelview_transform(trav);
00520   CPT(TransformState) internal_transform = trav->get_gsg()->get_cs_transform()->compose(modelview_transform);
00521 
00522   for (int i = 0; i < num_geoms; i++) {
00523     const Geom *geom = geoms.get_geom(i);
00524     if (geom->is_empty()) {
00525       continue;
00526     }
00527 
00528     CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i));
00529     if (state->has_cull_callback() && !state->cull_callback(trav, data)) {
00530       // Cull.
00531       continue;
00532     }
00533     
00534     // Cull the Geom bounding volume against the view frustum
00535     // and/or the cull planes.  Don't bother unless we've got more
00536     // than one Geom, since otherwise the bounding volume of the
00537     // GeomNode is (probably) the same as that of the one Geom,
00538     // and we've already culled against that.
00539     if (num_geoms > 1) {
00540       if (data._view_frustum != (GeometricBoundingVolume *)NULL) {
00541         // Cull the individual Geom against the view frustum.
00542         CPT(BoundingVolume) geom_volume = geom->get_bounds();
00543         const GeometricBoundingVolume *geom_gbv =
00544           DCAST(GeometricBoundingVolume, geom_volume);
00545         
00546         int result = data._view_frustum->contains(geom_gbv);
00547         if (result == BoundingVolume::IF_no_intersection) {
00548           // Cull this Geom.
00549           continue;
00550         }
00551       }
00552       if (!data._cull_planes->is_empty()) {
00553         // Also cull the Geom against the cull planes.
00554         CPT(BoundingVolume) geom_volume = geom->get_bounds();
00555         const GeometricBoundingVolume *geom_gbv =
00556           DCAST(GeometricBoundingVolume, geom_volume);
00557         int result;
00558         data._cull_planes->do_cull(result, state, geom_gbv);
00559         if (result == BoundingVolume::IF_no_intersection) {
00560           // Cull.
00561           continue;
00562         }
00563       }
00564     }
00565     
00566     CullableObject *object = 
00567       new CullableObject(geom, state, net_transform, 
00568                          modelview_transform, internal_transform);
00569     trav->get_cull_handler()->record_object(object, trav);
00570   }
00571 }
00572 
00573 ////////////////////////////////////////////////////////////////////
00574 //     Function: GeomNode::get_legal_collide_mask
00575 //       Access: Published, Virtual
00576 //  Description: Returns the subset of CollideMask bits that may be
00577 //               set for this particular type of PandaNode.  For most
00578 //               nodes, this is 0; it doesn't make sense to set a
00579 //               CollideMask for most kinds of nodes.
00580 //
00581 //               For nodes that can be collided with, such as GeomNode
00582 //               and CollisionNode, this returns all bits on.
00583 ////////////////////////////////////////////////////////////////////
00584 CollideMask GeomNode::
00585 get_legal_collide_mask() const {
00586   return CollideMask::all_on();
00587 }
00588 
00589 ////////////////////////////////////////////////////////////////////
00590 //     Function: GeomNode::add_geom
00591 //       Access: Published
00592 //  Description: Adds a new Geom to the node.  The geom is given the
00593 //               indicated state (which may be
00594 //               RenderState::make_empty(), to completely inherit its
00595 //               state from the scene graph).
00596 ////////////////////////////////////////////////////////////////////
00597 void GeomNode::
00598 add_geom(Geom *geom, const RenderState *state) {
00599   nassertv(geom != (Geom *)NULL);
00600   nassertv(geom->check_valid());
00601   nassertv(state != (RenderState *)NULL);
00602 
00603   Thread *current_thread = Thread::get_current_thread();
00604   OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
00605     CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
00606 
00607     cdata->modify_geoms()->push_back(GeomEntry(geom, state));
00608   }
00609   CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
00610 
00611   mark_internal_bounds_stale();
00612 }
00613 
00614 ////////////////////////////////////////////////////////////////////
00615 //     Function: GeomNode::add_geoms_from
00616 //       Access: Published
00617 //  Description: Copies the Geoms (and their associated RenderStates)
00618 //               from the indicated GeomNode into this one.
00619 ////////////////////////////////////////////////////////////////////
00620 void GeomNode::
00621 add_geoms_from(const GeomNode *other) {
00622   Thread *current_thread = Thread::get_current_thread();
00623   OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
00624     CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
00625     CDStageReader cdata_other(other->_cycler, pipeline_stage, current_thread);
00626 
00627     GeomList::const_iterator gi;
00628     CPT(GeomList) other_geoms = cdata_other->get_geoms();
00629     PT(GeomList) this_geoms = cdata->modify_geoms();
00630     for (gi = other_geoms->begin(); gi != other_geoms->end(); ++gi) {
00631       const GeomEntry &entry = (*gi);
00632       nassertv(entry._geom.get_read_pointer()->check_valid());
00633       this_geoms->push_back(entry);
00634     }
00635   }
00636   CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
00637 
00638   mark_internal_bounds_stale();
00639 }
00640 
00641 ////////////////////////////////////////////////////////////////////
00642 //     Function: GeomNode::set_geom
00643 //       Access: Public
00644 //  Description: Replaces the nth Geom of the node with a new pointer.
00645 //               There must already be a Geom in this slot.
00646 //
00647 //               Note that if this method is called in a downstream
00648 //               stage (for instance, during cull or draw), then it
00649 //               will propagate the new list of Geoms upstream all the
00650 //               way to pipeline stage 0, which may step on changes
00651 //               that were made independently in pipeline stage 0.
00652 //               Use with caution.
00653 ////////////////////////////////////////////////////////////////////
00654 void GeomNode::
00655 set_geom(int n, Geom *geom) {
00656   nassertv(geom != (Geom *)NULL);
00657   nassertv(geom->check_valid());
00658 
00659   CDWriter cdata(_cycler, true);
00660   PT(GeomList) geoms = cdata->modify_geoms();
00661   nassertv(n >= 0 && n < (int)geoms->size());
00662   (*geoms)[n]._geom = geom;
00663 
00664   mark_internal_bounds_stale();
00665 }
00666 
00667 ////////////////////////////////////////////////////////////////////
00668 //     Function: GeomNode::check_valid
00669 //       Access: Published
00670 //  Description: Verifies that the each Geom within the GeomNode
00671 //               reference vertices that actually exist within its
00672 //               GeomVertexData.  Returns true if the GeomNode appears
00673 //               to be valid, false otherwise.
00674 ////////////////////////////////////////////////////////////////////
00675 bool GeomNode::
00676 check_valid() const {
00677   int num_geoms = get_num_geoms();
00678   for (int i = 0; i < num_geoms; i++) {
00679     const Geom *geom = get_geom(i);
00680     if (!geom->check_valid()) {
00681       return false;
00682     }
00683   }
00684 
00685   return true;
00686 }
00687 
00688 ////////////////////////////////////////////////////////////////////
00689 //     Function: GeomNode::decompose
00690 //       Access: Published
00691 //  Description: Calls decompose() on each Geom with the GeomNode.
00692 //               This decomposes higher-order primitive types, like
00693 //               triangle strips, into lower-order types like indexed
00694 //               triangles.  Normally there is no reason to do this,
00695 //               but it can be useful as an early preprocessing step,
00696 //               to allow a later call to unify() to proceed more
00697 //               quickly.
00698 //
00699 //               See also SceneGraphReducer::decompose(), which is the
00700 //               normal way this is called.
00701 ////////////////////////////////////////////////////////////////////
00702 void GeomNode::
00703 decompose() {
00704   Thread *current_thread = Thread::get_current_thread();
00705   OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
00706     CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
00707 
00708     GeomList::iterator gi;
00709     PT(GeomList) geoms = cdata->modify_geoms();
00710     for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
00711       GeomEntry &entry = (*gi);
00712       nassertv(entry._geom.test_ref_count_integrity());
00713       PT(Geom) geom = entry._geom.get_write_pointer();
00714       geom->decompose_in_place();
00715     }
00716   }
00717   CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
00718 }
00719 
00720 ////////////////////////////////////////////////////////////////////
00721 //     Function: GeomNode::unify
00722 //       Access: Published
00723 //  Description: Attempts to unify all of the Geoms contained within
00724 //               this node into a single Geom, or at least as few
00725 //               Geoms as possible.  In turn, the individual
00726 //               GeomPrimitives contained within each resulting Geom
00727 //               are also unified.  The goal is to reduce the number
00728 //               of GeomPrimitives within the node as far as possible.
00729 //               This may result in composite primitives, such as
00730 //               triangle strips and triangle fans, being decomposed
00731 //               into triangles.  See also Geom::unify().
00732 //
00733 //               max_indices represents the maximum number of indices
00734 //               that will be put in any one GeomPrimitive.  If
00735 //               preserve_order is true, then the primitives will not
00736 //               be reordered during the operation, even if this
00737 //               results in a suboptimal result.
00738 //
00739 //               In order for this to be successful, the primitives
00740 //               must reference the same GeomVertexData, have the same
00741 //               fundamental primitive type, and have compatible shade
00742 //               models.
00743 ////////////////////////////////////////////////////////////////////
00744 void GeomNode::
00745 unify(int max_indices, bool preserve_order) {
00746   bool any_changed = false;
00747 
00748   Thread *current_thread = Thread::get_current_thread();
00749   OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
00750     CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
00751 
00752     PT(GeomList) new_geoms = new GeomList;
00753 
00754     // Try to unify each Geom with each preceding Geom.  This is an n^2
00755     // operation, but usually there are only a handful of Geoms to
00756     // consider, so that's not a big deal.
00757     GeomList::const_iterator gi;
00758     CPT(GeomList) old_geoms = cdata->get_geoms();
00759     for (gi = old_geoms->begin(); gi != old_geoms->end(); ++gi) {
00760       const GeomEntry &old_entry = (*gi);
00761       
00762       bool unified = false;
00763 
00764       // Go from back to front, to minimize damage to the primitive ordering.
00765       GeomList::reverse_iterator gj;
00766       for (gj = new_geoms->rbegin(); gj != new_geoms->rend() && !unified; ++gj) {
00767         GeomEntry &new_entry = (*gj);
00768         if (old_entry._state == new_entry._state) {
00769           // Both states match, so try to combine the primitives.
00770           CPT(Geom) old_geom = old_entry._geom.get_read_pointer();
00771           PT(Geom) new_geom = new_entry._geom.get_write_pointer();
00772           if (new_geom->copy_primitives_from(old_geom)) {
00773             // Successfully combined!
00774             unified = true;
00775             any_changed = true;
00776           }
00777         }
00778 
00779         if (preserve_order) {
00780           // If we're insisting on preserving the order, we can only
00781           // attempt to merge with the tail of the list.
00782           break;
00783         }
00784       }
00785       
00786       if (!unified) {
00787         // Couldn't unify this Geom with anything, so just add it to the
00788         // output list.
00789         new_geoms->push_back(old_entry);
00790       }
00791     }
00792     
00793     // Done!  We'll keep whatever's left in the output list.
00794     cdata->set_geoms(new_geoms);
00795 
00796     // Finally, go back through and unify the resulting geom(s).
00797     GeomList::iterator wgi;
00798     for (wgi = new_geoms->begin(); wgi != new_geoms->end(); ++wgi) {
00799       GeomEntry &entry = (*wgi);
00800       nassertv(entry._geom.test_ref_count_integrity());
00801       PT(Geom) geom = entry._geom.get_write_pointer();
00802       geom->unify_in_place(max_indices, preserve_order);
00803     }
00804   }
00805   CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
00806 
00807   if (any_changed) {
00808     mark_internal_bounds_stale();
00809   }
00810 }
00811 
00812 ////////////////////////////////////////////////////////////////////
00813 //     Function: GeomNode::write_geoms
00814 //       Access: Published
00815 //  Description: Writes a short description of all the Geoms in the
00816 //               node.
00817 ////////////////////////////////////////////////////////////////////
00818 void GeomNode::
00819 write_geoms(ostream &out, int indent_level) const {
00820   CDReader cdata(_cycler);
00821   write(out, indent_level);
00822   GeomList::const_iterator gi;
00823   CPT(GeomList) geoms = cdata->get_geoms();
00824   for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
00825     const GeomEntry &entry = (*gi);
00826     indent(out, indent_level + 2) 
00827       << *entry._geom.get_read_pointer() << " " << *entry._state << "\n";
00828   }
00829 }
00830 
00831 ////////////////////////////////////////////////////////////////////
00832 //     Function: GeomNode::write_verbose
00833 //       Access: Published
00834 //  Description: Writes a detailed description of all the Geoms in the
00835 //               node.
00836 ////////////////////////////////////////////////////////////////////
00837 void GeomNode::
00838 write_verbose(ostream &out, int indent_level) const {
00839   CDReader cdata(_cycler);
00840   write(out, indent_level);
00841   GeomList::const_iterator gi;
00842   CPT(GeomList) geoms = cdata->get_geoms();
00843   for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
00844     const GeomEntry &entry = (*gi);
00845     CPT(Geom) geom = entry._geom.get_read_pointer();
00846     indent(out, indent_level + 2) 
00847       << *geom << " " << *entry._state << "\n";
00848     geom->write(out, indent_level + 4);
00849   }
00850 }
00851 
00852 ////////////////////////////////////////////////////////////////////
00853 //     Function: GeomNode::output
00854 //       Access: Public, Virtual
00855 //  Description: 
00856 ////////////////////////////////////////////////////////////////////
00857 void GeomNode::
00858 output(ostream &out) const {
00859   // Accumulate the total set of RenderAttrib types that are applied
00860   // to any of our Geoms, so we can output them too.  The result will
00861   // be the list of attrib types that might be applied to some Geoms,
00862   // but not necessarily to all Geoms.
00863 
00864   CDReader cdata(_cycler);
00865 
00866   pset<TypeHandle> attrib_types;
00867 
00868   GeomList::const_iterator gi;
00869   CPT(RenderState) common = RenderState::make_empty();
00870 
00871   CPT(GeomList) geoms = cdata->get_geoms();
00872   for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
00873     const GeomEntry &entry = (*gi);
00874     common = common->compose(entry._state);
00875   }
00876 
00877   PandaNode::output(out);
00878   out << " (" << geoms->size() << " geoms";
00879 
00880   if (!common->is_empty()) {
00881     out << ": " << *common;    
00882   }
00883 
00884   out << ")";
00885 }
00886 
00887 ////////////////////////////////////////////////////////////////////
00888 //     Function: GeomNode::is_geom_node
00889 //       Access: Public, Virtual
00890 //  Description: A simple downcast check.  Returns true if this kind
00891 //               of node happens to inherit from GeomNode, false
00892 //               otherwise.
00893 //
00894 //               This is provided as a a faster alternative to calling
00895 //               is_of_type(GeomNode::get_class_type()), since this
00896 //               test is so important to rendering.
00897 ////////////////////////////////////////////////////////////////////
00898 bool GeomNode::
00899 is_geom_node() const {
00900   return true;
00901 }
00902 
00903 ////////////////////////////////////////////////////////////////////
00904 //     Function: GeomNode::do_premunge
00905 //       Access: Public
00906 //  Description: Uses the indicated GSG to premunge the Geoms in this
00907 //               node to optimize them for eventual rendering.  See
00908 //               SceneGraphReducer::premunge().
00909 ////////////////////////////////////////////////////////////////////
00910 void GeomNode::
00911 do_premunge(GraphicsStateGuardianBase *gsg,
00912             const RenderState *node_state,
00913             GeomTransformer &transformer) {
00914   Thread *current_thread = Thread::get_current_thread();
00915 
00916   OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
00917     CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
00918 
00919     GeomList::iterator gi;
00920     PT(GeomList) geoms = cdata->modify_geoms();
00921     for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
00922       GeomEntry &entry = (*gi);
00923       CPT(RenderState) geom_state = node_state->compose(entry._state);
00924       CPT(Geom) geom = entry._geom.get_read_pointer();
00925       PT(GeomMunger) munger = gsg->get_geom_munger(geom_state, current_thread);
00926       entry._geom = transformer.premunge_geom(geom, munger);
00927     }
00928   }
00929   CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
00930 }
00931 
00932 ////////////////////////////////////////////////////////////////////
00933 //     Function: GeomNode::r_mark_geom_bounds_stale
00934 //       Access: Protected, Virtual
00935 //  Description: Recursively calls Geom::mark_bounds_stale() on every
00936 //               Geom at this node and below.
00937 ////////////////////////////////////////////////////////////////////
00938 void GeomNode::
00939 r_mark_geom_bounds_stale(Thread *current_thread) {
00940   OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
00941     CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
00942 
00943     GeomList::iterator gi;
00944     PT(GeomList) geoms = cdata->modify_geoms();
00945     for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
00946       GeomEntry &entry = (*gi);
00947       entry._geom.get_read_pointer()->mark_bounds_stale();
00948     }
00949   }
00950   CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
00951   mark_internal_bounds_stale();
00952 
00953   PandaNode::r_mark_geom_bounds_stale(current_thread);
00954 }
00955 
00956 ////////////////////////////////////////////////////////////////////
00957 //     Function: GeomNode::compute_internal_bounds
00958 //       Access: Protected, Virtual
00959 //  Description: Returns a newly-allocated BoundingVolume that
00960 //               represents the internal contents of the node.  Should
00961 //               be overridden by PandaNode classes that contain
00962 //               something internally.
00963 ////////////////////////////////////////////////////////////////////
00964 void GeomNode::
00965 compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
00966                         int &internal_vertices,
00967                         int pipeline_stage,
00968                         Thread *current_thread) const {
00969   int num_vertices = 0;
00970 
00971   CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
00972 
00973   pvector<const BoundingVolume *> child_volumes;
00974   pvector<CPT(BoundingVolume) > child_volumes_ref;
00975   bool all_box = true;
00976 
00977   GeomList::const_iterator gi;
00978   CPT(GeomList) geoms = cdata->get_geoms();
00979   child_volumes.reserve(geoms->size());
00980   child_volumes_ref.reserve(geoms->size());
00981 
00982   for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
00983     const GeomEntry &entry = (*gi);
00984     CPT(Geom) geom = entry._geom.get_read_pointer();
00985     CPT(BoundingVolume) volume = geom->get_bounds();
00986 
00987     if (!volume->is_empty()) {
00988       child_volumes.push_back(volume);
00989       child_volumes_ref.push_back(volume);
00990       if (!volume->is_exact_type(BoundingBox::get_class_type())) {
00991         all_box = false;
00992       }
00993     }
00994     num_vertices += geom->get_nested_vertices();
00995   }
00996 
00997   PT(GeometricBoundingVolume) gbv;
00998 
00999   BoundingVolume::BoundsType btype = get_bounds_type();
01000   if (btype == BoundingVolume::BT_default) {
01001     btype = bounds_type;
01002   }
01003 
01004   if (btype == BoundingVolume::BT_box ||
01005       (btype != BoundingVolume::BT_sphere && all_box)) {
01006     // If all of the child volumes are a BoundingBox, then our volume
01007     // is also a BoundingBox.
01008     gbv = new BoundingBox;
01009   } else {
01010     // Otherwise, it's a sphere.
01011     gbv = new BoundingSphere;
01012   }
01013 
01014   if (child_volumes.size() > 0) {
01015     const BoundingVolume **child_begin = &child_volumes[0];
01016     const BoundingVolume **child_end = child_begin + child_volumes.size();
01017     ((BoundingVolume *)gbv)->around(child_begin, child_end);
01018   }
01019   
01020   internal_bounds = gbv;
01021   internal_vertices = num_vertices;
01022 }
01023 
01024 ////////////////////////////////////////////////////////////////////
01025 //     Function: GeomNode::register_with_read_factory
01026 //       Access: Public, Static
01027 //  Description: Tells the BamReader how to create objects of type
01028 //               GeomNode.
01029 ////////////////////////////////////////////////////////////////////
01030 void GeomNode::
01031 register_with_read_factory() {
01032   BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
01033 }
01034 
01035 ////////////////////////////////////////////////////////////////////
01036 //     Function: GeomNode::write_datagram
01037 //       Access: Public, Virtual
01038 //  Description: Writes the contents of this object to the datagram
01039 //               for shipping out to a Bam file.
01040 ////////////////////////////////////////////////////////////////////
01041 void GeomNode::
01042 write_datagram(BamWriter *manager, Datagram &dg) {
01043   PandaNode::write_datagram(manager, dg);
01044   manager->write_cdata(dg, _cycler);
01045 }
01046 
01047 ////////////////////////////////////////////////////////////////////
01048 //     Function: GeomNode::finalize
01049 //       Access: Public, Virtual
01050 //  Description: Called by the BamReader to perform any final actions
01051 //               needed for setting up the object after all objects
01052 //               have been read and all pointers have been completed.
01053 ////////////////////////////////////////////////////////////////////
01054 void GeomNode::
01055 finalize(BamReader *manager) {
01056   if (manager->get_file_minor_ver() < 14) {
01057     // With version 6.14, we changed the default ColorAttrib
01058     // behavior from make_vertex() to make_flat().  This means that
01059     // every Geom that contains vertex colors now needs to have an
01060     // explicit ColorAttrib::make_vertex() on its state.
01061 
01062     // Since we shouldn't override a different ColorAttrib inherited
01063     // from above, we create this new attrib with an override of -1.
01064 
01065     CPT(InternalName) color = InternalName::get_color();
01066     CPT(RenderAttrib) vertex_color = ColorAttrib::make_vertex();
01067 
01068     Thread *current_thread = Thread::get_current_thread();
01069     OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
01070       CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
01071 
01072       GeomList::iterator gi;
01073       PT(GeomList) geoms = cdata->modify_geoms();
01074       for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
01075         GeomEntry &entry = (*gi);
01076         CPT(Geom) geom = entry._geom.get_read_pointer();
01077 
01078         // Force the various GeomVertexArrayFormat objects to finalize
01079         // themselves.  We have to do this before we can reliably call
01080         // GeomVertexData::has_column().
01081         CPT(GeomVertexData) vdata = geom->get_vertex_data(current_thread);
01082         CPT(GeomVertexFormat) vformat = vdata->get_format();
01083         for (int i = 0; i < vformat->get_num_arrays(); ++i) {
01084           const GeomVertexArrayFormat *varray = vformat->get_array(i);
01085           manager->finalize_now((GeomVertexArrayFormat *)varray);
01086         }
01087 
01088         if (vdata->has_column(color) &&
01089             !entry._state->has_attrib(ColorAttrib::get_class_slot())) {
01090           // We'll be reassigning the RenderState.  Therefore, save it
01091           // temporarily to increment its reference count.
01092           PT(BamAuxData) aux_data = new BamAuxData;
01093           aux_data->_hold_state = entry._state;
01094           manager->set_aux_data((RenderState *)entry._state.p(), "hold_state", aux_data);
01095 
01096           entry._state = entry._state->add_attrib(vertex_color, -1);
01097         }
01098       }
01099     }
01100     CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
01101   }
01102 }
01103 
01104 ////////////////////////////////////////////////////////////////////
01105 //     Function: GeomNode::make_from_bam
01106 //       Access: Protected, Static
01107 //  Description: This function is called by the BamReader's factory
01108 //               when a new object of type GeomNode is encountered
01109 //               in the Bam file.  It should create the GeomNode
01110 //               and extract its information from the file.
01111 ////////////////////////////////////////////////////////////////////
01112 TypedWritable *GeomNode::
01113 make_from_bam(const FactoryParams &params) {
01114   GeomNode *node = new GeomNode("");
01115   DatagramIterator scan;
01116   BamReader *manager;
01117 
01118   parse_params(params, scan, manager);
01119   node->fillin(scan, manager);
01120 
01121   if (manager->get_file_minor_ver() < 14) {
01122     manager->register_finalize(node);
01123   }
01124 
01125   return node;
01126 }
01127 
01128 ////////////////////////////////////////////////////////////////////
01129 //     Function: GeomNode::fillin
01130 //       Access: Protected
01131 //  Description: This internal function is called by make_from_bam to
01132 //               read in all of the relevant data from the BamFile for
01133 //               the new GeomNode.
01134 ////////////////////////////////////////////////////////////////////
01135 void GeomNode::
01136 fillin(DatagramIterator &scan, BamReader *manager) {
01137   PandaNode::fillin(scan, manager);
01138   manager->read_cdata(scan, _cycler);
01139 }
01140 
01141 ////////////////////////////////////////////////////////////////////
01142 //     Function: GeomNode::CData::Copy Constructor
01143 //       Access: Public
01144 //  Description:
01145 ////////////////////////////////////////////////////////////////////
01146 GeomNode::CData::
01147 CData(const GeomNode::CData &copy) :
01148   _geoms(copy._geoms)
01149 {
01150 }
01151 
01152 ////////////////////////////////////////////////////////////////////
01153 //     Function: GeomNode::CData::make_copy
01154 //       Access: Public, Virtual
01155 //  Description:
01156 ////////////////////////////////////////////////////////////////////
01157 CycleData *GeomNode::CData::
01158 make_copy() const {
01159   return new CData(*this);
01160 }
01161 
01162 ////////////////////////////////////////////////////////////////////
01163 //     Function: GeomNode::CData::write_datagram
01164 //       Access: Public, Virtual
01165 //  Description: Writes the contents of this object to the datagram
01166 //               for shipping out to a Bam file.
01167 ////////////////////////////////////////////////////////////////////
01168 void GeomNode::CData::
01169 write_datagram(BamWriter *manager, Datagram &dg) const {
01170   CPT(GeomList) geoms = _geoms.get_read_pointer();
01171   int num_geoms = geoms->size();
01172   nassertv(num_geoms == (int)(PN_uint16)num_geoms);
01173   dg.add_uint16(num_geoms);
01174   
01175   GeomList::const_iterator gi;
01176   for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
01177     const GeomEntry &entry = (*gi);
01178     manager->write_pointer(dg, entry._geom.get_read_pointer());
01179     manager->write_pointer(dg, entry._state);
01180   }
01181 }
01182 
01183 ////////////////////////////////////////////////////////////////////
01184 //     Function: GeomNode::CData::complete_pointers
01185 //       Access: Public, Virtual
01186 //  Description: Receives an array of pointers, one for each time
01187 //               manager->read_pointer() was called in fillin().
01188 //               Returns the number of pointers processed.
01189 ////////////////////////////////////////////////////////////////////
01190 int GeomNode::CData::
01191 complete_pointers(TypedWritable **p_list, BamReader *manager) {
01192   int pi = CycleData::complete_pointers(p_list, manager);
01193 
01194   // Get the geom and state pointers.
01195   GeomList::iterator gi;
01196   PT(GeomList) geoms = _geoms.get_write_pointer();
01197   for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
01198     GeomEntry &entry = (*gi);
01199     entry._geom = DCAST(Geom, p_list[pi++]);
01200     entry._state = DCAST(RenderState, p_list[pi++]);
01201   }
01202 
01203   return pi;
01204 }
01205 
01206 ////////////////////////////////////////////////////////////////////
01207 //     Function: GeomNode::CData::fillin
01208 //       Access: Public, Virtual
01209 //  Description: This internal function is called by make_from_bam to
01210 //               read in all of the relevant data from the BamFile for
01211 //               the new GeomNode.
01212 ////////////////////////////////////////////////////////////////////
01213 void GeomNode::CData::
01214 fillin(DatagramIterator &scan, BamReader *manager) {
01215   int num_geoms = scan.get_uint16();
01216   // Read the list of geoms and states.  Push back a NULL for each one.
01217   PT(GeomList) geoms = new GeomList;
01218   geoms->reserve(num_geoms);
01219   for (int i = 0; i < num_geoms; i++) {
01220     manager->read_pointer(scan);
01221     manager->read_pointer(scan);
01222     geoms->push_back(GeomEntry(NULL, NULL));
01223   }
01224   _geoms = geoms;
01225 }
 All Classes Functions Variables Enumerations