Browse Source

Add M_filled_wireframe render mode

rdb 11 years ago
parent
commit
78f8f65ef9

+ 9 - 32
panda/src/framework/pandaFramework.cxx

@@ -140,12 +140,6 @@ open_framework(int &argc, char **&argv) {
     _task_mgr.add(task);
     _task_mgr.add(task);
   }
   }
 
 
-  _highlight_wireframe = NodePath("wireframe");
-  _highlight_wireframe.set_render_mode_wireframe(1);
-  _highlight_wireframe.set_texture_off(1);
-  _highlight_wireframe.set_color(1.0f, 0.0f, 0.0f, 1.0f, 1);
-  _highlight_wireframe.set_attrib(DepthOffsetAttrib::make());
-
   if (!playback_session.empty()) {
   if (!playback_session.empty()) {
     // If the config file so indicates, create a recorder and start it
     // If the config file so indicates, create a recorder and start it
     // playing.
     // playing.
@@ -784,13 +778,7 @@ set_highlight(const NodePath &node) {
   if (!_highlight.is_empty()) {
   if (!_highlight.is_empty()) {
     framework_cat.info(false) << _highlight << "\n";
     framework_cat.info(false) << _highlight << "\n";
     _highlight.show_bounds();
     _highlight.show_bounds();
-
-    // Also create a new instance of the highlighted geometry, as a
-    // sibling of itself, under the special highlight property.
-    if (_highlight.has_parent()) {
-      _highlight_wireframe.reparent_to(_highlight.get_parent());
-      _highlight.instance_to(_highlight_wireframe);
-    }
+    _highlight.set_render_mode_filled_wireframe(LColor(1.0f, 0.0f, 0.0f, 1.0f), 200);
   }
   }
 }
 }
 
 
@@ -803,11 +791,8 @@ void PandaFramework::
 clear_highlight() {
 clear_highlight() {
   if (!_highlight.is_empty()) {
   if (!_highlight.is_empty()) {
     _highlight.hide_bounds();
     _highlight.hide_bounds();
+    _highlight.clear_render_mode();
     _highlight = NodePath();
     _highlight = NodePath();
-
-    // Clean up the special highlight instance.
-    _highlight_wireframe.detach_node();
-    _highlight_wireframe.get_children().detach();
   }
   }
 }
 }
 
 
@@ -1012,7 +997,13 @@ event_w(const Event *event, void *) {
     WindowFramework *wf;
     WindowFramework *wf;
     DCAST_INTO_V(wf, param.get_ptr());
     DCAST_INTO_V(wf, param.get_ptr());
 
 
-    wf->set_wireframe(!wf->get_wireframe());
+    if (!wf->get_wireframe()) {
+      wf->set_wireframe(true, true);
+    } else if (wf->get_wireframe_filled()) {
+      wf->set_wireframe(true, false);
+    } else {
+      wf->set_wireframe(false, false);
+    }
   }
   }
 }
 }
 
 
