Browse Source

Remove old decal system to simplify cull/draw process a bit more

rdb 11 years ago
parent
commit
5e5a04031f

+ 4 - 4
panda/src/pgraph/config_pgraph.cxx

@@ -257,12 +257,12 @@ ConfigVariableBool retransform_sprites
           "necessary in order for fog to work correctly on the sprites."));
 
 ConfigVariableBool depth_offset_decals
-("depth-offset-decals", false,
+("depth-offset-decals", true,
  PRC_DESC("Set this true to allow decals to be implemented via the advanced "
           "depth offset feature, if supported, instead of via the traditional "
-          "(and slower) two-pass approach.  This is false by default "
-          "because it appears that many graphics drivers have issues with "
-          "their depth offset implementation."));
+          "(and slower) two-pass approach.  This is currently the only method "
+          "by which decals are implemented in Panda3D, and as such, this "
+          "setting is ignored."));
 
 ConfigVariableInt max_collect_vertices
 ("max-collect-vertices", 65534,

+ 6 - 51
panda/src/pgraph/cullBin.cxx

@@ -27,7 +27,7 @@ TypeHandle CullBin::_type_handle;
 ////////////////////////////////////////////////////////////////////
 //     Function: CullBin::Destructor
 //       Access: Public, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 CullBin::
 ~CullBin() {
@@ -115,7 +115,7 @@ check_flash_color() {
   } else {
     _has_flash_color = false;
     pgraph_cat.warning()
-      << "Invalid value for flash-bin-" << _name << ": " 
+      << "Invalid value for flash-bin-" << _name << ": "
       << flash_bin.get_string_value() << "\n";
   }
 #endif  // NDEBUG
@@ -124,7 +124,7 @@ check_flash_color() {
 ////////////////////////////////////////////////////////////////////
 //     Function: CullBin::ResultGraphBuilder::Constructor
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 CullBin::ResultGraphBuilder::
 ResultGraphBuilder(PandaNode *root_node) :
@@ -142,9 +142,8 @@ ResultGraphBuilder(PandaNode *root_node) :
 ////////////////////////////////////////////////////////////////////
 void CullBin::ResultGraphBuilder::
 add_object(CullableObject *object) {
-  if (_current_transform != object->_modelview_transform || 
-      _current_state != object->_state || 
-      object->is_fancy()) {
+  if (_current_transform != object->_modelview_transform ||
+      _current_state != object->_state) {
     // Create a new GeomNode to hold the net transform and state.  We
     // choose to create a new GeomNode for each new state, to make it
     // clearer to the observer when the state changes.
@@ -157,57 +156,13 @@ add_object(CullableObject *object) {
   }
 
   record_one_object(_current_node, object);
-
-  if (object->get_next() != (CullableObject *)NULL) {
-    // Collect the decal base pieces.
-    CullableObject *base = object->get_next();
-    while (base != (CullableObject *)NULL && base->_geom != (Geom *)NULL) {
-      record_one_object(_current_node, base);
-      base = base->get_next();
-    }
-
-    if (base != (CullableObject *)NULL) {
-      // Now, collect all the decals.
-      _current_node->set_effect(DecalEffect::make());
-      int decal_index = 0;
-
-      CPT(TransformState) transform;
-      CPT(RenderState) state;
-      PT(GeomNode) decal_node;
-      CullableObject *decal = base->get_next();
-      while (decal != (CullableObject *)NULL) {
-        if (transform != decal->_modelview_transform || 
-            state != decal->_state || 
-            decal->get_next() != (CullableObject *)NULL) {
-          // Create a new GeomNode to hold the net transform.
-          transform = decal->_modelview_transform;
-          state = decal->_state;
-          decal_node = new GeomNode("decal_" + format_string(decal_index));
-          _current_node->add_child(decal_node);
-          decal_node->set_transform(transform);
-          decal_node->set_state(state);
-        }
-        
-        record_one_object(decal_node, decal);
-        decal = decal->get_next();
-        ++decal_index;
-      }
-    }
-
-    // Reset the current node pointer for next time so the decal root
-    // will remain in its own node.
-    _current_node.clear();
-    _current_transform.clear();
-    _current_state.clear();
-  }
-
   ++_object_index;
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: CullBin::ResultGraphBuilder::record_one_object
 //       Access: Private
-//  Description: Records a single object, without regard to decalling.
+//  Description: Records a single object.
 ////////////////////////////////////////////////////////////////////
 void CullBin::ResultGraphBuilder::
 record_one_object(GeomNode *node, CullableObject *object) {

+ 13 - 61
panda/src/pgraph/cullResult.cxx

@@ -57,7 +57,7 @@ static const double bin_color_flash_rate = 1.0;  // 1 state change per second
 ////////////////////////////////////////////////////////////////////
 //     Function: CullResult::Constructor
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 CullResult::
 CullResult(GraphicsStateGuardianBase *gsg,
@@ -87,7 +87,7 @@ make_next() const {
 
   for (size_t i = 0; i < _bins.size(); ++i) {
     CullBin *old_bin = _bins[i];
-    if (old_bin == (CullBin *)NULL || 
+    if (old_bin == (CullBin *)NULL ||
         old_bin->get_bin_type() != bin_manager->get_bin_type(i)) {
       new_result->_bins.push_back((CullBin *)NULL);
     } else {
@@ -166,21 +166,19 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
       // later.  This means we must copy the object and add it to
       // both bins.  We can only do this if we do not have an
       // explicit bin already applied; otherwise, M_dual falls back
-      // to M_alpha. 
+      // to M_alpha.
       {
         const CullBinAttrib *bin_attrib = DCAST(CullBinAttrib, state->get_attrib(CullBinAttrib::get_class_slot()));
-        if (bin_attrib == (CullBinAttrib *)NULL || 
+        if (bin_attrib == (CullBinAttrib *)NULL ||
             bin_attrib->get_bin_name().empty()) {
-          // We make a copy of the object to draw the transparent part
-          // without decals; this gets placed in the transparent bin.
+          // We make a copy of the object to draw the transparent part;
+          // this gets placed in the transparent bin.
 #ifndef NDEBUG
-          if (m_dual_transparent) 
+          if (m_dual_transparent)
 #endif
             {
               CullableObject *transparent_part = new CullableObject(*object);
-              CPT(RenderState) transparent_state = object->has_decals() ? 
-                get_dual_transparent_state_decals() : 
-                get_dual_transparent_state();
+              CPT(RenderState) transparent_state = get_dual_transparent_state();
               transparent_part->_state = state->compose(transparent_state);
               if (transparent_part->munge_geom
                   (_gsg, _gsg->get_geom_munger(transparent_part->_state, current_thread),
@@ -195,9 +193,9 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
                 delete transparent_part;
               }
             }
-          
-          // Now we can draw the opaque part, with decals.  This will
-          // end up in the opaque bin.
+
+          // Now we can draw the opaque part.  This will end up in
+          // the opaque bin.
           object->_state = state->compose(get_dual_opaque_state());
 #ifndef NDEBUG
           if (!m_dual_opaque) {
@@ -210,7 +208,7 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
         // M_alpha.
       }
       break;
-      
+
     default:
       // Other kinds of transparency need no special handling.
       break;
@@ -443,8 +441,6 @@ check_flash_transparency(CPT(RenderState) &state, const LColor &transparency) {
 //       Access: Private
 //  Description: Returns a RenderState that renders only the
 //               transparent parts of an object, in support of M_dual.
-//               This state is suitable only for objects that do not
-//               contain decals.
 ////////////////////////////////////////////////////////////////////
 CPT(RenderState) CullResult::
 get_dual_transparent_state() {
@@ -454,10 +450,7 @@ get_dual_transparent_state() {
     // and hence filling up the depth buffer with large empty spaces
     // that may obscure other things.  However, this does mean we draw
     // pixels twice where the alpha == 1.0 (since they were already
-    // drawn in the opaque pass).  This is not normally a problem,
-    // except when we are using decals; in the case of decals, we
-    // don't want to draw the 1.0 pixels again, since these are the
-    // ones that may have been decaled onto.
+    // drawn in the opaque pass).  This is not normally a problem.
     state = RenderState::make(AlphaTestAttrib::make(AlphaTestAttrib::M_greater, 0.0f),
                               TransparencyAttrib::make(TransparencyAttrib::M_alpha),
                               DepthWriteAttrib::make(DepthWriteAttrib::M_off),
@@ -487,47 +480,6 @@ get_dual_transparent_state() {
   return state;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: CullResult::get_dual_transparent_state_decals
-//       Access: Private
-//  Description: Returns a RenderState that renders only the
-//               transparent parts of an object, but suitable for
-//               objects that contain decals.
-////////////////////////////////////////////////////////////////////
-CPT(RenderState) CullResult::
-get_dual_transparent_state_decals() {
-  static CPT(RenderState) state = NULL;
-  if (state == (const RenderState *)NULL) {
-    // This is exactly the same as above except here we make the alpha
-    // test of < 1.0 instead of > 0.0.  This makes us draw big empty
-    // pixels where the alpha values are 0.0, but we don't overwrite
-    // the decals where the pixels are 1.0.
-    state = RenderState::make(AlphaTestAttrib::make(AlphaTestAttrib::M_less, dual_opaque_level),
-                              TransparencyAttrib::make(TransparencyAttrib::M_alpha),
-                              DepthWriteAttrib::make(DepthWriteAttrib::M_off),
-                              RenderState::get_max_priority());
-  }
-
-#ifndef NDEBUG
-  if (m_dual_flash) {
-    int cycle = (int)(ClockObject::get_global_clock()->get_frame_time() * bin_color_flash_rate);
-    if ((cycle & 1) == 0) {
-      static CPT(RenderState) flash_state = NULL;
-      if (flash_state == (const RenderState *)NULL) {
-        flash_state = state->add_attrib(ColorAttrib::make_flat(LColor(0.8f, 0.2, 0.2, 1.0f)),
-                                        RenderState::get_max_priority());
-        flash_state = flash_state->add_attrib(ColorScaleAttrib::make(LVecBase4(1.0f, 1.0f, 1.0f, 1.0f)),
-                                              RenderState::get_max_priority());
-
-      }
-      return flash_state;
-    }
-  }
-#endif  // NDEBUG
-
-  return state;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: CullResult::get_dual_opaque_state
 //       Access: Private

+ 2 - 5
panda/src/pgraph/cullResult.h

@@ -72,12 +72,11 @@ private:
   static CPT(RenderState) get_alpha_state();
   static CPT(RenderState) get_binary_state();
   static CPT(RenderState) get_dual_transparent_state();
-  static CPT(RenderState) get_dual_transparent_state_decals();
   static CPT(RenderState) get_dual_opaque_state();
 
   GraphicsStateGuardianBase *_gsg;
   PStatCollector _draw_region_pcollector;
-  
+
   typedef pvector< PT(CullBin) > Bins;
   Bins _bins;
 
@@ -90,7 +89,7 @@ public:
     register_type(_type_handle, "CullResult",
                   ReferenceCount::get_class_type());
   }
-  
+
 private:
   static TypeHandle _type_handle;
 };
@@ -99,5 +98,3 @@ private:
 
 #endif
 
-
-  

+ 4 - 4
panda/src/pgraph/cullTraverser.I

@@ -110,12 +110,12 @@ get_initial_state() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: CullTraverser::get_depth_offset_decals
 //       Access: Published
-//  Description: Returns the depth_offset_decals flag.  See
-//               set_depth_offset_decals().
+//  Description: Returns true, as depth offsets are the only way
+//               that we implement decals nowadays.
 ////////////////////////////////////////////////////////////////////
 INLINE bool CullTraverser::
 get_depth_offset_decals() const {
-  return _depth_offset_decals;
+  return true;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -199,7 +199,7 @@ get_cull_handler() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: CullTraverser::set_portal_clipper
 //       Access: Published
-//  Description: Specifies _portal_clipper object pointer that 
+//  Description: Specifies _portal_clipper object pointer that
 //               subsequent traverse() or traverse_below may use.
 ////////////////////////////////////////////////////////////////////
 INLINE void CullTraverser::

+ 67 - 303
panda/src/pgraph/cullTraverser.cxx

@@ -47,7 +47,7 @@ TypeHandle CullTraverser::_type_handle;
 ////////////////////////////////////////////////////////////////////
 //     Function: CullTraverser::Constructor
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 CullTraverser::
 CullTraverser() :
@@ -65,7 +65,7 @@ CullTraverser() :
 ////////////////////////////////////////////////////////////////////
 //     Function: CullTraverser::Copy Constructor
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 CullTraverser::
 CullTraverser(const CullTraverser &copy) :
@@ -76,7 +76,6 @@ CullTraverser(const CullTraverser &copy) :
   _has_tag_state_key(copy._has_tag_state_key),
   _tag_state_key(copy._tag_state_key),
   _initial_state(copy._initial_state),
-  _depth_offset_decals(copy._depth_offset_decals),
   _view_frustum(copy._view_frustum),
   _cull_handler(copy._cull_handler),
   _portal_clipper(copy._portal_clipper),
@@ -98,7 +97,6 @@ set_scene(SceneSetup *scene_setup, GraphicsStateGuardianBase *gsg,
   _gsg = gsg;
 
   _initial_state = scene_setup->get_initial_state();
-  _depth_offset_decals = _gsg->depth_offset_decals() && depth_offset_decals;
 
   _current_thread = Thread::get_current_thread();
 
@@ -129,43 +127,43 @@ traverse(const NodePath &root) {
     PT(BoundingVolume) bv = _scene_setup->get_lens()->make_bounds();
     if (bv != (BoundingVolume *)NULL &&
         bv->is_of_type(GeometricBoundingVolume::get_class_type())) {
-      
+
       local_frustum = DCAST(GeometricBoundingVolume, bv);
     }
-      
+
     // This local_frustum is in camera space
     PortalClipper portal_viewer(local_frustum, _scene_setup);
     if (debug_portal_cull) {
       portal_viewer.draw_camera_frustum();
     }
-    
+
     // Store this pointer in this
     set_portal_clipper(&portal_viewer);
 
     CullTraverserData data(root, TransformState::make_identity(),
-                           _initial_state, _view_frustum, 
+                           _initial_state, _view_frustum,
                            _current_thread);
-    
+
     traverse(data);
-    
+
     // Finally add the lines to be drawn
     if (debug_portal_cull) {
       portal_viewer.draw_lines();
     }
-    
+
     // Render the frustum relative to the cull center.
     NodePath cull_center = _scene_setup->get_cull_center();
     CPT(TransformState) transform = cull_center.get_transform(root);
-    
+
     CullTraverserData my_data(data, portal_viewer._previous);
     my_data._net_transform = my_data._net_transform->compose(transform);
     traverse(my_data);
 
   } else {
     CullTraverserData data(root, TransformState::make_identity(),
-                           _initial_state, _view_frustum, 
+                           _initial_state, _view_frustum,
                            _current_thread);
-    
+
     traverse(data);
   }
 }
@@ -181,7 +179,7 @@ void CullTraverser::
 traverse(CullTraverserData &data) {
   if (is_in_view(data)) {
     if (pgraph_cat.is_spam()) {
-      pgraph_cat.spam() 
+      pgraph_cat.spam()
         << "\n" << data._node_path
         << " " << data._draw_mask << "\n";
     }
@@ -207,9 +205,9 @@ traverse(CullTraverserData &data) {
         // up now.
         show_bounds(data, node_effects->has_show_tight_bounds());
       }
-      
+
       data.apply_transform_and_state(this);
-      
+
       const FogAttrib *fog = DCAST(FogAttrib, node_reader->get_state()->get_attrib(FogAttrib::get_class_slot()));
       if (fog != (const FogAttrib *)NULL && fog->get_fog() != (Fog *)NULL) {
         // If we just introduced a FogAttrib here, call adjust_to_camera()
@@ -218,7 +216,7 @@ traverse(CullTraverserData &data) {
         // need for it.
         fog->get_fog()->adjust_to_camera(get_camera_transform());
       }
-      
+
       if (fancy_bits & PandaNode::FB_cull_callback) {
         PandaNode *node = data.node();
         if (!node->cull_callback(this, data)) {
@@ -247,47 +245,41 @@ traverse_below(CullTraverserData &data) {
 
   const RenderEffects *node_effects = node_reader->get_effects();
   bool has_decal = !this_node_hidden && node_effects->has_decal();
-  if (has_decal && !_depth_offset_decals) {
-    // Start the three-pass decal rendering if we're not using
-    // DepthOffsetAttribs to implement decals.
-    start_decal(data);
-    
-  } else {
-    if (!this_node_hidden) {
-      node->add_for_draw(this, data);
-    }
 
-    if (has_decal) {
-      // If we *are* implementing decals with DepthOffsetAttribs,
-      // apply it now, so that each child of this node gets offset by
-      // a tiny amount.
-      data._state = data._state->compose(get_depth_offset_state());
+  if (!this_node_hidden) {
+    node->add_for_draw(this, data);
+  }
+
+  if (has_decal) {
+    // If we *are* implementing decals with DepthOffsetAttribs,
+    // apply it now, so that each child of this node gets offset by
+    // a tiny amount.
+    data._state = data._state->compose(get_depth_offset_state());
 #ifndef NDEBUG
-      // This is just a sanity check message.
-      if (!node->is_geom_node()) {
-        pgraph_cat.error()
-          << "DecalEffect applied to " << *node << ", not a GeomNode.\n";
-      }
+    // This is just a sanity check message.
+    if (!node->is_geom_node()) {
+      pgraph_cat.error()
+        << "DecalEffect applied to " << *node << ", not a GeomNode.\n";
+    }
 #endif
+  }
+
+  // Now visit all the node's children.
+  PandaNode::Children children = node_reader->get_children();
+  node_reader->release();
+  int num_children = children.get_num_children();
+  if (node->has_selective_visibility()) {
+    int i = node->get_first_visible_child();
+    while (i < num_children) {
+      CullTraverserData next_data(data, children.get_child(i));
+      traverse(next_data);
+      i = node->get_next_visible_child(i);
     }
 
-    // Now visit all the node's children.
-    PandaNode::Children children = node_reader->get_children();
-    node_reader->release();
-    int num_children = children.get_num_children();
-    if (node->has_selective_visibility()) {
-      int i = node->get_first_visible_child();
-      while (i < num_children) {
-        CullTraverserData next_data(data, children.get_child(i));
-        traverse(next_data);
-        i = node->get_next_visible_child(i);
-      }
-      
-    } else {
-      for (int i = 0; i < num_children; i++) {
-        CullTraverserData next_data(data, children.get_child(i));
-        traverse(next_data);
-      }
+  } else {
+    for (int i = 0; i < num_children; i++) {
+      CullTraverserData next_data(data, children.get_child(i));
+      traverse(next_data);
     }
   }
 }
@@ -311,20 +303,20 @@ end_traverse() {
 //               bounding volume.
 ////////////////////////////////////////////////////////////////////
 void CullTraverser::
-draw_bounding_volume(const BoundingVolume *vol, 
+draw_bounding_volume(const BoundingVolume *vol,
                      const TransformState *net_transform,
                      const TransformState *modelview_transform) const {
   PT(Geom) bounds_viz = make_bounds_viz(vol);
-  
+
   if (bounds_viz != (Geom *)NULL) {
     _geoms_pcollector.add_level(2);
-    CullableObject *outer_viz = 
-      new CullableObject(bounds_viz, get_bounds_outer_viz_state(), 
+    CullableObject *outer_viz =
+      new CullableObject(bounds_viz, get_bounds_outer_viz_state(),
                          net_transform, modelview_transform, get_scene());
     _cull_handler->record_object(outer_viz, this);
-    
-    CullableObject *inner_viz = 
-      new CullableObject(bounds_viz, get_bounds_inner_viz_state(), 
+
+    CullableObject *inner_viz =
+      new CullableObject(bounds_viz, get_bounds_inner_viz_state(),
                          net_transform, modelview_transform, get_scene());
     _cull_handler->record_object(inner_viz, this);
   }
@@ -360,13 +352,13 @@ show_bounds(CullTraverserData &data, bool tight) {
 
     if (bounds_viz != (Geom *)NULL) {
       _geoms_pcollector.add_level(1);
-      CullableObject *outer_viz = 
-        new CullableObject(bounds_viz, get_bounds_outer_viz_state(), 
+      CullableObject *outer_viz =
+        new CullableObject(bounds_viz, get_bounds_outer_viz_state(),
                            net_transform, modelview_transform,
                            get_scene());
       _cull_handler->record_object(outer_viz, this);
     }
-    
+
   } else {
     draw_bounding_volume(node->get_bounds(),
                          net_transform, modelview_transform);
@@ -378,7 +370,7 @@ show_bounds(CullTraverserData &data, bool tight) {
       GeomNode *gnode = DCAST(GeomNode, node);
       int num_geoms = gnode->get_num_geoms();
       for (int i = 0; i < num_geoms; ++i) {
-        draw_bounding_volume(gnode->get_geom(i)->get_bounds(), 
+        draw_bounding_volume(gnode->get_geom(i)->get_bounds(),
                              net_transform, modelview_transform);
       }
     }
@@ -407,7 +399,7 @@ make_bounds_viz(const BoundingVolume *vol) {
       ("bounds", GeomVertexFormat::get_v3(),
        Geom::UH_stream);
     GeomVertexWriter vertex(vdata, InternalName::get_vertex());
-    
+
     PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_stream);
     for (int sl = 0; sl < num_slices; ++sl) {
       PN_stdfloat longitude0 = (PN_stdfloat)sl / (PN_stdfloat)num_slices;
@@ -419,11 +411,11 @@ make_bounds_viz(const BoundingVolume *vol) {
         vertex.add_data3(compute_point(sphere, latitude, longitude1));
       }
       vertex.add_data3(compute_point(sphere, 1.0, longitude0));
-      
+
       strip->add_next_vertices(num_stacks * 2);
       strip->close_primitive();
     }
-    
+
     geom = new Geom(vdata);
     geom->add_primitive(strip);
 
@@ -438,7 +430,7 @@ make_bounds_viz(const BoundingVolume *vol) {
     for (int i = 0; i < 8; ++i ) {
       vertex.add_data3(fvol->get_point(i));
     }
-    
+
     PT(GeomLines) lines = new GeomLines(Geom::UH_stream);
     lines->add_vertices(0, 1); lines->close_primitive();
     lines->add_vertices(1, 2); lines->close_primitive();
@@ -472,7 +464,7 @@ make_bounds_viz(const BoundingVolume *vol) {
     for (int i = 0; i < 8; ++i ) {
       vertex.add_data3(box.get_point(i));
     }
-    
+
     PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_stream);
     tris->add_vertices(0, 4, 5);
     tris->close_primitive();
@@ -533,7 +525,7 @@ make_tight_bounds_viz(PandaNode *node) const {
       Geom::UH_stream);
     GeomVertexWriter vertex(vdata, InternalName::get_vertex(),
                             _current_thread);
-    
+
     vertex.add_data3(n[0], n[1], n[2]);
     vertex.add_data3(n[0], n[1], x[2]);
     vertex.add_data3(n[0], x[1], n[2]);
@@ -542,7 +534,7 @@ make_tight_bounds_viz(PandaNode *node) const {
     vertex.add_data3(x[0], n[1], x[2]);
     vertex.add_data3(x[0], x[1], n[2]);
     vertex.add_data3(x[0], x[1], x[2]);
-  
+
     PT(GeomLinestrips) strip = new GeomLinestrips(Geom::UH_stream);
 
     // We wind one long linestrip around the wireframe cube.  This
@@ -564,7 +556,7 @@ make_tight_bounds_viz(PandaNode *node) const {
     strip->add_vertex(5);
     strip->add_vertex(1);
     strip->close_primitive();
-      
+
     geom = new Geom(vdata);
     geom->add_primitive(strip);
   }
@@ -576,10 +568,10 @@ make_tight_bounds_viz(PandaNode *node) const {
 //     Function: CullTraverser::compute_point
 //       Access: Private, Static
 //  Description: Returns a point on the surface of the sphere.
-//               latitude and longitude range from 0.0 to 1.0.  
+//               latitude and longitude range from 0.0 to 1.0.
 ////////////////////////////////////////////////////////////////////
 LVertex CullTraverser::
-compute_point(const BoundingSphere *sphere, 
+compute_point(const BoundingSphere *sphere,
               PN_stdfloat latitude, PN_stdfloat longitude) {
   PN_stdfloat s1, c1;
   csincos(latitude * MathNumbers::pi, &s1, &c1);
@@ -648,231 +640,3 @@ get_depth_offset_state() {
   }
   return state;
 }
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: CullTraverser::start_decal
-//       Access: Private
-//  Description: Collects a base node and all of the decals applied to
-//               it.  This involves recursing below the base GeomNode
-//               to find all the decal geoms.
-////////////////////////////////////////////////////////////////////
-void CullTraverser::
-start_decal(const CullTraverserData &data) {
-  PandaNode *node = data.node();
-  if (!node->is_geom_node()) {
-    pgraph_cat.error()
-      << "DecalEffect applied to " << *node << ", not a GeomNode.\n";
-    return;
-  }
-
-  const PandaNodePipelineReader *node_reader = data.node_reader();
-
-  // Build a chain of CullableObjects.  The head of the chain will be
-  // all of the base Geoms in order, followed by an empty
-  // CullableObject node, followed by all of the decal Geoms, in
-  // order.
-
-  // Since the CullableObject is a linked list which gets built in
-  // LIFO order, we start with the decals.
-  CullableObject *decals = (CullableObject *)NULL;
-  PandaNode::Children cr = node_reader->get_children();
-  int num_children = cr.get_num_children();
-  if (node->has_selective_visibility()) {
-    int i = node->get_first_visible_child();
-    while (i < num_children) {
-      CullTraverserData next_data(data, cr.get_child(i));
-      decals = r_get_decals(next_data, decals);
-      i = node->get_next_visible_child(i);
-    }
-    
-  } else {
-    for (int i = num_children - 1; i >= 0; i--) {
-      CullTraverserData next_data(data, cr.get_child(i));
-      decals = r_get_decals(next_data, decals);
-    }
-  }
-
-  // Now create a new, empty CullableObject to separate the decals
-  // from the non-decals.
-  CullableObject *separator = new CullableObject;
-  separator->set_next(decals);
-
-  // And now get the base Geoms, again in reverse order.
-  CullableObject *object = separator;
-  GeomNode *geom_node = DCAST(GeomNode, node);
-  GeomNode::Geoms geoms = geom_node->get_geoms();
-  int num_geoms = geoms.get_num_geoms();
-  _geoms_pcollector.add_level(num_geoms);
-  CPT(TransformState) net_transform = data.get_net_transform(this);
-  CPT(TransformState) modelview_transform = data.get_modelview_transform(this);
-  CPT(TransformState) internal_transform = _scene_setup->get_cs_transform()->compose(modelview_transform);
-  
-  for (int i = num_geoms - 1; i >= 0; i--) {
-    const Geom *geom = geoms.get_geom(i);
-    if (geom->is_empty()) {
-      continue;
-    }
-
-    CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i));
-    if (state->has_cull_callback() && !state->cull_callback(this, data)) {
-      // Cull.
-      continue;
-    }
-    
-    // Cull the Geom bounding volume against the view frustum
-    // and/or the cull planes.  Don't bother unless we've got more
-    // than one Geom, since otherwise the bounding volume of the
-    // GeomNode is (probably) the same as that of the one Geom,
-    // and we've already culled against that.
-    if (num_geoms > 1) {
-      if (data._view_frustum != (GeometricBoundingVolume *)NULL) {
-        // Cull the individual Geom against the view frustum.
-        CPT(BoundingVolume) geom_volume = geom->get_bounds();
-        const GeometricBoundingVolume *geom_gbv =
-          DCAST(GeometricBoundingVolume, geom_volume);
-        
-        int result = data._view_frustum->contains(geom_gbv);
-        if (result == BoundingVolume::IF_no_intersection) {
-          // Cull this Geom.
-          continue;
-        }
-      }
-      if (!data._cull_planes->is_empty()) {
-        // Also cull the Geom against the cull planes.
-        CPT(BoundingVolume) geom_volume = geom->get_bounds();
-        const GeometricBoundingVolume *geom_gbv =
-          DCAST(GeometricBoundingVolume, geom_volume);
-        int result;
-        data._cull_planes->do_cull(result, state, geom_gbv);
-        if (result == BoundingVolume::IF_no_intersection) {
-          // Cull.
-          continue;
-        }
-      }
-    }
-
-    CullableObject *next = object;
-    object =
-      new CullableObject(geom, state, net_transform, 
-                         modelview_transform, internal_transform);
-    object->set_next(next);
-  }
-
-  if (object != separator) {
-    // Finally, send the whole list down to the CullHandler for
-    // processing.  The first Geom in the node now represents the
-    // overall state.
-    _cull_handler->record_object(object, this);
-  } else {
-    // Never mind; there's nothing to render.
-    delete object;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CullTraverser::r_get_decals
-//       Access: Private
-//  Description: Recursively gets all the decals applied to a
-//               particular GeomNode.  These are built into a
-//               CullableObject list in LIFO order (so that the
-//               traversing the list will extract them in the order
-//               they were encountered in the scene graph).
-////////////////////////////////////////////////////////////////////
-CullableObject *CullTraverser::
-r_get_decals(CullTraverserData &data, CullableObject *decals) {
-  if (is_in_view(data)) {
-    PandaNodePipelineReader *node_reader = data.node_reader();
-    PandaNode *node = data.node();
-
-    const RenderEffects *node_effects = node_reader->get_effects();
-    if (node_effects->has_show_bounds()) {
-      // If we should show the bounding volume for this node, make it
-      // up now.
-      show_bounds(data, node_effects->has_show_tight_bounds());
-    }
-
-    data.apply_transform_and_state(this);
-
-    // First, visit all of the node's children.
-    int num_children = node_reader->get_num_children();
-    if (node->has_selective_visibility()) {
-      int i = node->get_first_visible_child();
-      while (i < num_children) {
-        CullTraverserData next_data(data, node_reader->get_child(i));
-        decals = r_get_decals(next_data, decals);
-        i = node->get_next_visible_child(i);
-      }
-      
-    } else {
-      for (int i = num_children - 1; i >= 0; i--) {
-        CullTraverserData next_data(data, node_reader->get_child(i));
-        decals = r_get_decals(next_data, decals);
-      }
-    }
-
-    // Now, tack on any geoms within the node.
-    if (node->is_geom_node()) {
-      GeomNode *geom_node = DCAST(GeomNode, node);
-      GeomNode::Geoms geoms = geom_node->get_geoms();
-      int num_geoms = geoms.get_num_geoms();
-      _geoms_pcollector.add_level(num_geoms);
-      CPT(TransformState) net_transform = data.get_net_transform(this);
-      CPT(TransformState) modelview_transform = data.get_modelview_transform(this);
-      CPT(TransformState) internal_transform = _scene_setup->get_cs_transform()->compose(modelview_transform);
-
-      for (int i = num_geoms - 1; i >= 0; i--) {
-        const Geom *geom = geoms.get_geom(i);
-        if (geom->is_empty()) {
-          continue;
-        }
-
-        CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i));
-        if (state->has_cull_callback() && !state->cull_callback(this, data)) {
-          // Cull.
-          continue;
-        }
-
-        // Cull the Geom bounding volume against the view frustum
-        // and/or the cull planes.  Don't bother unless we've got more
-        // than one Geom, since otherwise the bounding volume of the
-        // GeomNode is (probably) the same as that of the one Geom,
-        // and we've already culled against that.
-        if (num_geoms > 1) {
-          if (data._view_frustum != (GeometricBoundingVolume *)NULL) {
-            // Cull the individual Geom against the view frustum.
-            CPT(BoundingVolume) geom_volume = geom->get_bounds();
-            const GeometricBoundingVolume *geom_gbv =
-              DCAST(GeometricBoundingVolume, geom_volume);
-
-            int result = data._view_frustum->contains(geom_gbv);
-            if (result == BoundingVolume::IF_no_intersection) {
-              // Cull this Geom.
-              continue;
-            }
-          }
-          if (!data._cull_planes->is_empty()) {
-            // Also cull the Geom against the cull planes.
-            CPT(BoundingVolume) geom_volume = geom->get_bounds();
-            const GeometricBoundingVolume *geom_gbv =
-              DCAST(GeometricBoundingVolume, geom_volume);
-            int result;
-            data._cull_planes->do_cull(result, state, geom_gbv);
-            if (result == BoundingVolume::IF_no_intersection) {
-              // Cull.
-              continue;
-            }
-          }
-        }
-
-        CullableObject *next = decals;
-        decals =
-          new CullableObject(geom, state, net_transform, 
-                             modelview_transform, internal_transform);
-        decals->set_next(next);
-      }
-    }
-  }
-
-  return decals;
-}

+ 4 - 5
panda/src/pgraph/cullTraverser.h

@@ -87,7 +87,7 @@ PUBLISHED:
 
   INLINE static void flush_level();
 
-  void draw_bounding_volume(const BoundingVolume *vol, 
+  void draw_bounding_volume(const BoundingVolume *vol,
                             const TransformState *net_transform,
                             const TransformState *modelview_transform) const;
 
@@ -105,7 +105,7 @@ private:
   void show_bounds(CullTraverserData &data, bool tight);
   static PT(Geom) make_bounds_viz(const BoundingVolume *vol);
   PT(Geom) make_tight_bounds_viz(PandaNode *node) const;
-  static LVertex compute_point(const BoundingSphere *sphere, 
+  static LVertex compute_point(const BoundingSphere *sphere,
                                PN_stdfloat latitude, PN_stdfloat longitude);
   static CPT(RenderState) get_bounds_outer_viz_state();
   static CPT(RenderState) get_bounds_inner_viz_state();
@@ -121,12 +121,11 @@ private:
   bool _has_tag_state_key;
   string _tag_state_key;
   CPT(RenderState) _initial_state;
-  bool _depth_offset_decals;
   PT(GeometricBoundingVolume) _view_frustum;
   CullHandler *_cull_handler;
   PortalClipper *_portal_clipper;
   bool _effective_incomplete_render;
-  
+
 public:
   static TypeHandle get_class_type() {
     return _type_handle;
@@ -150,4 +149,4 @@ private:
 #endif
 
 
-  
+

+ 22 - 96
panda/src/pgraph/cullableObject.I

@@ -12,6 +12,7 @@
 //
 ////////////////////////////////////////////////////////////////////
 
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CullableObject::Constructor
 //       Access: Public
@@ -19,9 +20,7 @@
 //               filled in later.
 ////////////////////////////////////////////////////////////////////
 INLINE CullableObject::
-CullableObject() :
-  _fancy(false)
-{
+CullableObject() {
 #ifdef DO_MEMORY_USAGE
   MemoryUsage::update_type(this, get_class_type());
 #endif
@@ -42,8 +41,7 @@ CullableObject(const Geom *geom, const RenderState *state,
   _state(state),
   _net_transform(net_transform),
   _modelview_transform(modelview_transform),
-  _internal_transform(scene_setup->get_cs_transform()->compose(modelview_transform)),
-  _fancy(false)
+  _internal_transform(scene_setup->get_cs_transform()->compose(modelview_transform))
 {
 #ifdef DO_MEMORY_USAGE
   MemoryUsage::update_type(this, get_class_type());
@@ -65,20 +63,17 @@ CullableObject(const Geom *geom, const RenderState *state,
   _state(state),
   _net_transform(net_transform),
   _modelview_transform(modelview_transform),
-  _internal_transform(internal_transform),
-  _fancy(false)
+  _internal_transform(internal_transform)
 {
 #ifdef DO_MEMORY_USAGE
   MemoryUsage::update_type(this, get_class_type());
 #endif
 }
-  
 
 ////////////////////////////////////////////////////////////////////
 //     Function: CullableObject::Copy Constructor
 //       Access: Public
-//  Description: Copies the CullableObject, but does not copy its
-//               children (decals).
+//  Description: Copies the CullableObject.
 ////////////////////////////////////////////////////////////////////
 INLINE CullableObject::
 CullableObject(const CullableObject &copy) :
@@ -88,8 +83,7 @@ CullableObject(const CullableObject &copy) :
   _state(copy._state),
   _net_transform(copy._net_transform),
   _modelview_transform(copy._modelview_transform),
-  _internal_transform(copy._internal_transform),
-  _fancy(false)
+  _internal_transform(copy._internal_transform)
 {
 #ifdef DO_MEMORY_USAGE
   MemoryUsage::update_type(this, get_class_type());
@@ -99,12 +93,10 @@ CullableObject(const CullableObject &copy) :
 ////////////////////////////////////////////////////////////////////
 //     Function: CullableObject::Copy Assignment Operator
 //       Access: Public
-//  Description: Copies the CullableObject, but does not copy its
-//               children (decals).
+//  Description: Copies the CullableObject.
 ////////////////////////////////////////////////////////////////////
 INLINE void CullableObject::
 operator = (const CullableObject &copy) {
-  nassertv(!_fancy);
   _geom = copy._geom;
   _munger = copy._munger;
   _munged_data = copy._munged_data;
@@ -112,29 +104,7 @@ operator = (const CullableObject &copy) {
   _net_transform = copy._net_transform;
   _modelview_transform = copy._modelview_transform;
   _internal_transform = copy._internal_transform;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CullableObject::is_fancy
-//       Access: Public
-//  Description: Returns true if the object has something fancy to it:
-//               decals, maybe, or a draw_callback, that prevents it
-//               from being rendered inline.
-////////////////////////////////////////////////////////////////////
-INLINE bool CullableObject::
-is_fancy() const {
-  return _fancy;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CullableObject::has_decals
-//       Access: Public
-//  Description: Returns true if the object has decals associated with
-//               it.
-////////////////////////////////////////////////////////////////////
-INLINE bool CullableObject::
-has_decals() const {
-  return _fancy && (_next != (CullableObject *)NULL);
+  _draw_callback = copy._draw_callback;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -146,8 +116,17 @@ has_decals() const {
 ////////////////////////////////////////////////////////////////////
 INLINE void CullableObject::
 draw(GraphicsStateGuardianBase *gsg, bool force, Thread *current_thread) {
-  if (_fancy) {
-    draw_fancy(gsg, force, current_thread);
+  if (_draw_callback != (CallbackObject *)NULL) {
+    // It has a callback associated.
+    gsg->clear_before_callback();
+    gsg->set_state_and_transform(_state, _internal_transform);
+    GeomDrawCallbackData cbdata(this, gsg, force);
+    _draw_callback->do_callback(&cbdata);
+    if (cbdata.get_lost_state()) {
+      // Tell the GSG to forget its state.
+      gsg->clear_state_and_transform();
+    }
+    // Now the callback has taken care of drawing.
   } else {
     nassertv(_geom != (Geom *)NULL);
     gsg->set_state_and_transform(_state, _internal_transform);
@@ -184,43 +163,7 @@ request_resident() const {
 ////////////////////////////////////////////////////////////////////
 INLINE void CullableObject::
 set_draw_callback(CallbackObject *draw_callback) {
-  make_fancy();
-  if (draw_callback != _draw_callback) {
-    if (_draw_callback != (CallbackObject *)NULL) {
-      unref_delete(_draw_callback);
-    }
-    _draw_callback = draw_callback;
-    if (_draw_callback != (CallbackObject *)NULL) {
-      _draw_callback->ref();
-    }
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CullableObject::set_next
-//       Access: Public
-//  Description: Sets the next object in the decal chain.  This next
-//               object will be destructed when this object destructs.
-////////////////////////////////////////////////////////////////////
-INLINE void CullableObject::
-set_next(CullableObject *next) {
-  make_fancy();
-  nassertv(_next == (CullableObject *)NULL);
-  _next = next;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CullableObject::get_next
-//       Access: Public
-//  Description: Returns the next object in the decal chain, or NULL
-//               for the end of the chain.
-////////////////////////////////////////////////////////////////////
-INLINE CullableObject *CullableObject::
-get_next() const {
-  if (_fancy) {
-    return _next;
-  }
-  return NULL;
+  _draw_callback = draw_callback;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -233,23 +176,6 @@ flush_level() {
   _sw_sprites_pcollector.flush_level();
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: CullableObject::make_fancy
-//       Access: Private
-//  Description: Elevates this object to "fancy" status.  This means
-//               that the additional pointers, like _next and
-//               _draw_callback, have meaningful values and should be
-//               examined.
-////////////////////////////////////////////////////////////////////
-INLINE void CullableObject::
-make_fancy() {
-  if (!_fancy) {
-    _fancy = true;
-    _draw_callback = NULL;
-    _next = NULL;
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: CullableObject::draw_inline
 //       Access: Private
@@ -266,7 +192,7 @@ draw_inline(GraphicsStateGuardianBase *gsg, bool force, Thread *current_thread)
 ////////////////////////////////////////////////////////////////////
 //     Function: CullableObject::SortPoints::Constructor
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE CullableObject::SortPoints::
 SortPoints(const CullableObject::PointData *array) :
@@ -288,7 +214,7 @@ operator () (unsigned short a, unsigned short b) const {
 ////////////////////////////////////////////////////////////////////
 //     Function: CullableObject::SourceFormat::operator <
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE bool CullableObject::SourceFormat::
 operator < (const CullableObject::SourceFormat &other) const {

+ 4 - 116
panda/src/pgraph/cullableObject.cxx

@@ -30,7 +30,6 @@
 #include "geomTriangles.h"
 #include "light.h"
 #include "lightMutexHolder.h"
-#include "geomDrawCallbackData.h"
 
 CullableObject::FormatMap CullableObject::_format_map;
 LightMutex CullableObject::_format_lock;
@@ -180,41 +179,13 @@ munge_geom(GraphicsStateGuardianBase *gsg,
 #endif
   }
 
-  if (_fancy) {
-    // Only check the _next pointer if the _fancy flag is set.
-    if (_next != (CullableObject *)NULL) {
-      if (_next->_state != (RenderState *)NULL) {
-        _next->munge_geom(gsg, gsg->get_geom_munger(_next->_state, current_thread),
-                          traverser, force);
-      } else {
-        _next->munge_geom(gsg, munger, traverser, force);
-      }
-    }
-  }
-
   return true;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: CullableObject::Destructor
-//       Access: Public
-//  Description: Automatically deletes the whole chain of these things.
-////////////////////////////////////////////////////////////////////
-CullableObject::
-~CullableObject() {
-  if (_fancy) {
-    // Only check the _next pointer if the _fancy flag is set.
-    if (_next != (CullableObject *)NULL) {
-      delete _next;
-    }
-    set_draw_callback(NULL);
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: CullableObject::output
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 void CullableObject::
 output(ostream &out) const {
@@ -225,7 +196,6 @@ output(ostream &out) const {
   }
 }
 
-
 ////////////////////////////////////////////////////////////////////
 //     Function: CullableObject::munge_points_to_quads
 //       Access: Private
@@ -642,7 +612,7 @@ munge_texcoord_light_vector(const CullTraverser *traverser, bool force) {
     return true;
   }
 
-  if (!_munged_data->has_column(InternalName::get_vertex()) || 
+  if (!_munged_data->has_column(InternalName::get_vertex()) ||
       !_munged_data->has_column(InternalName::get_normal())) {
     // No vertex or normal; can't compute light vector.
     return true;
@@ -775,97 +745,15 @@ get_flash_hardware_state() {
   return flash_hardware_state;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: CullableObject::draw_fancy
-//       Access: Private
-//  Description: Something fancy about this object.  Draw it properly.
-////////////////////////////////////////////////////////////////////
-void CullableObject::
-draw_fancy(GraphicsStateGuardianBase *gsg, bool force, 
-           Thread *current_thread) {
-  nassertv(_fancy);
-  if (_draw_callback != (CallbackObject *)NULL) {
-    // It has a callback associated.
-    gsg->clear_before_callback();
-    gsg->set_state_and_transform(_state, _internal_transform);
-    GeomDrawCallbackData cbdata(this, gsg, force);
-    _draw_callback->do_callback(&cbdata);
-    if (cbdata.get_lost_state()) {
-      // Tell the GSG to forget its state.
-      gsg->clear_state_and_transform();
-    }
-    // Now the callback has taken care of drawing.
-
-  } else if (_next != (CullableObject *)NULL) {
-    // It has decals.
-    draw_with_decals(gsg, force, current_thread);
-
-  } else {
-    // Huh, nothing fancy after all.  Somehow the _fancy flag got set
-    // incorrectly; that's a bug.
-    gsg->set_state_and_transform(_state, _internal_transform);
-    draw_inline(gsg, force, current_thread);
-    nassertv(false);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CullableObject::draw_with_decals
-//       Access: Private
-//  Description: Draws the current CullableObject, assuming it has
-//               attached decals.
-////////////////////////////////////////////////////////////////////
-void CullableObject::
-draw_with_decals(GraphicsStateGuardianBase *gsg, bool force, 
-                 Thread *current_thread) {
-  nassertv(_fancy && _next != (CullableObject *)NULL);  
-  // We draw with a three-step process.
-
-  // First, render all of the base geometry for the first pass.
-  CPT(RenderState) state = gsg->begin_decal_base_first();
-
-  CullableObject *base = this;
-  while (base != (CullableObject *)NULL && base->_geom != (Geom *)NULL) {
-    gsg->set_state_and_transform(base->_state->compose(state), base->_internal_transform);
-    base->draw_inline(gsg, force, current_thread);
-    
-    base = base->_next;
-  }
-
-  if (base != (CullableObject *)NULL) {
-    // Now, draw all the decals.
-    state = gsg->begin_decal_nested();
-
-    CullableObject *decal = base->_next;
-    while (decal != (CullableObject *)NULL) {
-      gsg->set_state_and_transform(decal->_state->compose(state), decal->_internal_transform);
-      decal->draw_inline(gsg, force, current_thread);
-      decal = decal->_next;
-    }
-  }
-
-  // And now, re-draw the base geometry, if required.
-  state = gsg->begin_decal_base_second();
-  if (state != (const RenderState *)NULL) {
-    base = this;
-    while (base != (CullableObject *)NULL && base->_geom != (Geom *)NULL) {
-      gsg->set_state_and_transform(base->_state->compose(state), base->_internal_transform);
-      base->draw_inline(gsg, force, current_thread);
-      
-      base = base->_next;
-    }
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: CullableObject::SourceFormat::Constructor
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 CullableObject::SourceFormat::
 SourceFormat(const GeomVertexFormat *format, bool sprite_texcoord) :
   _format(format),
-  _sprite_texcoord(sprite_texcoord) 
+  _sprite_texcoord(sprite_texcoord)
 {
   _retransform_sprites = retransform_sprites;
 }

+ 6 - 24
panda/src/pgraph/cullableObject.h

@@ -32,17 +32,17 @@
 #include "sceneSetup.h"
 #include "lightMutex.h"
 #include "callbackObject.h"
+#include "geomDrawCallbackData.h"
 
 class CullTraverser;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : CullableObject
 // Description : The smallest atom of cull.  This is normally just a
-//               Geom and its associated state, but it also represent
-//               a number of Geoms to be drawn together, with a number
-//               of Geoms decalled onto them.
+//               Geom and its associated state, but it also contain
+//               a draw callback.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA_PGRAPH CullableObject 
+class EXPCL_PANDA_PGRAPH CullableObject
 #ifdef DO_MEMORY_USAGE
   : public ReferenceCount   // We inherit from ReferenceCount just to get the memory type tracking that MemoryUsage provides.
 #endif  // DO_MEMORY_USAGE
@@ -57,13 +57,10 @@ public:
                         const TransformState *net_transform,
                         const TransformState *modelview_transform,
                         const TransformState *internal_transform);
-    
+
   INLINE CullableObject(const CullableObject &copy);
   INLINE void operator = (const CullableObject &copy);
 
-  INLINE bool is_fancy() const;
-  INLINE bool has_decals() const;
-
   bool munge_geom(GraphicsStateGuardianBase *gsg,
                   GeomMunger *munger, const CullTraverser *traverser,
                   bool force);
@@ -74,11 +71,8 @@ public:
   INLINE static void flush_level();
 
   INLINE void set_draw_callback(CallbackObject *draw_callback);
-  INLINE void set_next(CullableObject *next);
-  INLINE CullableObject *get_next() const;
 
 public:
-  ~CullableObject();
   ALLOC_DELETED_CHAIN(CullableObject);
 
   void output(ostream &out) const;
@@ -91,17 +85,9 @@ public:
   CPT(TransformState) _net_transform;
   CPT(TransformState) _modelview_transform;
   CPT(TransformState) _internal_transform;
+  PT(CallbackObject) _draw_callback;
 
 private:
-  bool _fancy;
-
-  // Fancy things below.  These pointers are only meaningful if
-  // _fancy, above, is true.
-  CallbackObject *_draw_callback;
-  CullableObject *_next;  // for decals
-
-private:
-  INLINE void make_fancy();
   bool munge_points_to_quads(const CullTraverser *traverser, bool force);
   bool munge_texcoord_light_vector(const CullTraverser *traverser, bool force);
 
@@ -110,10 +96,6 @@ private:
 
   INLINE void draw_inline(GraphicsStateGuardianBase *gsg,
                           bool force, Thread *current_thread);
-  void draw_fancy(GraphicsStateGuardianBase *gsg, bool force, 
-                  Thread *current_thread);
-  void draw_with_decals(GraphicsStateGuardianBase *gsg, bool force, 
-                        Thread *current_thread);
 
 private:
   // This class is used internally by munge_points_to_quads().