Преглед на файлове

more pgraph refinements

David Rose преди 24 години
родител
ревизия
29e70407b5

+ 119 - 13
panda/src/char/characterJoint.cxx

@@ -160,6 +160,30 @@ update_internals(PartGroup *parent, bool self_changed, bool parent_changed) {
     }
     }
   }
   }
 
 
+  if (net_changed && !_net_transform_nodes.empty()) {
+    CPT(TransformState) t = TransformState::make_mat(_net_transform);
+
+    NodeList::iterator ai;
+    ai = _net_transform_nodes.begin();
+    while (ai != _net_transform_nodes.end()) {
+      PandaNode *node = *ai;
+      node->set_transform(t);
+      ++ai;
+    }
+  }
+
+  if (self_changed && !_local_transform_nodes.empty()) {
+    CPT(TransformState) t = TransformState::make_mat(_value);
+
+    NodeList::iterator ai;
+    ai = _local_transform_nodes.begin();
+    while (ai != _local_transform_nodes.end()) {
+      PandaNode *node = *ai;
+      node->set_transform(t);
+      ++ai;
+    }
+  }
+
   return self_changed || net_changed;
   return self_changed || net_changed;
 }
 }
 
 
@@ -203,18 +227,6 @@ has_net_transform(NodeRelation *arc) const {
   return (_net_transform_arcs.count(arc) > 0);
   return (_net_transform_arcs.count(arc) > 0);
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: CharacterJoint::clear_net_transforms
-//       Access: Public
-//  Description: Removes all arcs from the list of arcs that will be
-//               updated each frame with the joint's net transform
-//               from the root.
-////////////////////////////////////////////////////////////////////
-void CharacterJoint::
-clear_net_transforms() {
-  _net_transform_arcs.clear();
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CharacterJoint::add_local_transform
 //     Function: CharacterJoint::add_local_transform
 //       Access: Public
 //       Access: Public
@@ -255,16 +267,110 @@ has_local_transform(NodeRelation *arc) const {
   return (_local_transform_arcs.count(arc) > 0);
   return (_local_transform_arcs.count(arc) > 0);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJoint::add_net_transform
+//       Access: Public
+//  Description: Adds the indicated node to the list of nodes that will
+//               be updated each frame with the joint's net transform
+//               from the root.  Returns true if the node is
+//               successfully added, false if it had already been
+//               added.
+////////////////////////////////////////////////////////////////////
+bool CharacterJoint::
+add_net_transform(PandaNode *node) {
+  return _net_transform_nodes.insert(node).second;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJoint::remove_net_transform
+//       Access: Public
+//  Description: Removes the indicated node from the list of nodes that
+//               will be updated each frame with the joint's net
+//               transform from the root.  Returns true if the node is
+//               successfully removed, false if it was not on the
+//               list.
+////////////////////////////////////////////////////////////////////
+bool CharacterJoint::
+remove_net_transform(PandaNode *node) {
+  return (_net_transform_nodes.erase(node) > 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJoint::has_net_transform
+//       Access: Public
+//  Description: Returns true if the node is on the list of nodes that
+//               will be updated each frame with the joint's net
+//               transform from the root, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool CharacterJoint::
+has_net_transform(PandaNode *node) const {
+  return (_net_transform_nodes.count(node) > 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJoint::clear_net_transforms
+//       Access: Public
+//  Description: Removes all nodes from the list of nodes that will be
+//               updated each frame with the joint's net transform
+//               from the root.
+////////////////////////////////////////////////////////////////////
+void CharacterJoint::
+clear_net_transforms() {
+  _net_transform_arcs.clear();
+  _net_transform_nodes.clear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJoint::add_local_transform
+//       Access: Public
+//  Description: Adds the indicated node to the list of nodes that will
+//               be updated each frame with the joint's local
+//               transform from its parent.  Returns true if the node
+//               is successfully added, false if it had already been
+//               added.
+////////////////////////////////////////////////////////////////////
+bool CharacterJoint::
+add_local_transform(PandaNode *node) {
+  return _local_transform_nodes.insert(node).second;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJoint::remove_local_transform
+//       Access: Public
+//  Description: Removes the indicated node from the list of nodes that
+//               will be updated each frame with the joint's local
+//               transform from its parent.  Returns true if the node
+//               is successfully removed, false if it was not on the
+//               list.
+////////////////////////////////////////////////////////////////////
+bool CharacterJoint::
+remove_local_transform(PandaNode *node) {
+  return (_local_transform_nodes.erase(node) > 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJoint::has_local_transform
+//       Access: Public
+//  Description: Returns true if the node is on the list of nodes that
+//               will be updated each frame with the joint's local
+//               transform from its parent, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool CharacterJoint::
+has_local_transform(PandaNode *node) const {
+  return (_local_transform_nodes.count(node) > 0);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CharacterJoint::clear_local_transforms
 //     Function: CharacterJoint::clear_local_transforms
 //       Access: Public
 //       Access: Public
-//  Description: Removes all arcs from the list of arcs that will be
+//  Description: Removes all nodes from the list of nodes that will be
 //               updated each frame with the joint's local transform
 //               updated each frame with the joint's local transform
 //               from its parent.
 //               from its parent.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CharacterJoint::
 void CharacterJoint::
 clear_local_transforms() {
 clear_local_transforms() {
   _local_transform_arcs.clear();
   _local_transform_arcs.clear();
+  _local_transform_nodes.clear();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 13 - 1
panda/src/char/characterJoint.h

@@ -50,11 +50,19 @@ PUBLISHED:
   bool add_net_transform(NodeRelation *arc);
   bool add_net_transform(NodeRelation *arc);
   bool remove_net_transform(NodeRelation *arc);
   bool remove_net_transform(NodeRelation *arc);
   bool has_net_transform(NodeRelation *arc) const;
   bool has_net_transform(NodeRelation *arc) const;
-  void clear_net_transforms();
 
 
   bool add_local_transform(NodeRelation *arc);
   bool add_local_transform(NodeRelation *arc);
   bool remove_local_transform(NodeRelation *arc);
   bool remove_local_transform(NodeRelation *arc);
   bool has_local_transform(NodeRelation *arc) const;
   bool has_local_transform(NodeRelation *arc) const;
+
+  bool add_net_transform(PandaNode *node);
+  bool remove_net_transform(PandaNode *node);
+  bool has_net_transform(PandaNode *node) const;
+  void clear_net_transforms();
+
+  bool add_local_transform(PandaNode *node);
+  bool remove_local_transform(PandaNode *node);
+  bool has_local_transform(PandaNode *node) const;
   void clear_local_transforms();
   void clear_local_transforms();
 
 
 private:
 private:
@@ -62,6 +70,10 @@ private:
   ArcList _net_transform_arcs;
   ArcList _net_transform_arcs;
   ArcList _local_transform_arcs;
   ArcList _local_transform_arcs;
 
 
+  typedef pset< PT(PandaNode) > NodeList;
+  NodeList _net_transform_nodes;
+  NodeList _local_transform_nodes;
+
 public:
 public:
   static void register_with_read_factory(void);
   static void register_with_read_factory(void);
   virtual void write_datagram(BamWriter* manager, Datagram &me);
   virtual void write_datagram(BamWriter* manager, Datagram &me);

+ 2 - 0
panda/src/collide/qpcollisionNode.cxx

@@ -39,6 +39,8 @@ qpCollisionNode(const string &name) :
   _into_collide_mask(CollideMask::all_on()),
   _into_collide_mask(CollideMask::all_on()),
   _collide_geom(false)
   _collide_geom(false)
 {
 {
+  // CollisionNodes are hidden by default.
+  set_draw_mask(DrawMask::all_off());
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 11 - 2
panda/src/linmath/lmatrix4_src.cxx

@@ -129,8 +129,17 @@ convert_mat(CoordinateSystem from, CoordinateSystem to) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int FLOATNAME(LMatrix4)::
 int FLOATNAME(LMatrix4)::
 compare_to(const FLOATNAME(LMatrix4) &other, FLOATTYPE threshold) const {
 compare_to(const FLOATNAME(LMatrix4) &other, FLOATTYPE threshold) const {
-  for (int i = 0; i < 16; i++) {
-    if (!IS_THRESHOLD_EQUAL(_m.data[i], other._m.data[i], threshold)) {
+  FLOATTYPE scale = 1.0f / threshold;
+
+  // We compare values in reverse order, since the last row of the
+  // matrix is most likely to be different between different matrices.
+  for (int i = 15; i >= 0; i--) {
+    // We scale both elements into the same range and truncate, rather
+    // than comparing the absolute values of their differences with
+    // IS_THRESHOLD_EQUAL.  This prevents a slippery-slope effect
+    // where a == b and b == c but a != c.
+    if (cfloor(_m.data[i] * scale + 0.5) != 
+        cfloor(other._m.data[i] * scale + 0.5)) {
       return (_m.data[i] < other._m.data[i]) ? -1 : 1;
       return (_m.data[i] < other._m.data[i]) ? -1 : 1;
     }
     }
   }
   }

+ 8 - 1
panda/src/pgraph/fogAttrib.cxx

@@ -98,7 +98,14 @@ int FogAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
   const FogAttrib *ta;
   const FogAttrib *ta;
   DCAST_INTO_R(ta, other, 0);
   DCAST_INTO_R(ta, other, 0);
-  return (int)(_fog - ta->_fog);
+
+  // Comparing pointers by subtraction is problematic.  Instead of
+  // doing this, we'll just depend on the built-in != and < operators
+  // for comparing pointers.
+  if (_fog != ta->_fog) {
+    return _fog < ta->_fog ? -1 : 1;
+  }
+  return 0;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 8 - 1
panda/src/pgraph/materialAttrib.cxx

@@ -98,7 +98,14 @@ int MaterialAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
   const MaterialAttrib *ta;
   const MaterialAttrib *ta;
   DCAST_INTO_R(ta, other, 0);
   DCAST_INTO_R(ta, other, 0);
-  return (int)(_material - ta->_material);
+
+  // Comparing pointers by subtraction is problematic.  Instead of
+  // doing this, we'll just depend on the built-in != and < operators
+  // for comparing pointers.
+  if (_material != ta->_material) {
+    return _material < ta->_material ? -1 : 1;
+  }
+  return 0;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 1 - 6
panda/src/pgraph/pandaNode.cxx

@@ -398,6 +398,7 @@ PandaNode(const PandaNode &copy) :
   cdata->_state = copy_cdata->_state;
   cdata->_state = copy_cdata->_state;
   cdata->_effects = copy_cdata->_effects;
   cdata->_effects = copy_cdata->_effects;
   cdata->_transform = copy_cdata->_transform;
   cdata->_transform = copy_cdata->_transform;
+  cdata->_draw_mask = copy_cdata->_draw_mask;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -1261,12 +1262,6 @@ children_changed() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 PT(PandaNode) PandaNode::
 PT(PandaNode) PandaNode::
 r_copy_subgraph(PandaNode::InstanceMap &inst_map) const {
 r_copy_subgraph(PandaNode::InstanceMap &inst_map) const {
-  if (!safe_to_flatten()) {
-    // If this kind of node cannot be copied, quietly return the same
-    // pointer, making an instance instead of a copy.
-    return (PandaNode *)this;
-  }
-
   PT(PandaNode) copy = make_copy();
   PT(PandaNode) copy = make_copy();
   nassertr(copy != (PandaNode *)NULL, NULL);
   nassertr(copy != (PandaNode *)NULL, NULL);
   if (copy->get_type() != get_type()) {
   if (copy->get_type() != get_type()) {

+ 7 - 5
panda/src/pgraph/qpcullTraverser.cxx

@@ -131,19 +131,21 @@ traverse_below(PandaNode *node, const CullTraverserData &data) {
       }
       }
     }
     }
     
     
-    // Now visit all the node's children.
-    PandaNode::Children cr = node->get_children();
-    int num_children = cr.get_num_children();
+    // Now visit all the node's children.  We cannot use the
+    // node->get_children() interface, because that will keep a read
+    // pointer open, and we might end up changing this node during the
+    // traversal.
+    int num_children = node->get_num_children();
     if (node->has_selective_visibility()) {
     if (node->has_selective_visibility()) {
       int i = node->get_first_visible_child();
       int i = node->get_first_visible_child();
       while (i < num_children) {
       while (i < num_children) {
-        traverse(cr.get_child(i), data);
+        traverse(node->get_child(i), data);
         i = node->get_next_visible_child(i);
         i = node->get_next_visible_child(i);
       }
       }
       
       
     } else {
     } else {
       for (int i = 0; i < num_children; i++) {
       for (int i = 0; i < num_children; i++) {
-        traverse(cr.get_child(i), data);
+        traverse(node->get_child(i), data);
       }
       }
     }
     }
   }
   }

+ 2 - 2
panda/src/pgraph/qpsceneGraphReducer.cxx

@@ -713,7 +713,7 @@ do_flatten_siblings(PandaNode *parent_node, PandaNode *child1,
       << "Collapsing " << *child1 << " and " << *child2 << "\n";
       << "Collapsing " << *child1 << " and " << *child2 << "\n";
   }
   }
 
 
-  PT(PandaNode) new_child = collapse_nodes(child1, child2, true);
+  PT(PandaNode) new_child = collapse_nodes(child2, child1, true);
   if (new_child == (PandaNode *)NULL) {
   if (new_child == (PandaNode *)NULL) {
     if (pgraph_cat.is_debug()) {
     if (pgraph_cat.is_debug()) {
       pgraph_cat.debug()
       pgraph_cat.debug()
@@ -722,7 +722,7 @@ do_flatten_siblings(PandaNode *parent_node, PandaNode *child1,
     return NULL;
     return NULL;
   }
   }
 
 
-  choose_name(new_child, child1, child2);
+  choose_name(new_child, child2, child1);
 
 
   if (new_child == child1) {
   if (new_child == child1) {
     new_child->steal_children(child2);
     new_child->steal_children(child2);

+ 29 - 7
panda/src/pgraph/renderAttrib.cxx

@@ -20,7 +20,7 @@
 #include "bamReader.h"
 #include "bamReader.h"
 #include "indent.h"
 #include "indent.h"
 
 
-RenderAttrib::Attribs RenderAttrib::_attribs;
+RenderAttrib::Attribs *RenderAttrib::_attribs = NULL;
 TypeHandle RenderAttrib::_type_handle;
 TypeHandle RenderAttrib::_type_handle;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -30,7 +30,15 @@ TypeHandle RenderAttrib::_type_handle;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 RenderAttrib::
 RenderAttrib::
 RenderAttrib() {
 RenderAttrib() {
-  _saved_entry = _attribs.end();
+  if (_attribs == (Attribs *)NULL) {
+    // Make sure the global _attribs map is allocated.  This only has
+    // to be done once.  We could make this map static, but then we
+    // run into problems if anyone creates a RenderState object at
+    // static init time; it also seems to cause problems when the
+    // Panda shared library is unloaded at application exit time.
+    _attribs = new Attribs;
+  }
+  _saved_entry = _attribs->end();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -61,9 +69,23 @@ operator = (const RenderAttrib &) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 RenderAttrib::
 RenderAttrib::
 ~RenderAttrib() {
 ~RenderAttrib() {
-  if (_saved_entry != _attribs.end()) {
-    _attribs.erase(_saved_entry);
-    _saved_entry = _attribs.end();
+  if (_saved_entry != _attribs->end()) {
+    // We cannot make this assertion, because the RenderAttrib has
+    // already partially destructed--this means we cannot look up the
+    // object in the map.  In fact, the map is temporarily invalid
+    // until we finish destructing, since we screwed up the ordering
+    // when we changed the return value of get_type().
+    //    nassertv(_attribs->find(this) == _saved_entry);
+
+    // Note: this isn't thread-safe, because once the derived class
+    // destructor exits and before this destructor completes, the map
+    // is invalid, and other threads may inadvertently attempt to read
+    // the invalid map.  To make it thread-safe, we need to move this
+    // functionality to a separate method, that is to be called from
+    // *each* derived class's destructor (and then we can put the
+    // above assert back in).
+    _attribs->erase(_saved_entry);
+    _saved_entry = _attribs->end();
   }
   }
 }
 }
 
 
@@ -120,13 +142,13 @@ return_new(RenderAttrib *attrib) {
 
 
   // This should be a newly allocated pointer, not one that was used
   // This should be a newly allocated pointer, not one that was used
   // for anything else.
   // for anything else.
-  nassertr(attrib->_saved_entry == _attribs.end(), attrib);
+  nassertr(attrib->_saved_entry == _attribs->end(), attrib);
 
 
   // Save the attrib in a local PointerTo so that it will be freed at
   // Save the attrib in a local PointerTo so that it will be freed at
   // the end of this function if no one else uses it.
   // the end of this function if no one else uses it.
   CPT(RenderAttrib) pt_attrib = attrib;
   CPT(RenderAttrib) pt_attrib = attrib;
 
 
-  pair<Attribs::iterator, bool> result = _attribs.insert(attrib);
+  pair<Attribs::iterator, bool> result = _attribs->insert(attrib);
   if (result.second) {
   if (result.second) {
     // The attribute was inserted; save the iterator and return the
     // The attribute was inserted; save the iterator and return the
     // input attribute.
     // input attribute.

+ 1 - 1
panda/src/pgraph/renderAttrib.h

@@ -85,7 +85,7 @@ protected:
 
 
 private:
 private:
   typedef pset<const RenderAttrib *, IndirectCompareTo<RenderAttrib> > Attribs;
   typedef pset<const RenderAttrib *, IndirectCompareTo<RenderAttrib> > Attribs;
-  static Attribs _attribs;
+  static Attribs *_attribs;
 
 
   Attribs::iterator _saved_entry;
   Attribs::iterator _saved_entry;
 
 

+ 2 - 0
panda/src/pgraph/renderEffect.cxx

@@ -62,6 +62,7 @@ operator = (const RenderEffect &) {
 RenderEffect::
 RenderEffect::
 ~RenderEffect() {
 ~RenderEffect() {
   if (_saved_entry != _effects.end()) {
   if (_saved_entry != _effects.end()) {
+    nassertv(_effects.find(this) == _saved_entry);
     _effects.erase(_saved_entry);
     _effects.erase(_saved_entry);
     _saved_entry = _effects.end();
     _saved_entry = _effects.end();
   }
   }
@@ -153,6 +154,7 @@ return_new(RenderEffect *effect) {
     // The effect was inserted; save the iterator and return the
     // The effect was inserted; save the iterator and return the
     // input effect.
     // input effect.
     effect->_saved_entry = result.first;
     effect->_saved_entry = result.first;
+    effect->ref();  // **** TEMPORARY HACK
     return pt_effect;
     return pt_effect;
   }
   }
 
 

+ 1 - 1
panda/src/pgraph/renderState.I

@@ -113,7 +113,7 @@ compare_to(const Attribute &other) const {
     return _type.get_index() - other._type.get_index();
     return _type.get_index() - other._type.get_index();
   }
   }
   if (_attrib != other._attrib) {
   if (_attrib != other._attrib) {
-    return _attrib - other._attrib;
+    return _attrib < other._attrib ? -1 : 1;
   }
   }
   return _override - other._override;
   return _override - other._override;
 }
 }

+ 21 - 11
panda/src/pgraph/renderState.cxx

@@ -27,10 +27,11 @@
 #include "indent.h"
 #include "indent.h"
 #include "compareTo.h"
 #include "compareTo.h"
 
 
-RenderState::States RenderState::_states;
+RenderState::States *RenderState::_states = NULL;
 CPT(RenderState) RenderState::_empty_state;
 CPT(RenderState) RenderState::_empty_state;
 TypeHandle RenderState::_type_handle;
 TypeHandle RenderState::_type_handle;
 
 
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::Constructor
 //     Function: RenderState::Constructor
 //       Access: Protected
 //       Access: Protected
@@ -40,7 +41,15 @@ TypeHandle RenderState::_type_handle;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 RenderState::
 RenderState::
 RenderState() {
 RenderState() {
-  _saved_entry = _states.end();
+  if (_states == (States *)NULL) {
+    // Make sure the global _states map is allocated.  This only has
+    // to be done once.  We could make this map static, but then we
+    // run into problems if anyone creates a RenderState object at
+    // static init time; it also seems to cause problems when the
+    // Panda shared library is unloaded at application exit time.
+    _states = new States;
+  }
+  _saved_entry = _states->end();
   _self_compose = (RenderState *)NULL;
   _self_compose = (RenderState *)NULL;
   _flags = 0;
   _flags = 0;
 }
 }
@@ -73,10 +82,10 @@ operator = (const RenderState &) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 RenderState::
 RenderState::
 ~RenderState() {
 ~RenderState() {
-  // Remove the deleted RenderState object from the global pool.
-  if (_saved_entry != _states.end()) {
-    _states.erase(_saved_entry);
-    _saved_entry = _states.end();
+  if (_saved_entry != _states->end()) {
+    nassertv(_states->find(this) == _saved_entry);
+    _states->erase(_saved_entry);
+    _saved_entry = _states->end();
   }
   }
 
 
   // Now make sure we clean up all other floating pointers to the
   // Now make sure we clean up all other floating pointers to the
@@ -725,20 +734,21 @@ return_new(RenderState *state) {
 
 
   // This should be a newly allocated pointer, not one that was used
   // This should be a newly allocated pointer, not one that was used
   // for anything else.
   // for anything else.
-  nassertr(state->_saved_entry == _states.end(), state);
+  nassertr(state->_saved_entry == _states->end(), state);
 
 
   // Save the state in a local PointerTo so that it will be freed at
   // Save the state in a local PointerTo so that it will be freed at
   // the end of this function if no one else uses it.
   // the end of this function if no one else uses it.
   CPT(RenderState) pt_state = state;
   CPT(RenderState) pt_state = state;
 
 
-  pair<States::iterator, bool> result = _states.insert(state);
+  pair<States::iterator, bool> result = _states->insert(state);
+
   if (result.second) {
   if (result.second) {
     // The state was inserted; save the iterator and return the
     // The state was inserted; save the iterator and return the
     // input state.
     // input state.
     state->_saved_entry = result.first;
     state->_saved_entry = result.first;
     return pt_state;
     return pt_state;
   }
   }
-
+  
   // The state was not inserted; there must be an equivalent one
   // The state was not inserted; there must be an equivalent one
   // already in the set.  Return that one.
   // already in the set.  Return that one.
   return *(result.first);
   return *(result.first);
@@ -976,8 +986,8 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) {
 
 
   // Now make sure the array is properly sorted.  (It won't
   // Now make sure the array is properly sorted.  (It won't
   // necessarily preserve its correct sort after being read from bam,
   // necessarily preserve its correct sort after being read from bam,
-  // because the sort is based on TypeHandle indices, which can change
-  // from session to session.)
+  // because the sort is based on TypeHandle indices and raw pointers,
+  // both of which can change from session to session.)
   _attributes.sort();
   _attributes.sort();
 
 
   return pi;
   return pi;

+ 1 - 1
panda/src/pgraph/renderState.h

@@ -106,7 +106,7 @@ private:
 
 
 private:
 private:
   typedef pset<const RenderState *, IndirectLess<RenderState> > States;
   typedef pset<const RenderState *, IndirectLess<RenderState> > States;
-  static States _states;
+  static States *_states;
   static CPT(RenderState) _empty_state;
   static CPT(RenderState) _empty_state;
 
 
   // This iterator records the entry corresponding to this RenderState
   // This iterator records the entry corresponding to this RenderState

+ 8 - 1
panda/src/pgraph/textureAttrib.cxx

@@ -98,7 +98,14 @@ int TextureAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
   const TextureAttrib *ta;
   const TextureAttrib *ta;
   DCAST_INTO_R(ta, other, 0);
   DCAST_INTO_R(ta, other, 0);
-  return (int)(_texture - ta->_texture);
+  
+  // Comparing pointers by subtraction is problematic.  Instead of
+  // doing this, we'll just depend on the built-in != and < operators
+  // for comparing pointers.
+  if (_texture != ta->_texture) {
+    return _texture < ta->_texture ? -1 : 1;
+  }
+  return 0;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 16 - 7
panda/src/pgraph/transformState.cxx

@@ -24,7 +24,7 @@
 #include "indent.h"
 #include "indent.h"
 #include "compareTo.h"
 #include "compareTo.h"
 
 
-TransformState::States TransformState::_states;
+TransformState::States *TransformState::_states = NULL;
 CPT(TransformState) TransformState::_identity_state;
 CPT(TransformState) TransformState::_identity_state;
 TypeHandle TransformState::_type_handle;
 TypeHandle TransformState::_type_handle;
 
 
@@ -37,7 +37,15 @@ TypeHandle TransformState::_type_handle;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 TransformState::
 TransformState::
 TransformState() {
 TransformState() {
-  _saved_entry = _states.end();
+  if (_states == (States *)NULL) {
+    // Make sure the global _states map is allocated.  This only has
+    // to be done once.  We could make this map static, but then we
+    // run into problems if anyone creates a RenderState object at
+    // static init time; it also seems to cause problems when the
+    // Panda shared library is unloaded at application exit time.
+    _states = new States;
+  }
+  _saved_entry = _states->end();
   _self_compose = (TransformState *)NULL;
   _self_compose = (TransformState *)NULL;
   _flags = F_is_identity | F_singular_known;
   _flags = F_is_identity | F_singular_known;
   _inv_mat = (LMatrix4f *)NULL;
   _inv_mat = (LMatrix4f *)NULL;
@@ -77,9 +85,10 @@ TransformState::
   }
   }
 
 
   // Remove the deleted TransformState object from the global pool.
   // Remove the deleted TransformState object from the global pool.
-  if (_saved_entry != _states.end()) {
-    _states.erase(_saved_entry);
-    _saved_entry = _states.end();
+  if (_saved_entry != _states->end()) {
+    nassertv(_states->find(this) == _saved_entry);
+    _states->erase(_saved_entry);
+    _saved_entry = _states->end();
   }
   }
 
 
   // Now make sure we clean up all other floating pointers to the
   // Now make sure we clean up all other floating pointers to the
@@ -540,13 +549,13 @@ return_new(TransformState *state) {
 
 
   // This should be a newly allocated pointer, not one that was used
   // This should be a newly allocated pointer, not one that was used
   // for anything else.
   // for anything else.
-  nassertr(state->_saved_entry == _states.end(), state);
+  nassertr(state->_saved_entry == _states->end(), state);
 
 
   // Save the state in a local PointerTo so that it will be freed at
   // Save the state in a local PointerTo so that it will be freed at
   // the end of this function if no one else uses it.
   // the end of this function if no one else uses it.
   CPT(TransformState) pt_state = state;
   CPT(TransformState) pt_state = state;
 
 
-  pair<States::iterator, bool> result = _states.insert(state);
+  pair<States::iterator, bool> result = _states->insert(state);
   if (result.second) {
   if (result.second) {
     // The state was inserted; save the iterator and return the
     // The state was inserted; save the iterator and return the
     // input state.
     // input state.

+ 1 - 1
panda/src/pgraph/transformState.h

@@ -109,7 +109,7 @@ private:
 
 
 private:
 private:
   typedef pset<const TransformState *, IndirectLess<TransformState> > States;
   typedef pset<const TransformState *, IndirectLess<TransformState> > States;
-  static States _states;
+  static States *_states;
   static CPT(TransformState) _identity_state;
   static CPT(TransformState) _identity_state;
 
 
   // This iterator records the entry corresponding to this TransformState
   // This iterator records the entry corresponding to this TransformState

+ 9 - 0
panda/src/pgui/qppgTop.cxx

@@ -20,6 +20,7 @@
 #include "pgItem.h"
 #include "pgItem.h"
 #include "pgMouseWatcherGroup.h"
 #include "pgMouseWatcherGroup.h"
 #include "pgCullTraverser.h"
 #include "pgCullTraverser.h"
+#include "cullBinAttrib.h"
 
 
 #include "omniBoundingVolume.h"
 #include "omniBoundingVolume.h"
 
 
@@ -40,6 +41,14 @@ qpPGTop(const string &name) :
   // culling.
   // culling.
   set_bound(OmniBoundingVolume());
   set_bound(OmniBoundingVolume());
   set_final(true);
   set_final(true);
+
+  // Also, screw state sorting.  By default, everything under PGTop
+  // will be unsorted: rendered in scene graph order.  This is closer
+  // to what the user wants anyway in a 2-d scene graph.
+
+  // This override of 1000 should really be a system constant
+  // somewhere.
+  set_attrib(CullBinAttrib::make("unsorted", 0), 1000);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 3 - 0
panda/src/text/config_text.cxx

@@ -81,10 +81,13 @@ init_libtext() {
   string text_encoding = config_text.GetString("text-encoding", "iso8859");
   string text_encoding = config_text.GetString("text-encoding", "iso8859");
   if (text_encoding == "iso8859") {
   if (text_encoding == "iso8859") {
     TextNode::_default_encoding = TextNode::E_iso8859;
     TextNode::_default_encoding = TextNode::E_iso8859;
+    qpTextNode::_default_encoding = qpTextNode::E_iso8859;
   } else if (text_encoding == "utf8") {
   } else if (text_encoding == "utf8") {
     TextNode::_default_encoding = TextNode::E_utf8;
     TextNode::_default_encoding = TextNode::E_utf8;
+    qpTextNode::_default_encoding = qpTextNode::E_utf8;
   } else if (text_encoding == "unicode") {
   } else if (text_encoding == "unicode") {
     TextNode::_default_encoding = TextNode::E_unicode;
     TextNode::_default_encoding = TextNode::E_unicode;
+    qpTextNode::_default_encoding = qpTextNode::E_unicode;
   } else {
   } else {
     text_cat.error()
     text_cat.error()
       << "Invalid text-encoding: " << text_encoding << "\n";
       << "Invalid text-encoding: " << text_encoding << "\n";