From 594fc23c3b43d30f7aac3a7696111893c0174468 Mon Sep 17 00:00:00 2001 From: David Rose Date: Thu, 18 Jan 2001 18:55:30 +0000 Subject: [PATCH] *** empty log message *** --- panda/src/cull/config_cull.cxx | 2 +- panda/src/cull/config_cull.h | 2 + panda/src/cull/cullTraverser.I | 57 ---- panda/src/cull/cullTraverser.cxx | 258 ++++++++++++++---- panda/src/cull/cullTraverser.h | 19 +- panda/src/cull/geomBin.I | 13 + panda/src/cull/geomBin.cxx | 83 ++++++ panda/src/cull/geomBin.h | 7 + panda/src/cull/geomBinAttribute.I | 4 +- panda/src/cull/geomBinAttribute.h | 2 +- panda/src/cull/geomBinGroup.cxx | 17 ++ panda/src/cull/geomBinGroup.h | 2 + panda/src/cull/geomBinTransition.I | 4 +- panda/src/cull/geomBinTransition.h | 2 +- panda/src/putil/string_utils.cxx | 134 +++++++++ panda/src/putil/string_utils.h | 14 + pandatool/src/bam/Sources.pp | 2 +- pandatool/src/bam/bamInfo.cxx | 50 +++- pandatool/src/bam/bamInfo.h | 4 + .../src/egg-palettize/pal_string_utils.cxx | 109 -------- .../src/egg-palettize/pal_string_utils.h | 11 +- 21 files changed, 542 insertions(+), 254 deletions(-) diff --git a/panda/src/cull/config_cull.cxx b/panda/src/cull/config_cull.cxx index 7e1aaf95ac..196e76144e 100644 --- a/panda/src/cull/config_cull.cxx +++ b/panda/src/cull/config_cull.cxx @@ -17,7 +17,7 @@ #include -Configure(config_cull); +ConfigureDef(config_cull); NotifyCategoryDef(cull, ""); ConfigureFn(config_cull) { diff --git a/panda/src/cull/config_cull.h b/panda/src/cull/config_cull.h index 2602f702c2..ad97c4a1d1 100644 --- a/panda/src/cull/config_cull.h +++ b/panda/src/cull/config_cull.h @@ -8,7 +8,9 @@ #include #include +#include +ConfigureDecl(config_cull, EXPCL_PANDA, EXPTP_PANDA); NotifyCategoryDecl(cull, EXPCL_PANDA, EXPTP_PANDA); extern const bool cull_force_update; diff --git a/panda/src/cull/cullTraverser.I b/panda/src/cull/cullTraverser.I index a89e61a31b..b32380ef9a 100644 --- a/panda/src/cull/cullTraverser.I +++ b/panda/src/cull/cullTraverser.I @@ -9,63 +9,6 @@ #include #include -//////////////////////////////////////////////////////////////////// -// 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 // Access: Public diff --git a/panda/src/cull/cullTraverser.cxx b/panda/src/cull/cullTraverser.cxx index c59f4b615e..eada5afd4c 100644 --- a/panda/src/cull/cullTraverser.cxx +++ b/panda/src/cull/cullTraverser.cxx @@ -23,6 +23,7 @@ #include // for implicit_app_traversal #include // for support_decals #include +#include TypeHandle CullTraverser::_type_handle; @@ -43,16 +44,9 @@ CullTraverser(GraphicsStateGuardian *gsg, TypeHandle graph_type, const ArcChain &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; + + setup_initial_bins(); } //////////////////////////////////////////////////////////////////// @@ -63,6 +57,48 @@ CullTraverser(GraphicsStateGuardian *gsg, TypeHandle graph_type, CullTraverser:: ~CullTraverser() { // 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 // operation. while (!_toplevel_bins.empty()) { @@ -73,6 +109,54 @@ CullTraverser:: } 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"; } - nassertv(!_toplevel_bins.empty()); - nassertv(!_sub_bins.empty()); - bool is_initial = (_nested_count == 0); if (is_initial) { if (cull_force_update) { @@ -157,51 +238,67 @@ 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:: -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); + + default_bin->set_traverser(this); + fixed->set_traverser(this); + + + // 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); + } + } } } - - 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); -} //////////////////////////////////////////////////////////////////// // Function: CullTraverser::draw @@ -238,15 +335,32 @@ draw() { if (!cs->is_empty()) { 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; int draw_order = 0; + // Check the requested bin for the Geoms in this state. const GeomBinAttribute *bin_attrib; if (get_attribute_into(bin_attrib, cs->get_attributes(), GeomBinTransition::get_class_type())) { - requested_bin = get_bin(bin_attrib->get_bin()); 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); @@ -259,7 +373,10 @@ draw() { << "Drawing " << _sub_bins.size() << " bins.\n"; } 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"; } - // Insert the new bin by name. - bool inserted = - _toplevel_bins.insert(ToplevelBins::value_type(bin->get_name(), bin)).second; + const string &bin_name = bin->get_name(); - // If this assertion fails, there was already a bin by the same name - // in this traverser, an error condition. - nassertv(inserted); + // Insert the new bin by name. + pair 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 (bin_name == "default") { + _default_bin = bin; + } } //////////////////////////////////////////////////////////////////// @@ -612,9 +744,15 @@ detach_toplevel_bin(GeomBin *bin) { << "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()); _toplevel_bins.erase(tbi); + + if (bin_name == "default") { + _default_bin = (GeomBin *)NULL; + } } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/cull/cullTraverser.h b/panda/src/cull/cullTraverser.h index f2af51a3c1..87a7fd60ef 100644 --- a/panda/src/cull/cullTraverser.h +++ b/panda/src/cull/cullTraverser.h @@ -41,10 +41,15 @@ public: const ArcChain &arc_chain = ArcChain()); 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, const AllAttributesWrapper &initial_state, @@ -57,11 +62,9 @@ public: INLINE void draw_direct(const ArcChain &arc_chain, const AllAttributesWrapper &initial_state); -PUBLISHED: - void output(ostream &out) const; - void write(ostream &out, int indent_level = 0) const; - private: + void setup_initial_bins(); + void draw(); void clean_out_old_states(); diff --git a/panda/src/cull/geomBin.I b/panda/src/cull/geomBin.I index 0ec92790b1..a3e43f22eb 100644 --- a/panda/src/cull/geomBin.I +++ b/panda/src/cull/geomBin.I @@ -15,6 +15,7 @@ GeomBin(const string &name) : _traverser = (CullTraverser *)NULL; _is_attached = false; _sort = 0; + _active = true; _parent = (GeomBin *)NULL; } @@ -30,6 +31,18 @@ get_sort() const { 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 // Access: Public diff --git a/panda/src/cull/geomBin.cxx b/panda/src/cull/geomBin.cxx index 66c4387cef..7946007b4d 100644 --- a/panda/src/cull/geomBin.cxx +++ b/panda/src/cull/geomBin.cxx @@ -6,10 +6,15 @@ #include "geomBin.h" #include "cullTraverser.h" #include "config_cull.h" +#include "geomBinNormal.h" +#include "geomBinUnsorted.h" +#include "geomBinFixed.h" +#include "geomBinBackToFront.h" #include #include #include +#include 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 // Access: Public @@ -157,6 +174,72 @@ clear_traverser() { 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 // Access: Protected, Virtual diff --git a/panda/src/cull/geomBin.h b/panda/src/cull/geomBin.h index 04dc94b77f..4ab16681d9 100644 --- a/panda/src/cull/geomBin.h +++ b/panda/src/cull/geomBin.h @@ -45,6 +45,9 @@ PUBLISHED: INLINE int get_sort() const; void set_sort(int sort); + virtual void set_active(bool active); + INLINE bool is_active() const; + void set_traverser(CullTraverser *traverser); INLINE bool has_traverser() const; INLINE CullTraverser *get_traverser() const; @@ -67,6 +70,9 @@ public: 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: INLINE void claim_cull_state(CullState *cs); INLINE void disclaim_cull_state(CullState *cs); @@ -77,6 +83,7 @@ protected: CullTraverser *_traverser; bool _is_attached; int _sort; + bool _active; GeomBin *_parent; public: diff --git a/panda/src/cull/geomBinAttribute.I b/panda/src/cull/geomBinAttribute.I index c06524f94b..ce979a4329 100644 --- a/panda/src/cull/geomBinAttribute.I +++ b/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() // has returned true. //////////////////////////////////////////////////////////////////// -INLINE string GeomBinAttribute:: +INLINE const string &GeomBinAttribute:: get_bin() const { - nassertr(is_on(), string()); + nassertr(is_on(), _value); return _value; } diff --git a/panda/src/cull/geomBinAttribute.h b/panda/src/cull/geomBinAttribute.h index 718fdf7b5f..b31a5316c6 100644 --- a/panda/src/cull/geomBinAttribute.h +++ b/panda/src/cull/geomBinAttribute.h @@ -22,7 +22,7 @@ public: INLINE GeomBinAttribute(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; virtual TypeHandle get_handle() const; diff --git a/panda/src/cull/geomBinGroup.cxx b/panda/src/cull/geomBinGroup.cxx index 37f50bdd88..cdadd00314 100644 --- a/panda/src/cull/geomBinGroup.cxx +++ b/panda/src/cull/geomBinGroup.cxx @@ -81,6 +81,23 @@ remove_bin(int n) { 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 // Access: Public, Virtual diff --git a/panda/src/cull/geomBinGroup.h b/panda/src/cull/geomBinGroup.h index ee241a23b0..db226fec0c 100644 --- a/panda/src/cull/geomBinGroup.h +++ b/panda/src/cull/geomBinGroup.h @@ -32,6 +32,8 @@ PUBLISHED: INLINE GeomBin *get_bin(int n); PT(GeomBin) remove_bin(int n); + virtual void set_active(bool active); + public: virtual int choose_bin(CullState *cs) const=0; diff --git a/panda/src/cull/geomBinTransition.I b/panda/src/cull/geomBinTransition.I index 282a952308..95b9ff70b6 100644 --- a/panda/src/cull/geomBinTransition.I +++ b/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() // has returned true. //////////////////////////////////////////////////////////////////// -INLINE string GeomBinTransition:: +INLINE const string &GeomBinTransition:: get_bin() const { - nassertr(is_on(), string()); + nassertr(is_on(), _value); return _value; } diff --git a/panda/src/cull/geomBinTransition.h b/panda/src/cull/geomBinTransition.h index ea03017db9..1eb1b170c4 100644 --- a/panda/src/cull/geomBinTransition.h +++ b/panda/src/cull/geomBinTransition.h @@ -22,7 +22,7 @@ PUBLISHED: INLINE static GeomBinTransition off(); 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; public: diff --git a/panda/src/putil/string_utils.cxx b/panda/src/putil/string_utils.cxx index 2fd930585f..a4c7ea99d2 100644 --- a/panda/src/putil/string_utils.cxx +++ b/panda/src/putil/string_utils.cxx @@ -61,3 +61,137 @@ downcase(const string &s) { 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(); +} diff --git a/panda/src/putil/string_utils.h b/panda/src/putil/string_utils.h index 2157d8ea6d..5c485b6357 100644 --- a/panda/src/putil/string_utils.h +++ b/panda/src/putil/string_utils.h @@ -9,6 +9,7 @@ #include #include +#include // Case-insensitive string comparison, from Stroustrup's C++ third edition. // 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. 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 // ostream operator. template diff --git a/pandatool/src/bam/Sources.pp b/pandatool/src/bam/Sources.pp index 98f8bc105d..94ba0de98f 100644 --- a/pandatool/src/bam/Sources.pp +++ b/pandatool/src/bam/Sources.pp @@ -3,7 +3,7 @@ #define LOCAL_LIBS \ eggbase progbase #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 \ interrogatedb:c dtoolutil:c dconfig:c dtool:m pystub #define UNIX_SYS_LIBS \ diff --git a/pandatool/src/bam/bamInfo.cxx b/pandatool/src/bam/bamInfo.cxx index 0646c9a95d..f43d56bc21 100644 --- a/pandatool/src/bam/bamInfo.cxx +++ b/pandatool/src/bam/bamInfo.cxx @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -25,6 +26,16 @@ BamInfo() { clear_runlines(); 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; } @@ -46,10 +57,10 @@ run() { } if (_num_scene_graphs > 0) { - nout << "\rScene graph statistics:\n"; + nout << "\nScene graph statistics:\n"; _analyzer.write(nout, 2); } - nout << "\r"; + nout << "\n"; if (!okflag) { // 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 " << 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"; } +//////////////////////////////////////////////////////////////////// +// 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[]) { BamInfo prog; prog.parse_command_line(argc, argv); diff --git a/pandatool/src/bam/bamInfo.h b/pandatool/src/bam/bamInfo.h index 386ed42b72..d30c81e1d1 100644 --- a/pandatool/src/bam/bamInfo.h +++ b/pandatool/src/bam/bamInfo.h @@ -34,10 +34,14 @@ private: bool get_info(const Filename &filename); void describe_scene_graph(Node *node); void describe_general_object(TypedWriteable *object); + void list_hierarchy(Node *node, int indent_level); typedef vector Filenames; Filenames _filenames; + bool _verbose_geoms; + bool _verbose_transitions; + int _num_scene_graphs; SceneGraphAnalyzer _analyzer; }; diff --git a/pandatool/src/egg-palettize/pal_string_utils.cxx b/pandatool/src/egg-palettize/pal_string_utils.cxx index a0372da377..c5c832f647 100644 --- a/pandatool/src/egg-palettize/pal_string_utils.cxx +++ b/pandatool/src/egg-palettize/pal_string_utils.cxx @@ -9,115 +9,6 @@ #include -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 // of the line into value. void diff --git a/pandatool/src/egg-palettize/pal_string_utils.h b/pandatool/src/egg-palettize/pal_string_utils.h index c743791765..97f04128b6 100644 --- a/pandatool/src/egg-palettize/pal_string_utils.h +++ b/pandatool/src/egg-palettize/pal_string_utils.h @@ -7,19 +7,10 @@ #define PAL_STRING_UTILS_H #include -#include +#include 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 ¶m, string &value); bool parse_image_type_request(const string &word, PNMFileType *&color_type,