Selaa lähdekoodia

*** empty log message ***

David Rose 25 vuotta sitten
vanhempi
sitoutus
594fc23c3b

+ 1 - 1
panda/src/cull/config_cull.cxx

@@ -17,7 +17,7 @@
 
 
 #include <dconfig.h>
 #include <dconfig.h>
 
 
-Configure(config_cull);
+ConfigureDef(config_cull);
 NotifyCategoryDef(cull, "");
 NotifyCategoryDef(cull, "");
 
 
 ConfigureFn(config_cull) {
 ConfigureFn(config_cull) {

+ 2 - 0
panda/src/cull/config_cull.h

@@ -8,7 +8,9 @@
 
 
 #include <pandabase.h>
 #include <pandabase.h>
 #include <notifyCategoryProxy.h>
 #include <notifyCategoryProxy.h>
+#include <dconfig.h>
 
 
+ConfigureDecl(config_cull, EXPCL_PANDA, EXPTP_PANDA);
 NotifyCategoryDecl(cull, EXPCL_PANDA, EXPTP_PANDA);
 NotifyCategoryDecl(cull, EXPCL_PANDA, EXPTP_PANDA);
 
 
 extern const bool cull_force_update;
 extern const bool cull_force_update;

+ 0 - 57
panda/src/cull/cullTraverser.I

@@ -9,63 +9,6 @@
 #include <directRenderTraverser.h>
 #include <directRenderTraverser.h>
 #include <graphicsStateGuardian.h>
 #include <graphicsStateGuardian.h>
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: CullTraverser::set_default_bin
-//       Access: Public
-//  Description: Specifies the default GeomBin that any geometry will
-//               be assigned to if the scene graph doesn't specify
-//               otherwise.  There must always be some default GeomBin
-//               in effect.
-////////////////////////////////////////////////////////////////////
-INLINE void CullTraverser::
-set_default_bin(GeomBin *bin) {
-  nassertv(bin != (GeomBin *)NULL);
-  nassertv(bin->is_attached());
-  nassertv(bin->get_traverser() == this);
-  _default_bin = bin;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CullTraverser::get_default_bin
-//       Access: Public
-//  Description: Returns the default GeomBin that any geometry will
-//               be assigned to if the scene graph doesn't specify
-//               otherwise.
-////////////////////////////////////////////////////////////////////
-INLINE GeomBin *CullTraverser::
-get_default_bin() const {
-  return _default_bin;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CullTraverser::has_bin
-//       Access: Public
-//  Description: Returns true if a bin by the given name has been
-//               attached to the CullTraverser, false otherwise.
-////////////////////////////////////////////////////////////////////
-INLINE bool CullTraverser::
-has_bin(const string &name) const {
-  return (_toplevel_bins.count(name) != 0);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CullTraverser::get_bin
-//       Access: Public
-//  Description: Returns the GeomBin that was previously attached to
-//               the CullTraverser that shares the indicated name, or
-//               the default bin if no GeomBin with a matching name
-//               was added.
-////////////////////////////////////////////////////////////////////
-INLINE GeomBin *CullTraverser::
-get_bin(const string &name) const {
-  ToplevelBins::const_iterator tbi;
-  tbi = _toplevel_bins.find(name);
-  if (tbi == _toplevel_bins.end()) {
-    return get_default_bin();
-  }
-  return (*tbi).second;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CullTraverser::draw_geom
 //     Function: CullTraverser::draw_geom
 //       Access: Public
 //       Access: Public

+ 196 - 58
panda/src/cull/cullTraverser.cxx

@@ -23,6 +23,7 @@
 #include <config_sgraphutil.h>  // for implicit_app_traversal
 #include <config_sgraphutil.h>  // for implicit_app_traversal
 #include <config_sgattrib.h>    // for support_decals
 #include <config_sgattrib.h>    // for support_decals
 #include <pStatTimer.h>
 #include <pStatTimer.h>
+#include <string_utils.h>
 
 
 TypeHandle CullTraverser::_type_handle;
 TypeHandle CullTraverser::_type_handle;
 
 
@@ -43,16 +44,9 @@ CullTraverser(GraphicsStateGuardian *gsg, TypeHandle graph_type,
 	      const ArcChain &arc_chain) :
 	      const ArcChain &arc_chain) :
   RenderTraverser(gsg, graph_type, arc_chain)
   RenderTraverser(gsg, graph_type, arc_chain)
 {
 {
-  GeomBinNormal *default_bin = new GeomBinNormal("default");
-  GeomBinFixed *fixed = new GeomBinFixed("fixed");
-  fixed->set_sort(30);
-
-  default_bin->set_traverser(this);
-  fixed->set_traverser(this);
-
-  _default_bin = default_bin;
-
   _nested_count = 0;
   _nested_count = 0;
+
+  setup_initial_bins();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -63,6 +57,48 @@ CullTraverser(GraphicsStateGuardian *gsg, TypeHandle graph_type,
 CullTraverser::
 CullTraverser::
 ~CullTraverser() {
 ~CullTraverser() {
   // We should detach each of our associated bins when we destruct.
   // We should detach each of our associated bins when we destruct.
+  clear_bins();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullTraverser::has_bin
+//       Access: Public
+//  Description: Returns true if a bin by the given name has been
+//               attached to the CullTraverser, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool CullTraverser::
+has_bin(const string &name) const {
+  return (_toplevel_bins.count(name) != 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullTraverser::get_bin
+//       Access: Public
+//  Description: Returns the GeomBin that was previously attached to
+//               the CullTraverser that shares the indicated name, or
+//               NULL if no GeomBin with a matching name was added.
+////////////////////////////////////////////////////////////////////
+GeomBin *CullTraverser::
+get_bin(const string &name) const {
+  ToplevelBins::const_iterator tbi;
+  tbi = _toplevel_bins.find(name);
+  if (tbi == _toplevel_bins.end()) {
+    return NULL;
+  }
+  return (*tbi).second;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullTraverser::clear_bins
+//       Access: Public
+//  Description: Disassociates all the GeomBins previously associated
+//               with this traverser (and deletes them, if they have
+//               no other references).  You must add new GeomBins
+//               before rendering by calling set_traverser() on the
+//               appropriate bins.
+////////////////////////////////////////////////////////////////////
+void CullTraverser::
+clear_bins() {
   // We can't just run a for loop, because this is a self-modifying
   // We can't just run a for loop, because this is a self-modifying
   // operation.
   // operation.
   while (!_toplevel_bins.empty()) {
   while (!_toplevel_bins.empty()) {
@@ -73,6 +109,54 @@ CullTraverser::
   }
   }
 
 
   nassertv(_sub_bins.empty());
   nassertv(_sub_bins.empty());
+  nassertv(_default_bin == (GeomBin *)NULL);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullTraverser::output
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void CullTraverser::
+output(ostream &out) const {
+  int node_count = 0;
+  int used_states = 0;
+
+  States::const_iterator si;
+  for (si = _states.begin(); si != _states.end(); ++si) {
+    const CullState *cs = (*si);
+    int c = cs->count_current_nodes();
+    if (c != 0) {
+      node_count += c;
+      used_states++;
+    }
+  }
+
+  out << node_count << " nodes with " << used_states << " states; "
+      << _states.size() - used_states << " unused states.";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullTraverser::output
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void CullTraverser::
+write(ostream &out, int indent_level) const {
+  /*
+  States::const_iterator si;
+  for (si = _states.begin(); si != _states.end(); ++si) {
+    const CullState *cs = (*si);
+    cs->write(out, indent_level);
+    out << "\n";
+  }
+  */
+
+  ToplevelBins::const_iterator tbi;
+  for (tbi = _toplevel_bins.begin(); tbi != _toplevel_bins.end(); ++tbi) {
+    (*tbi).second->write(out, indent_level);
+  }
+  _lookup.write(out, indent_level);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -97,9 +181,6 @@ traverse(Node *root,
       << *root << "\n";
       << *root << "\n";
   }
   }
 
 
-  nassertv(!_toplevel_bins.empty());
-  nassertv(!_sub_bins.empty());
-
   bool is_initial = (_nested_count == 0);
   bool is_initial = (_nested_count == 0);
   if (is_initial) {
   if (is_initial) {
     if (cull_force_update) {
     if (cull_force_update) {
@@ -157,52 +238,68 @@ traverse(Node *root,
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CullTraverser::output
-//       Access: Public
-//  Description: 
+//     Function: CullTraverser::setup_initial_bins
+//       Access: Private
+//  Description: Creates all the appropriate rendering bins as
+//               requested from the Configrc file.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CullTraverser::
 void CullTraverser::
-output(ostream &out) const {
-  int node_count = 0;
-  int used_states = 0;
+setup_initial_bins() {
+  // We always have "default" and "fixed" hardcoded in, although these
+  // may be overridden by specifing a new bin with the same name in
+  // the Configrc file.
 
 
-  States::const_iterator si;
-  for (si = _states.begin(); si != _states.end(); ++si) {
-    const CullState *cs = (*si);
-    int c = cs->count_current_nodes();
-    if (c != 0) {
-      node_count += c;
-      used_states++;
-    }
-  }
+  GeomBinNormal *default_bin = new GeomBinNormal("default");
+  GeomBinFixed *fixed = new GeomBinFixed("fixed");
+  fixed->set_sort(30);
 
 
-  out << node_count << " nodes with " << used_states << " states; "
-      << _states.size() - used_states << " unused states.";
-}
+  default_bin->set_traverser(this);
+  fixed->set_traverser(this);
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: CullTraverser::output
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-void CullTraverser::
-write(ostream &out, int indent_level) const {
-  /*
-  States::const_iterator si;
-  for (si = _states.begin(); si != _states.end(); ++si) {
-    const CullState *cs = (*si);
-    cs->write(out, indent_level);
-    out << "\n";
-  }
-  */
 
 
-  ToplevelBins::const_iterator tbi;
-  for (tbi = _toplevel_bins.begin(); tbi != _toplevel_bins.end(); ++tbi) {
-    (*tbi).second->write(out, indent_level);
+  // Now get the config options.
+  Config::ConfigTable::Symbol cull_bins;
+  config_cull.GetAll("cull-bin", cull_bins);
+
+  Config::ConfigTable::Symbol::iterator bi;
+  for (bi = cull_bins.begin(); bi != cull_bins.end(); ++bi) {
+    ConfigString def = (*bi).Val();
+
+    // This is a string in three tokens, separated by whitespace:
+    //    bin_name sort type
+
+    vector_string words;
+    extract_words(def, words);
+
+    if (words.size() != 3) {
+      cull_cat.error()
+	<< "Invalid cull-bin definition: " << def << "\n"
+	<< "Definition should be three words: bin_name sort type\n";
+    } else {
+      int sort;
+      if (!string_to_int(words[1], sort)) {
+	cull_cat.error()
+	  << "Invalid cull-bin definition: " << def << "\n"
+	  << "Sort token " << words[1] << " is not an integer.\n";
+
+      } else {
+	TypeHandle type = GeomBin::parse_bin_type(words[2]);
+	if (type == TypeHandle::none()) {
+	  cull_cat.error()
+	    << "Invalid cull-bin definition: " << def << "\n"
+	    << "Bin type " << words[2] << " is not known.\n";
+	} else {
+	  PT(GeomBin) bin = GeomBin::make_bin(type, words[0]);
+	  nassertv(bin != (GeomBin *)NULL);
+	  bin->set_sort(sort);
+	  bin->set_traverser(this);
+	}
+      }
+    }
   }
   }
-  _lookup.write(out, indent_level);
 }
 }
 
 
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CullTraverser::draw
 //     Function: CullTraverser::draw
 //       Access: Private
 //       Access: Private
@@ -238,15 +335,32 @@ draw() {
     if (!cs->is_empty()) {
     if (!cs->is_empty()) {
       cs->apply_to(_initial_state);
       cs->apply_to(_initial_state);
 
 
-      // Check the requested bin for the Geoms in this state.
+      static string default_bin_name = "default";
+      string bin_name = default_bin_name;
       GeomBin *requested_bin = _default_bin;
       GeomBin *requested_bin = _default_bin;
       int draw_order = 0;
       int draw_order = 0;
 
 
+      // Check the requested bin for the Geoms in this state.
       const GeomBinAttribute *bin_attrib;
       const GeomBinAttribute *bin_attrib;
       if (get_attribute_into(bin_attrib, cs->get_attributes(),
       if (get_attribute_into(bin_attrib, cs->get_attributes(),
 			     GeomBinTransition::get_class_type())) {
 			     GeomBinTransition::get_class_type())) {
-	requested_bin = get_bin(bin_attrib->get_bin());
 	draw_order = bin_attrib->get_draw_order();
 	draw_order = bin_attrib->get_draw_order();
+	bin_name = bin_attrib->get_bin();
+	requested_bin = get_bin(bin_name);
+      }
+
+      if (requested_bin == (GeomBin *)NULL) {
+	// If we don't have a bin by this name, create one.
+	cull_cat.warning()
+	  << "Bin " << bin_name << " is unknown; creating a default bin.\n";
+
+	if (bin_name == "fixed") {
+	  requested_bin = new GeomBinFixed(bin_name);
+	  requested_bin->set_sort(20);
+	} else {
+	  requested_bin = new GeomBinNormal(bin_name);
+	}
+	requested_bin->set_traverser(this);
       }
       }
 
 
       requested_bin->record_current_state(_gsg, cs, draw_order, this);
       requested_bin->record_current_state(_gsg, cs, draw_order, this);
@@ -259,7 +373,10 @@ draw() {
 	<< "Drawing " << _sub_bins.size() << " bins.\n";
 	<< "Drawing " << _sub_bins.size() << " bins.\n";
     }
     }
     for (sbi = _sub_bins.begin(); sbi != _sub_bins.end(); ++sbi) {
     for (sbi = _sub_bins.begin(); sbi != _sub_bins.end(); ++sbi) {
-      (*sbi).second->draw(this);
+      GeomBin *bin = (*sbi).second;
+      if (bin->is_active()) {
+	bin->draw(this);
+      }
     }
     }
   }
   }
 }
 }
@@ -565,13 +682,28 @@ attach_toplevel_bin(GeomBin *bin) {
       << "Attaching toplevel bin " << *bin << "\n";
       << "Attaching toplevel bin " << *bin << "\n";
   }
   }
 
 
+  const string &bin_name = bin->get_name();
+
   // Insert the new bin by name.
   // Insert the new bin by name.
-  bool inserted = 
-    _toplevel_bins.insert(ToplevelBins::value_type(bin->get_name(), bin)).second;
+  pair<ToplevelBins::iterator, bool> result = 
+    _toplevel_bins.insert(ToplevelBins::value_type(bin_name, bin));
+
+  if (!result.second) {
+    // There was already a bin by the same name name in this
+    // traverser.  We should therefore detach this bin.
+    GeomBin *other_bin = (*result.first).second;
+    if (other_bin != bin) {
+      other_bin->clear_traverser();
+    }
+
+    result =
+      _toplevel_bins.insert(ToplevelBins::value_type(bin_name, bin));
+    nassertv(result.second);
+  }
 
 
-  // If this assertion fails, there was already a bin by the same name
-  // in this traverser, an error condition.
-  nassertv(inserted);
+  if (bin_name == "default") {
+    _default_bin = bin;
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -612,9 +744,15 @@ detach_toplevel_bin(GeomBin *bin) {
       << "Detaching toplevel bin " << *bin << "\n";
       << "Detaching toplevel bin " << *bin << "\n";
   }
   }
 
 
-  ToplevelBins::iterator tbi = _toplevel_bins.find(bin->get_name());
+  const string &bin_name = bin->get_name();
+
+  ToplevelBins::iterator tbi = _toplevel_bins.find(bin_name);
   nassertv(tbi != _toplevel_bins.end());
   nassertv(tbi != _toplevel_bins.end());
   _toplevel_bins.erase(tbi);
   _toplevel_bins.erase(tbi);
+
+  if (bin_name == "default") {
+    _default_bin = (GeomBin *)NULL;
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 11 - 8
panda/src/cull/cullTraverser.h

@@ -41,10 +41,15 @@ public:
 		const ArcChain &arc_chain = ArcChain());
 		const ArcChain &arc_chain = ArcChain());
   virtual ~CullTraverser();
   virtual ~CullTraverser();
 
 
-  INLINE void set_default_bin(GeomBin *bin);
-  INLINE GeomBin *get_default_bin() const;
-  INLINE bool has_bin(const string &name) const;
-  INLINE GeomBin *get_bin(const string &name) const;
+PUBLISHED:
+  bool has_bin(const string &name) const;
+  GeomBin *get_bin(const string &name) const;
+  void clear_bins();
+
+  void output(ostream &out) const;
+  void write(ostream &out, int indent_level = 0) const;
+
+public:
 
 
   virtual void traverse(Node *root, 
   virtual void traverse(Node *root, 
 			const AllAttributesWrapper &initial_state,
 			const AllAttributesWrapper &initial_state,
@@ -57,11 +62,9 @@ public:
   INLINE void draw_direct(const ArcChain &arc_chain,
   INLINE void draw_direct(const ArcChain &arc_chain,
 			  const AllAttributesWrapper &initial_state);
 			  const AllAttributesWrapper &initial_state);
 
 
-PUBLISHED:
-  void output(ostream &out) const;
-  void write(ostream &out, int indent_level = 0) const;
-
 private:
 private:
+  void setup_initial_bins();
+
   void draw();
   void draw();
   void clean_out_old_states();
   void clean_out_old_states();
 
 

+ 13 - 0
panda/src/cull/geomBin.I

@@ -15,6 +15,7 @@ GeomBin(const string &name) :
   _traverser = (CullTraverser *)NULL;
   _traverser = (CullTraverser *)NULL;
   _is_attached = false;
   _is_attached = false;
   _sort = 0;
   _sort = 0;
+  _active = true;
   _parent = (GeomBin *)NULL;
   _parent = (GeomBin *)NULL;
 }
 }
 
 
@@ -30,6 +31,18 @@ get_sort() const {
   return _sort;
   return _sort;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomBin::get_active
+//       Access: Public
+//  Description: Returns the active flag of this particular bin.  If
+//               the flag is false, the contents of the bin are not
+//               rendered.
+////////////////////////////////////////////////////////////////////
+INLINE bool GeomBin::
+is_active() const {
+  return _active;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomBin::has_traverser
 //     Function: GeomBin::has_traverser
 //       Access: Public
 //       Access: Public

+ 83 - 0
panda/src/cull/geomBin.cxx

@@ -6,10 +6,15 @@
 #include "geomBin.h"
 #include "geomBin.h"
 #include "cullTraverser.h"
 #include "cullTraverser.h"
 #include "config_cull.h"
 #include "config_cull.h"
+#include "geomBinNormal.h"
+#include "geomBinUnsorted.h"
+#include "geomBinFixed.h"
+#include "geomBinBackToFront.h"
 
 
 #include <indent.h>
 #include <indent.h>
 #include <nodeAttributes.h>
 #include <nodeAttributes.h>
 #include <graphicsStateGuardian.h>
 #include <graphicsStateGuardian.h>
+#include <string_utils.h>
 
 
 TypeHandle GeomBin::_type_handle;
 TypeHandle GeomBin::_type_handle;
 
 
@@ -105,6 +110,18 @@ set_sort(int sort) {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomBin::set_active
+//       Access: Public, Virtual
+//  Description: Sets the active flag of this particular bin.  If the
+//               flag is false, the contents of the bin are not
+//               rendered.
+////////////////////////////////////////////////////////////////////
+void GeomBin::
+set_active(bool active) {
+  _active = active;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomBin::set_traverser
 //     Function: GeomBin::set_traverser
 //       Access: Public
 //       Access: Public
@@ -157,6 +174,72 @@ clear_traverser() {
   return keep;
   return keep;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomBin::parse_bin_type
+//       Access: Public, Static
+//  Description: Converts from the given string representation to one
+//               of the derived GeomBin type handles.  Returns
+//               TypeHandle::none() if the string does not match any
+//               known bin type.
+////////////////////////////////////////////////////////////////////
+TypeHandle GeomBin::
+parse_bin_type(const string &bin_type) {
+  if (cmp_nocase_uh(bin_type, "normal") == 0) {
+    return GeomBinNormal::get_class_type();
+
+  } else if (cmp_nocase_uh(bin_type, "unsorted") == 0) {
+    return GeomBinUnsorted::get_class_type();
+
+  } else if (cmp_nocase_uh(bin_type, "state_sorted") == 0) {
+    // For now, GeomBinUnsorted stands in surprisingly well for
+    // GeomBinStateSorted.  This is because the states are already
+    // reasonably sorted as they come out of the CullTraverser, so it
+    // doesn't matter much whether the bin sorts it further.
+    return GeomBinUnsorted::get_class_type();
+
+  } else if (cmp_nocase_uh(bin_type, "statesorted") == 0) {
+    return GeomBinUnsorted::get_class_type();
+
+  } else if (cmp_nocase_uh(bin_type, "fixed") == 0) {
+    return GeomBinFixed::get_class_type();
+
+  } else if (cmp_nocase_uh(bin_type, "back_to_front") == 0) {
+    return GeomBinBackToFront::get_class_type();
+
+  } else if (cmp_nocase_uh(bin_type, "backtofront") == 0) {
+    return GeomBinBackToFront::get_class_type();
+
+  } else {
+    return TypeHandle::none();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomBin::make_bin
+//       Access: Public, Static
+//  Description: Creates and returns a new GeomBin of the appropriate
+//               type as indicated by the TypeHandle.  Returns NULL if
+//               the TypeHandle does not reflect a known GeomBin type.
+////////////////////////////////////////////////////////////////////
+PT(GeomBin) GeomBin::
+make_bin(TypeHandle type, const string &name) {
+  if (type == GeomBinNormal::get_class_type()) {
+    return new GeomBinNormal(name);
+
+  } else if (type == GeomBinUnsorted::get_class_type()) {
+    return new GeomBinUnsorted(name);
+
+  } else if (type == GeomBinFixed::get_class_type()) {
+    return new GeomBinFixed(name);
+
+  } else if (type == GeomBinBackToFront::get_class_type()) {
+    return new GeomBinBackToFront(name);
+
+  } else {
+    return NULL;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomBin::attach
 //     Function: GeomBin::attach
 //       Access: Protected, Virtual
 //       Access: Protected, Virtual

+ 7 - 0
panda/src/cull/geomBin.h

@@ -45,6 +45,9 @@ PUBLISHED:
   INLINE int get_sort() const;
   INLINE int get_sort() const;
   void set_sort(int sort);
   void set_sort(int sort);
 
 
+  virtual void set_active(bool active);
+  INLINE bool is_active() const;
+
   void set_traverser(CullTraverser *traverser);
   void set_traverser(CullTraverser *traverser);
   INLINE bool has_traverser() const;
   INLINE bool has_traverser() const;
   INLINE CullTraverser *get_traverser() const;
   INLINE CullTraverser *get_traverser() const;
@@ -67,6 +70,9 @@ public:
 
 
   virtual void draw(CullTraverser *trav)=0;
   virtual void draw(CullTraverser *trav)=0;
 
 
+  static TypeHandle parse_bin_type(const string &bin_type);
+  static PT(GeomBin) make_bin(TypeHandle type, const string &name);
+
 protected:
 protected:
   INLINE void claim_cull_state(CullState *cs);
   INLINE void claim_cull_state(CullState *cs);
   INLINE void disclaim_cull_state(CullState *cs);
   INLINE void disclaim_cull_state(CullState *cs);
@@ -77,6 +83,7 @@ protected:
   CullTraverser *_traverser;
   CullTraverser *_traverser;
   bool _is_attached;
   bool _is_attached;
   int _sort;
   int _sort;
+  bool _active;
   GeomBin *_parent;
   GeomBin *_parent;
 
 
 public:
 public:

+ 2 - 2
panda/src/cull/geomBinAttribute.I

@@ -43,9 +43,9 @@ set_on(const string &bin, int draw_order) {
 //               represents.  It is only valid to call this if is_on()
 //               represents.  It is only valid to call this if is_on()
 //               has returned true.
 //               has returned true.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE string GeomBinAttribute::
+INLINE const string &GeomBinAttribute::
 get_bin() const {
 get_bin() const {
-  nassertr(is_on(), string());
+  nassertr(is_on(), _value);
   return _value;
   return _value;
 }
 }
 
 

+ 1 - 1
panda/src/cull/geomBinAttribute.h

@@ -22,7 +22,7 @@ public:
   INLINE GeomBinAttribute(const string &bin, int draw_order = 0);
   INLINE GeomBinAttribute(const string &bin, int draw_order = 0);
 
 
   INLINE void set_on(const string &bin, int draw_order = 0);
   INLINE void set_on(const string &bin, int draw_order = 0);
-  INLINE string get_bin() const;
+  INLINE const string &get_bin() const;
   INLINE int get_draw_order() const;
   INLINE int get_draw_order() const;
 
 
   virtual TypeHandle get_handle() const;
   virtual TypeHandle get_handle() const;

+ 17 - 0
panda/src/cull/geomBinGroup.cxx

@@ -81,6 +81,23 @@ remove_bin(int n) {
   return sub_bin;
   return sub_bin;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomBinGroup::set_active
+//       Access: Public, Virtual
+//  Description: Sets the active flag of this particular bin, and all
+//               of its child bins.  If the flag is false, the
+//               contents of the bin are not rendered.
+////////////////////////////////////////////////////////////////////
+void GeomBinGroup::
+set_active(bool active) {
+  GeomBin::set_active(active);
+
+  SubBins::iterator sbi;
+  for (sbi = _sub_bins.begin(); sbi != _sub_bins.end(); ++sbi) {
+    (*sbi)->set_active(active);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomBinGroup::clear_current_states
 //     Function: GeomBinGroup::clear_current_states
 //       Access: Public, Virtual
 //       Access: Public, Virtual

+ 2 - 0
panda/src/cull/geomBinGroup.h

@@ -32,6 +32,8 @@ PUBLISHED:
   INLINE GeomBin *get_bin(int n);
   INLINE GeomBin *get_bin(int n);
   PT(GeomBin) remove_bin(int n);
   PT(GeomBin) remove_bin(int n);
 
 
+  virtual void set_active(bool active);
+
 public:
 public:
   virtual int choose_bin(CullState *cs) const=0;
   virtual int choose_bin(CullState *cs) const=0;
 
 

+ 2 - 2
panda/src/cull/geomBinTransition.I

@@ -58,9 +58,9 @@ set_on(const string &bin, int draw_order) {
 //               represents.  It is only valid to call this if is_on()
 //               represents.  It is only valid to call this if is_on()
 //               has returned true.
 //               has returned true.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE string GeomBinTransition::
+INLINE const string &GeomBinTransition::
 get_bin() const {
 get_bin() const {
-  nassertr(is_on(), string());
+  nassertr(is_on(), _value);
   return _value;
   return _value;
 }
 }
 
 

+ 1 - 1
panda/src/cull/geomBinTransition.h

@@ -22,7 +22,7 @@ PUBLISHED:
   INLINE static GeomBinTransition off();
   INLINE static GeomBinTransition off();
 
 
   INLINE void set_on(const string &bin, int draw_order);
   INLINE void set_on(const string &bin, int draw_order);
-  INLINE string get_bin() const;
+  INLINE const string &get_bin() const;
   INLINE int get_draw_order() const;
   INLINE int get_draw_order() const;
 
 
 public:  
 public:  

+ 134 - 0
panda/src/putil/string_utils.cxx

@@ -61,3 +61,137 @@ downcase(const string &s) {
   return result;
   return result;
 }
 }
 
 
+
+////////////////////////////////////////////////////////////////////
+//     Function: extract_words
+//  Description: Divides the string into a number of words according
+//               to whitespace.  The words vector should be cleared by
+//               the user before calling; otherwise, the list of words
+//               in the string will be appended to the end of whatever
+//               was there before.
+//
+//               The return value is the number of words extracted.
+////////////////////////////////////////////////////////////////////
+int
+extract_words(const string &str, vector_string &words) {
+  int num_words = 0;
+
+  size_t pos = 0;
+  while (pos < str.length() && isspace(str[pos])) {
+    pos++;
+  }
+  while (pos < str.length()) {
+    size_t word_start = pos;
+    while (pos < str.length() && !isspace(str[pos])) {
+      pos++;
+    }
+    words.push_back(str.substr(word_start, pos - word_start));
+    num_words++;
+
+    while (pos < str.length() && isspace(str[pos])) {
+      pos++;
+    }
+  }
+
+  return num_words;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: trim_left
+//  Description: Returns a new string representing the contents of the
+//               given string with the leading whitespace removed.
+////////////////////////////////////////////////////////////////////
+string 
+trim_left(const string &str) {
+  size_t begin = 0;
+  while (begin < str.size() && isspace(str[begin])) {
+    begin++;
+  }
+
+  return str.substr(begin);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: trim_right
+//  Description: Returns a new string representing the contents of the
+//               given string with the trailing whitespace removed.
+////////////////////////////////////////////////////////////////////
+string 
+trim_right(const string &str) {
+  size_t begin = 0;
+  size_t end = str.size();
+  while (end > begin && isspace(str[end - 1])) {
+    end--;
+  }
+
+  return str.substr(begin, end - begin);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: string_to_int
+//  Description: A string-interface wrapper around the C library
+//               strtol().  This parses the ASCII representation of an
+//               integer, and then sets tail to everything that
+//               follows the first valid integer read.  If, on exit,
+//               str == tail, there was no valid integer in the
+//               source string; if !tail.empty(), there was garbage
+//               after the integer.
+//
+//               It is legal if str and tail refer to the same string.
+////////////////////////////////////////////////////////////////////
+int
+string_to_int(const string &str, string &tail) {
+  const char *nptr = str.c_str();
+  char *endptr;
+  int result = strtol(nptr, &endptr, 10);
+  tail = endptr;
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: string_to_int
+//  Description: Another flavor of string_to_int(), this one returns
+//               true if the string is a perfectly valid integer (and
+//               sets result to that value), or false otherwise.
+////////////////////////////////////////////////////////////////////
+bool
+string_to_int(const string &str, int &result) {
+  string tail;
+  result = string_to_int(str, tail);
+  return tail.empty();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: string_to_double
+//  Description: A string-interface wrapper around the C library
+//               strtol().  This parses the ASCII representation of an
+//               floating-point number, and then sets tail to
+//               everything that follows the first valid integer read.
+//               If, on exit, str == tail, there was no valid integer
+//               in the source string; if !tail.empty(), there was
+//               garbage after the number.
+//
+//               It is legal if str and tail refer to the same string.
+////////////////////////////////////////////////////////////////////
+double
+string_to_double(const string &str, string &tail) {
+  const char *nptr = str.c_str();
+  char *endptr;
+  double result = strtod(nptr, &endptr);
+  tail = endptr;
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: string_to_double
+//  Description: Another flavor of string_to_double(), this one
+//               returns true if the string is a perfectly valid
+//               number (and sets result to that value), or false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+bool
+string_to_double(const string &str, double &result) {
+  string tail;
+  result = string_to_double(str, tail);
+  return tail.empty();
+}

+ 14 - 0
panda/src/putil/string_utils.h

@@ -9,6 +9,7 @@
 #include <pandabase.h>
 #include <pandabase.h>
 
 
 #include <string>
 #include <string>
+#include <vector_string.h>
 
 
 // Case-insensitive string comparison, from Stroustrup's C++ third edition.
 // Case-insensitive string comparison, from Stroustrup's C++ third edition.
 // Works like strcmp().
 // Works like strcmp().
@@ -20,6 +21,19 @@ EXPCL_PANDA int cmp_nocase_uh(const string &s, const string &s2);
 // Returns the string converted to lowercase.
 // Returns the string converted to lowercase.
 EXPCL_PANDA string downcase(const string &s);
 EXPCL_PANDA string downcase(const string &s);
 
 
+// Separates the string into words according to whitespace.
+EXPCL_PANDA int extract_words(const string &str, vector_string &words);
+
+// Trims leading and/or trailing whitespace from the string.
+EXPCL_PANDA string trim_left(const string &str);
+EXPCL_PANDA string trim_right(const string &str);
+
+// Functions to parse numeric values out of a string.
+EXPCL_PANDA int string_to_int(const string &str, string &tail);
+EXPCL_PANDA bool string_to_int(const string &str, int &result);
+EXPCL_PANDA double string_to_double(const string &str, string &tail);
+EXPCL_PANDA bool string_to_double(const string &str, double &result);
+
 // Convenience function to make a string from anything that has an
 // Convenience function to make a string from anything that has an
 // ostream operator.
 // ostream operator.
 template<class Thing>
 template<class Thing>

+ 1 - 1
pandatool/src/bam/Sources.pp

@@ -3,7 +3,7 @@
   #define LOCAL_LIBS \
   #define LOCAL_LIBS \
     eggbase progbase
     eggbase progbase
   #define OTHER_LIBS \
   #define OTHER_LIBS \
-    loader:c egg:c sgraphutil:c sgattrib:c sgraph:c pnmimagetypes:c \
+    cull:c loader:c egg:c sgraphutil:c sgattrib:c sgraph:c pnmimagetypes:c \
     graph:c putil:c express:c panda:m pandaexpress:m \
     graph:c putil:c express:c panda:m pandaexpress:m \
     interrogatedb:c dtoolutil:c dconfig:c dtool:m pystub
     interrogatedb:c dtoolutil:c dconfig:c dtool:m pystub
   #define UNIX_SYS_LIBS \
   #define UNIX_SYS_LIBS \

+ 48 - 2
pandatool/src/bam/bamInfo.cxx

@@ -8,6 +8,7 @@
 #include <bamFile.h>
 #include <bamFile.h>
 #include <node.h>
 #include <node.h>
 #include <renderRelation.h>
 #include <renderRelation.h>
+#include <geomNode.h>
 
 
 #include <vector>
 #include <vector>
 
 
@@ -25,6 +26,16 @@ BamInfo() {
   clear_runlines();
   clear_runlines();
   add_runline("[opts] input.bam [input.bam ... ]");
   add_runline("[opts] input.bam [input.bam ... ]");
 
 
+  add_option
+    ("t", "", 0, 
+     "List explicitly each transition in the hierarchy.",
+     &BamInfo::dispatch_none, &_verbose_transitions);
+
+  add_option
+    ("g", "", 0, 
+     "Output verbose information about the each Geom in the Bam file.",
+     &BamInfo::dispatch_none, &_verbose_geoms);
+
   _num_scene_graphs = 0;
   _num_scene_graphs = 0;
 }
 }
 
 
@@ -46,10 +57,10 @@ run() {
   }
   }
 
 
   if (_num_scene_graphs > 0) {
   if (_num_scene_graphs > 0) {
-    nout << "\rScene graph statistics:\n";
+    nout << "\nScene graph statistics:\n";
     _analyzer.write(nout, 2);
     _analyzer.write(nout, 2);
   }
   }
-  nout << "\r";
+  nout << "\n";
 
 
   if (!okflag) {
   if (!okflag) {
     // Exit with an error if any of the files was unreadable.
     // Exit with an error if any of the files was unreadable.
@@ -145,6 +156,10 @@ describe_scene_graph(Node *node) {
 
 
   nout << "  " << num_nodes << " nodes, bounding volume is "
   nout << "  " << num_nodes << " nodes, bounding volume is "
        << arc->get_bound() << "\n";
        << arc->get_bound() << "\n";
+
+  if (_verbose_geoms || _verbose_transitions) {
+    list_hierarchy(node, 0);
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -159,6 +174,37 @@ describe_general_object(TypedWriteable *object) {
   nout << "  " << object->get_type() << "\n";
   nout << "  " << object->get_type() << "\n";
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: BamInfo::list_hierarchy
+//       Access: Private
+//  Description: Outputs the hierarchy and all of the verbose GeomNode
+//               information.
+////////////////////////////////////////////////////////////////////
+void BamInfo::
+list_hierarchy(Node *node, int indent_level) {
+  indent(nout, indent_level) << *node << "\n";
+
+  if (_verbose_geoms && node->is_of_type(GeomNode::get_class_type())) {
+    GeomNode *geom_node;
+    DCAST_INTO_V(geom_node, node);
+    geom_node->write_verbose(nout, indent_level);
+  }
+
+  int num_children = node->get_num_children(RenderRelation::get_class_type());
+  for (int i = 0; i < num_children; i++) {
+    NodeRelation *arc = node->get_child(RenderRelation::get_class_type(), i);
+    nout << "\n";
+    indent(nout, indent_level + 2) << *arc << "\n";
+
+    if (_verbose_transitions) {
+      arc->write_transitions(nout, indent_level + 2);
+      nout << "\n";
+    }
+
+    list_hierarchy(arc->get_child(), indent_level + 4);
+  }
+}
+
 int main(int argc, char *argv[]) {
 int main(int argc, char *argv[]) {
   BamInfo prog;
   BamInfo prog;
   prog.parse_command_line(argc, argv);
   prog.parse_command_line(argc, argv);

+ 4 - 0
pandatool/src/bam/bamInfo.h

@@ -34,10 +34,14 @@ private:
   bool get_info(const Filename &filename);
   bool get_info(const Filename &filename);
   void describe_scene_graph(Node *node);
   void describe_scene_graph(Node *node);
   void describe_general_object(TypedWriteable *object);
   void describe_general_object(TypedWriteable *object);
+  void list_hierarchy(Node *node, int indent_level);
 
 
   typedef vector<Filename> Filenames;
   typedef vector<Filename> Filenames;
   Filenames _filenames;
   Filenames _filenames;
 
 
+  bool _verbose_geoms;
+  bool _verbose_transitions;
+
   int _num_scene_graphs;
   int _num_scene_graphs;
   SceneGraphAnalyzer _analyzer;
   SceneGraphAnalyzer _analyzer;
 };
 };

+ 0 - 109
pandatool/src/egg-palettize/pal_string_utils.cxx

@@ -9,115 +9,6 @@
 #include <pnmFileTypeRegistry.h>
 #include <pnmFileTypeRegistry.h>
 
 
 
 
-string 
-trim_left(const string &str) {
-  size_t begin = 0;
-  while (begin < str.size() && isspace(str[begin])) {
-    begin++;
-  }
-
-  return str.substr(begin);
-}
-
-string 
-trim_right(const string &str) {
-  size_t begin = 0;
-  size_t end = str.size();
-  while (end > begin && isspace(str[end - 1])) {
-    end--;
-  }
-
-  return str.substr(begin, end - begin);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: string_to_int
-//  Description: A string-interface wrapper around the C library
-//               strtol().  This parses the ASCII representation of an
-//               integer, and then sets tail to everything that
-//               follows the first valid integer read.  If, on exit,
-//               str == tail, there was no valid integer in the
-//               source string; if !tail.empty(), there was garbage
-//               after the integer.
-//
-//               It is legal if str and tail refer to the same string.
-////////////////////////////////////////////////////////////////////
-int
-string_to_int(const string &str, string &tail) {
-  const char *nptr = str.c_str();
-  char *endptr;
-  int result = strtol(nptr, &endptr, 10);
-  tail = endptr;
-  return result;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: string_to_int
-//  Description: Another flavor of string_to_int(), this one returns
-//               true if the string is a perfectly valid integer (and
-//               sets result to that value), or false otherwise.
-////////////////////////////////////////////////////////////////////
-bool
-string_to_int(const string &str, int &result) {
-  string tail;
-  result = string_to_int(str, tail);
-  return tail.empty();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: string_to_double
-//  Description: A string-interface wrapper around the C library
-//               strtol().  This parses the ASCII representation of an
-//               floating-point number, and then sets tail to
-//               everything that follows the first valid integer read.
-//               If, on exit, str == tail, there was no valid integer
-//               in the source string; if !tail.empty(), there was
-//               garbage after the number.
-//
-//               It is legal if str and tail refer to the same string.
-////////////////////////////////////////////////////////////////////
-double
-string_to_double(const string &str, string &tail) {
-  const char *nptr = str.c_str();
-  char *endptr;
-  double result = strtod(nptr, &endptr);
-  tail = endptr;
-  return result;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: string_to_double
-//  Description: Another flavor of string_to_double(), this one
-//               returns true if the string is a perfectly valid
-//               number (and sets result to that value), or false
-//               otherwise.
-////////////////////////////////////////////////////////////////////
-bool
-string_to_double(const string &str, double &result) {
-  string tail;
-  result = string_to_double(str, tail);
-  return tail.empty();
-}
-
-void
-extract_words(const string &str, vector_string &words) {
-  size_t pos = 0;
-  while (pos < str.length() && isspace(str[pos])) {
-    pos++;
-  }
-  while (pos < str.length()) {
-    size_t word_start = pos;
-    while (pos < str.length() && !isspace(str[pos])) {
-      pos++;
-    }
-    words.push_back(str.substr(word_start, pos - word_start));
-
-    while (pos < str.length() && isspace(str[pos])) {
-      pos++;
-    }
-  }
-}
-
 // Extracts the first word of the string into param, and the remainder
 // Extracts the first word of the string into param, and the remainder
 // of the line into value.
 // of the line into value.
 void 
 void 

+ 1 - 10
pandatool/src/egg-palettize/pal_string_utils.h

@@ -7,19 +7,10 @@
 #define PAL_STRING_UTILS_H
 #define PAL_STRING_UTILS_H
 
 
 #include <pandatoolbase.h>
 #include <pandatoolbase.h>
-#include <vector_string.h>
+#include <string_utils.h>
 
 
 class PNMFileType;
 class PNMFileType;
 
 
-string trim_left(const string &str);
-string trim_right(const string &str);
-
-int string_to_int(const string &str, string &tail);
-bool string_to_int(const string &str, int &result);
-double string_to_double(const string &str, string &tail);
-bool string_to_double(const string &str, double &result);
-
-void extract_words(const string &str, vector_string &words);
 void extract_param_value(const string &str, string &param, string &value);
 void extract_param_value(const string &str, string &param, string &value);
 
 
 bool parse_image_type_request(const string &word, PNMFileType *&color_type,
 bool parse_image_type_request(const string &word, PNMFileType *&color_type,