ソースを参照

NodeCachedReferenceCount

David Rose 20 年 前
コミット
977f692331

+ 0 - 203
panda/src/express/pointerToBase.I

@@ -105,209 +105,6 @@ reassign(const PointerToBase<To> &copy) {
   reassign((To *)copy._void_ptr);
   reassign((To *)copy._void_ptr);
 }
 }
 
 
-#ifndef CPPPARSER
-#ifndef WIN32_VC
-////////////////////////////////////////////////////////////////////
-//     Function: PointerToBase::Equivalence operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-template<class T>
-INLINE bool PointerToBase<T>::
-operator == (const To *other) const {
-  return (To *)_void_ptr == other;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PointerToBase::Nonequivalence operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-template<class T>
-INLINE bool PointerToBase<T>::
-operator != (const To *other) const {
-  return (To *)_void_ptr != other;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PointerToBase::Greater-than operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-template<class T>
-INLINE bool PointerToBase<T>::
-operator > (const To *other) const {
-  return (To *)_void_ptr > other;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PointerToBase::Less-than-or-equal operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-template<class T>
-INLINE bool PointerToBase<T>::
-operator <= (const To *other) const {
-  return (To *)_void_ptr <= other;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PointerToBase::Greater-than-or-equal operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-template<class T>
-INLINE bool PointerToBase<T>::
-operator >= (const To *other) const {
-  return (To *)_void_ptr >= other;
-}
-////////////////////////////////////////////////////////////////////
-//     Function: PointerToBase::Equivalence operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-template<class T>
-INLINE bool PointerToBase<T>::
-operator == (To *other) const {
-  return (To *)_void_ptr == other;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PointerToBase::Nonequivalence operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-template<class T>
-INLINE bool PointerToBase<T>::
-operator != (To *other) const {
-  return (To *)_void_ptr != other;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PointerToBase::Greater-than operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-template<class T>
-INLINE bool PointerToBase<T>::
-operator > (To *other) const {
-  return (To *)_void_ptr > other;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PointerToBase::Less-than-or-equal operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-template<class T>
-INLINE bool PointerToBase<T>::
-operator <= (To *other) const {
-  return (To *)_void_ptr <= other;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PointerToBase::Greater-than-or-equal operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-template<class T>
-INLINE bool PointerToBase<T>::
-operator >= (To *other) const {
-  return (To *)_void_ptr >= other;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PointerToBase::Equivalence operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-template<class T>
-INLINE bool PointerToBase<T>::
-operator == (const PointerToBase<To> &other) const {
-  return (To *)_void_ptr == (To *)other._void_ptr;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PointerToBase::Nonequivalence operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-template<class T>
-INLINE bool PointerToBase<T>::
-operator != (const PointerToBase<To> &other) const {
-  return (To *)_void_ptr != (To *)other._void_ptr;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PointerToBase::Greater-than operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-template<class T>
-INLINE bool PointerToBase<T>::
-operator > (const PointerToBase<To> &other) const {
-  return (To *)_void_ptr > (To *)other._void_ptr;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PointerToBase::Less-than-or-equal operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-template<class T>
-INLINE bool PointerToBase<T>::
-operator <= (const PointerToBase<To> &other) const {
-  return (To *)_void_ptr <= (To *)other._void_ptr;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PointerToBase::Greater-than-or-equal operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-template<class T>
-INLINE bool PointerToBase<T>::
-operator >= (const PointerToBase<To> &other) const {
-  return (To *)_void_ptr >= (To *)other._void_ptr;
-}
-#endif  // WIN32_VC
-
-////////////////////////////////////////////////////////////////////
-//     Function: PointerToBase::Less-than operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-template<class T>
-INLINE bool PointerToBase<T>::
-operator < (const To *other) const {
-  return (To *)_void_ptr < other;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PointerToBase::Less-than operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-template<class T>
-INLINE bool PointerToBase<T>::
-operator < (const PointerToBase<To> &other) const {
-  return (To *)_void_ptr < (To *)other._void_ptr;
-}
-
-#endif  // CPPPARSER
-
-////////////////////////////////////////////////////////////////////
-//     Function: PointerToBase::get_hash
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-template<class T>
-INLINE size_t PointerToBase<T>::
-get_hash() const {
-  return (size_t)_void_ptr;
-}
-
-
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PointerToBase::clear
 //     Function: PointerToBase::clear

+ 0 - 27
panda/src/express/pointerToBase.h

@@ -49,33 +49,6 @@ protected:
   // PointerToBase, because we will have to specialize on const
   // PointerToBase, because we will have to specialize on const
   // vs. non-const later.
   // vs. non-const later.
 
 
-public:
-  // These comparison functions are common to all things PointerTo, so
-  // they're defined up here.
-#ifndef CPPPARSER
-#ifndef WIN32_VC
-  INLINE bool operator == (const To *other) const;
-  INLINE bool operator != (const To *other) const;
-  INLINE bool operator > (const To *other) const;
-  INLINE bool operator <= (const To *other) const;
-  INLINE bool operator >= (const To *other) const;
-  INLINE bool operator == (To *other) const;
-  INLINE bool operator != (To *other) const;
-  INLINE bool operator > (To *other) const;
-  INLINE bool operator <= (To *other) const;
-  INLINE bool operator >= (To *other) const;
-
-  INLINE bool operator == (const PointerToBase<To> &other) const;
-  INLINE bool operator != (const PointerToBase<To> &other) const;
-  INLINE bool operator > (const PointerToBase<To> &other) const;
-  INLINE bool operator <= (const PointerToBase<To> &other) const;
-  INLINE bool operator >= (const PointerToBase<To> &other) const;
-#endif  // WIN32_VC
-  INLINE bool operator < (const To *other) const;
-  INLINE bool operator < (const PointerToBase<To> &other) const;
-#endif  // CPPPARSER
-  INLINE size_t get_hash() const;
-
 PUBLISHED:
 PUBLISHED:
   INLINE void clear();
   INLINE void clear();
 
 

+ 182 - 0
panda/src/express/pointerToVoid.I

@@ -48,3 +48,185 @@ INLINE bool PointerToVoid::
 is_null() const {
 is_null() const {
   return (_void_ptr == (void *)NULL);
   return (_void_ptr == (void *)NULL);
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToVoid::get_hash
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE size_t PointerToVoid::
+get_hash() const {
+  return (size_t)_void_ptr;
+}
+
+#ifndef WIN32_VC
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToVoid::Equivalence operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool PointerToVoid::
+operator == (const void *other) const {
+  return _void_ptr == other;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToVoid::Nonequivalence operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool PointerToVoid::
+operator != (const void *other) const {
+  return _void_ptr != other;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToVoid::Greater-than operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool PointerToVoid::
+operator > (const void *other) const {
+  return _void_ptr > other;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToVoid::Less-than-or-equal operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool PointerToVoid::
+operator <= (const void *other) const {
+  return _void_ptr <= other;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToVoid::Greater-than-or-equal operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool PointerToVoid::
+operator >= (const void *other) const {
+  return _void_ptr >= other;
+}
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToVoid::Equivalence operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool PointerToVoid::
+operator == (void *other) const {
+  return _void_ptr == other;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToVoid::Nonequivalence operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool PointerToVoid::
+operator != (void *other) const {
+  return _void_ptr != other;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToVoid::Greater-than operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool PointerToVoid::
+operator > (void *other) const {
+  return _void_ptr > other;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToVoid::Less-than-or-equal operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool PointerToVoid::
+operator <= (void *other) const {
+  return _void_ptr <= other;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToVoid::Greater-than-or-equal operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool PointerToVoid::
+operator >= (void *other) const {
+  return _void_ptr >= other;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToVoid::Equivalence operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool PointerToVoid::
+operator == (const PointerToVoid &other) const {
+  return _void_ptr == other._void_ptr;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToVoid::Nonequivalence operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool PointerToVoid::
+operator != (const PointerToVoid &other) const {
+  return _void_ptr != other._void_ptr;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToVoid::Greater-than operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool PointerToVoid::
+operator > (const PointerToVoid &other) const {
+  return _void_ptr > other._void_ptr;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToVoid::Less-than-or-equal operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool PointerToVoid::
+operator <= (const PointerToVoid &other) const {
+  return _void_ptr <= other._void_ptr;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToVoid::Greater-than-or-equal operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool PointerToVoid::
+operator >= (const PointerToVoid &other) const {
+  return _void_ptr >= other._void_ptr;
+}
+#endif  // WIN32_VC
+
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToVoid::Less-than operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool PointerToVoid::
+operator < (const void *other) const {
+  return _void_ptr < other;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToVoid::Less-than operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool PointerToVoid::
+operator < (const PointerToVoid &other) const {
+  return _void_ptr < other._void_ptr;
+}
+

+ 25 - 0
panda/src/express/pointerToVoid.h

@@ -40,6 +40,31 @@ protected:
 
 
 PUBLISHED:
 PUBLISHED:
   INLINE bool is_null() const;
   INLINE bool is_null() const;
+  INLINE size_t get_hash() const;
+
+public:
+  // These comparison functions are common to all things PointerTo, so
+  // they're defined up here.
+#ifndef WIN32_VC
+  INLINE bool operator == (const void *other) const;
+  INLINE bool operator != (const void *other) const;
+  INLINE bool operator > (const void *other) const;
+  INLINE bool operator <= (const void *other) const;
+  INLINE bool operator >= (const void *other) const;
+  INLINE bool operator == (void *other) const;
+  INLINE bool operator != (void *other) const;
+  INLINE bool operator > (void *other) const;
+  INLINE bool operator <= (void *other) const;
+  INLINE bool operator >= (void *other) const;
+
+  INLINE bool operator == (const PointerToVoid &other) const;
+  INLINE bool operator != (const PointerToVoid &other) const;
+  INLINE bool operator > (const PointerToVoid &other) const;
+  INLINE bool operator <= (const PointerToVoid &other) const;
+  INLINE bool operator >= (const PointerToVoid &other) const;
+#endif  // WIN32_VC
+  INLINE bool operator < (const void *other) const;
+  INLINE bool operator < (const PointerToVoid &other) const;
 
 
 protected:
 protected:
   // Within the PointerToVoid class, we only store a void pointer.
   // Within the PointerToVoid class, we only store a void pointer.

+ 4 - 3
panda/src/pgraph/pandaNode.h

@@ -37,6 +37,7 @@
 #include "luse.h"
 #include "luse.h"
 #include "ordered_vector.h"
 #include "ordered_vector.h"
 #include "pointerTo.h"
 #include "pointerTo.h"
+#include "nodePointerTo.h"
 #include "pointerToArray.h"
 #include "pointerToArray.h"
 #include "notify.h"
 #include "notify.h"
 
 
@@ -315,10 +316,10 @@ private:
     Up _up;
     Up _up;
     Paths _paths;
     Paths _paths;
 
 
-    CPT(RenderState) _state;
+    NCPT(RenderState) _state;
     CPT(RenderEffects) _effects;
     CPT(RenderEffects) _effects;
-    CPT(TransformState) _transform;
-    CPT(TransformState) _prev_transform;
+    NCPT(TransformState) _transform;
+    NCPT(TransformState) _prev_transform;
 
 
     TagData _tag_data;
     TagData _tag_data;
 
 

+ 82 - 0
panda/src/pgraph/renderState.I

@@ -61,6 +61,74 @@ get_override(int n) const {
   return _attributes[n]._override;
   return _attributes[n]._override;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::cache_ref
+//       Access: Published
+//  Description: Overrides this method to update PStats appropriately.
+////////////////////////////////////////////////////////////////////
+INLINE int RenderState::
+cache_ref() const {
+#ifdef DO_PSTATS
+  int old_referenced_bits = get_referenced_bits();
+  int result = NodeCachedReferenceCount::cache_ref();
+  consider_update_pstats(old_referenced_bits);
+  return result;
+#else  // DO_PSTATS
+  return NodeCachedReferenceCount::cache_ref();
+#endif  // DO_PSTATS
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::cache_unref
+//       Access: Published
+//  Description: Overrides this method to update PStats appropriately.
+////////////////////////////////////////////////////////////////////
+INLINE int RenderState::
+cache_unref() const {
+#ifdef DO_PSTATS
+  int old_referenced_bits = get_referenced_bits();
+  int result = NodeCachedReferenceCount::cache_unref();
+  consider_update_pstats(old_referenced_bits);
+  return result;
+#else  // DO_PSTATS
+  return NodeCachedReferenceCount::cache_unref();
+#endif  // DO_PSTATS
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::node_ref
+//       Access: Published
+//  Description: Overrides this method to update PStats appropriately.
+////////////////////////////////////////////////////////////////////
+INLINE int RenderState::
+node_ref() const {
+#ifdef DO_PSTATS
+  int old_referenced_bits = get_referenced_bits();
+  int result = NodeCachedReferenceCount::node_ref();
+  consider_update_pstats(old_referenced_bits);
+  return result;
+#else  // DO_PSTATS
+  return NodeCachedReferenceCount::node_ref();
+#endif  // DO_PSTATS
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::node_unref
+//       Access: Published
+//  Description: Overrides this method to update PStats appropriately.
+////////////////////////////////////////////////////////////////////
+INLINE int RenderState::
+node_unref() const {
+#ifdef DO_PSTATS
+  int old_referenced_bits = get_referenced_bits();
+  int result = NodeCachedReferenceCount::node_unref();
+  consider_update_pstats(old_referenced_bits);
+  return result;
+#else  // DO_PSTATS
+  return NodeCachedReferenceCount::node_unref();
+#endif  // DO_PSTATS
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::get_draw_order
 //     Function: RenderState::get_draw_order
 //       Access: Published
 //       Access: Published
@@ -325,6 +393,20 @@ is_destructing() const {
 #endif
 #endif
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::consider_update_pstats
+//       Access: Private
+//  Description: Calls update_pstats() if the state of the referenced
+//               bits has changed from the indicated value.
+////////////////////////////////////////////////////////////////////
+INLINE void RenderState::
+consider_update_pstats(int old_referenced_bits) const {
+  int new_referenced_bits = get_referenced_bits();
+  if (old_referenced_bits != new_referenced_bits) {
+    update_pstats(old_referenced_bits, new_referenced_bits);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::Composition::Constructor
 //     Function: RenderState::Composition::Constructor
 //       Access: Public
 //       Access: Public

+ 25 - 0
panda/src/pgraph/renderState.cxx

@@ -40,6 +40,8 @@ UpdateSeq RenderState::_last_cycle_detect;
 PStatCollector RenderState::_cache_update_pcollector("*:State Cache:Update");
 PStatCollector RenderState::_cache_update_pcollector("*:State Cache:Update");
 PStatCollector RenderState::_state_compose_pcollector("*:State Cache:Compose State");
 PStatCollector RenderState::_state_compose_pcollector("*:State Cache:Compose State");
 PStatCollector RenderState::_state_invert_pcollector("*:State Cache:Invert State");
 PStatCollector RenderState::_state_invert_pcollector("*:State Cache:Invert State");
+PStatCollector RenderState::_node_counter("RenderStates:On nodes");
+PStatCollector RenderState::_cache_counter("RenderStates:Cached");
 
 
 TypeHandle RenderState::_type_handle;
 TypeHandle RenderState::_type_handle;
 
 
@@ -1611,6 +1613,29 @@ determine_render_mode() {
   _flags |= F_checked_render_mode;
   _flags |= F_checked_render_mode;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::update_pstats
+//       Access: Private
+//  Description: Moves the RenderState object from one PStats category
+//               to another, so that we can track in PStats how many
+//               pointers are held by nodes, and how many are held in
+//               the cache only.
+////////////////////////////////////////////////////////////////////
+void RenderState::
+update_pstats(int old_referenced_bits, int new_referenced_bits) {
+  if ((old_referenced_bits & R_node) != 0) {
+    _node_counter.sub_level(1);
+  } else if ((old_referenced_bits & R_cache) != 0) {
+    _cache_counter.sub_level(1);
+  }
+  if ((new_referenced_bits & R_node) != 0) {
+    _node_counter.add_level(1);
+  } else if ((new_referenced_bits & R_cache) != 0) {
+    _cache_counter.add_level(1);
+  }
+}
+
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::register_with_read_factory
 //     Function: RenderState::register_with_read_factory
 //       Access: Public, Static
 //       Access: Public, Static

+ 15 - 4
panda/src/pgraph/renderState.h

@@ -22,7 +22,7 @@
 #include "pandabase.h"
 #include "pandabase.h"
 
 
 #include "renderAttrib.h"
 #include "renderAttrib.h"
-#include "cachedTypedWritableReferenceCount.h"
+#include "nodeCachedReferenceCount.h"
 #include "pointerTo.h"
 #include "pointerTo.h"
 #include "ordered_vector.h"
 #include "ordered_vector.h"
 #include "updateSeq.h"
 #include "updateSeq.h"
@@ -52,7 +52,7 @@ class FactoryParams;
 //               instead of modifying a RenderState object, create a
 //               instead of modifying a RenderState object, create a
 //               new one.
 //               new one.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA RenderState : public CachedTypedWritableReferenceCount {
+class EXPCL_PANDA RenderState : public NodeCachedReferenceCount {
 protected:
 protected:
   RenderState();
   RenderState();
 
 
@@ -100,6 +100,11 @@ PUBLISHED:
 
 
   int unref() const;
   int unref() const;
 
 
+  INLINE int cache_ref() const;
+  INLINE int cache_unref() const;
+  INLINE int node_ref() const;
+  INLINE int node_unref() const;
+
   void output(ostream &out) const;
   void output(ostream &out) const;
   void write(ostream &out, int indent_level) const;
   void write(ostream &out, int indent_level) const;
 
 
@@ -174,6 +179,9 @@ private:
   INLINE void set_destructing();
   INLINE void set_destructing();
   INLINE bool is_destructing() const;
   INLINE bool is_destructing() const;
 
 
+  INLINE void consider_update_pstats(int old_referenced_bits) const;
+  static void update_pstats(int old_referenced_bits, int new_referenced_bits);
+
 private:
 private:
   typedef pset<const RenderState *, indirect_less<const RenderState *> > States;
   typedef pset<const RenderState *, indirect_less<const RenderState *> > States;
   static States *_states;
   static States *_states;
@@ -215,6 +223,9 @@ private:
   static PStatCollector _state_compose_pcollector;
   static PStatCollector _state_compose_pcollector;
   static PStatCollector _state_invert_pcollector;
   static PStatCollector _state_invert_pcollector;
 
 
+  static PStatCollector _node_counter;
+  static PStatCollector _cache_counter;
+
 private:
 private:
   // This is the actual data within the RenderState: a set of
   // This is the actual data within the RenderState: a set of
   // RenderAttribs.
   // RenderAttribs.
@@ -283,9 +294,9 @@ public:
     return _type_handle;
     return _type_handle;
   }
   }
   static void init_type() {
   static void init_type() {
-    CachedTypedWritableReferenceCount::init_type();
+    NodeCachedReferenceCount::init_type();
     register_type(_type_handle, "RenderState",
     register_type(_type_handle, "RenderState",
-                  CachedTypedWritableReferenceCount::get_class_type());
+                  NodeCachedReferenceCount::get_class_type());
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 1 - 0
panda/src/pgraph/stateMunger.h

@@ -21,6 +21,7 @@
 
 
 #include "pandabase.h"
 #include "pandabase.h"
 #include "qpgeomMunger.h"
 #include "qpgeomMunger.h"
+#include "renderState.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : StateMunger
 //       Class : StateMunger

+ 82 - 0
panda/src/pgraph/transformState.I

@@ -437,6 +437,74 @@ get_mat() const {
   return _mat;
   return _mat;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::cache_ref
+//       Access: Published
+//  Description: Overrides this method to update PStats appropriately.
+////////////////////////////////////////////////////////////////////
+INLINE int TransformState::
+cache_ref() const {
+#ifdef DO_PSTATS
+  int old_referenced_bits = get_referenced_bits();
+  int result = NodeCachedReferenceCount::cache_ref();
+  consider_update_pstats(old_referenced_bits);
+  return result;
+#else  // DO_PSTATS
+  return NodeCachedReferenceCount::cache_ref();
+#endif  // DO_PSTATS
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::cache_unref
+//       Access: Published
+//  Description: Overrides this method to update PStats appropriately.
+////////////////////////////////////////////////////////////////////
+INLINE int TransformState::
+cache_unref() const {
+#ifdef DO_PSTATS
+  int old_referenced_bits = get_referenced_bits();
+  int result = NodeCachedReferenceCount::cache_unref();
+  consider_update_pstats(old_referenced_bits);
+  return result;
+#else  // DO_PSTATS
+  return NodeCachedReferenceCount::cache_unref();
+#endif  // DO_PSTATS
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::node_ref
+//       Access: Published
+//  Description: Overrides this method to update PStats appropriately.
+////////////////////////////////////////////////////////////////////
+INLINE int TransformState::
+node_ref() const {
+#ifdef DO_PSTATS
+  int old_referenced_bits = get_referenced_bits();
+  int result = NodeCachedReferenceCount::node_ref();
+  consider_update_pstats(old_referenced_bits);
+  return result;
+#else  // DO_PSTATS
+  return NodeCachedReferenceCount::node_ref();
+#endif  // DO_PSTATS
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::node_unref
+//       Access: Published
+//  Description: Overrides this method to update PStats appropriately.
+////////////////////////////////////////////////////////////////////
+INLINE int TransformState::
+node_unref() const {
+#ifdef DO_PSTATS
+  int old_referenced_bits = get_referenced_bits();
+  int result = NodeCachedReferenceCount::node_unref();
+  consider_update_pstats(old_referenced_bits);
+  return result;
+#else  // DO_PSTATS
+  return NodeCachedReferenceCount::node_unref();
+#endif  // DO_PSTATS
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::check_singular
 //     Function: TransformState::check_singular
 //       Access: Private
 //       Access: Private
@@ -563,6 +631,20 @@ is_destructing() const {
 #endif
 #endif
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::consider_update_pstats
+//       Access: Private
+//  Description: Calls update_pstats() if the state of the referenced
+//               bits has changed from the indicated value.
+////////////////////////////////////////////////////////////////////
+INLINE void TransformState::
+consider_update_pstats(int old_referenced_bits) const {
+  int new_referenced_bits = get_referenced_bits();
+  if (old_referenced_bits != new_referenced_bits) {
+    update_pstats(old_referenced_bits, new_referenced_bits);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::Composition::Constructor
 //     Function: TransformState::Composition::Constructor
 //       Access: Public
 //       Access: Public

+ 24 - 0
panda/src/pgraph/transformState.cxx

@@ -32,6 +32,8 @@ UpdateSeq TransformState::_last_cycle_detect;
 PStatCollector TransformState::_cache_update_pcollector("*:State Cache:Update");
 PStatCollector TransformState::_cache_update_pcollector("*:State Cache:Update");
 PStatCollector TransformState::_transform_compose_pcollector("*:State Cache:Compose Transform");
 PStatCollector TransformState::_transform_compose_pcollector("*:State Cache:Compose Transform");
 PStatCollector TransformState::_transform_invert_pcollector("*:State Cache:Invert Transform");
 PStatCollector TransformState::_transform_invert_pcollector("*:State Cache:Invert Transform");
+PStatCollector TransformState::_node_counter("TransformStates:On nodes");
+PStatCollector TransformState::_cache_counter("TransformStates:Cached");
 
 
 TypeHandle TransformState::_type_handle;
 TypeHandle TransformState::_type_handle;
 
 
@@ -1500,6 +1502,28 @@ calc_mat() {
   _flags |= F_mat_known;
   _flags |= F_mat_known;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::update_pstats
+//       Access: Private
+//  Description: Moves the TransformState object from one PStats category
+//               to another, so that we can track in PStats how many
+//               pointers are held by nodes, and how many are held in
+//               the cache only.
+////////////////////////////////////////////////////////////////////
+void TransformState::
+update_pstats(int old_referenced_bits, int new_referenced_bits) {
+  if ((old_referenced_bits & R_node) != 0) {
+    _node_counter.sub_level(1);
+  } else if ((old_referenced_bits & R_cache) != 0) {
+    _cache_counter.sub_level(1);
+  }
+  if ((new_referenced_bits & R_node) != 0) {
+    _node_counter.add_level(1);
+  } else if ((new_referenced_bits & R_cache) != 0) {
+    _cache_counter.add_level(1);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::register_with_read_factory
 //     Function: TransformState::register_with_read_factory
 //       Access: Public, Static
 //       Access: Public, Static

+ 15 - 4
panda/src/pgraph/transformState.h

@@ -21,7 +21,7 @@
 
 
 #include "pandabase.h"
 #include "pandabase.h"
 
 
-#include "cachedTypedWritableReferenceCount.h"
+#include "nodeCachedReferenceCount.h"
 #include "pointerTo.h"
 #include "pointerTo.h"
 #include "luse.h"
 #include "luse.h"
 #include "pset.h"
 #include "pset.h"
@@ -54,7 +54,7 @@ class FactoryParams;
 //               instead of modifying a TransformState object, create a
 //               instead of modifying a TransformState object, create a
 //               new one.
 //               new one.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA TransformState : public CachedTypedWritableReferenceCount {
+class EXPCL_PANDA TransformState : public NodeCachedReferenceCount {
 protected:
 protected:
   TransformState();
   TransformState();
 
 
@@ -129,6 +129,11 @@ PUBLISHED:
 
 
   int unref() const;
   int unref() const;
 
 
+  INLINE int cache_ref() const;
+  INLINE int cache_unref() const;
+  INLINE int node_ref() const;
+  INLINE int node_unref() const;
+
   void output(ostream &out) const;
   void output(ostream &out) const;
   void write(ostream &out, int indent_level) const;
   void write(ostream &out, int indent_level) const;
 
 
@@ -203,6 +208,9 @@ private:
   static PStatCollector _transform_compose_pcollector;
   static PStatCollector _transform_compose_pcollector;
   static PStatCollector _transform_invert_pcollector;
   static PStatCollector _transform_invert_pcollector;
 
 
+  static PStatCollector _node_counter;
+  static PStatCollector _cache_counter;
+
 private:
 private:
   // This is the actual data within the TransformState.
   // This is the actual data within the TransformState.
   INLINE void check_singular() const;
   INLINE void check_singular() const;
@@ -221,6 +229,9 @@ private:
   INLINE void set_destructing();
   INLINE void set_destructing();
   INLINE bool is_destructing() const;
   INLINE bool is_destructing() const;
 
 
+  INLINE void consider_update_pstats(int old_referenced_bits) const;
+  static void update_pstats(int old_referenced_bits, int new_referenced_bits);
+
   enum Flags {
   enum Flags {
     F_is_identity        = 0x0001,
     F_is_identity        = 0x0001,
     F_is_singular        = 0x0002,
     F_is_singular        = 0x0002,
@@ -260,9 +271,9 @@ public:
     return _type_handle;
     return _type_handle;
   }
   }
   static void init_type() {
   static void init_type() {
-    CachedTypedWritableReferenceCount::init_type();
+    NodeCachedReferenceCount::init_type();
     register_type(_type_handle, "TransformState",
     register_type(_type_handle, "TransformState",
-                  CachedTypedWritableReferenceCount::get_class_type());
+                  NodeCachedReferenceCount::get_class_type());
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

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

@@ -202,8 +202,12 @@ static LevelCollectorProperties level_properties[] = {
   { 1, "Memory usage:C++",                 { 0.2, 0.2, 1.0 } },
   { 1, "Memory usage:C++",                 { 0.2, 0.2, 1.0 } },
   { 1, "Memory usage:Interpreter",         { 0.8, 0.2, 0.5 } },
   { 1, "Memory usage:Interpreter",         { 0.8, 0.2, 0.5 } },
   { 1, "TransformStates",                  { 1.0, 0.5, 0.5 },  "", 5000 },
   { 1, "TransformStates",                  { 1.0, 0.5, 0.5 },  "", 5000 },
+  { 1, "TransformStates:On nodes",         { 0.2, 0.8, 1.0 } },
+  { 1, "TransformStates:Cached",           { 1.0, 0.0, 0.2 } },
   { 1, "TransformStates:Unused",           { 0.2, 0.2, 0.2 } },
   { 1, "TransformStates:Unused",           { 0.2, 0.2, 0.2 } },
   { 1, "RenderStates",                     { 0.5, 0.5, 1.0 },  "", 1000 },
   { 1, "RenderStates",                     { 0.5, 0.5, 1.0 },  "", 1000 },
+  { 1, "RenderStates:On nodes",            { 0.2, 0.8, 1.0 } },
+  { 1, "RenderStates:Cached",              { 1.0, 0.0, 0.2 } },
   { 1, "RenderStates:Unused",              { 0.2, 0.2, 0.2 } },
   { 1, "RenderStates:Unused",              { 0.2, 0.2, 0.2 } },
   { 0, NULL }
   { 0, NULL }
 };
 };

+ 9 - 0
panda/src/putil/Sources.pp

@@ -39,6 +39,9 @@
     load_prc_file.h \
     load_prc_file.h \
     modifierButtons.I modifierButtons.h mouseButton.h \
     modifierButtons.I modifierButtons.h mouseButton.h \
     mouseData.I mouseData.h nameUniquifier.I nameUniquifier.h \
     mouseData.I mouseData.h nameUniquifier.I nameUniquifier.h \
+    nodeCachedReferenceCount.h nodeCachedReferenceCount.I \
+    nodePointerToBase.h nodePointerToBase.I \
+    nodePointerTo.h nodePointerTo.I \
     pipeline.h pipeline.I \
     pipeline.h pipeline.I \
     pipelineCycler.h pipelineCycler.I \
     pipelineCycler.h pipelineCycler.I \
     pipelineCyclerBase.h pipelineCyclerBase.I \
     pipelineCyclerBase.h pipelineCyclerBase.I \
@@ -71,6 +74,9 @@
     load_prc_file.cxx \
     load_prc_file.cxx \
     modifierButtons.cxx mouseButton.cxx mouseData.cxx \
     modifierButtons.cxx mouseButton.cxx mouseData.cxx \
     nameUniquifier.cxx \
     nameUniquifier.cxx \
+    nodeCachedReferenceCount.cxx \
+    nodePointerToBase.cxx \
+    nodePointerTo.cxx \
     pipeline.cxx \
     pipeline.cxx \
     pipelineCycler.cxx \
     pipelineCycler.cxx \
     pipelineCyclerBase.cxx \
     pipelineCyclerBase.cxx \
@@ -114,6 +120,9 @@
     modifierButtons.I \
     modifierButtons.I \
     modifierButtons.h mouseButton.h mouseData.I mouseData.h \
     modifierButtons.h mouseButton.h mouseData.I mouseData.h \
     nameUniquifier.I nameUniquifier.h \
     nameUniquifier.I nameUniquifier.h \
+    nodeCachedReferenceCount.h nodeCachedReferenceCount.I \
+    nodePointerToBase.h nodePointerToBase.I \
+    nodePointerTo.h nodePointerTo.I \
     pipeline.h pipeline.I \
     pipeline.h pipeline.I \
     pipelineCycler.h pipelineCycler.I \
     pipelineCycler.h pipelineCycler.I \
     pipelineCyclerBase.h pipelineCyclerBase.I \
     pipelineCyclerBase.h pipelineCyclerBase.I \

+ 8 - 8
panda/src/putil/cachedTypedWritableReferenceCount.I

@@ -130,20 +130,20 @@ INLINE CachedTypedWritableReferenceCount::
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CachedTypedWritableReferenceCount::get_cache_ref_count
 //     Function: CachedTypedWritableReferenceCount::get_cache_ref_count
-//       Access: Public
+//       Access: Published
 //  Description: Returns the current reference count.
 //  Description: Returns the current reference count.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE int CachedTypedWritableReferenceCount::
 INLINE int CachedTypedWritableReferenceCount::
 get_cache_ref_count() const {
 get_cache_ref_count() const {
 #ifndef NDEBUG
 #ifndef NDEBUG
-  test_cache_ref_count_integrity();
+  test_ref_count_integrity();
 #endif
 #endif
   return _cache_ref_count;
   return _cache_ref_count;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CachedTypedWritableReferenceCount::cache_ref
 //     Function: CachedTypedWritableReferenceCount::cache_ref
-//       Access: Public
+//       Access: Published
 //  Description: Explicitly increments the reference count.
 //  Description: Explicitly increments the reference count.
 //
 //
 //               This function is const, even though it changes the
 //               This function is const, even though it changes the
@@ -179,7 +179,7 @@ cache_ref() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CachedTypedWritableReferenceCount::cache_unref
 //     Function: CachedTypedWritableReferenceCount::cache_unref
-//       Access: Public
+//       Access: Published
 //  Description: Explicitly decrements the reference count.  Note that
 //  Description: Explicitly decrements the reference count.  Note that
 //               the object will not be implicitly deleted by unref()
 //               the object will not be implicitly deleted by unref()
 //               simply because the reference count drops to zero.
 //               simply because the reference count drops to zero.
@@ -231,13 +231,13 @@ cache_unref() const {
 
 
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CachedTypedWritableReferenceCount::test_cache_ref_count_integrity
-//       Access: Public
+//     Function: CachedTypedWritableReferenceCount::test_ref_count_integrity
+//       Access: Published
 //  Description: Does some easy checks to make sure that the reference
 //  Description: Does some easy checks to make sure that the reference
 //               count isn't completely bogus.
 //               count isn't completely bogus.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void CachedTypedWritableReferenceCount::
 INLINE void CachedTypedWritableReferenceCount::
-test_cache_ref_count_integrity() const {
+test_ref_count_integrity() const {
 #ifndef NDEBUG
 #ifndef NDEBUG
   nassertv(this != NULL);
   nassertv(this != NULL);
 
 
@@ -255,7 +255,7 @@ test_cache_ref_count_integrity() const {
   // somewhere.
   // somewhere.
   nassertv(_cache_ref_count >= 0);
   nassertv(_cache_ref_count >= 0);
 
 
-  test_ref_count_integrity();
+  TypedWritableReferenceCount::test_ref_count_integrity();
 #endif
 #endif
 }
 }
 
 

+ 1 - 1
panda/src/putil/cachedTypedWritableReferenceCount.h

@@ -52,7 +52,7 @@ PUBLISHED:
   INLINE int get_cache_ref_count() const;
   INLINE int get_cache_ref_count() const;
   INLINE int cache_ref() const;
   INLINE int cache_ref() const;
   INLINE int cache_unref() const;
   INLINE int cache_unref() const;
-  INLINE void test_cache_ref_count_integrity() const;
+  INLINE void test_ref_count_integrity() const;
 
 
 private:
 private:
   int _cache_ref_count;
   int _cache_ref_count;

+ 2 - 0
panda/src/putil/config_util.cxx

@@ -24,6 +24,7 @@
 #include "datagram.h"
 #include "datagram.h"
 #include "factoryParam.h"
 #include "factoryParam.h"
 #include "namable.h"
 #include "namable.h"
+#include "nodeCachedReferenceCount.h"
 #include "referenceCount.h"
 #include "referenceCount.h"
 #include "typedObject.h"
 #include "typedObject.h"
 #include "typedReferenceCount.h"
 #include "typedReferenceCount.h"
@@ -63,6 +64,7 @@ ConfigureFn(config_util) {
   Datagram::init_type();
   Datagram::init_type();
   FactoryParam::init_type();
   FactoryParam::init_type();
   Namable::init_type();
   Namable::init_type();
+  NodeCachedReferenceCount::init_type();
   ReferenceCount::init_type();
   ReferenceCount::init_type();
   TypedObject::init_type();
   TypedObject::init_type();
   TypedReferenceCount::init_type();
   TypedReferenceCount::init_type();

+ 319 - 0
panda/src/putil/nodeCachedReferenceCount.I

@@ -0,0 +1,319 @@
+// Filename: nodeCachedReferenceCount.I
+// Created by:  drose (07May05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeCachedReferenceCount::Constructor
+//       Access: Protected
+//  Description: The ReferenceCount constructor is protected because
+//               you almost never want to create just a ReferenceCount
+//               object by itself, and it's probably a mistake if you
+//               try.
+//
+//               ReferenceCount doesn't store any useful information
+//               in its own right; its only purpose is to add
+//               reference-counting to some other class via
+//               inheritance.
+////////////////////////////////////////////////////////////////////
+INLINE NodeCachedReferenceCount::
+NodeCachedReferenceCount() {
+  _node_ref_count = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeCachedReferenceCount::Copy Constructor
+//       Access: Protected
+//  Description: The copies of reference-counted objects do not
+//               themselves inherit the reference count!
+//
+//               This copy constructor is protected because you almost
+//               never want to create just a ReferenceCount object by
+//               itself, and it's probably a mistake if you try.
+////////////////////////////////////////////////////////////////////
+INLINE NodeCachedReferenceCount::
+NodeCachedReferenceCount(const NodeCachedReferenceCount &copy) : CachedTypedWritableReferenceCount(copy) {
+  _node_ref_count = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeCachedReferenceCount::Copy Assignment Operator
+//       Access: Protected
+//  Description: The copies of reference-counted objects do not
+//               themselves inherit the reference count!
+//
+//               This copy assignment operator is protected because
+//               you almost never want to copy just a ReferenceCount
+//               object by itself, and it's probably a mistake if you
+//               try.  Instead, this should only be called from a
+//               derived class that implements this operator and then
+//               calls up the inheritance chain.
+////////////////////////////////////////////////////////////////////
+INLINE void NodeCachedReferenceCount::
+operator = (const NodeCachedReferenceCount &copy) {
+  nassertv(this != NULL);
+
+  // If this assertion fails, our own pointer was recently deleted.
+  // Possibly you used a real pointer instead of a PointerTo at some
+  // point, and the object was deleted when the PointerTo went out of
+  // scope.  Maybe you tried to create an automatic (local variable)
+  // instance of a class that derives from ReferenceCount.  Or maybe
+  // your headers are out of sync, and you need to make clean in
+  // direct or some higher tree.
+  nassertv(_node_ref_count != -100);
+
+  CachedTypedWritableReferenceCount::operator = (copy);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeCachedReferenceCount::Destructor
+//       Access: Protected
+//  Description: The ReferenceCount destructor is protected to
+//               discourage users from accidentally trying to delete a
+//               ReferenceCount pointer directly.  This is almost
+//               always a bad idea, since the destructor is not
+//               virtual, and you've almost certainly got some pointer
+//               to something that inherits from ReferenceCount, not
+//               just a plain old ReferenceCount object.
+////////////////////////////////////////////////////////////////////
+INLINE NodeCachedReferenceCount::
+~NodeCachedReferenceCount() {
+  nassertv(this != NULL);
+
+  // If this assertion fails, we're trying to delete an object that
+  // was just deleted.  Possibly you used a real pointer instead of a
+  // PointerTo at some point, and the object was deleted when the
+  // PointerTo went out of scope.  Maybe you tried to create an
+  // automatic (local variable) instance of a class that derives from
+  // ReferenceCount.  Or maybe your headers are out of sync, and you
+  // need to make clean in direct or some higher tree.
+  nassertv(_node_ref_count != -100);
+
+  // If this assertion fails, the reference counts are all screwed
+  // up altogether.  Maybe some errant code stomped all over memory
+  // somewhere.
+  nassertv(_node_ref_count >= 0);
+
+  // If this assertion fails, someone tried to delete this object
+  // while its reference count was still positive.  Maybe you tried
+  // to point a PointerTo at a static object (a local variable,
+  // instead of one allocated via new)?  The test below against 0x7f
+  // is supposed to check for that, but it's a pretty hokey test.
+
+  // Another possibility is you inadvertently omitted a copy
+  // constructor for a ReferenceCount object, and then bitwise
+  // copied a dynamically allocated value--reference count and
+  // all--onto a locally allocated one.
+  nassertv(_node_ref_count == 0);
+
+#ifndef NDEBUG
+  // Ok, all clear to delete.  Now set the reference count to -100,
+  // so we'll have a better chance of noticing if we happen to have
+  // a stray pointer to it still out there.
+  _node_ref_count = -100;
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeCachedReferenceCount::get_node_ref_count
+//       Access: Published
+//  Description: Returns the current reference count.
+////////////////////////////////////////////////////////////////////
+INLINE int NodeCachedReferenceCount::
+get_node_ref_count() const {
+#ifndef NDEBUG
+  test_ref_count_integrity();
+#endif
+  return _node_ref_count;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeCachedReferenceCount::node_ref
+//       Access: Published
+//  Description: Explicitly increments the reference count.
+//
+//               This function is const, even though it changes the
+//               object, because generally fiddling with an object's
+//               reference count isn't considered part of fiddling
+//               with the object.  An object might be const in other
+//               ways, but we still need to accurately count the
+//               number of references to it.
+//
+//               The return value is the new reference count.
+////////////////////////////////////////////////////////////////////
+INLINE int NodeCachedReferenceCount::
+node_ref() const {
+  nassertr(this != NULL, 0);
+
+  // If this assertion fails, we're trying to delete an object that
+  // was just deleted.  Possibly you used a real pointer instead of a
+  // PointerTo at some point, and the object was deleted when the
+  // PointerTo went out of scope.  Maybe you tried to create an
+  // automatic (local variable) instance of a class that derives from
+  // ReferenceCount.  Or maybe your headers are out of sync, and you
+  // need to make clean in direct or some higher tree.
+  nassertr(_node_ref_count != -100, 0);
+
+  // If this assertion fails, the reference counts are all screwed
+  // up altogether.  Maybe some errant code stomped all over memory
+  // somewhere.
+  nassertr(_node_ref_count >= 0, 0);
+
+  ref();
+  return AtomicAdjust::inc(((NodeCachedReferenceCount *)this)->_node_ref_count);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeCachedReferenceCount::node_unref
+//       Access: Published
+//  Description: Explicitly decrements the reference count.  Note that
+//               the object will not be implicitly deleted by unref()
+//               simply because the reference count drops to zero.
+//               (Having a member function delete itself is
+//               problematic; plus, we don't have a virtual destructor
+//               anyway.) However, see the helper function
+//               unref_delete().
+//
+//               User code should avoid using ref() and unref()
+//               directly, which can result in missed reference
+//               counts.  Instead, let a PointerTo object manage the
+//               reference counting automatically.
+//
+//               This function is const, even though it changes the
+//               object, because generally fiddling with an object's
+//               reference count isn't considered part of fiddling
+//               with the object.  An object might be const in other
+//               ways, but we still need to accurately count the
+//               number of references to it.
+//
+//               The return value is the new reference count.
+////////////////////////////////////////////////////////////////////
+INLINE int NodeCachedReferenceCount::
+node_unref() const {
+  nassertr(this != NULL, false);
+
+  // If this assertion fails, we're trying to delete an object that
+  // was just deleted.  Possibly you used a real pointer instead of a
+  // PointerTo at some point, and the object was deleted when the
+  // PointerTo went out of scope.  Maybe you tried to create an
+  // automatic (local variable) instance of a class that derives from
+  // ReferenceCount.  Or maybe your headers are out of sync, and you
+  // need to make clean in direct or some higher tree.
+  nassertr(_node_ref_count != -100, false);
+
+  // If this assertion fails, the reference counts are all screwed
+  // up altogether.  Maybe some errant code stomped all over memory
+  // somewhere.
+  nassertr(_node_ref_count >= 0, false);
+
+  // If this assertion fails, you tried to unref an object with a
+  // zero reference count.  Are you using ref() and unref()
+  // directly?  Are you sure you can't use PointerTo's?
+  nassertr(_node_ref_count > 0, false);
+
+  unref();
+  return AtomicAdjust::dec(((NodeCachedReferenceCount *)this)->_node_ref_count);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeCachedReferenceCount::test_ref_count_integrity
+//       Access: Published
+//  Description: Does some easy checks to make sure that the reference
+//               count isn't completely bogus.
+////////////////////////////////////////////////////////////////////
+INLINE void NodeCachedReferenceCount::
+test_ref_count_integrity() const {
+#ifndef NDEBUG
+  nassertv(this != NULL);
+
+  // If this assertion fails, we're trying to delete an object that
+  // was just deleted.  Possibly you used a real pointer instead of a
+  // PointerTo at some point, and the object was deleted when the
+  // PointerTo went out of scope.  Maybe you tried to create an
+  // automatic (local variable) instance of a class that derives from
+  // ReferenceCount.  Or maybe your headers are out of sync, and you
+  // need to make clean in direct or some higher tree.
+  nassertv(_node_ref_count != -100);
+
+  // If this assertion fails, the reference counts are all screwed
+  // up altogether.  Maybe some errant code stomped all over memory
+  // somewhere.
+  nassertv(_node_ref_count >= 0);
+
+  CachedTypedWritableReferenceCount::test_ref_count_integrity();
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeCachedReferenceCount::get_referenced_bits
+//       Access: Published
+//  Description: Returns the union of the values defined in the
+//               Referenced enum that represents the various things
+//               that appear to be holding a pointer to this object.
+//
+//               If R_node is included, at least one node is holding a
+//               pointer; if R_cache is included, at least one cache
+//               element is.
+////////////////////////////////////////////////////////////////////
+INLINE int NodeCachedReferenceCount::
+get_referenced_bits() const {
+  int result = 0;
+  if (get_node_ref_count() != 0) {
+    result |= R_node;
+  }
+  if (get_cache_ref_count() != 0) {
+    result |= R_cache;
+  }
+
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: node_unref_delete
+//  Description: This global helper function will unref the given
+//               ReferenceCount object, and if the reference count
+//               reaches zero, automatically delete it.  It can't be a
+//               member function because it's usually a bad idea to
+//               delete an object from within its own member function.
+//               It's a template function so the destructor doesn't
+//               have to be virtual.
+////////////////////////////////////////////////////////////////////
+template<class RefCountType>
+INLINE void
+node_unref_delete(RefCountType *ptr) {
+  ptr->node_unref();
+  if (ptr->get_ref_count() == 0) {
+#ifndef NDEBUG
+    if (get_leak_memory()) {
+      // In leak-memory mode, we don't actually delete the pointer,
+      // although we do call the destructor explicitly.  This has
+      // exactly the same effect as deleting it, without actually
+      // freeing up the memory it uses.
+
+      // Furthermore, if we have never-destruct set, we don't even
+      // call the destructor.
+      if (!get_never_destruct()) {
+        ptr->~RefCountType();
+      }
+      return;
+    }
+#endif
+    delete ptr;
+  }
+}
+

+ 22 - 0
panda/src/putil/nodeCachedReferenceCount.cxx

@@ -0,0 +1,22 @@
+// Filename: nodeCachedReferenceCount.cxx
+// Created by:  drose (07May05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "nodeCachedReferenceCount.h"
+
+TypeHandle NodeCachedReferenceCount::_type_handle;
+

+ 95 - 0
panda/src/putil/nodeCachedReferenceCount.h

@@ -0,0 +1,95 @@
+// Filename: nodeCachedReferenceCount.h
+// Created by:  drose (07May05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef NODECACHEDREFERENCECOUNT_H
+#define NODECACHEDREFERENCECOUNT_H
+
+#include "pandabase.h"
+
+#include "cachedTypedWritableReferenceCount.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : NodeCachedReferenceCount
+// Description : This class further specializes
+//               CachedTypedWritableReferenceCount to also add a
+//               node_ref_count, for the purposes of counting the
+//               number of times the object is referenced by a "node",
+//               presumably a PandaNode.
+//
+//               The intended design is to use this as a base class
+//               for RenderState and TransformState, both of which are
+//               held by PandaNodes, and also have caches which are
+//               independently maintained.  By keeping track of how
+//               many nodes hold a pointer to a particular object, we
+//               can classify each object into node-referenced,
+//               cache-referenced, or other, which is primarily useful
+//               for PStats reporting.
+//
+//               As with CachedTypedWritableReferenceCount's
+//               cache_ref() and cache_unref(), the new methods
+//               node_ref() and node_unref() automatically increment
+//               and decrement the primary reference count as well.
+//               In this case, however, there does exist a
+//               NodePointerTo<> class to maintain the node_ref
+//               counters automatically.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA NodeCachedReferenceCount : public CachedTypedWritableReferenceCount {
+protected:
+  INLINE NodeCachedReferenceCount();
+  INLINE NodeCachedReferenceCount(const NodeCachedReferenceCount &copy);
+  INLINE void operator = (const NodeCachedReferenceCount &copy);
+  INLINE ~NodeCachedReferenceCount();
+
+PUBLISHED:
+  INLINE int get_node_ref_count() const;
+  INLINE int node_ref() const;
+  INLINE int node_unref() const;
+  INLINE void test_ref_count_integrity() const;
+
+  enum Referenced {
+    R_node  = 0x001,
+    R_cache = 0x002,
+  };
+
+  INLINE int get_referenced_bits() const;
+  
+private:
+  int _node_ref_count;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+
+  static void init_type() {
+    CachedTypedWritableReferenceCount::init_type();
+    register_type(_type_handle, "NodeCachedReferenceCount",
+                  CachedTypedWritableReferenceCount::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+template<class RefCountType>
+INLINE void node_unref_delete(RefCountType *ptr);
+
+#include "nodeCachedReferenceCount.I"
+
+#endif  
+

+ 239 - 0
panda/src/putil/nodePointerTo.I

@@ -0,0 +1,239 @@
+// Filename: nodePointerTo.I
+// Created by:  drose (07May05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePointerTo::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE NodePointerTo<T>::
+NodePointerTo(To *ptr) : NodePointerToBase<T>(ptr) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePointerTo::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE NodePointerTo<T>::
+NodePointerTo(const NodePointerTo<T> &copy) :
+  NodePointerToBase<T>((const NodePointerToBase<T> &)copy)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePointerTo::Dereference operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE TYPENAME NodePointerTo<T>::To &NodePointerTo<T>::
+operator *() const {
+  return *((To *)(this->_void_ptr));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePointerTo::Member access operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE TYPENAME NodePointerTo<T>::To *NodePointerTo<T>::
+operator -> () const {
+  return (To *)(this->_void_ptr);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePointerTo::Typecast operator
+//       Access: Public
+//  Description: We also have the typecast operator to automatically
+//               convert NodePointerTo's to the required kind of actual
+//               pointer.  This introduces ambiguities which the
+//               compiler will resolve one way or the other, but we
+//               don't care which way it goes because either will be
+//               correct.
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE NodePointerTo<T>::
+operator TYPENAME NodePointerToBase<T>::To *() const {
+  return (To *)(this->_void_ptr);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePointerTo::p
+//       Access: Public
+//  Description: Returns an ordinary pointer instead of a NodePointerTo.
+//               Useful to work around compiler problems, particularly
+//               for implicit upcasts.
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE TYPENAME NodePointerTo<T>::To *NodePointerTo<T>::
+p() const {
+  return (To *)(this->_void_ptr);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePointerTo::Assignment operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE NodePointerTo<T> &NodePointerTo<T>::
+operator = (To *ptr) {
+  reassign(ptr);
+  return *this;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePointerTo::Assignment operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE NodePointerTo<T> &NodePointerTo<T>::
+operator = (const NodePointerTo<T> &copy) {
+  reassign((const NodePointerToBase<T> &)copy);
+  return *this;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConstPointerTo::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE NodeConstPointerTo<T>::
+NodeConstPointerTo(const TYPENAME NodeConstPointerTo<T>::To *ptr) :
+  NodePointerToBase<T>((TYPENAME NodeConstPointerTo<T>::To *)ptr)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConstPointerTo::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE NodeConstPointerTo<T>::
+NodeConstPointerTo(const NodePointerTo<T> &copy) :
+  NodePointerToBase<T>((const NodePointerToBase<T> &)copy)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConstPointerTo::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE NodeConstPointerTo<T>::
+NodeConstPointerTo(const NodeConstPointerTo<T> &copy) :
+  NodePointerToBase<T>((const NodePointerToBase<T> &)copy)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConstPointerTo::Dereference operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE const TYPENAME NodeConstPointerTo<T>::To &NodeConstPointerTo<T>::
+operator *() const {
+  return *((To *)(this->_void_ptr));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConstPointerTo::Member access operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE const TYPENAME NodeConstPointerTo<T>::To *NodeConstPointerTo<T>::
+operator -> () const {
+  return (To *)(this->_void_ptr);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConstPointerTo::Typecast operator
+//       Access: Public
+//  Description: We also have the typecast operator to automatically
+//               convert NodeConstPointerTo's to the required kind of actual
+//               pointer.  This introduces ambiguities which the
+//               compiler will resolve one way or the other, but we
+//               don't care which way it goes because either will be
+//               correct.
+////////////////////////////////////////////////////////////////////
+
+template<class T>
+INLINE NodeConstPointerTo<T>::
+operator const TYPENAME NodePointerToBase<T>::To *() const {
+  return (To *)(this->_void_ptr);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConstPointerTo::p
+//       Access: Public
+//  Description: Returns an ordinary pointer instead of a NodeConstPointerTo.
+//               Useful to work around compiler problems, particularly
+//               for implicit upcasts.
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE const TYPENAME NodeConstPointerTo<T>::To *NodeConstPointerTo<T>::
+p() const {
+  return (To *)(this->_void_ptr);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConstPointerTo::Assignment operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE NodeConstPointerTo<T> &NodeConstPointerTo<T>::
+operator = (const To *ptr) {
+  reassign((To *)ptr);
+  return *this;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConstPointerTo::Assignment operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE NodeConstPointerTo<T> &NodeConstPointerTo<T>::
+operator = (const NodePointerTo<T> &copy) {
+  reassign((const NodePointerToBase<T> &)copy);
+  return *this;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConstPointerTo::Assignment operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE NodeConstPointerTo<T> &NodeConstPointerTo<T>::
+operator = (const NodeConstPointerTo<T> &copy) {
+  reassign((const NodePointerToBase<T> &)copy);
+  return *this;
+}

+ 19 - 0
panda/src/putil/nodePointerTo.cxx

@@ -0,0 +1,19 @@
+// Filename: nodePointerTo.cxx
+// Created by:  drose (07May05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "nodePointerTo.h"

+ 81 - 0
panda/src/putil/nodePointerTo.h

@@ -0,0 +1,81 @@
+// Filename: nodePointerTo.h
+// Created by:  drose (07May05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef NODEPOINTERTO_H
+#define NODEPOINTERTO_H
+
+#include "pandabase.h"
+#include "nodePointerToBase.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : NodePointerTo
+// Description : 
+
+//               This implements the special NodePointerTo template
+//               class, which works just like PointerTo except it
+//               manages the objects node_ref_count instead of the
+//               normal ref_count.
+////////////////////////////////////////////////////////////////////
+template <class T>
+class NodePointerTo : public NodePointerToBase<T> {
+public:
+  typedef TYPENAME NodePointerToBase<T>::To To;
+  INLINE NodePointerTo(To *ptr = (To *)NULL);
+  INLINE NodePointerTo(const NodePointerTo<T> &copy);
+
+  INLINE To &operator *() const;
+  INLINE To *operator -> () const;
+  INLINE operator TYPENAME NodePointerToBase<T>::To *() const;
+
+  INLINE To *p() const;
+
+  INLINE NodePointerTo<T> &operator = (To *ptr);
+  INLINE NodePointerTo<T> &operator = (const NodePointerTo<T> &copy);
+};
+
+
+////////////////////////////////////////////////////////////////////
+//       Class : NodeConstPointerTo
+// Description : A NodeConstPointerTo is similar to a NodePointerTo,
+//               except it keeps a const pointer to the thing.
+////////////////////////////////////////////////////////////////////
+template <class T>
+class NodeConstPointerTo : public NodePointerToBase<T> {
+public:
+  typedef TYPENAME NodePointerToBase<T>::To To;
+  INLINE NodeConstPointerTo(const To *ptr = (const To *)NULL);
+  INLINE NodeConstPointerTo(const NodePointerTo<T> &copy);
+  INLINE NodeConstPointerTo(const NodeConstPointerTo<T> &copy);
+
+  INLINE const To &operator *() const;
+  INLINE const To *operator -> () const;
+  INLINE operator const TYPENAME NodePointerToBase<T>::To *() const;
+
+  INLINE const To *p() const;
+
+  INLINE NodeConstPointerTo<T> &operator = (const To *ptr);
+  INLINE NodeConstPointerTo<T> &operator = (const NodePointerTo<T> &copy);
+  INLINE NodeConstPointerTo<T> &operator = (const NodeConstPointerTo<T> &copy);
+};
+
+#define NPT(type) NodePointerTo< type >
+#define NCPT(type) NodeConstPointerTo< type >
+
+#include "nodePointerTo.I"
+
+#endif

+ 135 - 0
panda/src/putil/nodePointerToBase.I

@@ -0,0 +1,135 @@
+// Filename: nodePointerToBase.I
+// Created by:  drose (07May05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePointerToBase::Constructor
+//       Access: Protected
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE NodePointerToBase<T>::
+NodePointerToBase(To *ptr) {
+  reassign(ptr);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePointerToBase::Copy Constructor
+//       Access: Protected
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE NodePointerToBase<T>::
+NodePointerToBase(const NodePointerToBase<T> &copy) {
+  reassign(copy);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePointerToBase::Destructor
+//       Access: Protected
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE NodePointerToBase<T>::
+~NodePointerToBase() {
+  reassign((To *)NULL);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePointerToBase::reassign
+//       Access: Protected
+//  Description: This is the main work of the NodePointerTo family.  When
+//               the pointer is reassigned, decrement the old
+//               reference count and increment the new one.
+////////////////////////////////////////////////////////////////////
+template<class T>
+void NodePointerToBase<T>::
+reassign(To *ptr) {
+  if (ptr != (To *)_void_ptr) {
+    // First save the old pointer; we won't delete it until we have
+    // assigned the new one.  We do this just in case there are
+    // cascading effects from deleting this pointer that might
+    // inadvertently delete the new one.  (Don't laugh--it's
+    // happened!)
+    To *old_ptr = (To *)_void_ptr;
+
+    _void_ptr = (void *)ptr;
+    if (ptr != (To *)NULL) {
+      ptr->node_ref();
+#ifdef DO_MEMORY_USAGE
+      if (MemoryUsage::get_track_memory_usage()) {
+        // Make sure the MemoryUsage record knows what the TypeHandle
+        // is, if we know it ourselves.
+        TypeHandle type = get_type_handle(To);
+        if (type == TypeHandle::none()) {
+          do_init_type(To);
+          type = get_type_handle(To);
+        }
+        if (type != TypeHandle::none()) {
+          MemoryUsage::update_type(ptr, type);
+        }
+      }
+#endif
+    }
+
+    // Now delete the old pointer.
+    if (old_ptr != (To *)NULL) {
+      node_unref_delete(old_ptr);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePointerToBase::reassign
+//       Access: Protected
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE void NodePointerToBase<T>::
+reassign(const NodePointerToBase<To> &copy) {
+  reassign((To *)copy._void_ptr);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePointerToBase::clear
+//       Access: Published
+//  Description: A convenient way to set the NodePointerTo object to NULL.
+//               (Assignment to a NULL pointer also works, of course.)
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE void NodePointerToBase<T>::
+clear() {
+  reassign((To *)NULL);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePointerToBase::output
+//       Access: Published
+//  Description: A handy function to output NodePointerTo's as a hex
+//               pointer followed by a reference count.
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE void NodePointerToBase<T>::
+output(ostream &out) const {
+  out << _void_ptr;
+  if (_void_ptr != (void *)NULL) {
+    out << ":" << ((To *)_void_ptr)->get_node_ref_count() << "/"
+        << ((To *)_void_ptr)->get_ref_count();
+  }
+}

+ 19 - 0
panda/src/putil/nodePointerToBase.cxx

@@ -0,0 +1,19 @@
+// Filename: nodePointerToBase.cxx
+// Created by:  drose (07May05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "nodePointerToBase.h"

+ 70 - 0
panda/src/putil/nodePointerToBase.h

@@ -0,0 +1,70 @@
+// Filename: nodePointerToBase.h
+// Created by:  drose (07May05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef NODEPOINTERTOBASE_H
+#define NODEPOINTERTOBASE_H
+
+#include "pandabase.h"
+#include "pointerToVoid.h"
+#include "nodeCachedReferenceCount.h"
+#include "memoryUsage.h"
+#include "config_express.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : NodePointerToBase
+// Description : This is similar to PointerToBase, but it manages
+//               objects of type NodeCachedReferenceCount, and it
+//               updates the node_ref_count instead of the regular
+//               ref_count.  It is intended for use only in PandaNode,
+//               to hold a pointer to RenderState and TransformState,
+//               although it could be used by any object that wanted
+//               to maintain a separate reference count for reporting
+//               purposes.
+////////////////////////////////////////////////////////////////////
+template <class T>
+class NodePointerToBase : public PointerToVoid {
+public:
+  typedef T To;
+
+protected:
+  INLINE NodePointerToBase(To *ptr);
+  INLINE NodePointerToBase(const NodePointerToBase<T> &copy);
+  INLINE ~NodePointerToBase();
+
+  void reassign(To *ptr);
+  INLINE void reassign(const NodePointerToBase<To> &copy);
+
+  // No assignment or retrieval functions are declared in
+  // NodePointerToBase, because we will have to specialize on const
+  // vs. non-const later.
+
+PUBLISHED:
+  INLINE void clear();
+
+  void output(ostream &out) const;
+};
+
+template<class T>
+INLINE ostream &operator <<(ostream &out, const NodePointerToBase<T> &pointer) {
+  pointer.output(out);
+  return out;
+}
+
+#include "nodePointerToBase.I"
+
+#endif

+ 0 - 3
panda/src/putil/putil_composite1.cxx

@@ -24,6 +24,3 @@
 #include "lineStreamBuf.cxx"
 #include "lineStreamBuf.cxx"
 #include "load_prc_file.cxx"
 #include "load_prc_file.cxx"
 #include "modifierButtons.cxx"
 #include "modifierButtons.cxx"
-#include "mouseButton.cxx"
-#include "mouseData.cxx"
-

+ 5 - 0
panda/src/putil/putil_composite2.cxx

@@ -1,4 +1,9 @@
+#include "mouseButton.cxx"
+#include "mouseData.cxx"
 #include "nameUniquifier.cxx"
 #include "nameUniquifier.cxx"
+#include "nodeCachedReferenceCount.cxx"
+#include "nodePointerToBase.cxx"
+#include "nodePointerTo.cxx"
 #include "pipeline.cxx"
 #include "pipeline.cxx"
 #include "pipelineCycler.cxx"
 #include "pipelineCycler.cxx"
 #include "pipelineCyclerBase.cxx"
 #include "pipelineCyclerBase.cxx"