Panda3D
 All Classes Functions Variables Enumerations
cullTraverser.cxx
00001 // Filename: cullTraverser.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 "config_pgraph.h"
00016 #include "cullTraverser.h"
00017 #include "cullTraverserData.h"
00018 #include "transformState.h"
00019 #include "renderState.h"
00020 #include "fogAttrib.h"
00021 #include "colorAttrib.h"
00022 #include "renderModeAttrib.h"
00023 #include "cullFaceAttrib.h"
00024 #include "depthOffsetAttrib.h"
00025 #include "cullHandler.h"
00026 #include "dcast.h"
00027 #include "geomNode.h"
00028 #include "config_pgraph.h"
00029 #include "boundingSphere.h"
00030 #include "boundingBox.h"
00031 #include "boundingHexahedron.h"
00032 #include "portalClipper.h"
00033 #include "geom.h"
00034 #include "geomTristrips.h"
00035 #include "geomTriangles.h"
00036 #include "geomLinestrips.h"
00037 #include "geomLines.h"
00038 #include "geomVertexWriter.h"
00039 
00040 PStatCollector CullTraverser::_nodes_pcollector("Nodes");
00041 PStatCollector CullTraverser::_geom_nodes_pcollector("Nodes:GeomNodes");
00042 PStatCollector CullTraverser::_geoms_pcollector("Geoms");
00043 PStatCollector CullTraverser::_geoms_occluded_pcollector("Geoms:Occluded");
00044 
00045 TypeHandle CullTraverser::_type_handle;
00046 
00047 ////////////////////////////////////////////////////////////////////
00048 //     Function: CullTraverser::Constructor
00049 //       Access: Published
00050 //  Description: 
00051 ////////////////////////////////////////////////////////////////////
00052 CullTraverser::
00053 CullTraverser() :
00054   _gsg(NULL),
00055   _current_thread(Thread::get_current_thread())
00056 {
00057   _camera_mask = DrawMask::all_on();
00058   _has_tag_state_key = false;
00059   _initial_state = RenderState::make_empty();
00060   _cull_handler = (CullHandler *)NULL;
00061   _portal_clipper = (PortalClipper *)NULL;
00062   _effective_incomplete_render = true;
00063 }
00064 
00065 ////////////////////////////////////////////////////////////////////
00066 //     Function: CullTraverser::Copy Constructor
00067 //       Access: Published
00068 //  Description: 
00069 ////////////////////////////////////////////////////////////////////
00070 CullTraverser::
00071 CullTraverser(const CullTraverser &copy) :
00072   _gsg(copy._gsg),
00073   _current_thread(copy._current_thread),
00074   _scene_setup(copy._scene_setup),
00075   _camera_mask(copy._camera_mask),
00076   _has_tag_state_key(copy._has_tag_state_key),
00077   _tag_state_key(copy._tag_state_key),
00078   _initial_state(copy._initial_state),
00079   _depth_offset_decals(copy._depth_offset_decals),
00080   _view_frustum(copy._view_frustum),
00081   _cull_handler(copy._cull_handler),
00082   _portal_clipper(copy._portal_clipper),
00083   _effective_incomplete_render(copy._effective_incomplete_render)
00084 {
00085 }
00086 
00087 ////////////////////////////////////////////////////////////////////
00088 //     Function: CullTraverser::set_scene
00089 //       Access: Published, Virtual
00090 //  Description: Sets the SceneSetup object that indicates the initial
00091 //               camera position, etc.  This must be called before
00092 //               traversal begins.
00093 ////////////////////////////////////////////////////////////////////
00094 void CullTraverser::
00095 set_scene(SceneSetup *scene_setup, GraphicsStateGuardianBase *gsg,
00096           bool dr_incomplete_render) {
00097   _scene_setup = scene_setup;
00098   _gsg = gsg;
00099 
00100   _initial_state = scene_setup->get_initial_state();
00101   _depth_offset_decals = _gsg->depth_offset_decals() && depth_offset_decals;
00102 
00103   _current_thread = Thread::get_current_thread();
00104 
00105   const Camera *camera = scene_setup->get_camera_node();
00106   _tag_state_key = camera->get_tag_state_key();
00107   _has_tag_state_key = !_tag_state_key.empty();
00108   _camera_mask = camera->get_camera_mask();
00109 
00110   _effective_incomplete_render = _gsg->get_incomplete_render() && dr_incomplete_render;
00111 }
00112 
00113 ////////////////////////////////////////////////////////////////////
00114 //     Function: CullTraverser::traverse
00115 //       Access: Published
00116 //  Description: Begins the traversal from the indicated node.
00117 ////////////////////////////////////////////////////////////////////
00118 void CullTraverser::
00119 traverse(const NodePath &root) {
00120   nassertv(_cull_handler != (CullHandler *)NULL);
00121   nassertv(_scene_setup != (SceneSetup *)NULL);
00122 
00123   if (allow_portal_cull) {
00124     // This _view_frustum is in cull_center space
00125     //Erik: obsolete?
00126     //PT(GeometricBoundingVolume) vf = _view_frustum;
00127 
00128     GeometricBoundingVolume *local_frustum = NULL;
00129     PT(BoundingVolume) bv = _scene_setup->get_lens()->make_bounds();
00130     if (bv != (BoundingVolume *)NULL &&
00131         bv->is_of_type(GeometricBoundingVolume::get_class_type())) {
00132       
00133       local_frustum = DCAST(GeometricBoundingVolume, bv);
00134     }
00135       
00136     // This local_frustum is in camera space
00137     PortalClipper portal_viewer(local_frustum, _scene_setup);
00138     if (debug_portal_cull) {
00139       portal_viewer.draw_camera_frustum();
00140     }
00141     
00142     // Store this pointer in this
00143     set_portal_clipper(&portal_viewer);
00144 
00145     CullTraverserData data(root, TransformState::make_identity(),
00146                            _initial_state, _view_frustum, 
00147                            _current_thread);
00148     
00149     traverse(data);
00150     
00151     // Finally add the lines to be drawn
00152     if (debug_portal_cull) {
00153       portal_viewer.draw_lines();
00154     }
00155     
00156     // Render the frustum relative to the cull center.
00157     NodePath cull_center = _scene_setup->get_cull_center();
00158     CPT(TransformState) transform = cull_center.get_transform(root);
00159     
00160     CullTraverserData my_data(data, portal_viewer._previous);
00161     my_data._net_transform = my_data._net_transform->compose(transform);
00162     traverse(my_data);
00163 
00164   } else {
00165     CullTraverserData data(root, TransformState::make_identity(),
00166                            _initial_state, _view_frustum, 
00167                            _current_thread);
00168     
00169     traverse(data);
00170   }
00171 }
00172 
00173 ////////////////////////////////////////////////////////////////////
00174 //     Function: CullTraverser::traverse
00175 //       Access: Published
00176 //  Description: Traverses from the next node with the given
00177 //               data, which has been constructed with the node but
00178 //               has not yet been converted into the node's space.
00179 ////////////////////////////////////////////////////////////////////
00180 void CullTraverser::
00181 traverse(CullTraverserData &data) {
00182   if (is_in_view(data)) {
00183     if (pgraph_cat.is_spam()) {
00184       pgraph_cat.spam() 
00185         << "\n" << data._node_path
00186         << " " << data._draw_mask << "\n";
00187     }
00188 
00189     PandaNodePipelineReader *node_reader = data.node_reader();
00190     int fancy_bits = node_reader->get_fancy_bits();
00191 
00192     if ((fancy_bits & (PandaNode::FB_transform |
00193                        PandaNode::FB_state |
00194                        PandaNode::FB_effects |
00195                        PandaNode::FB_tag |
00196                        PandaNode::FB_draw_mask |
00197                        PandaNode::FB_cull_callback)) == 0 &&
00198         data._cull_planes->is_empty()) {
00199       // Nothing interesting in this node; just move on.
00200       traverse_below(data);
00201 
00202     } else {
00203       // Something in this node is worth taking a closer look.
00204       const RenderEffects *node_effects = node_reader->get_effects();
00205       if (node_effects->has_show_bounds()) {
00206         // If we should show the bounding volume for this node, make it
00207         // up now.
00208         show_bounds(data, node_effects->has_show_tight_bounds());
00209       }
00210       
00211       data.apply_transform_and_state(this);
00212       
00213       const FogAttrib *fog = DCAST(FogAttrib, node_reader->get_state()->get_attrib(FogAttrib::get_class_slot()));
00214       if (fog != (const FogAttrib *)NULL && fog->get_fog() != (Fog *)NULL) {
00215         // If we just introduced a FogAttrib here, call adjust_to_camera()
00216         // now.  This maybe isn't the perfect time to call it, but it's
00217         // good enough; and at this time we have all the information we
00218         // need for it.
00219         fog->get_fog()->adjust_to_camera(get_camera_transform());
00220       }
00221       
00222       if (fancy_bits & PandaNode::FB_cull_callback) {
00223         PandaNode *node = data.node();
00224         if (!node->cull_callback(this, data)) {
00225           return;
00226         }
00227       }
00228       traverse_below(data);
00229     }
00230   }
00231 }
00232 
00233 ////////////////////////////////////////////////////////////////////
00234 //     Function: CullTraverser::traverse_below
00235 //       Access: Published, Virtual
00236 //  Description: Traverses all the children of the indicated node,
00237 //               with the given data, which has been converted into
00238 //               the node's space.
00239 ////////////////////////////////////////////////////////////////////
00240 void CullTraverser::
00241 traverse_below(CullTraverserData &data) {
00242   _nodes_pcollector.add_level(1);
00243   PandaNodePipelineReader *node_reader = data.node_reader();
00244   PandaNode *node = data.node();
00245 
00246   bool this_node_hidden = data.is_this_node_hidden(this);
00247 
00248   const RenderEffects *node_effects = node_reader->get_effects();
00249   bool has_decal = !this_node_hidden && node_effects->has_decal();
00250   if (has_decal && !_depth_offset_decals) {
00251     // Start the three-pass decal rendering if we're not using
00252     // DepthOffsetAttribs to implement decals.
00253     start_decal(data);
00254     
00255   } else {
00256     if (!this_node_hidden) {
00257       node->add_for_draw(this, data);
00258     }
00259 
00260     if (has_decal) {
00261       // If we *are* implementing decals with DepthOffsetAttribs,
00262       // apply it now, so that each child of this node gets offset by
00263       // a tiny amount.
00264       data._state = data._state->compose(get_depth_offset_state());
00265 #ifndef NDEBUG
00266       // This is just a sanity check message.
00267       if (!node->is_geom_node()) {
00268         pgraph_cat.error()
00269           << "DecalEffect applied to " << *node << ", not a GeomNode.\n";
00270       }
00271 #endif
00272     }
00273 
00274     // Now visit all the node's children.
00275     PandaNode::Children children = node_reader->get_children();
00276     node_reader->release();
00277     int num_children = children.get_num_children();
00278     if (node->has_selective_visibility()) {
00279       int i = node->get_first_visible_child();
00280       while (i < num_children) {
00281         CullTraverserData next_data(data, children.get_child(i));
00282         traverse(next_data);
00283         i = node->get_next_visible_child(i);
00284       }
00285       
00286     } else {
00287       for (int i = 0; i < num_children; i++) {
00288         CullTraverserData next_data(data, children.get_child(i));
00289         traverse(next_data);
00290       }
00291     }
00292   }
00293 }
00294 
00295 ////////////////////////////////////////////////////////////////////
00296 //     Function: CullTraverser::end_traverse
00297 //       Access: Published, Virtual
00298 //  Description: Should be called when the traverser has finished
00299 //               traversing its scene, this gives it a chance to do
00300 //               any necessary finalization.
00301 ////////////////////////////////////////////////////////////////////
00302 void CullTraverser::
00303 end_traverse() {
00304   _cull_handler->end_traverse();
00305 }
00306 
00307 ////////////////////////////////////////////////////////////////////
00308 //     Function: CullTraverser::draw_bounding_volume
00309 //       Access: Published
00310 //  Description: Draws an appropriate visualization of the indicated
00311 //               bounding volume.
00312 ////////////////////////////////////////////////////////////////////
00313 void CullTraverser::
00314 draw_bounding_volume(const BoundingVolume *vol, 
00315                      const TransformState *net_transform,
00316                      const TransformState *modelview_transform) const {
00317   PT(Geom) bounds_viz = make_bounds_viz(vol);
00318   
00319   if (bounds_viz != (Geom *)NULL) {
00320     _geoms_pcollector.add_level(2);
00321     CullableObject *outer_viz = 
00322       new CullableObject(bounds_viz, get_bounds_outer_viz_state(), 
00323                          net_transform, modelview_transform, get_gsg());
00324     _cull_handler->record_object(outer_viz, this);
00325     
00326     CullableObject *inner_viz = 
00327       new CullableObject(bounds_viz, get_bounds_inner_viz_state(), 
00328                          net_transform, modelview_transform, get_gsg());
00329     _cull_handler->record_object(inner_viz, this);
00330   }
00331 }
00332 
00333 ////////////////////////////////////////////////////////////////////
00334 //     Function: CullTraverser::is_in_view
00335 //       Access: Protected, Virtual
00336 //  Description: Returns true if the current node is fully or
00337 //               partially within the viewing area and should be
00338 //               drawn, or false if it (and all of its children)
00339 //               should be pruned.
00340 ////////////////////////////////////////////////////////////////////
00341 bool CullTraverser::
00342 is_in_view(CullTraverserData &data) {
00343   return data.is_in_view(_camera_mask);
00344 }
00345 
00346 ////////////////////////////////////////////////////////////////////
00347 //     Function: CullTraverser::show_bounds
00348 //       Access: Private
00349 //  Description: Draws an appropriate visualization of the node's
00350 //               external bounding volume.
00351 ////////////////////////////////////////////////////////////////////
00352 void CullTraverser::
00353 show_bounds(CullTraverserData &data, bool tight) {
00354   PandaNode *node = data.node();
00355   CPT(TransformState) net_transform = data.get_net_transform(this);
00356   CPT(TransformState) modelview_transform = data.get_modelview_transform(this);
00357 
00358   if (tight) {
00359     PT(Geom) bounds_viz = make_tight_bounds_viz(node);
00360 
00361     if (bounds_viz != (Geom *)NULL) {
00362       _geoms_pcollector.add_level(1);
00363       CullableObject *outer_viz = 
00364         new CullableObject(bounds_viz, get_bounds_outer_viz_state(), 
00365                            net_transform, modelview_transform,
00366                            get_gsg());
00367       _cull_handler->record_object(outer_viz, this);
00368     }
00369     
00370   } else {
00371     draw_bounding_volume(node->get_bounds(),
00372                          net_transform, modelview_transform);
00373 
00374     if (node->is_geom_node()) {
00375       // Also show the bounding volumes of included Geoms.
00376       net_transform = net_transform->compose(node->get_transform());
00377       modelview_transform = modelview_transform->compose(node->get_transform());
00378       GeomNode *gnode = DCAST(GeomNode, node);
00379       int num_geoms = gnode->get_num_geoms();
00380       for (int i = 0; i < num_geoms; ++i) {
00381         draw_bounding_volume(gnode->get_geom(i)->get_bounds(), 
00382                              net_transform, modelview_transform);
00383       }
00384     }
00385   }
00386 }
00387 
00388 ////////////////////////////////////////////////////////////////////
00389 //     Function: CullTraverser::make_bounds_viz
00390 //       Access: Private, Static
00391 //  Description: Returns an appropriate visualization of the indicated
00392 //               bounding volume.
00393 ////////////////////////////////////////////////////////////////////
00394 PT(Geom) CullTraverser::
00395 make_bounds_viz(const BoundingVolume *vol) {
00396   PT(Geom) geom;
00397   if (vol->is_infinite() || vol->is_empty()) {
00398     // No way to draw an infinite or empty bounding volume.
00399 
00400   } else if (vol->is_of_type(BoundingSphere::get_class_type())) {
00401     const BoundingSphere *sphere = DCAST(BoundingSphere, vol);
00402 
00403     static const int num_slices = 16;
00404     static const int num_stacks = 8;
00405 
00406     PT(GeomVertexData) vdata = new GeomVertexData
00407       ("bounds", GeomVertexFormat::get_v3(),
00408        Geom::UH_stream);
00409     GeomVertexWriter vertex(vdata, InternalName::get_vertex());
00410     
00411     PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_stream);
00412     for (int sl = 0; sl < num_slices; ++sl) {
00413       PN_stdfloat longitude0 = (PN_stdfloat)sl / (PN_stdfloat)num_slices;
00414       PN_stdfloat longitude1 = (PN_stdfloat)(sl + 1) / (PN_stdfloat)num_slices;
00415       vertex.add_data3(compute_point(sphere, 0.0, longitude0));
00416       for (int st = 1; st < num_stacks; ++st) {
00417         PN_stdfloat latitude = (PN_stdfloat)st / (PN_stdfloat)num_stacks;
00418         vertex.add_data3(compute_point(sphere, latitude, longitude0));
00419         vertex.add_data3(compute_point(sphere, latitude, longitude1));
00420       }
00421       vertex.add_data3(compute_point(sphere, 1.0, longitude0));
00422       
00423       strip->add_next_vertices(num_stacks * 2);
00424       strip->close_primitive();
00425     }
00426     
00427     geom = new Geom(vdata);
00428     geom->add_primitive(strip);
00429 
00430   } else if (vol->is_of_type(BoundingHexahedron::get_class_type())) {
00431     const BoundingHexahedron *fvol = DCAST(BoundingHexahedron, vol);
00432 
00433     PT(GeomVertexData) vdata = new GeomVertexData
00434       ("bounds", GeomVertexFormat::get_v3(),
00435        Geom::UH_stream);
00436     GeomVertexWriter vertex(vdata, InternalName::get_vertex());
00437 
00438     for (int i = 0; i < 8; ++i ) {
00439       vertex.add_data3(fvol->get_point(i));
00440     }
00441     
00442     PT(GeomLines) lines = new GeomLines(Geom::UH_stream);
00443     lines->add_vertices(0, 1); lines->close_primitive();
00444     lines->add_vertices(1, 2); lines->close_primitive();
00445     lines->add_vertices(2, 3); lines->close_primitive();
00446     lines->add_vertices(3, 0); lines->close_primitive();
00447 
00448     lines->add_vertices(4, 5); lines->close_primitive();
00449     lines->add_vertices(5, 6); lines->close_primitive();
00450     lines->add_vertices(6, 7); lines->close_primitive();
00451     lines->add_vertices(7, 4); lines->close_primitive();
00452 
00453     lines->add_vertices(0, 4); lines->close_primitive();
00454     lines->add_vertices(1, 5); lines->close_primitive();
00455     lines->add_vertices(2, 6); lines->close_primitive();
00456     lines->add_vertices(3, 7); lines->close_primitive();
00457 
00458     geom = new Geom(vdata);
00459     geom->add_primitive(lines);
00460 
00461   } else if (vol->is_of_type(FiniteBoundingVolume::get_class_type())) {
00462     const FiniteBoundingVolume *fvol = DCAST(FiniteBoundingVolume, vol);
00463 
00464     BoundingBox box(fvol->get_min(), fvol->get_max());
00465     box.local_object();
00466 
00467     PT(GeomVertexData) vdata = new GeomVertexData
00468       ("bounds", GeomVertexFormat::get_v3(),
00469        Geom::UH_stream);
00470     GeomVertexWriter vertex(vdata, InternalName::get_vertex());
00471 
00472     for (int i = 0; i < 8; ++i ) {
00473       vertex.add_data3(box.get_point(i));
00474     }
00475     
00476     PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_stream);
00477     tris->add_vertices(0, 4, 5);
00478     tris->close_primitive();
00479     tris->add_vertices(0, 5, 1);
00480     tris->close_primitive();
00481     tris->add_vertices(4, 6, 7);
00482     tris->close_primitive();
00483     tris->add_vertices(4, 7, 5);
00484     tris->close_primitive();
00485     tris->add_vertices(6, 2, 3);
00486     tris->close_primitive();
00487     tris->add_vertices(6, 3, 7);
00488     tris->close_primitive();
00489     tris->add_vertices(2, 0, 1);
00490     tris->close_primitive();
00491     tris->add_vertices(2, 1, 3);
00492     tris->close_primitive();
00493     tris->add_vertices(1, 5, 7);
00494     tris->close_primitive();
00495     tris->add_vertices(1, 7, 3);
00496     tris->close_primitive();
00497     tris->add_vertices(2, 6, 4);
00498     tris->close_primitive();
00499     tris->add_vertices(2, 4, 0);
00500     tris->close_primitive();
00501 
00502     geom = new Geom(vdata);
00503     geom->add_primitive(tris);
00504 
00505   } else {
00506     pgraph_cat.warning()
00507       << "Don't know how to draw a representation of "
00508       << vol->get_class_type() << "\n";
00509   }
00510 
00511   return geom;
00512 }
00513 
00514 ////////////////////////////////////////////////////////////////////
00515 //     Function: CullTraverser::make_tight_bounds_viz
00516 //       Access: Private
00517 //  Description: Returns a bounding-box visualization of the indicated
00518 //               node's "tight" bounding volume.
00519 ////////////////////////////////////////////////////////////////////
00520 PT(Geom) CullTraverser::
00521 make_tight_bounds_viz(PandaNode *node) const {
00522   PT(Geom) geom;
00523 
00524   NodePath np = NodePath::any_path(node);
00525 
00526   LPoint3 n, x;
00527   bool found_any = false;
00528   node->calc_tight_bounds(n, x, found_any, TransformState::make_identity(),
00529                           _current_thread);
00530   if (found_any) {
00531     PT(GeomVertexData) vdata = new GeomVertexData
00532       ("bounds", GeomVertexFormat::get_v3(),
00533       Geom::UH_stream);
00534     GeomVertexWriter vertex(vdata, InternalName::get_vertex(),
00535                             _current_thread);
00536     
00537     vertex.add_data3(n[0], n[1], n[2]);
00538     vertex.add_data3(n[0], n[1], x[2]);
00539     vertex.add_data3(n[0], x[1], n[2]);
00540     vertex.add_data3(n[0], x[1], x[2]);
00541     vertex.add_data3(x[0], n[1], n[2]);
00542     vertex.add_data3(x[0], n[1], x[2]);
00543     vertex.add_data3(x[0], x[1], n[2]);
00544     vertex.add_data3(x[0], x[1], x[2]);
00545   
00546     PT(GeomLinestrips) strip = new GeomLinestrips(Geom::UH_stream);
00547 
00548     // We wind one long linestrip around the wireframe cube.  This
00549     // does require backtracking a few times here and there.
00550     strip->add_vertex(0);
00551     strip->add_vertex(1);
00552     strip->add_vertex(3);
00553     strip->add_vertex(2);
00554     strip->add_vertex(0);
00555     strip->add_vertex(4);
00556     strip->add_vertex(5);
00557     strip->add_vertex(7);
00558     strip->add_vertex(6);
00559     strip->add_vertex(4);
00560     strip->add_vertex(6);
00561     strip->add_vertex(2);
00562     strip->add_vertex(3);
00563     strip->add_vertex(7);
00564     strip->add_vertex(5);
00565     strip->add_vertex(1);
00566     strip->close_primitive();
00567       
00568     geom = new Geom(vdata);
00569     geom->add_primitive(strip);
00570   }
00571 
00572   return geom;
00573 }
00574 
00575 ////////////////////////////////////////////////////////////////////
00576 //     Function: CullTraverser::compute_point
00577 //       Access: Private, Static
00578 //  Description: Returns a point on the surface of the sphere.
00579 //               latitude and longitude range from 0.0 to 1.0.  
00580 ////////////////////////////////////////////////////////////////////
00581 LVertex CullTraverser::
00582 compute_point(const BoundingSphere *sphere, 
00583               PN_stdfloat latitude, PN_stdfloat longitude) {
00584   PN_stdfloat s1, c1;
00585   csincos(latitude * MathNumbers::pi, &s1, &c1);
00586 
00587   PN_stdfloat s2, c2;
00588   csincos(longitude * 2.0 * MathNumbers::pi, &s2, &c2);
00589 
00590   LVertex p(s1 * c2, s1 * s2, c1);
00591   return p * sphere->get_radius() + sphere->get_center();
00592 }
00593 
00594 ////////////////////////////////////////////////////////////////////
00595 //     Function: CullTraverser::get_bounds_outer_viz_state
00596 //       Access: Private, Static
00597 //  Description: Returns a RenderState for rendering the outside
00598 //               surfaces of the bounding volume visualizations.
00599 ////////////////////////////////////////////////////////////////////
00600 CPT(RenderState) CullTraverser::
00601 get_bounds_outer_viz_state() {
00602   // Once someone asks for this pointer, we hold its reference count
00603   // and never free it.
00604   static CPT(RenderState) state = (const RenderState *)NULL;
00605   if (state == (const RenderState *)NULL) {
00606     state = RenderState::make
00607       (ColorAttrib::make_flat(LColor(0.3, 1.0f, 0.5f, 1.0f)),
00608        RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
00609        CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise));
00610   }
00611   return state;
00612 }
00613 
00614 ////////////////////////////////////////////////////////////////////
00615 //     Function: CullTraverser::get_bounds_inner_viz_state
00616 //       Access: Private, Static
00617 //  Description: Returns a RenderState for rendering the inside
00618 //               surfaces of the bounding volume visualizations.
00619 ////////////////////////////////////////////////////////////////////
00620 CPT(RenderState) CullTraverser::
00621 get_bounds_inner_viz_state() {
00622   // Once someone asks for this pointer, we hold its reference count
00623   // and never free it.
00624   static CPT(RenderState) state = (const RenderState *)NULL;
00625   if (state == (const RenderState *)NULL) {
00626     state = RenderState::make
00627       (ColorAttrib::make_flat(LColor(0.15f, 0.5f, 0.25f, 1.0f)),
00628        RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
00629        CullFaceAttrib::make(CullFaceAttrib::M_cull_counter_clockwise));
00630   }
00631   return state;
00632 }
00633 
00634 ////////////////////////////////////////////////////////////////////
00635 //     Function: CullTraverser::get_depth_offset_state
00636 //       Access: Private, Static
00637 //  Description: Returns a RenderState for increasing the DepthOffset
00638 //               by one.
00639 ////////////////////////////////////////////////////////////////////
00640 CPT(RenderState) CullTraverser::
00641 get_depth_offset_state() {
00642   // Once someone asks for this pointer, we hold its reference count
00643   // and never free it.
00644   static CPT(RenderState) state = (const RenderState *)NULL;
00645   if (state == (const RenderState *)NULL) {
00646     state = RenderState::make
00647       (DepthOffsetAttrib::make(1));
00648   }
00649   return state;
00650 }
00651 
00652 
00653 ////////////////////////////////////////////////////////////////////
00654 //     Function: CullTraverser::start_decal
00655 //       Access: Private
00656 //  Description: Collects a base node and all of the decals applied to
00657 //               it.  This involves recursing below the base GeomNode
00658 //               to find all the decal geoms.
00659 ////////////////////////////////////////////////////////////////////
00660 void CullTraverser::
00661 start_decal(const CullTraverserData &data) {
00662   PandaNode *node = data.node();
00663   if (!node->is_geom_node()) {
00664     pgraph_cat.error()
00665       << "DecalEffect applied to " << *node << ", not a GeomNode.\n";
00666     return;
00667   }
00668 
00669   const PandaNodePipelineReader *node_reader = data.node_reader();
00670 
00671   // Build a chain of CullableObjects.  The head of the chain will be
00672   // all of the base Geoms in order, followed by an empty
00673   // CullableObject node, followed by all of the decal Geoms, in
00674   // order.
00675 
00676   // Since the CullableObject is a linked list which gets built in
00677   // LIFO order, we start with the decals.
00678   CullableObject *decals = (CullableObject *)NULL;
00679   PandaNode::Children cr = node_reader->get_children();
00680   int num_children = cr.get_num_children();
00681   if (node->has_selective_visibility()) {
00682     int i = node->get_first_visible_child();
00683     while (i < num_children) {
00684       CullTraverserData next_data(data, cr.get_child(i));
00685       decals = r_get_decals(next_data, decals);
00686       i = node->get_next_visible_child(i);
00687     }
00688     
00689   } else {
00690     for (int i = num_children - 1; i >= 0; i--) {
00691       CullTraverserData next_data(data, cr.get_child(i));
00692       decals = r_get_decals(next_data, decals);
00693     }
00694   }
00695 
00696   // Now create a new, empty CullableObject to separate the decals
00697   // from the non-decals.
00698   CullableObject *separator = new CullableObject;
00699   separator->set_next(decals);
00700 
00701   // And now get the base Geoms, again in reverse order.
00702   CullableObject *object = separator;
00703   GeomNode *geom_node = DCAST(GeomNode, node);
00704   GeomNode::Geoms geoms = geom_node->get_geoms();
00705   int num_geoms = geoms.get_num_geoms();
00706   _geoms_pcollector.add_level(num_geoms);
00707   CPT(TransformState) net_transform = data.get_net_transform(this);
00708   CPT(TransformState) modelview_transform = data.get_modelview_transform(this);
00709   CPT(TransformState) internal_transform = get_gsg()->get_cs_transform()->compose(modelview_transform);
00710   
00711   for (int i = num_geoms - 1; i >= 0; i--) {
00712     const Geom *geom = geoms.get_geom(i);
00713     if (geom->is_empty()) {
00714       continue;
00715     }
00716 
00717     CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i));
00718     if (state->has_cull_callback() && !state->cull_callback(this, data)) {
00719       // Cull.
00720       continue;
00721     }
00722     
00723     // Cull the Geom bounding volume against the view frustum
00724     // and/or the cull planes.  Don't bother unless we've got more
00725     // than one Geom, since otherwise the bounding volume of the
00726     // GeomNode is (probably) the same as that of the one Geom,
00727     // and we've already culled against that.
00728     if (num_geoms > 1) {
00729       if (data._view_frustum != (GeometricBoundingVolume *)NULL) {
00730         // Cull the individual Geom against the view frustum.
00731         CPT(BoundingVolume) geom_volume = geom->get_bounds();
00732         const GeometricBoundingVolume *geom_gbv =
00733           DCAST(GeometricBoundingVolume, geom_volume);
00734         
00735         int result = data._view_frustum->contains(geom_gbv);
00736         if (result == BoundingVolume::IF_no_intersection) {
00737           // Cull this Geom.
00738           continue;
00739         }
00740       }
00741       if (!data._cull_planes->is_empty()) {
00742         // Also cull the Geom against the cull planes.
00743         CPT(BoundingVolume) geom_volume = geom->get_bounds();
00744         const GeometricBoundingVolume *geom_gbv =
00745           DCAST(GeometricBoundingVolume, geom_volume);
00746         int result;
00747         data._cull_planes->do_cull(result, state, geom_gbv);
00748         if (result == BoundingVolume::IF_no_intersection) {
00749           // Cull.
00750           continue;
00751         }
00752       }
00753     }
00754 
00755     CullableObject *next = object;
00756     object =
00757       new CullableObject(geom, state, net_transform, 
00758                          modelview_transform, internal_transform);
00759     object->set_next(next);
00760   }
00761 
00762   if (object != separator) {
00763     // Finally, send the whole list down to the CullHandler for
00764     // processing.  The first Geom in the node now represents the
00765     // overall state.
00766     _cull_handler->record_object(object, this);
00767   } else {
00768     // Never mind; there's nothing to render.
00769     delete object;
00770   }
00771 }
00772 
00773 ////////////////////////////////////////////////////////////////////
00774 //     Function: CullTraverser::r_get_decals
00775 //       Access: Private
00776 //  Description: Recursively gets all the decals applied to a
00777 //               particular GeomNode.  These are built into a
00778 //               CullableObject list in LIFO order (so that the
00779 //               traversing the list will extract them in the order
00780 //               they were encountered in the scene graph).
00781 ////////////////////////////////////////////////////////////////////
00782 CullableObject *CullTraverser::
00783 r_get_decals(CullTraverserData &data, CullableObject *decals) {
00784   if (is_in_view(data)) {
00785     PandaNodePipelineReader *node_reader = data.node_reader();
00786     PandaNode *node = data.node();
00787 
00788     const RenderEffects *node_effects = node_reader->get_effects();
00789     if (node_effects->has_show_bounds()) {
00790       // If we should show the bounding volume for this node, make it
00791       // up now.
00792       show_bounds(data, node_effects->has_show_tight_bounds());
00793     }
00794 
00795     data.apply_transform_and_state(this);
00796 
00797     // First, visit all of the node's children.
00798     int num_children = node_reader->get_num_children();
00799     if (node->has_selective_visibility()) {
00800       int i = node->get_first_visible_child();
00801       while (i < num_children) {
00802         CullTraverserData next_data(data, node_reader->get_child(i));
00803         decals = r_get_decals(next_data, decals);
00804         i = node->get_next_visible_child(i);
00805       }
00806       
00807     } else {
00808       for (int i = num_children - 1; i >= 0; i--) {
00809         CullTraverserData next_data(data, node_reader->get_child(i));
00810         decals = r_get_decals(next_data, decals);
00811       }
00812     }
00813 
00814     // Now, tack on any geoms within the node.
00815     if (node->is_geom_node()) {
00816       GeomNode *geom_node = DCAST(GeomNode, node);
00817       GeomNode::Geoms geoms = geom_node->get_geoms();
00818       int num_geoms = geoms.get_num_geoms();
00819       _geoms_pcollector.add_level(num_geoms);
00820       CPT(TransformState) net_transform = data.get_net_transform(this);
00821       CPT(TransformState) modelview_transform = data.get_modelview_transform(this);
00822       CPT(TransformState) internal_transform = get_gsg()->get_cs_transform()->compose(modelview_transform);
00823 
00824       for (int i = num_geoms - 1; i >= 0; i--) {
00825         const Geom *geom = geoms.get_geom(i);
00826         if (geom->is_empty()) {
00827           continue;
00828         }
00829 
00830         CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i));
00831         if (state->has_cull_callback() && !state->cull_callback(this, data)) {
00832           // Cull.
00833           continue;
00834         }
00835 
00836         // Cull the Geom bounding volume against the view frustum
00837         // and/or the cull planes.  Don't bother unless we've got more
00838         // than one Geom, since otherwise the bounding volume of the
00839         // GeomNode is (probably) the same as that of the one Geom,
00840         // and we've already culled against that.
00841         if (num_geoms > 1) {
00842           if (data._view_frustum != (GeometricBoundingVolume *)NULL) {
00843             // Cull the individual Geom against the view frustum.
00844             CPT(BoundingVolume) geom_volume = geom->get_bounds();
00845             const GeometricBoundingVolume *geom_gbv =
00846               DCAST(GeometricBoundingVolume, geom_volume);
00847 
00848             int result = data._view_frustum->contains(geom_gbv);
00849             if (result == BoundingVolume::IF_no_intersection) {
00850               // Cull this Geom.
00851               continue;
00852             }
00853           }
00854           if (!data._cull_planes->is_empty()) {
00855             // Also cull the Geom against the cull planes.
00856             CPT(BoundingVolume) geom_volume = geom->get_bounds();
00857             const GeometricBoundingVolume *geom_gbv =
00858               DCAST(GeometricBoundingVolume, geom_volume);
00859             int result;
00860             data._cull_planes->do_cull(result, state, geom_gbv);
00861             if (result == BoundingVolume::IF_no_intersection) {
00862               // Cull.
00863               continue;
00864             }
00865           }
00866         }
00867 
00868         CullableObject *next = decals;
00869         decals =
00870           new CullableObject(geom, state, net_transform, 
00871                              modelview_transform, internal_transform);
00872         decals->set_next(next);
00873       }
00874     }
00875   }
00876 
00877   return decals;
00878 }
 All Classes Functions Variables Enumerations