Browse Source

improved memory tracking tools

David Rose 24 years ago
parent
commit
22288e7e48
46 changed files with 1652 additions and 293 deletions
  1. 3 0
      dtool/Config.Irix.pp
  2. 6 0
      dtool/Config.Linux.pp
  3. 3 2
      dtool/Config.Win32.pp
  4. 6 0
      dtool/LocalSetup.pp
  5. 6 2
      dtool/src/dtoolbase/Sources.pp
  6. 18 0
      dtool/src/dtoolbase/dtoolbase.cxx
  7. 40 0
      dtool/src/dtoolbase/dtoolbase_cc.h
  8. 51 0
      dtool/src/dtoolbase/pallocator.T
  9. 66 0
      dtool/src/dtoolbase/pallocator.h
  10. 44 0
      dtool/src/dtoolbase/pdeque.h
  11. 44 0
      dtool/src/dtoolbase/plist.h
  12. 56 0
      dtool/src/dtoolbase/pmap.h
  13. 56 0
      dtool/src/dtoolbase/pset.h
  14. 44 0
      dtool/src/dtoolbase/pvector.h
  15. 2 2
      dtool/src/dtoolutil/vector_src.h
  16. 29 0
      panda/src/cull/cullTraverser.cxx
  17. 2 0
      panda/src/cull/cullTraverser.h
  18. 21 0
      panda/src/display/graphicsStateGuardian.cxx
  19. 3 2
      panda/src/display/graphicsStateGuardian.h
  20. 2 0
      panda/src/downloader/downloader_headers.h
  21. 12 6
      panda/src/express/Sources.pp
  22. 83 0
      panda/src/express/memoryInfo.I
  23. 149 0
      panda/src/express/memoryInfo.cxx
  24. 88 0
      panda/src/express/memoryInfo.h
  25. 34 0
      panda/src/express/memoryUsage.I
  26. 309 154
      panda/src/express/memoryUsage.cxx
  27. 31 25
      panda/src/express/memoryUsage.h
  28. 128 0
      panda/src/express/memoryUsagePointerCounts.I
  29. 77 0
      panda/src/express/memoryUsagePointerCounts.cxx
  30. 67 0
      panda/src/express/memoryUsagePointerCounts.h
  31. 10 10
      panda/src/express/memoryUsagePointers.I
  32. 6 6
      panda/src/express/memoryUsagePointers.cxx
  33. 3 3
      panda/src/express/memoryUsagePointers.h
  34. 1 1
      panda/src/express/referenceCount.h
  35. 3 11
      panda/src/glgsg/glGraphicsStateGuardian.cxx
  36. 10 0
      panda/src/graph/nodeAttributes.I
  37. 2 0
      panda/src/graph/nodeAttributes.h
  38. 15 0
      panda/src/graph/nodeRelation.I
  39. 1 0
      panda/src/graph/nodeRelation.h
  40. 12 0
      panda/src/pstatclient/pStatClient.cxx
  41. 1 0
      panda/src/pstatclient/pStatProperties.cxx
  42. 34 34
      panda/src/putil/pointerToArray.I
  43. 28 29
      panda/src/putil/pointerToArray.h
  44. 24 6
      panda/src/sgmanip/nodePath.I
  45. 20 0
      panda/src/sgmanip/nodePath.cxx
  46. 2 0
      panda/src/sgmanip/nodePath.h

+ 3 - 0
dtool/Config.Irix.pp

@@ -93,3 +93,6 @@
 
 
 // Do we have RTTI (and <typeinfo>)?
 // Do we have RTTI (and <typeinfo>)?
 #define HAVE_RTTI 1
 #define HAVE_RTTI 1
+
+// Must global operator new and delete functions throw exceptions?
+#define GLOBAL_OPERATOR_NEW_EXCEPTIONS

+ 6 - 0
dtool/Config.Linux.pp

@@ -93,3 +93,9 @@
 
 
 // Do we have RTTI (and <typeinfo>)?
 // Do we have RTTI (and <typeinfo>)?
 #define HAVE_RTTI 1
 #define HAVE_RTTI 1
+
+// Must global operator new and delete functions throw exceptions?
+#define GLOBAL_OPERATOR_NEW_EXCEPTIONS 1
+
+// Do we expect the old gcc custom STL allocator?
+#define GCC_STYLE_ALLOCATOR 1

+ 3 - 2
dtool/Config.Win32.pp

@@ -94,8 +94,9 @@
 // Do we have RTTI (and <typeinfo>)?
 // Do we have RTTI (and <typeinfo>)?
 #define HAVE_RTTI 1
 #define HAVE_RTTI 1
 
 
+// Must global operator new and delete functions throw exceptions?
+#define GLOBAL_OPERATOR_NEW_EXCEPTIONS
+
 // can Intel C++ build this directory successfully (if not, change CC to msvc)
 // can Intel C++ build this directory successfully (if not, change CC to msvc)
 #define NOT_INTEL_BUILDABLE false
 #define NOT_INTEL_BUILDABLE false
 
 
-
-

+ 6 - 0
dtool/LocalSetup.pp

@@ -181,6 +181,12 @@ $[cdefine HAVE_SYS_SOUNDCARD_H]
 /* Do we have RTTI (and <typeinfo>)? */
 /* Do we have RTTI (and <typeinfo>)? */
 $[cdefine HAVE_RTTI]
 $[cdefine HAVE_RTTI]
 
 
+/* Must global operator new and delete functions throw exceptions? */
+$[cdefine GLOBAL_OPERATOR_NEW_EXCEPTIONS]
+
+/* Do we expect the old gcc custom STL allocator? */
+$[cdefine GCC_STYLE_ALLOCATOR]
+
 #end dtool_config.h
 #end dtool_config.h
 
 
 #endif   // BUILD_TYPE
 #endif   // BUILD_TYPE

+ 6 - 2
dtool/src/dtoolbase/Sources.pp

@@ -6,8 +6,12 @@
   
   
   #define SOURCES \
   #define SOURCES \
     dtoolbase.cxx dtoolbase.h dtoolbase_cc.h dtoolsymbols.h \
     dtoolbase.cxx dtoolbase.h dtoolbase_cc.h dtoolsymbols.h \
-    fakestringstream.h
+    fakestringstream.h \
+    pallocator.T pallocator.h \
+    pdeque.h plist.h pmap.h pset.h pvector.h
 
 
   #define INSTALL_HEADERS \
   #define INSTALL_HEADERS \
-    dtoolbase.h dtoolbase_cc.h dtoolsymbols.h fakestringstream.h
+    dtoolbase.h dtoolbase_cc.h dtoolsymbols.h fakestringstream.h \
+    pallocator.T pallocator.h \
+    pdeque.h plist.h pmap.h pset.h pvector.h
 #end lib_target
 #end lib_target

+ 18 - 0
dtool/src/dtoolbase/dtoolbase.cxx

@@ -17,3 +17,21 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 #include "dtoolbase.h"
 #include "dtoolbase.h"
+
+
+#ifndef NDEBUG
+
+void *default_operator_new(size_t size) {
+  return malloc(size);
+}
+
+void default_operator_delete(void *ptr) {
+  free(ptr);
+}
+
+// We absolutely depend on the static initialization of these pointers
+// to happen at load time, before any static constructors are called.
+void *(*global_operator_new)(size_t size) = &default_operator_new;
+void (*global_operator_delete)(void *ptr) = &default_operator_delete;
+
+#endif  // NDEBUG

+ 40 - 0
dtool/src/dtoolbase/dtoolbase_cc.h

@@ -95,5 +95,45 @@ using namespace std;
 
 
 #endif  // CPPPARSER
 #endif  // CPPPARSER
 
 
+// Now redefine global operators new and delete so we can optionally
+// provide custom handlers for them.  The MemoryUsage class in Panda
+// takes advantage of this to track the size of allocated pointers.
+#ifndef NDEBUG
+EXPCL_DTOOL void *default_operator_new(size_t size);
+EXPCL_DTOOL void default_operator_delete(void *ptr);
+
+extern EXPCL_DTOOL void *(*global_operator_new)(size_t size);
+extern EXPCL_DTOOL void (*global_operator_delete)(void *ptr);
+
+#ifdef GLOBAL_OPERATOR_NEW_EXCEPTIONS
+INLINE void *operator new(size_t size) throw (std::bad_alloc) {
+  return (*global_operator_new)(size);
+}
+INLINE void *operator new[](size_t size) throw (std::bad_alloc) {
+  return (*global_operator_new)(size);
+}
+
+INLINE void operator delete(void *ptr) throw() {
+  (*global_operator_delete)(ptr);
+}
+INLINE void operator delete[](void *ptr) throw() {
+  (*global_operator_delete)(ptr);
+}
+#else   // GLOBAL_OPERATOR_NEW_EXCEPTIONS
+INLINE void *operator new(size_t size) {
+  return (*global_operator_new)(size);
+}
+INLINE void *operator new[](size_t size) {
+  return (*global_operator_new)(size);
+}
+
+INLINE void operator delete(void *ptr) {
+  (*global_operator_delete)(ptr);
+}
+INLINE void operator delete[](void *ptr) {
+  (*global_operator_delete)(ptr);
+}
+#endif  // GLOBAL_OPERATOR_NEW_EXCEPTIONS
+#endif  // NDEBUG
 
 
 #endif
 #endif

+ 51 - 0
dtool/src/dtoolbase/pallocator.T

@@ -0,0 +1,51 @@
+// Filename: pallocator.T
+// Created by:  drose (05Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifdef GCC_STYLE_ALLOCATOR
+
+#ifndef NDEBUG
+template<class Type>
+INLINE void *pallocator<Type>::
+allocate(size_t n) {
+  return (*global_operator_new)(n);
+}
+
+template<class Type>
+INLINE void pallocator<Type>::
+deallocate(void *p, size_t) {
+  return (*global_operator_delete)(p);
+}
+#endif  // NDEBUG
+
+#else  // GCC_STYLE_ALLOCATOR
+
+#ifndef NDEBUG
+template<class Type>
+INLINE pallocator<Type>::pointer pallocator<Type>::
+allocate(pallocator<Type>::size_type n, allocator<void>::const_pointer) {
+  return (*global_operator_new)(n * sizeof(Type));
+}
+
+template<class Type>
+INLINE void pallocator<Type>::
+deallocate(pallocator<Type>::pointer p, allocator<Type>::size_type) {
+  return (*global_operator_delete)(p);
+}
+#endif  // NDEBUG
+
+#endif  // GCC_STYLE_ALLOCATOR

+ 66 - 0
dtool/src/dtoolbase/pallocator.h

@@ -0,0 +1,66 @@
+// Filename: pallocator.h
+// Created by:  drose (05Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PALLOCATOR_H
+#define PALLOCATOR_H
+
+#include "dtoolbase.h"
+
+#include <memory>
+#include <vector>
+
+////////////////////////////////////////////////////////////////////
+//       Class : pallocator
+// Description : This is our own Panda specialization on the default
+//               STL allocator.  Its main purpose is to call the hooks
+//               for MemoryUsage to properly track STL-allocated
+//               memory.
+//
+//               pvector, pmap, etc. are all defined in this directory
+//               to use a pallocator.
+////////////////////////////////////////////////////////////////////
+
+#ifdef GCC_STYLE_ALLOCATOR
+// Early versions of gcc used its own kind of allocator, somewhat
+// different from the STL standard.
+
+template<class Type>
+class pallocator : public alloc {
+public:
+#ifndef NDEBUG
+  static void *allocate(size_t n);
+  static void deallocate(void *p, size_t n);
+#endif  // NDEBUG
+};
+
+#else  // GCC_STYLE_ALLOCATOR
+
+template<class Type>
+class pallocator : public allocator<Type> {
+public:
+#ifndef NDEBUG
+  INLINE pointer allocate(size_type n, allocator<void>::const_pointer hint = 0);
+  INLINE void deallocate(pointer p, size_type n);
+#endif  // NDEBUG
+};
+#endif  // GCC_STYLE_ALLOCATOR
+
+#include "pallocator.T"
+
+#endif
+

+ 44 - 0
dtool/src/dtoolbase/pdeque.h

@@ -0,0 +1,44 @@
+// Filename: pdeque.h
+// Created by:  drose (05Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PDEQUE_H
+#define PDEQUE_H
+
+#include "dtoolbase.h"
+#include "pallocator.h"
+
+#include <deque>
+
+////////////////////////////////////////////////////////////////////
+//       Class : pdeque
+// Description : This is our own Panda specialization on the default
+//               STL deque.  Its main purpose is to call the hooks
+//               for MemoryUsage to properly track STL-allocated
+//               memory.
+////////////////////////////////////////////////////////////////////
+template<class Type>
+class pdeque : public deque<Type, pallocator<Type> > {
+public:
+  pdeque() : deque<Type, pallocator<Type> >() { }
+  pdeque(const pdeque<Type> &copy) : deque<Type, pallocator<Type> >(copy) { }
+  pdeque(size_type n) : deque<Type, pallocator<Type> >(n) { }
+  pdeque(size_type n, const Type &value) : deque<Type, pallocator<Type> >(n, value) { }
+};
+
+#endif
+

+ 44 - 0
dtool/src/dtoolbase/plist.h

@@ -0,0 +1,44 @@
+// Filename: plist.h
+// Created by:  drose (05Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PLIST_H
+#define PLIST_H
+
+#include "dtoolbase.h"
+#include "pallocator.h"
+
+#include <list>
+
+////////////////////////////////////////////////////////////////////
+//       Class : plist
+// Description : This is our own Panda specialization on the default
+//               STL list.  Its main purpose is to call the hooks
+//               for MemoryUsage to properly track STL-allocated
+//               memory.
+////////////////////////////////////////////////////////////////////
+template<class Type>
+class plist : public list<Type, pallocator<Type> > {
+public:
+  plist() : list<Type, pallocator<Type> >() { }
+  plist(const plist<Type> &copy) : list<Type, pallocator<Type> >(copy) { }
+  plist(size_type n) : list<Type, pallocator<Type> >(n) { }
+  plist(size_type n, const Type &value) : list<Type, pallocator<Type> >(n, value) { }
+};
+
+#endif
+

+ 56 - 0
dtool/src/dtoolbase/pmap.h

