From aa5de2fee9886ca4a175e3124257bbc7acc60f53 Mon Sep 17 00:00:00 2001 From: Garux Date: Wed, 11 Aug 2021 18:18:38 +0300 Subject: [PATCH] wrap winding_next logic prevent crash in AddWindingToConvexHull() --- tools/quake3/common/polylib.cpp | 41 +++++++++++++++++---------------- tools/quake3/common/polylib.h | 9 ++++++++ tools/quake3/q3map2/brush.cpp | 8 +++---- tools/quake3/q3map2/map.cpp | 2 +- tools/quake3/q3map2/surface.cpp | 8 +------ 5 files changed, 35 insertions(+), 33 deletions(-) diff --git a/tools/quake3/common/polylib.cpp b/tools/quake3/common/polylib.cpp index 30d0078b..5ccd9d4b 100644 --- a/tools/quake3/common/polylib.cpp +++ b/tools/quake3/common/polylib.cpp @@ -55,14 +55,13 @@ winding_t AllocWinding( int points ){ ============ */ void RemoveColinearPoints( winding_t& w ){ - winding_t p; - p.reserve( w.size() ); + winding_t p = AllocWinding( w.size() ); - for ( size_t i = 0 ; i < w.size() ; i++ ) + for ( size_t i = 0; i < w.size(); i++ ) { - const size_t j = ( i + 1 ) % w.size(); - const size_t k = ( i + w.size() - 1 ) % w.size(); - if ( vector3_dot( VectorNormalized( w[j] - w[i] ), VectorNormalized( w[j] - w[k] ) ) < 0.999 ) { + const size_t j = winding_next( w, i ); + const size_t k = winding_next( w, j ); + if ( vector3_dot( VectorNormalized( w[k] - w[j] ), VectorNormalized( w[k] - w[i] ) ) < 0.999 ) { p.push_back( w[i] ); } } @@ -377,7 +376,7 @@ std::pair ClipWindingEpsilonStrict( const winding_t& in } // generate a split point - const Vector3& p2 = in[( i + 1 ) % in.size()]; + const Vector3& p2 = in[winding_next( in, i )]; const double dot = dists[i] / ( dists[i] - dists[i + 1] ); Vector3 mid; for ( j = 0; j < 3; j++ ) @@ -586,8 +585,7 @@ void ChopWindingInPlace( winding_t& inout, const Plane3f& plane, float epsilon ) } - winding_t f; - f.reserve( in.size() + 4 ); // cant use counts[0]+2 because of fp grouping errors + winding_t f = AllocWinding( in.size() + 4 ); // cant use counts[0]+2 because of fp grouping errors for ( i = 0; i < in.size(); i++ ) { @@ -607,7 +605,7 @@ void ChopWindingInPlace( winding_t& inout, const Plane3f& plane, float epsilon ) } // generate a split point - const Vector3& p2 = in[( i + 1 ) % in.size()]; + const Vector3& p2 = in[winding_next( in, i )]; const double dot = dists[i] / ( dists[i] - dists[i + 1] ); Vector3 mid; @@ -668,7 +666,7 @@ void CheckWinding( const winding_t& w ){ } // check the edge isnt degenerate - const Vector3& p2 = w[( i + 1 == w.size() )? 0 : i + 1]; + const Vector3& p2 = w[winding_next( w, i )]; const Vector3 dir = p2 - p1; if ( vector3_length( dir ) < ON_EPSILON ) { @@ -750,16 +748,19 @@ void AddWindingToConvexHull( const winding_t& w, winding_t& hull, const Vecto hull = w; return; } + if( hull.size() > MAX_HULL_POINTS ) + Error( "MAX_HULL_POINTS" ); numHullPoints = hull.size(); - memcpy( hullPoints, hull.data(), numHullPoints * sizeof( Vector3 ) ); + memcpy( hullPoints, hull.data(), numHullPoints * sizeof( *hullPoints ) ); for ( const Vector3 &p : w ) { + const auto wrap = [numHullPoints]( int id ){ + return id >= numHullPoints? id - numHullPoints : id; + }; // calculate hull side vectors for ( j = 0; j < numHullPoints; j++ ) { - k = ( j + 1 ) % numHullPoints; - - hullDirs[j] = vector3_cross( normal, VectorNormalized( hullPoints[k] - hullPoints[j] ) ); + hullDirs[j] = vector3_cross( normal, VectorNormalized( hullPoints[wrap( j + 1 )] - hullPoints[j] ) ); } outside = false; @@ -778,7 +779,7 @@ void AddWindingToConvexHull( const winding_t& w, winding_t& hull, const Vecto // find the back side to front side transition for ( j = 0; j < numHullPoints; j++ ) { - if ( !hullSide[ j % numHullPoints ] && hullSide[ ( j + 1 ) % numHullPoints ] ) { + if ( !hullSide[ j ] && hullSide[ wrap( j + 1 ) ] ) { break; } } @@ -791,17 +792,17 @@ void AddWindingToConvexHull( const winding_t& w, winding_t& hull, const Vecto numNew = 1; // copy over all points that aren't double fronts - j = ( j + 1 ) % numHullPoints; + j = wrap( j + 1 ); for ( k = 0; k < numHullPoints; k++ ) { - if ( hullSide[ ( j + k ) % numHullPoints ] && hullSide[ ( j + k + 1 ) % numHullPoints ] ) { + if ( hullSide[ wrap( j + k ) ] && hullSide[ wrap( j + k + 1 ) ] ) { continue; } - newHullPoints[numNew] = hullPoints[ ( j + k + 1 ) % numHullPoints ]; + newHullPoints[numNew] = hullPoints[ wrap( j + k + 1 ) ]; numNew++; } numHullPoints = numNew; - memcpy( hullPoints, newHullPoints, numHullPoints * sizeof( Vector3 ) ); + memcpy( hullPoints, newHullPoints, numHullPoints * sizeof( *hullPoints ) ); } hull = winding_t( hullPoints, hullPoints + numHullPoints ); diff --git a/tools/quake3/common/polylib.h b/tools/quake3/common/polylib.h index 522b84a3..ac3259ef 100644 --- a/tools/quake3/common/polylib.h +++ b/tools/quake3/common/polylib.h @@ -25,6 +25,15 @@ using winding_t = std::vector; +// index < w.size() +inline size_t winding_next( const winding_t& w, size_t index ){ + return ++index == w.size()? 0 : index; +} +// it < w.end() +inline winding_t::iterator winding_next( winding_t& w, winding_t::iterator it ){ + return ++it == w.end()? w.begin() : it; +} + #define MAX_POINTS_ON_WINDING 512 // you can define on_epsilon in the makefile as tighter diff --git a/tools/quake3/q3map2/brush.cpp b/tools/quake3/q3map2/brush.cpp index 65d17eb2..0c4c9500 100644 --- a/tools/quake3/q3map2/brush.cpp +++ b/tools/quake3/q3map2/brush.cpp @@ -191,7 +191,7 @@ bool FixWinding( winding_t& w ){ /* check all verts */ for ( winding_t::iterator i = w.begin(); i != w.end(); ) { - winding_t::iterator j = ( std::next( i ) == w.end() )? w.begin() : std::next( i ); + winding_t::iterator j = winding_next( w, i ); /* don't remove points if winding is a triangle */ if ( w.size() == 3 ) { return valid; @@ -566,10 +566,8 @@ void FilterStructuralBrushesIntoTree( entity_t *e, tree_t& tree ) { #define EDGE_LENGTH 0.2 bool WindingIsTiny( const winding_t& w ){ /* - if (WindingArea (w) < 1) - return true; - return false; - */ + return WindingArea( w ) < 1; +*/ int edges = 0; for ( size_t i = w.size() - 1, j = 0; j < w.size(); i = j, ++j ) diff --git a/tools/quake3/q3map2/map.cpp b/tools/quake3/q3map2/map.cpp index 5a4860fa..7c27a7e1 100644 --- a/tools/quake3/q3map2/map.cpp +++ b/tools/quake3/q3map2/map.cpp @@ -664,7 +664,7 @@ void AddBrushBevels( void ){ // test the non-axial plane edges for ( size_t i = 6; i < sides.size(); ++i ) { for ( size_t j = 0; j < sides[i].winding.size(); j++ ) { - Vector3 vec = sides[i].winding[j] - sides[i].winding[( ( j + 1 ) == sides[i].winding.size() )? 0 : ( j + 1 )]; + Vector3 vec = sides[i].winding[j] - sides[i].winding[winding_next( sides[i].winding, j )]; if ( VectorNormalize( vec ) < 0.5f ) { continue; } diff --git a/tools/quake3/q3map2/surface.cpp b/tools/quake3/q3map2/surface.cpp index 030878a8..5894d868 100644 --- a/tools/quake3/q3map2/surface.cpp +++ b/tools/quake3/q3map2/surface.cpp @@ -1558,14 +1558,8 @@ void CullSides( entity_t *e ){ } /* find second common point (regardless of winding order) */ - second = -1; + second = ( ( first + 1 ) < numPoints )? ( first + 1 ) : 0; dir = 0; - if ( ( first + 1 ) < numPoints ) { - second = first + 1; - } - else{ - second = 0; - } if ( vector3_equal_epsilon( w1[ 1 ], w2[ second ], CULL_EPSILON ) ) { dir = 1; }