//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_RemoveTinyFaces(void) { int side, num; tmp_face_t *face, *nextface; tmp_area_t *tmparea; //FIXME: loop over the faces instead of area->faces Log_Write("AAS_RemoveTinyFaces\r\n"); num = 0; for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next) { for (face = tmparea->tmpfaces; face; face = nextface) { side = face->frontarea != tmparea; nextface = face->next[side]; // if (WindingArea(face->winding) < 1) { if (face->frontarea) AAS_RemoveFaceFromArea(face, face->frontarea); if (face->backarea) AAS_RemoveFaceFromArea(face, face->backarea); AAS_FreeTmpFace(face); //Log_Write("area %d face %d is tiny\r\n", tmparea->areanum, face->num); num++; } //end if } //end for } //end for Log_Write("%d tiny faces removed\r\n", num); } //end of the function AAS_RemoveTinyFaces
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_MergePlaneFaces(tmp_area_t *tmparea, int planenum) { tmp_face_t *face1, *face2, *nextface2; winding_t *neww; int side1, side2; for (face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1]) { side1 = face1->frontarea != tmparea; if (face1->planenum != planenum) continue; // for (face2 = face1->next[side1]; face2; face2 = nextface2) { side2 = face2->frontarea != tmparea; nextface2 = face2->next[side2]; // if ((face2->planenum & ~1) != (planenum & ~1)) continue; // neww = MergeWindings(face1->winding, face2->winding, mapplanes[face1->planenum].normal); FreeWinding(face1->winding); face1->winding = neww; if (face2->frontarea) AAS_RemoveFaceFromArea(face2, face2->frontarea); if (face2->backarea) AAS_RemoveFaceFromArea(face2, face2->backarea); AAS_FreeTmpFace(face2); // nextface2 = face1->next[side1]; } //end for } //end for } //end of the function AAS_MergePlaneFaces
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_FlipFace(tmp_face_t *face) { tmp_area_t *frontarea, *backarea; winding_t *w; frontarea = face->frontarea; backarea = face->backarea; //must have an area at both sides before flipping is allowed if(!frontarea || !backarea) { return; } //flip the face winding w = face->winding; face->winding = ReverseWinding(w); FreeWinding(w); //flip the face plane face->planenum ^= 1; //flip the face areas AAS_RemoveFaceFromArea(face, frontarea); AAS_RemoveFaceFromArea(face, backarea); AAS_AddFaceSideToArea(face, 1, frontarea); AAS_AddFaceSideToArea(face, 0, backarea); } //end of the function AAS_FlipFace
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_TryMergeFaces( tmp_face_t *face1, tmp_face_t *face2 ) { winding_t *neww; #ifdef DEBUG if ( !face1->winding ) { Error( "face1 %d without winding", face1->num ); } if ( !face2->winding ) { Error( "face2 %d without winding", face2->num ); } #endif //DEBUG // if ( face1->faceflags != face2->faceflags ) { return false; } //NOTE: if the front or back area is zero this doesn't mean there's //a real area. It means there's solid at that side of the face //if both faces have the same front area if ( face1->frontarea == face2->frontarea ) { //if both faces have the same back area if ( face1->backarea == face2->backarea ) { //if the faces are in the same plane if ( face1->planenum == face2->planenum ) { //if they have both a front and a back area (no solid on either side) if ( face1->frontarea && face1->backarea ) { neww = MergeWindings( face1->winding, face2->winding, mapplanes[face1->planenum].normal ); } //end if else { //this function is to be found in l_poly.c neww = TryMergeWinding( face1->winding, face2->winding, mapplanes[face1->planenum].normal ); } //end else if ( neww ) { FreeWinding( face1->winding ); face1->winding = neww; if ( face2->frontarea ) { AAS_RemoveFaceFromArea( face2, face2->frontarea ); } if ( face2->backarea ) { AAS_RemoveFaceFromArea( face2, face2->backarea ); } AAS_FreeTmpFace( face2 ); return true; } //end if } //end if else if ( ( face1->planenum & ~1 ) == ( face2->planenum & ~1 ) ) { Log_Write( "face %d and %d, same front and back area but flipped planes\r\n", face1->num, face2->num ); } //end if } //end if } //end if return false; } //end of the function AAS_TryMergeFaces
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_SplitArea( tmp_area_t *tmparea, int planenum, tmp_area_t **frontarea, tmp_area_t **backarea ) { int side; tmp_area_t *facefrontarea, *facebackarea, *faceotherarea; tmp_face_t *face, *frontface, *backface, *splitface, *nextface; winding_t *splitwinding; plane_t *splitplane; /* #ifdef AW_DEBUG int facesplits, groundsplits, epsilonface; Log_Print("\n----------------------\n"); Log_Print("splitting area %d\n", areanum); Log_Print("with normal = \'%f %f %f\', dist = %f\n", normal[0], normal[1], normal[2], dist); AAS_TestSplitPlane(areanum, normal, dist, &facesplits, &groundsplits, &epsilonface); Log_Print("face splits = %d\nground splits = %d\n", facesplits, groundsplits); if (epsilonface) Log_Print("aaahh epsilon face\n"); #endif //AW_DEBUG*/ //the original area AAS_FlipAreaFaces( tmparea ); AAS_CheckArea( tmparea ); // splitplane = &mapplanes[planenum]; /* //create a split winding, first base winding for plane splitwinding = BaseWindingForPlane(splitplane->normal, splitplane->dist); //chop with all the faces of the area for (face = tmparea->tmpfaces; face && splitwinding; face = face->next[side]) { //side of the face the original area was on side = face->frontarea != tmparea->areanum; plane = &mapplanes[face->planenum ^ side]; ChopWindingInPlace(&splitwinding, plane->normal, plane->dist, 0); // PLANESIDE_EPSILON); } //end for*/ splitwinding = AAS_SplitWinding( tmparea, planenum ); if ( !splitwinding ) { /* #ifdef DEBUG AAS_TestSplitPlane(areanum, normal, dist, &facesplits, &groundsplits, &epsilonface); Log_Print("\nface splits = %d\nground splits = %d\n", facesplits, groundsplits); if (epsilonface) Log_Print("aaahh epsilon face\n"); #endif //DEBUG*/ Error( "AAS_SplitArea: no split winding when splitting area %d\n", tmparea->areanum ); } //end if //create a split face splitface = AAS_AllocTmpFace(); //get the map plane splitface->planenum = planenum; //store the split winding splitface->winding = splitwinding; //the new front area ( *frontarea ) = AAS_AllocTmpArea(); ( *frontarea )->presencetype = tmparea->presencetype; ( *frontarea )->contents = tmparea->contents; ( *frontarea )->modelnum = tmparea->modelnum; ( *frontarea )->tmpfaces = NULL; //the new back area ( *backarea ) = AAS_AllocTmpArea(); ( *backarea )->presencetype = tmparea->presencetype; ( *backarea )->contents = tmparea->contents; ( *backarea )->modelnum = tmparea->modelnum; ( *backarea )->tmpfaces = NULL; //add the split face to the new areas AAS_AddFaceSideToArea( splitface, 0, ( *frontarea ) ); AAS_AddFaceSideToArea( splitface, 1, ( *backarea ) ); //split all the faces of the original area for ( face = tmparea->tmpfaces; face; face = nextface ) { //side of the face the original area was on side = face->frontarea != tmparea; //next face of the original area nextface = face->next[side]; //front area of the face facefrontarea = face->frontarea; //back area of the face facebackarea = face->backarea; //remove the face from both the front and back areas if ( facefrontarea ) { AAS_RemoveFaceFromArea( face, facefrontarea ); } if ( facebackarea ) { AAS_RemoveFaceFromArea( face, facebackarea ); } //split the face AAS_SplitFace( face, splitplane->normal, splitplane->dist, &frontface, &backface ); //free the original face AAS_FreeTmpFace( face ); //get the number of the area at the other side of the face if ( side ) { faceotherarea = facefrontarea; } else { faceotherarea = facebackarea;} //if there is an area at the other side of the original face if ( faceotherarea ) { if ( frontface ) { AAS_AddFaceSideToArea( frontface, !side, faceotherarea ); } if ( backface ) { AAS_AddFaceSideToArea( backface, !side, faceotherarea ); } } //end if //add the front and back part left after splitting the original face to the new areas if ( frontface ) { AAS_AddFaceSideToArea( frontface, side, ( *frontarea ) ); } if ( backface ) { AAS_AddFaceSideToArea( backface, side, ( *backarea ) ); } } //end for if ( !( *frontarea )->tmpfaces ) { Log_Print( "AAS_SplitArea: front area without faces\n" ); } if ( !( *backarea )->tmpfaces ) { Log_Print( "AAS_SplitArea: back area without faces\n" ); } tmparea->invalid = true; /* #ifdef AW_DEBUG for (i = 0, face = frontarea->tmpfaces; face; face = face->next[side]) { side = face->frontarea != frontarea->areanum; i++; } //end for Log_Print("created front area %d with %d faces\n", frontarea->areanum, i); for (i = 0, face = backarea->tmpfaces; face; face = face->next[side]) { side = face->frontarea != backarea->areanum; i++; } //end for Log_Print("created back area %d with %d faces\n", backarea->areanum, i); #endif //AW_DEBUG*/ AAS_FlipAreaFaces( ( *frontarea ) ); AAS_FlipAreaFaces( ( *backarea ) ); // AAS_CheckArea( ( *frontarea ) ); AAS_CheckArea( ( *backarea ) ); } //end of the function AAS_SplitArea
//=========================================================================== // try to merge the areas at both sides of the given face // // Parameter: seperatingface : face that seperates two areas // Returns: - // Changes Globals: - //=========================================================================== int AAS_TryMergeFaceAreas( tmp_face_t *seperatingface ) { int side1, side2, area1faceflags, area2faceflags; tmp_area_t *tmparea1, *tmparea2, *newarea; tmp_face_t *face1, *face2, *nextface1, *nextface2; tmparea1 = seperatingface->frontarea; tmparea2 = seperatingface->backarea; //areas must have the same presence type if ( tmparea1->presencetype != tmparea2->presencetype ) { return false; } //areas must have the same area contents if ( tmparea1->contents != tmparea2->contents ) { return false; } //areas must have the same bsp model inside (or both none) if ( tmparea1->modelnum != tmparea2->modelnum ) { return false; } area1faceflags = 0; area2faceflags = 0; for ( face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side1] ) { side1 = ( face1->frontarea != tmparea1 ); //debug: check if the area belongs to the area if ( face1->frontarea != tmparea1 && face1->backarea != tmparea1 ) { Error( "face does not belong to area1" ); } //just continue if the face is seperating the two areas //NOTE: a result of this is that ground and gap areas can // be merged if the seperating face is the gap if ( ( face1->frontarea == tmparea1 && face1->backarea == tmparea2 ) || ( face1->frontarea == tmparea2 && face1->backarea == tmparea1 ) ) { continue; } //get area1 face flags area1faceflags |= face1->faceflags; if ( AAS_GapFace( face1, side1 ) ) { area1faceflags |= FACE_GAP; } // for ( face2 = tmparea2->tmpfaces; face2; face2 = face2->next[side2] ) { side2 = ( face2->frontarea != tmparea2 ); //debug: check if the area belongs to the area if ( face2->frontarea != tmparea2 && face2->backarea != tmparea2 ) { Error( "face does not belong to area2" ); } //just continue if the face is seperating the two areas //NOTE: a result of this is that ground and gap areas can // be merged if the seperating face is the gap if ( ( face2->frontarea == tmparea1 && face2->backarea == tmparea2 ) || ( face2->frontarea == tmparea2 && face2->backarea == tmparea1 ) ) { continue; } //get area2 face flags area2faceflags |= face2->faceflags; if ( AAS_GapFace( face2, side2 ) ) { area2faceflags |= FACE_GAP; } //if the two faces would create a non-convex area if ( NonConvex( face1, face2, side1, side2 ) ) { return false; } } //end for } //end for //if one area has gap faces (that aren't seperating the two areas) //and the other has ground faces (that aren't seperating the two areas), //the areas can't be merged if ( ( ( area1faceflags & FACE_GROUND ) && ( area2faceflags & FACE_GAP ) ) || ( ( area2faceflags & FACE_GROUND ) && ( area1faceflags & FACE_GAP ) ) ) { // Log_Print(" can't merge: ground/gap\n"); return false; } //end if // Log_Print("merged area %d & %d to %d with %d faces\n", tmparea1->areanum, tmparea2->areanum, newarea->areanum, numfaces); // return false; // //AAS_CheckArea(tmparea1); //AAS_CheckArea(tmparea2); //create the new area newarea = AAS_AllocTmpArea(); newarea->presencetype = tmparea1->presencetype; newarea->contents = tmparea1->contents; newarea->modelnum = tmparea1->modelnum; newarea->tmpfaces = NULL; //add all the faces (except the seperating ones) from the first area //to the new area for ( face1 = tmparea1->tmpfaces; face1; face1 = nextface1 ) { side1 = ( face1->frontarea != tmparea1 ); nextface1 = face1->next[side1]; //don't add seperating faces if ( ( face1->frontarea == tmparea1 && face1->backarea == tmparea2 ) || ( face1->frontarea == tmparea2 && face1->backarea == tmparea1 ) ) { continue; } //end if // AAS_RemoveFaceFromArea( face1, tmparea1 ); AAS_AddFaceSideToArea( face1, side1, newarea ); } //end for //add all the faces (except the seperating ones) from the second area //to the new area for ( face2 = tmparea2->tmpfaces; face2; face2 = nextface2 ) { side2 = ( face2->frontarea != tmparea2 ); nextface2 = face2->next[side2]; //don't add seperating faces if ( ( face2->frontarea == tmparea1 && face2->backarea == tmparea2 ) || ( face2->frontarea == tmparea2 && face2->backarea == tmparea1 ) ) { continue; } //end if // AAS_RemoveFaceFromArea( face2, tmparea2 ); AAS_AddFaceSideToArea( face2, side2, newarea ); } //end for //free all shared faces for ( face1 = tmparea1->tmpfaces; face1; face1 = nextface1 ) { side1 = ( face1->frontarea != tmparea1 ); nextface1 = face1->next[side1]; // AAS_RemoveFaceFromArea( face1, face1->frontarea ); AAS_RemoveFaceFromArea( face1, face1->backarea ); AAS_FreeTmpFace( face1 ); } //end for // tmparea1->mergedarea = newarea; tmparea1->invalid = true; tmparea2->mergedarea = newarea; tmparea2->invalid = true; // AAS_CheckArea( newarea ); AAS_FlipAreaFaces( newarea ); // Log_Print("merged area %d & %d to %d with %d faces\n", tmparea1->areanum, tmparea2->areanum, newarea->areanum); return true; } //end of the function AAS_TryMergeFaceAreas