Просмотр исходного кода

implement qpNodePath.showBounds()

David Rose 24 лет назад
Родитель
Сommit
3790f2756c

+ 1 - 1
panda/src/dgraph/qpdataNode.h

@@ -84,7 +84,7 @@ PUBLISHED:
   void write_outputs(ostream &out) const;
   void write_connections(ostream &out) const;
 
-  //protected:
+protected:
   int define_input(const string &name, TypeHandle data_type);
   int define_output(const string &name, TypeHandle data_type);
 

+ 3 - 0
panda/src/pgraph/Sources.pp

@@ -54,6 +54,7 @@
     qpsceneGraphReducer.I qpsceneGraphReducer.h \
     selectiveChildNode.I selectiveChildNode.h \
     qpsequenceNode.I qpsequenceNode.h \
+    showBoundsEffect.I showBoundsEffect.h \
     texMatrixAttrib.I texMatrixAttrib.h \
     textureApplyAttrib.I textureApplyAttrib.h \
     textureAttrib.I textureAttrib.h \
@@ -112,6 +113,7 @@
     qpsceneGraphReducer.cxx \
     selectiveChildNode.cxx \
     qpsequenceNode.cxx \
+    showBoundsEffect.cxx \
     texMatrixAttrib.cxx \
     textureApplyAttrib.cxx \
     textureAttrib.cxx \
@@ -172,6 +174,7 @@
     qpsceneGraphReducer.I qpsceneGraphReducer.h \
     selectiveChildNode.I selectiveChildNode.h \
     qpsequenceNode.I qpsequenceNode.h \
+    showBoundsEffect.I showBoundsEffect.h \
     texMatrixAttrib.I texMatrixAttrib.h \
     textureApplyAttrib.I textureApplyAttrib.h \
     textureAttrib.I textureAttrib.h \

+ 3 - 0
panda/src/pgraph/config_pgraph.cxx

@@ -52,6 +52,7 @@
 #include "renderState.h"
 #include "selectiveChildNode.h"
 #include "qpsequenceNode.h"
+#include "showBoundsEffect.h"
 #include "texMatrixAttrib.h"
 #include "textureApplyAttrib.h"
 #include "textureAttrib.h"