@@ -0,0 +1,56 @@
+// Filename: pmap.h
+// Created by:  drose (05Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PMAP_H
+#define PMAP_H
+
+#include "dtoolbase.h"
+#include "pallocator.h"
+
+#include <map>
+
+////////////////////////////////////////////////////////////////////
+//       Class : pmap
+// Description : This is our own Panda specialization on the default
+//               STL map.  Its main purpose is to call the hooks
+//               for MemoryUsage to properly track STL-allocated
+//               memory.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value, class Compare = less<Key> >
+class pmap : public map<Key, Value, Compare, pallocator<pair<Key, Value> > > {
+public:
+  pmap() : map<Key, Value, Compare, pallocator<pair<Key, Value> > >() { }
+  pmap(const pmap<Key> &copy) : map<Key, Value, Compare, pallocator<pair<Key, Value> > >(copy) { }
+};
+
+////////////////////////////////////////////////////////////////////
+//       Class : pmultimap
+// Description : This is our own Panda specialization on the default
+//               STL multimap.  Its main purpose is to call the hooks
+//               for MemoryUsage to properly track STL-allocated
+//               memory.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value, class Compare = less<Key> >
+class pmultimap : public multimap<Key, Value, Compare, pallocator<pair<Key, Value> > > {
+public:
+  pmultimap() : multimap<Key, Value, Compare, pallocator<pair<Key, Value> > >() { }
+  pmultimap(const pmultimap<Key> &copy) : multimap<Key, Value, Compare, pallocator<pair<Key, Value> > >(copy) { }
+};
+
+#endif
+

+ 56 - 0
dtool/src/dtoolbase/pset.h

@@ -0,0 +1,56 @@
+// Filename: pset.h
+// Created by:  drose (05Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PSET_H
+#define PSET_H
+
+#include "dtoolbase.h"
+#include "pallocator.h"
+
+#include <set>
+
+////////////////////////////////////////////////////////////////////
+//       Class : pset
+// Description : This is our own Panda specialization on the default
+//               STL set.  Its main purpose is to call the hooks
+//               for MemoryUsage to properly track STL-allocated
+//               memory.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Compare = less<Key> >
+class pset : public set<Key, Compare, pallocator<Key> > {
+public:
+  pset() : set<Key, Compare, pallocator<Key> >() { }
+  pset(const pset<Key> &copy) : set<Key, Compare, pallocator<Key> >(copy) { }
+};
+
+////////////////////////////////////////////////////////////////////
+//       Class : pmultiset
+// Description : This is our own Panda specialization on the default
+//               STL multiset.  Its main purpose is to call the hooks
+//               for MemoryUsage to properly track STL-allocated
+//               memory.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Compare = less<Key> >
+class pmultiset : public multiset<Key, Compare, pallocator<Key> > {
+public:
+  pmultiset() : multiset<Key, Compare, pallocator<Key> >() { }
+  pmultiset(const pmultiset<Key> &copy) : multiset<Key, Compare, pallocator<Key> >(copy) { }
+};
+
+#endif
+

+ 44 - 0
dtool/src/dtoolbase/pvector.h

@@ -0,0 +1,44 @@
+// Filename: pvector.h
+// Created by:  drose (05Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PVECTOR_H
+#define PVECTOR_H
+
+#include "dtoolbase.h"
+#include "pallocator.h"
+
+#include <vector>
+
+////////////////////////////////////////////////////////////////////
+//       Class : pvector
+// Description : This is our own Panda specialization on the default
+//               STL vector.  Its main purpose is to call the hooks
+//               for MemoryUsage to properly track STL-allocated
+//               memory.
+////////////////////////////////////////////////////////////////////
+template<class Type>
+class pvector : public vector<Type, pallocator<Type> > {
+public:
+  pvector() : vector<Type, pallocator<Type> >() { }
+  pvector(const pvector<Type> &copy) : vector<Type, pallocator<Type> >(copy) { }
+  pvector(size_type n) : vector<Type, pallocator<Type> >(n) { }
+  pvector(size_type n, const Type &value) : vector<Type, pallocator<Type> >(n, value) { }
+};
+
+#endif
+

+ 2 - 2
dtool/src/dtoolutil/vector_src.h

@@ -45,7 +45,7 @@
 //
 //
 // They will automatically be undefined at the end of the file.
 // They will automatically be undefined at the end of the file.
 
 
-#include <vector>
+#include "pvector.h"
 
 
 #if defined(WIN32_VC) && !defined(CPPPARSER)
 #if defined(WIN32_VC) && !defined(CPPPARSER)
 
 
@@ -65,7 +65,7 @@ EXPORT_TEMPLATE_CLASS(EXPCL, EXPTP, std::vector<TYPE>)
 #endif
 #endif
 
 
 // Now make a typedef for the vector.
 // Now make a typedef for the vector.
-typedef std::vector<TYPE> NAME;
+typedef pvector<TYPE> NAME;
 
 
   // Finally, we must define a non-inline function that performs the
   // Finally, we must define a non-inline function that performs the
   // insert operation given a range of pointers.  We do this because
   // insert operation given a range of pointers.  We do this because

+ 29 - 0
panda/src/cull/cullTraverser.cxx