@@ -1286,13 +1277,6 @@ event_arrow_left(const Event *, void *data) {
       int index = parent.node()->find_child(node.node());
       int index = parent.node()->find_child(node.node());
       nassertv(index >= 0);
       nassertv(index >= 0);
       int sibling = index - 1;
       int sibling = index - 1;
-
-      if (sibling >= 0 &&
-          parent.node()->get_child(sibling) == self->_highlight_wireframe.node()) {
-        // Skip over the special highlight node.
-        sibling--;
-      }
-
       if (sibling >= 0) {
       if (sibling >= 0) {
         self->set_highlight(NodePath(parent, parent.node()->get_child(sibling)));
         self->set_highlight(NodePath(parent, parent.node()->get_child(sibling)));
       }
       }
@@ -1319,13 +1303,6 @@ event_arrow_right(const Event *, void *data) {
       nassertv(index >= 0);
       nassertv(index >= 0);
       int num_children = parent.node()->get_num_children();
       int num_children = parent.node()->get_num_children();
       int sibling = index + 1;
       int sibling = index + 1;
-
-      if (sibling < num_children &&
-          parent.node()->get_child(sibling) == self->_highlight_wireframe.node()) {
-        // Skip over the special highlight node.
-        sibling++;
-      }
-
       if (sibling < num_children) {
       if (sibling < num_children) {
         self->set_highlight(NodePath(parent, parent.node()->get_child(sibling)));
         self->set_highlight(NodePath(parent, parent.node()->get_child(sibling)));
       }
       }

+ 12 - 1
panda/src/framework/windowFramework.I

@@ -33,7 +33,7 @@ get_panda_framework() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GraphicsWindow *WindowFramework::
 INLINE GraphicsWindow *WindowFramework::
 get_graphics_window() const {
 get_graphics_window() const {
-  if (_window != (GraphicsOutput *)NULL && 
+  if (_window != (GraphicsOutput *)NULL &&
       _window->is_of_type(GraphicsWindow::get_class_type())) {
       _window->is_of_type(GraphicsWindow::get_class_type())) {
     return DCAST(GraphicsWindow, _window);
     return DCAST(GraphicsWindow, _window);
   }
   }
@@ -117,6 +117,17 @@ get_wireframe() const {
   return _wireframe_enabled;
   return _wireframe_enabled;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: WindowFramework::get_wireframe_filled
+//       Access: Public
+//  Description: Returns the current state of the wireframe_filled
+//               flag.
+////////////////////////////////////////////////////////////////////
+INLINE bool WindowFramework::
+get_wireframe_filled() const {
+  return _wireframe_filled;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: WindowFramework::get_texture
 //     Function: WindowFramework::get_texture
 //       Access: Public
 //       Access: Public

+ 29 - 14
panda/src/framework/windowFramework.cxx

@@ -87,6 +87,7 @@ WindowFramework(PandaFramework *panda_framework) :
   _anim_controls_enabled = false;
   _anim_controls_enabled = false;
   _anim_index = 0;
   _anim_index = 0;
   _wireframe_enabled = false;
   _wireframe_enabled = false;
+  _wireframe_filled = false;
   _texture_enabled = true;
   _texture_enabled = true;
   _two_sided_enabled = false;
   _two_sided_enabled = false;
   _one_sided_reverse_enabled = false;
   _one_sided_reverse_enabled = false;
@@ -362,7 +363,7 @@ get_pixel_2d() {
     PGTop *top = new PGTop("pixel_2d");
     PGTop *top = new PGTop("pixel_2d");
     _pixel_2d = get_render_2d().attach_new_node(top);
     _pixel_2d = get_render_2d().attach_new_node(top);
     _pixel_2d.set_pos(-1, 0, 1);
     _pixel_2d.set_pos(-1, 0, 1);
-  
+
     if (_window->has_size()) {
     if (_window->has_size()) {
       int x_size = _window->get_sbs_left_x_size();
       int x_size = _window->get_sbs_left_x_size();
       int y_size = _window->get_sbs_left_y_size();
       int y_size = _window->get_sbs_left_y_size();
@@ -653,7 +654,7 @@ load_model(const NodePath &parent, Filename filename) {
         // A texture object.  Not exactly an image, but certainly a
         // A texture object.  Not exactly an image, but certainly a
         // texture.
         // texture.
         is_image = true;
         is_image = true;
-        
+
       } else {
       } else {
         TexturePool *texture_pool = TexturePool::get_global_ptr();
         TexturePool *texture_pool = TexturePool::get_global_ptr();
         if (texture_pool->get_texture_type(extension) != NULL) {
         if (texture_pool->get_texture_type(extension) != NULL) {
@@ -845,7 +846,7 @@ adjust_dimensions() {
     x_size = _window->get_sbs_left_x_size();
     x_size = _window->get_sbs_left_x_size();
     y_size = _window->get_sbs_left_y_size();
     y_size = _window->get_sbs_left_y_size();
   }
   }
-  
+
   if (this_aspect_ratio == 0.0f) {
   if (this_aspect_ratio == 0.0f) {
     // An aspect ratio of 0.0 means to try to infer it.
     // An aspect ratio of 0.0 means to try to infer it.
     this_aspect_ratio = 1.0f;
     this_aspect_ratio = 1.0f;
@@ -942,28 +943,42 @@ split_window(SplitType split_type) {
 //               rendering (false).
 //               rendering (false).
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void WindowFramework::
 void WindowFramework::
-set_wireframe(bool enable) {
-  if (enable == _wireframe_enabled) {
+set_wireframe(bool enable, bool filled) {
+  if (enable == _wireframe_enabled && filled == _wireframe_filled) {
     return;
     return;
   }
   }
 
 
   NodePath render = get_render();
   NodePath render = get_render();
 
 
+  if (!_two_sided_enabled) {
+    render.clear_two_sided();
+  }
+
   if (enable) {
   if (enable) {
-    render.set_render_mode_wireframe(override_priority);
-    render.set_two_sided(true, override_priority);
+    if (filled) {
+      render.set_attrib(RenderModeAttrib::make(
+        RenderModeAttrib::M_filled_wireframe,
+        1.4f, false, LColor(1, 1, 1, .5f)),
+        override_priority);
+      // Darken the scene so that the wireframe is clearly visible,
+      // even when the scene is completely white.
+      render.set_color_scale(LColor(0.7f, 0.7f, 0.7f, 1), override_priority);
+    } else {
+      render.set_render_mode_wireframe(override_priority);
+      render.set_two_sided(true, override_priority);
+      render.clear_color_scale();
+    }
   } else {
   } else {
     render.clear_render_mode();
     render.clear_render_mode();
-    if (!_two_sided_enabled) {
-      render.clear_two_sided();
-    }
     if (_one_sided_reverse_enabled) {
     if (_one_sided_reverse_enabled) {
       CPT(RenderAttrib) attrib = CullFaceAttrib::make_reverse();
       CPT(RenderAttrib) attrib = CullFaceAttrib::make_reverse();
       render.node()->set_attrib(attrib);
       render.node()->set_attrib(attrib);
     }
     }
+    render.clear_color_scale();
   }
   }
 
 
   _wireframe_enabled = enable;
   _wireframe_enabled = enable;
+  _wireframe_filled = filled;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -1285,7 +1300,7 @@ load_image_as_model(const Filename &filename) {
   } else {
   } else {
     framework_cat.warning()
     framework_cat.warning()
       << "Texture size is 0 0: " << *tex << "\n";
       << "Texture size is 0 0: " << *tex << "\n";
-    
+
     left   = -scale;
     left   = -scale;
     right  =  scale;
     right  =  scale;
     top    =  scale;
     top    =  scale;
@@ -1314,9 +1329,9 @@ load_image_as_model(const Filename &filename) {
     // Vertices and 3-d texture coordinates.
     // Vertices and 3-d texture coordinates.
     vformat = GeomVertexFormat::register_format
     vformat = GeomVertexFormat::register_format
       (new GeomVertexArrayFormat
       (new GeomVertexArrayFormat
-       (InternalName::get_vertex(), 3, 
+       (InternalName::get_vertex(), 3,
         GeomEnums::NT_stdfloat, GeomEnums::C_point,
         GeomEnums::NT_stdfloat, GeomEnums::C_point,
-        InternalName::get_texcoord(), 3, 
+        InternalName::get_texcoord(), 3,
         GeomEnums::NT_stdfloat, GeomEnums::C_texcoord));
         GeomEnums::NT_stdfloat, GeomEnums::C_texcoord));
   }
   }
 
 
@@ -1331,7 +1346,7 @@ load_image_as_model(const Filename &filename) {
     vertex.add_data3(LVertex::rfu(left, 0.02, bottom));
     vertex.add_data3(LVertex::rfu(left, 0.02, bottom));
     vertex.add_data3(LVertex::rfu(right, 0.02, top));
     vertex.add_data3(LVertex::rfu(right, 0.02, top));
     vertex.add_data3(LVertex::rfu(right, 0.02, bottom));
     vertex.add_data3(LVertex::rfu(right, 0.02, bottom));
-    
+
     texcoord.add_data2(0.0f, tex_scale[1]);
     texcoord.add_data2(0.0f, tex_scale[1]);
     texcoord.add_data2(0.0f, 0.0f);
     texcoord.add_data2(0.0f, 0.0f);
     texcoord.add_data2(tex_scale[0], tex_scale[1]);
     texcoord.add_data2(tex_scale[0], tex_scale[1]);

+ 7 - 5
panda/src/framework/windowFramework.h

@@ -97,7 +97,7 @@ public:
                    const pvector<Filename> &files);
                    const pvector<Filename> &files);
   NodePath load_model(const NodePath &parent, Filename filename);
   NodePath load_model(const NodePath &parent, Filename filename);
   NodePath load_default_model(const NodePath &parent);
   NodePath load_default_model(const NodePath &parent);
-  void loop_animations(int hierarchy_match_flags = 
+  void loop_animations(int hierarchy_match_flags =
                        PartGroup::HMF_ok_part_extra |
                        PartGroup::HMF_ok_part_extra |
                        PartGroup::HMF_ok_anim_extra);
                        PartGroup::HMF_ok_anim_extra);
   void stagger_animations();
   void stagger_animations();
@@ -122,7 +122,7 @@ public:
   };
   };
   WindowFramework *split_window(SplitType split_type = ST_default);
   WindowFramework *split_window(SplitType split_type = ST_default);
 
 
-  void set_wireframe(bool enable);
+  void set_wireframe(bool enable, bool filled=false);
   void set_texture(bool enable);
   void set_texture(bool enable);
   void set_two_sided(bool enable);
   void set_two_sided(bool enable);
   void set_one_sided_reverse(bool enable);
   void set_one_sided_reverse(bool enable);
@@ -131,6 +131,7 @@ public:
   void set_background_type(BackgroundType type);
   void set_background_type(BackgroundType type);
 
 
   INLINE bool get_wireframe() const;
   INLINE bool get_wireframe() const;
+  INLINE bool get_wireframe_filled() const;
   INLINE bool get_texture() const;
   INLINE bool get_texture() const;
   INLINE bool get_two_sided() const;
   INLINE bool get_two_sided() const;
   INLINE bool get_one_sided_reverse() const;
   INLINE bool get_one_sided_reverse() const;
@@ -150,7 +151,7 @@ private:
   void destroy_anim_controls();
   void destroy_anim_controls();
   void update_anim_controls();
   void update_anim_controls();
 
 
-  void setup_shuttle_button(const string &label, int index, 
+  void setup_shuttle_button(const string &label, int index,
                             EventHandler::EventCallbackFunction *func);
                             EventHandler::EventCallbackFunction *func);
   void back_button();
   void back_button();
   void pause_button();
   void pause_button();
@@ -194,12 +195,13 @@ private:
 
 
   NodePath _alight;
   NodePath _alight;
   NodePath _dlight;
   NodePath _dlight;
-  
+
   bool _got_keyboard;
   bool _got_keyboard;
   bool _got_trackball;
   bool _got_trackball;
   bool _got_lights;
   bool _got_lights;
 
 
   bool _wireframe_enabled;
   bool _wireframe_enabled;
+  bool _wireframe_filled;
   bool _texture_enabled;
   bool _texture_enabled;
   bool _two_sided_enabled;
   bool _two_sided_enabled;
   bool _one_sided_reverse_enabled;
   bool _one_sided_reverse_enabled;
@@ -210,7 +212,7 @@ private:
   PT(SceneGraphAnalyzerMeter) _scene_graph_analyzer_meter;
   PT(SceneGraphAnalyzerMeter) _scene_graph_analyzer_meter;
 
 
   BackgroundType _background_type;
   BackgroundType _background_type;
-  
+
   static PT(TextFont) _shuttle_controls_font;
   static PT(TextFont) _shuttle_controls_font;
 
 
 public:
 public:

+ 32 - 0
panda/src/pgraph/cullResult.I

@@ -39,3 +39,35 @@ get_bin(int bin_index) {
   }
   }
   return make_new_bin(bin_index);
   return make_new_bin(bin_index);
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullResult::check_flash_bin
+//       Access: Private
+//  Description: If the user configured flash-bin-binname, then update
+//               the object's state to flash all the geometry in the
+//               bin.
+////////////////////////////////////////////////////////////////////
+INLINE void CullResult::
+check_flash_bin(CPT(RenderState) &state, CullBinManager *bin_manager, int bin_index) {
+#ifndef NDEBUG
+  if (bin_manager->get_bin_flash_active(bin_index)) {
+    apply_flash_color(state, bin_manager->get_bin_flash_color(bin_index));
+  }
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullResult::check_flash_transparency
+//       Access: Private
+//  Description: If the user configured show-transparency, then
+//               update the object's state to flash the current
+//               geometry with the specified color.
+////////////////////////////////////////////////////////////////////
+INLINE void CullResult::
+check_flash_transparency(CPT(RenderState) &state, const LColor &color) {
+#ifndef NDEBUG
+  if (_show_transparency) {
+    apply_flash_color(state, color);
+  }
+#endif
+}

+ 60 - 54
panda/src/pgraph/cullResult.cxx

@@ -27,27 +27,28 @@
 #include "clockObject.h"
 #include "clockObject.h"
 #include "config_pgraph.h"
 #include "config_pgraph.h"
 #include "depthOffsetAttrib.h"
 #include "depthOffsetAttrib.h"
+#include "colorBlendAttrib.h"
 
 
 TypeHandle CullResult::_type_handle;
 TypeHandle CullResult::_type_handle;
 
 
 // This value is used instead of 1.0 to represent the alpha level of a
 // This value is used instead of 1.0 to represent the alpha level of a
 // pixel that is to be considered "opaque" for the purposes of M_dual.
 // pixel that is to be considered "opaque" for the purposes of M_dual.
-
+//
 // Ideally, 1.0 is the only correct value for this.  Realistically, we
 // Ideally, 1.0 is the only correct value for this.  Realistically, we
 // have to fudge it lower for two reasons:
 // have to fudge it lower for two reasons:
-
+//
 // (1) The modelers tend to paint textures with very slight
 // (1) The modelers tend to paint textures with very slight
 // transparency levels in places that are not intended to be
 // transparency levels in places that are not intended to be
 // transparent, without realizing it.  These very faint transparency
 // transparent, without realizing it.  These very faint transparency
 // regions are normally (almost) invisible, but when rendered with
 // regions are normally (almost) invisible, but when rendered with
 // M_dual they may be revealed as regions of poor alpha sorting.
 // M_dual they may be revealed as regions of poor alpha sorting.
-
+//
 // (2) There seems to be some problem in DX where, in certain
 // (2) There seems to be some problem in DX where, in certain
 // circumstances apparently related to automatic texture management,
 // circumstances apparently related to automatic texture management,
 // it spontaneously drops out the bottom two bits of an eight-bit
 // it spontaneously drops out the bottom two bits of an eight-bit
 // alpha channel, causing a value of 255 to become a value of 252
 // alpha channel, causing a value of 255 to become a value of 252
 // instead.
 // instead.
-
+//
 // We use 256 as the denominator here (instead of, say, 255) because a
 // We use 256 as the denominator here (instead of, say, 255) because a
 // fractional power of two will have a terminating representation in
 // fractional power of two will have a terminating representation in
 // base 2, and thus will be more likely to have a precise value in
 // base 2, and thus will be more likely to have a precise value in
@@ -69,6 +70,10 @@ CullResult(GraphicsStateGuardianBase *gsg,
 #ifdef DO_MEMORY_USAGE
 #ifdef DO_MEMORY_USAGE
   MemoryUsage::update_type(this, get_class_type());
   MemoryUsage::update_type(this, get_class_type());
 #endif
 #endif
+
+#ifndef NDEBUG
+  _show_transparency = show_transparency.get_value();
+#endif
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -130,17 +135,13 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
       // M_alpha implies an alpha-write test, so we don't waste time
       // M_alpha implies an alpha-write test, so we don't waste time
       // writing 0-valued pixels.
       // writing 0-valued pixels.
       object->_state = state->compose(get_alpha_state());
       object->_state = state->compose(get_alpha_state());
-#ifndef NDEBUG
       check_flash_transparency(object->_state, flash_alpha_color);
       check_flash_transparency(object->_state, flash_alpha_color);
-#endif
       break;
       break;
 
 
     case TransparencyAttrib::M_binary:
     case TransparencyAttrib::M_binary:
       // M_binary is implemented by explicitly setting the alpha test.
       // M_binary is implemented by explicitly setting the alpha test.
       object->_state = state->compose(get_binary_state());
       object->_state = state->compose(get_binary_state());
-#ifndef NDEBUG
       check_flash_transparency(object->_state, flash_binary_color);
       check_flash_transparency(object->_state, flash_binary_color);
-#endif
       break;
       break;
 
 
     case TransparencyAttrib::M_multisample:
     case TransparencyAttrib::M_multisample:
@@ -150,9 +151,7 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
       if (!_gsg->get_supports_multisample()) {
       if (!_gsg->get_supports_multisample()) {
         object->_state = state->compose(get_binary_state());
         object->_state = state->compose(get_binary_state());
       }
       }
-#ifndef NDEBUG
       check_flash_transparency(object->_state, flash_multisample_color);
       check_flash_transparency(object->_state, flash_multisample_color);
-#endif
       break;
       break;
 
 
     case TransparencyAttrib::M_dual:
     case TransparencyAttrib::M_dual:
@@ -192,12 +191,7 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
                 int transparent_bin_index = transparent_part->_state->get_bin_index();
                 int transparent_bin_index = transparent_part->_state->get_bin_index();
                 CullBin *bin = get_bin(transparent_bin_index);
                 CullBin *bin = get_bin(transparent_bin_index);
                 nassertv(bin != (CullBin *)NULL);
                 nassertv(bin != (CullBin *)NULL);
-#ifndef NDEBUG
-                if (bin_manager->get_bin_flash_active(transparent_bin_index)) {
-                  do_flash_bin(transparent_part->_state,
-                    bin_manager->get_bin_flash_color(transparent_bin_index));
-                }
-#endif
+                check_flash_bin(transparent_part->_state, bin_manager, transparent_bin_index);
                 bin->add_object(transparent_part, current_thread);
                 bin->add_object(transparent_part, current_thread);
               } else {
               } else {
                 delete transparent_part;
                 delete transparent_part;
@@ -225,16 +219,34 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
     }
     }
   }
   }
 
 
+  // Check for a special wireframe setting.
+  const RenderModeAttrib *rmode = (const RenderModeAttrib *)
+    object->_state->get_attrib(RenderModeAttrib::get_class_slot());
+  if (rmode != (const RenderModeAttrib *)NULL) {
+    if (rmode->get_mode() == RenderModeAttrib::M_filled_wireframe) {
+      CullableObject *wireframe_part = new CullableObject(*object);
+      wireframe_part->_state = get_wireframe_overlay_state(rmode);
+
+      if (wireframe_part->munge_geom
+          (_gsg, _gsg->get_geom_munger(wireframe_part->_state, current_thread),
+           traverser, force)) {
+        int wireframe_bin_index = bin_manager->find_bin("fixed");
+        CullBin *bin = get_bin(wireframe_bin_index);
+        nassertv(bin != (CullBin *)NULL);
+        check_flash_bin(wireframe_part->_state, bin_manager, wireframe_bin_index);
+        bin->add_object(wireframe_part, current_thread);
+      } else {
+        delete wireframe_part;
+      }
+
+      object->_state = object->_state->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled));
+    }
+  }
+
   int bin_index = object->_state->get_bin_index();
   int bin_index = object->_state->get_bin_index();
   CullBin *bin = get_bin(bin_index);
   CullBin *bin = get_bin(bin_index);
   nassertv(bin != (CullBin *)NULL);
   nassertv(bin != (CullBin *)NULL);
-
-#ifndef NDEBUG
-  if (bin_manager->get_bin_flash_active(bin_index)) {
-    do_flash_bin(object->_state,
-      bin_manager->get_bin_flash_color(bin_index));
-  }
-#endif
+  check_flash_bin(object->_state, bin_manager, bin_index);
 
 
   // Munge vertices as needed for the GSG's requirements, and the
   // Munge vertices as needed for the GSG's requirements, and the
   // object's current state.
   // object's current state.
@@ -410,16 +422,15 @@ get_binary_state() {
   return state;
   return state;
 }
 }
 
 
+#ifndef NDEBUG
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CullResult::do-flash_bin
+//     Function: CullResult::apply_flash_color
 //       Access: Private
 //       Access: Private
-//  Description: If the user configured flash-bin-binname, then update
-//               the object's state to flash all the geometry in the
-//               bin.
+//  Description: Update the object's state to flash the geometry
+//               with a solid color.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CullResult::
 void CullResult::
-do_flash_bin(CPT(RenderState) &state, const LColor &flash_color) {
-#ifndef NDEBUG
+apply_flash_color(CPT(RenderState) &state, const LColor &flash_color) {
   int cycle = (int)(ClockObject::get_global_clock()->get_frame_time() * bin_color_flash_rate);
   int cycle = (int)(ClockObject::get_global_clock()->get_frame_time() * bin_color_flash_rate);
   if ((cycle & 1) == 0) {
   if ((cycle & 1) == 0) {
     state = state->remove_attrib(TextureAttrib::get_class_slot());
     state = state->remove_attrib(TextureAttrib::get_class_slot());
@@ -429,32 +440,8 @@ do_flash_bin(CPT(RenderState) &state, const LColor &flash_color) {
     state = state->add_attrib(ColorAttrib::make_flat(flash_color),
     state = state->add_attrib(ColorAttrib::make_flat(flash_color),
                               RenderState::get_max_priority());
                               RenderState::get_max_priority());
   }
   }
-#endif  // NDEBUG
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CullResult::check_flash_transparency
-//       Access: Private
-//  Description: If the user configured show-transparency, then
-//               update the object's state to flash the current
-//               geometry with the specified color.
-////////////////////////////////////////////////////////////////////
-void CullResult::
-check_flash_transparency(CPT(RenderState) &state, const LColor &transparency) {
-#ifndef NDEBUG
-  if (show_transparency) {
-    int cycle = (int)(ClockObject::get_global_clock()->get_frame_time() * bin_color_flash_rate);
-    if ((cycle & 1) == 0) {
-      state = state->remove_attrib(TextureAttrib::get_class_slot());
-      state = state->remove_attrib(LightAttrib::get_class_slot());
-      state = state->remove_attrib(ColorScaleAttrib::get_class_slot());
-      state = state->remove_attrib(FogAttrib::get_class_slot());
-      state = state->add_attrib(ColorAttrib::make_flat(transparency),
-                                RenderState::get_max_priority());
-    }
-  }
-#endif
 }
 }
+#endif  // NDEBUG
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CullResult::get_dual_transparent_state
 //     Function: CullResult::get_dual_transparent_state
@@ -535,3 +522,22 @@ get_dual_opaque_state() {
   return state;
   return state;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: CullResult::get_wireframe_overlay_state
+//       Access: Private
+//  Description: Returns a RenderState that renders only the
+//               wireframe part of an M_filled_wireframe model.
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) CullResult::
+get_wireframe_overlay_state(const RenderModeAttrib *rmode) {
+  return RenderState::make(
+    DepthOffsetAttrib::make(1, 0, 0.99999f),
+    ColorAttrib::make_flat(rmode->get_wireframe_color()),
+    ColorBlendAttrib::make(ColorBlendAttrib::M_add,
+                           ColorBlendAttrib::O_incoming_alpha,
+                           ColorBlendAttrib::O_one_minus_incoming_alpha),
+    RenderModeAttrib::make(RenderModeAttrib::M_wireframe,
+                           rmode->get_thickness(),
+                           rmode->get_perspective()));
+}
+

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

@@ -17,6 +17,7 @@
 
 
 #include "pandabase.h"
 #include "pandabase.h"
 #include "cullBin.h"
 #include "cullBin.h"
+#include "cullBinManager.h"
 #include "renderState.h"
 #include "renderState.h"
 #include "cullableObject.h"
 #include "cullableObject.h"
 #include "geomMunger.h"
 #include "geomMunger.h"
@@ -26,12 +27,11 @@
 #include "pset.h"
 #include "pset.h"
 #include "pmap.h"
 #include "pmap.h"
 
 
-
-class GraphicsStateGuardianBase;
 class CullTraverser;
 class CullTraverser;
-class TransformState;
+class GraphicsStateGuardianBase;
 class RenderState;
 class RenderState;
 class SceneSetup;
 class SceneSetup;
+class TransformState;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : CullResult
 //       Class : CullResult
@@ -66,13 +66,19 @@ public:
 
 
 private:
 private:
   CullBin *make_new_bin(int bin_index);
   CullBin *make_new_bin(int bin_index);
-  void do_flash_bin(CPT(RenderState) &state, const LColor &flash_color);
-  void check_flash_transparency(CPT(RenderState) &state, const LColor &color);
+
+  INLINE void check_flash_bin(CPT(RenderState) &state, CullBinManager *bin_manager, int bin_index);
+  INLINE void check_flash_transparency(CPT(RenderState) &state, const LColor &color);
+
+#ifndef NDEBUG
+  void apply_flash_color(CPT(RenderState) &state, const LColor &flash_color);
+#endif
 
 
   static CPT(RenderState) get_alpha_state();
   static CPT(RenderState) get_alpha_state();
   static CPT(RenderState) get_binary_state();
   static CPT(RenderState) get_binary_state();
   static CPT(RenderState) get_dual_transparent_state();
   static CPT(RenderState) get_dual_transparent_state();
   static CPT(RenderState) get_dual_opaque_state();
   static CPT(RenderState) get_dual_opaque_state();
+  static CPT(RenderState) get_wireframe_overlay_state(const RenderModeAttrib *rmode);
 
 
   GraphicsStateGuardianBase *_gsg;
   GraphicsStateGuardianBase *_gsg;
   PStatCollector _draw_region_pcollector;
   PStatCollector _draw_region_pcollector;
@@ -80,6 +86,10 @@ private:
   typedef pvector< PT(CullBin) > Bins;
   typedef pvector< PT(CullBin) > Bins;
   Bins _bins;
   Bins _bins;
 
 
+#ifndef NDEBUG
+  bool _show_transparency;
+#endif
+
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;

+ 16 - 0
panda/src/pgraph/nodePath.cxx

@@ -5213,6 +5213,22 @@ set_render_mode_filled(int priority) {
   node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled, thickness, perspective), priority);
   node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled, thickness, perspective), priority);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::set_render_mode_filled_wireframe
+//       Access: Published
+//  Description: Sets up the geometry at this level and below (unless
+//               overridden) to render in filled, but overlay the
+//               wireframe on top with a fixed color.  This is useful
+//               for debug visualizations.
+////////////////////////////////////////////////////////////////////
+void NodePath::
+set_render_mode_filled_wireframe(const LColor &wireframe_color, int priority) {
+  nassertv_always(!is_empty());
+  PN_stdfloat thickness = get_render_mode_thickness();
+  bool perspective = get_render_mode_perspective();
+  node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled_wireframe, thickness, perspective, wireframe_color), priority);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePath::set_render_mode_perspective
 //     Function: NodePath::set_render_mode_perspective
 //       Access: Published
 //       Access: Published

+ 1 - 0
panda/src/pgraph/nodePath.h

@@ -766,6 +766,7 @@ PUBLISHED:
 
 
   void set_render_mode_wireframe(int priority = 0);
   void set_render_mode_wireframe(int priority = 0);
   void set_render_mode_filled(int priority = 0);
   void set_render_mode_filled(int priority = 0);
+  void set_render_mode_filled_wireframe(const LColor &wireframe_color, int priority = 0);
   void set_render_mode_thickness(PN_stdfloat thickness, int priority = 0);
   void set_render_mode_thickness(PN_stdfloat thickness, int priority = 0);
   void set_render_mode_perspective(bool perspective, int priority = 0);
   void set_render_mode_perspective(bool perspective, int priority = 0);
   void set_render_mode(RenderModeAttrib::Mode mode, PN_stdfloat thickness, int priority = 0);
   void set_render_mode(RenderModeAttrib::Mode mode, PN_stdfloat thickness, int priority = 0);

+ 15 - 2
panda/src/pgraph/renderModeAttrib.I

@@ -21,10 +21,11 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE RenderModeAttrib::
 INLINE RenderModeAttrib::
 RenderModeAttrib(RenderModeAttrib::Mode mode, PN_stdfloat thickness,
 RenderModeAttrib(RenderModeAttrib::Mode mode, PN_stdfloat thickness,
-                 bool perspective) :
+                 bool perspective, const LColor &wireframe_color) :
   _mode(mode),
   _mode(mode),
   _thickness(thickness),
   _thickness(thickness),
-  _perspective(perspective)
+  _perspective(perspective),
+  _wireframe_color(wireframe_color)
 {
 {
 }
 }
 
 
@@ -68,6 +69,18 @@ get_perspective() const {
   return _perspective;
   return _perspective;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderModeAttrib::get_wireframe_color
+//       Access: Published
+//  Description: Returns the color that is used in M_filled_wireframe
+//               mode to distinguish the wireframe from the rest of
+//               the geometry.
+////////////////////////////////////////////////////////////////////
+INLINE const LColor &RenderModeAttrib::
+get_wireframe_color() const {
+  return _wireframe_color;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderModeAttrib::get_geom_rendering
 //     Function: RenderModeAttrib::get_geom_rendering
 //       Access: Published
 //       Access: Published

+ 28 - 4
panda/src/pgraph/renderModeAttrib.cxx

@@ -44,10 +44,15 @@ int RenderModeAttrib::_attrib_slot;
 //               it is false, the point thickness is actually a width
 //               it is false, the point thickness is actually a width
 //               in pixels, and points are a uniform screen size
 //               in pixels, and points are a uniform screen size
 //               regardless of distance from the camera.
 //               regardless of distance from the camera.
+//
+//               In M_filled_wireframe mode, you should also specify
+//               the wireframe_color, indicating the flat color to
+//               assign to the overlayed wireframe.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) RenderModeAttrib::
 CPT(RenderAttrib) RenderModeAttrib::
-make(RenderModeAttrib::Mode mode, PN_stdfloat thickness, bool perspective) {
-  RenderModeAttrib *attrib = new RenderModeAttrib(mode, thickness, perspective);
+make(RenderModeAttrib::Mode mode, PN_stdfloat thickness,
+     bool perspective, const LColor &wireframe_color) {
+  RenderModeAttrib *attrib = new RenderModeAttrib(mode, thickness, perspective, wireframe_color);
   return return_new(attrib);
   return return_new(attrib);
 }
 }
 
 
@@ -66,7 +71,7 @@ make_default() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderModeAttrib::output
 //     Function: RenderModeAttrib::output
 //       Access: Public, Virtual
 //       Access: Public, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void RenderModeAttrib::
 void RenderModeAttrib::
 output(ostream &out) const {
 output(ostream &out) const {
@@ -91,6 +96,10 @@ output(ostream &out) const {
   case M_filled_flat:
   case M_filled_flat:
     out << "filled_flat";
     out << "filled_flat";
     break;
     break;
+
+  case M_filled_wireframe:
+    out << "filled_wireframe(" << get_wireframe_color() << ")";
+    break;
   }
   }
 
 
   if (get_thickness() != 1.0f) {
   if (get_thickness() != 1.0f) {
@@ -130,6 +139,9 @@ compare_to_impl(const RenderAttrib *other) const {
   if (_perspective != ta->_perspective) {
   if (_perspective != ta->_perspective) {
     return (int)_perspective - (int)ta->_perspective;
     return (int)_perspective - (int)ta->_perspective;
   }
   }
+  if (_mode == M_filled_wireframe && _wireframe_color != ta->_wireframe_color) {
+    return _wireframe_color.compare_to(ta->_wireframe_color);
+  }
   return 0;
   return 0;
 }
 }
 
 
@@ -149,6 +161,9 @@ get_hash_impl() const {
   hash = int_hash::add_hash(hash, (int)_mode);
   hash = int_hash::add_hash(hash, (int)_mode);
   hash = float_hash().add_hash(hash, _thickness);
   hash = float_hash().add_hash(hash, _thickness);
   hash = int_hash::add_hash(hash, (int)_perspective);
   hash = int_hash::add_hash(hash, (int)_perspective);
+  if (_mode == M_filled_wireframe) {
+    hash = _wireframe_color.add_hash(hash);
+  }
   return hash;
   return hash;
 }
 }
 
 
@@ -180,7 +195,8 @@ compose_impl(const RenderAttrib *other) const {
     mode = get_mode();
     mode = get_mode();
   }
   }
 
 
-  return make(mode, ta->get_thickness(), ta->get_perspective());
+  return make(mode, ta->get_thickness(), ta->get_perspective(),
+              ta->get_wireframe_color());
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -207,6 +223,10 @@ write_datagram(BamWriter *manager, Datagram &dg) {
   dg.add_int8(_mode);
   dg.add_int8(_mode);
   dg.add_stdfloat(_thickness);
   dg.add_stdfloat(_thickness);
   dg.add_bool(_perspective);
   dg.add_bool(_perspective);
+
+  if (_mode == M_filled_wireframe) {
+    _wireframe_color.write_datagram(dg);
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -243,4 +263,8 @@ fillin(DatagramIterator &scan, BamReader *manager) {
   _mode = (Mode)scan.get_int8();
   _mode = (Mode)scan.get_int8();
   _thickness = scan.get_stdfloat();
   _thickness = scan.get_stdfloat();
   _perspective = scan.get_bool();
   _perspective = scan.get_bool();
+
+  if (_mode == M_filled_wireframe) {
+    _wireframe_color.read_datagram(scan);
+  }
 }
 }

+ 12 - 4
panda/src/pgraph/renderModeAttrib.h

@@ -44,20 +44,27 @@ PUBLISHED:
     // Filled polygons, without any particular emphasis on perspective
     // Filled polygons, without any particular emphasis on perspective
     // correctness (a particularly useful designation for software
     // correctness (a particularly useful designation for software
     // rendering sprites).
     // rendering sprites).
-    M_filled_flat
+    M_filled_flat,
+
+    // Filled polygons with wireframe rendered in front.
+    // The wireframe is given a solid color.
+    M_filled_wireframe
   };
   };
 
 
 private:
 private:
-  INLINE RenderModeAttrib(Mode mode, PN_stdfloat thickness, bool perspective);
+  INLINE RenderModeAttrib(Mode mode, PN_stdfloat thickness, bool perspective,
+                          const LColor &wireframe_color = LColor::zero());
 
 
 PUBLISHED:
 PUBLISHED:
   static CPT(RenderAttrib) make(Mode mode, PN_stdfloat thickness = 1.0f,
   static CPT(RenderAttrib) make(Mode mode, PN_stdfloat thickness = 1.0f,
-                                bool perspective = false);
+                                bool perspective = false,
+                                const LColor &wireframe_color = LColor::zero());
   static CPT(RenderAttrib) make_default();
   static CPT(RenderAttrib) make_default();
 
 
   INLINE Mode get_mode() const;
   INLINE Mode get_mode() const;
   INLINE PN_stdfloat get_thickness() const;
   INLINE PN_stdfloat get_thickness() const;
   INLINE bool get_perspective() const;
   INLINE bool get_perspective() const;
+  INLINE const LColor &get_wireframe_color() const;
 
 
   INLINE int get_geom_rendering(int geom_rendering) const;
   INLINE int get_geom_rendering(int geom_rendering) const;
 
 
@@ -73,6 +80,7 @@ private:
   Mode _mode;
   Mode _mode;
   PN_stdfloat _thickness;
   PN_stdfloat _thickness;
   bool _perspective;
   bool _perspective;
+  LColor _wireframe_color;
 
 
 PUBLISHED:
 PUBLISHED:
   static int get_class_slot() {
   static int get_class_slot() {
@@ -89,7 +97,7 @@ public:
 protected:
 protected:
   static TypedWritable *make_from_bam(const FactoryParams &params);
   static TypedWritable *make_from_bam(const FactoryParams &params);
   void fillin(DatagramIterator &scan, BamReader *manager);
   void fillin(DatagramIterator &scan, BamReader *manager);
-  
+
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;