*** empty log message ***

This commit is contained in:
David Rose 2001-01-18 18:55:30 +00:00
parent c03729fba3
commit 594fc23c3b
21 changed files with 542 additions and 254 deletions

View File

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

View File

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

View File

@ -9,63 +9,6 @@
#include <directRenderTraverser.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
// Access: Public

View File

@ -23,6 +23,7 @@
#include <config_sgraphutil.h> // for implicit_app_traversal
#include <config_sgattrib.h> // for support_decals
#include <pStatTimer.h>
#include <string_utils.h>
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<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 (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;
}
}
////////////////////////////////////////////////////////////////////

View File

@ -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();

View File

@ -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

View File

@ -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 <indent.h>
#include <nodeAttributes.h>
#include <graphicsStateGuardian.h>
#include <string_utils.h>
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

View File

@ -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:

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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:

View File

@ -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();
}

View File

@ -9,6 +9,7 @@
#include <pandabase.h>
#include <string>
#include <vector_string.h>
// 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<class Thing>

View File

@ -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 \

View File

@ -8,6 +8,7 @@
#include <bamFile.h>
#include <node.h>
#include <renderRelation.h>
#include <geomNode.h>
#include <vector>
@ -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);

View File

@ -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<Filename> Filenames;
Filenames _filenames;
bool _verbose_geoms;
bool _verbose_transitions;
int _num_scene_graphs;
SceneGraphAnalyzer _analyzer;
};

View File

@ -9,115 +9,6 @@
#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
// of the line into value.
void

View File

@ -7,19 +7,10 @@
#define PAL_STRING_UTILS_H
#include <pandatoolbase.h>
#include <vector_string.h>
#include <string_utils.h>
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);
bool parse_image_type_request(const string &word, PNMFileType *&color_type,