Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 94 additions & 62 deletions neo/idlib/geometry/Winding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,10 @@ idWinding::Split
=============
*/
int idWinding::Split( const idPlane &plane, const float epsilon, idWinding **front, idWinding **back ) const {
float * dists;
double * dists;
byte * sides;
int counts[3];
float dot;
double dot;
int i, j;
const idVec5 * p1, *p2;
idVec5 mid;
Expand All @@ -107,14 +107,17 @@ int idWinding::Split( const idPlane &plane, const float epsilon, idWinding **fro
return 0; // it's not like the callers check the return value anyway..
}

dists = (float *) _alloca( (numPoints+4) * sizeof( float ) );
dists = (double *) _alloca( (numPoints+4) * sizeof( double ) );
sides = (byte *) _alloca( (numPoints+4) * sizeof( byte ) );

counts[0] = counts[1] = counts[2] = 0;

const idVec3 &pn = plane.Normal();
double pa = pn[0], pb = pn[1], pc = pn[2], pd = plane[3];

// determine sides for each point
for ( i = 0; i < numPoints; i++ ) {
dists[i] = dot = plane.Distance( p[i].ToVec3() );
dists[i] = dot = pa * (double)p[i].x + pb * (double)p[i].y + pc * (double)p[i].z + pd;
if ( dot > epsilon ) {
sides[i] = SIDE_FRONT;
} else if ( dot < -epsilon ) {
Expand Down Expand Up @@ -188,36 +191,38 @@ int idWinding::Split( const idPlane &plane, const float epsilon, idWinding **fro

// always calculate the split going from the same side
// or minor epsilon issues can happen
// morb: lerp in double is enough. trying to nail down x87 equivalence resulted in complexity.
if ( sides[i] == SIDE_FRONT ) {
dot = dists[i] / ( dists[i] - dists[i+1] );
double dotd = (double)dists[i] / ( (double)dists[i] - (double)dists[i+1] );
for ( j = 0; j < 3; j++ ) {
// avoid round off error when possible
if ( plane.Normal()[j] == 1.0f ) {
mid[j] = plane.Dist();
} else if ( plane.Normal()[j] == -1.0f ) {
mid[j] = -plane.Dist();
} else {
mid[j] = (*p1)[j] + dot * ( (*p2)[j] - (*p1)[j] );
mid[j] = (float)( (double)(*p1)[j] + dotd * ( (double)(*p2)[j] - (double)(*p1)[j] ) );
}
}
mid.s = p1->s + dot * ( p2->s - p1->s );
mid.t = p1->t + dot * ( p2->t - p1->t );
mid.s = (float)( (double)p1->s + dotd * ( (double)p2->s - (double)p1->s ) );
mid.t = (float)( (double)p1->t + dotd * ( (double)p2->t - (double)p1->t ) );
} else {
dot = dists[i+1] / ( dists[i+1] - dists[i] );
double dotd = (double)dists[i+1] / ( (double)dists[i+1] - (double)dists[i] );
for ( j = 0; j < 3; j++ ) {
// avoid round off error when possible
if ( plane.Normal()[j] == 1.0f ) {
mid[j] = plane.Dist();
} else if ( plane.Normal()[j] == -1.0f ) {
mid[j] = -plane.Dist();
} else {
mid[j] = (*p2)[j] + dot * ( (*p1)[j] - (*p2)[j] );
mid[j] = (float)( (double)(*p2)[j] + dotd * ( (double)(*p1)[j] - (double)(*p2)[j] ) );
}
}
mid.s = p2->s + dot * ( p1->s - p2->s );
mid.t = p2->t + dot * ( p1->t - p2->t );
mid.s = (float)( (double)p2->s + dotd * ( (double)p1->s - (double)p2->s ) );
mid.t = (float)( (double)p2->t + dotd * ( (double)p1->t - (double)p2->t ) );
}


f->p[f->numPoints] = mid;
f->numPoints++;
b->p[b->numPoints] = mid;
Expand All @@ -237,12 +242,12 @@ idWinding::Clip
=============
*/
idWinding *idWinding::Clip( const idPlane &plane, const float epsilon, const bool keepOn ) {
float * dists;
double * dists;
byte * sides;
idVec5 * newPoints;
int newNumPoints;
int counts[3];
float dot;
double dot;
int i, j;
idVec5 * p1, *p2;
idVec5 mid;
Expand All @@ -256,14 +261,18 @@ idWinding *idWinding::Clip( const idPlane &plane, const float epsilon, const boo
return NULL;
}

dists = (float *) _alloca( (numPoints+4) * sizeof( float ) );
dists = (double *) _alloca( (numPoints+4) * sizeof( double ) );
sides = (byte *) _alloca( (numPoints+4) * sizeof( byte ) );

counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;

// morb: distance in double precision (see idWinding::Split)
const idVec3 &pn = plane.Normal();
double pa = pn[0], pb = pn[1], pc = pn[2], pd = plane[3];

// determine sides for each point
for ( i = 0; i < numPoints; i++ ) {
dists[i] = dot = plane.Distance( p[i].ToVec3() );
dists[i] = dot = pa * (double)p[i].x + pb * (double)p[i].y + pc * (double)p[i].z + pd;
if ( dot > epsilon ) {
sides[i] = SIDE_FRONT;
} else if ( dot < -epsilon ) {
Expand Down Expand Up @@ -324,19 +333,22 @@ idWinding *idWinding::Clip( const idPlane &plane, const float epsilon, const boo
// generate a split point
p2 = &p[(i+1)%numPoints];

dot = dists[i] / (dists[i] - dists[i+1]);
for ( j = 0; j < 3; j++ ) {
// avoid round off error when possible
if ( plane.Normal()[j] == 1.0f ) {
mid[j] = plane.Dist();
} else if ( plane.Normal()[j] == -1.0f ) {
mid[j] = -plane.Dist();
} else {
mid[j] = (*p1)[j] + dot * ( (*p2)[j] - (*p1)[j] );
// morb: lerp in double.
{
double dotd = (double)dists[i] / ( (double)dists[i] - (double)dists[i+1] );
for ( j = 0; j < 3; j++ ) {
// avoid round off error when possible
if ( plane.Normal()[j] == 1.0f ) {
mid[j] = plane.Dist();
} else if ( plane.Normal()[j] == -1.0f ) {
mid[j] = -plane.Dist();
} else {
mid[j] = (float)( (double)(*p1)[j] + dotd * ( (double)(*p2)[j] - (double)(*p1)[j] ) );
}
}
mid.s = (float)( (double)p1->s + dotd * ( (double)p2->s - (double)p1->s ) );
mid.t = (float)( (double)p1->t + dotd * ( (double)p2->t - (double)p1->t ) );
}
mid.s = p1->s + dot * ( p2->s - p1->s );
mid.t = p1->t + dot * ( p2->t - p1->t );

newPoints[newNumPoints] = mid;
newNumPoints++;
Expand All @@ -358,27 +370,31 @@ idWinding::ClipInPlace
=============
*/
bool idWinding::ClipInPlace( const idPlane &plane, const float epsilon, const bool keepOn ) {
float* dists;
double* dists;
byte * sides;
idVec5 * newPoints;
int newNumPoints;
int counts[3];
float dot;
double dot;
int i, j;
idVec5 * p1, *p2;
idVec5 mid;
int maxpts;

assert( this );

dists = (float *) _alloca( (numPoints+4) * sizeof( float ) );
dists = (double *) _alloca( (numPoints+4) * sizeof( double ) );
sides = (byte *) _alloca( (numPoints+4) * sizeof( byte ) );

counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;

// morb: distance in double precision (see idWinding::Split)
const idVec3 &pn = plane.Normal();
double pa = pn[0], pb = pn[1], pc = pn[2], pd = plane[3];

// determine sides for each point
for ( i = 0; i < numPoints; i++ ) {
dists[i] = dot = plane.Distance( p[i].ToVec3() );
dists[i] = dot = pa * (double)p[i].x + pb * (double)p[i].y + pc * (double)p[i].z + pd;
if ( dot > epsilon ) {
sides[i] = SIDE_FRONT;
} else if ( dot < -epsilon ) {
Expand Down Expand Up @@ -439,19 +455,22 @@ bool idWinding::ClipInPlace( const idPlane &plane, const float epsilon, const bo
// generate a split point
p2 = &p[(i+1)%numPoints];

dot = dists[i] / (dists[i] - dists[i+1]);
for ( j = 0; j < 3; j++ ) {
// avoid round off error when possible
if ( plane.Normal()[j] == 1.0f ) {
mid[j] = plane.Dist();
} else if ( plane.Normal()[j] == -1.0f ) {
mid[j] = -plane.Dist();
} else {
mid[j] = (*p1)[j] + dot * ( (*p2)[j] - (*p1)[j] );
// morb: lerp in double.
{
double dotd = (double)dists[i] / ( (double)dists[i] - (double)dists[i+1] );
for ( j = 0; j < 3; j++ ) {
// avoid round off error when possible
if ( plane.Normal()[j] == 1.0f ) {
mid[j] = plane.Dist();
} else if ( plane.Normal()[j] == -1.0f ) {
mid[j] = -plane.Dist();
} else {
mid[j] = (float)( (double)(*p1)[j] + dotd * ( (double)(*p2)[j] - (double)(*p1)[j] ) );
}
}
mid.s = (float)( (double)p1->s + dotd * ( (double)p2->s - (double)p1->s ) );
mid.t = (float)( (double)p1->t + dotd * ( (double)p2->t - (double)p1->t ) );
}
mid.s = p1->s + dot * ( p2->s - p1->s );
mid.t = p1->t + dot * ( p2->t - p1->t );

newPoints[newNumPoints] = mid;
newNumPoints++;
Expand Down Expand Up @@ -766,12 +785,14 @@ void idWinding::RemoveColinearPoints( const idVec3 &normal, const float epsilon
idVec3 edgeNormal;
float dist;

if ( numPoints <= 3 ) {
return;
}

for ( i = 0; i < numPoints; i++ ) {

// c/o TDM - don't remove any points when there are only 3 or less left to avoid
// degenerating the winding, otherwise this may result in windings with numPoints = 0
if ( numPoints <= 3 ) {
return;
}

// create plane through edge orthogonal to winding plane
edgeNormal = (p[i].ToVec3() - p[(i+numPoints-1)%numPoints].ToVec3()).Cross( normal );
edgeNormal.Normalize();
Expand Down Expand Up @@ -1303,12 +1324,16 @@ idWinding::PlaneSide
int idWinding::PlaneSide( const idPlane &plane, const float epsilon ) const {
bool front, back;
int i;
float d;
double d;

// morb: double-precision distance for SelectSplitPlaneNum scoring.
const idVec3 &pn = plane.Normal();
double pa = pn[0], pb = pn[1], pc = pn[2], pd = plane[3];

front = false;
back = false;
for ( i = 0; i < numPoints; i++ ) {
d = plane.Distance( p[i].ToVec3() );
d = pa * (double)p[i].x + pb * (double)p[i].y + pc * (double)p[i].z + pd;
if ( d < -epsilon ) {
if ( front ) {
return SIDE_CROSS;
Expand Down Expand Up @@ -1494,19 +1519,23 @@ idFixedWinding::Split
*/
int idFixedWinding::Split( idFixedWinding *back, const idPlane &plane, const float epsilon ) {
int counts[3];
float dists[MAX_POINTS_ON_WINDING+4];
double dists[MAX_POINTS_ON_WINDING+4];
byte sides[MAX_POINTS_ON_WINDING+4];
float dot;
double dot;
int i, j;
idVec5 *p1, *p2;
idVec5 mid;
idFixedWinding out;

counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;

// morb: distance in double precision (see idWinding::Split)
const idVec3 &pn = plane.Normal();
double pa = pn[0], pb = pn[1], pc = pn[2], pd = plane[3];

// determine sides for each point
for ( i = 0; i < numPoints; i++ ) {
dists[i] = dot = plane.Distance( p[i].ToVec3() );
dists[i] = dot = pa * (double)p[i].x + pb * (double)p[i].y + pc * (double)p[i].z + pd;
if ( dot > epsilon ) {
sides[i] = SIDE_FRONT;
} else if ( dot < -epsilon ) {
Expand Down Expand Up @@ -1584,19 +1613,22 @@ int idFixedWinding::Split( idFixedWinding *back, const idPlane &plane, const flo
p2 = &p[j];
}

dot = dists[i] / (dists[i] - dists[i+1]);
for ( j = 0; j < 3; j++ ) {
// avoid round off error when possible
if ( plane.Normal()[j] == 1.0f ) {
mid[j] = plane.Dist();
} else if ( plane.Normal()[j] == -1.0f ) {
mid[j] = -plane.Dist();
} else {
mid[j] = (*p1)[j] + dot * ( (*p2)[j] - (*p1)[j] );
// morb: lerp in double.
{
double dotd = (double)dists[i] / ( (double)dists[i] - (double)dists[i+1] );
for ( j = 0; j < 3; j++ ) {
// avoid round off error when possible
if ( plane.Normal()[j] == 1.0f ) {
mid[j] = plane.Dist();
} else if ( plane.Normal()[j] == -1.0f ) {
mid[j] = -plane.Dist();
} else {
mid[j] = (float)( (double)(*p1)[j] + dotd * ( (double)(*p2)[j] - (double)(*p1)[j] ) );
}
}
mid.s = (float)( (double)p1->s + dotd * ( (double)p2->s - (double)p1->s ) );
mid.t = (float)( (double)p1->t + dotd * ( (double)p2->t - (double)p1->t ) );
}
mid.s = p1->s + dot * ( p2->s - p1->s );
mid.t = p1->t + dot * ( p2->t - p1->t );

out.p[out.numPoints] = mid;
out.numPoints++;
Expand Down
32 changes: 19 additions & 13 deletions neo/tools/compilers/aas/AASBuild.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -863,24 +863,30 @@ bool idAASBuild::Build( const idStr& fileName, const idAASSettings* settings )
bsp.MeltPortals( AREACONTENTS_SOLID );

// store the file from the bsp tree
StoreFile( bsp );
bool storeOk = StoreFile( bsp );
file->settings = *aasSettings;

// calculate reachability
reach.Build( mapFile, file );
if ( storeOk ) {
// calculate reachability
reach.Build( mapFile, file );

// build clusters
cluster.Build( file );
// build clusters
cluster.Build( file );

// optimize the file
if( !aasSettings->noOptimize )
{
file->Optimize();
}
// optimize the file
if( !aasSettings->noOptimize )
{
file->Optimize();
}

// write the file
name.SetFileExtension( aasSettings->fileExtension );
file->Write( name, mapFile->GetGeometryCRC() );
// write the file
name.SetFileExtension( aasSettings->fileExtension );
file->Write( name, mapFile->GetGeometryCRC() );
} else {
// morb: downstream phases would dereference truncated area indices
common->Warning( "Skipping AAS write for %s",
aasSettings->fileExtension.c_str() );
}

// delete the map file
delete mapFile;
Expand Down
14 changes: 13 additions & 1 deletion neo/tools/compilers/aas/AASBuild_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ idAASBuild::GetFaceForPortal
bool idAASBuild::GetFaceForPortal( idBrushBSPPortal* portal, int side, int* faceNum )
{
int i, j, v1num;
int numFaceEdges, faceEdges[MAX_POINTS_ON_WINDING];
int numFaceEdges;
idWinding* w;
aasFace_t face;

Expand All @@ -255,6 +255,10 @@ bool idAASBuild::GetFaceForPortal( idBrushBSPPortal* portal, int side, int* face
}

w = portal->GetWinding();
// morb: buffer should be sized to the winding.
// modern systems otherwise detect stack-smashing here (!) with >64 points.
int* faceEdges = (int*)_alloca( w->GetNumPoints() * sizeof( int ) );

// turn the winding into a sequence of edges
numFaceEdges = 0;
v1num = -1; // first vertex unknown
Expand Down Expand Up @@ -554,5 +558,13 @@ bool idAASBuild::StoreFile( const idBrushBSP& bsp )

common->Printf( "\r%6d areas\n", file->areas.Num() );

// morb: aasFace_t::areas[2] is `short`; >32767 areas silently truncates,
// dereferences indices, then segfaults.
if ( file->areas.Num() > 32767 ) {
common->Warning( "Skipping write: AAS area count %d is greater than 32767",
file->areas.Num() );
return false;
}

return true;
}
Loading
Loading