Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

aas_create.c (35954B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 
     23 #include "qbsp.h"
     24 #include "../botlib/aasfile.h"
     25 #include "aas_create.h"
     26 #include "aas_store.h"
     27 #include "aas_gsubdiv.h"
     28 #include "aas_facemerging.h"
     29 #include "aas_areamerging.h"
     30 #include "aas_edgemelting.h"
     31 #include "aas_prunenodes.h"
     32 #include "aas_cfg.h"
     33 #include "../game/surfaceflags.h"
     34 
     35 //#define AW_DEBUG
     36 //#define L_DEBUG
     37 
     38 #define AREAONFACESIDE(face, area)		(face->frontarea != area)
     39 
     40 tmp_aas_t tmpaasworld;
     41 
     42 //===========================================================================
     43 //
     44 // Parameter:				-
     45 // Returns:					-
     46 // Changes Globals:		-
     47 //===========================================================================
     48 void AAS_InitTmpAAS(void)
     49 {
     50 	//tmp faces
     51 	tmpaasworld.numfaces = 0;
     52 	tmpaasworld.facenum = 0;
     53 	tmpaasworld.faces = NULL;
     54 	//tmp convex areas
     55 	tmpaasworld.numareas = 0;
     56 	tmpaasworld.areanum = 0;
     57 	tmpaasworld.areas = NULL;
     58 	//tmp nodes
     59 	tmpaasworld.numnodes = 0;
     60 	tmpaasworld.nodes = NULL;
     61 	//
     62 	tmpaasworld.nodebuffer = NULL;
     63 } //end of the function AAS_InitTmpAAS
     64 //===========================================================================
     65 //
     66 // Parameter:				-
     67 // Returns:					-
     68 // Changes Globals:		-
     69 //===========================================================================
     70 void AAS_FreeTmpAAS(void)
     71 {
     72 	tmp_face_t *f, *nextf;
     73 	tmp_area_t *a, *nexta;
     74 	tmp_nodebuf_t *nb, *nextnb;
     75 
     76 	//free all the faces
     77 	for (f = tmpaasworld.faces; f; f = nextf)
     78 	{
     79 		nextf = f->l_next;
     80 		if (f->winding) FreeWinding(f->winding);
     81 		FreeMemory(f);
     82 	} //end if
     83 	//free all tmp areas
     84 	for (a = tmpaasworld.areas; a; a = nexta)
     85 	{
     86 		nexta = a->l_next;
     87 		if (a->settings) FreeMemory(a->settings);
     88 		FreeMemory(a);
     89 	} //end for
     90 	//free all the tmp nodes
     91 	for (nb = tmpaasworld.nodebuffer; nb; nb = nextnb)
     92 	{
     93 		nextnb = nb->next;
     94 		FreeMemory(nb);
     95 	} //end for
     96 } //end of the function AAS_FreeTmpAAS
     97 //===========================================================================
     98 //
     99 // Parameter:				-
    100 // Returns:					-
    101 // Changes Globals:		-
    102 //===========================================================================
    103 tmp_face_t *AAS_AllocTmpFace(void)
    104 {
    105 	tmp_face_t *tmpface;
    106 
    107 	tmpface = (tmp_face_t *) GetClearedMemory(sizeof(tmp_face_t));
    108 	tmpface->num = tmpaasworld.facenum++;
    109 	tmpface->l_prev = NULL;
    110 	tmpface->l_next = tmpaasworld.faces;
    111 	if (tmpaasworld.faces) tmpaasworld.faces->l_prev = tmpface;
    112 	tmpaasworld.faces = tmpface;
    113 	tmpaasworld.numfaces++;
    114 	return tmpface;
    115 } //end of the function AAS_AllocTmpFace
    116 //===========================================================================
    117 //
    118 // Parameter:				-
    119 // Returns:					-
    120 // Changes Globals:		-
    121 //===========================================================================
    122 void AAS_FreeTmpFace(tmp_face_t *tmpface)
    123 {
    124 	if (tmpface->l_next) tmpface->l_next->l_prev = tmpface->l_prev;
    125 	if (tmpface->l_prev) tmpface->l_prev->l_next = tmpface->l_next;
    126 	else tmpaasworld.faces = tmpface->l_next;
    127 	//free the winding
    128 	if (tmpface->winding) FreeWinding(tmpface->winding);
    129 	//free the face
    130 	FreeMemory(tmpface);
    131 	tmpaasworld.numfaces--;
    132 } //end of the function AAS_FreeTmpFace
    133 //===========================================================================
    134 //
    135 // Parameter:				-
    136 // Returns:					-
    137 // Changes Globals:		-
    138 //===========================================================================
    139 tmp_area_t *AAS_AllocTmpArea(void)
    140 {
    141 	tmp_area_t *tmparea;
    142 
    143 	tmparea = (tmp_area_t *) GetClearedMemory(sizeof(tmp_area_t));
    144 	tmparea->areanum = tmpaasworld.areanum++;
    145 	tmparea->l_prev = NULL;
    146 	tmparea->l_next = tmpaasworld.areas;
    147 	if (tmpaasworld.areas) tmpaasworld.areas->l_prev = tmparea;
    148 	tmpaasworld.areas = tmparea;
    149 	tmpaasworld.numareas++;
    150 	return tmparea;
    151 } //end of the function AAS_AllocTmpArea
    152 //===========================================================================
    153 //
    154 // Parameter:				-
    155 // Returns:					-
    156 // Changes Globals:		-
    157 //===========================================================================
    158 void AAS_FreeTmpArea(tmp_area_t *tmparea)
    159 {
    160 	if (tmparea->l_next) tmparea->l_next->l_prev = tmparea->l_prev;
    161 	if (tmparea->l_prev) tmparea->l_prev->l_next = tmparea->l_next;
    162 	else tmpaasworld.areas = tmparea->l_next;
    163 	if (tmparea->settings) FreeMemory(tmparea->settings);
    164 	FreeMemory(tmparea);
    165 	tmpaasworld.numareas--;
    166 } //end of the function AAS_FreeTmpArea
    167 //===========================================================================
    168 //
    169 // Parameter:				-
    170 // Returns:					-
    171 // Changes Globals:		-
    172 //===========================================================================
    173 tmp_node_t *AAS_AllocTmpNode(void)
    174 {
    175 	tmp_nodebuf_t *nodebuf;
    176 
    177 	if (!tmpaasworld.nodebuffer ||
    178 			tmpaasworld.nodebuffer->numnodes >= NODEBUF_SIZE)
    179 	{
    180 		nodebuf = (tmp_nodebuf_t *) GetClearedMemory(sizeof(tmp_nodebuf_t));
    181 		nodebuf->next = tmpaasworld.nodebuffer;
    182 		nodebuf->numnodes = 0;
    183 		tmpaasworld.nodebuffer = nodebuf;
    184 	} //end if
    185 	tmpaasworld.numnodes++;
    186 	return &tmpaasworld.nodebuffer->nodes[tmpaasworld.nodebuffer->numnodes++];
    187 } //end of the function AAS_AllocTmpNode
    188 //===========================================================================
    189 //
    190 // Parameter:				-
    191 // Returns:					-
    192 // Changes Globals:		-
    193 //===========================================================================
    194 void AAS_FreeTmpNode(tmp_node_t *tmpnode)
    195 {
    196 	tmpaasworld.numnodes--;
    197 } //end of the function AAS_FreeTmpNode
    198 //===========================================================================
    199 // returns true if the face is a gap from the given side
    200 //
    201 // Parameter:				-
    202 // Returns:					-
    203 // Changes Globals:		-
    204 //===========================================================================
    205 int AAS_GapFace(tmp_face_t *tmpface, int side)
    206 {
    207 	vec3_t invgravity;
    208 
    209 	//if the face is a solid or ground face it can't be a gap
    210 	if (tmpface->faceflags & (FACE_GROUND | FACE_SOLID)) return 0;
    211 
    212 	VectorCopy(cfg.phys_gravitydirection, invgravity);
    213 	VectorInverse(invgravity);
    214 
    215 	return (DotProduct(invgravity, mapplanes[tmpface->planenum ^ side].normal) > cfg.phys_maxsteepness);
    216 } //end of the function AAS_GapFace
    217 //===========================================================================
    218 // returns true if the face is a ground face
    219 //
    220 // Parameter:				-
    221 // Returns:					-
    222 // Changes Globals:		-
    223 //===========================================================================
    224 int AAS_GroundFace(tmp_face_t *tmpface)
    225 {
    226 	vec3_t invgravity;
    227 
    228 	//must be a solid face
    229 	if (!(tmpface->faceflags & FACE_SOLID)) return 0;
    230 
    231 	VectorCopy(cfg.phys_gravitydirection, invgravity);
    232 	VectorInverse(invgravity);
    233 
    234 	return (DotProduct(invgravity, mapplanes[tmpface->planenum].normal) > cfg.phys_maxsteepness);
    235 } //end of the function AAS_GroundFace
    236 //===========================================================================
    237 // adds the side of a face to an area
    238 //
    239 // side :	0 = front side
    240 //				1 = back side
    241 //
    242 // Parameter:				-
    243 // Returns:					-
    244 // Changes Globals:		-
    245 //===========================================================================
    246 void AAS_AddFaceSideToArea(tmp_face_t *tmpface, int side, tmp_area_t *tmparea)
    247 {
    248 	int tmpfaceside;
    249 
    250 	if (side)
    251 	{
    252 		if (tmpface->backarea) Error("AAS_AddFaceSideToArea: already a back area\n");
    253 	} //end if
    254 	else
    255 	{
    256 		if (tmpface->frontarea) Error("AAS_AddFaceSideToArea: already a front area\n");
    257 	} //end else
    258 
    259 	if (side) tmpface->backarea = tmparea;
    260 	else tmpface->frontarea = tmparea;
    261 
    262 	if (tmparea->tmpfaces)
    263 	{
    264 		tmpfaceside = tmparea->tmpfaces->frontarea != tmparea;
    265 		tmparea->tmpfaces->prev[tmpfaceside] = tmpface;
    266 	} //end if
    267 	tmpface->next[side] = tmparea->tmpfaces;
    268 	tmpface->prev[side] = NULL;
    269 	tmparea->tmpfaces = tmpface;
    270 } //end of the function AAS_AddFaceSideToArea
    271 //===========================================================================
    272 // remove (a side of) a face from an area
    273 //
    274 // Parameter:				-
    275 // Returns:					-
    276 // Changes Globals:		-
    277 //===========================================================================
    278 void AAS_RemoveFaceFromArea(tmp_face_t *tmpface, tmp_area_t *tmparea)
    279 {
    280 	int side, prevside, nextside;
    281 
    282 	if (tmpface->frontarea != tmparea &&
    283 			tmpface->backarea != tmparea)
    284 	{
    285 		Error("AAS_RemoveFaceFromArea: face not part of the area");
    286 	} //end if
    287 	side = tmpface->frontarea != tmparea;
    288 	if (tmpface->prev[side])
    289 	{
    290 		prevside = tmpface->prev[side]->frontarea != tmparea;
    291 		tmpface->prev[side]->next[prevside] = tmpface->next[side];
    292 	} //end if
    293 	else
    294 	{
    295 		tmparea->tmpfaces = tmpface->next[side];
    296 	} //end else
    297 	if (tmpface->next[side])
    298 	{
    299 		nextside = tmpface->next[side]->frontarea != tmparea;
    300 		tmpface->next[side]->prev[nextside] = tmpface->prev[side];
    301 	} //end if
    302 	//remove the area number from the face depending on the side
    303 	if (side) tmpface->backarea = NULL;
    304 	else tmpface->frontarea = NULL;
    305 	tmpface->prev[side] = NULL;
    306 	tmpface->next[side] = NULL;
    307 } //end of the function AAS_RemoveFaceFromArea
    308 //===========================================================================
    309 //
    310 // Parameter:				-
    311 // Returns:					-
    312 // Changes Globals:		-
    313 //===========================================================================
    314 void AAS_CheckArea(tmp_area_t *tmparea)
    315 {
    316 	int side;
    317 	tmp_face_t *face;
    318 	plane_t *plane;
    319 	vec3_t wcenter, acenter = {0, 0, 0};
    320 	vec3_t normal;
    321 	float n, dist;
    322 
    323 	if (tmparea->invalid) Log_Print("AAS_CheckArea: invalid area\n");
    324 	for (n = 0, face = tmparea->tmpfaces; face; face = face->next[side])
    325 	{
    326 		//side of the face the area is on
    327 		side = face->frontarea != tmparea;
    328 		WindingCenter(face->winding, wcenter);
    329 		VectorAdd(acenter, wcenter, acenter);
    330 		n++;
    331 	} //end for
    332 	n = 1 / n;
    333 	VectorScale(acenter, n, acenter);
    334 	for (face = tmparea->tmpfaces; face; face = face->next[side])
    335 	{
    336 		//side of the face the area is on
    337 		side = face->frontarea != tmparea;
    338 
    339 #ifdef L_DEBUG
    340 		if (WindingError(face->winding))
    341 		{
    342 			Log_Write("AAS_CheckArea: area %d face %d: %s\r\n", tmparea->areanum,
    343 						face->num, WindingErrorString());
    344 		} //end if
    345 #endif L_DEBUG
    346 
    347 		plane = &mapplanes[face->planenum ^ side];
    348 
    349 		if (DotProduct(plane->normal, acenter) - plane->dist < 0)
    350 		{
    351 			Log_Print("AAS_CheckArea: area %d face %d is flipped\n", tmparea->areanum, face->num);
    352 			Log_Print("AAS_CheckArea: area %d center is %f %f %f\n", tmparea->areanum, acenter[0], acenter[1], acenter[2]);
    353 		} //end if
    354 		//check if the winding plane is the same as the face plane
    355 		WindingPlane(face->winding, normal, &dist);
    356 		plane = &mapplanes[face->planenum];
    357 #ifdef L_DEBUG
    358 		if (fabs(dist - plane->dist) > 0.4 ||
    359 				fabs(normal[0] - plane->normal[0]) > 0.0001 ||
    360 				fabs(normal[1] - plane->normal[1]) > 0.0001 ||
    361 				fabs(normal[2] - plane->normal[2]) > 0.0001)
    362 		{
    363 			Log_Write("AAS_CheckArea: area %d face %d winding plane unequal to face plane\r\n",
    364 										tmparea->areanum, face->num);
    365 		} //end if
    366 #endif L_DEBUG
    367 	} //end for
    368 } //end of the function AAS_CheckArea
    369 //===========================================================================
    370 //
    371 // Parameter:				-
    372 // Returns:					-
    373 // Changes Globals:		-
    374 //===========================================================================
    375 void AAS_CheckFaceWindingPlane(tmp_face_t *face)
    376 {
    377 	float dist, sign1, sign2;
    378 	vec3_t normal;
    379 	plane_t *plane;
    380 	winding_t *w;
    381 
    382 	//check if the winding plane is the same as the face plane
    383 	WindingPlane(face->winding, normal, &dist);
    384 	plane = &mapplanes[face->planenum];
    385 	//
    386 	sign1 = DotProduct(plane->normal, normal);
    387 	//
    388 	if (fabs(dist - plane->dist) > 0.4 ||
    389 			fabs(normal[0] - plane->normal[0]) > 0.0001 ||
    390 			fabs(normal[1] - plane->normal[1]) > 0.0001 ||
    391 			fabs(normal[2] - plane->normal[2]) > 0.0001)
    392 	{
    393 		VectorInverse(normal);
    394 		dist = -dist;
    395 		if (fabs(dist - plane->dist) > 0.4 ||
    396 				fabs(normal[0] - plane->normal[0]) > 0.0001 ||
    397 				fabs(normal[1] - plane->normal[1]) > 0.0001 ||
    398 				fabs(normal[2] - plane->normal[2]) > 0.0001)
    399 		{
    400 			Log_Write("AAS_CheckFaceWindingPlane: face %d winding plane unequal to face plane\r\n",
    401 									face->num);
    402 			//
    403 			sign2 = DotProduct(plane->normal, normal);
    404 			if ((sign1 < 0 && sign2 > 0) ||
    405 					(sign1 > 0 && sign2 < 0))
    406 			{
    407 				Log_Write("AAS_CheckFaceWindingPlane: face %d winding reversed\r\n",
    408 									face->num);
    409 				w = face->winding;
    410 				face->winding = ReverseWinding(w);
    411 				FreeWinding(w);
    412 			} //end if
    413 		} //end if
    414 		else
    415 		{
    416 			Log_Write("AAS_CheckFaceWindingPlane: face %d winding reversed\r\n",
    417 									face->num);
    418 			w = face->winding;
    419 			face->winding = ReverseWinding(w);
    420 			FreeWinding(w);
    421 		} //end else
    422 	} //end if
    423 } //end of the function AAS_CheckFaceWindingPlane
    424 //===========================================================================
    425 //
    426 // Parameter:				-
    427 // Returns:					-
    428 // Changes Globals:		-
    429 //===========================================================================
    430 void AAS_CheckAreaWindingPlanes(void)
    431 {
    432 	int side;
    433 	tmp_area_t *tmparea;
    434 	tmp_face_t *face;
    435 
    436 	Log_Write("AAS_CheckAreaWindingPlanes:\r\n");
    437 	for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
    438 	{
    439 		if (tmparea->invalid) continue;
    440 		for (face = tmparea->tmpfaces; face; face = face->next[side])
    441 		{
    442 			side = face->frontarea != tmparea;
    443 			AAS_CheckFaceWindingPlane(face);
    444 		} //end for
    445 	} //end for
    446 } //end of the function AAS_CheckAreaWindingPlanes
    447 //===========================================================================
    448 //
    449 // Parameter:				-
    450 // Returns:					-
    451 // Changes Globals:		-
    452 //===========================================================================
    453 void AAS_FlipAreaFaces(tmp_area_t *tmparea)
    454 {
    455 	int side;
    456 	tmp_face_t *face;
    457 	plane_t *plane;
    458 	vec3_t wcenter, acenter = {0, 0, 0};
    459 	//winding_t *w;
    460 	float n;
    461 
    462 	for (n = 0, face = tmparea->tmpfaces; face; face = face->next[side])
    463 	{
    464 		if (!face->frontarea) Error("face %d has no front area\n", face->num);
    465 		//side of the face the area is on
    466 		side = face->frontarea != tmparea;
    467 		WindingCenter(face->winding, wcenter);
    468 		VectorAdd(acenter, wcenter, acenter);
    469 		n++;
    470 	} //end for
    471 	n = 1 / n;
    472 	VectorScale(acenter, n, acenter);
    473 	for (face = tmparea->tmpfaces; face; face = face->next[side])
    474 	{
    475 		//side of the face the area is on
    476 		side = face->frontarea != tmparea;
    477 
    478 		plane = &mapplanes[face->planenum ^ side];
    479 
    480 		if (DotProduct(plane->normal, acenter) - plane->dist < 0)
    481 		{
    482 			Log_Print("area %d face %d flipped: front area %d, back area %d\n", tmparea->areanum, face->num,
    483 					face->frontarea ? face->frontarea->areanum : 0,
    484 					face->backarea ? face->backarea->areanum : 0);
    485 			/*
    486 			face->planenum = face->planenum ^ 1;
    487 			w = face->winding;
    488 			face->winding = ReverseWinding(w);
    489 			FreeWinding(w);
    490 			*/
    491 		} //end if
    492 #ifdef L_DEBUG
    493 		{
    494 			float dist;
    495 			vec3_t normal;
    496 
    497 			//check if the winding plane is the same as the face plane
    498 			WindingPlane(face->winding, normal, &dist);
    499 			plane = &mapplanes[face->planenum];
    500 			if (fabs(dist - plane->dist) > 0.4 ||
    501 					fabs(normal[0] - plane->normal[0]) > 0.0001 ||
    502 					fabs(normal[1] - plane->normal[1]) > 0.0001 ||
    503 					fabs(normal[2] - plane->normal[2]) > 0.0001)
    504 			{
    505 				Log_Write("area %d face %d winding plane unequal to face plane\r\n",
    506 											tmparea->areanum, face->num);
    507 			} //end if
    508 		}
    509 #endif
    510 	} //end for
    511 } //end of the function AAS_FlipAreaFaces
    512 //===========================================================================
    513 //
    514 // Parameter:				-
    515 // Returns:					-
    516 // Changes Globals:		-
    517 //===========================================================================
    518 void AAS_RemoveAreaFaceColinearPoints(void)
    519 {
    520 	int side;
    521 	tmp_face_t *face;
    522 	tmp_area_t *tmparea;
    523 
    524 	//FIXME: loop over the faces instead of area->faces
    525 	for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
    526 	{
    527 		for (face = tmparea->tmpfaces; face; face = face->next[side])
    528 		{
    529 			side = face->frontarea != tmparea;
    530 			RemoveColinearPoints(face->winding);
    531 //			RemoveEqualPoints(face->winding, 0.1);
    532 		} //end for
    533 	} //end for
    534 } //end of the function AAS_RemoveAreaFaceColinearPoints
    535 //===========================================================================
    536 //
    537 // Parameter:				-
    538 // Returns:					-
    539 // Changes Globals:		-
    540 //===========================================================================
    541 void AAS_RemoveTinyFaces(void)
    542 {
    543 	int side, num;
    544 	tmp_face_t *face, *nextface;
    545 	tmp_area_t *tmparea;
    546 
    547 	//FIXME: loop over the faces instead of area->faces
    548 	Log_Write("AAS_RemoveTinyFaces\r\n");
    549 	num = 0;
    550 	for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
    551 	{
    552 		for (face = tmparea->tmpfaces; face; face = nextface)
    553 		{
    554 			side = face->frontarea != tmparea;
    555 			nextface = face->next[side];
    556 			//
    557 			if (WindingArea(face->winding) < 1)
    558 			{
    559 				if (face->frontarea) AAS_RemoveFaceFromArea(face, face->frontarea);
    560 				if (face->backarea) AAS_RemoveFaceFromArea(face, face->backarea);
    561 				AAS_FreeTmpFace(face);
    562 				//Log_Write("area %d face %d is tiny\r\n", tmparea->areanum, face->num);
    563 				num++;
    564 			} //end if
    565 		} //end for
    566 	} //end for
    567 	Log_Write("%d tiny faces removed\r\n", num);
    568 } //end of the function AAS_RemoveTinyFaces
    569 //===========================================================================
    570 //
    571 // Parameter:				-
    572 // Returns:					-
    573 // Changes Globals:		-
    574 //===========================================================================
    575 void AAS_CreateAreaSettings(void)
    576 {
    577 	int i, flags, side, numgrounded, numladderareas, numliquidareas;
    578 	tmp_face_t *face;
    579 	tmp_area_t *tmparea;
    580 
    581 	numgrounded = 0;
    582 	numladderareas = 0;
    583 	numliquidareas = 0;
    584 	Log_Write("AAS_CreateAreaSettings\r\n");
    585 	i = 0;
    586 	qprintf("%6d areas provided with settings", i);
    587 	for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
    588 	{
    589 		//if the area is invalid there no need to create settings for it
    590 		if (tmparea->invalid) continue;
    591 
    592 		tmparea->settings = (tmp_areasettings_t *) GetClearedMemory(sizeof(tmp_areasettings_t));
    593 		tmparea->settings->contents = tmparea->contents;
    594 		tmparea->settings->modelnum = tmparea->modelnum;
    595 		flags = 0;
    596 		for (face = tmparea->tmpfaces; face; face = face->next[side])
    597 		{
    598 			side = face->frontarea != tmparea;
    599 			flags |= face->faceflags;
    600 		} //end for
    601 		tmparea->settings->areaflags = 0;
    602 		if (flags & FACE_GROUND)
    603 		{
    604 			tmparea->settings->areaflags |= AREA_GROUNDED;
    605 			numgrounded++;
    606 		} //end if
    607 		if (flags & FACE_LADDER)
    608 		{
    609 			tmparea->settings->areaflags |= AREA_LADDER;
    610 			numladderareas++;
    611 		} //end if
    612 		if (tmparea->contents & (AREACONTENTS_WATER |
    613 											AREACONTENTS_SLIME |
    614 											AREACONTENTS_LAVA))
    615 		{
    616 			tmparea->settings->areaflags |= AREA_LIQUID;
    617 			numliquidareas++;
    618 		} //end if
    619 		//presence type of the area
    620 		tmparea->settings->presencetype = tmparea->presencetype;
    621 		//
    622 		qprintf("\r%6d", ++i);
    623 	} //end for
    624 	qprintf("\n");
    625 #ifdef AASINFO
    626 	Log_Print("%6d grounded areas\n", numgrounded);
    627 	Log_Print("%6d ladder areas\n", numladderareas);
    628 	Log_Print("%6d liquid areas\n", numliquidareas);
    629 #endif //AASINFO
    630 } //end of the function AAS_CreateAreaSettings
    631 //===========================================================================
    632 // create a tmp AAS area from a leaf node
    633 //
    634 // Parameter:				-
    635 // Returns:					-
    636 // Changes Globals:		-
    637 //===========================================================================
    638 tmp_node_t *AAS_CreateArea(node_t *node)
    639 {
    640 	int pside;
    641 	int areafaceflags;
    642 	portal_t	*p;
    643 	tmp_face_t *tmpface;
    644 	tmp_area_t *tmparea;
    645 	tmp_node_t *tmpnode;
    646 	vec3_t up = {0, 0, 1};
    647 
    648 	//create an area from this leaf
    649 	tmparea = AAS_AllocTmpArea();
    650 	tmparea->tmpfaces = NULL;
    651 	//clear the area face flags
    652 	areafaceflags = 0;
    653 	//make aas faces from the portals
    654 	for (p = node->portals; p; p = p->next[pside])
    655 	{
    656 		pside = (p->nodes[1] == node);
    657 		//don't create faces from very small portals
    658 //		if (WindingArea(p->winding) < 1) continue;
    659 		//if there's already a face created for this portal
    660 		if (p->tmpface)
    661 		{
    662 			//add the back side of the face to the area
    663 			AAS_AddFaceSideToArea(p->tmpface, 1, tmparea);
    664 		} //end if
    665 		else
    666 		{
    667 			tmpface = AAS_AllocTmpFace();
    668 			//set the face pointer at the portal so we can see from
    669 			//the portal there's a face created for it
    670 			p->tmpface = tmpface;
    671 			//FIXME: test this change
    672 			//tmpface->planenum = (p->planenum & ~1) | pside;
    673 			tmpface->planenum = p->planenum ^ pside;
    674 			if (pside) tmpface->winding = ReverseWinding(p->winding);
    675 			else tmpface->winding = CopyWinding(p->winding);
    676 #ifdef L_DEBUG
    677 			//
    678 			AAS_CheckFaceWindingPlane(tmpface);
    679 #endif //L_DEBUG
    680 			//if there's solid at the other side of the portal
    681 			if (p->nodes[!pside]->contents & (CONTENTS_SOLID | CONTENTS_PLAYERCLIP))
    682 			{
    683 				tmpface->faceflags |= FACE_SOLID;
    684 			} //end if
    685 			//else there is no solid at the other side and if there
    686 			//is a liquid at this side
    687 			else if (node->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA))
    688 			{
    689 				tmpface->faceflags |= FACE_LIQUID;
    690 				//if there's no liquid at the other side
    691 				if (!(p->nodes[!pside]->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)))
    692 				{
    693 					tmpface->faceflags |= FACE_LIQUIDSURFACE;
    694 				} //end if
    695 			} //end else
    696 			//if there's ladder contents at other side of the portal
    697 			if ((p->nodes[pside]->contents & CONTENTS_LADDER) ||
    698 					(p->nodes[!pside]->contents & CONTENTS_LADDER))
    699 			{
    700 
    701 				//NOTE: doesn't have to be solid at the other side because
    702 				// when standing one can use a crouch area (which is not solid)
    703 				// as a ladder
    704 				// imagine a ladder one can walk underthrough,
    705 				// under the ladder against the ladder is a crouch area
    706 				// the (vertical) sides of this crouch area area also used as
    707 				// ladder sides when standing (not crouched)
    708 				tmpface->faceflags |= FACE_LADDER;
    709 			} //end if
    710 			//if it is possible to stand on the face
    711 			if (AAS_GroundFace(tmpface))
    712 			{
    713 				tmpface->faceflags |= FACE_GROUND;
    714 			} //end if
    715 			//
    716 			areafaceflags |= tmpface->faceflags;
    717 			//no aas face number yet (zero is a dummy in the aasworld faces)
    718 			tmpface->aasfacenum = 0;
    719 			//add the front side of the face to the area
    720 			AAS_AddFaceSideToArea(tmpface, 0, tmparea);
    721 		} //end else
    722 	} //end for
    723 	qprintf("\r%6d", tmparea->areanum);
    724 	//presence type in the area
    725 	tmparea->presencetype = ~node->expansionbboxes & cfg.allpresencetypes;
    726 	//
    727 	tmparea->contents = 0;
    728 	if (node->contents & CONTENTS_CLUSTERPORTAL) tmparea->contents |= AREACONTENTS_CLUSTERPORTAL;
    729 	if (node->contents & CONTENTS_MOVER) tmparea->contents |= AREACONTENTS_MOVER;
    730 	if (node->contents & CONTENTS_TELEPORTER) tmparea->contents |= AREACONTENTS_TELEPORTER;
    731 	if (node->contents & CONTENTS_JUMPPAD) tmparea->contents |= AREACONTENTS_JUMPPAD;
    732 	if (node->contents & CONTENTS_DONOTENTER) tmparea->contents |= AREACONTENTS_DONOTENTER;
    733 	if (node->contents & CONTENTS_WATER) tmparea->contents |= AREACONTENTS_WATER;
    734 	if (node->contents & CONTENTS_LAVA) tmparea->contents |= AREACONTENTS_LAVA;
    735 	if (node->contents & CONTENTS_SLIME) tmparea->contents |= AREACONTENTS_SLIME;
    736 	if (node->contents & CONTENTS_NOTTEAM1) tmparea->contents |= AREACONTENTS_NOTTEAM1;
    737 	if (node->contents & CONTENTS_NOTTEAM2) tmparea->contents |= AREACONTENTS_NOTTEAM2;
    738 
    739 	//store the bsp model that's inside this node
    740 	tmparea->modelnum = node->modelnum;
    741 	//sorta check for flipped area faces (remove??)
    742 	AAS_FlipAreaFaces(tmparea);
    743 	//check if the area is ok (remove??)
    744 	AAS_CheckArea(tmparea);
    745 	//
    746 	tmpnode = AAS_AllocTmpNode();
    747 	tmpnode->planenum = 0;
    748 	tmpnode->children[0] = 0;
    749 	tmpnode->children[1] = 0;
    750 	tmpnode->tmparea = tmparea;
    751 	//
    752 	return tmpnode;
    753 } //end of the function AAS_CreateArea
    754 //===========================================================================
    755 //
    756 // Parameter:				-
    757 // Returns:					-
    758 // Changes Globals:		-
    759 //===========================================================================
    760 tmp_node_t *AAS_CreateAreas_r(node_t *node)
    761 {
    762 	tmp_node_t *tmpnode;
    763 
    764 	//recurse down to leafs
    765 	if (node->planenum != PLANENUM_LEAF)
    766 	{
    767 		//the first tmp node is a dummy
    768 		tmpnode = AAS_AllocTmpNode();
    769 		tmpnode->planenum = node->planenum;
    770 		tmpnode->children[0] = AAS_CreateAreas_r(node->children[0]);
    771 		tmpnode->children[1] = AAS_CreateAreas_r(node->children[1]);
    772 		return tmpnode;
    773 	} //end if
    774 	//areas won't be created for solid leafs
    775 	if (node->contents & CONTENTS_SOLID)
    776 	{
    777 		//just return zero for a solid leaf (in tmp AAS NULL is a solid leaf)
    778 		return NULL;
    779 	} //end if
    780 
    781 	return AAS_CreateArea(node);
    782 } //end of the function AAS_CreateAreas_r
    783 //===========================================================================
    784 //
    785 // Parameter:				-
    786 // Returns:					-
    787 // Changes Globals:		-
    788 //===========================================================================
    789 void AAS_CreateAreas(node_t *node)
    790 {
    791 	Log_Write("AAS_CreateAreas\r\n");
    792 	qprintf("%6d areas created", 0);
    793 	tmpaasworld.nodes = AAS_CreateAreas_r(node);
    794 	qprintf("\n");
    795 	Log_Write("%6d areas created\r\n", tmpaasworld.numareas);
    796 } //end of the function AAS_CreateAreas
    797 //===========================================================================
    798 //
    799 // Parameter:				-
    800 // Returns:					-
    801 // Changes Globals:		-
    802 //===========================================================================
    803 void AAS_PrintNumGroundFaces(void)
    804 {
    805 	tmp_face_t *tmpface;
    806 	int numgroundfaces = 0;
    807 
    808 	for (tmpface = tmpaasworld.faces; tmpface; tmpface = tmpface->l_next)
    809 	{
    810 		if (tmpface->faceflags & FACE_GROUND)
    811 		{
    812 			numgroundfaces++;
    813 		} //end if
    814 	} //end for
    815 	qprintf("%6d ground faces\n", numgroundfaces);
    816 } //end of the function AAS_PrintNumGroundFaces
    817 //===========================================================================
    818 // checks the number of shared faces between the given two areas
    819 // since areas are convex they should only have ONE shared face
    820 // however due to crappy face merging there are sometimes several
    821 // shared faces
    822 //
    823 // Parameter:				-
    824 // Returns:					-
    825 // Changes Globals:		-
    826 //===========================================================================
    827 void AAS_CheckAreaSharedFaces(tmp_area_t *tmparea1, tmp_area_t *tmparea2)
    828 {
    829 	int numsharedfaces, side;
    830 	tmp_face_t *face1, *sharedface;
    831 
    832 	if (tmparea1->invalid || tmparea2->invalid) return;
    833 
    834 	sharedface = NULL;
    835 	numsharedfaces = 0;
    836 	for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side])
    837 	{
    838 		side = face1->frontarea != tmparea1;
    839 		if (face1->backarea == tmparea2 || face1->frontarea == tmparea2)
    840 		{
    841 			sharedface = face1;
    842 			numsharedfaces++;
    843 		} //end if
    844 	} //end if
    845 	if (!sharedface) return;
    846 	//the areas should only have one shared face
    847 	if (numsharedfaces > 1)
    848 	{
    849 		Log_Write("---- tmp area %d and %d have %d shared faces\r\n",
    850 									tmparea1->areanum, tmparea2->areanum, numsharedfaces);
    851 		for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side])
    852 		{
    853 			side = face1->frontarea != tmparea1;
    854 			if (face1->backarea == tmparea2 || face1->frontarea == tmparea2)
    855 			{
    856 				Log_Write("face %d, planenum = %d, face->frontarea = %d face->backarea = %d\r\n",
    857 								face1->num, face1->planenum, face1->frontarea->areanum, face1->backarea->areanum);
    858 			} //end if
    859 		} //end if
    860 	} //end if
    861 } //end of the function AAS_CheckAreaSharedFaces
    862 //===========================================================================
    863 //
    864 // Parameter:				-
    865 // Returns:					-
    866 // Changes Globals:		-
    867 //===========================================================================
    868 void AAS_CheckSharedFaces(void)
    869 {
    870 	tmp_area_t *tmparea1, *tmparea2;
    871 
    872 	for (tmparea1 = tmpaasworld.areas; tmparea1; tmparea1 = tmparea1->l_next)
    873 	{
    874 		for (tmparea2 = tmpaasworld.areas; tmparea2; tmparea2 = tmparea2->l_next)
    875 		{
    876 			if (tmparea1 == tmparea2) continue;
    877 			AAS_CheckAreaSharedFaces(tmparea1, tmparea2);
    878 		} //end for
    879 	} //end for
    880 } //end of the function AAS_CheckSharedFaces
    881 //===========================================================================
    882 //
    883 // Parameter:				-
    884 // Returns:					-
    885 // Changes Globals:		-
    886 //===========================================================================
    887 void AAS_FlipFace(tmp_face_t *face)
    888 {
    889 	tmp_area_t *frontarea, *backarea;
    890 	winding_t *w;
    891 
    892 	frontarea = face->frontarea;
    893 	backarea = face->backarea;
    894 	//must have an area at both sides before flipping is allowed
    895 	if (!frontarea || !backarea) return;
    896 	//flip the face winding
    897 	w = face->winding;
    898 	face->winding = ReverseWinding(w);
    899 	FreeWinding(w);
    900 	//flip the face plane
    901 	face->planenum ^= 1;
    902 	//flip the face areas
    903 	AAS_RemoveFaceFromArea(face, frontarea);
    904 	AAS_RemoveFaceFromArea(face, backarea);
    905 	AAS_AddFaceSideToArea(face, 1, frontarea);
    906 	AAS_AddFaceSideToArea(face, 0, backarea);
    907 } //end of the function AAS_FlipFace
    908 //===========================================================================
    909 //
    910 // Parameter:				-
    911 // Returns:					-
    912 // Changes Globals:		-
    913 //===========================================================================
    914 /*
    915 void AAS_FlipAreaSharedFaces(tmp_area_t *tmparea1, tmp_area_t *tmparea2)
    916 {
    917 	int numsharedfaces, side, area1facing, area2facing;
    918 	tmp_face_t *face1, *sharedface;
    919 
    920 	if (tmparea1->invalid || tmparea2->invalid) return;
    921 
    922 	sharedface = NULL;
    923 	numsharedfaces = 0;
    924 	area1facing = 0;		//number of shared faces facing towards area 1
    925 	area2facing = 0;		//number of shared faces facing towards area 2
    926 	for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side])
    927 	{
    928 		side = face1->frontarea != tmparea1;
    929 		if (face1->backarea == tmparea2 || face1->frontarea == tmparea2)
    930 		{
    931 			sharedface = face1;
    932 			numsharedfaces++;
    933 			if (face1->frontarea == tmparea1) area1facing++;
    934 			else area2facing++;
    935 		} //end if
    936 	} //end if
    937 	if (!sharedface) return;
    938 	//if there's only one shared face
    939 	if (numsharedfaces <= 1) return;
    940 	//if all the shared faces are facing to the same area
    941 	if (numsharedfaces == area1facing || numsharedfaces == area2facing) return;
    942 	//
    943 	do
    944 	{
    945 		for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side])
    946 		{
    947 			side = face1->frontarea != tmparea1;
    948 			if (face1->backarea == tmparea2 || face1->frontarea == tmparea2)
    949 			{
    950 				if (face1->frontarea != tmparea1)
    951 				{
    952 					AAS_FlipFace(face1);
    953 					break;
    954 				} //end if
    955 			} //end if
    956 		} //end for
    957 	} while(face1);
    958 } //end of the function AAS_FlipAreaSharedFaces
    959 //===========================================================================
    960 //
    961 // Parameter:				-
    962 // Returns:					-
    963 // Changes Globals:		-
    964 //===========================================================================
    965 void AAS_FlipSharedFaces(void)
    966 {
    967 	int i;
    968 	tmp_area_t *tmparea1, *tmparea2;
    969 
    970 	i = 0;
    971 	qprintf("%6d areas checked for shared face flipping", i);
    972 	for (tmparea1 = tmpaasworld.areas; tmparea1; tmparea1 = tmparea1->l_next)
    973 	{
    974 		if (tmparea1->invalid) continue;
    975 		for (tmparea2 = tmpaasworld.areas; tmparea2; tmparea2 = tmparea2->l_next)
    976 		{
    977 			if (tmparea2->invalid) continue;
    978 			if (tmparea1 == tmparea2) continue;
    979 			AAS_FlipAreaSharedFaces(tmparea1, tmparea2);
    980 		} //end for
    981 		qprintf("\r%6d", ++i);
    982 	} //end for
    983 	Log_Print("\r%6d areas checked for shared face flipping\n", i);
    984 } //end of the function AAS_FlipSharedFaces
    985 */
    986 //===========================================================================
    987 //
    988 // Parameter:				-
    989 // Returns:					-
    990 // Changes Globals:		-
    991 //===========================================================================
    992 void AAS_FlipSharedFaces(void)
    993 {
    994 	int i, side1, side2;
    995 	tmp_area_t *tmparea1;
    996 	tmp_face_t *face1, *face2;
    997 
    998 	i = 0;
    999 	qprintf("%6d areas checked for shared face flipping", i);
   1000 	for (tmparea1 = tmpaasworld.areas; tmparea1; tmparea1 = tmparea1->l_next)
   1001 	{
   1002 		if (tmparea1->invalid) continue;
   1003 		for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side1])
   1004 		{
   1005 			side1 = face1->frontarea != tmparea1;
   1006 			if (!face1->frontarea || !face1->backarea) continue;
   1007 			//
   1008 			for (face2 = face1->next[side1]; face2; face2 = face2->next[side2])
   1009 			{
   1010 				side2 = face2->frontarea != tmparea1;
   1011 				if (!face2->frontarea || !face2->backarea) continue;
   1012 				//
   1013 				if (face1->frontarea == face2->backarea &&
   1014 					face1->backarea == face2->frontarea)
   1015 				{
   1016 					AAS_FlipFace(face2);
   1017 				} //end if
   1018 				//recheck side
   1019 				side2 = face2->frontarea != tmparea1;
   1020 			} //end for
   1021 		} //end for
   1022 		qprintf("\r%6d", ++i);
   1023 	} //end for
   1024 	qprintf("\n");
   1025 	Log_Write("%6d areas checked for shared face flipping\r\n", i);
   1026 } //end of the function AAS_FlipSharedFaces
   1027 //===========================================================================
   1028 // creates an .AAS file with the given name
   1029 // a MAP should be loaded before calling this
   1030 //
   1031 // Parameter:				-
   1032 // Returns:					-
   1033 // Changes Globals:		-
   1034 //===========================================================================
   1035 void AAS_Create(char *aasfile)
   1036 {
   1037 	entity_t	*e;
   1038 	tree_t *tree;
   1039 	double start_time;
   1040 
   1041 	//for a possible leak file
   1042 	strcpy(source, aasfile);
   1043 	StripExtension(source);
   1044 	//the time started
   1045 	start_time = I_FloatTime();
   1046 	//set the default number of threads (depends on number of processors)
   1047 	ThreadSetDefault();
   1048 	//set the global entity number to the world model
   1049 	entity_num = 0;
   1050 	//the world entity
   1051 	e = &entities[entity_num];
   1052 	//process the whole world
   1053 	tree = ProcessWorldBrushes(e->firstbrush, e->firstbrush + e->numbrushes);
   1054 	//if the conversion is cancelled
   1055 	if (cancelconversion)
   1056 	{
   1057 		Tree_Free(tree);
   1058 		return;
   1059 	} //end if
   1060 	//display BSP tree creation time
   1061 	Log_Print("BSP tree created in %5.0f seconds\n", I_FloatTime() - start_time);
   1062 	//prune the bsp tree
   1063 	Tree_PruneNodes(tree->headnode);
   1064 	//if the conversion is cancelled
   1065 	if (cancelconversion)
   1066 	{
   1067 		Tree_Free(tree);
   1068 		return;
   1069 	} //end if
   1070 	//create the tree portals
   1071 	MakeTreePortals(tree);
   1072 	//if the conversion is cancelled
   1073 	if (cancelconversion)
   1074 	{
   1075 		Tree_Free(tree);
   1076 		return;
   1077 	} //end if
   1078 	//Marks all nodes that can be reached by entites
   1079 	if (FloodEntities(tree))
   1080 	{
   1081 		//fill out nodes that can't be reached
   1082 		FillOutside(tree->headnode);
   1083 	} //end if
   1084 	else
   1085 	{
   1086 		LeakFile(tree);
   1087 		Error("**** leaked ****\n");
   1088 		return;
   1089 	} //end else
   1090 	//create AAS from the BSP tree
   1091 	//==========================================
   1092 	//initialize tmp aas
   1093 	AAS_InitTmpAAS();
   1094 	//create the convex areas from the leaves
   1095 	AAS_CreateAreas(tree->headnode);
   1096 	//free the BSP tree because it isn't used anymore
   1097 	if (freetree) Tree_Free(tree);
   1098 	//try to merge area faces
   1099 	AAS_MergeAreaFaces();
   1100 	//do gravitational subdivision
   1101 	AAS_GravitationalSubdivision();
   1102 	//merge faces if possible
   1103 	AAS_MergeAreaFaces();
   1104 	AAS_RemoveAreaFaceColinearPoints();
   1105 	//merge areas if possible
   1106 	AAS_MergeAreas();
   1107 	//NOTE: prune nodes directly after area merging
   1108 	AAS_PruneNodes();
   1109 	//flip shared faces so they are all facing to the same area
   1110 	AAS_FlipSharedFaces();
   1111 	AAS_RemoveAreaFaceColinearPoints();
   1112 	//merge faces if possible
   1113 	AAS_MergeAreaFaces();
   1114 	//merge area faces in the same plane
   1115 	AAS_MergeAreaPlaneFaces();
   1116 	//do ladder subdivision
   1117 	AAS_LadderSubdivision();
   1118 	//FIXME: melting is buggy
   1119 	AAS_MeltAreaFaceWindings();
   1120 	//remove tiny faces
   1121 	AAS_RemoveTinyFaces();
   1122 	//create area settings
   1123 	AAS_CreateAreaSettings();
   1124 	//check if the winding plane is equal to the face plane
   1125 	//AAS_CheckAreaWindingPlanes();
   1126 	//
   1127 	//AAS_CheckSharedFaces();
   1128 	//==========================================
   1129 	//if the conversion is cancelled
   1130 	if (cancelconversion)
   1131 	{
   1132 		Tree_Free(tree);
   1133 		AAS_FreeTmpAAS();
   1134 		return;
   1135 	} //end if
   1136 	//store the created AAS stuff in the AAS file format and write the file
   1137 	AAS_StoreFile(aasfile);
   1138 	//free the temporary AAS memory
   1139 	AAS_FreeTmpAAS();
   1140 	//display creation time
   1141 	Log_Print("\nAAS created in %5.0f seconds\n", I_FloatTime() - start_time);
   1142 } //end of the function AAS_Create