From 8cdac14db3bf803b59fed167f1480a3a34826089 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 2 Mar 2022 14:38:02 +0100 Subject: [PATCH] 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. --- panda/src/collide/collisionBox.I | 40 +-------- panda/src/collide/collisionBox.cxx | 131 ++++++++++++----------------- panda/src/collide/collisionBox.h | 17 ++-- 3 files changed, 63 insertions(+), 125 deletions(-) diff --git a/panda/src/collide/collisionBox.I b/panda/src/collide/collisionBox.I index 62c58cbceb..86473473cf 100644 --- a/panda/src/collide/collisionBox.I +++ b/panda/src/collide/collisionBox.I @@ -17,11 +17,10 @@ */ INLINE CollisionBox:: CollisionBox(const LPoint3 ¢er, 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 ©) : 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 ©) { _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]; -} diff --git a/panda/src/collide/collisionBox.cxx b/panda/src/collide/collisionBox.cxx index 278f8516ff..cb1d9a3c92 100644 --- a/panda/src/collide/collisionBox.cxx +++ b/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"; + for (size_t i = 0; i < 4; i++) { + points[i]._v = points[(i + 1) % 4]._p - points[i]._p; + points[i]._v.normalize(); } - collide_cat.error(false) - << " normal " << normal << " with length " << normal.length() << "\n"; - _points.clear(); - } - */ -#endif - - compute_vectors(_points[plane]); } /** @@ -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); } } } diff --git a/panda/src/collide/collisionBox.h b/panda/src/collide/collisionBox.h index 4bf96f0212..69a0e13889 100644 --- a/panda/src/collide/collisionBox.h +++ b/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 ©); @@ -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);