@@ -128,6 +129,7 @@ init_libpgraph() {
   RenderState::init_type();
   SelectiveChildNode::init_type();
   qpSequenceNode::init_type();
+  ShowBoundsEffect::init_type();
   TexMatrixAttrib::init_type();
   TextureApplyAttrib::init_type();
   TextureAttrib::init_type();
@@ -166,6 +168,7 @@ init_libpgraph() {
   RenderModeAttrib::register_with_read_factory();
   RenderState::register_with_read_factory();
   qpSequenceNode::register_with_read_factory();
+  ShowBoundsEffect::register_with_read_factory();
   TexMatrixAttrib::register_with_read_factory();
   TextureApplyAttrib::register_with_read_factory();
   TextureAttrib::register_with_read_factory();

+ 8 - 8
panda/src/pgraph/cullTraverserData.cxx

@@ -115,8 +115,8 @@ is_in_view_impl() {
     // actually culling an object we simply force it to be drawn in
     // red wireframe.
     _view_frustum = (GeometricBoundingVolume *)NULL;
-    CPT(RenderState) fake_effect = get_fake_view_frustum_cull_effect();
-    _state = _state->compose(fake_effect);
+    CPT(RenderState) fake_state = get_fake_view_frustum_cull_state();
+    _state = _state->compose(fake_state);
     
   } else if ((result & BoundingVolume::IF_all) != 0) {
     // The node and its descendants are completely enclosed within
@@ -140,24 +140,24 @@ is_in_view_impl() {
 
 
 ////////////////////////////////////////////////////////////////////
-//     Function: CullTraverserData::get_fake_view_frustum_cull_effect
+//     Function: CullTraverserData::get_fake_view_frustum_cull_state
 //       Access: Private, Static
 //  Description: Returns a RenderState for rendering stuff in red
 //               wireframe, strictly for the fake_view_frustum_cull
 //               effect.
 ////////////////////////////////////////////////////////////////////
 CPT(RenderState) CullTraverserData::
-get_fake_view_frustum_cull_effect() {
+get_fake_view_frustum_cull_state() {
   // Once someone asks for this pointer, we hold its reference count
   // and never free it.
-  static CPT(RenderState) effect = (const RenderState *)NULL;
-  if (effect == (const RenderState *)NULL) {
-    effect = RenderState::make
+  static CPT(RenderState) state = (const RenderState *)NULL;
+  if (state == (const RenderState *)NULL) {
+    state = RenderState::make
       (ColorAttrib::make_flat(Colorf(1.0f, 0.0f, 0.0f, 1.0f)),
        TextureAttrib::make_off(),
        RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
        1000);
   }
-  return effect;
+  return state;
 }
 

+ 1 - 1
panda/src/pgraph/cullTraverserData.h

@@ -77,7 +77,7 @@ public:
 
 private:
   bool is_in_view_impl();
-  static CPT(RenderState) get_fake_view_frustum_cull_effect();
+  static CPT(RenderState) get_fake_view_frustum_cull_state();
 };
 
 #include "cullTraverserData.I"

+ 17 - 0
panda/src/pgraph/cullableObject.I

@@ -45,6 +45,23 @@ CullableObject(const CullTraverserData &data,
   _next(next)
 {
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullableObject::Constructor
+//       Access: Public
+//  Description: Creates a CullableObject based the indicated geom,
+//               with the indicated render state and transform.
+////////////////////////////////////////////////////////////////////
+INLINE CullableObject::
+CullableObject(Geom *geom, const RenderState *state,
+               const TransformState *transform,
+               CullableObject *next) :
+  _geom(geom),
+  _state(state),
+  _transform(transform),
+  _next(next)
+{
+}
   
 
 ////////////////////////////////////////////////////////////////////

+ 4 - 1
panda/src/pgraph/cullableObject.h

@@ -42,7 +42,10 @@ public:
   INLINE CullableObject(const CullTraverserData &data,
                         qpGeomNode *geom_node, int i,
                         CullableObject *next = NULL);
-
+  INLINE CullableObject(Geom *geom, const RenderState *state,
+                        const TransformState *transform,
+                        CullableObject *next = NULL);
+    
 private:
   INLINE CullableObject(const CullableObject &copy);
   INLINE void operator = (const CullableObject &copy);

+ 1 - 0
panda/src/pgraph/pgraph_composite2.cxx

@@ -22,6 +22,7 @@
 #include "qpsceneGraphReducer.cxx"
 #include "selectiveChildNode.cxx"
 #include "qpsequenceNode.cxx"
+#include "showBoundsEffect.cxx"
 #include "test_pgraph.cxx"
 #include "texMatrixAttrib.cxx"
 #include "textureApplyAttrib.cxx"

+ 123 - 5
panda/src/pgraph/qpcullTraverser.cxx

@@ -25,6 +25,11 @@
 #include "dcast.h"
 #include "qpgeomNode.h"
 #include "config_pgraph.h"
+#include "boundingSphere.h"
+#include "geomSphere.h"
+#include "colorAttrib.h"
+#include "renderModeAttrib.h"
+#include "cullFaceAttrib.h"
 
 
 TypeHandle qpCullTraverser::_type_handle;
@@ -89,11 +94,19 @@ traverse(CullTraverserData &data) {
   // optimization, we should tag nodes with these properties as
   // being "fancy", and skip this processing for non-fancy nodes.
   if (data.is_in_view(_camera_mask)) {
-    data.apply_transform_and_state(this);
-
     PandaNode *node = data.node();
 
-    const FogAttrib *fog = node->get_state()->get_fog();
+    const RenderEffects *node_effects = node->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);
+    }
+
+    data.apply_transform_and_state(this);
+
+    const RenderState *node_state = node->get_state();
+    const FogAttrib *fog = node_state->get_fog();
     if (fog != (const FogAttrib *)NULL && fog->get_fog() != (qpFog *)NULL) {
       // If we just introduced a FogAttrib here, call adjust_to_camera()
       // now.  This maybe isn't the perfect time to call it, but it's
@@ -160,6 +173,104 @@ traverse_below(const CullTraverserData &data) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpCullTraverser::show_bounds
+//       Access: Private
+//  Description: Draws an appropriate visualization of the node's
+//               external bounding volume.
+////////////////////////////////////////////////////////////////////
+void qpCullTraverser::
+show_bounds(CullTraverserData &data) {
+  PandaNode *node = data.node();
+
+  PT(Geom) bounds_viz = make_bounds_viz(node->get_bound());
+  if (bounds_viz != (Geom *)NULL) {
+    CullableObject *outer_viz = 
+      new CullableObject(bounds_viz, get_bounds_outer_viz_state(), 
+                         data._render_transform);
+    _cull_handler->record_object(outer_viz);
+
+    CullableObject *inner_viz = 
+      new CullableObject(bounds_viz, get_bounds_inner_viz_state(), 
+                         data._render_transform);
+    _cull_handler->record_object(inner_viz);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpCullTraverser::make_bounds_viz
+//       Access: Private
+//  Description: Returns an appropriate visualization of the indicated
+//               bounding volume.
+////////////////////////////////////////////////////////////////////
+PT(Geom) qpCullTraverser::
+make_bounds_viz(const BoundingVolume &vol) {
+  PT(Geom) geom;
+  if (vol.is_infinite()) {
+    // No way to draw an infinite bounding volume.
+
+  } else if (vol.is_of_type(BoundingSphere::get_class_type())) {
+    const BoundingSphere *sphere = DCAST(BoundingSphere, &vol);
+    
+    geom = new GeomSphere;
+    PTA_Vertexf verts;
+    LPoint3f center = sphere->get_center();
+    verts.push_back(center);
+    center[0] += sphere->get_radius();
+    verts.push_back(center);
+    geom->set_coords(verts);
+    geom->set_num_prims(1);
+    
+  } else {
+    pgraph_cat.warning()
+      << "Don't know how to draw a representation of "
+      << vol.get_class_type() << "\n";
+  }
+
+  return geom;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpCullTraverser::get_bounds_outer_viz_state
+//       Access: Private, Static
+//  Description: Returns a RenderState for rendering the outside
+//               surfaces of the bounding volume visualizations.
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) qpCullTraverser::
+get_bounds_outer_viz_state() {
+  // Once someone asks for this pointer, we hold its reference count
+  // and never free it.
+  static CPT(RenderState) state = (const RenderState *)NULL;
+  if (state == (const RenderState *)NULL) {
+    state = RenderState::make
+      (ColorAttrib::make_flat(Colorf(0.3f, 1.0f, 0.5f, 1.0f)),
+       RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
+       CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise));
+  }
+  return state;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpCullTraverser::get_bounds_inner_viz_state
+//       Access: Private, Static
+//  Description: Returns a RenderState for rendering the inside
+//               surfaces of the bounding volume visualizations.
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) qpCullTraverser::
+get_bounds_inner_viz_state() {
+  // Once someone asks for this pointer, we hold its reference count
+  // and never free it.
+  static CPT(RenderState) state = (const RenderState *)NULL;
+  if (state == (const RenderState *)NULL) {
+    state = RenderState::make
+      (ColorAttrib::make_flat(Colorf(0.15f, 0.5f, 0.25f, 1.0f)),
+       RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
+       CullFaceAttrib::make(CullFaceAttrib::M_cull_counter_clockwise));
+  }
+  return state;
+}
+
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpCullTraverser::start_decal
 //       Access: Private
@@ -233,10 +344,17 @@ start_decal(const CullTraverserData &data) {
 CullableObject *qpCullTraverser::
 r_get_decals(CullTraverserData &data, CullableObject *decals) {
   if (data.is_in_view(_camera_mask)) {
-    data.apply_transform_and_state(this);
-
     PandaNode *node = data.node();
 
+    const RenderEffects *node_effects = node->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);
+    }
+
+    data.apply_transform_and_state(this);
+
     // First, visit all of the node's children.
     int num_children = node->get_num_children();
     if (node->has_selective_visibility()) {

+ 6 - 0
panda/src/pgraph/qpcullTraverser.h

@@ -21,6 +21,7 @@
 
 #include "pandabase.h"
 
+#include "geom.h"
 #include "renderState.h"
 #include "transformState.h"
 #include "geometricBoundingVolume.h"
@@ -73,6 +74,11 @@ public:
   void traverse_below(const CullTraverserData &data);
 
 private:
+  void show_bounds(CullTraverserData &data);
+  PT(Geom) make_bounds_viz(const BoundingVolume &vol);
+  CPT(RenderState) get_bounds_outer_viz_state();
+  CPT(RenderState) get_bounds_inner_viz_state();
+
   void start_decal(const CullTraverserData &data);
   CullableObject *r_get_decals(CullTraverserData &data,
                                CullableObject *decals);

+ 52 - 2
panda/src/pgraph/qpnodePath.cxx

@@ -33,6 +33,7 @@
 #include "depthTestAttrib.h"
 #include "depthWriteAttrib.h"
 #include "billboardEffect.h"
+#include "showBoundsEffect.h"
 #include "transparencyAttrib.h"
 #include "materialPool.h"
 #include "look_at.h"
@@ -2423,7 +2424,7 @@ prepare_scene(GraphicsStateGuardianBase *gsg, bool force_retained_mode) {
 void qpNodePath::
 show_bounds() {
   nassertv_always(!is_empty());
-  nassertv(false);
+  node()->set_effect(ShowBoundsEffect::make());
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -2435,7 +2436,7 @@ show_bounds() {
 void qpNodePath::
 hide_bounds() {
   nassertv_always(!is_empty());
-  nassertv(false);
+  node()->clear_effect(ShowBoundsEffect::get_class_type());
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -2452,6 +2453,28 @@ get_bounds() const {
   return node()->get_bound().make_copy();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpNodePath::force_recompute_bounds
+//       Access: Published
+//  Description: Forces the recomputing of all the bounding volumes at
+//               every node in the subgraph beginning at this node and
+//               below.
+//
+//               This should not normally need to be called, since the
+//               bounding volumes are supposed to be recomputed
+//               automatically when necessary.  It may be useful when
+//               debugging, to verify that the bounding volumes have
+//               not become inadvertently stale; it may also be useful
+//               to force animated characters to update their bounding
+//               volumes (which does not presently happen
+//               automatically).
+////////////////////////////////////////////////////////////////////
+void qpNodePath::
+force_recompute_bounds() {
+  nassertv_always(!is_empty());
+  r_force_recompute_bounds(node());
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpNodePath::write_bounds
 //       Access: Published
@@ -2902,6 +2925,33 @@ r_adjust_all_priorities(PandaNode *node, int adjustment) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpNodePath::r_force_recompute_bounds
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void qpNodePath::
+r_force_recompute_bounds(PandaNode *node) {
+  if (node->is_geom_node()) {
+    qpGeomNode *gnode;
+    DCAST_INTO_V(gnode, node);
+
+    int num_geoms = gnode->get_num_geoms();
+    for (int i = 0; i < num_geoms; i++) {
+      gnode->get_geom(i)->mark_bound_stale();
+    }
+  }
+
+  node->mark_bound_stale();
+
+  // Now consider children.
+  PandaNode::Children cr = node->get_children();
+  int num_children = cr.get_num_children();
+  for (int i = 0; i < num_children; i++) {
+    r_force_recompute_bounds(cr.get_child(i));
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpNodePath::r_calc_tight_bounds
 //       Access: Private

+ 2 - 0
panda/src/pgraph/qpnodePath.h

@@ -483,6 +483,7 @@ PUBLISHED:
   void show_bounds();
   void hide_bounds();
   PT(BoundingVolume) get_bounds() const;
+  void force_recompute_bounds();
   void write_bounds(ostream &out) const;
   bool calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point);
 
@@ -515,6 +516,7 @@ private:
 
   void r_adjust_all_priorities(PandaNode *node, int adjustment);
 
+  void r_force_recompute_bounds(PandaNode *node);
   void r_calc_tight_bounds(PandaNode *node,
                            LPoint3f &min_point, LPoint3f &max_point,
                            bool &found_any, const TransformState *transform);

+ 21 - 0
panda/src/pgraph/renderEffects.I

@@ -180,3 +180,24 @@ has_decal() const {
   }
   return ((_flags & F_has_decal) != 0);
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderEffects::has_show_bounds
+//       Access: Public
+//  Description: This function is provided as an optimization, to
+//               speed up the render-time checking for the existance
+//               of a ShowBoundsEffect on this state.  It returns true
+//               if a ShowBoundsEffect exists, false otherwise.  Note
+//               that since there is no additional information stored
+//               on the ShowBoundsEffect, there's no point in
+//               returning it if it exists.
+////////////////////////////////////////////////////////////////////
+INLINE bool RenderEffects::
+has_show_bounds() const {
+  if ((_flags & F_checked_show_bounds) == 0) {
+    // We pretend this function is const, even though it transparently
+    // modifies the internal show_bounds cache.
+    ((RenderEffects *)this)->determine_show_bounds();
+  }
+  return ((_flags & F_has_show_bounds) != 0);
+}

+ 15 - 0
panda/src/pgraph/renderEffects.cxx

@@ -19,6 +19,7 @@
 #include "renderEffects.h"
 #include "billboardEffect.h"
 #include "decalEffect.h"
+#include "showBoundsEffect.h"
 #include "config_pgraph.h"
 #include "bamReader.h"
 #include "bamWriter.h"
@@ -459,6 +460,20 @@ determine_decal() {
   _flags |= F_checked_decal;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderEffects::determine_show_bounds
+//       Access: Private
+//  Description: This is the private implementation of has_show_bounds().
+////////////////////////////////////////////////////////////////////
+void RenderEffects::
+determine_show_bounds() {
+  const RenderEffect *effect = get_effect(ShowBoundsEffect::get_class_type());
+  if (effect != (const RenderEffect *)NULL) {
+    _flags |= F_has_show_bounds;
+  }
+  _flags |= F_checked_show_bounds;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderEffects::register_with_read_factory
 //       Access: Public, Static

+ 4 - 0
panda/src/pgraph/renderEffects.h

@@ -88,11 +88,13 @@ PUBLISHED:
 public:
   INLINE const BillboardEffect *get_billboard() const;
   INLINE bool has_decal() const;
+  INLINE bool has_show_bounds() const;
 
 private:
   static CPT(RenderEffects) return_new(RenderEffects *state);
   void determine_billboard();
   void determine_decal();
+  void determine_show_bounds();
 
 private:
   typedef pset<const RenderEffects *, IndirectLess<RenderEffects> > States;
@@ -131,6 +133,8 @@ private:
     F_checked_billboard    = 0x0001,
     F_checked_decal        = 0x0002,
     F_has_decal            = 0x0004,
+    F_checked_show_bounds  = 0x0008,
+    F_has_show_bounds      = 0x0010,
   };
   short _flags;
 

+ 28 - 0
panda/src/pgraph/showBoundsEffect.I

@@ -0,0 +1,28 @@
+// Filename: showBoundsEffect.I
+// Created by:  drose (25Mar02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShowBoundsEffect::Constructor
+//       Access: Private
+//  Description: Use ShowBoundsEffect::make() to construct a new
+//               ShowBoundsEffect object.
+////////////////////////////////////////////////////////////////////
+INLINE ShowBoundsEffect::
+ShowBoundsEffect() {
+}

+ 140 - 0
panda/src/pgraph/showBoundsEffect.cxx

@@ -0,0 +1,140 @@
+// Filename: showBoundsEffect.cxx
+// Created by:  drose (25Mar02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "showBoundsEffect.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+#include "datagram.h"
+#include "datagramIterator.h"
+
+TypeHandle ShowBoundsEffect::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShowBoundsEffect::make
+//       Access: Published, Static
+//  Description: Constructs a new ShowBoundsEffect object.
+////////////////////////////////////////////////////////////////////
+CPT(RenderEffect) ShowBoundsEffect::
+make() {
+  ShowBoundsEffect *effect = new ShowBoundsEffect;
+  return return_new(effect);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShowBoundsEffect::safe_to_combine
+//       Access: Public, Virtual
+//  Description: Returns true if this kind of effect can safely be
+//               combined with sibling nodes that share the exact same
+//               effect, or false if this is not a good idea.
+////////////////////////////////////////////////////////////////////
+bool ShowBoundsEffect::
+safe_to_combine() const {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShowBoundsEffect::compare_to_impl
+//       Access: Protected, Virtual
+//  Description: Intended to be overridden by derived ShowBoundsEffect
+//               types to return a unique number indicating whether
+//               this ShowBoundsEffect is equivalent to the other one.
+//
+//               This should return 0 if the two ShowBoundsEffect objects
+//               are equivalent, a number less than zero if this one
+//               should be sorted before the other one, and a number
+//               greater than zero otherwise.
+//
+//               This will only be called with two ShowBoundsEffect
+//               objects whose get_type() functions return the same.
+////////////////////////////////////////////////////////////////////
+int ShowBoundsEffect::
+compare_to_impl(const RenderEffect *other) const {
+  // All ShowBoundsEffects are equivalent--there are no properties to
+  // store.
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShowBoundsEffect::make_default_impl
+//       Access: Protected, Virtual
+//  Description: Intended to be overridden by derived ShowBoundsEffect
+//               types to specify what the default property for a
+//               ShowBoundsEffect of this type should be.
+//
+//               This should return a newly-allocated ShowBoundsEffect of
+//               the same type that corresponds to whatever the
+//               standard default for this kind of ShowBoundsEffect is.
+////////////////////////////////////////////////////////////////////
+RenderEffect *ShowBoundsEffect::
+make_default_impl() const {
+  return new ShowBoundsEffect;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShowBoundsEffect::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               ShowBoundsEffect.
+////////////////////////////////////////////////////////////////////
+void ShowBoundsEffect::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShowBoundsEffect::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void ShowBoundsEffect::
+write_datagram(BamWriter *manager, Datagram &dg) {
+  RenderEffect::write_datagram(manager, dg);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShowBoundsEffect::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type ShowBoundsEffect is encountered
+//               in the Bam file.  It should create the ShowBoundsEffect
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *ShowBoundsEffect::
+make_from_bam(const FactoryParams &params) {
+  ShowBoundsEffect *effect = new ShowBoundsEffect;
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  effect->fillin(scan, manager);
+
+  return effect;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShowBoundsEffect::fillin
+//       Access: Protected
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new ShowBoundsEffect.
+////////////////////////////////////////////////////////////////////
+void ShowBoundsEffect::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  RenderEffect::fillin(scan, manager);
+}

+ 74 - 0
panda/src/pgraph/showBoundsEffect.h

@@ -0,0 +1,74 @@
+// Filename: showBoundsEffect.h
+// Created by:  drose (25Mar02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef SHOWBOUNDSEFFECT_H
+#define SHOWBOUNDSEFFECT_H
+
+#include "pandabase.h"
+
+#include "renderEffect.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : ShowBoundsEffect
+// Description : Applied to a GeomNode to cause a visible bounding
+//               volume to be drawn for this node.  This is generally
+//               used only during development to help identify
+//               bounding volume issues.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA ShowBoundsEffect : public RenderEffect {
+private:
+  INLINE ShowBoundsEffect();
+
+PUBLISHED:
+  static CPT(RenderEffect) make();
+
+protected:
+  virtual bool safe_to_combine() const;
+  virtual int compare_to_impl(const RenderEffect *other) const;
+  virtual RenderEffect *make_default_impl() const;
+
+public:
+  static void register_with_read_factory();
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+  void fillin(DatagramIterator &scan, BamReader *manager);
+  
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    RenderEffect::init_type();
+    register_type(_type_handle, "ShowBoundsEffect",
+                  RenderEffect::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "showBoundsEffect.I"
+
+#endif
+