Jelajahi Sumber

64-bit collision traverser; add CollisionNode::set_collider_sort()

David Rose 19 tahun lalu
induk
melakukan
05b0adcbb5

+ 5 - 16
panda/src/collide/collisionLevelState.I

@@ -25,7 +25,7 @@
 INLINE CollisionLevelState::
 CollisionLevelState(const NodePath &node_path) :
   _node_path(node_path),
-  _current(0),
+  _current(CollisionLevelState::CurrentMask::all_off()),
   _include_mask(CollideMask::all_on())
 {
 }
@@ -85,7 +85,7 @@ operator = (const CollisionLevelState &copy) {
 ////////////////////////////////////////////////////////////////////
 INLINE int CollisionLevelState::
 get_max_colliders() {
-  return sizeof(CurrentMask) * 8;
+  return CurrentMask::get_max_num_bits();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -129,7 +129,7 @@ get_num_colliders() const {
 INLINE bool CollisionLevelState::
 has_collider(int n) const {
   nassertr(n >= 0 && n < (int)_colliders.size(), false);
-  return (_current & get_mask(n)) != 0;
+  return (_current.get_bit(n));
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -139,7 +139,7 @@ has_collider(int n) const {
 ////////////////////////////////////////////////////////////////////
 INLINE bool CollisionLevelState::
 has_any_collider() const {
-  return _current != 0;
+  return !_current.is_zero();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -233,7 +233,7 @@ omit_collider(int n) {
   nassertv(n >= 0 && n < (int)_colliders.size());
   nassertv(has_collider(n));
 
-  _current &= ~get_mask(n);
+  _current.clear_bit(n);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -268,14 +268,3 @@ INLINE CollideMask CollisionLevelState::
 get_include_mask() const {
   return _include_mask;
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: CollisionLevelState::get_mask
-//       Access: Private
-//  Description: Returns a single bit associated with the nth
-//               collider.
-////////////////////////////////////////////////////////////////////
-INLINE CollisionLevelState::CurrentMask CollisionLevelState::
-get_mask(int n) const {
-  return ((CurrentMask)1) << n;
-}

+ 7 - 8
panda/src/collide/collisionLevelState.cxx

@@ -33,7 +33,7 @@ clear() {
   _colliders.clear();
   _local_bounds.clear();
   _parent_bounds.clear();
-  _current = 0;
+  _current.clear();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -44,7 +44,8 @@ clear() {
 ////////////////////////////////////////////////////////////////////
 void CollisionLevelState::
 reserve(int num_colliders) {
-  nassertv(num_colliders <= get_max_colliders());
+  nassertv(!CurrentMask::has_max_num_bits() ||
+           num_colliders <= CurrentMask::get_max_num_bits());
   _colliders.reserve(num_colliders);
   _local_bounds.reserve(num_colliders);
 }
@@ -58,7 +59,8 @@ reserve(int num_colliders) {
 void CollisionLevelState::
 prepare_collider(const ColliderDef &def, const NodePath &root) {
   int index = (int)_colliders.size();
-  nassertv(index < get_max_colliders());
+  nassertv(!CurrentMask::has_max_num_bits() ||
+           index <= CurrentMask::get_max_num_bits());
   _colliders.push_back(def);
 
   CollisionSolid *collider = def._collider;
@@ -93,11 +95,9 @@ prepare_collider(const ColliderDef &def, const NodePath &root) {
     _local_bounds.push_back(gbv);
   }
   
-  CurrentMask mask = get_mask(index); 
-  _current |= mask;
+  _current.set_bit(index);
 
   _parent_bounds = _local_bounds;
-  nassertv(mask != 0);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -137,8 +137,7 @@ any_in_bounds() {
         // no collide bits in common between our collider and this
         // node.
         CollideMask from_mask = cnode->get_from_collide_mask() & _include_mask;
-        if (cnode->get_collide_geom() ||
-            (from_mask & node()->get_net_collide_mask()) != 0) {
+        if (!(from_mask & node()->get_net_collide_mask()).is_zero()) {
           // There are bits in common, so go ahead and try the
           // bounding volume.
           const GeometricBoundingVolume *col_gbv =

+ 2 - 3
panda/src/collide/collisionLevelState.h

@@ -29,6 +29,7 @@
 #include "pointerTo.h"
 #include "plist.h"
 #include "pStatCollector.h"
+#include "bitMask.h"
 
 class CollisionSolid;
 class CollisionNode;
@@ -87,9 +88,7 @@ private:
   // current node.  Don't confuse it with CollideMask, which is a set
   // of user-defined bits that specify which CollisionSolids may
   // possibly intersect with each other.
-  typedef unsigned int CurrentMask;
-
-  INLINE CurrentMask get_mask(int n) const;
+  typedef BitMaskNative CurrentMask;
 
   WorkingNodePath _node_path;
 

+ 33 - 0
panda/src/collide/collisionNode.I

@@ -144,6 +144,39 @@ add_solid(CollisionSolid *solid) {
   return _solids.size() - 1;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CollisionNode::get_collider_sort
+//       Access: Published
+//  Description: Returns the collider_sort value that has been set for
+//               this particular node.  See set_collider_sort().
+////////////////////////////////////////////////////////////////////
+INLINE int CollisionNode::
+get_collider_sort() const {
+  return _collider_sort;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CollisionNode::set_collider_sort
+//       Access: Published
+//  Description: Sets a particular collider_sort value on this node.
+//               This controls the order in which colliders (that is,
+//               "from nodes") are grouped together for the collision
+//               traversal.
+//
+//               If there are 32 or fewer colliders added to any
+//               particular CollisionTraverser, then this value has no
+//               meaning.  It is only useful if there are many
+//               colliders, which may force the CollisionTraverser to
+//               make multiple passes through the data; in that case,
+//               it may be a useful optimization to group colliders
+//               that have similar bounding volumes together (by
+//               giving them similar sort values).
+////////////////////////////////////////////////////////////////////
+INLINE void CollisionNode::
+set_collider_sort(int sort) {
+  _collider_sort = sort;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionNode::get_default_collide_mask
 //       Access: Published, Static

+ 1 - 57
panda/src/collide/collisionNode.cxx

@@ -44,7 +44,7 @@ CollisionNode::
 CollisionNode(const string &name) :
   PandaNode(name),
   _from_collide_mask(get_default_collide_mask()),
-  _collide_geom(false)
+  _collider_sort(0)
 {
   set_cull_callback();
 
@@ -300,62 +300,6 @@ output(ostream &out) const {
 void CollisionNode::
 set_from_collide_mask(CollideMask mask) {
   _from_collide_mask = mask;
-
-  if (_collide_geom) {
-    _from_collide_mask |= GeomNode::get_default_collide_mask();
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CollisionNode::set_collide_geom
-//       Access: Published
-//  Description: Sets the state of the "collide geom" flag for this
-//               CollisionNode.  
-//
-//               This flag is now deprecated, now that GeomNodes have
-//               their own into_collide_mask, just like CollisionNodes
-//               do.  Instead of using set_collide_geom(), you should
-//               use the from_collide_mask to control which GeomNodes
-//               each CollisionNode will intersect with.  
-//
-//               In particular, you may be interested in setting
-//               from_collide_mask to the value returned by
-//               GeomNode::get_default_collide_mask(), which is the
-//               default into_collide_mask that all GeomNodes will be
-//               given (unless they are explicitly given some other
-//               mask).
-////////////////////////////////////////////////////////////////////
-void CollisionNode::
-set_collide_geom(bool flag) {
-  // Only repeat this warning every five seconds or so--no need to be
-  // completely spammy.
-  static double last_warning = -10.0;
-  double now = ClockObject::get_global_clock()->get_frame_time();
-  double elapsed = now - last_warning;
-  if (elapsed > 5.0) {
-    last_warning = now;
-    collide_cat.warning()
-      << "Using deprecated set_collide_geom().  Replace this with an appropriate call to set_from_collide_mask(), e.g. set_from_collide_mask(GeomNode::get_default_collide_mask()).\n";
-  }
-    
-  _collide_geom = flag;
-
-  if (_collide_geom) {
-    _from_collide_mask |= GeomNode::get_default_collide_mask();
-  } else {
-    _from_collide_mask &= ~GeomNode::get_default_collide_mask();
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CollisionNode::get_collide_geom
-//       Access: Published
-//  Description: Returns the current state of the collide_geom flag.
-//               See set_collide_geom().
-////////////////////////////////////////////////////////////////////
-bool CollisionNode::
-get_collide_geom() const {
-  return _collide_geom;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 5 - 5
panda/src/collide/collisionNode.h

@@ -61,9 +61,6 @@ PUBLISHED:
   INLINE CollideMask get_from_collide_mask() const;
   INLINE CollideMask get_into_collide_mask() const;
 
-  void set_collide_geom(bool flag);
-  bool get_collide_geom() const;
-
   INLINE void clear_solids();
   INLINE int get_num_solids() const;
   INLINE CollisionSolid *get_solid(int n) const;
@@ -71,6 +68,9 @@ PUBLISHED:
   INLINE void remove_solid(int n);
   INLINE int add_solid(CollisionSolid *solid);
 
+  INLINE int get_collider_sort() const;
+  INLINE void set_collider_sort(int sort);
+
   INLINE static CollideMask get_default_collide_mask();
 
 protected:
@@ -83,11 +83,11 @@ private:
   // traversal will take place in App only.  Perhaps we will revisit
   // this later.
   CollideMask _from_collide_mask;
-  bool _collide_geom;
+  int _collider_sort;
 
   typedef pvector< PT(CollisionSolid) > Solids;
   Solids _solids;
-
+  
 public:
   static void register_with_read_factory();
   virtual void write_datagram(BamWriter *manager, Datagram &dg);

+ 15 - 3
panda/src/collide/collisionTraverser.cxx

@@ -40,12 +40,23 @@
 #include "pStatTimer.h"
 #include "indent.h"
 
+#include <algorithm>
+
 PStatCollector CollisionTraverser::_collisions_pcollector("App:Collisions");
 
 PStatCollector CollisionTraverser::_cnode_volume_pcollector("Collision Volumes:CollisionNode");
 PStatCollector CollisionTraverser::_gnode_volume_pcollector("Collision Volumes:GeomNode");
 PStatCollector CollisionTraverser::_geom_volume_pcollector("Collision Volumes:Geom");
 
+// This function object class is used in prepare_colliders(), below.
+class SortByColliderSort {
+public:
+  inline bool operator () (const CollisionTraverser::OrderedColliderDef &a,
+                           const CollisionTraverser::OrderedColliderDef &b) const {
+    return DCAST(CollisionNode, a._node_path.node())->get_collider_sort() < DCAST(CollisionNode, b._node_path.node())->get_collider_sort();
+  }
+};
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionTraverser::Constructor
 //       Access: Published
@@ -466,10 +477,11 @@ prepare_colliders(CollisionTraverser::LevelStates &level_states,
   // correct.
   level_state.reserve(min(num_colliders, max_colliders));
 
+  OrderedColliders sorted = _ordered_colliders;
+  sort(sorted.begin(), sorted.end(), SortByColliderSort());
+
   OrderedColliders::iterator oci;
-  for (oci = _ordered_colliders.begin(); 
-       oci != _ordered_colliders.end(); 
-       ++oci) {
+  for (oci = sorted.begin(); oci != sorted.end(); ++oci) {
     NodePath cnode_path = (*oci)._node_path;
 
     if (!cnode_path.is_same_graph(root)) {

+ 2 - 0
panda/src/collide/collisionTraverser.h

@@ -142,6 +142,8 @@ private:
   // pstats category for actual collision detection (vs. bounding heirarchy collision detection)
   typedef pvector<PStatCollector> SolidCollideCollectors;
   SolidCollideCollectors _solid_collide_collectors;
+
+  friend class SortByColliderSort;
 };
 
 INLINE ostream &operator << (ostream &out, const CollisionTraverser &trav) {

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

@@ -45,7 +45,7 @@ class DatagramIterator;
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA BitArray {
 public:
-  typedef BitMask32 MaskType;
+  typedef BitMaskNative MaskType;
   typedef MaskType::WordType WordType;
   enum { num_bits_per_word = MaskType::num_bits };
 

+ 9 - 0
panda/src/putil/bitMask.h

@@ -144,6 +144,15 @@ INLINE ostream &operator << (ostream &out, const BitMask<WType, nbits> &bitmask)
 EXPORT_TEMPLATE_CLASS(EXPCL_PANDA, EXPTP_PANDA, BITMASK32_DEF);
 
 typedef BitMask<PN_uint32, 32> BitMask32;
+typedef BitMask<PN_uint64, 64> BitMask64;
+
+#if NATIVE_WORDSIZE == 32
+typedef BitMask32 BitMaskNative;
+#elif NATIVE_WORDSIZE == 64
+typedef BitMask64 BitMaskNative;
+#else
+#error No definition for NATIVE_WORDSIZE--should be defined in dtoolbase.h.
+#endif  // NATIVE_WORDSIZE
 
 // Tell GCC that we'll take care of the instantiation explicitly here.
 #ifdef __GNUC__