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

aas_gsubdiv.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 #include "aas_cfg.h"
00028 
00029 #define FACECLIP_EPSILON            0.2
00030 #define FACE_EPSILON                    1.0
00031 
00032 int numgravitationalsubdivisions = 0;
00033 int numladdersubdivisions = 0;
00034 
00035 //NOTE: only do gravitational subdivision BEFORE area merging!!!!!!!
00036 //          because the bsp tree isn't refreshes like with ladder subdivision
00037 
00038 //===========================================================================
00039 // NOTE: the original face is invalid after splitting
00040 //
00041 // Parameter:               -
00042 // Returns:                 -
00043 // Changes Globals:     -
00044 //===========================================================================
00045 void AAS_SplitFace(tmp_face_t *face, vec3_t normal, float dist,
00046                             tmp_face_t **frontface, tmp_face_t **backface)
00047 {
00048     winding_t *frontw, *backw;
00049 
00050     //
00051     *frontface = *backface = NULL;
00052 
00053     ClipWindingEpsilon(face->winding, normal, dist, FACECLIP_EPSILON, &frontw, &backw);
00054 
00055 #ifdef DEBUG
00056     //
00057     if (frontw)
00058     {
00059         if (WindingIsTiny(frontw))
00060         {
00061             Log_Write("AAS_SplitFace: tiny back face\r\n");
00062             FreeWinding(frontw);
00063             frontw = NULL;
00064         } //end if
00065     } //end if
00066     if (backw)
00067     {
00068         if (WindingIsTiny(backw))
00069         {
00070             Log_Write("AAS_SplitFace: tiny back face\r\n");
00071             FreeWinding(backw);
00072             backw = NULL;
00073         } //end if
00074     } //end if
00075 #endif //DEBUG
00076     //if the winding was split
00077     if (frontw)
00078     {
00079         //check bounds
00080         (*frontface) = AAS_AllocTmpFace();
00081         (*frontface)->planenum = face->planenum;
00082         (*frontface)->winding = frontw;
00083         (*frontface)->faceflags = face->faceflags;
00084     } //end if
00085     if (backw)
00086     {
00087         //check bounds
00088         (*backface) = AAS_AllocTmpFace();
00089         (*backface)->planenum = face->planenum;
00090         (*backface)->winding = backw;
00091         (*backface)->faceflags = face->faceflags;
00092     } //end if
00093 } //end of the function AAS_SplitFace
00094 //===========================================================================
00095 //
00096 // Parameter:               -
00097 // Returns:                 -
00098 // Changes Globals:     -
00099 //===========================================================================
00100 winding_t *AAS_SplitWinding(tmp_area_t *tmparea, int planenum)
00101 {
00102     tmp_face_t *face;
00103     plane_t *plane;
00104     int side;
00105     winding_t *splitwinding;
00106 
00107     //
00108     plane = &mapplanes[planenum];
00109     //create a split winding, first base winding for plane
00110     splitwinding = BaseWindingForPlane(plane->normal, plane->dist);
00111     //chop with all the faces of the area
00112     for (face = tmparea->tmpfaces; face && splitwinding; face = face->next[side])
00113     {
00114         //side of the face the original area was on
00115         side = face->frontarea != tmparea;
00116         plane = &mapplanes[face->planenum ^ side];
00117         ChopWindingInPlace(&splitwinding, plane->normal, plane->dist, 0); // PLANESIDE_EPSILON);
00118     } //end for
00119     return splitwinding;
00120 } //end of the function AAS_SplitWinding
00121 //===========================================================================
00122 //
00123 // Parameter:               -
00124 // Returns:                 -
00125 // Changes Globals:     -
00126 //===========================================================================
00127 int AAS_TestSplitPlane(tmp_area_t *tmparea, vec3_t normal, float dist,
00128                             int *facesplits, int *groundsplits, int *epsilonfaces)
00129 {
00130     int j, side, front, back, planenum;
00131     float d, d_front, d_back;
00132     tmp_face_t *face;
00133     winding_t *w;
00134 
00135     *facesplits = *groundsplits = *epsilonfaces = 0;
00136 
00137     planenum = FindFloatPlane(normal, dist);
00138 
00139     w = AAS_SplitWinding(tmparea, planenum);
00140     if (!w) return false;
00141     FreeWinding(w);
00142     //
00143     for (face = tmparea->tmpfaces; face; face = face->next[side])
00144     {
00145         //side of the face the area is on
00146         side = face->frontarea != tmparea;
00147 
00148         if ((face->planenum & ~1) == (planenum & ~1))
00149         {
00150             Log_Print("AAS_TestSplitPlane: tried face plane as splitter\n");
00151             return false;
00152         } //end if
00153         w = face->winding;
00154         //reset distance at front and back side of plane
00155         d_front = d_back = 0;
00156         //reset front and back flags
00157         front = back = 0;
00158         for (j = 0; j < w->numpoints; j++)
00159         {
00160             d = DotProduct(w->p[j], normal) - dist;
00161             if (d > d_front) d_front = d;
00162             if (d < d_back) d_back = d;
00163 
00164             if (d > 0.4) // PLANESIDE_EPSILON)
00165                 front = 1;
00166             if (d < -0.4) // PLANESIDE_EPSILON)
00167                 back = 1;
00168         } //end for
00169         //check for an epsilon face
00170         if ( (d_front > FACECLIP_EPSILON && d_front < FACE_EPSILON)
00171             || (d_back < -FACECLIP_EPSILON && d_back > -FACE_EPSILON) )
00172         {
00173             (*epsilonfaces)++;
00174         } //end if
00175         //if the face has points at both sides of the plane
00176         if (front && back)
00177         {
00178             (*facesplits)++;
00179             if (face->faceflags & FACE_GROUND)
00180             {
00181                 (*groundsplits)++;
00182             } //end if
00183         } //end if
00184     } //end for
00185     return true;
00186 } //end of the function AAS_TestSplitPlane
00187 //===========================================================================
00188 //
00189 // Parameter:               -
00190 // Returns:                 -
00191 // Changes Globals:     -
00192 //===========================================================================
00193 void AAS_SplitArea(tmp_area_t *tmparea, int planenum, tmp_area_t **frontarea, tmp_area_t **backarea)
00194 {
00195     int side;
00196     tmp_area_t *facefrontarea, *facebackarea, *faceotherarea;
00197     tmp_face_t *face, *frontface, *backface, *splitface, *nextface;
00198     winding_t *splitwinding;
00199     plane_t *splitplane;
00200 
00201 /*
00202 #ifdef AW_DEBUG
00203     int facesplits, groundsplits, epsilonface;
00204     Log_Print("\n----------------------\n");
00205     Log_Print("splitting area %d\n", areanum);
00206     Log_Print("with normal = \'%f %f %f\', dist = %f\n", normal[0], normal[1], normal[2], dist);
00207     AAS_TestSplitPlane(areanum, normal, dist,
00208                                         &facesplits, &groundsplits, &epsilonface);
00209     Log_Print("face splits = %d\nground splits = %d\n", facesplits, groundsplits);
00210     if (epsilonface) Log_Print("aaahh epsilon face\n");
00211 #endif //AW_DEBUG*/
00212     //the original area
00213 
00214     AAS_FlipAreaFaces(tmparea);
00215     AAS_CheckArea(tmparea);
00216     //
00217     splitplane = &mapplanes[planenum];
00218 /*  //create a split winding, first base winding for plane
00219     splitwinding = BaseWindingForPlane(splitplane->normal, splitplane->dist);
00220     //chop with all the faces of the area
00221     for (face = tmparea->tmpfaces; face && splitwinding; face = face->next[side])
00222     {
00223         //side of the face the original area was on
00224         side = face->frontarea != tmparea->areanum;
00225         plane = &mapplanes[face->planenum ^ side];
00226         ChopWindingInPlace(&splitwinding, plane->normal, plane->dist, 0); // PLANESIDE_EPSILON);
00227     } //end for*/
00228     splitwinding = AAS_SplitWinding(tmparea, planenum);
00229     if (!splitwinding)
00230     {
00231 /*
00232 #ifdef DEBUG
00233         AAS_TestSplitPlane(areanum, normal, dist,
00234                                             &facesplits, &groundsplits, &epsilonface);
00235         Log_Print("\nface splits = %d\nground splits = %d\n", facesplits, groundsplits);
00236         if (epsilonface) Log_Print("aaahh epsilon face\n");
00237 #endif //DEBUG*/
00238         Error("AAS_SplitArea: no split winding when splitting area %d\n", tmparea->areanum);
00239     } //end if
00240     //create a split face
00241     splitface = AAS_AllocTmpFace();
00242     //get the map plane
00243     splitface->planenum = planenum;
00244     //store the split winding
00245     splitface->winding = splitwinding;
00246     //the new front area
00247     (*frontarea) = AAS_AllocTmpArea();
00248     (*frontarea)->presencetype = tmparea->presencetype;
00249     (*frontarea)->contents = tmparea->contents;
00250     (*frontarea)->modelnum = tmparea->modelnum;
00251     (*frontarea)->tmpfaces = NULL;
00252     //the new back area
00253     (*backarea) = AAS_AllocTmpArea();
00254     (*backarea)->presencetype = tmparea->presencetype;
00255     (*backarea)->contents = tmparea->contents;
00256     (*backarea)->modelnum = tmparea->modelnum;
00257     (*backarea)->tmpfaces = NULL;
00258     //add the split face to the new areas
00259     AAS_AddFaceSideToArea(splitface, 0, (*frontarea));
00260     AAS_AddFaceSideToArea(splitface, 1, (*backarea));
00261 
00262     //split all the faces of the original area
00263     for (face = tmparea->tmpfaces; face; face = nextface)
00264     {
00265         //side of the face the original area was on
00266         side = face->frontarea != tmparea;
00267         //next face of the original area
00268         nextface = face->next[side];
00269         //front area of the face
00270         facefrontarea = face->frontarea;
00271         //back area of the face
00272         facebackarea = face->backarea;
00273         //remove the face from both the front and back areas
00274         if (facefrontarea) AAS_RemoveFaceFromArea(face, facefrontarea);
00275         if (facebackarea) AAS_RemoveFaceFromArea(face, facebackarea);
00276         //split the face
00277         AAS_SplitFace(face, splitplane->normal, splitplane->dist, &frontface, &backface);
00278         //free the original face
00279         AAS_FreeTmpFace(face);
00280         //get the number of the area at the other side of the face
00281         if (side) faceotherarea = facefrontarea;
00282         else faceotherarea = facebackarea;
00283         //if there is an area at the other side of the original face
00284         if (faceotherarea)
00285         {
00286             if (frontface) AAS_AddFaceSideToArea(frontface, !side, faceotherarea);
00287             if (backface) AAS_AddFaceSideToArea(backface, !side, faceotherarea);
00288         } //end if
00289         //add the front and back part left after splitting the original face to the new areas
00290         if (frontface) AAS_AddFaceSideToArea(frontface, side, (*frontarea));
00291         if (backface) AAS_AddFaceSideToArea(backface, side, (*backarea));
00292     } //end for
00293 
00294     if (!(*frontarea)->tmpfaces) Log_Print("AAS_SplitArea: front area without faces\n");
00295     if (!(*backarea)->tmpfaces) Log_Print("AAS_SplitArea: back area without faces\n");
00296 
00297     tmparea->invalid = true;
00298 /*
00299 #ifdef AW_DEBUG
00300     for (i = 0, face = frontarea->tmpfaces; face; face = face->next[side])
00301     {
00302         side = face->frontarea != frontarea->areanum;
00303         i++;
00304     } //end for
00305     Log_Print("created front area %d with %d faces\n", frontarea->areanum, i);
00306 
00307     for (i = 0, face = backarea->tmpfaces; face; face = face->next[side])
00308     {
00309         side = face->frontarea != backarea->areanum;
00310         i++;
00311     } //end for
00312     Log_Print("created back area %d with %d faces\n", backarea->areanum, i);
00313 #endif //AW_DEBUG*/
00314 
00315     AAS_FlipAreaFaces((*frontarea));
00316     AAS_FlipAreaFaces((*backarea));
00317     //
00318     AAS_CheckArea((*frontarea));
00319     AAS_CheckArea((*backarea));
00320 } //end of the function AAS_SplitArea
00321 //===========================================================================
00322 //
00323 // Parameter:               -
00324 // Returns:                 -
00325 // Changes Globals:     -
00326 //===========================================================================
00327 int AAS_FindBestAreaSplitPlane(tmp_area_t *tmparea, vec3_t normal, float *dist)
00328 {
00329     int side1, side2;
00330     int foundsplitter, facesplits, groundsplits, epsilonfaces, bestepsilonfaces;
00331     float bestvalue, value;
00332     tmp_face_t *face1, *face2;
00333     vec3_t tmpnormal, invgravity;
00334     float tmpdist;
00335 
00336     //get inverse of gravity direction
00337     VectorCopy(cfg.phys_gravitydirection, invgravity);
00338     VectorInverse(invgravity);
00339 
00340     foundsplitter = false;
00341     bestvalue = -999999;
00342     bestepsilonfaces = 0;
00343     //
00344 #ifdef AW_DEBUG
00345     Log_Print("finding split plane for area %d\n", tmparea->areanum);
00346 #endif //AW_DEBUG
00347     for (face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1])
00348     {
00349         //side of the face the area is on
00350         side1 = face1->frontarea != tmparea;
00351         //
00352         if (WindingIsTiny(face1->winding))
00353         {
00354             Log_Write("gsubdiv: area %d has a tiny winding\r\n", tmparea->areanum);
00355             continue;
00356         } //end if
00357         //if the face isn't a gap or ground there's no split edge
00358         if (!(face1->faceflags & FACE_GROUND) && !AAS_GapFace(face1, side1)) continue;
00359         //
00360         for (face2 = face1->next[side1]; face2; face2 = face2->next[side2])
00361         {
00362             //side of the face the area is on
00363             side2 = face2->frontarea != tmparea;
00364             //
00365             if (WindingIsTiny(face1->winding))
00366             {
00367                 Log_Write("gsubdiv: area %d has a tiny winding\r\n", tmparea->areanum);
00368                 continue;
00369             } //end if
00370             //if the face isn't a gap or ground there's no split edge
00371             if (!(face2->faceflags & FACE_GROUND) && !AAS_GapFace(face2, side2)) continue;
00372             //only split between gaps and ground
00373             if (!(((face1->faceflags & FACE_GROUND) && AAS_GapFace(face2, side2)) ||
00374                     ((face2->faceflags & FACE_GROUND) && AAS_GapFace(face1, side1)))) continue;
00375             //find a plane seperating the windings of the faces
00376             if (!FindPlaneSeperatingWindings(face1->winding, face2->winding, invgravity,
00377                                                         tmpnormal, &tmpdist)) continue;
00378 #ifdef AW_DEBUG
00379             Log_Print("normal = \'%f %f %f\', dist = %f\n",
00380                             tmpnormal[0], tmpnormal[1], tmpnormal[2], tmpdist);
00381 #endif //AW_DEBUG
00382             //get metrics for this vertical plane
00383             if (!AAS_TestSplitPlane(tmparea, tmpnormal, tmpdist,
00384                                         &facesplits, &groundsplits, &epsilonfaces))
00385             {
00386                 continue;
00387             } //end if
00388 #ifdef AW_DEBUG
00389             Log_Print("face splits = %d\nground splits = %d\n",
00390                             facesplits, groundsplits);
00391 #endif //AW_DEBUG
00392             value = 100 - facesplits - 2 * groundsplits;
00393             //avoid epsilon faces
00394             value += epsilonfaces * -1000;
00395             if (value > bestvalue)
00396             {
00397                 VectorCopy(tmpnormal, normal);
00398                 *dist = tmpdist;
00399                 bestvalue = value;
00400                 bestepsilonfaces = epsilonfaces;
00401                 foundsplitter = true;
00402             } //end if
00403         } //end for
00404     } //end for
00405     if (bestepsilonfaces)
00406     {
00407         Log_Write("found %d epsilon faces trying to split area %d\r\n",
00408                                     epsilonfaces, tmparea->areanum);
00409     } //end else
00410     return foundsplitter;
00411 } //end of the function AAS_FindBestAreaSplitPlane
00412 //===========================================================================
00413 //
00414 // Parameter:               -
00415 // Returns:                 -
00416 // Changes Globals:     -
00417 //===========================================================================
00418 tmp_node_t *AAS_SubdivideArea_r(tmp_node_t *tmpnode)
00419 {
00420     int planenum;
00421     tmp_area_t *frontarea, *backarea;
00422     tmp_node_t *tmpnode1, *tmpnode2;
00423     vec3_t normal;
00424     float dist;
00425 
00426     if (AAS_FindBestAreaSplitPlane(tmpnode->tmparea, normal, &dist))
00427     {
00428         qprintf("\r%6d", ++numgravitationalsubdivisions);
00429         //
00430         planenum = FindFloatPlane(normal, dist);
00431         //split the area
00432         AAS_SplitArea(tmpnode->tmparea, planenum, &frontarea, &backarea);
00433         //
00434         tmpnode->tmparea = NULL;
00435         tmpnode->planenum = FindFloatPlane(normal, dist);
00436         //
00437         tmpnode1 = AAS_AllocTmpNode();
00438         tmpnode1->planenum = 0;
00439         tmpnode1->tmparea = frontarea;
00440         //
00441         tmpnode2 = AAS_AllocTmpNode();
00442         tmpnode2->planenum = 0;
00443         tmpnode2->tmparea = backarea;
00444         //subdivide the areas created by splitting recursively
00445         tmpnode->children[0] = AAS_SubdivideArea_r(tmpnode1);
00446         tmpnode->children[1] = AAS_SubdivideArea_r(tmpnode2);
00447     } //end if
00448     return tmpnode;
00449 } //end of the function AAS_SubdivideArea_r
00450 //===========================================================================
00451 //
00452 // Parameter:               -
00453 // Returns:                 -
00454 // Changes Globals:     -
00455 //===========================================================================
00456 tmp_node_t *AAS_GravitationalSubdivision_r(tmp_node_t *tmpnode)
00457 {
00458     //if this is a solid leaf
00459     if (!tmpnode) return NULL;
00460     //negative so it's an area
00461     if (tmpnode->tmparea) return AAS_SubdivideArea_r(tmpnode);
00462     //do the children recursively
00463     tmpnode->children[0] = AAS_GravitationalSubdivision_r(tmpnode->children[0]);
00464     tmpnode->children[1] = AAS_GravitationalSubdivision_r(tmpnode->children[1]);
00465     return tmpnode;
00466 } //end of the function AAS_GravitationalSubdivision_r
00467 //===========================================================================
00468 // NOTE: merge faces and melt edges first
00469 //
00470 // Parameter:               -
00471 // Returns:                 -
00472 // Changes Globals:     -
00473 //===========================================================================
00474 void AAS_GravitationalSubdivision(void)
00475 {
00476     Log_Write("AAS_GravitationalSubdivision\r\n");
00477     numgravitationalsubdivisions = 0;
00478     qprintf("%6i gravitational subdivisions", numgravitationalsubdivisions);
00479     //start with the head node
00480     AAS_GravitationalSubdivision_r(tmpaasworld.nodes);
00481     qprintf("\n");
00482     Log_Write("%6i gravitational subdivisions\r\n", numgravitationalsubdivisions);
00483 } //end of the function AAS_GravitationalSubdivision
00484 //===========================================================================
00485 //
00486 // Parameter:               -
00487 // Returns:                 -
00488 // Changes Globals:     -
00489 //===========================================================================
00490 tmp_node_t *AAS_RefreshLadderSubdividedTree_r(tmp_node_t *tmpnode, tmp_area_t *tmparea,
00491                                                   tmp_node_t *tmpnode1, tmp_node_t *tmpnode2, int planenum)
00492 {
00493     //if this is a solid leaf
00494     if (!tmpnode) return NULL;
00495     //negative so it's an area
00496     if (tmpnode->tmparea)
00497     {
00498         if (tmpnode->tmparea == tmparea)
00499         {
00500             tmpnode->tmparea = NULL;
00501             tmpnode->planenum = planenum;
00502             tmpnode->children[0] = tmpnode1;
00503             tmpnode->children[1] = tmpnode2;
00504         } //end if
00505         return tmpnode;
00506     } //end if
00507     //do the children recursively
00508     tmpnode->children[0] = AAS_RefreshLadderSubdividedTree_r(tmpnode->children[0],
00509                                     tmparea, tmpnode1, tmpnode2, planenum);
00510     tmpnode->children[1] = AAS_RefreshLadderSubdividedTree_r(tmpnode->children[1],
00511                                     tmparea, tmpnode1, tmpnode2, planenum);
00512     return tmpnode;
00513 } //end of the function AAS_RefreshLadderSubdividedTree_r
00514 //===========================================================================
00515 // find an area with ladder faces and ground faces that are not connected
00516 // split the area with a horizontal plane at the lowest vertex of all
00517 // ladder faces in the area
00518 //
00519 // Parameter:               -
00520 // Returns:                 -
00521 // Changes Globals:     -
00522 //===========================================================================
00523 tmp_node_t *AAS_LadderSubdivideArea_r(tmp_node_t *tmpnode)
00524 {
00525     int side1, i, planenum;
00526     int foundladderface, foundgroundface;
00527     float dist;
00528     tmp_area_t *tmparea, *frontarea, *backarea;
00529     tmp_face_t *face1;
00530     tmp_node_t *tmpnode1, *tmpnode2;
00531     vec3_t lowestpoint, normal = {0, 0, 1};
00532     plane_t *plane;
00533     winding_t *w;
00534 
00535     tmparea = tmpnode->tmparea;
00536     //skip areas with a liquid
00537     if (tmparea->contents & (AREACONTENTS_WATER
00538                                     | AREACONTENTS_LAVA
00539                                     | AREACONTENTS_SLIME)) return tmpnode;
00540     //must be possible to stand in the area
00541     if (!(tmparea->presencetype & PRESENCE_NORMAL)) return tmpnode;
00542     //
00543     foundladderface = false;
00544     foundgroundface = false;
00545     lowestpoint[2] = 99999;
00546     //
00547     for (face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1])
00548     {
00549         //side of the face the area is on
00550         side1 = face1->frontarea != tmparea;
00551         //if the face is a ladder face
00552         if (face1->faceflags & FACE_LADDER)
00553         {
00554             plane = &mapplanes[face1->planenum];
00555             //the ladder face plane should be pretty much vertical
00556             if (DotProduct(plane->normal, normal) > -0.1)
00557             {
00558                 foundladderface = true;
00559                 //find lowest point
00560                 for (i = 0; i < face1->winding->numpoints; i++)
00561                 {
00562                     if (face1->winding->p[i][2] < lowestpoint[2])
00563                     {
00564                         VectorCopy(face1->winding->p[i], lowestpoint);
00565                     } //end if
00566                 } //end for
00567             } //end if
00568         } //end if
00569         else if (face1->faceflags & FACE_GROUND)
00570         {
00571             foundgroundface = true;
00572         } //end else if
00573     } //end for
00574     //
00575     if ((!foundladderface) || (!foundgroundface)) return tmpnode;
00576     //
00577     for (face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1])
00578     {
00579         //side of the face the area is on
00580         side1 = face1->frontarea != tmparea;
00581         //if the face isn't a ground face
00582         if (!(face1->faceflags & FACE_GROUND)) continue;
00583         //the ground plane
00584         plane = &mapplanes[face1->planenum];
00585         //get the difference between the ground plane and the lowest point
00586         dist = DotProduct(plane->normal, lowestpoint) - plane->dist;
00587         //if the lowest point is very near one of the ground planes
00588         if (dist > -1 && dist < 1)
00589         {
00590             return tmpnode;
00591         } //end if
00592     } //end for
00593     //
00594     dist = DotProduct(normal, lowestpoint);
00595     planenum = FindFloatPlane(normal, dist);
00596     //
00597     w = AAS_SplitWinding(tmparea, planenum);
00598     if (!w) return tmpnode;
00599     FreeWinding(w);
00600     //split the area with a horizontal plane through the lowest point
00601     qprintf("\r%6d", ++numladdersubdivisions);
00602     //
00603     AAS_SplitArea(tmparea, planenum, &frontarea, &backarea);
00604     //
00605     tmpnode->tmparea = NULL;
00606     tmpnode->planenum = planenum;
00607     //
00608     tmpnode1 = AAS_AllocTmpNode();
00609     tmpnode1->planenum = 0;
00610     tmpnode1->tmparea = frontarea;
00611     //
00612     tmpnode2 = AAS_AllocTmpNode();
00613     tmpnode2->planenum = 0;
00614     tmpnode2->tmparea = backarea;
00615     //subdivide the areas created by splitting recursively
00616     tmpnode->children[0] = AAS_LadderSubdivideArea_r(tmpnode1);
00617     tmpnode->children[1] = AAS_LadderSubdivideArea_r(tmpnode2);
00618     //refresh the tree
00619     AAS_RefreshLadderSubdividedTree_r(tmpaasworld.nodes, tmparea, tmpnode1, tmpnode2, planenum);
00620     //
00621     return tmpnode;
00622 } //end of the function AAS_LadderSubdivideArea_r
00623 //===========================================================================
00624 //
00625 // Parameter:               -
00626 // Returns:                 -
00627 // Changes Globals:     -
00628 //===========================================================================
00629 tmp_node_t *AAS_LadderSubdivision_r(tmp_node_t *tmpnode)
00630 {
00631     //if this is a solid leaf
00632     if (!tmpnode) return 0;
00633     //negative so it's an area
00634     if (tmpnode->tmparea) return AAS_LadderSubdivideArea_r(tmpnode);
00635     //do the children recursively
00636     tmpnode->children[0] = AAS_LadderSubdivision_r(tmpnode->children[0]);
00637     tmpnode->children[1] = AAS_LadderSubdivision_r(tmpnode->children[1]);
00638     return tmpnode;
00639 } //end of the function AAS_LadderSubdivision_r
00640 //===========================================================================
00641 //
00642 // Parameter:               -
00643 // Returns:                 -
00644 // Changes Globals:     -
00645 //===========================================================================
00646 void AAS_LadderSubdivision(void)
00647 {
00648     Log_Write("AAS_LadderSubdivision\r\n");
00649     numladdersubdivisions = 0;
00650     qprintf("%6i ladder subdivisions", numladdersubdivisions);
00651     //start with the head node
00652     AAS_LadderSubdivision_r(tmpaasworld.nodes);
00653     //
00654     qprintf("\n");
00655     Log_Write("%6i ladder subdivisions\r\n", numladdersubdivisions);
00656 } //end of the function AAS_LadderSubdivision

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