Browse Source

collide: First pass at reducing memory overhead of CollisionBox

This is just the low-hanging fruit, there are a lot more gains to be realized.
rdb 3 years ago
parent
commit
8cdac14db3
3 changed files with 64 additions and 126 deletions
  1. 4 36
      panda/src/collide/collisionBox.I
  2. 53 80
      panda/src/collide/collisionBox.cxx
  3. 7 10
      panda/src/collide/collisionBox.h

+ 4 - 36
panda/src/collide/collisionBox.I

@@ -17,11 +17,10 @@
  */
 INLINE CollisionBox::
 CollisionBox(const LPoint3 &center, PN_stdfloat x, PN_stdfloat y, PN_stdfloat z) :
-  _center(center), _x(x), _y(y), _z(z)
+  _center(center)
 {
-  _min = LPoint3(_center.get_x() - _x, _center.get_y() - _y, _center.get_z() - _z);
-  _max = LPoint3(_center.get_x() + _x, _center.get_y() + _y, _center.get_z() + _z);
-  _radius = sqrt(_x*_x + _y*_y + _z*_z);
+  _min = LPoint3(_center.get_x() - x, _center.get_y() - y, _center.get_z() - z);
+  _max = LPoint3(_center.get_x() + x, _center.get_y() + y, _center.get_z() + z);
   for(int v = 0; v < 8; v++)
     _vertex[v] = get_point_aabb(v);
   for(int p = 0; p < 6; p++)
@@ -37,10 +36,6 @@ CollisionBox(const LPoint3 &min, const LPoint3 &max) :
   _min(min), _max(max)
 {
   _center = (_min + _max) / 2;
-  _x = _center.get_x() - _min.get_x();
-  _y = _center.get_y() - _min.get_y();
-  _z = _center.get_z() - _min.get_z();
-  _radius = sqrt(_x*_x + _y*_y + _z*_z);
   for(int v = 0; v < 8; v++)
     _vertex[v] = get_point_aabb(v);
   for(int p = 0; p < 6; p++)
@@ -63,11 +58,7 @@ CollisionBox(const CollisionBox &copy) :
   CollisionSolid(copy),
   _center(copy._center),
   _min(copy._min),
-  _max(copy._max),
-  _x(copy._x ),
-  _y(copy._y ),
-  _z(copy._z ),
-  _radius(copy._radius )
+  _max(copy._max)
 {
   for(int v = 0; v < 8; v++)
     _vertex[v] = copy._vertex[v];
@@ -152,7 +143,6 @@ get_point(int n) const {
   return _vertex[n];
 }
 
-
 /**
  * Returns the nth vertex of the Axis Aligned Bounding Box.
  */
@@ -243,20 +233,6 @@ calc_to_3d_mat(LMatrix4 &to_3d_mat,int plane) const {
   to_3d_mat.set_row(3, get_plane(plane).get_point());
 }
 
-/**
- * Fills the indicated matrix with the appropriate rotation transform to move
- * points from the 2-d plane into the 3-d (X, 0, Z) plane.
- *
- * This is essentially similar to calc_to_3d_mat, except that the matrix is
- * rederived from whatever is stored in _to_2d_mat, guaranteeing that it will
- * match whatever algorithm produced that one, even if it was produced on a
- * different machine with different numerical precision.
- */
-INLINE void CollisionBox::
-rederive_to_3d_mat(LMatrix4 &to_3d_mat, int plane) const {
-  to_3d_mat.invert_from(_to_2d_mat[plane]);
-}
-
 /**
  * Extrude the indicated point in the polygon's 2-d definition space back into
  * 3-d coordinates.
@@ -295,11 +271,3 @@ operator = (const CollisionBox::PointDef &copy) {
   _p = copy._p;
   _v = copy._v;
 }
-
-/**
- * returns the points that form the nth plane
- */
-INLINE CollisionBox::Points CollisionBox::
-get_plane_points(int n) {
-  return _points[n];
-}

+ 53 - 80
panda/src/collide/collisionBox.cxx

@@ -66,14 +66,11 @@ make_copy() {
  * Compute parameters for each of the box's sides
  */
 void CollisionBox::
-setup_box(){
-  for(int plane = 0; plane < 6; plane++) {
-    LPoint3 array[4];
-    array[0] = get_point(plane_def[plane][0]);
-    array[1] = get_point(plane_def[plane][1]);
-    array[2] = get_point(plane_def[plane][2]);
-    array[3] = get_point(plane_def[plane][3]);
-    setup_points(array, array+4, plane);
+setup_box() {
+  assert(sizeof(_points) / sizeof(_points[0]) == 6);
+  assert(sizeof(_points[0]) / sizeof(_points[0][0]) == 4);
+  for (int plane = 0; plane < 6; plane++) {
+    setup_points(plane);
   }
 }
 
@@ -81,11 +78,8 @@ setup_box(){
  * Computes the plane and 2d projection of points that make up this side.
  */
 void CollisionBox::
-setup_points(const LPoint3 *begin, const LPoint3 *end, int plane) {
-  int num_points = end - begin;
-  nassertv(num_points >= 3);
-
-  _points[plane].clear();
+setup_points(int plane) {
+  PointDef *points = _points[plane];
 
   // Construct a matrix that rotates the points from the (X,0,Z) plane into
   // the 3-d plane.
@@ -96,32 +90,15 @@ setup_points(const LPoint3 *begin, const LPoint3 *end, int plane) {
   _to_2d_mat[plane].invert_from(to_3d_mat);
 
   // Now project all of the points onto the 2-d plane.
-
-  const LPoint3 *pi;
-  for (pi = begin; pi != end; ++pi) {
-    LPoint3 point = (*pi) * _to_2d_mat[plane];
-    _points[plane].push_back(PointDef(point[0], point[2]));
+  for (size_t i = 0; i < 4; ++i) {
+    LPoint3 point = get_point(plane_def[plane][i]) * _to_2d_mat[plane];
+    points[i] = PointDef(point[0], point[2]);
   }
 
-  nassertv(_points[plane].size() >= 3);
-
-#ifndef NDEBUG
-  /*
-  // Now make sure the points define a convex polygon.
-  if (is_concave()) {
-  collide_cat.error() << "Invalid concave CollisionPolygon defined:\n";
-  const LPoint3 *pi;
-  for (pi = begin; pi != end; ++pi) {
-  collide_cat.error(false) << "  " << (*pi) << "\n";
-  }
-  collide_cat.error(false)
-  << "  normal " << normal << " with length " << normal.length() << "\n";
-  _points.clear();
-  }
-  */
-#endif
-
-  compute_vectors(_points[plane]);
+  for (size_t i = 0; i < 4; i++) {
+    points[i]._v = points[(i + 1) % 4]._p - points[i]._p;
+    points[i]._v.normalize();
+  }
 }
 
 /**
@@ -146,10 +123,6 @@ xform(const LMatrix4 &mat) {
   for(int p = 0; p < 6 ; p++) {
     _planes[p] = set_plane(p);
   }
-  _x = _vertex[0].get_x() - _center.get_x();
-  _y = _vertex[0].get_y() - _center.get_y();
-  _z = _vertex[0].get_z() - _center.get_z();
-  _radius = sqrt(_x * _x + _y * _y + _z * _z);
   setup_box();
   mark_viz_stale();
   mark_internal_bounds_stale();
@@ -196,7 +169,11 @@ output(std::ostream &out) const {
  */
 PT(BoundingVolume) CollisionBox::
 compute_internal_bounds() const {
-  return new BoundingSphere(_center, _radius);
+  PN_stdfloat x = _vertex[0].get_x() - _center.get_x();
+  PN_stdfloat y = _vertex[0].get_y() - _center.get_y();
+  PN_stdfloat z = _vertex[0].get_z() - _center.get_z();
+  PN_stdfloat radius = sqrt(x * x + y * y + z * z);
+  return new BoundingSphere(_center, radius);
 }
 
 /**
@@ -233,10 +210,8 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
   LVector3 normal;
 
   for(ip = 0, intersect = false; ip < 6 && !intersect; ip++) {
-    plane = get_plane( ip );
-    if (_points[ip].size() < 3) {
-      continue;
-    }
+    plane = get_plane(ip);
+
     if (wrt_prev_space != wrt_space) {
       // If we have a delta between the previous position and the current
       // position, we use that to determine some more properties of the
@@ -322,17 +297,17 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
       Points new_points;
       if (apply_clip_plane(new_points, cpa, entry.get_into_node_path().get_net_transform(),ip)) {
         // All points are behind the clip plane; just do the default test.
-        edge_dist = dist_to_polygon(p, _points[ip]);
+        edge_dist = dist_to_polygon(p, _points[ip], 4);
       } else if (new_points.empty()) {
         // The polygon is completely clipped.
         continue;
       } else {
         // Test against the clipped polygon.
-        edge_dist = dist_to_polygon(p, new_points);
+        edge_dist = dist_to_polygon(p, new_points.data(), new_points.size());
       }
     } else {
       // No clip plane is in effect.  Do the default test.
-      edge_dist = dist_to_polygon(p, _points[ip]);
+      edge_dist = dist_to_polygon(p, _points[ip], 4);
     }
 
     max_dist = from_radius;
@@ -1129,13 +1104,13 @@ apply_clip_plane(CollisionBox::Points &new_points,
       LPlane plane = plane_node->get_plane() * new_transform->get_mat();
       if (first_plane) {
         first_plane = false;
-        if (!clip_polygon(new_points, _points[plane_no], plane, plane_no)) {
+        if (!clip_polygon(new_points, _points[plane_no], 4, plane, plane_no)) {
           all_in = false;
         }
       } else {
         Points last_points;
         last_points.swap(new_points);
-        if (!clip_polygon(new_points, last_points, plane, plane_no)) {
+        if (!clip_polygon(new_points, last_points.data(), last_points.size(), plane, plane_no)) {
           all_in = false;
         }
       }
@@ -1158,10 +1133,10 @@ apply_clip_plane(CollisionBox::Points &new_points,
  */
 bool CollisionBox::
 clip_polygon(CollisionBox::Points &new_points,
-             const CollisionBox::Points &source_points,
+             const PointDef *source_points, size_t num_source_points,
              const LPlane &plane, int plane_no) const {
   new_points.clear();
-  if (source_points.empty()) {
+  if (num_source_points == 0) {
     return true;
   }
 
@@ -1173,7 +1148,7 @@ clip_polygon(CollisionBox::Points &new_points,
     if (plane.dist_to_plane(get_plane(plane_no).get_point()) < 0.0) {
       // A point within the polygon is behind the clipping plane: the polygon
       // is all in.
-      new_points = source_points;
+      new_points.insert(new_points.end(), source_points, source_points + num_source_points);
       return true;
     }
     return false;
@@ -1194,14 +1169,13 @@ clip_polygon(CollisionBox::Points &new_points,
   // We might increase the number of vertices by as many as 1, if the plane
   // clips off exactly one corner.  (We might also decrease the number of
   // vertices, or keep them the same number.)
-  new_points.reserve(source_points.size() + 1);
+  new_points.reserve(num_source_points + 1);
 
-  LPoint2 last_point = source_points.back()._p;
+  LPoint2 last_point = source_points[num_source_points - 1]._p;
   bool last_is_in = !is_right(last_point - from2d, delta2d);
   bool all_in = last_is_in;
-  Points::const_iterator pi;
-  for (pi = source_points.begin(); pi != source_points.end(); ++pi) {
-    const LPoint2 &this_point = (*pi)._p;
+  for (size_t pi = 0; pi < num_source_points; ++pi) {
+    const LPoint2 &this_point = source_points[pi]._p;
     bool this_is_in = !is_right(this_point - from2d, delta2d);
 
     // There appears to be a compiler bug in gcc 4.0: we need to extract this
@@ -1234,15 +1208,13 @@ clip_polygon(CollisionBox::Points &new_points,
   return all_in;
 }
 
-
 /**
  * Returns the linear distance from the 2-d point to the nearest part of the
  * polygon defined by the points vector.  The result is negative if the point
  * is within the polygon.
  */
 PN_stdfloat CollisionBox::
-dist_to_polygon(const LPoint2 &p, const CollisionBox::Points &points) const {
-
+dist_to_polygon(const LPoint2 &p, const PointDef *points, size_t num_points) const {
   // We know that that the polygon is convex and is defined with the points in
   // counterclockwise order.  Therefore, we simply compare the signed distance
   // to each line segment; we ignore any negative values, and take the minimum
@@ -1254,10 +1226,9 @@ dist_to_polygon(const LPoint2 &p, const CollisionBox::Points &points) const {
   bool got_dist = false;
   PN_stdfloat best_dist = -1.0f;
 
-  size_t num_points = points.size();
   for (size_t i = 0; i < num_points - 1; ++i) {
     PN_stdfloat d = dist_to_line_segment(p, points[i]._p, points[i + 1]._p,
-                                   points[i]._v);
+                                         points[i]._v);
     if (d >= 0.0f) {
       if (!got_dist || d < best_dist) {
         best_dist = d;
@@ -1267,7 +1238,7 @@ dist_to_polygon(const LPoint2 &p, const CollisionBox::Points &points) const {
   }
 
   PN_stdfloat d = dist_to_line_segment(p, points[num_points - 1]._p, points[0]._p,
-                                 points[num_points - 1]._v);
+                                       points[num_points - 1]._v);
   if (d >= 0.0f) {
     if (!got_dist || d < best_dist) {
       best_dist = d;
@@ -1450,10 +1421,14 @@ write_datagram(BamWriter *manager, Datagram &me) {
   for(int i=0; i < 8; i++) {
     _vertex[i].write_datagram(me);
   }
-  me.add_stdfloat(_radius);
-  me.add_stdfloat(_x);
-  me.add_stdfloat(_y);
-  me.add_stdfloat(_z);
+  PN_stdfloat x = _vertex[0].get_x() - _center.get_x();
+  PN_stdfloat y = _vertex[0].get_y() - _center.get_y();
+  PN_stdfloat z = _vertex[0].get_z() - _center.get_z();
+  PN_stdfloat radius = sqrt(x * x + y * y + z * z);
+  me.add_stdfloat(radius);
+  me.add_stdfloat(x);
+  me.add_stdfloat(y);
+  me.add_stdfloat(z);
   for(int i=0; i < 6; i++) {
     _planes[i].write_datagram(me);
   }
@@ -1461,8 +1436,8 @@ write_datagram(BamWriter *manager, Datagram &me) {
     _to_2d_mat[i].write_datagram(me);
   }
   for(int i=0; i < 6; i++) {
-    me.add_uint16(_points[i].size());
-    for (size_t j = 0; j < _points[i].size(); j++) {
+    me.add_uint16(4);
+    for (size_t j = 0; j < 4; j++) {
       _points[i][j]._p.write_datagram(me);
       _points[i][j]._v.write_datagram(me);
     }
@@ -1497,10 +1472,10 @@ fillin(DatagramIterator& scan, BamReader* manager) {
   for(int i=0; i < 8; i++) {
     _vertex[i].read_datagram(scan);
   }
-  _radius = scan.get_stdfloat();
-  _x = scan.get_stdfloat();
-  _y = scan.get_stdfloat();
-  _z = scan.get_stdfloat();
+  scan.get_stdfloat();
+  scan.get_stdfloat();
+  scan.get_stdfloat();
+  scan.get_stdfloat();
   for(int i=0; i < 6; i++) {
     _planes[i].read_datagram(scan);
   }
@@ -1509,12 +1484,10 @@ fillin(DatagramIterator& scan, BamReader* manager) {
   }
   for(int i=0; i < 6; i++) {
     size_t size = scan.get_uint16();
+    nassertv(size == 4);
     for (size_t j = 0; j < size; j++) {
-      LPoint2 p;
-      LVector2 v;
-      p.read_datagram(scan);
-      v.read_datagram(scan);
-      _points[i].push_back(PointDef(p, v));
+      _points[i][j]._p.read_datagram(scan);
+      _points[i][j]._v.read_datagram(scan);
     }
   }
 }

+ 7 - 10
panda/src/collide/collisionBox.h

@@ -99,7 +99,6 @@ private:
   LPoint3 _center;
   LPoint3 _min;
   LPoint3 _max;
-  PN_stdfloat _x, _y, _z, _radius;
   LPoint3 _vertex[8]; // Each of the Eight Vertices of the Box
   LPlane _planes[6]; //Points to each of the six sides of the Box
 
@@ -119,6 +118,7 @@ private:
 public:
   class PointDef {
   public:
+    PointDef() = default;
     INLINE PointDef(const LPoint2 &p, const LVector2 &v);
     INLINE PointDef(PN_stdfloat x, PN_stdfloat y);
     INLINE PointDef(const PointDef &copy);
@@ -134,25 +134,22 @@ public:
                     const Points &points) const;
 
   bool point_is_inside(const LPoint2 &p, const Points &points) const;
-  PN_stdfloat dist_to_polygon(const LPoint2 &p, const Points &points) const;
+  PN_stdfloat dist_to_polygon(const LPoint2 &p, const PointDef *points, size_t num_points) const;
 
-  void setup_points(const LPoint3 *begin, const LPoint3 *end, int plane);
+  void setup_points(int plane);
   INLINE LPoint2 to_2d(const LVecBase3 &point3d, int plane) const;
   INLINE void calc_to_3d_mat(LMatrix4 &to_3d_mat, int plane) const;
-  INLINE void rederive_to_3d_mat(LMatrix4 &to_3d_mat, int plane) const;
   INLINE static LPoint3 to_3d(const LVecBase2 &point2d, const LMatrix4 &to_3d_mat);
-  bool clip_polygon(Points &new_points, const Points &source_points,
-                    const LPlane &plane,int plane_no) const;
+  bool clip_polygon(Points &new_points, const PointDef *source_points,
+                    size_t num_source_points, const LPlane &plane,
+                    int plane_no) const;
   bool apply_clip_plane(Points &new_points, const ClipPlaneAttrib *cpa,
                         const TransformState *net_transform, int plane_no) const;
 
 private:
-  Points _points[6]; // one set of points for each of the six planes that make up the box
+  PointDef _points[6][4]; // one set of points for each of the six planes that make up the box
   LMatrix4 _to_2d_mat[6];
 
-public:
-  INLINE Points get_plane_points( int n );
-
 public:
   static void register_with_read_factory();
   virtual void write_datagram(BamWriter *manager, Datagram &me);