Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

tetrahedron.c (42552B)


      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 "l_mem.h"
     25 #include "../botlib/aasfile.h"
     26 #include "aas_store.h"
     27 #include "aas_cfg.h"
     28 #include "aas_file.h"
     29 
     30 //
     31 // creating tetrahedrons from a arbitrary world bounded by triangles
     32 //
     33 // a triangle has 3 corners and 3 edges
     34 // a tetrahedron is build out of 4 triangles
     35 // a tetrahedron has 6 edges
     36 // we start with a world bounded by triangles, a side of a triangle facing
     37 // towards the oudside of the world is marked as part of tetrahedron -1
     38 //
     39 // a tetrahedron is defined by two non-coplanar triangles with a shared edge
     40 //
     41 // a tetrahedron is defined by one triangle and a vertex not in the triangle plane
     42 //
     43 // if all triangles using a specific vertex have tetrahedrons
     44 // at both sides then this vertex will never be part of a new tetrahedron
     45 //
     46 // if all triangles using a specific edge have tetrahedrons
     47 // at both sides then this vertex will never be part of a new tetrahedron
     48 //
     49 // each triangle can only be shared by two tetrahedrons
     50 // when all triangles have tetrahedrons at both sides then we're done
     51 //
     52 // if we cannot create any new tetrahedrons and there is at least one triangle
     53 // which has a tetrahedron only at one side then the world leaks
     54 //
     55 
     56 #define Sign(x)		(x < 0 ? 1 : 0)
     57 
     58 #define MAX_TH_VERTEXES			128000
     59 #define MAX_TH_PLANES			128000
     60 #define MAX_TH_EDGES			512000
     61 #define MAX_TH_TRIANGLES		51200
     62 #define MAX_TH_TETRAHEDRONS		12800
     63 
     64 #define PLANEHASH_SIZE			1024
     65 #define EDGEHASH_SIZE			1024
     66 #define TRIANGLEHASH_SIZE		1024
     67 #define VERTEXHASH_SHIFT		7
     68 #define VERTEXHASH_SIZE			((MAX_MAP_BOUNDS>>(VERTEXHASH_SHIFT-1))+1)	//was 64
     69 
     70 #define	NORMAL_EPSILON			0.0001
     71 #define DIST_EPSILON			0.1
     72 #define VERTEX_EPSILON			0.01
     73 #define INTEGRAL_EPSILON		0.01
     74 
     75 
     76 //plane
     77 typedef struct th_plane_s
     78 {
     79 	vec3_t normal;
     80 	float dist;
     81 	int type;
     82 	int signbits;
     83 	struct th_plane_s *hashnext;		//next plane in hash
     84 } th_plane_t;
     85 
     86 //vertex
     87 typedef struct th_vertex_s
     88 {
     89 	vec3_t v;
     90 	int usercount;						//2x the number of to be processed
     91 										//triangles using this vertex
     92 	struct th_vertex_s *hashnext;		//next vertex in hash
     93 } th_vertex_t;
     94 
     95 //edge
     96 typedef struct th_edge_s
     97 {
     98 	int v[2];							//vertex indexes
     99 	int usercount;						//number of to be processed
    100 										//triangles using this edge
    101 	struct th_edge_s *hashnext;			//next edge in hash
    102 } th_edge_t;
    103 
    104 //triangle
    105 typedef struct th_triangle_s
    106 {
    107 	int edges[3];						//negative if edge is flipped
    108 	th_plane_t planes[3];				//triangle bounding planes
    109 	int planenum;						//plane the triangle is in
    110 	int front;							//tetrahedron at the front
    111 	int back;							//tetrahedron at the back
    112 	vec3_t mins, maxs;					//triangle bounding box
    113 	struct th_triangle_s *prev, *next;	//links in linked triangle lists
    114 	struct th_triangle_s *hashnext;		//next triangle in hash
    115 } th_triangle_t;
    116 
    117 //tetrahedron
    118 typedef struct th_tetrahedron_s
    119 {
    120 	int triangles[4];					//negative if at backside of triangle
    121 	float volume;						//tetrahedron volume
    122 } th_tetrahedron_t;
    123 
    124 typedef struct th_s
    125 {
    126 	//vertexes
    127 	int numvertexes;
    128 	th_vertex_t *vertexes;
    129 	th_vertex_t *vertexhash[VERTEXHASH_SIZE * VERTEXHASH_SIZE];
    130 	//planes
    131 	int numplanes;
    132 	th_plane_t *planes;
    133 	th_plane_t *planehash[PLANEHASH_SIZE];
    134 	//edges
    135 	int numedges;
    136 	th_edge_t *edges;
    137 	th_edge_t *edgehash[EDGEHASH_SIZE];
    138 	//triangles
    139 	int numtriangles;
    140 	th_triangle_t *triangles;
    141 	th_triangle_t *trianglehash[TRIANGLEHASH_SIZE];
    142 	//tetrahedrons
    143 	int numtetrahedrons;
    144 	th_tetrahedron_t *tetrahedrons;
    145 } th_t;
    146 
    147 th_t thworld;
    148 
    149 //===========================================================================
    150 //
    151 // Parameter:			-
    152 // Returns:				-
    153 // Changes Globals:		-
    154 //===========================================================================
    155 void TH_InitMaxTH(void)
    156 {
    157 	//get memory for the tetrahedron data
    158 	thworld.vertexes = (th_vertex_t *) GetClearedMemory(MAX_TH_VERTEXES * sizeof(th_vertex_t));
    159 	thworld.planes = (th_plane_t *) GetClearedMemory(MAX_TH_PLANES * sizeof(th_plane_t));
    160 	thworld.edges = (th_edge_t *) GetClearedMemory(MAX_TH_EDGES * sizeof(th_edge_t));
    161 	thworld.triangles = (th_triangle_t *) GetClearedMemory(MAX_TH_TRIANGLES * sizeof(th_triangle_t));
    162 	thworld.tetrahedrons = (th_tetrahedron_t *) GetClearedMemory(MAX_TH_TETRAHEDRONS * sizeof(th_tetrahedron_t));
    163 	//reset the hash tables
    164 	memset(thworld.vertexhash, 0, VERTEXHASH_SIZE * sizeof(th_vertex_t *));
    165 	memset(thworld.planehash, 0, PLANEHASH_SIZE * sizeof(th_plane_t *));
    166 	memset(thworld.edgehash, 0, EDGEHASH_SIZE * sizeof(th_edge_t *));
    167 	memset(thworld.trianglehash, 0, TRIANGLEHASH_SIZE * sizeof(th_triangle_t *));
    168 } //end of the function TH_InitMaxTH
    169 //===========================================================================
    170 //
    171 // Parameter:			-
    172 // Returns:				-
    173 // Changes Globals:		-
    174 //===========================================================================
    175 void TH_FreeMaxTH(void)
    176 {
    177 	if (thworld.vertexes) FreeMemory(thworld.vertexes);
    178 	thworld.vertexes = NULL;
    179 	thworld.numvertexes = 0;
    180 	if (thworld.planes) FreeMemory(thworld.planes);
    181 	thworld.planes = NULL;
    182 	thworld.numplanes = 0;
    183 	if (thworld.edges) FreeMemory(thworld.edges);
    184 	thworld.edges = NULL;
    185 	thworld.numedges = 0;
    186 	if (thworld.triangles) FreeMemory(thworld.triangles);
    187 	thworld.triangles = NULL;
    188 	thworld.numtriangles = 0;
    189 	if (thworld.tetrahedrons) FreeMemory(thworld.tetrahedrons);
    190 	thworld.tetrahedrons = NULL;
    191 	thworld.numtetrahedrons = 0;
    192 } //end of the function TH_FreeMaxTH
    193 //===========================================================================
    194 //
    195 // Parameter:			-
    196 // Returns:				-
    197 // Changes Globals:		-
    198 //===========================================================================
    199 float TH_TriangleArea(th_triangle_t *tri)
    200 {
    201 	return 0;
    202 } //end of the function TH_TriangleArea
    203 //===========================================================================
    204 //
    205 // Parameter:			-
    206 // Returns:				-
    207 // Changes Globals:		-
    208 //===========================================================================
    209 float TH_TetrahedronVolume(th_tetrahedron_t *tetrahedron)
    210 {
    211 	int edgenum, verts[3], i, j, v2;
    212 	float volume, d;
    213 	th_triangle_t *tri, *tri2;
    214 	th_plane_t *plane;
    215 
    216 	tri = &thworld.triangles[abs(tetrahedron->triangles[0])];
    217 	for (i = 0; i < 3; i++)
    218 	{
    219 		edgenum = tri->edges[i];
    220 		if (edgenum < 0) verts[i] = thworld.edges[abs(edgenum)].v[1];
    221 		else verts[i] = thworld.edges[edgenum].v[0];
    222 	} //end for
    223 	//
    224 	tri2 = &thworld.triangles[abs(tetrahedron->triangles[1])];
    225 	for (j = 0; j < 3; j++)
    226 	{
    227 		edgenum = tri2->edges[i];
    228 		if (edgenum < 0) v2 = thworld.edges[abs(edgenum)].v[1];
    229 		else v2 = thworld.edges[edgenum].v[0];
    230 		if (v2 != verts[0] &&
    231 			v2 != verts[1] &&
    232 			v2 != verts[2]) break;
    233 	} //end for
    234 
    235 	plane = &thworld.planes[tri->planenum];
    236 	d = -(DotProduct (thworld.vertexes[v2].v, plane->normal) - plane->dist);
    237 	volume = TH_TriangleArea(tri) * d / 3;
    238 	return volume;
    239 } //end of the function TH_TetrahedronVolume
    240 //===========================================================================
    241 //
    242 // Parameter:			-
    243 // Returns:				-
    244 // Changes Globals:		-
    245 //===========================================================================
    246 int TH_PlaneSignBits(vec3_t normal)
    247 {
    248 	int i, signbits;
    249 
    250 	signbits = 0;
    251 	for (i = 2; i >= 0; i--)
    252 	{
    253 		signbits = (signbits << 1) + Sign(normal[i]);
    254 	} //end for
    255 	return signbits;
    256 } //end of the function TH_PlaneSignBits
    257 //===========================================================================
    258 //
    259 // Parameter:			-
    260 // Returns:				-
    261 // Changes Globals:		-
    262 //===========================================================================
    263 int TH_PlaneTypeForNormal(vec3_t normal)
    264 {
    265 	vec_t	ax, ay, az;
    266 	
    267 // NOTE: should these have an epsilon around 1.0?		
    268 	if (normal[0] == 1.0 || normal[0] == -1.0)
    269 		return PLANE_X;
    270 	if (normal[1] == 1.0 || normal[1] == -1.0)
    271 		return PLANE_Y;
    272 	if (normal[2] == 1.0 || normal[2] == -1.0)
    273 		return PLANE_Z;
    274 		
    275 	ax = fabs(normal[0]);
    276 	ay = fabs(normal[1]);
    277 	az = fabs(normal[2]);
    278 	
    279 	if (ax >= ay && ax >= az)
    280 		return PLANE_ANYX;
    281 	if (ay >= ax && ay >= az)
    282 		return PLANE_ANYY;
    283 	return PLANE_ANYZ;
    284 } //end of the function TH_PlaneTypeForNormal
    285 //===========================================================================
    286 //
    287 // Parameter:			-
    288 // Returns:				-
    289 // Changes Globals:		-
    290 //===========================================================================
    291 qboolean TH_PlaneEqual(th_plane_t *p, vec3_t normal, vec_t dist)
    292 {
    293 	if (
    294 	   fabs(p->normal[0] - normal[0]) < NORMAL_EPSILON
    295 	&& fabs(p->normal[1] - normal[1]) < NORMAL_EPSILON
    296 	&& fabs(p->normal[2] - normal[2]) < NORMAL_EPSILON
    297 	&& fabs(p->dist - dist) < DIST_EPSILON )
    298 		return true;
    299 	return false;
    300 } //end of the function TH_PlaneEqual
    301 //===========================================================================
    302 //
    303 // Parameter:			-
    304 // Returns:				-
    305 // Changes Globals:		-
    306 //===========================================================================
    307 void TH_AddPlaneToHash(th_plane_t *p)
    308 {
    309 	int hash;
    310 
    311 	hash = (int)fabs(p->dist) / 8;
    312 	hash &= (PLANEHASH_SIZE-1);
    313 
    314 	p->hashnext = thworld.planehash[hash];
    315 	thworld.planehash[hash] = p;
    316 } //end of the function TH_AddPlaneToHash
    317 //===========================================================================
    318 //
    319 // Parameter:			-
    320 // Returns:				-
    321 // Changes Globals:		-
    322 //===========================================================================
    323 int TH_CreateFloatPlane(vec3_t normal, vec_t dist)
    324 {
    325 	th_plane_t *p, temp;
    326 
    327 	if (VectorLength(normal) < 0.5)
    328 		Error ("FloatPlane: bad normal");
    329 	// create a new plane
    330 	if (thworld.numplanes+2 > MAX_TH_PLANES)
    331 		Error ("MAX_TH_PLANES");
    332 
    333 	p = &thworld.planes[thworld.numplanes];
    334 	VectorCopy (normal, p->normal);
    335 	p->dist = dist;
    336 	p->type = (p+1)->type = TH_PlaneTypeForNormal (p->normal);
    337 	p->signbits = TH_PlaneSignBits(p->normal);
    338 
    339 	VectorSubtract (vec3_origin, normal, (p+1)->normal);
    340 	(p+1)->dist = -dist;
    341 	(p+1)->signbits = TH_PlaneSignBits((p+1)->normal);
    342 
    343 	thworld.numplanes += 2;
    344 
    345 	// allways put axial planes facing positive first
    346 	if (p->type < 3)
    347 	{
    348 		if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0)
    349 		{
    350 			// flip order
    351 			temp = *p;
    352 			*p = *(p+1);
    353 			*(p+1) = temp;
    354 
    355 			TH_AddPlaneToHash(p);
    356 			TH_AddPlaneToHash(p+1);
    357 			return thworld.numplanes - 1;
    358 		} //end if
    359 	} //end if
    360 
    361 	TH_AddPlaneToHash(p);
    362 	TH_AddPlaneToHash(p+1);
    363 	return thworld.numplanes - 2;
    364 } //end of the function TH_CreateFloatPlane
    365 //===========================================================================
    366 //
    367 // Parameter:			-
    368 // Returns:				-
    369 // Changes Globals:		-
    370 //===========================================================================
    371 void TH_SnapVector(vec3_t normal)
    372 {
    373 	int		i;
    374 
    375 	for (i = 0; i < 3; i++)
    376 	{
    377 		if ( fabs(normal[i] - 1) < NORMAL_EPSILON )
    378 		{
    379 			VectorClear (normal);
    380 			normal[i] = 1;
    381 			break;
    382 		} //end if
    383 		if ( fabs(normal[i] - -1) < NORMAL_EPSILON )
    384 		{
    385 			VectorClear (normal);
    386 			normal[i] = -1;
    387 			break;
    388 		} //end if
    389 	} //end for
    390 } //end of the function TH_SnapVector
    391 //===========================================================================
    392 //
    393 // Parameter:			-
    394 // Returns:				-
    395 // Changes Globals:		-
    396 //===========================================================================
    397 void TH_SnapPlane(vec3_t normal, vec_t *dist)
    398 {
    399 	TH_SnapVector(normal);
    400 
    401 	if (fabs(*dist-Q_rint(*dist)) < DIST_EPSILON)
    402 		*dist = Q_rint(*dist);
    403 } //end of the function TH_SnapPlane
    404 //===========================================================================
    405 //
    406 // Parameter:			-
    407 // Returns:				-
    408 // Changes Globals:		-
    409 //===========================================================================
    410 int TH_FindFloatPlane(vec3_t normal, vec_t dist)
    411 {
    412 	int i;
    413 	th_plane_t *p;
    414 	int hash, h;
    415 
    416 	TH_SnapPlane (normal, &dist);
    417 	hash = (int)fabs(dist) / 8;
    418 	hash &= (PLANEHASH_SIZE-1);
    419 
    420 	// search the border bins as well
    421 	for (i = -1; i <= 1; i++)
    422 	{
    423 		h = (hash+i)&(PLANEHASH_SIZE-1);
    424 		for (p = thworld.planehash[h]; p; p = p->hashnext)
    425 		{
    426 			if (TH_PlaneEqual(p, normal, dist))
    427 			{
    428 				return p - thworld.planes;
    429 			} //end if
    430 		} //end for
    431 	} //end for
    432 	return TH_CreateFloatPlane(normal, dist);
    433 } //end of the function TH_FindFloatPlane
    434 //===========================================================================
    435 //
    436 // Parameter:			-
    437 // Returns:				-
    438 // Changes Globals:		-
    439 //===========================================================================
    440 int TH_PlaneFromPoints(int v1, int v2, int v3)
    441 {
    442 	vec3_t t1, t2, normal;
    443 	vec_t dist;
    444 	float *p0, *p1, *p2;
    445 
    446 	p0 = thworld.vertexes[v1].v;
    447 	p1 = thworld.vertexes[v2].v;
    448 	p2 = thworld.vertexes[v3].v;
    449 
    450 	VectorSubtract(p0, p1, t1);
    451 	VectorSubtract(p2, p1, t2);
    452 	CrossProduct(t1, t2, normal);
    453 	VectorNormalize(normal);
    454 
    455 	dist = DotProduct(p0, normal);
    456 
    457 	return TH_FindFloatPlane(normal, dist);
    458 } //end of the function TH_PlaneFromPoints
    459 //===========================================================================
    460 //
    461 // Parameter:			-
    462 // Returns:				-
    463 // Changes Globals:		-
    464 //===========================================================================
    465 void TH_AddEdgeUser(int edgenum)
    466 {
    467 	th_edge_t *edge;
    468 
    469 	edge = &thworld.edges[abs(edgenum)];
    470 	//increase edge user count
    471 	edge->usercount++;
    472 	//increase vertex user count as well
    473 	thworld.vertexes[edge->v[0]].usercount++;
    474 	thworld.vertexes[edge->v[1]].usercount++;
    475 } //end of the function TH_AddEdgeUser
    476 //===========================================================================
    477 //
    478 // Parameter:			-
    479 // Returns:				-
    480 // Changes Globals:		-
    481 //===========================================================================
    482 void TH_RemoveEdgeUser(int edgenum)
    483 {
    484 	th_edge_t *edge;
    485 
    486 	edge = &thworld.edges[abs(edgenum)];
    487 	//decrease edge user count
    488 	edge->usercount--;
    489 	//decrease vertex user count as well
    490 	thworld.vertexes[edge->v[0]].usercount--;
    491 	thworld.vertexes[edge->v[1]].usercount--;
    492 } //end of the function TH_RemoveEdgeUser
    493 //===========================================================================
    494 //
    495 // Parameter:			-
    496 // Returns:				-
    497 // Changes Globals:		-
    498 //===========================================================================
    499 void TH_FreeTriangleEdges(th_triangle_t *tri)
    500 {
    501 	int i;
    502 
    503 	for (i = 0; i < 3; i++)
    504 	{
    505 		TH_RemoveEdgeUser(abs(tri->edges[i]));
    506 	} //end for
    507 } //end of the function TH_FreeTriangleEdges
    508 //===========================================================================
    509 //
    510 // Parameter:			-
    511 // Returns:				-
    512 // Changes Globals:		-
    513 //===========================================================================
    514 unsigned TH_HashVec(vec3_t vec)
    515 {
    516 	int x, y;
    517 
    518 	x = (MAX_MAP_BOUNDS + (int)(vec[0]+0.5)) >> VERTEXHASH_SHIFT;
    519 	y = (MAX_MAP_BOUNDS + (int)(vec[1]+0.5)) >> VERTEXHASH_SHIFT;
    520 
    521 	if (x < 0 || x >= VERTEXHASH_SIZE || y < 0 || y >= VERTEXHASH_SIZE)
    522 		Error("HashVec: point %f %f %f outside valid range", vec[0], vec[1], vec[2]);
    523 	
    524 	return y*VERTEXHASH_SIZE + x;
    525 } //end of the function TH_HashVec
    526 //===========================================================================
    527 //
    528 // Parameter:			-
    529 // Returns:				-
    530 // Changes Globals:		-
    531 //===========================================================================
    532 int TH_FindVertex(vec3_t v)
    533 {
    534 	int i, h;
    535 	th_vertex_t *vertex;
    536 	vec3_t vert;
    537 	
    538 	for (i = 0; i < 3; i++)
    539 	{
    540 		if ( fabs(v[i] - Q_rint(v[i])) < INTEGRAL_EPSILON)
    541 			vert[i] = Q_rint(v[i]);
    542 		else
    543 			vert[i] = v[i];
    544 	} //end for
    545 
    546 	h = TH_HashVec(vert);
    547 
    548 	for (vertex = thworld.vertexhash[h]; vertex; vertex = vertex->hashnext)
    549 	{
    550 		if (fabs(vertex->v[0] - vert[0]) < VERTEX_EPSILON &&
    551 			fabs(vertex->v[1] - vert[1]) < VERTEX_EPSILON &&
    552 			fabs(vertex->v[2] - vert[2]) < VERTEX_EPSILON)
    553 		{
    554 			return vertex - thworld.vertexes;
    555 		} //end if
    556 	} //end for
    557 	return 0;
    558 } //end of the function TH_FindVertex
    559 //===========================================================================
    560 //
    561 // Parameter:			-
    562 // Returns:				-
    563 // Changes Globals:		-
    564 //===========================================================================
    565 void TH_AddVertexToHash(th_vertex_t *vertex)
    566 {
    567 	int hashvalue;
    568 
    569 	hashvalue = TH_HashVec(vertex->v);
    570 	vertex->hashnext = thworld.vertexhash[hashvalue];
    571 	thworld.vertexhash[hashvalue] = vertex;
    572 } //end of the function TH_AddVertexToHash
    573 //===========================================================================
    574 //
    575 // Parameter:			-
    576 // Returns:				-
    577 // Changes Globals:		-
    578 //===========================================================================
    579 int TH_CreateVertex(vec3_t v)
    580 {
    581 	if (thworld.numvertexes == 0) thworld.numvertexes = 1;
    582 	if (thworld.numvertexes >= MAX_TH_VERTEXES)
    583 		Error("MAX_TH_VERTEXES");
    584 	VectorCopy(v, thworld.vertexes[thworld.numvertexes].v);
    585 	thworld.vertexes[thworld.numvertexes].usercount = 0;
    586 	TH_AddVertexToHash(&thworld.vertexes[thworld.numvertexes]);
    587 	thworld.numvertexes++;
    588 	return thworld.numvertexes-1;
    589 } //end of the function TH_CreateVertex
    590 //===========================================================================
    591 //
    592 // Parameter:			-
    593 // Returns:				-
    594 // Changes Globals:		-
    595 //===========================================================================
    596 int TH_FindOrCreateVertex(vec3_t v)
    597 {
    598 	int vertexnum;
    599 
    600 	vertexnum = TH_FindVertex(v);
    601 	if (!vertexnum) vertexnum = TH_CreateVertex(v);
    602 	return vertexnum;
    603 } //end of the function TH_FindOrCreateVertex
    604 //===========================================================================
    605 //
    606 // Parameter:			-
    607 // Returns:				-
    608 // Changes Globals:		-
    609 //===========================================================================
    610 int TH_FindEdge(int v1, int v2)
    611 {
    612 	int hashvalue;
    613 	th_edge_t *edge;
    614 
    615 	hashvalue = (v1 + v2) & (EDGEHASH_SIZE-1);
    616 
    617 	for (edge = thworld.edgehash[hashvalue]; edge; edge = edge->hashnext)
    618 	{
    619 		if (edge->v[0] == v1 && edge->v[1] == v2) return edge - thworld.edges;
    620 		if (edge->v[1] == v1 && edge->v[0] == v2) return -(edge - thworld.edges);
    621 	} //end for
    622 	return 0;
    623 } //end of the function TH_FindEdge
    624 //===========================================================================
    625 //
    626 // Parameter:			-
    627 // Returns:				-
    628 // Changes Globals:		-
    629 //===========================================================================
    630 void TH_AddEdgeToHash(th_edge_t *edge)
    631 {
    632 	int hashvalue;
    633 
    634 	hashvalue = (edge->v[0] + edge->v[1]) & (EDGEHASH_SIZE-1);
    635 	edge->hashnext = thworld.edgehash[hashvalue];
    636 	thworld.edgehash[hashvalue] = edge;
    637 } //end of the function TH_AddEdgeToHash
    638 //===========================================================================
    639 //
    640 // Parameter:			-
    641 // Returns:				-
    642 // Changes Globals:		-
    643 //===========================================================================
    644 int TH_CreateEdge(int v1, int v2)
    645 {
    646 	th_edge_t *edge;
    647 
    648 	if (thworld.numedges == 0) thworld.numedges = 1;
    649 	if (thworld.numedges >= MAX_TH_EDGES)
    650 		Error("MAX_TH_EDGES");
    651 	edge = &thworld.edges[thworld.numedges++];
    652 	edge->v[0] = v1;
    653 	edge->v[1] = v2;
    654 	TH_AddEdgeToHash(edge);
    655 	return thworld.numedges-1;
    656 } //end of the function TH_CreateEdge
    657 //===========================================================================
    658 //
    659 // Parameter:			-
    660 // Returns:				-
    661 // Changes Globals:		-
    662 //===========================================================================
    663 int TH_FindOrCreateEdge(int v1, int v2)
    664 {
    665 	int edgenum;
    666 
    667 	edgenum = TH_FindEdge(v1, v2);
    668 	if (!edgenum) edgenum = TH_CreateEdge(v1, v2);
    669 	return edgenum;
    670 } //end of the function TH_FindOrCreateEdge
    671 //===========================================================================
    672 //
    673 // Parameter:			-
    674 // Returns:				-
    675 // Changes Globals:		-
    676 //===========================================================================
    677 int TH_FindTriangle(int verts[3])
    678 {
    679 	int i, hashvalue, edges[3];
    680 	th_triangle_t *tri;
    681 
    682 	for (i = 0; i < 3; i++)
    683 	{
    684 		edges[i] = TH_FindEdge(verts[i], verts[(i+1)%3]);
    685 		if (!edges[i]) return false;
    686 	} //end for
    687 	hashvalue = (abs(edges[0]) + abs(edges[1]) + abs(edges[2])) & (TRIANGLEHASH_SIZE-1);
    688 	for (tri = thworld.trianglehash[hashvalue]; tri; tri = tri->next)
    689 	{
    690 		for (i = 0; i < 3; i++)
    691 		{
    692 			if (abs(tri->edges[i]) != abs(edges[0]) &&
    693 				abs(tri->edges[i]) != abs(edges[1]) &&
    694 				abs(tri->edges[i]) != abs(edges[2])) break;
    695 		} //end for
    696 		if (i >= 3) return tri - thworld.triangles;
    697 	} //end for
    698 	return 0;
    699 } //end of the function TH_FindTriangle
    700 //===========================================================================
    701 //
    702 // Parameter:			-
    703 // Returns:				-
    704 // Changes Globals:		-
    705 //===========================================================================
    706 void TH_AddTriangleToHash(th_triangle_t *tri)
    707 {
    708 	int hashvalue;
    709 
    710 	hashvalue = (abs(tri->edges[0]) + abs(tri->edges[1]) + abs(tri->edges[2])) & (TRIANGLEHASH_SIZE-1);
    711 	tri->hashnext = thworld.trianglehash[hashvalue];
    712 	thworld.trianglehash[hashvalue] = tri;
    713 } //end of the function TH_AddTriangleToHash
    714 //===========================================================================
    715 //
    716 // Parameter:			-
    717 // Returns:				-
    718 // Changes Globals:		-
    719 //===========================================================================
    720 void TH_CreateTrianglePlanes(int verts[3], th_plane_t *triplane, th_plane_t *planes)
    721 {
    722 	int i;
    723 	vec3_t dir;
    724 
    725 	for (i = 0; i < 3; i++)
    726 	{
    727 		VectorSubtract(thworld.vertexes[verts[(i+1)%3]].v, thworld.vertexes[verts[i]].v, dir);
    728 		CrossProduct(dir, triplane->normal, planes[i].normal);
    729 		VectorNormalize(planes[i].normal);
    730 		planes[i].dist = DotProduct(thworld.vertexes[verts[i]].v, planes[i].normal);
    731 	} //end for
    732 } //end of the function TH_CreateTrianglePlanes
    733 //===========================================================================
    734 //
    735 // Parameter:			-
    736 // Returns:				-
    737 // Changes Globals:		-
    738 //===========================================================================
    739 int TH_CreateTriangle(int verts[3])
    740 {
    741 	th_triangle_t *tri;
    742 	int i;
    743 
    744 	if (thworld.numtriangles == 0) thworld.numtriangles = 1;
    745 	if (thworld.numtriangles >= MAX_TH_TRIANGLES)
    746 		Error("MAX_TH_TRIANGLES");
    747 	tri = &thworld.triangles[thworld.numtriangles++];
    748 	for (i = 0; i < 3; i++)
    749 	{
    750 		tri->edges[i] = TH_FindOrCreateEdge(verts[i], verts[(i+1)%3]);
    751 		TH_AddEdgeUser(abs(tri->edges[i]));
    752 	} //end for
    753 	tri->front = 0;
    754 	tri->back = 0;
    755 	tri->planenum = TH_PlaneFromPoints(verts[0], verts[1], verts[2]);
    756 	tri->prev = NULL;
    757 	tri->next = NULL;
    758 	tri->hashnext = NULL;
    759 	TH_CreateTrianglePlanes(verts, &thworld.planes[tri->planenum], tri->planes);
    760 	TH_AddTriangleToHash(tri);
    761 	ClearBounds(tri->mins, tri->maxs);
    762 	for (i = 0; i < 3; i++)
    763 	{
    764 		AddPointToBounds(thworld.vertexes[verts[i]].v, tri->mins, tri->maxs);
    765 	} //end for
    766 	return thworld.numtriangles-1;
    767 } //end of the function TH_CreateTriangle
    768 //===========================================================================
    769 //
    770 // Parameter:			-
    771 // Returns:				-
    772 // Changes Globals:		-
    773 //===========================================================================
    774 int TH_CreateTetrahedron(int triangles[4])
    775 {
    776 	th_tetrahedron_t *tetrahedron;
    777 	int i;
    778 
    779 	if (thworld.numtetrahedrons == 0) thworld.numtetrahedrons = 1;
    780 	if (thworld.numtetrahedrons >= MAX_TH_TETRAHEDRONS)
    781 		Error("MAX_TH_TETRAHEDRONS");
    782 	tetrahedron = &thworld.tetrahedrons[thworld.numtetrahedrons++];
    783 	for (i = 0; i < 4; i++)
    784 	{
    785 		tetrahedron->triangles[i] = triangles[i];
    786 		if (thworld.triangles[abs(triangles[i])].front)
    787 		{
    788 			thworld.triangles[abs(triangles[i])].back = thworld.numtetrahedrons-1;
    789 		} //end if
    790 		else
    791 		{
    792 			thworld.triangles[abs(triangles[i])].front = thworld.numtetrahedrons-1;
    793 		} //end else
    794 	} //end for
    795 	tetrahedron->volume = 0;
    796 	return thworld.numtetrahedrons-1;
    797 } //end of the function TH_CreateTetrahedron
    798 //===========================================================================
    799 //
    800 // Parameter:			-
    801 // Returns:				-
    802 // Changes Globals:		-
    803 //===========================================================================
    804 int TH_IntersectTrianglePlanes(int v1, int v2, th_plane_t *triplane, th_plane_t *planes)
    805 {
    806 	float *p1, *p2, front, back, frac, d;
    807 	int i, side, lastside;
    808 	vec3_t mid;
    809 
    810 	p1 = thworld.vertexes[v1].v;
    811 	p2 = thworld.vertexes[v2].v;
    812 
    813 	front = DotProduct(p1, triplane->normal) - triplane->dist;
    814 	back = DotProduct(p2, triplane->normal) - triplane->dist;
    815 	//if both points at the same side of the plane
    816 	if (front < 0.1 && back < 0.1) return false;
    817 	if (front > -0.1 && back > -0.1) return false;
    818 	//
    819 	frac = front/(front-back);
    820 	mid[0] = p1[0] + (p2[0] - p1[0]) * frac;
    821 	mid[1] = p1[1] + (p2[1] - p1[1]) * frac;
    822 	mid[2] = p1[2] + (p2[2] - p1[2]) * frac;
    823 	//if the mid point is at the same side of all the tri bounding planes
    824 	lastside = 0;
    825 	for (i = 0; i < 3; i++)
    826 	{
    827 		d = DotProduct(mid, planes[i].normal) - planes[i].dist;
    828 		side = d < 0;
    829 		if (i && side != lastside) return false;
    830 		lastside = side;
    831 	} //end for
    832 	return true;
    833 } //end of the function TH_IntersectTrianglePlanes
    834 //===========================================================================
    835 //
    836 // Parameter:			-
    837 // Returns:				-
    838 // Changes Globals:		-
    839 //===========================================================================
    840 int TH_OutsideBoundingBox(int v1, int v2, vec3_t mins, vec3_t maxs)
    841 {
    842 	float *p1, *p2;
    843 	int i;
    844 
    845 	p1 = thworld.vertexes[v1].v;
    846 	p2 = thworld.vertexes[v2].v;
    847 	//if both points are at the outer side of one of the bounding box planes
    848 	for (i = 0; i < 3; i++)
    849 	{
    850 		if (p1[i] < mins[i] && p2[i] < mins[i]) return true;
    851 		if (p1[i] > maxs[i] && p2[i] > maxs[i]) return true;
    852 	} //end for
    853 	return false;
    854 } //end of the function TH_OutsideBoundingBox
    855 //===========================================================================
    856 //
    857 // Parameter:			-
    858 // Returns:				-
    859 // Changes Globals:		-
    860 //===========================================================================
    861 int TH_TryEdge(int v1, int v2)
    862 {
    863 	int i, j, v;
    864 	th_plane_t *plane;
    865 	th_triangle_t *tri;
    866 
    867 	//if the edge already exists it must be valid
    868 	if (TH_FindEdge(v1, v2)) return true;
    869 	//test the edge with all existing triangles
    870 	for (i = 1; i < thworld.numtriangles; i++)
    871 	{
    872 		tri = &thworld.triangles[i];
    873 		//if triangle is enclosed by two tetrahedrons we don't have to test it
    874 		//because the edge always has to go through another triangle of those
    875 		//tetrahedrons first to reach the enclosed triangle
    876 		if (tri->front && tri->back) continue;
    877 		//if the edges is totally outside the triangle bounding box
    878 		if (TH_OutsideBoundingBox(v1, v2, tri->mins, tri->maxs)) continue;
    879 		//if one of the edge vertexes is used by this triangle
    880 		for (j = 0; j < 3; j++)
    881 		{
    882 			v = thworld.edges[abs(tri->edges[j])].v[tri->edges[j] < 0];
    883 			if (v == v1 || v == v2) break;
    884 		} //end for
    885 		if (j < 3) continue;
    886 		//get the triangle plane
    887 		plane = &thworld.planes[tri->planenum];
    888 		//if the edge intersects with a triangle then it's not valid
    889 		if (TH_IntersectTrianglePlanes(v1, v2, plane, tri->planes)) return false;
    890 	} //end for
    891 	return true;
    892 } //end of the function TH_TryEdge
    893 //===========================================================================
    894 //
    895 // Parameter:			-
    896 // Returns:				-
    897 // Changes Globals:		-
    898 //===========================================================================
    899 int TH_TryTriangle(int verts[3])
    900 {
    901 	th_plane_t planes[3], triplane;
    902 	vec3_t t1, t2;
    903 	float *p0, *p1, *p2;
    904 	int i, j;
    905 
    906 	p0 = thworld.vertexes[verts[0]].v;
    907 	p1 = thworld.vertexes[verts[1]].v;
    908 	p2 = thworld.vertexes[verts[2]].v;
    909 
    910 	VectorSubtract(p0, p1, t1);
    911 	VectorSubtract(p2, p1, t2);
    912 	CrossProduct(t1, t2, triplane.normal);
    913 	VectorNormalize(triplane.normal);
    914 	triplane.dist = DotProduct(p0, triplane.normal);
    915 	//
    916 	TH_CreateTrianglePlanes(verts, &triplane, planes);
    917 	//test if any existing edge intersects with this triangle
    918 	for (i = 1; i < thworld.numedges; i++)
    919 	{
    920 		//if the edge is only used by triangles with tetrahedrons at both sides
    921 		if (!thworld.edges[i].usercount) continue;
    922 		//if one of the triangle vertexes is used by this edge
    923 		for (j = 0; j < 3; j++)
    924 		{
    925 			if (verts[j] == thworld.edges[j].v[0] ||
    926 				verts[j] == thworld.edges[j].v[1]) break;
    927 		} //end for
    928 		if (j < 3) continue;
    929 		//if this edge intersects with the triangle
    930 		if (TH_IntersectTrianglePlanes(thworld.edges[i].v[0], thworld.edges[i].v[1], &triplane, planes)) return false;
    931 	} //end for
    932 	return true;
    933 } //end of the function TH_TryTriangle
    934 //===========================================================================
    935 //
    936 // Parameter:			-
    937 // Returns:				-
    938 // Changes Globals:		-
    939 //===========================================================================
    940 void TH_AddTriangleToList(th_triangle_t **trianglelist, th_triangle_t *tri)
    941 {
    942 	tri->prev = NULL;
    943 	tri->next = *trianglelist;
    944 	if (*trianglelist) (*trianglelist)->prev = tri;
    945 	*trianglelist = tri;
    946 } //end of the function TH_AddTriangleToList
    947 //===========================================================================
    948 //
    949 // Parameter:			-
    950 // Returns:				-
    951 // Changes Globals:		-
    952 //===========================================================================
    953 void TH_RemoveTriangleFromList(th_triangle_t **trianglelist, th_triangle_t *tri)
    954 {
    955 	if (tri->next) tri->next->prev = tri->prev;
    956 	if (tri->prev) tri->prev->next = tri->next;
    957 	else *trianglelist = tri->next;
    958 } //end of the function TH_RemoveTriangleFromList
    959 //===========================================================================
    960 //
    961 // Parameter:			-
    962 // Returns:				-
    963 // Changes Globals:		-
    964 //===========================================================================
    965 int TH_FindTetrahedron1(th_triangle_t *tri, int *triangles)
    966 {
    967 	int i, j, edgenum, side, v1, v2, v3, v4;
    968 	int verts1[3], verts2[3];
    969 	th_triangle_t *tri2;
    970 
    971 	//find another triangle with a shared edge
    972 	for (tri2 = tri->next; tri2; tri2 = tri2->next)
    973 	{
    974 		//if the triangles are in the same plane
    975 		if ((tri->planenum & ~1) == (tri2->planenum & ~1)) continue;
    976 		//try to find a shared edge
    977 		for (i = 0; i < 3; i++)
    978 		{
    979 			edgenum = abs(tri->edges[i]);
    980 			for (j = 0; j < 3; j++)
    981 			{
    982 				if (edgenum == abs(tri2->edges[j])) break;
    983 			} //end for
    984 			if (j < 3) break;
    985 		} //end for
    986 		//if the triangles have a shared edge
    987 		if (i < 3)
    988 		{
    989 			edgenum = tri->edges[(i+1)%3];
    990 			if (edgenum < 0) v1 = thworld.edges[abs(edgenum)].v[0];
    991 			else v1 = thworld.edges[edgenum].v[1];
    992 			edgenum = tri2->edges[(j+1)%3];
    993 			if (edgenum < 0) v2 = thworld.edges[abs(edgenum)].v[0];
    994 			else v2 = thworld.edges[edgenum].v[1];
    995 			//try the new edge
    996 			if (TH_TryEdge(v1, v2))
    997 			{
    998 				edgenum = tri->edges[i];
    999 				side = edgenum < 0;
   1000 				//get the vertexes of the shared edge
   1001 				v3 = thworld.edges[abs(edgenum)].v[side];
   1002 				v4 = thworld.edges[abs(edgenum)].v[!side];
   1003 				//try the two new triangles
   1004 				verts1[0] = v1;
   1005 				verts1[1] = v2;
   1006 				verts1[2] = v3;
   1007 				triangles[2] = TH_FindTriangle(verts1);
   1008 				if (triangles[2] || TH_TryTriangle(verts1))
   1009 				{
   1010 					verts2[0] = v2;
   1011 					verts2[1] = v1;
   1012 					verts2[2] = v4;
   1013 					triangles[3] = TH_FindTriangle(verts2);
   1014 					if (triangles[3] || TH_TryTriangle(verts2))
   1015 					{
   1016 						triangles[0] = tri - thworld.triangles;
   1017 						triangles[1] = tri2 - thworld.triangles;
   1018 						if (!triangles[2]) triangles[2] = TH_CreateTriangle(verts1);
   1019 						if (!triangles[3]) triangles[3] = TH_CreateTriangle(verts2);
   1020 						return true;
   1021 					} //end if
   1022 				} //end if
   1023 			} //end if
   1024 		} //end if
   1025 	} //end for
   1026 	return false;
   1027 } //end of the function TH_FindTetrahedron
   1028 //===========================================================================
   1029 //
   1030 // Parameter:			-
   1031 // Returns:				-
   1032 // Changes Globals:		-
   1033 //===========================================================================
   1034 int TH_FindTetrahedron2(th_triangle_t *tri, int *triangles)
   1035 {
   1036 	int i, edgenum, v1, verts[3], triverts[3];
   1037 	float d;
   1038 	th_plane_t *plane;
   1039 
   1040 	//get the verts of this triangle
   1041 	for (i = 0; i < 3; i++)
   1042 	{
   1043 		edgenum = tri->edges[i];
   1044 		if (edgenum < 0) verts[i] = thworld.edges[abs(edgenum)].v[1];
   1045 		else verts[i] = thworld.edges[edgenum].v[0];
   1046 	} //end for
   1047 	//
   1048 	plane = &thworld.planes[tri->planenum];
   1049 	for (v1 = 0; v1 < thworld.numvertexes; v1++)
   1050 	{
   1051 		//if the vertex is only used by triangles with tetrahedrons at both sides
   1052 		if (!thworld.vertexes[v1].usercount) continue;
   1053 		//check if the vertex is not coplanar with the triangle
   1054 		d = DotProduct(thworld.vertexes[v1].v, plane->normal) - plane->dist;
   1055 		if (fabs(d) < 1) continue;
   1056 		//check if we can create edges from the triangle towards this new vertex
   1057 		for (i = 0; i < 3; i++)
   1058 		{
   1059 			if (v1 == verts[i]) break;
   1060 			if (!TH_TryEdge(v1, verts[i])) break;
   1061 		} //end for
   1062 		if (i < 3) continue;
   1063 		//check if the triangles are valid
   1064 		for (i = 0; i < 3; i++)
   1065 		{
   1066 			triverts[0] = v1;
   1067 			triverts[1] = verts[i];
   1068 			triverts[2] = verts[(i+1)%3];
   1069 			//if the triangle already exists then it is valid
   1070 			triangles[i] = TH_FindTriangle(triverts);
   1071 			if (!triangles[i])
   1072 			{
   1073 				if (!TH_TryTriangle(triverts)) break;
   1074 			} //end if
   1075 		} //end for
   1076 		if (i < 3) continue;
   1077 		//create the tetrahedron triangles using the new vertex
   1078 		for (i = 0; i < 3; i++)
   1079 		{
   1080 			if (!triangles[i])
   1081 			{
   1082 				triverts[0] = v1;
   1083 				triverts[1] = verts[i];
   1084 				triverts[2] = verts[(i+1)%3];
   1085 				triangles[i] = TH_CreateTriangle(triverts);
   1086 			} //end if
   1087 		} //end for
   1088 		//add the existing triangle
   1089 		triangles[3] = tri - thworld.triangles;
   1090 		//
   1091 		return true;
   1092 	} //end for
   1093 	return false;
   1094 } //end of the function TH_FindTetrahedron2
   1095 //===========================================================================
   1096 //
   1097 // Parameter:			-
   1098 // Returns:				-
   1099 // Changes Globals:		-
   1100 //===========================================================================
   1101 void TH_TetrahedralDecomposition(th_triangle_t *triangles)
   1102 {
   1103 	int i, thtriangles[4], numtriangles;
   1104 	th_triangle_t *donetriangles, *tri;
   1105 
   1106 	donetriangles = NULL;
   1107 
   1108 	/*
   1109 	numtriangles = 0;
   1110 	qprintf("%6d triangles", numtriangles);
   1111 	for (tri = triangles; tri; tri = triangles)
   1112 	{
   1113 		qprintf("\r%6d", numtriangles++);
   1114 		if (!TH_FindTetrahedron1(tri, thtriangles))
   1115 		{
   1116 //			if (!TH_FindTetrahedron2(tri, thtriangles))
   1117 			{
   1118 //				Error("triangle without tetrahedron");
   1119 				TH_RemoveTriangleFromList(&triangles, tri);
   1120 				continue;
   1121 			} //end if
   1122 		} //end if
   1123 		//create a tetrahedron from the triangles
   1124 		TH_CreateTetrahedron(thtriangles);
   1125 		//
   1126 		for (i = 0; i < 4; i++)
   1127 		{
   1128 			if (thworld.triangles[abs(thtriangles[i])].front &&
   1129 				thworld.triangles[abs(thtriangles[i])].back)
   1130 			{
   1131 				TH_RemoveTriangleFromList(&triangles, &thworld.triangles[abs(thtriangles[i])]);
   1132 				TH_AddTriangleToList(&donetriangles, &thworld.triangles[abs(thtriangles[i])]);
   1133 				TH_FreeTriangleEdges(&thworld.triangles[abs(thtriangles[i])]);
   1134 			} //end if
   1135 			else
   1136 			{
   1137 				TH_AddTriangleToList(&triangles, &thworld.triangles[abs(thtriangles[i])]);
   1138 			} //end else
   1139 		} //end for
   1140 	} //end for*/
   1141 	qprintf("%6d tetrahedrons", thworld.numtetrahedrons);
   1142 	do
   1143 	{
   1144 		do
   1145 		{
   1146 			numtriangles = 0;
   1147 			for (i = 1; i < thworld.numtriangles; i++)
   1148 			{
   1149 				tri = &thworld.triangles[i];
   1150 				if (tri->front && tri->back) continue;
   1151 				//qprintf("\r%6d", numtriangles++);
   1152 				if (!TH_FindTetrahedron1(tri, thtriangles))
   1153 				{
   1154 //					if (!TH_FindTetrahedron2(tri, thtriangles))
   1155 					{
   1156 						continue;
   1157 					} //end if
   1158 				} //end if
   1159 				numtriangles++;
   1160 				//create a tetrahedron from the triangles
   1161 				TH_CreateTetrahedron(thtriangles);
   1162 				qprintf("\r%6d", thworld.numtetrahedrons);
   1163 			} //end for
   1164 		} while(numtriangles);
   1165  		for (i = 1; i < thworld.numtriangles; i++)
   1166 		{
   1167 			tri = &thworld.triangles[i];
   1168 			if (tri->front && tri->back) continue;
   1169 			//qprintf("\r%6d", numtriangles++);
   1170 //			if (!TH_FindTetrahedron1(tri, thtriangles))
   1171 			{
   1172 				if (!TH_FindTetrahedron2(tri, thtriangles))
   1173 				{
   1174 					continue;
   1175 				} //end if
   1176 			} //end if
   1177 			numtriangles++;
   1178 			//create a tetrahedron from the triangles
   1179 			TH_CreateTetrahedron(thtriangles);
   1180 			qprintf("\r%6d", thworld.numtetrahedrons);
   1181 		} //end for
   1182 	} while(numtriangles);
   1183 	//
   1184 	numtriangles = 0;
   1185 	for (i = 1; i < thworld.numtriangles; i++)
   1186 	{
   1187 		tri = &thworld.triangles[i];
   1188 		if (!tri->front && !tri->back) numtriangles++;
   1189 	} //end for
   1190 	Log_Print("\r%6d triangles with front only\n", numtriangles);
   1191 	Log_Print("\r%6d tetrahedrons\n", thworld.numtetrahedrons-1);
   1192 } //end of the function TH_TetrahedralDecomposition
   1193 //===========================================================================
   1194 //
   1195 // Parameter:			-
   1196 // Returns:				-
   1197 // Changes Globals:		-
   1198 //===========================================================================
   1199 void TH_AASFaceVertex(aas_face_t *face, int index, vec3_t vertex)
   1200 {
   1201 	int edgenum, side;
   1202 
   1203 	edgenum = aasworld.edgeindex[face->firstedge + index];
   1204 	side = edgenum < 0;
   1205 	VectorCopy(aasworld.vertexes[aasworld.edges[abs(edgenum)].v[side]], vertex);
   1206 } //end of the function TH_AASFaceVertex
   1207 //===========================================================================
   1208 //
   1209 // Parameter:			-
   1210 // Returns:				-
   1211 // Changes Globals:		-
   1212 //===========================================================================
   1213 int TH_Colinear(float *v0, float *v1, float *v2)
   1214 {
   1215 	vec3_t t1, t2, vcross;
   1216 	float d;
   1217 	
   1218 	VectorSubtract(v1, v0, t1);
   1219 	VectorSubtract(v2, v0, t2);
   1220 	CrossProduct (t1, t2, vcross);
   1221 	d = VectorLength( vcross );
   1222 
   1223 	// if cross product is zero point is colinear
   1224 	if (d < 10)
   1225 	{
   1226 		return true;
   1227 	} //end if
   1228 	return false;
   1229 } //end of the function TH_Colinear
   1230 //===========================================================================
   1231 //
   1232 // Parameter:			-
   1233 // Returns:				-
   1234 // Changes Globals:		-
   1235 //===========================================================================
   1236 void TH_FaceCenter(aas_face_t *face, vec3_t center)
   1237 {
   1238 	int i, edgenum, side;
   1239 	aas_edge_t *edge;
   1240 
   1241 	VectorClear(center);
   1242 	for (i = 0; i < face->numedges; i++)
   1243 	{
   1244 		edgenum = abs(aasworld.edgeindex[face->firstedge + i]);
   1245 		side = edgenum < 0;
   1246 		edge = &aasworld.edges[abs(edgenum)];
   1247 		VectorAdd(aasworld.vertexes[edge->v[side]], center, center);
   1248 	} //end for
   1249 	VectorScale(center, 1.0 / face->numedges, center);
   1250 } //end of the function TH_FaceCenter
   1251 //===========================================================================
   1252 //
   1253 // Parameter:			-
   1254 // Returns:				-
   1255 // Changes Globals:		-
   1256 //===========================================================================
   1257 th_triangle_t *TH_CreateAASFaceTriangles(aas_face_t *face)
   1258 {
   1259 	int i, first, verts[3], trinum;
   1260 	vec3_t p0, p1, p2, p3, p4, center;
   1261 	th_triangle_t *tri, *triangles;
   1262 
   1263 	triangles = NULL;
   1264 	//find three points that are not colinear
   1265 	for (i = 0; i < face->numedges; i++)
   1266 	{
   1267 		TH_AASFaceVertex(face, (face->numedges + i-2)%face->numedges, p0);
   1268 		TH_AASFaceVertex(face, (face->numedges + i-1)%face->numedges, p1);
   1269 		TH_AASFaceVertex(face, (i  )%face->numedges, p2);
   1270 		if (TH_Colinear(p2, p0, p1)) continue;
   1271 		TH_AASFaceVertex(face, (i+1)%face->numedges, p3);
   1272 		TH_AASFaceVertex(face, (i+2)%face->numedges, p4);
   1273 		if (TH_Colinear(p2, p3, p4)) continue;
   1274 		break;
   1275 	} //end for
   1276 	//if there are three points that are not colinear
   1277 	if (i < face->numedges)
   1278 	{
   1279 		//normal triangulation
   1280 		first = i; //left and right most point of three non-colinear points
   1281 		TH_AASFaceVertex(face, first, p0);
   1282 		verts[0] = TH_FindOrCreateVertex(p0);
   1283 		for (i = 1; i < face->numedges-1; i++)
   1284 		{
   1285 			TH_AASFaceVertex(face, (first+i  )%face->numedges, p1);
   1286 			TH_AASFaceVertex(face, (first+i+1)%face->numedges, p2);
   1287 			verts[1] = TH_FindOrCreateVertex(p1);
   1288 			verts[2] = TH_FindOrCreateVertex(p2);
   1289 			trinum = TH_CreateTriangle(verts);
   1290 			tri = &thworld.triangles[trinum];
   1291 			tri->front = -1;
   1292 			TH_AddTriangleToList(&triangles, tri);
   1293 		} //end for
   1294 	} //end if
   1295 	else
   1296 	{
   1297 		//fan triangulation
   1298 		TH_FaceCenter(face, center);
   1299 		//
   1300 		verts[0] = TH_FindOrCreateVertex(center);
   1301 		for (i = 0; i < face->numedges; i++)
   1302 		{
   1303 			TH_AASFaceVertex(face, (i  )%face->numedges, p1);
   1304 			TH_AASFaceVertex(face, (i+1)%face->numedges, p2);
   1305 			if (TH_Colinear(center, p1, p2)) continue;
   1306 			verts[1] = TH_FindOrCreateVertex(p1);
   1307 			verts[2] = TH_FindOrCreateVertex(p2);
   1308 			trinum = TH_CreateTriangle(verts);
   1309 			tri = &thworld.triangles[trinum];
   1310 			tri->front = -1;
   1311 			TH_AddTriangleToList(&triangles, tri);
   1312 		} //end for
   1313 	} //end else
   1314 	return triangles;
   1315 } //end of the function TH_CreateAASFaceTriangles
   1316 //===========================================================================
   1317 //
   1318 // Parameter:			-
   1319 // Returns:				-
   1320 // Changes Globals:		-
   1321 //===========================================================================
   1322 th_triangle_t *TH_AASToTriangleMesh(void)
   1323 {
   1324 	int i, j, facenum, otherareanum;
   1325 	aas_face_t *face;
   1326 	th_triangle_t *tri, *nexttri, *triangles;
   1327 
   1328 	triangles = NULL;
   1329 	for (i = 1; i < aasworld.numareas; i++)
   1330 	{
   1331 		//if (!(aasworld.areasettings[i].presencetype & PRESENCE_NORMAL)) continue;
   1332 		for (j = 0; j < aasworld.areas[i].numfaces; j++)
   1333 		{
   1334 			facenum = abs(aasworld.faceindex[aasworld.areas[i].firstface + j]);
   1335 			face = &aasworld.faces[facenum];
   1336 			//only convert solid faces into triangles
   1337 			if (!(face->faceflags & FACE_SOLID))
   1338 			{
   1339 				/*
   1340 				if (face->frontarea == i) otherareanum = face->backarea;
   1341 				else otherareanum = face->frontarea;
   1342 				if (aasworld.areasettings[otherareanum].presencetype & PRESENCE_NORMAL) continue;
   1343 				*/
   1344 				continue;
   1345 			} //end if
   1346 			//
   1347 			tri = TH_CreateAASFaceTriangles(face);
   1348 			for (; tri; tri = nexttri)
   1349 			{
   1350 				nexttri = tri->next;
   1351 				TH_AddTriangleToList(&triangles, tri);
   1352 			} //end for
   1353 		} //end if
   1354 	} //end for
   1355 	return triangles;
   1356 } //end of the function TH_AASToTriangleMesh
   1357 //===========================================================================
   1358 //
   1359 // Parameter:			-
   1360 // Returns:				-
   1361 // Changes Globals:		-
   1362 //===========================================================================
   1363 void TH_AASToTetrahedrons(char *filename)
   1364 {
   1365 	th_triangle_t *triangles, *tri, *lasttri;
   1366 	int cnt;
   1367 
   1368 	if (!AAS_LoadAASFile(filename, 0, 0))
   1369 		Error("couldn't load %s\n", filename);
   1370 
   1371 	//
   1372 	TH_InitMaxTH();
   1373 	//create a triangle mesh from the solid faces in the AAS file
   1374 	triangles = TH_AASToTriangleMesh();
   1375 	//
   1376 	cnt = 0;
   1377 	lasttri = NULL;
   1378 	for (tri = triangles; tri; tri = tri->next)
   1379 	{
   1380 		cnt++;
   1381 		if (tri->prev != lasttri) Log_Print("BAH\n");
   1382 		lasttri = tri;
   1383 	} //end for
   1384 	Log_Print("%6d triangles\n", cnt);
   1385 	//create a tetrahedral decomposition of the world bounded by triangles
   1386 	TH_TetrahedralDecomposition(triangles);
   1387 	//
   1388 	TH_FreeMaxTH();
   1389 } //end of the function TH_AASToTetrahedrons