Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

aas_areamerging.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 
00023 #include "qbsp.h"
00024 #include "../botlib/aasfile.h"
00025 #include "aas_create.h"
00026 #include "aas_store.h"
00027 
00028 #define CONVEX_EPSILON      0.3
00029 
00030 //===========================================================================
00031 //
00032 // Parameter:               -
00033 // Returns:                 -
00034 // Changes Globals:     -
00035 //===========================================================================
00036 tmp_node_t *AAS_RefreshMergedTree_r(tmp_node_t *tmpnode)
00037 {
00038     tmp_area_t *tmparea;
00039 
00040     //if this is a solid leaf
00041     if (!tmpnode) return NULL;
00042     //if this is an area leaf
00043     if (tmpnode->tmparea)
00044     {
00045         tmparea = tmpnode->tmparea;
00046         while(tmparea->mergedarea) tmparea = tmparea->mergedarea;
00047         tmpnode->tmparea = tmparea;
00048         return tmpnode;
00049     } //end if
00050     //do the children recursively
00051     tmpnode->children[0] = AAS_RefreshMergedTree_r(tmpnode->children[0]);
00052     tmpnode->children[1] = AAS_RefreshMergedTree_r(tmpnode->children[1]);
00053     return tmpnode;
00054 } //end of the function AAS_RefreshMergedTree_r
00055 //===========================================================================
00056 // returns true if the two given faces would create a non-convex area at
00057 // the given sides, otherwise false is returned
00058 //
00059 // Parameter:               -
00060 // Returns:                 -
00061 // Changes Globals:     -
00062 //===========================================================================
00063 int NonConvex(tmp_face_t *face1, tmp_face_t *face2, int side1, int side2)
00064 {
00065     int i;
00066     winding_t *w1, *w2;
00067     plane_t *plane1, *plane2;
00068     
00069     w1 = face1->winding;
00070     w2 = face2->winding;
00071 
00072     plane1 = &mapplanes[face1->planenum ^ side1];
00073     plane2 = &mapplanes[face2->planenum ^ side2];
00074 
00075     //check if one of the points of face1 is at the back of the plane of face2
00076     for (i = 0; i < w1->numpoints; i++)
00077     {
00078         if (DotProduct(plane2->normal, w1->p[i]) - plane2->dist < -CONVEX_EPSILON) return true;
00079     } //end for
00080     //check if one of the points of face2 is at the back of the plane of face1
00081     for (i = 0; i < w2->numpoints; i++)
00082     {
00083         if (DotProduct(plane1->normal, w2->p[i]) - plane1->dist < -CONVEX_EPSILON) return true;
00084     } //end for
00085 
00086     return false;
00087 } //end of the function NonConvex
00088 //===========================================================================
00089 // try to merge the areas at both sides of the given face
00090 //
00091 // Parameter:               seperatingface      : face that seperates two areas
00092 // Returns:                 -
00093 // Changes Globals:     -
00094 //===========================================================================
00095 int AAS_TryMergeFaceAreas(tmp_face_t *seperatingface)
00096 {
00097     int side1, side2, area1faceflags, area2faceflags;
00098     tmp_area_t *tmparea1, *tmparea2, *newarea;
00099     tmp_face_t *face1, *face2, *nextface1, *nextface2;
00100 
00101     tmparea1 = seperatingface->frontarea;
00102     tmparea2 = seperatingface->backarea;
00103 
00104     //areas must have the same presence type
00105     if (tmparea1->presencetype != tmparea2->presencetype) return false;
00106     //areas must have the same area contents
00107     if (tmparea1->contents != tmparea2->contents) return false;
00108     //areas must have the same bsp model inside (or both none)
00109     if (tmparea1->modelnum != tmparea2->modelnum) return false;
00110 
00111     area1faceflags = 0;
00112     area2faceflags = 0;
00113     for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side1])
00114     {
00115         side1 = (face1->frontarea != tmparea1);
00116         //debug: check if the area belongs to the area
00117         if (face1->frontarea != tmparea1 &&
00118                 face1->backarea != tmparea1) Error("face does not belong to area1");
00119         //just continue if the face is seperating the two areas
00120         //NOTE: a result of this is that ground and gap areas can
00121         //      be merged if the seperating face is the gap
00122         if ((face1->frontarea == tmparea1 &&
00123                 face1->backarea == tmparea2) ||
00124                 (face1->frontarea == tmparea2 &&
00125                 face1->backarea == tmparea1)) continue;
00126         //get area1 face flags
00127         area1faceflags |= face1->faceflags;
00128         if (AAS_GapFace(face1, side1)) area1faceflags |= FACE_GAP;
00129         //
00130         for (face2 = tmparea2->tmpfaces; face2; face2 = face2->next[side2])
00131         {
00132             side2 = (face2->frontarea != tmparea2);
00133             //debug: check if the area belongs to the area
00134             if (face2->frontarea != tmparea2 &&
00135                     face2->backarea != tmparea2) Error("face does not belong to area2");
00136             //just continue if the face is seperating the two areas
00137             //NOTE: a result of this is that ground and gap areas can
00138             //      be merged if the seperating face is the gap
00139             if ((face2->frontarea == tmparea1 &&
00140                     face2->backarea == tmparea2) ||
00141                     (face2->frontarea == tmparea2 &&
00142                     face2->backarea == tmparea1)) continue;
00143             //get area2 face flags
00144             area2faceflags |= face2->faceflags;
00145             if (AAS_GapFace(face2, side2)) area2faceflags |= FACE_GAP;
00146             //if the two faces would create a non-convex area
00147             if (NonConvex(face1, face2, side1, side2)) return false;
00148         } //end for
00149     } //end for
00150     //if one area has gap faces (that aren't seperating the two areas)
00151     //and the other has ground faces (that aren't seperating the two areas),
00152     //the areas can't be merged
00153     if (((area1faceflags & FACE_GROUND) && (area2faceflags & FACE_GAP)) ||
00154             ((area2faceflags & FACE_GROUND) && (area1faceflags & FACE_GAP)))
00155     {
00156 //      Log_Print("   can't merge: ground/gap\n");
00157         return false;
00158     } //end if
00159 
00160 //  Log_Print("merged area %d & %d to %d with %d faces\n", tmparea1->areanum, tmparea2->areanum, newarea->areanum, numfaces);
00161 //  return false;
00162     //
00163     //AAS_CheckArea(tmparea1);
00164     //AAS_CheckArea(tmparea2);
00165     //create the new area
00166     newarea = AAS_AllocTmpArea();
00167     newarea->presencetype = tmparea1->presencetype;
00168     newarea->contents = tmparea1->contents;
00169     newarea->modelnum = tmparea1->modelnum;
00170     newarea->tmpfaces = NULL;
00171 
00172     //add all the faces (except the seperating ones) from the first area
00173     //to the new area
00174     for (face1 = tmparea1->tmpfaces; face1; face1 = nextface1)
00175     {
00176         side1 = (face1->frontarea != tmparea1);
00177         nextface1 = face1->next[side1];
00178         //don't add seperating faces
00179         if ((face1->frontarea == tmparea1 &&
00180                 face1->backarea == tmparea2) ||
00181                 (face1->frontarea == tmparea2 &&
00182                 face1->backarea == tmparea1))
00183         {
00184             continue;
00185         } //end if
00186         //
00187         AAS_RemoveFaceFromArea(face1, tmparea1);
00188         AAS_AddFaceSideToArea(face1, side1, newarea);
00189     } //end for
00190     //add all the faces (except the seperating ones) from the second area
00191     //to the new area
00192     for (face2 = tmparea2->tmpfaces; face2; face2 = nextface2)
00193     {
00194         side2 = (face2->frontarea != tmparea2);
00195         nextface2 = face2->next[side2];
00196         //don't add seperating faces
00197         if ((face2->frontarea == tmparea1 &&
00198                 face2->backarea == tmparea2) ||
00199                 (face2->frontarea == tmparea2 &&
00200                 face2->backarea == tmparea1))
00201         {
00202             continue;
00203         } //end if
00204         //
00205         AAS_RemoveFaceFromArea(face2, tmparea2);
00206         AAS_AddFaceSideToArea(face2, side2, newarea);
00207     } //end for
00208     //free all shared faces
00209     for (face1 = tmparea1->tmpfaces; face1; face1 = nextface1)
00210     {
00211         side1 = (face1->frontarea != tmparea1);
00212         nextface1 = face1->next[side1];
00213         //
00214         AAS_RemoveFaceFromArea(face1, face1->frontarea);
00215         AAS_RemoveFaceFromArea(face1, face1->backarea);
00216         AAS_FreeTmpFace(face1);
00217     } //end for
00218     //
00219     tmparea1->mergedarea = newarea;
00220     tmparea1->invalid = true;
00221     tmparea2->mergedarea = newarea;
00222     tmparea2->invalid = true;
00223     //
00224     AAS_CheckArea(newarea);
00225     AAS_FlipAreaFaces(newarea);
00226 //  Log_Print("merged area %d & %d to %d with %d faces\n", tmparea1->areanum, tmparea2->areanum, newarea->areanum);
00227     return true;
00228 } //end of the function AAS_TryMergeFaceAreas
00229 //===========================================================================
00230 // try to merge areas
00231 // merged areas are added to the end of the convex area list so merging
00232 // will be tried for those areas as well
00233 //
00234 // Parameter:               -
00235 // Returns:                 -
00236 // Changes Globals:     tmpaasworld
00237 //===========================================================================
00238 /*
00239 void AAS_MergeAreas(void)
00240 {
00241     int side, nummerges;
00242     tmp_area_t *tmparea, *othertmparea;
00243     tmp_face_t *face;
00244 
00245     nummerges = 0;
00246     Log_Write("AAS_MergeAreas\r\n");
00247     qprintf("%6d areas merged", 1);
00248     //first merge grounded areas only
00249     //NOTE: this is useless because the area settings aren't available yet
00250     for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
00251     {
00252 //      Log_Print("checking area %d\n", i);
00253         //if the area is invalid
00254         if (tmparea->invalid)
00255         {
00256 //          Log_Print("   area invalid\n");
00257             continue;
00258         } //end if
00259         //
00260 //      if (!(tmparea->settings->areaflags & AREA_GROUNDED)) continue;
00261         //
00262         for (face = tmparea->tmpfaces; face; face = face->next[side])
00263         {
00264             side = (face->frontarea != tmparea);
00265             //if the face has both a front and back area
00266             if (face->frontarea && face->backarea)
00267             {
00268                 //
00269                 if (face->frontarea == tmparea) othertmparea = face->backarea;
00270                 else othertmparea = face->frontarea;
00271 //              if (!(othertmparea->settings->areaflags & AREA_GROUNDED)) continue;
00272 //              Log_Print("  checking area %d with %d\n", face->frontarea, face->backarea);
00273                 if (AAS_TryMergeFaceAreas(face))
00274                 {
00275                     qprintf("\r%6d", ++nummerges);
00276                     break;
00277                 } //end if
00278             } //end if
00279         } //end for
00280     } //end for
00281     //merge all areas
00282     for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
00283     {
00284 //      Log_Print("checking area %d\n", i);
00285         //if the area is invalid
00286         if (tmparea->invalid)
00287         {
00288 //          Log_Print("   area invalid\n");
00289             continue;
00290         } //end if
00291         //
00292         for (face = tmparea->tmpfaces; face; face = face->next[side])
00293         {
00294             side = (face->frontarea != tmparea);
00295             //if the face has both a front and back area
00296             if (face->frontarea && face->backarea)
00297             {
00298 //              Log_Print("  checking area %d with %d\n", face->frontarea, face->backarea);
00299                 if (AAS_TryMergeFaceAreas(face))
00300                 {
00301                     qprintf("\r%6d", ++nummerges);
00302                     break;
00303                 } //end if
00304             } //end if
00305         } //end for
00306     } //end for
00307     Log_Print("\r%6d areas merged\n", nummerges);
00308     //refresh the merged tree
00309     AAS_RefreshMergedTree_r(tmpaasworld.nodes);
00310 } //end of the function AAS_MergeAreas*/
00311 
00312 int AAS_GroundArea(tmp_area_t *tmparea)
00313 {
00314     tmp_face_t *face;
00315     int side;
00316 
00317     for (face = tmparea->tmpfaces; face; face = face->next[side])
00318     {
00319         side = (face->frontarea != tmparea);
00320         if (face->faceflags & FACE_GROUND) return true;
00321     } //end for
00322     return false;
00323 } //end of the function AAS_GroundArea
00324 
00325 void AAS_MergeAreas(void)
00326 {
00327     int side, nummerges, merges, groundfirst;
00328     tmp_area_t *tmparea, *othertmparea;
00329     tmp_face_t *face;
00330 
00331     nummerges = 0;
00332     Log_Write("AAS_MergeAreas\r\n");
00333     qprintf("%6d areas merged", 1);
00334     //
00335     groundfirst = true;
00336     //for (i = 0; i < 4 || merges; i++)
00337     while(1)
00338     {
00339         //if (i < 2) groundfirst = true;
00340         //else groundfirst = false;
00341         //
00342         merges = 0;
00343         //first merge grounded areas only
00344         for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
00345         {
00346             //if the area is invalid
00347             if (tmparea->invalid)
00348             {
00349                 continue;
00350             } //end if
00351             //
00352             if (groundfirst)
00353             {
00354                 if (!AAS_GroundArea(tmparea)) continue;
00355             } //end if
00356             //
00357             for (face = tmparea->tmpfaces; face; face = face->next[side])
00358             {
00359                 side = (face->frontarea != tmparea);
00360                 //if the face has both a front and back area
00361                 if (face->frontarea && face->backarea)
00362                 {
00363                     //
00364                     if (face->frontarea == tmparea) othertmparea = face->backarea;
00365                     else othertmparea = face->frontarea;
00366                     //
00367                     if (groundfirst)
00368                     {
00369                         if (!AAS_GroundArea(othertmparea)) continue;
00370                     } //end if
00371                     if (AAS_TryMergeFaceAreas(face))
00372                     {
00373                         qprintf("\r%6d", ++nummerges);
00374                         merges++;
00375                         break;
00376                     } //end if
00377                 } //end if
00378             } //end for
00379         } //end for
00380         if (!merges)
00381         {
00382             if (groundfirst) groundfirst = false;
00383             else break;
00384         } //end if
00385     } //end for
00386     qprintf("\n");
00387     Log_Write("%6d areas merged\r\n", nummerges);
00388     //refresh the merged tree
00389     AAS_RefreshMergedTree_r(tmpaasworld.nodes);
00390 } //end of the function AAS_MergeAreas

Generated on Thu Aug 25 12:37:13 2005 for Quake III Arena by  doxygen 1.3.9.1