📄 aas_gsubdiv.c
字号:
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "qbsp.h"
#include "../botlib/aasfile.h"
#include "aas_create.h"
#include "aas_store.h"
#include "aas_cfg.h"
#define FACECLIP_EPSILON 0.2
#define FACE_EPSILON 1.0
int numgravitationalsubdivisions = 0;
int numladdersubdivisions = 0;
//NOTE: only do gravitational subdivision BEFORE area merging!!!!!!!
// because the bsp tree isn't refreshes like with ladder subdivision
//===========================================================================
// NOTE: the original face is invalid after splitting
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_SplitFace(tmp_face_t *face, vec3_t normal, float dist,
tmp_face_t **frontface, tmp_face_t **backface)
{
winding_t *frontw, *backw;
//
*frontface = *backface = NULL;
ClipWindingEpsilon(face->winding, normal, dist, FACECLIP_EPSILON, &frontw, &backw);
#ifdef DEBUG
//
if (frontw)
{
if (WindingIsTiny(frontw))
{
Log_Write("AAS_SplitFace: tiny back face\r\n");
FreeWinding(frontw);
frontw = NULL;
} //end if
} //end if
if (backw)
{
if (WindingIsTiny(backw))
{
Log_Write("AAS_SplitFace: tiny back face\r\n");
FreeWinding(backw);
backw = NULL;
} //end if
} //end if
#endif //DEBUG
//if the winding was split
if (frontw)
{
//check bounds
(*frontface) = AAS_AllocTmpFace();
(*frontface)->planenum = face->planenum;
(*frontface)->winding = frontw;
(*frontface)->faceflags = face->faceflags;
} //end if
if (backw)
{
//check bounds
(*backface) = AAS_AllocTmpFace();
(*backface)->planenum = face->planenum;
(*backface)->winding = backw;
(*backface)->faceflags = face->faceflags;
} //end if
} //end of the function AAS_SplitFace
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
winding_t *AAS_SplitWinding(tmp_area_t *tmparea, int planenum)
{
tmp_face_t *face;
plane_t *plane;
int side;
winding_t *splitwinding;
//
plane = &mapplanes[planenum];
//create a split winding, first base winding for plane
splitwinding = BaseWindingForPlane(plane->normal, plane->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;
plane = &mapplanes[face->planenum ^ side];
ChopWindingInPlace(&splitwinding, plane->normal, plane->dist, 0); // PLANESIDE_EPSILON);
} //end for
return splitwinding;
} //end of the function AAS_SplitWinding
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_TestSplitPlane(tmp_area_t *tmparea, vec3_t normal, float dist,
int *facesplits, int *groundsplits, int *epsilonfaces)
{
int j, side, front, back, planenum;
float d, d_front, d_back;
tmp_face_t *face;
winding_t *w;
*facesplits = *groundsplits = *epsilonfaces = 0;
planenum = FindFloatPlane(normal, dist);
w = AAS_SplitWinding(tmparea, planenum);
if (!w) return false;
FreeWinding(w);
//
for (face = tmparea->tmpfaces; face; face = face->next[side])
{
//side of the face the area is on
side = face->frontarea != tmparea;
if ((face->planenum & ~1) == (planenum & ~1))
{
Log_Print("AAS_TestSplitPlane: tried face plane as splitter\n");
return false;
} //end if
w = face->winding;
//reset distance at front and back side of plane
d_front = d_back = 0;
//reset front and back flags
front = back = 0;
for (j = 0; j < w->numpoints; j++)
{
d = DotProduct(w->p[j], normal) - dist;
if (d > d_front) d_front = d;
if (d < d_back) d_back = d;
if (d > 0.4) // PLANESIDE_EPSILON)
front = 1;
if (d < -0.4) // PLANESIDE_EPSILON)
back = 1;
} //end for
//check for an epsilon face
if ( (d_front > FACECLIP_EPSILON && d_front < FACE_EPSILON)
|| (d_back < -FACECLIP_EPSILON && d_back > -FACE_EPSILON) )
{
(*epsilonfaces)++;
} //end if
//if the face has points at both sides of the plane
if (front && back)
{
(*facesplits)++;
if (face->faceflags & FACE_GROUND)
{
(*groundsplits)++;
} //end if
} //end if
} //end for
return true;
} //end of the function AAS_TestSplitPlane
//===========================================================================
//
// 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
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_FindBestAreaSplitPlane(tmp_area_t *tmparea, vec3_t normal, float *dist)
{
int side1, side2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -