123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143 |
- /*
- ===========================================================================
- 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_gsubdiv.h"
- #include "aas_facemerging.h"
- #include "aas_areamerging.h"
- #include "aas_edgemelting.h"
- #include "aas_prunenodes.h"
- #include "aas_cfg.h"
- #include "../game/surfaceflags.h"
- //#define AW_DEBUG
- //#define L_DEBUG
- #define AREAONFACESIDE(face, area) (face->frontarea != area)
- tmp_aas_t tmpaasworld;
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void AAS_InitTmpAAS(void)
- {
- //tmp faces
- tmpaasworld.numfaces = 0;
- tmpaasworld.facenum = 0;
- tmpaasworld.faces = NULL;
- //tmp convex areas
- tmpaasworld.numareas = 0;
- tmpaasworld.areanum = 0;
- tmpaasworld.areas = NULL;
- //tmp nodes
- tmpaasworld.numnodes = 0;
- tmpaasworld.nodes = NULL;
- //
- tmpaasworld.nodebuffer = NULL;
- } //end of the function AAS_InitTmpAAS
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void AAS_FreeTmpAAS(void)
- {
- tmp_face_t *f, *nextf;
- tmp_area_t *a, *nexta;
- tmp_nodebuf_t *nb, *nextnb;
- //free all the faces
- for (f = tmpaasworld.faces; f; f = nextf)
- {
- nextf = f->l_next;
- if (f->winding) FreeWinding(f->winding);
- FreeMemory(f);
- } //end if
- //free all tmp areas
- for (a = tmpaasworld.areas; a; a = nexta)
- {
- nexta = a->l_next;
- if (a->settings) FreeMemory(a->settings);
- FreeMemory(a);
- } //end for
- //free all the tmp nodes
- for (nb = tmpaasworld.nodebuffer; nb; nb = nextnb)
- {
- nextnb = nb->next;
- FreeMemory(nb);
- } //end for
- } //end of the function AAS_FreeTmpAAS
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- tmp_face_t *AAS_AllocTmpFace(void)
- {
- tmp_face_t *tmpface;
- tmpface = (tmp_face_t *) GetClearedMemory(sizeof(tmp_face_t));
- tmpface->num = tmpaasworld.facenum++;
- tmpface->l_prev = NULL;
- tmpface->l_next = tmpaasworld.faces;
- if (tmpaasworld.faces) tmpaasworld.faces->l_prev = tmpface;
- tmpaasworld.faces = tmpface;
- tmpaasworld.numfaces++;
- return tmpface;
- } //end of the function AAS_AllocTmpFace
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void AAS_FreeTmpFace(tmp_face_t *tmpface)
- {
- if (tmpface->l_next) tmpface->l_next->l_prev = tmpface->l_prev;
- if (tmpface->l_prev) tmpface->l_prev->l_next = tmpface->l_next;
- else tmpaasworld.faces = tmpface->l_next;
- //free the winding
- if (tmpface->winding) FreeWinding(tmpface->winding);
- //free the face
- FreeMemory(tmpface);
- tmpaasworld.numfaces--;
- } //end of the function AAS_FreeTmpFace
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- tmp_area_t *AAS_AllocTmpArea(void)
- {
- tmp_area_t *tmparea;
- tmparea = (tmp_area_t *) GetClearedMemory(sizeof(tmp_area_t));
- tmparea->areanum = tmpaasworld.areanum++;
- tmparea->l_prev = NULL;
- tmparea->l_next = tmpaasworld.areas;
- if (tmpaasworld.areas) tmpaasworld.areas->l_prev = tmparea;
- tmpaasworld.areas = tmparea;
- tmpaasworld.numareas++;
- return tmparea;
- } //end of the function AAS_AllocTmpArea
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void AAS_FreeTmpArea(tmp_area_t *tmparea)
- {
- if (tmparea->l_next) tmparea->l_next->l_prev = tmparea->l_prev;
- if (tmparea->l_prev) tmparea->l_prev->l_next = tmparea->l_next;
- else tmpaasworld.areas = tmparea->l_next;
- if (tmparea->settings) FreeMemory(tmparea->settings);
- FreeMemory(tmparea);
- tmpaasworld.numareas--;
- } //end of the function AAS_FreeTmpArea
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- tmp_node_t *AAS_AllocTmpNode(void)
- {
- tmp_nodebuf_t *nodebuf;
- if (!tmpaasworld.nodebuffer ||
- tmpaasworld.nodebuffer->numnodes >= NODEBUF_SIZE)
- {
- nodebuf = (tmp_nodebuf_t *) GetClearedMemory(sizeof(tmp_nodebuf_t));
- nodebuf->next = tmpaasworld.nodebuffer;
- nodebuf->numnodes = 0;
- tmpaasworld.nodebuffer = nodebuf;
- } //end if
- tmpaasworld.numnodes++;
- return &tmpaasworld.nodebuffer->nodes[tmpaasworld.nodebuffer->numnodes++];
- } //end of the function AAS_AllocTmpNode
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void AAS_FreeTmpNode(tmp_node_t *tmpnode)
- {
- tmpaasworld.numnodes--;
- } //end of the function AAS_FreeTmpNode
- //===========================================================================
- // returns true if the face is a gap from the given side
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- int AAS_GapFace(tmp_face_t *tmpface, int side)
- {
- vec3_t invgravity;
- //if the face is a solid or ground face it can't be a gap
- if (tmpface->faceflags & (FACE_GROUND | FACE_SOLID)) return 0;
- VectorCopy(cfg.phys_gravitydirection, invgravity);
- VectorInverse(invgravity);
- return (DotProduct(invgravity, mapplanes[tmpface->planenum ^ side].normal) > cfg.phys_maxsteepness);
- } //end of the function AAS_GapFace
- //===========================================================================
- // returns true if the face is a ground face
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- int AAS_GroundFace(tmp_face_t *tmpface)
- {
- vec3_t invgravity;
- //must be a solid face
- if (!(tmpface->faceflags & FACE_SOLID)) return 0;
- VectorCopy(cfg.phys_gravitydirection, invgravity);
- VectorInverse(invgravity);
- return (DotProduct(invgravity, mapplanes[tmpface->planenum].normal) > cfg.phys_maxsteepness);
- } //end of the function AAS_GroundFace
- //===========================================================================
- // adds the side of a face to an area
- //
- // side : 0 = front side
- // 1 = back side
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void AAS_AddFaceSideToArea(tmp_face_t *tmpface, int side, tmp_area_t *tmparea)
- {
- int tmpfaceside;
- if (side)
- {
- if (tmpface->backarea) Error("AAS_AddFaceSideToArea: already a back area\n");
- } //end if
- else
- {
- if (tmpface->frontarea) Error("AAS_AddFaceSideToArea: already a front area\n");
- } //end else
- if (side) tmpface->backarea = tmparea;
- else tmpface->frontarea = tmparea;
- if (tmparea->tmpfaces)
- {
- tmpfaceside = tmparea->tmpfaces->frontarea != tmparea;
- tmparea->tmpfaces->prev[tmpfaceside] = tmpface;
- } //end if
- tmpface->next[side] = tmparea->tmpfaces;
- tmpface->prev[side] = NULL;
- tmparea->tmpfaces = tmpface;
- } //end of the function AAS_AddFaceSideToArea
- //===========================================================================
- // remove (a side of) a face from an area
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void AAS_RemoveFaceFromArea(tmp_face_t *tmpface, tmp_area_t *tmparea)
- {
- int side, prevside, nextside;
- if (tmpface->frontarea != tmparea &&
- tmpface->backarea != tmparea)
- {
- Error("AAS_RemoveFaceFromArea: face not part of the area");
- } //end if
- side = tmpface->frontarea != tmparea;
- if (tmpface->prev[side])
- {
- prevside = tmpface->prev[side]->frontarea != tmparea;
- tmpface->prev[side]->next[prevside] = tmpface->next[side];
- } //end if
- else
- {
- tmparea->tmpfaces = tmpface->next[side];
- } //end else
- if (tmpface->next[side])
- {
- nextside = tmpface->next[side]->frontarea != tmparea;
- tmpface->next[side]->prev[nextside] = tmpface->prev[side];
- } //end if
- //remove the area number from the face depending on the side
- if (side) tmpface->backarea = NULL;
- else tmpface->frontarea = NULL;
- tmpface->prev[side] = NULL;
- tmpface->next[side] = NULL;
- } //end of the function AAS_RemoveFaceFromArea
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void AAS_CheckArea(tmp_area_t *tmparea)
- {
- int side;
- tmp_face_t *face;
- plane_t *plane;
- vec3_t wcenter, acenter = {0, 0, 0};
- vec3_t normal;
- float n, dist;
- if (tmparea->invalid) Log_Print("AAS_CheckArea: invalid area\n");
- for (n = 0, face = tmparea->tmpfaces; face; face = face->next[side])
- {
- //side of the face the area is on
- side = face->frontarea != tmparea;
- WindingCenter(face->winding, wcenter);
- VectorAdd(acenter, wcenter, acenter);
- n++;
- } //end for
- n = 1 / n;
- VectorScale(acenter, n, acenter);
- for (face = tmparea->tmpfaces; face; face = face->next[side])
- {
- //side of the face the area is on
- side = face->frontarea != tmparea;
- #ifdef L_DEBUG
- if (WindingError(face->winding))
- {
- Log_Write("AAS_CheckArea: area %d face %d: %s\r\n", tmparea->areanum,
- face->num, WindingErrorString());
- } //end if
- #endif L_DEBUG
- plane = &mapplanes[face->planenum ^ side];
- if (DotProduct(plane->normal, acenter) - plane->dist < 0)
- {
- Log_Print("AAS_CheckArea: area %d face %d is flipped\n", tmparea->areanum, face->num);
- Log_Print("AAS_CheckArea: area %d center is %f %f %f\n", tmparea->areanum, acenter[0], acenter[1], acenter[2]);
- } //end if
- //check if the winding plane is the same as the face plane
- WindingPlane(face->winding, normal, &dist);
- plane = &mapplanes[face->planenum];
- #ifdef L_DEBUG
- if (fabs(dist - plane->dist) > 0.4 ||
- fabs(normal[0] - plane->normal[0]) > 0.0001 ||
- fabs(normal[1] - plane->normal[1]) > 0.0001 ||
- fabs(normal[2] - plane->normal[2]) > 0.0001)
- {
- Log_Write("AAS_CheckArea: area %d face %d winding plane unequal to face plane\r\n",
- tmparea->areanum, face->num);
- } //end if
- #endif L_DEBUG
- } //end for
- } //end of the function AAS_CheckArea
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void AAS_CheckFaceWindingPlane(tmp_face_t *face)
- {
- float dist, sign1, sign2;
- vec3_t normal;
- plane_t *plane;
- winding_t *w;
- //check if the winding plane is the same as the face plane
- WindingPlane(face->winding, normal, &dist);
- plane = &mapplanes[face->planenum];
- //
- sign1 = DotProduct(plane->normal, normal);
- //
- if (fabs(dist - plane->dist) > 0.4 ||
- fabs(normal[0] - plane->normal[0]) > 0.0001 ||
- fabs(normal[1] - plane->normal[1]) > 0.0001 ||
- fabs(normal[2] - plane->normal[2]) > 0.0001)
- {
- VectorInverse(normal);
- dist = -dist;
- if (fabs(dist - plane->dist) > 0.4 ||
- fabs(normal[0] - plane->normal[0]) > 0.0001 ||
- fabs(normal[1] - plane->normal[1]) > 0.0001 ||
- fabs(normal[2] - plane->normal[2]) > 0.0001)
- {
- Log_Write("AAS_CheckFaceWindingPlane: face %d winding plane unequal to face plane\r\n",
- face->num);
- //
- sign2 = DotProduct(plane->normal, normal);
- if ((sign1 < 0 && sign2 > 0) ||
- (sign1 > 0 && sign2 < 0))
- {
- Log_Write("AAS_CheckFaceWindingPlane: face %d winding reversed\r\n",
- face->num);
- w = face->winding;
- face->winding = ReverseWinding(w);
- FreeWinding(w);
- } //end if
- } //end if
- else
- {
- Log_Write("AAS_CheckFaceWindingPlane: face %d winding reversed\r\n",
- face->num);
- w = face->winding;
- face->winding = ReverseWinding(w);
- FreeWinding(w);
- } //end else
- } //end if
- } //end of the function AAS_CheckFaceWindingPlane
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void AAS_CheckAreaWindingPlanes(void)
- {
- int side;
- tmp_area_t *tmparea;
- tmp_face_t *face;
- Log_Write("AAS_CheckAreaWindingPlanes:\r\n");
- for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
- {
- if (tmparea->invalid) continue;
- for (face = tmparea->tmpfaces; face; face = face->next[side])
- {
- side = face->frontarea != tmparea;
- AAS_CheckFaceWindingPlane(face);
- } //end for
- } //end for
- } //end of the function AAS_CheckAreaWindingPlanes
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void AAS_FlipAreaFaces(tmp_area_t *tmparea)
- {
- int side;
- tmp_face_t *face;
- plane_t *plane;
- vec3_t wcenter, acenter = {0, 0, 0};
- //winding_t *w;
- float n;
- for (n = 0, face = tmparea->tmpfaces; face; face = face->next[side])
- {
- if (!face->frontarea) Error("face %d has no front area\n", face->num);
- //side of the face the area is on
- side = face->frontarea != tmparea;
- WindingCenter(face->winding, wcenter);
- VectorAdd(acenter, wcenter, acenter);
- n++;
- } //end for
- n = 1 / n;
- VectorScale(acenter, n, acenter);
- for (face = tmparea->tmpfaces; face; face = face->next[side])
- {
- //side of the face the area is on
- side = face->frontarea != tmparea;
- plane = &mapplanes[face->planenum ^ side];
- if (DotProduct(plane->normal, acenter) - plane->dist < 0)
- {
- Log_Print("area %d face %d flipped: front area %d, back area %d\n", tmparea->areanum, face->num,
- face->frontarea ? face->frontarea->areanum : 0,
- face->backarea ? face->backarea->areanum : 0);
- /*
- face->planenum = face->planenum ^ 1;
- w = face->winding;
- face->winding = ReverseWinding(w);
- FreeWinding(w);
- */
- } //end if
- #ifdef L_DEBUG
- {
- float dist;
- vec3_t normal;
- //check if the winding plane is the same as the face plane
- WindingPlane(face->winding, normal, &dist);
- plane = &mapplanes[face->planenum];
- if (fabs(dist - plane->dist) > 0.4 ||
- fabs(normal[0] - plane->normal[0]) > 0.0001 ||
- fabs(normal[1] - plane->normal[1]) > 0.0001 ||
- fabs(normal[2] - plane->normal[2]) > 0.0001)
- {
- Log_Write("area %d face %d winding plane unequal to face plane\r\n",
- tmparea->areanum, face->num);
- } //end if
- }
- #endif
- } //end for
- } //end of the function AAS_FlipAreaFaces
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void AAS_RemoveAreaFaceColinearPoints(void)
- {
- int side;
- tmp_face_t *face;
- tmp_area_t *tmparea;
- //FIXME: loop over the faces instead of area->faces
- for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
- {
- for (face = tmparea->tmpfaces; face; face = face->next[side])
- {
- side = face->frontarea != tmparea;
- RemoveColinearPoints(face->winding);
- // RemoveEqualPoints(face->winding, 0.1);
- } //end for
- } //end for
- } //end of the function AAS_RemoveAreaFaceColinearPoints
- //===========================================================================
- //
- // 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_CreateAreaSettings(void)
- {
- int i, flags, side, numgrounded, numladderareas, numliquidareas;
- tmp_face_t *face;
- tmp_area_t *tmparea;
- numgrounded = 0;
- numladderareas = 0;
- numliquidareas = 0;
- Log_Write("AAS_CreateAreaSettings\r\n");
- i = 0;
- qprintf("%6d areas provided with settings", i);
- for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
- {
- //if the area is invalid there no need to create settings for it
- if (tmparea->invalid) continue;
- tmparea->settings = (tmp_areasettings_t *) GetClearedMemory(sizeof(tmp_areasettings_t));
- tmparea->settings->contents = tmparea->contents;
- tmparea->settings->modelnum = tmparea->modelnum;
- flags = 0;
- for (face = tmparea->tmpfaces; face; face = face->next[side])
- {
- side = face->frontarea != tmparea;
- flags |= face->faceflags;
- } //end for
- tmparea->settings->areaflags = 0;
- if (flags & FACE_GROUND)
- {
- tmparea->settings->areaflags |= AREA_GROUNDED;
- numgrounded++;
- } //end if
- if (flags & FACE_LADDER)
- {
- tmparea->settings->areaflags |= AREA_LADDER;
- numladderareas++;
- } //end if
- if (tmparea->contents & (AREACONTENTS_WATER |
- AREACONTENTS_SLIME |
- AREACONTENTS_LAVA))
- {
- tmparea->settings->areaflags |= AREA_LIQUID;
- numliquidareas++;
- } //end if
- //presence type of the area
- tmparea->settings->presencetype = tmparea->presencetype;
- //
- qprintf("\r%6d", ++i);
- } //end for
- qprintf("\n");
- #ifdef AASINFO
- Log_Print("%6d grounded areas\n", numgrounded);
- Log_Print("%6d ladder areas\n", numladderareas);
- Log_Print("%6d liquid areas\n", numliquidareas);
- #endif //AASINFO
- } //end of the function AAS_CreateAreaSettings
- //===========================================================================
- // create a tmp AAS area from a leaf node
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- tmp_node_t *AAS_CreateArea(node_t *node)
- {
- int pside;
- int areafaceflags;
- portal_t *p;
- tmp_face_t *tmpface;
- tmp_area_t *tmparea;
- tmp_node_t *tmpnode;
- vec3_t up = {0, 0, 1};
- //create an area from this leaf
- tmparea = AAS_AllocTmpArea();
- tmparea->tmpfaces = NULL;
- //clear the area face flags
- areafaceflags = 0;
- //make aas faces from the portals
- for (p = node->portals; p; p = p->next[pside])
- {
- pside = (p->nodes[1] == node);
- //don't create faces from very small portals
- // if (WindingArea(p->winding) < 1) continue;
- //if there's already a face created for this portal
- if (p->tmpface)
- {
- //add the back side of the face to the area
- AAS_AddFaceSideToArea(p->tmpface, 1, tmparea);
- } //end if
- else
- {
- tmpface = AAS_AllocTmpFace();
- //set the face pointer at the portal so we can see from
- //the portal there's a face created for it
- p->tmpface = tmpface;
- //FIXME: test this change
- //tmpface->planenum = (p->planenum & ~1) | pside;
- tmpface->planenum = p->planenum ^ pside;
- if (pside) tmpface->winding = ReverseWinding(p->winding);
- else tmpface->winding = CopyWinding(p->winding);
- #ifdef L_DEBUG
- //
- AAS_CheckFaceWindingPlane(tmpface);
- #endif //L_DEBUG
- //if there's solid at the other side of the portal
- if (p->nodes[!pside]->contents & (CONTENTS_SOLID | CONTENTS_PLAYERCLIP))
- {
- tmpface->faceflags |= FACE_SOLID;
- } //end if
- //else there is no solid at the other side and if there
- //is a liquid at this side
- else if (node->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA))
- {
- tmpface->faceflags |= FACE_LIQUID;
- //if there's no liquid at the other side
- if (!(p->nodes[!pside]->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)))
- {
- tmpface->faceflags |= FACE_LIQUIDSURFACE;
- } //end if
- } //end else
- //if there's ladder contents at other side of the portal
- if ((p->nodes[pside]->contents & CONTENTS_LADDER) ||
- (p->nodes[!pside]->contents & CONTENTS_LADDER))
- {
- //NOTE: doesn't have to be solid at the other side because
- // when standing one can use a crouch area (which is not solid)
- // as a ladder
- // imagine a ladder one can walk underthrough,
- // under the ladder against the ladder is a crouch area
- // the (vertical) sides of this crouch area area also used as
- // ladder sides when standing (not crouched)
- tmpface->faceflags |= FACE_LADDER;
- } //end if
- //if it is possible to stand on the face
- if (AAS_GroundFace(tmpface))
- {
- tmpface->faceflags |= FACE_GROUND;
- } //end if
- //
- areafaceflags |= tmpface->faceflags;
- //no aas face number yet (zero is a dummy in the aasworld faces)
- tmpface->aasfacenum = 0;
- //add the front side of the face to the area
- AAS_AddFaceSideToArea(tmpface, 0, tmparea);
- } //end else
- } //end for
- qprintf("\r%6d", tmparea->areanum);
- //presence type in the area
- tmparea->presencetype = ~node->expansionbboxes & cfg.allpresencetypes;
- //
- tmparea->contents = 0;
- if (node->contents & CONTENTS_CLUSTERPORTAL) tmparea->contents |= AREACONTENTS_CLUSTERPORTAL;
- if (node->contents & CONTENTS_MOVER) tmparea->contents |= AREACONTENTS_MOVER;
- if (node->contents & CONTENTS_TELEPORTER) tmparea->contents |= AREACONTENTS_TELEPORTER;
- if (node->contents & CONTENTS_JUMPPAD) tmparea->contents |= AREACONTENTS_JUMPPAD;
- if (node->contents & CONTENTS_DONOTENTER) tmparea->contents |= AREACONTENTS_DONOTENTER;
- if (node->contents & CONTENTS_WATER) tmparea->contents |= AREACONTENTS_WATER;
- if (node->contents & CONTENTS_LAVA) tmparea->contents |= AREACONTENTS_LAVA;
- if (node->contents & CONTENTS_SLIME) tmparea->contents |= AREACONTENTS_SLIME;
- if (node->contents & CONTENTS_NOTTEAM1) tmparea->contents |= AREACONTENTS_NOTTEAM1;
- if (node->contents & CONTENTS_NOTTEAM2) tmparea->contents |= AREACONTENTS_NOTTEAM2;
- //store the bsp model that's inside this node
- tmparea->modelnum = node->modelnum;
- //sorta check for flipped area faces (remove??)
- AAS_FlipAreaFaces(tmparea);
- //check if the area is ok (remove??)
- AAS_CheckArea(tmparea);
- //
- tmpnode = AAS_AllocTmpNode();
- tmpnode->planenum = 0;
- tmpnode->children[0] = 0;
- tmpnode->children[1] = 0;
- tmpnode->tmparea = tmparea;
- //
- return tmpnode;
- } //end of the function AAS_CreateArea
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- tmp_node_t *AAS_CreateAreas_r(node_t *node)
- {
- tmp_node_t *tmpnode;
- //recurse down to leafs
- if (node->planenum != PLANENUM_LEAF)
- {
- //the first tmp node is a dummy
- tmpnode = AAS_AllocTmpNode();
- tmpnode->planenum = node->planenum;
- tmpnode->children[0] = AAS_CreateAreas_r(node->children[0]);
- tmpnode->children[1] = AAS_CreateAreas_r(node->children[1]);
- return tmpnode;
- } //end if
- //areas won't be created for solid leafs
- if (node->contents & CONTENTS_SOLID)
- {
- //just return zero for a solid leaf (in tmp AAS NULL is a solid leaf)
- return NULL;
- } //end if
- return AAS_CreateArea(node);
- } //end of the function AAS_CreateAreas_r
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void AAS_CreateAreas(node_t *node)
- {
- Log_Write("AAS_CreateAreas\r\n");
- qprintf("%6d areas created", 0);
- tmpaasworld.nodes = AAS_CreateAreas_r(node);
- qprintf("\n");
- Log_Write("%6d areas created\r\n", tmpaasworld.numareas);
- } //end of the function AAS_CreateAreas
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void AAS_PrintNumGroundFaces(void)
- {
- tmp_face_t *tmpface;
- int numgroundfaces = 0;
- for (tmpface = tmpaasworld.faces; tmpface; tmpface = tmpface->l_next)
- {
- if (tmpface->faceflags & FACE_GROUND)
- {
- numgroundfaces++;
- } //end if
- } //end for
- qprintf("%6d ground faces\n", numgroundfaces);
- } //end of the function AAS_PrintNumGroundFaces
- //===========================================================================
- // checks the number of shared faces between the given two areas
- // since areas are convex they should only have ONE shared face
- // however due to crappy face merging there are sometimes several
- // shared faces
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void AAS_CheckAreaSharedFaces(tmp_area_t *tmparea1, tmp_area_t *tmparea2)
- {
- int numsharedfaces, side;
- tmp_face_t *face1, *sharedface;
- if (tmparea1->invalid || tmparea2->invalid) return;
- sharedface = NULL;
- numsharedfaces = 0;
- for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side])
- {
- side = face1->frontarea != tmparea1;
- if (face1->backarea == tmparea2 || face1->frontarea == tmparea2)
- {
- sharedface = face1;
- numsharedfaces++;
- } //end if
- } //end if
- if (!sharedface) return;
- //the areas should only have one shared face
- if (numsharedfaces > 1)
- {
- Log_Write("---- tmp area %d and %d have %d shared faces\r\n",
- tmparea1->areanum, tmparea2->areanum, numsharedfaces);
- for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side])
- {
- side = face1->frontarea != tmparea1;
- if (face1->backarea == tmparea2 || face1->frontarea == tmparea2)
- {
- Log_Write("face %d, planenum = %d, face->frontarea = %d face->backarea = %d\r\n",
- face1->num, face1->planenum, face1->frontarea->areanum, face1->backarea->areanum);
- } //end if
- } //end if
- } //end if
- } //end of the function AAS_CheckAreaSharedFaces
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void AAS_CheckSharedFaces(void)
- {
- tmp_area_t *tmparea1, *tmparea2;
- for (tmparea1 = tmpaasworld.areas; tmparea1; tmparea1 = tmparea1->l_next)
- {
- for (tmparea2 = tmpaasworld.areas; tmparea2; tmparea2 = tmparea2->l_next)
- {
- if (tmparea1 == tmparea2) continue;
- AAS_CheckAreaSharedFaces(tmparea1, tmparea2);
- } //end for
- } //end for
- } //end of the function AAS_CheckSharedFaces
- //===========================================================================
- //
- // 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: -
- //===========================================================================
- /*
- void AAS_FlipAreaSharedFaces(tmp_area_t *tmparea1, tmp_area_t *tmparea2)
- {
- int numsharedfaces, side, area1facing, area2facing;
- tmp_face_t *face1, *sharedface;
- if (tmparea1->invalid || tmparea2->invalid) return;
- sharedface = NULL;
- numsharedfaces = 0;
- area1facing = 0; //number of shared faces facing towards area 1
- area2facing = 0; //number of shared faces facing towards area 2
- for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side])
- {
- side = face1->frontarea != tmparea1;
- if (face1->backarea == tmparea2 || face1->frontarea == tmparea2)
- {
- sharedface = face1;
- numsharedfaces++;
- if (face1->frontarea == tmparea1) area1facing++;
- else area2facing++;
- } //end if
- } //end if
- if (!sharedface) return;
- //if there's only one shared face
- if (numsharedfaces <= 1) return;
- //if all the shared faces are facing to the same area
- if (numsharedfaces == area1facing || numsharedfaces == area2facing) return;
- //
- do
- {
- for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side])
- {
- side = face1->frontarea != tmparea1;
- if (face1->backarea == tmparea2 || face1->frontarea == tmparea2)
- {
- if (face1->frontarea != tmparea1)
- {
- AAS_FlipFace(face1);
- break;
- } //end if
- } //end if
- } //end for
- } while(face1);
- } //end of the function AAS_FlipAreaSharedFaces
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void AAS_FlipSharedFaces(void)
- {
- int i;
- tmp_area_t *tmparea1, *tmparea2;
- i = 0;
- qprintf("%6d areas checked for shared face flipping", i);
- for (tmparea1 = tmpaasworld.areas; tmparea1; tmparea1 = tmparea1->l_next)
- {
- if (tmparea1->invalid) continue;
- for (tmparea2 = tmpaasworld.areas; tmparea2; tmparea2 = tmparea2->l_next)
- {
- if (tmparea2->invalid) continue;
- if (tmparea1 == tmparea2) continue;
- AAS_FlipAreaSharedFaces(tmparea1, tmparea2);
- } //end for
- qprintf("\r%6d", ++i);
- } //end for
- Log_Print("\r%6d areas checked for shared face flipping\n", i);
- } //end of the function AAS_FlipSharedFaces
- */
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void AAS_FlipSharedFaces(void)
- {
- int i, side1, side2;
- tmp_area_t *tmparea1;
- tmp_face_t *face1, *face2;
- i = 0;
- qprintf("%6d areas checked for shared face flipping", i);
- for (tmparea1 = tmpaasworld.areas; tmparea1; tmparea1 = tmparea1->l_next)
- {
- if (tmparea1->invalid) continue;
- for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side1])
- {
- side1 = face1->frontarea != tmparea1;
- if (!face1->frontarea || !face1->backarea) continue;
- //
- for (face2 = face1->next[side1]; face2; face2 = face2->next[side2])
- {
- side2 = face2->frontarea != tmparea1;
- if (!face2->frontarea || !face2->backarea) continue;
- //
- if (face1->frontarea == face2->backarea &&
- face1->backarea == face2->frontarea)
- {
- AAS_FlipFace(face2);
- } //end if
- //recheck side
- side2 = face2->frontarea != tmparea1;
- } //end for
- } //end for
- qprintf("\r%6d", ++i);
- } //end for
- qprintf("\n");
- Log_Write("%6d areas checked for shared face flipping\r\n", i);
- } //end of the function AAS_FlipSharedFaces
- //===========================================================================
- // creates an .AAS file with the given name
- // a MAP should be loaded before calling this
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void AAS_Create(char *aasfile)
- {
- entity_t *e;
- tree_t *tree;
- double start_time;
- //for a possible leak file
- strcpy(source, aasfile);
- StripExtension(source);
- //the time started
- start_time = I_FloatTime();
- //set the default number of threads (depends on number of processors)
- ThreadSetDefault();
- //set the global entity number to the world model
- entity_num = 0;
- //the world entity
- e = &entities[entity_num];
- //process the whole world
- tree = ProcessWorldBrushes(e->firstbrush, e->firstbrush + e->numbrushes);
- //if the conversion is cancelled
- if (cancelconversion)
- {
- Tree_Free(tree);
- return;
- } //end if
- //display BSP tree creation time
- Log_Print("BSP tree created in %5.0f seconds\n", I_FloatTime() - start_time);
- //prune the bsp tree
- Tree_PruneNodes(tree->headnode);
- //if the conversion is cancelled
- if (cancelconversion)
- {
- Tree_Free(tree);
- return;
- } //end if
- //create the tree portals
- MakeTreePortals(tree);
- //if the conversion is cancelled
- if (cancelconversion)
- {
- Tree_Free(tree);
- return;
- } //end if
- //Marks all nodes that can be reached by entites
- if (FloodEntities(tree))
- {
- //fill out nodes that can't be reached
- FillOutside(tree->headnode);
- } //end if
- else
- {
- LeakFile(tree);
- Error("**** leaked ****\n");
- return;
- } //end else
- //create AAS from the BSP tree
- //==========================================
- //initialize tmp aas
- AAS_InitTmpAAS();
- //create the convex areas from the leaves
- AAS_CreateAreas(tree->headnode);
- //free the BSP tree because it isn't used anymore
- if (freetree) Tree_Free(tree);
- //try to merge area faces
- AAS_MergeAreaFaces();
- //do gravitational subdivision
- AAS_GravitationalSubdivision();
- //merge faces if possible
- AAS_MergeAreaFaces();
- AAS_RemoveAreaFaceColinearPoints();
- //merge areas if possible
- AAS_MergeAreas();
- //NOTE: prune nodes directly after area merging
- AAS_PruneNodes();
- //flip shared faces so they are all facing to the same area
- AAS_FlipSharedFaces();
- AAS_RemoveAreaFaceColinearPoints();
- //merge faces if possible
- AAS_MergeAreaFaces();
- //merge area faces in the same plane
- AAS_MergeAreaPlaneFaces();
- //do ladder subdivision
- AAS_LadderSubdivision();
- //FIXME: melting is buggy
- AAS_MeltAreaFaceWindings();
- //remove tiny faces
- AAS_RemoveTinyFaces();
- //create area settings
- AAS_CreateAreaSettings();
- //check if the winding plane is equal to the face plane
- //AAS_CheckAreaWindingPlanes();
- //
- //AAS_CheckSharedFaces();
- //==========================================
- //if the conversion is cancelled
- if (cancelconversion)
- {
- Tree_Free(tree);
- AAS_FreeTmpAAS();
- return;
- } //end if
- //store the created AAS stuff in the AAS file format and write the file
- AAS_StoreFile(aasfile);
- //free the temporary AAS memory
- AAS_FreeTmpAAS();
- //display creation time
- Log_Print("\nAAS created in %5.0f seconds\n", I_FloatTime() - start_time);
- } //end of the function AAS_Create
|