@@ -143,6 +143,35 @@ clear_bins() {
   nassertv(_default_bin == (GeomBin *)NULL);
   nassertv(_default_bin == (GeomBin *)NULL);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: CullTraverser::clear_state
+//       Access: Public
+//  Description: Removes all the cached state information stored
+//               within the CullTraverser, and forces it to rebuild
+//               this state from scratch the next frame.
+//
+//               This can be used to clear out state that has gone
+//               bad, as well as to free up memory pointers that
+//               otherwise may be held for another frame.
+////////////////////////////////////////////////////////////////////
+void CullTraverser::
+clear_state() {
+  _states.clear();
+  _lookup.clear();
+
+  ToplevelBins::const_iterator tbi;
+  for (tbi = _toplevel_bins.begin(); tbi != _toplevel_bins.end(); ++tbi) {
+    (*tbi).second->clear_current_states();
+  }
+  SubBins::const_iterator sbi;
+  for (sbi = _sub_bins.begin(); sbi != _sub_bins.end(); ++sbi) {
+    (*sbi).second->clear_current_states();
+  }
+  _default_bin->clear_current_states();
+
+  _initial_state = AllAttributesWrapper();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CullTraverser::output
 //     Function: CullTraverser::output
 //       Access: Public
 //       Access: Public

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

@@ -59,6 +59,8 @@ PUBLISHED:
   GeomBin *get_bin(const string &name) const;
   GeomBin *get_bin(const string &name) const;
   void clear_bins();
   void clear_bins();
 
 
+  void clear_state();
+
   void output(ostream &out) const;
   void output(ostream &out) const;
   void write(ostream &out, int indent_level = 0) const;
   void write(ostream &out, int indent_level = 0) const;
 
 

+ 21 - 0
panda/src/display/graphicsStateGuardian.cxx

@@ -125,6 +125,27 @@ release_all_textures() {
   nassertv(_prepared_textures.empty());
   nassertv(_prepared_textures.empty());
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::clear_attribute
+//       Access: Public
+//  Description: Explicitly clear the indicated attribute, specified
+//               by the TypeHandle of its associated transition.  If
+//               the attribute is not set already, this does nothing;
+//               if it is set, it resets it to its default value.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+clear_attribute(TypeHandle type) {
+  NodeAttributes::iterator ai = _state.find(type);
+  if (ai != _state.end()) {
+    // The state is already set; get the initial value and reset it.
+    PT(NodeAttribute) initial = (*ai).second->make_initial();
+    initial->issue(this);
+
+    // Now remove the state entry from the set.
+    _state.erase(ai);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::reset
 //     Function: GraphicsStateGuardian::reset
 //       Access: Public, Virtual
 //       Access: Public, Virtual

+ 3 - 2
panda/src/display/graphicsStateGuardian.h

@@ -78,10 +78,11 @@ PUBLISHED:
   }
   }
 
 
   void enable_frame_clear(bool clear_color, bool clear_depth);
   void enable_frame_clear(bool clear_color, bool clear_depth);
-
-public:
   void release_all_textures();
   void release_all_textures();
 
 
+  void clear_attribute(TypeHandle type);
+
+public:
   virtual void clear(const RenderBuffer &buffer)=0;
   virtual void clear(const RenderBuffer &buffer)=0;
   virtual void clear(const RenderBuffer &buffer, const DisplayRegion* region)=0;
   virtual void clear(const RenderBuffer &buffer, const DisplayRegion* region)=0;
 
 

+ 2 - 0
panda/src/downloader/downloader_headers.h

@@ -16,9 +16,11 @@
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
+#ifdef WIN32_VC
 #define WINDOWS_LEAN_AND_MEAN
 #define WINDOWS_LEAN_AND_MEAN
 #include <windows.h>
 #include <windows.h>
 #undef WINDOWS_LEAN_AND_MEAN
 #undef WINDOWS_LEAN_AND_MEAN
+#endif
 
 
 #include <errno.h>
 #include <errno.h>
 #include <error_utils.h>
 #include <error_utils.h>

+ 12 - 6
panda/src/express/Sources.pp

@@ -20,8 +20,11 @@
      datagramOutputFile.h datagramSink.I datagramSink.h \
      datagramOutputFile.h datagramSink.I datagramSink.h \
      get_config_path.h hashGeneratorBase.I hashGeneratorBase.h \
      get_config_path.h hashGeneratorBase.I hashGeneratorBase.h \
      hashVal.I hashVal.h indent.I indent.h littleEndian.h \
      hashVal.I hashVal.h indent.I indent.h littleEndian.h \
-     memoryUsage.I memoryUsage.h memoryUsagePointers.I \
-     memoryUsagePointers.h multifile.I multifile.h namable.I \
+     memoryInfo.I memoryInfo.h \
+     memoryUsage.I memoryUsage.h \
+     memoryUsagePointerCounts.I memoryUsagePointerCounts.h \
+     memoryUsagePointers.I memoryUsagePointers.h \
+     multifile.I multifile.h namable.I \
      namable.h nativeNumericData.I nativeNumericData.h \
      namable.h nativeNumericData.I nativeNumericData.h \
      numeric_types.h pointerTo.I pointerTo.h referenceCount.I \
      numeric_types.h pointerTo.I pointerTo.h referenceCount.I \
      profileTimer.I profileTimer.h referenceCount.h \
      profileTimer.I profileTimer.h referenceCount.h \
@@ -36,7 +39,8 @@
      config_express.cxx datagram.cxx datagramGenerator.cxx \
      config_express.cxx datagram.cxx datagramGenerator.cxx \
      datagramInputFile.cxx datagramIterator.cxx \
      datagramInputFile.cxx datagramIterator.cxx \
      datagramOutputFile.cxx datagramSink.cxx get_config_path.cxx \
      datagramOutputFile.cxx datagramSink.cxx get_config_path.cxx \
-     hashGeneratorBase.cxx hashVal.cxx indent.cxx memoryUsage.cxx \
+     hashGeneratorBase.cxx hashVal.cxx indent.cxx \
+     memoryInfo.cxx memoryUsage.cxx memoryUsagePointerCounts.cxx \
      memoryUsagePointers.cxx multifile.cxx namable.cxx \
      memoryUsagePointers.cxx multifile.cxx namable.cxx \
      nativeNumericData.cxx profileTimer.cxx referenceCount.cxx \
      nativeNumericData.cxx profileTimer.cxx referenceCount.cxx \
      reversedNumericData.cxx trueClock.cxx typeHandle.cxx \
      reversedNumericData.cxx trueClock.cxx typeHandle.cxx \
@@ -58,9 +62,11 @@
     datagramGenerator.h get_config_path.h               \
     datagramGenerator.h get_config_path.h               \
     hashGeneratorBase.I hashGeneratorBase.h \
     hashGeneratorBase.I hashGeneratorBase.h \
     hashVal.I hashVal.h \
     hashVal.I hashVal.h \
-    indent.I indent.h littleEndian.h            \
-    memoryUsage.I memoryUsage.h memoryUsagePointers.I           \
-    memoryUsagePointers.h multifile.I multifile.h \
+    indent.I indent.h littleEndian.h                    \
+    memoryInfo.I memoryInfo.h \
+    memoryUsage.I memoryUsage.h \
+    memoryUsagePointerCounts.I memoryUsagePointerCounts.h \
+    memoryUsagePointers.I memoryUsagePointers.h multifile.I multifile.h \
     nativeNumericData.I nativeNumericData.h \
     nativeNumericData.I nativeNumericData.h \
     numeric_types.h \
     numeric_types.h \
     pointerTo.I pointerTo.h referenceCount.I referenceCount.h       \
     pointerTo.I pointerTo.h referenceCount.I referenceCount.h       \

+ 83 - 0
panda/src/express/memoryInfo.I

@@ -0,0 +1,83 @@
+// Filename: memoryInfo.I
+// Created by:  drose (04Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryInfo::get_void_ptr
+//       Access: Public
+//  Description: Returns the data pointer as a void pointer.  This
+//               should always be non-NULL.
+////////////////////////////////////////////////////////////////////
+void *MemoryInfo::get_void_ptr() const {
+  return _void_ptr;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryInfo::get_ref_ptr
+//       Access: Public
+//  Description: Returns the data pointer as a ReferenceCount pointer.
+//               This may be NULL if the data pointer does not
+//               represent a ReferenceCount object.
+////////////////////////////////////////////////////////////////////
+ReferenceCount *MemoryInfo::get_ref_ptr() const {
+  return _ref_ptr;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryInfo::get_typed_ptr
+//       Access: Public
+//  Description: Returns the data pointer as a TypedObject pointer.
+//               This may be NULL if the data pointer does not
+//               represent a pointer to a TypedObject.
+////////////////////////////////////////////////////////////////////
+TypedObject *MemoryInfo::get_typed_ptr() const {
+  return _typed_ptr;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryInfo::is_size_known
+//       Access: Public
+//  Description: Returns true if the size of the memory block
+//               referenced by this pointer is known.  Most pointers'
+//               sizes should be known, but some may not be.
+////////////////////////////////////////////////////////////////////
+bool MemoryInfo::is_size_known() const {
+  return (_flags & F_size_known) != 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryInfo::get_size
+//       Access: Public
+//  Description: Returns the size in bytes of the memory block
+//               referenced by this pointer, if it is known.  Returns
+//               zero if the size is not known.
+////////////////////////////////////////////////////////////////////
+size_t MemoryInfo::get_size() const {
+  return _size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryInfo::get_time
+//       Access: Public
+//  Description: Returns the time in seconds (based on the
+//               GlobalClock) at which the pointer was allocated.
+////////////////////////////////////////////////////////////////////
+double MemoryInfo::get_time() const {
+  return _time;
+}
+

+ 149 - 0
panda/src/express/memoryInfo.cxx

@@ -0,0 +1,149 @@
+// Filename: memoryInfo.cxx
+// Created by:  drose (04Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "memoryInfo.h"
+#include "typedReferenceCount.h"
+#include "typeHandle.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryInfo::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+MemoryInfo::
+MemoryInfo() {
+  _void_ptr = (void *)NULL;
+  _ref_ptr = (ReferenceCount *)NULL;
+  _typed_ptr = (TypedObject *)NULL;
+  _size = 0;
+  _static_type = TypeHandle::none();
+  _dynamic_type = TypeHandle::none();
+
+  _flags = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryInfo::get_type
+//       Access: Public
+//  Description: Returns the best known type, dynamic or static, of
+//               the pointer.
+////////////////////////////////////////////////////////////////////
+TypeHandle MemoryInfo::
+get_type() {
+  // If we don't want to consider the dynamic type any further, use
+  // what we've got.
+  if ((_flags & F_reconsider_dynamic_type) == 0) {
+    if (_dynamic_type == TypeHandle::none()) {
+      return _static_type;
+    }
+    return _dynamic_type;
+  }
+
+  // Otherwise, examine the pointer again and make sure it's still the
+  // best information we have.  We have to do this each time because
+  // if we happen to be examining the pointer from within the
+  // constructor or destructor, its dynamic type will appear to be
+  // less-specific than it actually is, so our idea of what type this
+  // thing is could change from time to time.
+  determine_dynamic_type();
+
+  // Now return the more specific of the two.
+  TypeHandle type = _static_type;
+  update_type_handle(type, _dynamic_type);
+
+  return type;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryInfo::determine_dynamic_type
+//       Access: Public
+//  Description: Tries to determine the actual type of the object to
+//               which this thing is pointed, if possible.
+////////////////////////////////////////////////////////////////////
+void MemoryInfo::
+determine_dynamic_type() {
+  if ((_flags & F_reconsider_dynamic_type) != 0 &&
+      _static_type != TypeHandle::none()) {
+    // See if we know enough now to infer the dynamic type from the
+    // pointer.
+
+    if (_typed_ptr == (TypedObject *)NULL) {
+      // If our static type is known to inherit from
+      // TypedReferenceCount, then we can directly downcast to get the
+      // TypedObject pointer.
+      if (_static_type.is_derived_from(TypedReferenceCount::get_class_type())) {
+        _typed_ptr = (TypedReferenceCount *)_ref_ptr;
+      }
+    }
+
+    if (_typed_ptr != (TypedObject *)NULL) {
+      // If we have a TypedObject pointer, we can determine the type.
+      // This might still not return the exact type, particularly if
+      // we are being called within the destructor or constructor of
+      // this object.
+      TypeHandle got_type = _typed_ptr->get_type();
+
+      if (got_type == TypeHandle::none()) {
+        express_cat.warning()
+          << "Found an unregistered type in a " << _static_type
+          << " pointer:\n"
+          << "Check derived types of " << _static_type
+          << " and make sure that all are being initialized.\n";
+        _dynamic_type = _static_type;
+        _flags &= ~F_reconsider_dynamic_type;
+        return;
+      }
+
+      update_type_handle(_dynamic_type, got_type);
+    }
+  }
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryInfo::update_type_handle
+//       Access: Public
+//  Description: Updates the given destination TypeHandle with the
+//               refined TypeHandle, if it is in fact more specific
+//               than the original value for the destination.
+////////////////////////////////////////////////////////////////////
+void MemoryInfo::
+update_type_handle(TypeHandle &destination, TypeHandle refined) {
+  if (refined == TypeHandle::none()) {
+    express_cat.error()
+      << "Attempt to update type of " << (void *)_ref_ptr
+      << "(type is " << get_type()
+      << ") to an undefined type!\n";
+
+  } else if (destination == refined) {
+    // Updating with the same type, no problem.
+
+  } else if (destination.is_derived_from(refined)) {
+    // Updating with a less-specific type, no problem.
+
+  } else if (refined.is_derived_from(destination)) {
+    // Updating with a more-specific type, no problem.
+    destination = refined;
+
+  } else {
+    express_cat.error()
+      << "Pointer " << (void *)_ref_ptr << " previously indicated as type "
+      << destination << " is now type " << refined << "!\n";
+    destination = refined;
+  }
+}

+ 88 - 0
panda/src/express/memoryInfo.h

@@ -0,0 +1,88 @@
+// Filename: memoryInfo.h
+// Created by:  drose (04Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef MEMORYINFO_H
+#define MEMORYINFO_H
+
+#include <pandabase.h>
+#include "typeHandle.h"
+
+class ReferenceCount;
+class TypedObject;
+
+#ifndef NDEBUG
+////////////////////////////////////////////////////////////////////
+//       Class : MemoryInfo
+// Description : This is a supporting class for MemoryUsage.  It
+//               records the detailed information for a particular
+//               pointer allocated by Panda code.  This record is only
+//               kept if track-mem-usage is configured #t.
+//
+//               It's not exported from the DLL, and it doesn't even
+//               exist if we're compiling NDEBUG.
+////////////////////////////////////////////////////////////////////
+class MemoryInfo {
+public:
+  MemoryInfo();
+
+public:
+  // Members to view the MemoryInfo structure.
+  TypeHandle get_type();
+
+  INLINE void *get_void_ptr() const;
+  INLINE ReferenceCount *get_ref_ptr() const;
+  INLINE TypedObject *get_typed_ptr() const;
+
+  INLINE bool is_size_known() const;
+  INLINE size_t get_size() const;
+
+  INLINE double get_time() const;
+
+public:
+  // Members to set up the MemoryInfo structure.
+  void determine_dynamic_type();
+  void update_type_handle(TypeHandle &destination, TypeHandle refined);
+
+private:
+  enum Flags {
+    F_got_ref                 = 0x0001,
+    F_got_void                = 0x0002,
+    F_size_known              = 0x0004,
+    F_reconsider_dynamic_type = 0x0008,
+  };
+  
+  void *_void_ptr;
+  ReferenceCount *_ref_ptr;
+  TypedObject *_typed_ptr;
+  size_t _size;
+  TypeHandle _static_type;
+  TypeHandle _dynamic_type;
+  int _flags;
+  
+  double _time;
+  int _freeze_index;
+
+  friend class MemoryUsage;
+};
+
+#include "memoryInfo.I"
+
+#endif  // NDEBUG
+
+#endif
+

+ 34 - 0
panda/src/express/memoryUsage.I

@@ -115,6 +115,40 @@ remove_pointer(ReferenceCount *ptr) {
 
 
 #endif  // __GNUC__
 #endif  // __GNUC__
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryUsage::is_tracking
+//       Access: Public, Static
+//  Description: Returns true if the MemoryUsage object is currently
+//               tracking memory (e.g. track-memory-usage is
+//               configured #t).
+////////////////////////////////////////////////////////////////////
+INLINE bool MemoryUsage::
+is_tracking() {
+  return get_global_ptr()->_track_memory_usage;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryUsage::get_allocated_size
+//       Access: Public, Static
+//  Description: Returns the total number of bytes of allocated memory
+//               as counted, excluding the memory previously frozen.
+////////////////////////////////////////////////////////////////////
+INLINE size_t MemoryUsage::
+get_allocated_size() {
+  return get_global_ptr()->ns_get_allocated_size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryUsage::get_total_size
+//       Access: Public, Static
+//  Description: Returns the total number of bytes of allocated memory
+//               as counted, including the memory previously frozen.
+////////////////////////////////////////////////////////////////////
+INLINE size_t MemoryUsage::
+get_total_size() {
+  return get_global_ptr()->ns_get_total_size();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: MemoryUsage::get_num_pointers
 //     Function: MemoryUsage::get_num_pointers
 //       Access: Public, Static
 //       Access: Public, Static

+ 309 - 154
panda/src/express/memoryUsage.cxx

@@ -49,116 +49,6 @@ double MemoryUsage::AgeHistogram::_cutoff[MemoryUsage::AgeHistogram::num_buckets
   60.0,
   60.0,
 };
 };
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: MemoryUsage::MemoryInfo::get_type
-//       Access: Public
-//  Description: Returns the best known type, dynamic or static, of
-//               the pointer.
-////////////////////////////////////////////////////////////////////
-TypeHandle MemoryUsage::MemoryInfo::
-get_type() {
-  // If we don't want to consider the dynamic type any further, use
-  // what we've got.
-  if (!_reconsider_dynamic_type) {
-    if (_dynamic_type == TypeHandle::none()) {
-      return _static_type;
-    }
-    return _dynamic_type;
-  }
-
-  // Otherwise, examine the pointer again and make sure it's still the
-  // best information we have.  We have to do this each time because
-  // if we happen to be examining the pointer from within the
-  // constructor or destructor, its dynamic type will appear to be
-  // less-specific than it actually is, so our idea of what type this
-  // thing is could change from time to time.
-  determine_dynamic_type();
-
-  // Now return the more specific of the two.
-  TypeHandle type = _static_type;
-  update_type_handle(type, _dynamic_type);
-
-  return type;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: MemoryUsage::MemoryInfo::determine_dynamic_type
-//       Access: Public
-//  Description: Tries to determine the actual type of the object to
-//               which this thing is pointed, if possible.
-////////////////////////////////////////////////////////////////////
-void MemoryUsage::MemoryInfo::
-determine_dynamic_type() {
-  if (_reconsider_dynamic_type && _static_type != TypeHandle::none()) {
-    // See if we know enough now to infer the dynamic type from the
-    // pointer.
-
-    if (_typed_ptr == (TypedObject *)NULL) {
-      // If our static type is known to inherit from
-      // TypedReferenceCount, then we can directly downcast to get the
-      // TypedObject pointer.
-      if (_static_type.is_derived_from(TypedReferenceCount::get_class_type())) {
-        _typed_ptr = (TypedReferenceCount *)_ptr;
-      }
-    }
-
-    if (_typed_ptr != (TypedObject *)NULL) {
-      // If we have a TypedObject pointer, we can determine the type.
-      // This might still not return the exact type, particularly if
-      // we are being called within the destructor or constructor of
-      // this object.
-      TypeHandle got_type = _typed_ptr->get_type();
-
-      if (got_type == TypeHandle::none()) {
-        express_cat.warning()
-          << "Found an unregistered type in a " << _static_type
-          << " pointer:\n"
-          << "Check derived types of " << _static_type
-          << " and make sure that all are being initialized.\n";
-        _dynamic_type = _static_type;
-        _reconsider_dynamic_type = false;
-        return;
-      }
-
-      update_type_handle(_dynamic_type, got_type);
-    }
-  }
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: MemoryUsage::MemoryInfo::update_type_handle
-//       Access: Public
-//  Description: Updates the given destination TypeHandle with the
-//               refined TypeHandle, if it is in fact more specific
-//               than the original value for the destination.
-////////////////////////////////////////////////////////////////////
-void MemoryUsage::MemoryInfo::
-update_type_handle(TypeHandle &destination, TypeHandle refined) {
-  if (refined == TypeHandle::none()) {
-    express_cat.error()
-      << "Attempt to update type of " << (void *)_ptr
-      << "(type is " << get_type()
-      << ") to an undefined type!\n";
-
-  } else if (destination == refined) {
-    // Updating with the same type, no problem.
-
-  } else if (destination.is_derived_from(refined)) {
-    // Updating with a less-specific type, no problem.
-
-  } else if (refined.is_derived_from(destination)) {
-    // Updating with a more-specific type, no problem.
-    destination = refined;
-
-  } else {
-    express_cat.error()
-      << "Pointer " << (void *)_ptr << " previously indicated as type "
-      << destination << " is now type " << refined << "!\n";
-    destination = refined;
-  }
-}
-
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: MemoryUsage::TypeHistogram::add_info
 //     Function: MemoryUsage::TypeHistogram::add_info
@@ -166,8 +56,8 @@ update_type_handle(TypeHandle &destination, TypeHandle refined) {
 //  Description: Adds a single entry to the histogram.
 //  Description: Adds a single entry to the histogram.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void MemoryUsage::TypeHistogram::
 void MemoryUsage::TypeHistogram::
-add_info(TypeHandle type) {
-  _counts[type]++;
+add_info(TypeHandle type, MemoryInfo &info) {
+  _counts[type].add_info(info);
 }
 }
 
 
 
 
@@ -175,14 +65,16 @@ add_info(TypeHandle type) {
 // below, to sort the types in descending order by counts.
 // below, to sort the types in descending order by counts.
 class TypeHistogramCountSorter {
 class TypeHistogramCountSorter {
 public:
 public:
-  TypeHistogramCountSorter(int count, TypeHandle type) {
-    _count = count;
-    _type = type;
+  TypeHistogramCountSorter(const MemoryUsagePointerCounts &count, 
+                           TypeHandle type) :
+    _count(count),
+    _type(type)
+  {
   }
   }
   bool operator < (const TypeHistogramCountSorter &other) const {
   bool operator < (const TypeHistogramCountSorter &other) const {
     return _count > other._count;
     return _count > other._count;
   }
   }
-  int _count;
+  MemoryUsagePointerCounts _count;
   TypeHandle _type;
   TypeHandle _type;
 };
 };
 
 
@@ -206,7 +98,13 @@ show() const {
 
 
   vector<TypeHistogramCountSorter>::const_iterator vi;
   vector<TypeHistogramCountSorter>::const_iterator vi;
   for (vi = count_sorter.begin(); vi != count_sorter.end(); ++vi) {
   for (vi = count_sorter.begin(); vi != count_sorter.end(); ++vi) {
-    nout << (*vi)._type << " : " << (*vi)._count << " pointers.\n";
+    TypeHandle type = (*vi)._type;
+    if (type == TypeHandle::none()) {
+      nout << "unknown";
+    } else {
+      nout << type;
+    }
+    nout << " : " << (*vi)._count << "\n";
   }
   }
 }
 }
 
 
@@ -236,10 +134,10 @@ AgeHistogram() {
 //  Description: Adds a single entry to the histogram.
 //  Description: Adds a single entry to the histogram.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void MemoryUsage::AgeHistogram::
 void MemoryUsage::AgeHistogram::
-add_info(double age) {
+add_info(double age, MemoryInfo &info) {
   int bucket = choose_bucket(age);
   int bucket = choose_bucket(age);
   nassertv(bucket >= 0 && bucket < num_buckets);
   nassertv(bucket >= 0 && bucket < num_buckets);
-  _counts[bucket]++;
+  _counts[bucket].add_info(info);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -250,11 +148,13 @@ add_info(double age) {
 void MemoryUsage::AgeHistogram::
 void MemoryUsage::AgeHistogram::
 show() const {
 show() const {
   for (int i = 0; i < num_buckets - 1; i++) {
   for (int i = 0; i < num_buckets - 1; i++) {
-    nout << _cutoff[i] << " to " << _cutoff[i + 1] << " seconds old : "
-         << _counts[i] << " pointers.\n";
+    nout << _cutoff[i] << " to " << _cutoff[i + 1] << " seconds old : ";
+    _counts[i].output(nout);
+    nout << "\n";
   }
   }
-  nout << _cutoff[num_buckets - 1] << " seconds old and up : "
-       << _counts[num_buckets - 1] << " pointers.\n";
+  nout << _cutoff[num_buckets - 1] << " seconds old and up : ";
+  _counts[num_buckets - 1].output(nout);
+  nout << "\n";
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -265,7 +165,7 @@ show() const {
 void MemoryUsage::AgeHistogram::
 void MemoryUsage::AgeHistogram::
 clear() {
 clear() {
   for (int i = 0; i < num_buckets; i++) {
   for (int i = 0; i < num_buckets; i++) {
-    _counts[i] = 0;
+    _counts[i].clear();
   }
   }
 }
 }
 
 
@@ -341,6 +241,37 @@ remove_pointer(ReferenceCount *ptr) {
 
 
 #endif // __GNUC__ && !NDEBUG
 #endif // __GNUC__ && !NDEBUG
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryUsage::operator_new_handler
+//       Access: Public, Static
+//  Description: This is set up as a global handler function (by
+//               redefining a function pointer in Dtool) for the
+//               operator new function.  If track-memory-usage is
+//               enabled, this function will be called whenever any
+//               new operator within the Panda source is invoked.
+////////////////////////////////////////////////////////////////////
+void *MemoryUsage::
+operator_new_handler(size_t size) {
+  void *ptr = default_operator_new(size);
+  get_global_ptr()->ns_record_void_pointer(ptr, size);
+  return ptr;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryUsage::operator_delete_handler
+//       Access: Public, Static
+//  Description: This is set up as a global handler function (by
+//               redefining a function pointer in Dtool) for the
+//               operator delete function.  If track-memory-usage is
+//               enabled, this function will be called whenever any
+//               delete operator within the Panda source is invoked.
+////////////////////////////////////////////////////////////////////
+void MemoryUsage::
+operator_delete_handler(void *ptr) {
+  get_global_ptr()->ns_remove_void_pointer(ptr);
+  return default_operator_delete(ptr);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: MemoryUsage::Constructor
 //     Function: MemoryUsage::Constructor
 //       Access: Private
 //       Access: Private
@@ -354,8 +285,18 @@ MemoryUsage() {
   _track_memory_usage =
   _track_memory_usage =
     config_express.GetBool("track-memory-usage", false);
     config_express.GetBool("track-memory-usage", false);
 
 
+  if (_track_memory_usage) {
+    // Redefine the global pointers for operator new and operator
+    // delete (these pointers are defined up in DTOOL) to vector into
+    // this class.
+    global_operator_new = &operator_new_handler;
+    global_operator_delete = &operator_delete_handler;
+  }
+
   _freeze_index = 0;
   _freeze_index = 0;
   _count = 0;
   _count = 0;
+  _allocated_size = 0;
+  _total_size = 0;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -382,24 +323,31 @@ get_global_ptr() {
 void MemoryUsage::
 void MemoryUsage::
 ns_record_pointer(ReferenceCount *ptr) {
 ns_record_pointer(ReferenceCount *ptr) {
   if (_track_memory_usage) {
   if (_track_memory_usage) {
-    MemoryInfo info;
-    info._ptr = ptr;
-    info._typed_ptr = (TypedObject *)NULL;
+    pair<Table::iterator, bool> insert_result =
+      _table.insert(Table::value_type((void *)ptr, MemoryInfo()));
+    
+    // This shouldn't fail.
+    assert(insert_result.first != _table.end());
+
+    if (insert_result.second) {
+      _count++;
+    }
+
+    MemoryInfo &info = (*insert_result.first).second;
+
+    // We shouldn't already have a ReferenceCount pointer.
+    if ((info._flags & MemoryInfo::F_got_ref) != 0) {
+      express_cat.error()
+        << "Pointer " << (void *)ptr << " recorded twice!\n";
+    }
+
+    info._void_ptr = (void *)ptr;
+    info._ref_ptr = ptr;
     info._static_type = ReferenceCount::get_class_type();
     info._static_type = ReferenceCount::get_class_type();
     info._dynamic_type = ReferenceCount::get_class_type();
     info._dynamic_type = ReferenceCount::get_class_type();
     info._time = TrueClock::get_ptr()->get_real_time();
     info._time = TrueClock::get_ptr()->get_real_time();
     info._freeze_index = _freeze_index;
     info._freeze_index = _freeze_index;
-    info._reconsider_dynamic_type = true;
-
-    Table::iterator ti;
-    ti = _table.find(ptr);
-    if (ti != _table.end()) {
-      express_cat.error() << "Pointer " << (void *)ptr << " recorded twice!\n";
-      (*ti).second = info;
-    } else {
-      _table[ptr] = info;
-      _count++;
-    }
+    info._flags |= (MemoryInfo::F_reconsider_dynamic_type | MemoryInfo::F_got_ref);
   }
   }
 }
 }
 
 
@@ -427,6 +375,8 @@ ns_update_type(ReferenceCount *ptr, TypeHandle type) {
     MemoryInfo &info = (*ti).second;
     MemoryInfo &info = (*ti).second;
     info.update_type_handle(info._static_type, type);
     info.update_type_handle(info._static_type, type);
     info.determine_dynamic_type();
     info.determine_dynamic_type();
+
+    consolidate_void_ptr(info);
   }
   }
 }
 }
 
 
@@ -456,6 +406,8 @@ ns_update_type(ReferenceCount *ptr, TypedObject *typed_ptr) {
     MemoryInfo &info = (*ti).second;
     MemoryInfo &info = (*ti).second;
     info._typed_ptr = typed_ptr;
     info._typed_ptr = typed_ptr;
     info.determine_dynamic_type();
     info.determine_dynamic_type();
+
+    consolidate_void_ptr(info);
   }
   }
 }
 }
 
 
@@ -481,6 +433,14 @@ ns_remove_pointer(ReferenceCount *ptr) {
 
 
     MemoryInfo &info = (*ti).second;
     MemoryInfo &info = (*ti).second;
 
 
+    if ((info._flags & MemoryInfo::F_got_ref) == 0) {
+      express_cat.error()
+        << "Pointer " << (void *)ptr << " deleted twice!\n";
+      return;
+    }
+
+    info._flags &= ~MemoryInfo::F_got_ref;
+
     // Since the pointer has been destructed, we can't safely call its
     // Since the pointer has been destructed, we can't safely call its
     // TypedObject virtual methods any more.  Better clear out the
     // TypedObject virtual methods any more.  Better clear out the
     // typed_ptr for good measure.
     // typed_ptr for good measure.
@@ -488,15 +448,143 @@ ns_remove_pointer(ReferenceCount *ptr) {
 
 
     if (info._freeze_index == _freeze_index) {
     if (info._freeze_index == _freeze_index) {
       double now = TrueClock::get_ptr()->get_real_time();
       double now = TrueClock::get_ptr()->get_real_time();
-      _count--;
-      _trend_types.add_info(info.get_type());
-      _trend_ages.add_info(now - info._time);
+      _trend_types.add_info(info.get_type(), info);
+      _trend_ages.add_info(now - info._time, info);
     }
     }
 
 
-    _table.erase(ti);
+    if ((info._flags & (MemoryInfo::F_got_ref | MemoryInfo::F_got_void)) == 0) {
+      // If we don't expect to call any more remove_*_pointer on this
+      // pointer, remove it from the table.
+      if (info._freeze_index == _freeze_index) {
+        _count--;
+        _allocated_size -= info._size;
+      }
+      _total_size -= info._size;
+
+      _table.erase(ti);
+    }
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryUsage::ns_record_void_pointer
+//       Access: Private
+//  Description: Records a pointer that's not even necessarily a
+//               ReferenceCount object (but for which we know the size
+//               of the allocated structure).
+////////////////////////////////////////////////////////////////////
+void MemoryUsage::
+ns_record_void_pointer(void *ptr, size_t size) {
+  if (_track_memory_usage) {
+    pair<Table::iterator, bool> insert_result =
+      _table.insert(Table::value_type((void *)ptr, MemoryInfo()));
+    
+    // This shouldn't fail.
+    assert(insert_result.first != _table.end());
+
+    if (insert_result.second) {
+      _count++;
+    }
+
+    MemoryInfo &info = (*insert_result.first).second;
+
+    // We shouldn't already have a void pointer.
+    if ((info._flags & MemoryInfo::F_got_void) != 0) {
+      express_cat.error()
+        << "Pointer " << (void *)ptr << " recorded twice!\n";
+    }
+
+    if (info._freeze_index == _freeze_index) {
+      _allocated_size += size - info._size;
+    } else {
+      _allocated_size += size;
+    }
+    _total_size += size - info._size;
+
+    info._void_ptr = ptr;
+    info._size = size;
+    info._time = TrueClock::get_ptr()->get_real_time();
+    info._freeze_index = _freeze_index;
+    info._flags |= (MemoryInfo::F_got_void | MemoryInfo::F_size_known);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryUsage::ns_remove_void_pointer
+//       Access: Private
+//  Description: Removes a pointer previously recorded via
+//               record_void_pointer.
+////////////////////////////////////////////////////////////////////
+void MemoryUsage::
+ns_remove_void_pointer(void *ptr) {
+  if (_track_memory_usage) {
+    Table::iterator ti;
+    ti = _table.find(ptr);
+    if (ti == _table.end()) {
+      // The pointer we tried to delete was not recorded in the table.
+
+      // We can't report this as an error, because (a) we might have
+      // removed the void pointer entry already when we consolidated,
+      // and (b) a few objects might have been created during static
+      // init time, before we grabbed the operator new/delete function
+      // handlers.
+      return;
+    }
+
+    MemoryInfo &info = (*ti).second;
+
+    if ((info._flags & MemoryInfo::F_got_void) == 0) {
+      express_cat.error()
+        << "Pointer " << (void *)ptr << " deleted twice!\n";
+      return;
+    }
+
+    if ((info._flags & MemoryInfo::F_got_ref) != 0) {
+      express_cat.error()
+        << "Pointer " << (void *)ptr << " did not destruct before being deleted!\n";
+    }
+
+    info._flags &= ~MemoryInfo::F_got_void;
+
+    if ((info._flags & (MemoryInfo::F_got_ref | MemoryInfo::F_got_void)) == 0) {
+      // If we don't expect to call any more remove_*_pointer on this
+      // pointer, remove it from the table.
+
+      if (info._freeze_index == _freeze_index) {
+        _count--;
+        _allocated_size -= info._size;
+      }
+      _total_size -= info._size;
+
+      _table.erase(ti);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryUsage::ns_get_allocated_size
+//       Access: Private
+//  Description: Returns the total number of bytes of allocated memory
+//               as counted, excluding the memory previously frozen.
+////////////////////////////////////////////////////////////////////
+size_t MemoryUsage::
+ns_get_allocated_size() {
+  nassertr(_track_memory_usage, 0);
+  return _allocated_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryUsage::ns_get_total_size
+//       Access: Private
+//  Description: Returns the total number of bytes of allocated memory
+//               as counted, including the memory previously frozen.
+////////////////////////////////////////////////////////////////////
+size_t MemoryUsage::
+ns_get_total_size() {
+  nassertr(_track_memory_usage, 0);
+  return _total_size;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: MemoryUsage::ns_get_num_pointers
 //     Function: MemoryUsage::ns_get_num_pointers
 //       Access: Private
 //       Access: Private
@@ -523,8 +611,9 @@ ns_get_pointers(MemoryUsagePointers &result) {
   Table::iterator ti;
   Table::iterator ti;
   for (ti = _table.begin(); ti != _table.end(); ++ti) {
   for (ti = _table.begin(); ti != _table.end(); ++ti) {
     MemoryInfo &info = (*ti).second;
     MemoryInfo &info = (*ti).second;
-    if (info._freeze_index == _freeze_index) {
-      result.add_entry(info._ptr, info._typed_ptr, info.get_type(),
+    if (info._freeze_index == _freeze_index &&
+        info._ref_ptr != (ReferenceCount *)NULL) {
+      result.add_entry(info._ref_ptr, info._typed_ptr, info.get_type(),
                        now - info._time);
                        now - info._time);
     }
     }
   }
   }
@@ -546,11 +635,12 @@ ns_get_pointers_of_type(MemoryUsagePointers &result, TypeHandle type) {
   Table::iterator ti;
   Table::iterator ti;
   for (ti = _table.begin(); ti != _table.end(); ++ti) {
   for (ti = _table.begin(); ti != _table.end(); ++ti) {
     MemoryInfo &info = (*ti).second;
     MemoryInfo &info = (*ti).second;
-    if (info._freeze_index == _freeze_index) {
+    if (info._freeze_index == _freeze_index &&
+        info._ref_ptr != (ReferenceCount *)NULL) {
       TypeHandle info_type = info.get_type();
       TypeHandle info_type = info.get_type();
       if (info_type != TypeHandle::none() &&
       if (info_type != TypeHandle::none() &&
           info_type.is_derived_from(type)) {
           info_type.is_derived_from(type)) {
-        result.add_entry(info._ptr, info._typed_ptr, info_type,
+        result.add_entry(info._ref_ptr, info._typed_ptr, info_type,
                          now - info._time);
                          now - info._time);
       }
       }
     }
     }
@@ -574,11 +664,12 @@ ns_get_pointers_of_age(MemoryUsagePointers &result,
   Table::iterator ti;
   Table::iterator ti;
   for (ti = _table.begin(); ti != _table.end(); ++ti) {
   for (ti = _table.begin(); ti != _table.end(); ++ti) {
     MemoryInfo &info = (*ti).second;
     MemoryInfo &info = (*ti).second;
-    if (info._freeze_index == _freeze_index) {
+    if (info._freeze_index == _freeze_index &&
+        info._ref_ptr != (ReferenceCount *)NULL) {
       double age = now - info._time;
       double age = now - info._time;
       if ((age >= from && age <= to) ||
       if ((age >= from && age <= to) ||
           (age >= to && age <= from)) {
           (age >= to && age <= from)) {
-        result.add_entry(info._ptr, info._typed_ptr, info.get_type(), age);
+        result.add_entry(info._ref_ptr, info._typed_ptr, info.get_type(), age);
       }
       }
     }
     }
   }
   }
@@ -616,10 +707,11 @@ ns_get_pointers_with_zero_count(MemoryUsagePointers &result) {
   Table::iterator ti;
   Table::iterator ti;
   for (ti = _table.begin(); ti != _table.end(); ++ti) {
   for (ti = _table.begin(); ti != _table.end(); ++ti) {
     MemoryInfo &info = (*ti).second;
     MemoryInfo &info = (*ti).second;
-    if (info._freeze_index == _freeze_index) {
-      if ((*ti).first->get_ref_count() == 0) {
-        (*ti).first->ref();
-        result.add_entry(info._ptr, info._typed_ptr, info.get_type(),
+    if (info._freeze_index == _freeze_index && 
+        info._ref_ptr != (ReferenceCount *)NULL) {
+      if (info._ref_ptr->get_ref_count() == 0) {
+        info._ref_ptr->ref();
+        result.add_entry(info._ref_ptr, info._typed_ptr, info.get_type(),
                          now - info._time);
                          now - info._time);
       }
       }
     }
     }
@@ -639,6 +731,7 @@ ns_get_pointers_with_zero_count(MemoryUsagePointers &result) {
 void MemoryUsage::
 void MemoryUsage::
 ns_freeze() {
 ns_freeze() {
   _count = 0;
   _count = 0;
+  _allocated_size = 0;
   _trend_types.clear();
   _trend_types.clear();
   _trend_ages.clear();
   _trend_ages.clear();
   _freeze_index++;
   _freeze_index++;
@@ -658,7 +751,7 @@ ns_show_current_types() {
   for (ti = _table.begin(); ti != _table.end(); ++ti) {
   for (ti = _table.begin(); ti != _table.end(); ++ti) {
     MemoryInfo &info = (*ti).second;
     MemoryInfo &info = (*ti).second;
     if (info._freeze_index == _freeze_index) {
     if (info._freeze_index == _freeze_index) {
-      hist.add_info(info.get_type());
+      hist.add_info(info.get_type(), info);
     }
     }
   }
   }
 
 
@@ -692,7 +785,7 @@ ns_show_current_ages() {
   for (ti = _table.begin(); ti != _table.end(); ++ti) {
   for (ti = _table.begin(); ti != _table.end(); ++ti) {
     MemoryInfo &info = (*ti).second;
     MemoryInfo &info = (*ti).second;
     if (info._freeze_index == _freeze_index) {
     if (info._freeze_index == _freeze_index) {
-      hist.add_info(now - info._time);
+      hist.add_info(now - info._time, info);
     }
     }
   }
   }
 
 
@@ -711,6 +804,68 @@ ns_show_trend_ages() {
   _trend_ages.show();
   _trend_ages.show();
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryUsage::consolidate_void_ptr
+//       Access: Private
+//  Description: If the size information has not yet been determined
+//               for this pointer, checks to see if it has possible
+//               been recorded under the TypedObject pointer (this
+//               will happen when the class inherits from TypedObject
+//               before ReferenceCount, e.g. TypedReferenceCount).
+////////////////////////////////////////////////////////////////////
+void MemoryUsage::
+consolidate_void_ptr(MemoryInfo &info) {
+  if (info.is_size_known()) {
+    // We already know the size, so no sweat.
+    return;
+  }
+
+  if (info.get_typed_ptr() == (TypedObject *)NULL) {
+    // We don't have a typed pointer for this thing yet.
+    return;
+  }
+
+  void *typed_ptr = (void *)info.get_typed_ptr();
+
+  if (typed_ptr == (void *)info.get_ref_ptr()) {
+    // The TypedObject pointer is the same pointer as the
+    // ReferenceCount pointer, so there's no point in looking it up
+    // separately.  Actually, this really shouldn't even be possible.
+    return;
+  }
+
+  Table::iterator ti;
+  ti = _table.find(typed_ptr);
+  if (ti == _table.end()) {
+    // No entry for the typed pointer, either.
+    return;
+  }
+
+  // We do have an entry!  Copy over the relevant pieces.
+  MemoryInfo &typed_info = (*ti).second;
+
+  if (typed_info.is_size_known()) {
+    info._size = typed_info.get_size();
+    info._flags |= MemoryInfo::F_size_known;
+    if (typed_info._freeze_index == _freeze_index) {
+      _allocated_size += info._size;
+    }
+  }
+
+  // The typed_ptr is clearly the more accurate pointer to the
+  // beginning of the structure.
+  info._void_ptr = typed_ptr;
+
+  // Now that we've consolidated the pointers, remove the void pointer
+  // entry.
+  if (info._freeze_index == _freeze_index) {
+    _count--;
+    _allocated_size -= info._size;
+  }
+    
+
+  _table.erase(ti);
+}
 
 
 
 
 #endif  // NDEBUG
 #endif  // NDEBUG

+ 31 - 25
panda/src/express/memoryUsage.h

@@ -22,6 +22,8 @@
 #include <pandabase.h>
 #include <pandabase.h>
 
 
 #include "typedObject.h"
 #include "typedObject.h"
+#include "memoryInfo.h"
+#include "memoryUsagePointerCounts.h"
 
 
 #include <map>
 #include <map>
 
 
@@ -42,7 +44,6 @@ class EXPCL_PANDAEXPRESS MemoryUsage {
 public:
 public:
   INLINE static bool get_track_memory_usage();
   INLINE static bool get_track_memory_usage();
 
 
-PUBLISHED:
 #if defined(__GNUC__) && !defined(NDEBUG)
 #if defined(__GNUC__) && !defined(NDEBUG)
   // There seems to be a problem with egcs-2.91.66: it gets confused
   // There seems to be a problem with egcs-2.91.66: it gets confused
   // with too many nested inline functions, and sets the wrong pointer
   // with too many nested inline functions, and sets the wrong pointer
@@ -62,7 +63,20 @@ PUBLISHED:
   INLINE static void remove_pointer(ReferenceCount *ptr);
   INLINE static void remove_pointer(ReferenceCount *ptr);
 #endif // __GNUC__ && !NDEBUG
 #endif // __GNUC__ && !NDEBUG
 
 
-#ifndef NDEBUG
+#ifdef NDEBUG
+public:
+  INLINE static bool is_tracking() { return false; }
+  INLINE static size_t get_allocated_size() { return 0; }
+
+#else  // NDEBUG
+public:
+  static void *operator_new_handler(size_t size);
+  static void operator_delete_handler(void *ptr);
+
+PUBLISHED:
+  INLINE static bool is_tracking();
+  INLINE static size_t get_allocated_size();
+  INLINE static size_t get_total_size();
   INLINE static int get_num_pointers();
   INLINE static int get_num_pointers();
   INLINE static void get_pointers(MemoryUsagePointers &result);
   INLINE static void get_pointers(MemoryUsagePointers &result);
   INLINE static void get_pointers_of_type(MemoryUsagePointers &result,
   INLINE static void get_pointers_of_type(MemoryUsagePointers &result,
@@ -87,6 +101,11 @@ private:
   void ns_update_type(ReferenceCount *ptr, TypedObject *typed_ptr);
   void ns_update_type(ReferenceCount *ptr, TypedObject *typed_ptr);
   void ns_remove_pointer(ReferenceCount *ptr);
   void ns_remove_pointer(ReferenceCount *ptr);
 
 
+  void ns_record_void_pointer(void *ptr, size_t size);
+  void ns_remove_void_pointer(void *ptr);
+
+  size_t ns_get_allocated_size();
+  size_t ns_get_total_size();
   int ns_get_num_pointers();
   int ns_get_num_pointers();
   void ns_get_pointers(MemoryUsagePointers &result);
   void ns_get_pointers(MemoryUsagePointers &result);
   void ns_get_pointers_of_type(MemoryUsagePointers &result,
   void ns_get_pointers_of_type(MemoryUsagePointers &result,
@@ -101,38 +120,25 @@ private:
   void ns_show_current_ages();
   void ns_show_current_ages();
   void ns_show_trend_ages();
   void ns_show_trend_ages();
 
 
-  static MemoryUsage *_global_ptr;
+  void consolidate_void_ptr(MemoryInfo &info);
 
 
-  class MemoryInfo {
-  public:
-    TypeHandle get_type();
-    void determine_dynamic_type();
-    void update_type_handle(TypeHandle &destination, TypeHandle refined);
-
-    ReferenceCount *_ptr;
-    TypedObject *_typed_ptr;
-    TypeHandle _static_type;
-    TypeHandle _dynamic_type;
-
-    double _time;
-    int _freeze_index;
-    bool _reconsider_dynamic_type;
-  };
+  static MemoryUsage *_global_ptr;
 
 
-  typedef map<ReferenceCount *, MemoryInfo> Table;
+  typedef map<void *, MemoryInfo> Table;
   Table _table;
   Table _table;
   int _freeze_index;
   int _freeze_index;
   int _count;
   int _count;
-
+  size_t _allocated_size;
+  size_t _total_size;
 
 
   class TypeHistogram {
   class TypeHistogram {
   public:
   public:
-    void add_info(TypeHandle type);
+    void add_info(TypeHandle type, MemoryInfo &info);
     void show() const;
     void show() const;
     void clear();
     void clear();
 
 
   private:
   private:
-    typedef map<TypeHandle, int> Counts;
+    typedef map<TypeHandle, MemoryUsagePointerCounts> Counts;
     Counts _counts;
     Counts _counts;
   };
   };
   TypeHistogram _trend_types;
   TypeHistogram _trend_types;
@@ -140,7 +146,7 @@ private:
   class AgeHistogram {
   class AgeHistogram {
   public:
   public:
     AgeHistogram();
     AgeHistogram();
-    void add_info(double age);
+    void add_info(double age, MemoryInfo &info);
     void show() const;
     void show() const;
     void clear();
     void clear();
 
 
@@ -148,7 +154,7 @@ private:
     int choose_bucket(double age) const;
     int choose_bucket(double age) const;
 
 
     enum { num_buckets = 5 };
     enum { num_buckets = 5 };
-    int _counts[num_buckets];
+    MemoryUsagePointerCounts _counts[num_buckets];
     static double _cutoff[num_buckets];
     static double _cutoff[num_buckets];
   };
   };
   AgeHistogram _trend_ages;
   AgeHistogram _trend_ages;
@@ -156,7 +162,7 @@ private:
 
 
   bool _track_memory_usage;
   bool _track_memory_usage;
 
 
-#endif
+#endif  // NDEBUG
 };
 };
 
 
 #include "memoryUsage.I"
 #include "memoryUsage.I"

+ 128 - 0
panda/src/express/memoryUsagePointerCounts.I

@@ -0,0 +1,128 @@
+// Filename: memoryUsagePointerCounts.I
+// Created by:  drose (04Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryUsagePointerCounts::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE MemoryUsagePointerCounts::
+MemoryUsagePointerCounts() {
+  _count = 0;
+  _unknown_size_count = 0;
+  _size = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryUsagePointerCounts::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE MemoryUsagePointerCounts::
+MemoryUsagePointerCounts(const MemoryUsagePointerCounts &copy) :
+  _count(copy._count),
+  _unknown_size_count(copy._unknown_size_count),
+  _size(copy._size)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryUsagePointerCounts::Copy Assignment
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void MemoryUsagePointerCounts::
+operator = (const MemoryUsagePointerCounts &copy) {
+  _count = copy._count;
+  _unknown_size_count = copy._unknown_size_count;
+  _size = copy._size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryUsagePointerCounts::clear
+//       Access: Public
+//  Description: Resets the counter to empty.
+////////////////////////////////////////////////////////////////////
+INLINE void MemoryUsagePointerCounts::
+clear() {
+  _count = 0;
+  _unknown_size_count = 0;
+  _size = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryUsagePointerCounts::is_size_unknown
+//       Access: Public
+//  Description: Returns true if none of the pointers in the count
+//               have a known size, or false if at least one of them
+//               does.
+////////////////////////////////////////////////////////////////////
+INLINE bool MemoryUsagePointerCounts::
+is_size_unknown() const {
+  return _unknown_size_count == _count;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryUsagePointerCounts::get_size
+//       Access: Public
+//  Description: Returns the total allocated size of all pointers in
+//               the count whose size is known.
+////////////////////////////////////////////////////////////////////
+INLINE size_t MemoryUsagePointerCounts::
+get_size() const {
+  return _size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryUsagePointerCounts::get_count
+//       Access: Public
+//  Description: Returns the total number of pointers in the count.
+////////////////////////////////////////////////////////////////////
+INLINE int MemoryUsagePointerCounts::
+get_count() const {
+  return _count;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryUsagePointerCounts::Ordering Operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool MemoryUsagePointerCounts::
+operator < (const MemoryUsagePointerCounts &other) const {
+  if (is_size_unknown() != other.is_size_unknown()) {
+    return is_size_unknown() > other.is_size_unknown();
+  }
+
+  if (get_size() != other.get_size()) {
+    return get_size() < other.get_size();
+  }
+
+  if (get_count() != other.get_count()) {
+    return get_count() != other.get_count();
+  }
+
+  return false;
+}
+
+INLINE ostream &
+operator << (ostream &out, const MemoryUsagePointerCounts &c) {
+  c.output(out);
+  return out;
+}

+ 77 - 0
panda/src/express/memoryUsagePointerCounts.cxx

@@ -0,0 +1,77 @@
+// Filename: memoryUsagePointerCounts.cxx
+// Created by:  drose (04Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+#include "memoryUsagePointerCounts.h"
+#include "memoryInfo.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryUsagePointerCounts::add_info
+//       Access: Public
+//  Description: Adds a pointer definition to the counter.
+////////////////////////////////////////////////////////////////////
+void MemoryUsagePointerCounts::
+add_info(MemoryInfo &info) {
+  _count++;
+
+  if (info.is_size_known()) {
+    _size += info.get_size();
+  } else {
+    _unknown_size_count++;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryUsagePointerCounts::output
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void MemoryUsagePointerCounts::
+output(ostream &out) const {
+  out << _count << " pointers";
+  if (_unknown_size_count < _count) {
+    out << ", ";
+    output_bytes(out, _size);
+    out << ", ";
+    output_bytes(out, _size / (_count - _unknown_size_count));
+    out << " each";
+      
+    if (_unknown_size_count != 0) {
+      out << " (" << _unknown_size_count << " of unknown size)";
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryUsagePointerCounts::output_bytes
+//       Access: Private, Static
+//  Description: Formats a size in bytes in a meaningful and concise
+//               way for output, with units.
+////////////////////////////////////////////////////////////////////
+void MemoryUsagePointerCounts::
+output_bytes(ostream &out, size_t size) {
+  if (size < 4 * 1024) {
+    out << size << " bytes";
+    
+  } else if (size < 4 * 1024 * 1024) {
+    out << size / 1024 << " Kb";
+    
+  } else {
+    out << size / (1024 * 1024) << " Mb";
+  }
+}

+ 67 - 0
panda/src/express/memoryUsagePointerCounts.h

@@ -0,0 +1,67 @@
+// Filename: memoryUsagePointerCounts.h
+// Created by:  drose (04Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef MEMORYUSAGEPOINTERCOUNTS_H
+#define MEMORYUSAGEPOINTERCOUNTS_H
+
+#include <pandabase.h>
+
+class MemoryInfo;
+
+#ifndef NDEBUG
+////////////////////////////////////////////////////////////////////
+//       Class : MemoryUsagePointerCounts
+// Description : This is a supporting class for MemoryUsage.  It
+//               tracks the relative counts of a number of pointers of
+//               some type (or age), for use by TypeHistogram and
+//               AgeHistogram.  It's not exported from the DLL, and it
+//               doesn't even exist if we're compiling NDEBUG.
+////////////////////////////////////////////////////////////////////
+class MemoryUsagePointerCounts {
+public:
+  INLINE MemoryUsagePointerCounts();
+  INLINE MemoryUsagePointerCounts(const MemoryUsagePointerCounts &copy);
+  INLINE void operator = (const MemoryUsagePointerCounts &copy);
+
+  INLINE void clear();
+  void add_info(MemoryInfo &info);
+  void output(ostream &out) const;
+
+  INLINE bool is_size_unknown() const;
+  INLINE size_t get_size() const;
+  INLINE int get_count() const;
+
+  INLINE bool operator < (const MemoryUsagePointerCounts &other) const;
+
+private:
+  static void output_bytes(ostream &out, size_t size);
+
+private:
+  int _count;
+  int _unknown_size_count;
+  size_t _size;
+};
+
+INLINE ostream &operator << (ostream &out, const MemoryUsagePointerCounts &c);
+
+#include "memoryUsagePointerCounts.I"
+
+#endif  // NDEBUG
+
+#endif
+

+ 10 - 10
panda/src/express/memoryUsagePointers.I

@@ -22,14 +22,14 @@
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE MemoryUsagePointers::Entry::
 INLINE MemoryUsagePointers::Entry::
-Entry(ReferenceCount *ptr, TypedObject *typed_ptr,
+Entry(ReferenceCount *ref_ptr, TypedObject *typed_ptr,
       TypeHandle type, double age) :
       TypeHandle type, double age) :
-  _ptr(ptr),
+  _ref_ptr(ref_ptr),
   _typed_ptr(typed_ptr),
   _typed_ptr(typed_ptr),
   _type(type),
   _type(type),
   _age(age)
   _age(age)
 {
 {
-  _ptr->ref();
+  _ref_ptr->ref();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -39,12 +39,12 @@ Entry(ReferenceCount *ptr, TypedObject *typed_ptr,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE MemoryUsagePointers::Entry::
 INLINE MemoryUsagePointers::Entry::
 Entry(const Entry &copy) :
 Entry(const Entry &copy) :
-  _ptr(copy._ptr),
+  _ref_ptr(copy._ref_ptr),
   _typed_ptr(copy._typed_ptr),
   _typed_ptr(copy._typed_ptr),
   _type(copy._type),
   _type(copy._type),
   _age(copy._age)
   _age(copy._age)
 {
 {
-  _ptr->ref();
+  _ref_ptr->ref();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -54,12 +54,12 @@ Entry(const Entry &copy) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void MemoryUsagePointers::Entry::
 INLINE void MemoryUsagePointers::Entry::
 operator = (const Entry &copy) {
 operator = (const Entry &copy) {
-  if (_ptr != copy._ptr) {
-    _ptr->unref();
-    _ptr = copy._ptr;
+  if (_ref_ptr != copy._ref_ptr) {
+    _ref_ptr->unref();
+    _ref_ptr = copy._ref_ptr;
     // We can't call unref_delete(), because we don't know what kind
     // We can't call unref_delete(), because we don't know what kind
     // of pointer it is precisely.  Potential leak.
     // of pointer it is precisely.  Potential leak.
-    _ptr->ref();
+    _ref_ptr->ref();
   }
   }
   _typed_ptr = copy._typed_ptr;
   _typed_ptr = copy._typed_ptr;
   _type = copy._type;
   _type = copy._type;
@@ -75,6 +75,6 @@ INLINE MemoryUsagePointers::Entry::
 ~Entry() {
 ~Entry() {
   // We can't call unref_delete(), because we don't know what kind
   // We can't call unref_delete(), because we don't know what kind
   // of pointer it is precisely.  Potential leak.
   // of pointer it is precisely.  Potential leak.
-  _ptr->unref();
+  _ref_ptr->unref();
 }
 }
 
 

+ 6 - 6
panda/src/express/memoryUsagePointers.cxx

@@ -78,7 +78,7 @@ get_num_pointers() const {
 ReferenceCount *MemoryUsagePointers::
 ReferenceCount *MemoryUsagePointers::
 get_pointer(int n) const {
 get_pointer(int n) const {
   nassertr(n >= 0 && n < get_num_pointers(), NULL);
   nassertr(n >= 0 && n < get_num_pointers(), NULL);
-  return _entries[n]._ptr;
+  return _entries[n]._ref_ptr;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -98,7 +98,7 @@ get_typed_pointer(int n) const {
     return typed_ptr;
     return typed_ptr;
   }
   }
 
 
-  ReferenceCount *ptr = _entries[n]._ptr;
+  ReferenceCount *ref_ptr = _entries[n]._ref_ptr;
 
 
   TypeHandle type = _entries[n]._type;
   TypeHandle type = _entries[n]._type;
 
 
@@ -116,7 +116,7 @@ get_typed_pointer(int n) const {
 
 
   if (type != TypeHandle::none() &&
   if (type != TypeHandle::none() &&
       type.is_derived_from(TypedReferenceCount::get_class_type())) {
       type.is_derived_from(TypedReferenceCount::get_class_type())) {
-    return (TypedReferenceCount *)ptr;
+    return (TypedReferenceCount *)ref_ptr;
   }
   }
   return NULL;
   return NULL;
 }
 }
@@ -176,13 +176,13 @@ clear() {
 //               only by MemoryUsage.
 //               only by MemoryUsage.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void MemoryUsagePointers::
 void MemoryUsagePointers::
-add_entry(ReferenceCount *ptr, TypedObject *typed_ptr,
+add_entry(ReferenceCount *ref_ptr, TypedObject *typed_ptr,
           TypeHandle type, double age) {
           TypeHandle type, double age) {
   // We can't safly add pointers with a zero reference count.  They
   // We can't safly add pointers with a zero reference count.  They
   // might be statically-allocated or something, and if we try to add
   // might be statically-allocated or something, and if we try to add
   // them they'll try to destruct when the PointerTo later goes away.
   // them they'll try to destruct when the PointerTo later goes away.
-  if (ptr->get_ref_count() != 0) {
-    _entries.push_back(Entry(ptr, typed_ptr, type, age));
+  if (ref_ptr->get_ref_count() != 0) {
+    _entries.push_back(Entry(ref_ptr, typed_ptr, type, age));
   }
   }
 }
 }
 
 

+ 3 - 3
panda/src/express/memoryUsagePointers.h

@@ -64,12 +64,12 @@ PUBLISHED:
   void clear();
   void clear();
 
 
 private:
 private:
-  void add_entry(ReferenceCount *ptr, TypedObject *typed_ptr,
+  void add_entry(ReferenceCount *ref_ptr, TypedObject *typed_ptr,
                  TypeHandle type, double age);
                  TypeHandle type, double age);
 
 
   class Entry {
   class Entry {
   public:
   public:
-    INLINE Entry(ReferenceCount *ptr, TypedObject *typed_ptr,
+    INLINE Entry(ReferenceCount *ref_ptr, TypedObject *typed_ptr,
                  TypeHandle type, double age);
                  TypeHandle type, double age);
     INLINE Entry(const Entry &copy);
     INLINE Entry(const Entry &copy);
     INLINE void operator = (const Entry &copy);
     INLINE void operator = (const Entry &copy);
@@ -80,7 +80,7 @@ private:
     // (since ReferenceCount has no public destructor).  If we can't
     // (since ReferenceCount has no public destructor).  If we can't
     // delete it, we can't make a PointerTo it, since PointerTo wants
     // delete it, we can't make a PointerTo it, since PointerTo wants
     // to be able to delete things.
     // to be able to delete things.
-    ReferenceCount *_ptr;
+    ReferenceCount *_ref_ptr;
     TypedObject *_typed_ptr;
     TypedObject *_typed_ptr;
     TypeHandle _type;
     TypeHandle _type;
     double _age;
     double _age;

+ 1 - 1
panda/src/express/referenceCount.h

@@ -118,7 +118,7 @@ private:
 //               only works when the base type is, in fact, a class.
 //               only works when the base type is, in fact, a class.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template<class Base>
 template<class Base>
-class EXPCL_PANDAEXPRESS RefCountObj : public Base, public ReferenceCount {
+class EXPCL_PANDAEXPRESS RefCountObj : public ReferenceCount, public Base {
 public:
 public:
   INLINE RefCountObj();
   INLINE RefCountObj();
   INLINE RefCountObj(const Base &copy);
   INLINE RefCountObj(const Base &copy);

+ 3 - 11
panda/src/glgsg/glGraphicsStateGuardian.cxx

@@ -495,9 +495,7 @@ render_frame(const AllAttributesWrapper &initial_state) {
   // texture state has changed, we have to be sure to clear the
   // texture state has changed, we have to be sure to clear the
   // current texture state now.  A bit unfortunate, but probably not
   // current texture state now.  A bit unfortunate, but probably not
   // measurably expensive.
   // measurably expensive.
-  NodeAttributes state;
-  state.set_attribute(TextureTransition::get_class_type(), new TextureAttribute);
-  set_state(state, false);
+  clear_attribute(TextureTransition::get_class_type());
 #endif
 #endif
 
 
   if (_clear_buffer_type != 0) {
   if (_clear_buffer_type != 0) {
@@ -558,9 +556,7 @@ render_frame(const AllAttributesWrapper &initial_state) {
     // Also force the lighting state to unlit, so that issue_light()
     // Also force the lighting state to unlit, so that issue_light()
     // will be guaranteed to be called next frame even if we have the
     // will be guaranteed to be called next frame even if we have the
     // same set of light pointers we had this frame.
     // same set of light pointers we had this frame.
-    NodeAttributes state;
-    state.set_attribute(LightTransition::get_class_type(), new LightAttribute);
-    set_state(state, false);
+    clear_attribute(LightTransition::get_class_type());
 
 
     // All this work to undo the lighting state each frame doesn't seem
     // All this work to undo the lighting state each frame doesn't seem
     // ideal--there may be a better way.  Maybe if the lights were just
     // ideal--there may be a better way.  Maybe if the lights were just
@@ -1997,15 +1993,11 @@ copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
   //  activate();
   //  activate();
   set_pack_alignment(1);
   set_pack_alignment(1);
 
 
-  NodeAttributes state;
-
   // Bug fix for RE, RE2, and VTX - need to disable texturing in order
   // Bug fix for RE, RE2, and VTX - need to disable texturing in order
   // for glReadPixels() to work
   // for glReadPixels() to work
   // NOTE: reading the depth buffer is *much* slower than reading the
   // NOTE: reading the depth buffer is *much* slower than reading the
   // color buffer
   // color buffer
-  state.set_attribute(TextureTransition::get_class_type(),
-              new TextureAttribute);
-  set_state(state, false);
+  clear_attribute(TextureTransition::get_class_type());
 
 
   int xo, yo, w, h;
   int xo, yo, w, h;
   dr->get_region_pixels(xo, yo, w, h);
   dr->get_region_pixels(xo, yo, w, h);

+ 10 - 0
panda/src/graph/nodeAttributes.I

@@ -77,6 +77,16 @@ insert(NodeAttributes::iterator position,
   return _attributes.insert(position, x);
   return _attributes.insert(position, x);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: NodeAttributes::find
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE_GRAPH NodeAttributes::iterator NodeAttributes::
+find(const key_type &k) {
+  return _attributes.find(k);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NodeAttributes::erase
 //     Function: NodeAttributes::erase
 //       Access: Public
 //       Access: Public

+ 2 - 0
panda/src/graph/nodeAttributes.h

@@ -64,6 +64,7 @@ public:
   // of PANDA.DLL.
   // of PANDA.DLL.
   typedef Attributes::iterator iterator;
   typedef Attributes::iterator iterator;
   typedef Attributes::const_iterator const_iterator;
   typedef Attributes::const_iterator const_iterator;
+  typedef Attributes::key_type key_type;
   typedef Attributes::value_type value_type;
   typedef Attributes::value_type value_type;
   typedef Attributes::size_type size_type;
   typedef Attributes::size_type size_type;
 
 
@@ -73,6 +74,7 @@ public:
   INLINE_GRAPH const_iterator begin() const;
   INLINE_GRAPH const_iterator begin() const;
   INLINE_GRAPH const_iterator end() const;
   INLINE_GRAPH const_iterator end() const;
   INLINE_GRAPH iterator insert(iterator position, const value_type &x);
   INLINE_GRAPH iterator insert(iterator position, const value_type &x);
+  INLINE_GRAPH iterator find(const key_type &k);
   INLINE_GRAPH void erase(iterator position);
   INLINE_GRAPH void erase(iterator position);
 
 
 public:
 public:

+ 15 - 0
panda/src/graph/nodeRelation.I

@@ -289,6 +289,21 @@ get_last_update() const {
   return _last_update;
   return _last_update;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: NodeRelation::clear_wrt_cache
+//       Access: Public
+//  Description: Blows away the wrt cache information on this arc.
+//               This forces the wrt to be recomputed next time it is
+//               asked for.
+////////////////////////////////////////////////////////////////////
+INLINE_GRAPH void NodeRelation::
+clear_wrt_cache() {
+  _net_transitions.clear();
+  _top_subtree = (Node *)NULL;
+  _all_verified = UpdateSeq::initial();
+  _last_update = ++last_graph_update(_graph_type);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NodeRelation::create_typed_arc
 //     Function: NodeRelation::create_typed_arc
 //       Access: Public, Static
 //       Access: Public, Static

+ 1 - 0
panda/src/graph/nodeRelation.h

@@ -122,6 +122,7 @@ PUBLISHED:
   INLINE_GRAPH int compare_transitions_to(const NodeRelation *arc) const;
   INLINE_GRAPH int compare_transitions_to(const NodeRelation *arc) const;
 
 
   INLINE_GRAPH UpdateSeq get_last_update() const;
   INLINE_GRAPH UpdateSeq get_last_update() const;
+  INLINE_GRAPH void clear_wrt_cache();
 
 
 public:
 public:
   bool sub_render_trans(const AllAttributesWrapper &attrib,
   bool sub_render_trans(const AllAttributesWrapper &attrib,

+ 12 - 0
panda/src/pstatclient/pStatClient.cxx

@@ -39,6 +39,10 @@
 
 
 PStatClient *PStatClient::_global_pstats = NULL;
 PStatClient *PStatClient::_global_pstats = NULL;
 
 
+#ifndef CPPPARSER
+PStatCollector _memory_usage_pcollector("Panda memory usage");
+#endif
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PStatClient::PerThreadData::Constructor
 //     Function: PStatClient::PerThreadData::Constructor
 //       Access: Public
 //       Access: Public
@@ -363,6 +367,14 @@ make_thread(const string &name) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PStatClient::
 void PStatClient::
 main_tick() {
 main_tick() {
+  // We have code here to report the memory usage.  We can't put this
+  // code inside the MemoryUsage class, where it fits a little better,
+  // simply because MemoryUsage is a very low-level class that doesn't
+  // know about PStatClient.
+  if (MemoryUsage::is_tracking()) {
+    _memory_usage_pcollector.set_level(MemoryUsage::get_total_size());
+  }
+  
   get_global_pstats()->get_main_thread().new_frame();
   get_global_pstats()->get_main_thread().new_frame();
 }
 }
 
 

+ 1 - 0
panda/src/pstatclient/pStatProperties.cxx

@@ -147,6 +147,7 @@ static LevelCollectorProperties level_properties[] = {
   { 1, "State changes",                    { 1.0, 0.5, 0.2 },  "", 500.0 },
   { 1, "State changes",                    { 1.0, 0.5, 0.2 },  "", 500.0 },
   { 1, "State changes:Transforms",         { 0.2, 0.2, 0.8 }, },
   { 1, "State changes:Transforms",         { 0.2, 0.2, 0.8 }, },
   { 1, "State changes:Textures",           { 0.8, 0.2, 0.2 }, },
   { 1, "State changes:Textures",           { 0.8, 0.2, 0.2 }, },
+  { 1, "Panda memory usage",               { 0.8, 0.2, 0.5 },  "MB", 64, 1048576 },
   { 0, NULL }
   { 0, NULL }
 };
 };
 
 

+ 34 - 34
panda/src/putil/pointerToArray.I

@@ -17,10 +17,10 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 template<class Element>
 template<class Element>
-vector<Element> PointerToArray<Element>::_empty_array;
+pvector<Element> PointerToArray<Element>::_empty_array;
 
 
 template<class Element>
 template<class Element>
-vector<Element> ConstPointerToArray<Element>::_empty_array;
+pvector<Element> ConstPointerToArray<Element>::_empty_array;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PointerToArray::Constructor
 //     Function: PointerToArray::Constructor
@@ -30,7 +30,7 @@ vector<Element> ConstPointerToArray<Element>::_empty_array;
 template<class Element>
 template<class Element>
 INLINE PointerToArray<Element>::
 INLINE PointerToArray<Element>::
 PointerToArray() :
 PointerToArray() :
-  PointerToBase<RefCountObj<vector<Element> > >((RefCountObj<vector<Element> > *)NULL)
+  PointerToBase<RefCountObj<pvector<Element> > >((RefCountObj<pvector<Element> > *)NULL)
 {
 {
 }
 }
 
 
@@ -42,7 +42,7 @@ PointerToArray() :
 template<class Element>
 template<class Element>
 INLINE PointerToArray<Element>::
 INLINE PointerToArray<Element>::
 PointerToArray(size_type n) :
 PointerToArray(size_type n) :
-  PointerToBase<RefCountObj<vector<Element> > >(new RefCountObj<vector<Element> >) {
+  PointerToBase<RefCountObj<pvector<Element> > >(new RefCountObj<pvector<Element> >) {
   _ptr->reserve(n);
   _ptr->reserve(n);
   insert(begin(), n, Element());
   insert(begin(), n, Element());
 }
 }
@@ -55,7 +55,7 @@ PointerToArray(size_type n) :
 template<class Element>
 template<class Element>
 INLINE PointerToArray<Element>::
 INLINE PointerToArray<Element>::
 PointerToArray(size_type n, const Element &value) :
 PointerToArray(size_type n, const Element &value) :
-  PointerToBase<RefCountObj<vector<Element> > >(new RefCountObj<vector<Element> >) {
+  PointerToBase<RefCountObj<pvector<Element> > >(new RefCountObj<pvector<Element> >) {
   _ptr->reserve(n);
   _ptr->reserve(n);
   insert(begin(), n, value);
   insert(begin(), n, value);
 }
 }
@@ -68,7 +68,7 @@ PointerToArray(size_type n, const Element &value) :
 template<class Element>
 template<class Element>
 INLINE PointerToArray<Element>::
 INLINE PointerToArray<Element>::
 PointerToArray(const PointerToArray<Element> &copy) :
 PointerToArray(const PointerToArray<Element> &copy) :
-  PointerToBase<RefCountObj<vector<Element> > >(copy)
+  PointerToBase<RefCountObj<pvector<Element> > >(copy)
 {
 {
 }
 }
 
 
@@ -148,7 +148,7 @@ template<class Element>
 INLINE PointerToArray<Element>::size_type PointerToArray<Element>::
 INLINE PointerToArray<Element>::size_type PointerToArray<Element>::
 max_size() const {
 max_size() const {
   nassertd(_ptr != NULL) {
   nassertd(_ptr != NULL) {
-    ((PointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
+    ((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
   }
   }
   return _ptr->max_size();
   return _ptr->max_size();
 }
 }
@@ -173,7 +173,7 @@ template<class Element>
 INLINE void PointerToArray<Element>::
 INLINE void PointerToArray<Element>::
 reserve(PointerToArray<Element>::size_type n) {
 reserve(PointerToArray<Element>::size_type n) {
   if (_ptr == NULL) {
   if (_ptr == NULL) {
-    reassign(new RefCountObj<vector<Element> >);
+    reassign(new RefCountObj<pvector<Element> >);
   }
   }
   _ptr->reserve(n);
   _ptr->reserve(n);
 }
 }
@@ -199,7 +199,7 @@ template<class Element>
 INLINE PointerToArray<Element>::reference PointerToArray<Element>::
 INLINE PointerToArray<Element>::reference PointerToArray<Element>::
 front() const {
 front() const {
   nassertd(_ptr != NULL) {
   nassertd(_ptr != NULL) {
-    ((PointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
+    ((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
   }
   }
   nassertd(!_ptr->empty()) {
   nassertd(!_ptr->empty()) {
     _ptr->push_back(Element());
     _ptr->push_back(Element());
@@ -216,7 +216,7 @@ template<class Element>
 INLINE PointerToArray<Element>::reference PointerToArray<Element>::
 INLINE PointerToArray<Element>::reference PointerToArray<Element>::
 back() const {
 back() const {
   nassertd(_ptr != NULL) {
   nassertd(_ptr != NULL) {
-    ((PointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
+    ((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
   }
   }
   nassertd(!_ptr->empty()) {
   nassertd(!_ptr->empty()) {
     _ptr->push_back(Element());
     _ptr->push_back(Element());
@@ -261,7 +261,7 @@ template<class Element>
 INLINE void PointerToArray<Element>::
 INLINE void PointerToArray<Element>::
 erase(iterator position) const {
 erase(iterator position) const {
   nassertd(_ptr != NULL) {
   nassertd(_ptr != NULL) {
-    ((PointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
+    ((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
   }
   }
   nassertv(position >= _ptr->begin() &&
   nassertv(position >= _ptr->begin() &&
            position <= _ptr->end());
            position <= _ptr->end());
@@ -277,7 +277,7 @@ template<class Element>
 INLINE void PointerToArray<Element>::
 INLINE void PointerToArray<Element>::
 erase(iterator first, iterator last) const {
 erase(iterator first, iterator last) const {
   nassertd(_ptr != NULL) {
   nassertd(_ptr != NULL) {
-    ((PointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
+    ((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
   }
   }
   nassertv(first >= _ptr->begin() && first <= _ptr->end());
   nassertv(first >= _ptr->begin() && first <= _ptr->end());
   nassertv(last >= _ptr->begin() && last <= _ptr->end());
   nassertv(last >= _ptr->begin() && last <= _ptr->end());
@@ -294,7 +294,7 @@ template<class Element>
 INLINE PointerToArray<Element>::reference PointerToArray<Element>::
 INLINE PointerToArray<Element>::reference PointerToArray<Element>::
 operator [](size_type n) const {
 operator [](size_type n) const {
   nassertd(_ptr != NULL) {
   nassertd(_ptr != NULL) {
-    ((PointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
+    ((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
   }
   }
   nassertd(!_ptr->empty()) {
   nassertd(!_ptr->empty()) {
     _ptr->push_back(Element());
     _ptr->push_back(Element());
@@ -313,7 +313,7 @@ template<class Element>
 INLINE void PointerToArray<Element>::
 INLINE void PointerToArray<Element>::
 push_back(const Element &x) {
 push_back(const Element &x) {
   if (_ptr == NULL) {
   if (_ptr == NULL) {
-    reassign(new RefCountObj<vector<Element> >);
+    reassign(new RefCountObj<pvector<Element> >);
   }
   }
   _ptr->push_back(x);
   _ptr->push_back(x);
 }
 }
@@ -327,7 +327,7 @@ template<class Element>
 INLINE void PointerToArray<Element>::
 INLINE void PointerToArray<Element>::
 pop_back() {
 pop_back() {
   nassertd(_ptr != NULL) {
   nassertd(_ptr != NULL) {
-    ((PointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
+    ((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
   }
   }
   nassertv(!_ptr->empty());
   nassertv(!_ptr->empty());
   _ptr->pop_back();
   _ptr->pop_back();
@@ -344,7 +344,7 @@ template<class Element>
 INLINE void PointerToArray<Element>::
 INLINE void PointerToArray<Element>::
 make_empty() {
 make_empty() {
   nassertd(_ptr != NULL) {
   nassertd(_ptr != NULL) {
-    ((PointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
+    ((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
   }
   }
   nassertv(!_ptr->empty());
   nassertv(!_ptr->empty());
   _ptr->clear();
   _ptr->clear();
@@ -385,10 +385,10 @@ p() const {
 //               with some of the vector's esoteric functionality.
 //               with some of the vector's esoteric functionality.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template<class Element>
 template<class Element>
-INLINE vector<Element> &PointerToArray<Element>::
+INLINE pvector<Element> &PointerToArray<Element>::
 v() const {
 v() const {
   nassertd(_ptr != NULL) {
   nassertd(_ptr != NULL) {
-    ((PointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
+    ((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
   }
   }
   return *_ptr;
   return *_ptr;
 }
 }
@@ -403,7 +403,7 @@ template<class Element>
 INLINE void* PointerToArray<Element>::
 INLINE void* PointerToArray<Element>::
 get_void_ptr() const
 get_void_ptr() const
 {
 {
-  return PointerToBase<RefCountObj<vector<Element> > >::_ptr;
+  return PointerToBase<RefCountObj<pvector<Element> > >::_ptr;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -415,7 +415,7 @@ template<class Element>
 INLINE void PointerToArray<Element>::
 INLINE void PointerToArray<Element>::
 set_void_ptr(void* p)
 set_void_ptr(void* p)
 {
 {
-  reassign((RefCountObj<vector<Element> > *)p);
+  reassign((RefCountObj<pvector<Element> > *)p);
 }
 }
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PointerToArray::get_ref_count
 //     Function: PointerToArray::get_ref_count
@@ -435,7 +435,7 @@ get_ref_count() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template<class Element>
 template<class Element>
 INLINE PointerToArray<Element> &PointerToArray<Element>::
 INLINE PointerToArray<Element> &PointerToArray<Element>::
-operator = (RefCountObj<vector<Element> > *ptr) {
+operator = (RefCountObj<pvector<Element> > *ptr) {
   reassign(ptr);
   reassign(ptr);
   return *this;
   return *this;
 }
 }
@@ -462,7 +462,7 @@ operator = (const PointerToArray<Element> &copy) {
 template<class Element>
 template<class Element>
 INLINE void PointerToArray<Element>::
 INLINE void PointerToArray<Element>::
 clear() {
 clear() {
-  reassign((RefCountObj<vector<Element> > *)NULL);
+  reassign((RefCountObj<pvector<Element> > *)NULL);
 }
 }
 
 
 
 
@@ -475,7 +475,7 @@ clear() {
 template<class Element>
 template<class Element>
 INLINE ConstPointerToArray<Element>::
 INLINE ConstPointerToArray<Element>::
 ConstPointerToArray() :
 ConstPointerToArray() :
-  PointerToBase<RefCountObj<vector<Element> > >((RefCountObj<vector<Element> > *)NULL)
+  PointerToBase<RefCountObj<pvector<Element> > >((RefCountObj<pvector<Element> > *)NULL)
 {
 {
 }
 }
 
 
@@ -487,7 +487,7 @@ ConstPointerToArray() :
 template<class Element>
 template<class Element>
 INLINE ConstPointerToArray<Element>::
 INLINE ConstPointerToArray<Element>::
 ConstPointerToArray(const PointerToArray<Element> &copy) :
 ConstPointerToArray(const PointerToArray<Element> &copy) :
-  PointerToBase<RefCountObj<vector<Element> > >(copy)
+  PointerToBase<RefCountObj<pvector<Element> > >(copy)
 {
 {
 }
 }
 
 
@@ -499,7 +499,7 @@ ConstPointerToArray(const PointerToArray<Element> &copy) :
 template<class Element>
 template<class Element>
 INLINE ConstPointerToArray<Element>::
 INLINE ConstPointerToArray<Element>::
 ConstPointerToArray(const ConstPointerToArray<Element> &copy) :
 ConstPointerToArray(const ConstPointerToArray<Element> &copy) :
-  PointerToBase<RefCountObj<vector<Element> > >(copy)
+  PointerToBase<RefCountObj<pvector<Element> > >(copy)
 {
 {
 }
 }
 
 
@@ -579,7 +579,7 @@ template<class Element>
 INLINE ConstPointerToArray<Element>::size_type ConstPointerToArray<Element>::
 INLINE ConstPointerToArray<Element>::size_type ConstPointerToArray<Element>::
 max_size() const {
 max_size() const {
   nassertd(_ptr != NULL) {
   nassertd(_ptr != NULL) {
-    ((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
+    ((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
   }
   }
   return _ptr->max_size();
   return _ptr->max_size();
 }
 }
@@ -604,7 +604,7 @@ template<class Element>
 INLINE ConstPointerToArray<Element>::size_type ConstPointerToArray<Element>::
 INLINE ConstPointerToArray<Element>::size_type ConstPointerToArray<Element>::
 capacity() const {
 capacity() const {
   nassertd(_ptr != NULL) {
   nassertd(_ptr != NULL) {
-    ((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
+    ((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
   }
   }
   return _ptr->capacity();
   return _ptr->capacity();
 }
 }
@@ -619,7 +619,7 @@ template<class Element>
 INLINE ConstPointerToArray<Element>::reference ConstPointerToArray<Element>::
 INLINE ConstPointerToArray<Element>::reference ConstPointerToArray<Element>::
 operator[](size_type n) const {
 operator[](size_type n) const {
   nassertd(_ptr != NULL) {
   nassertd(_ptr != NULL) {
-    ((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
+    ((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
   }
   }
   nassertd(!_ptr->empty()) {
   nassertd(!_ptr->empty()) {
     _ptr->push_back(Element());
     _ptr->push_back(Element());
@@ -638,7 +638,7 @@ template<class Element>
 INLINE ConstPointerToArray<Element>::reference ConstPointerToArray<Element>::
 INLINE ConstPointerToArray<Element>::reference ConstPointerToArray<Element>::
 front() const {
 front() const {
   nassertd(_ptr != NULL) {
   nassertd(_ptr != NULL) {
-    ((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
+    ((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
   }
   }
   nassertd(!_ptr->empty()) {
   nassertd(!_ptr->empty()) {
     _ptr->push_back(Element());
     _ptr->push_back(Element());
@@ -655,7 +655,7 @@ template<class Element>
 INLINE ConstPointerToArray<Element>::reference ConstPointerToArray<Element>::
 INLINE ConstPointerToArray<Element>::reference ConstPointerToArray<Element>::
 back() const {
 back() const {
   nassertd(_ptr != NULL) {
   nassertd(_ptr != NULL) {
-    ((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
+    ((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
   }
   }
   nassertd(!_ptr->empty()) {
   nassertd(!_ptr->empty()) {
     _ptr->push_back(Element());
     _ptr->push_back(Element());
@@ -698,10 +698,10 @@ p() const {
 //               with some of the vector's esoteric functionality.
 //               with some of the vector's esoteric functionality.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template<class Element>
 template<class Element>
-INLINE const vector<Element> &ConstPointerToArray<Element>::
+INLINE const pvector<Element> &ConstPointerToArray<Element>::
 v() const {
 v() const {
   nassertd(_ptr != NULL) {
   nassertd(_ptr != NULL) {
-    ((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
+    ((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
   }
   }
   return *_ptr;
   return *_ptr;
 }
 }
@@ -724,7 +724,7 @@ get_ref_count() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template<class Element>
 template<class Element>
 INLINE ConstPointerToArray<Element> &ConstPointerToArray<Element>::
 INLINE ConstPointerToArray<Element> &ConstPointerToArray<Element>::
-operator = (RefCountObj<vector<Element> > *ptr) {
+operator = (RefCountObj<pvector<Element> > *ptr) {
   reassign(ptr);
   reassign(ptr);
   return *this;
   return *this;
 }
 }
@@ -763,6 +763,6 @@ operator = (const ConstPointerToArray<Element> &copy) {
 template<class Element>
 template<class Element>
 INLINE void ConstPointerToArray<Element>::
 INLINE void ConstPointerToArray<Element>::
 clear() {
 clear() {
-  reassign((RefCountObj<vector<Element> > *)NULL);
+  reassign((RefCountObj<pvector<Element> > *)NULL);
 }
 }
 
 

+ 28 - 29
panda/src/putil/pointerToArray.h

@@ -72,8 +72,7 @@
 
 
 #include "referenceCount.h"
 #include "referenceCount.h"
 #include "pointerTo.h"
 #include "pointerTo.h"
-
-#include <vector>
+#include "pvector.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : PointerToArray
 //       Class : PointerToArray
@@ -84,17 +83,17 @@
 //               with a reference count.
 //               with a reference count.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template <class Element>
 template <class Element>
-class PointerToArray : public PointerToBase<RefCountObj<vector<Element> > > {
+class PointerToArray : public PointerToBase<RefCountObj<pvector<Element> > > {
 public:
 public:
-  typedef vector<Element>::value_type value_type;
-  typedef vector<Element>::reference reference;
-  typedef vector<Element>::const_reference const_reference;
-  typedef vector<Element>::iterator iterator;
-  typedef vector<Element>::const_iterator const_iterator;
-  typedef vector<Element>::reverse_iterator reverse_iterator;
-  typedef vector<Element>::const_reverse_iterator const_reverse_iterator;
-  typedef vector<Element>::difference_type difference_type;
-  typedef vector<Element>::size_type size_type;
+  typedef pvector<Element>::value_type value_type;
+  typedef pvector<Element>::reference reference;
+  typedef pvector<Element>::const_reference const_reference;
+  typedef pvector<Element>::iterator iterator;
+  typedef pvector<Element>::const_iterator const_iterator;
+  typedef pvector<Element>::reverse_iterator reverse_iterator;
+  typedef pvector<Element>::const_reverse_iterator const_reverse_iterator;
+  typedef pvector<Element>::difference_type difference_type;
+  typedef pvector<Element>::size_type size_type;
 
 
 PUBLISHED:
 PUBLISHED:
   INLINE PointerToArray();
   INLINE PointerToArray();
@@ -153,7 +152,7 @@ public:
 
 
   INLINE operator Element *() const;
   INLINE operator Element *() const;
   INLINE Element *p() const;
   INLINE Element *p() const;
-  INLINE vector<Element> &v() const;
+  INLINE pvector<Element> &v() const;
 
 
   //These functions are only to be used in Reading through BamReader.
   //These functions are only to be used in Reading through BamReader.
   //They are designed to work in pairs, so that you register what is
   //They are designed to work in pairs, so that you register what is
@@ -168,7 +167,7 @@ public:
 
 
   // Reassignment is by pointer, not memberwise as with a vector.
   // Reassignment is by pointer, not memberwise as with a vector.
   INLINE PointerToArray<Element> &
   INLINE PointerToArray<Element> &
-  operator = (RefCountObj<vector<Element> > *ptr);
+  operator = (RefCountObj<pvector<Element> > *ptr);
   INLINE PointerToArray<Element> &
   INLINE PointerToArray<Element> &
   operator = (const PointerToArray<Element> &copy);
   operator = (const PointerToArray<Element> &copy);
   INLINE void clear();
   INLINE void clear();
@@ -179,7 +178,7 @@ private:
   // NULL pointer.  It might not be shared properly between different
   // NULL pointer.  It might not be shared properly between different
   // .so's, since it's a static member of a template class, but we
   // .so's, since it's a static member of a template class, but we
   // don't really care.
   // don't really care.
-  static vector<Element> _empty_array;
+  static pvector<Element> _empty_array;
 };
 };
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -188,22 +187,22 @@ private:
 //               may not be modified.
 //               may not be modified.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template <class Element>
 template <class Element>
-class ConstPointerToArray : public PointerToBase<RefCountObj<vector<Element> > > {
+class ConstPointerToArray : public PointerToBase<RefCountObj<pvector<Element> > > {
 public:
 public:
-  typedef vector<Element>::value_type value_type;
-  typedef vector<Element>::const_reference reference;
-  typedef vector<Element>::const_reference const_reference;
-  typedef vector<Element>::const_iterator iterator;
-  typedef vector<Element>::const_iterator const_iterator;
+  typedef pvector<Element>::value_type value_type;
+  typedef pvector<Element>::const_reference reference;
+  typedef pvector<Element>::const_reference const_reference;
+  typedef pvector<Element>::const_iterator iterator;
+  typedef pvector<Element>::const_iterator const_iterator;
 #ifdef WIN32_VC
 #ifdef WIN32_VC
   // VC++ seems to break the const_reverse_iterator definition somehow.
   // VC++ seems to break the const_reverse_iterator definition somehow.
-  typedef vector<Element>::reverse_iterator reverse_iterator;
+  typedef pvector<Element>::reverse_iterator reverse_iterator;
 #else
 #else
-  typedef vector<Element>::const_reverse_iterator reverse_iterator;
+  typedef pvector<Element>::const_reverse_iterator reverse_iterator;
 #endif
 #endif
-  typedef vector<Element>::const_reverse_iterator const_reverse_iterator;
-  typedef vector<Element>::difference_type difference_type;
-  typedef vector<Element>::size_type size_type;
+  typedef pvector<Element>::const_reverse_iterator const_reverse_iterator;
+  typedef pvector<Element>::difference_type difference_type;
+  typedef pvector<Element>::size_type size_type;
 
 
   INLINE ConstPointerToArray();
   INLINE ConstPointerToArray();
   INLINE ConstPointerToArray(const PointerToArray<Element> &copy);
   INLINE ConstPointerToArray(const PointerToArray<Element> &copy);
@@ -233,13 +232,13 @@ public:
 
 
   INLINE operator const Element *() const;
   INLINE operator const Element *() const;
   INLINE const Element *p() const;
   INLINE const Element *p() const;
-  INLINE const vector<Element> &v() const;
+  INLINE const pvector<Element> &v() const;
 
 
   INLINE int get_ref_count() const;
   INLINE int get_ref_count() const;
 
 
   // Reassignment is by pointer, not memberwise as with a vector.
   // Reassignment is by pointer, not memberwise as with a vector.
   INLINE ConstPointerToArray<Element> &
   INLINE ConstPointerToArray<Element> &
-  operator = (RefCountObj<vector<Element> > *ptr);
+  operator = (RefCountObj<pvector<Element> > *ptr);
   INLINE ConstPointerToArray<Element> &
   INLINE ConstPointerToArray<Element> &
   operator = (const PointerToArray<Element> &copy);
   operator = (const PointerToArray<Element> &copy);
   INLINE ConstPointerToArray<Element> &
   INLINE ConstPointerToArray<Element> &
@@ -252,7 +251,7 @@ private:
   // NULL pointer.  It might not be shared properly between different
   // NULL pointer.  It might not be shared properly between different
   // .so's, since it's a static member of a template class, but we
   // .so's, since it's a static member of a template class, but we
   // don't really care.
   // don't really care.
-  static vector<Element> _empty_array;
+  static pvector<Element> _empty_array;
 };
 };
 
 
 
 

+ 24 - 6
panda/src/sgmanip/nodePath.I

@@ -1446,12 +1446,14 @@ hide_collision_solids() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePath::is_hidden
 //     Function: NodePath::is_hidden
 //       Access: Public
 //       Access: Public
-//  Description: Returns true if some arc above this bottom node has
-//               been set to 'hide', false if it should be visible.
+//  Description: Returns true if the bottom arc has been hidden,
+//               false otherwise.  The bottom node may still be
+//               invisible due to a higher ancestor having been
+//               hidden; use get_hidden_ancestor() to check this.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool NodePath::
 INLINE bool NodePath::
 is_hidden() const {
 is_hidden() const {
-  return !get_hidden_ancestor().is_empty();
+  return (arc()->has_transition(PruneTransition::get_class_type()));
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -1489,10 +1491,26 @@ unstash() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePath::is_stashed
 //     Function: NodePath::is_stashed
 //       Access: Public
 //       Access: Public
-//  Description: Returns true if some arc above this bottom node has
-//               been set to 'stash', false if it should be visible.
+//  Description: Returns true if the bottom arc has been 'stashed',
+//               false otherwise.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool NodePath::
 INLINE bool NodePath::
 is_stashed() const {
 is_stashed() const {
-  return !get_stashed_ancestor().is_empty();
+  return (arc()->get_graph_type() == NodeRelation::get_stashed_type());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::clear_wrt_cache
+//       Access: Public
+//  Description: Recursively calls clear_wrt_cache() on every arc
+//               beginning at the bottom arc and below.  This wipes
+//               out the cached wrt information, which will make the
+//               next call to wrt() more expensive, but may reclaim
+//               some memory and free up some otherwise unused
+//               pointers.
+////////////////////////////////////////////////////////////////////
+INLINE void NodePath::
+clear_wrt_cache() {
+  nassertv_always(!is_empty());
+  r_clear_wrt_cache(arc());
 }
 }

+ 20 - 0
panda/src/sgmanip/nodePath.cxx

@@ -3147,3 +3147,23 @@ r_adjust_all_priorities(NodeRelation *arc, int adjustment) {
     r_adjust_all_priorities(child_arc, adjustment);
     r_adjust_all_priorities(child_arc, adjustment);
   }
   }
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::r_clear_wrt_cache
+//       Access: Private
+//  Description: The recursive implementation of
+//               clear_wrt_cache().  This walks through the
+//               subgraph defined by the indicated arc and below.
+////////////////////////////////////////////////////////////////////
+void NodePath::
+r_clear_wrt_cache(NodeRelation *arc) {
+  arc->clear_wrt_cache();
+
+  Node *dnode = arc->get_child();
+
+  int num_children = dnode->get_num_children(_graph_type);
+  for (int i = 0; i < num_children; i++) {
+    NodeRelation *child_arc = dnode->get_child(_graph_type, i);
+    r_clear_wrt_cache(child_arc);
+  }
+}

+ 2 - 0
panda/src/sgmanip/nodePath.h

@@ -510,6 +510,7 @@ PUBLISHED:
   NodePath get_stashed_ancestor() const;
   NodePath get_stashed_ancestor() const;
 
 
   void prepare_scene(GraphicsStateGuardianBase *gsg);
   void prepare_scene(GraphicsStateGuardianBase *gsg);
+  INLINE void clear_wrt_cache();
 
 
   void show_bounds();
   void show_bounds();
   void hide_bounds();
   void hide_bounds();
@@ -542,6 +543,7 @@ private:
   void r_list_transitions(ostream &out, int indent_level) const;
   void r_list_transitions(ostream &out, int indent_level) const;
 
 
   void r_adjust_all_priorities(NodeRelation *arc, int adjustment);
   void r_adjust_all_priorities(NodeRelation *arc, int adjustment);
+  void r_clear_wrt_cache(NodeRelation *arc);
 
 
   // It's important that there are no data members in this class.  Put
   // It's important that there are no data members in this class.  Put
   // them in NodePathBase instead.
   // them in NodePathBase instead.