/* ============ idBrush::Subtract ============ */ bool idBrush::Subtract( const idBrush* b, idBrushList& list ) const { int i; idBrush* front, *back; const idBrush* in; list.Clear(); in = this; for( i = 0; i < b->sides.Num() && in; i++ ) { in->Split( b->sides[i]->plane, b->sides[i]->planeNum, &front, &back ); if( in != this ) { delete in; } if( front ) { list.AddToTail( front ); } in = back; } // if didn't really intersect if( !in ) { list.Free(); return false; } delete in; return true; }
/* ============ idAASBuild::ClipBrushSidesWithProcBSP ============ */ void idAASBuild::ClipBrushSidesWithProcBSP( idBrushList &brushList ) { int i, clippedSides; idBrush *brush; idFixedWinding neww; idBounds bounds; float radius; idVec3 origin; // if the .proc file has no BSP tree if( idAASBuild::procNodes == NULL ) { return; } clippedSides = 0; for( brush = brushList.Head(); brush; brush = brush->Next() ) { for( i = 0; i < brush->GetNumSides(); i++ ) { if( !brush->GetSide( i )->GetWinding() ) { continue; } // make a local copy of the winding neww = *brush->GetSide( i )->GetWinding(); neww.GetBounds( bounds ); origin = ( bounds[1] - bounds[0] ) * 0.5f; radius = origin.Length() + ON_EPSILON; origin = bounds[0] + origin; if( ChoppedAwayByProcBSP( 0, &neww, brush->GetSide( i )->GetPlane().Normal(), origin, radius ) ) { brush->GetSide( i )->SetFlag( SFL_USED_SPLITTER ); clippedSides++; } } } common->Printf( "%6d brush sides clipped\n", clippedSides ); }
/* ============ idAASBuild::AddBrushesForMapFile ============ */ idBrushList idAASBuild::AddBrushesForMapFile( const idMapFile *mapFile, idBrushList brushList ) { int i; common->Printf( "[Brush Load]\n" ); brushList = AddBrushesForMapEntity( mapFile->GetEntity( 0 ), 0, brushList ); for( i = 1; i < mapFile->GetNumEntities(); i++ ) { const char *classname = mapFile->GetEntity( i )->epairs.GetString( "classname" ); if( idStr::Icmp( classname, "func_aas_obstacle" ) == 0 ) { brushList = AddBrushesForMapEntity( mapFile->GetEntity( i ), i, brushList ); } } common->Printf( "%6d brushes\n", brushList.Num() ); return brushList; }
/* ============ idBrushList::Split ============ */ void idBrushList::Split( const idPlane& plane, int planeNum, idBrushList& frontList, idBrushList& backList, bool useBrushSavedPlaneSide ) { idBrush* b, *front, *back; frontList.Clear(); backList.Clear(); if( !useBrushSavedPlaneSide ) { for( b = head; b; b = b->next ) { b->Split( plane, planeNum, &front, &back ); if( front ) { frontList.AddToTail( front ); } if( back ) { backList.AddToTail( back ); } } return; } for( b = head; b; b = b->next ) { if( b->savedPlaneSide & BRUSH_PLANESIDE_BOTH ) { b->Split( plane, planeNum, &front, &back ); if( front ) { frontList.AddToTail( front ); } if( back ) { backList.AddToTail( back ); } } else if( b->savedPlaneSide & BRUSH_PLANESIDE_FRONT ) { frontList.AddToTail( b->Copy() ); } else { backList.AddToTail( b->Copy() ); } } }
/* ============ idBrushMap::WriteBrushList ============ */ void idBrushMap::WriteBrushList( const idBrushList& brushList ) { idBrush* b; if( !fp ) { return; } for( b = brushList.Head(); b; b = b->Next() ) { WriteBrush( b ); } }
/* ============ idAASBuild::AddBrushForMapBrush ============ */ idBrushList idAASBuild::AddBrushesForMapBrush( const idMapBrush* mapBrush, const idVec3& origin, const idMat3& axis, int entityNum, int primitiveNum, idBrushList brushList ) { int contents, i; idMapBrushSide* mapSide; const idMaterial* mat; idList<idBrushSide*> sideList; idBrush* brush; idPlane plane; contents = 0; for( i = 0; i < mapBrush->GetNumSides(); i++ ) { mapSide = mapBrush->GetSide( i ); mat = declManager->FindMaterial( mapSide->GetMaterial() ); contents |= mat->GetContentFlags(); plane = mapSide->GetPlane(); plane.FixDegeneracies( DEGENERATE_DIST_EPSILON ); sideList.Append( new idBrushSide( plane, -1 ) ); } contents = ContentsForAAS( contents ); if( !contents ) { for( i = 0; i < sideList.Num(); i++ ) { delete sideList[i]; } return brushList; } brush = new idBrush(); brush->SetContents( contents ); if( !brush->FromSides( sideList ) ) { common->Warning( "brush primitive %d on entity %d is degenerate", primitiveNum, entityNum ); delete brush; return brushList; } brush->SetEntityNum( entityNum ); brush->SetPrimitiveNum( primitiveNum ); brush->Transform( origin, axis ); brushList.AddToTail( brush ); return brushList; }
/* ============ idAASBuild::AddBrushesForPatch ============ */ idBrushList idAASBuild::AddBrushesForMapPatch( const idMapPatch* mapPatch, const idVec3& origin, const idMat3& axis, int entityNum, int primitiveNum, idBrushList brushList ) { int i, j, contents, validBrushes; float dot; int v1, v2, v3, v4; idFixedWinding w; idPlane plane; idVec3 d1, d2; idBrush* brush; idSurface_Patch mesh; const idMaterial* mat; mat = declManager->FindMaterial( mapPatch->GetMaterial() ); contents = ContentsForAAS( mat->GetContentFlags() ); if( !contents ) { return brushList; } mesh = idSurface_Patch( *mapPatch ); // if the patch has an explicit number of subdivisions use it to avoid cracks if( mapPatch->GetExplicitlySubdivided() ) { mesh.SubdivideExplicit( mapPatch->GetHorzSubdivisions(), mapPatch->GetVertSubdivisions(), false, true ); } else { mesh.Subdivide( DEFAULT_CURVE_MAX_ERROR_CD, DEFAULT_CURVE_MAX_ERROR_CD, DEFAULT_CURVE_MAX_LENGTH_CD, false ); } validBrushes = 0; for( i = 0; i < mesh.GetWidth() - 1; i++ ) { for( j = 0; j < mesh.GetHeight() - 1; j++ ) { v1 = j * mesh.GetWidth() + i; v2 = v1 + 1; v3 = v1 + mesh.GetWidth() + 1; v4 = v1 + mesh.GetWidth(); d1 = mesh[v2].xyz - mesh[v1].xyz; d2 = mesh[v3].xyz - mesh[v1].xyz; plane.SetNormal( d1.Cross( d2 ) ); if( plane.Normalize() != 0.0f ) { plane.FitThroughPoint( mesh[v1].xyz ); dot = plane.Distance( mesh[v4].xyz ); // if we can turn it into a quad if( idMath::Fabs( dot ) < 0.1f ) { w.Clear(); w += mesh[v1].xyz; w += mesh[v2].xyz; w += mesh[v3].xyz; w += mesh[v4].xyz; brush = new idBrush(); brush->SetContents( contents ); if( brush->FromWinding( w, plane ) ) { brush->SetEntityNum( entityNum ); brush->SetPrimitiveNum( primitiveNum ); brush->SetFlag( BFL_PATCH ); brush->Transform( origin, axis ); brushList.AddToTail( brush ); validBrushes++; } else { delete brush; } continue; } else { // create one of the triangles w.Clear(); w += mesh[v1].xyz; w += mesh[v2].xyz; w += mesh[v3].xyz; brush = new idBrush(); brush->SetContents( contents ); if( brush->FromWinding( w, plane ) ) { brush->SetEntityNum( entityNum ); brush->SetPrimitiveNum( primitiveNum ); brush->SetFlag( BFL_PATCH ); brush->Transform( origin, axis ); brushList.AddToTail( brush ); validBrushes++; } else { delete brush; } } } // create the other triangle d1 = mesh[v3].xyz - mesh[v1].xyz; d2 = mesh[v4].xyz - mesh[v1].xyz; plane.SetNormal( d1.Cross( d2 ) ); if( plane.Normalize() != 0.0f ) { plane.FitThroughPoint( mesh[v1].xyz ); w.Clear(); w += mesh[v1].xyz; w += mesh[v3].xyz; w += mesh[v4].xyz; brush = new idBrush(); brush->SetContents( contents ); if( brush->FromWinding( w, plane ) ) { brush->SetEntityNum( entityNum ); brush->SetPrimitiveNum( primitiveNum ); brush->SetFlag( BFL_PATCH ); brush->Transform( origin, axis ); brushList.AddToTail( brush ); validBrushes++; } else { delete brush; } } } } if( !validBrushes ) { common->Warning( "patch primitive %d on entity %d is completely degenerate", primitiveNum, entityNum ); } return brushList; }