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

tetrahedron.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 
00023 #include "qbsp.h"
00024 #include "l_mem.h"
00025 #include "../botlib/aasfile.h"
00026 #include "aas_store.h"
00027 #include "aas_cfg.h"
00028 #include "aas_file.h"
00029 
00030 //
00031 // creating tetrahedrons from a arbitrary world bounded by triangles
00032 //
00033 // a triangle has 3 corners and 3 edges
00034 // a tetrahedron is build out of 4 triangles
00035 // a tetrahedron has 6 edges
00036 // we start with a world bounded by triangles, a side of a triangle facing
00037 // towards the oudside of the world is marked as part of tetrahedron -1
00038 //
00039 // a tetrahedron is defined by two non-coplanar triangles with a shared edge
00040 //
00041 // a tetrahedron is defined by one triangle and a vertex not in the triangle plane
00042 //
00043 // if all triangles using a specific vertex have tetrahedrons
00044 // at both sides then this vertex will never be part of a new tetrahedron
00045 //
00046 // if all triangles using a specific edge have tetrahedrons
00047 // at both sides then this vertex will never be part of a new tetrahedron
00048 //
00049 // each triangle can only be shared by two tetrahedrons
00050 // when all triangles have tetrahedrons at both sides then we're done
00051 //
00052 // if we cannot create any new tetrahedrons and there is at least one triangle
00053 // which has a tetrahedron only at one side then the world leaks
00054 //
00055 
00056 #define Sign(x)     (x < 0 ? 1 : 0)
00057 
00058 #define MAX_TH_VERTEXES         128000
00059 #define MAX_TH_PLANES           128000
00060 #define MAX_TH_EDGES            512000
00061 #define MAX_TH_TRIANGLES        51200
00062 #define MAX_TH_TETRAHEDRONS     12800
00063 
00064 #define PLANEHASH_SIZE          1024
00065 #define EDGEHASH_SIZE           1024
00066 #define TRIANGLEHASH_SIZE       1024
00067 #define VERTEXHASH_SHIFT        7
00068 #define VERTEXHASH_SIZE         ((MAX_MAP_BOUNDS>>(VERTEXHASH_SHIFT-1))+1)  //was 64
00069 
00070 #define NORMAL_EPSILON          0.0001
00071 #define DIST_EPSILON            0.1
00072 #define VERTEX_EPSILON          0.01
00073 #define INTEGRAL_EPSILON        0.01
00074 
00075 
00076 //plane
00077 typedef struct th_plane_s
00078 {
00079     vec3_t normal;
00080     float dist;
00081     int type;
00082     int signbits;
00083     struct th_plane_s *hashnext;        //next plane in hash
00084 } th_plane_t;
00085 
00086 //vertex
00087 typedef struct th_vertex_s
00088 {
00089     vec3_t v;
00090     int usercount;                      //2x the number of to be processed
00091                                         //triangles using this vertex
00092     struct th_vertex_s *hashnext;       //next vertex in hash
00093 } th_vertex_t;
00094 
00095 //edge
00096 typedef struct th_edge_s
00097 {
00098     int v[2];                           //vertex indexes
00099     int usercount;                      //number of to be processed
00100                                         //triangles using this edge
00101     struct th_edge_s *hashnext;         //next edge in hash
00102 } th_edge_t;
00103 
00104 //triangle
00105 typedef struct th_triangle_s
00106 {
00107     int edges[3];                       //negative if edge is flipped
00108     th_plane_t planes[3];               //triangle bounding planes
00109     int planenum;                       //plane the triangle is in
00110     int front;                          //tetrahedron at the front
00111     int back;                           //tetrahedron at the back
00112     vec3_t mins, maxs;                  //triangle bounding box
00113     struct th_triangle_s *prev, *next;  //links in linked triangle lists
00114     struct th_triangle_s *hashnext;     //next triangle in hash
00115 } th_triangle_t;
00116 
00117 //tetrahedron
00118 typedef struct th_tetrahedron_s
00119 {
00120     int triangles[4];                   //negative if at backside of triangle
00121     float volume;                       //tetrahedron volume
00122 } th_tetrahedron_t;
00123 
00124 typedef struct th_s
00125 {
00126     //vertexes
00127     int numvertexes;
00128     th_vertex_t *vertexes;
00129     th_vertex_t *vertexhash[VERTEXHASH_SIZE * VERTEXHASH_SIZE];
00130     //planes
00131     int numplanes;
00132     th_plane_t *planes;
00133     th_plane_t *planehash[PLANEHASH_SIZE];
00134     //edges
00135     int numedges;
00136     th_edge_t *edges;
00137     th_edge_t *edgehash[EDGEHASH_SIZE];
00138     //triangles
00139     int numtriangles;
00140     th_triangle_t *triangles;
00141     th_triangle_t *trianglehash[TRIANGLEHASH_SIZE];
00142     //tetrahedrons
00143     int numtetrahedrons;
00144     th_tetrahedron_t *tetrahedrons;
00145 } th_t;
00146 
00147 th_t thworld;
00148 
00149 //===========================================================================
00150 //
00151 // Parameter:           -
00152 // Returns:             -
00153 // Changes Globals:     -
00154 //===========================================================================
00155 void TH_InitMaxTH(void)
00156 {
00157     //get memory for the tetrahedron data
00158     thworld.vertexes = (th_vertex_t *) GetClearedMemory(MAX_TH_VERTEXES * sizeof(th_vertex_t));
00159     thworld.planes = (th_plane_t *) GetClearedMemory(MAX_TH_PLANES * sizeof(th_plane_t));
00160     thworld.edges = (th_edge_t *) GetClearedMemory(MAX_TH_EDGES * sizeof(th_edge_t));
00161     thworld.triangles = (th_triangle_t *) GetClearedMemory(MAX_TH_TRIANGLES * sizeof(th_triangle_t));
00162     thworld.tetrahedrons = (th_tetrahedron_t *) GetClearedMemory(MAX_TH_TETRAHEDRONS * sizeof(th_tetrahedron_t));
00163     //reset the hash tables
00164     memset(thworld.vertexhash, 0, VERTEXHASH_SIZE * sizeof(th_vertex_t *));
00165     memset(thworld.planehash, 0, PLANEHASH_SIZE * sizeof(th_plane_t *));
00166     memset(thworld.edgehash, 0, EDGEHASH_SIZE * sizeof(th_edge_t *));
00167     memset(thworld.trianglehash, 0, TRIANGLEHASH_SIZE * sizeof(th_triangle_t *));
00168 } //end of the function TH_InitMaxTH
00169 //===========================================================================
00170 //
00171 // Parameter:           -
00172 // Returns:             -
00173 // Changes Globals:     -
00174 //===========================================================================
00175 void TH_FreeMaxTH(void)
00176 {
00177     if (thworld.vertexes) FreeMemory(thworld.vertexes);
00178     thworld.vertexes = NULL;
00179     thworld.numvertexes = 0;
00180     if (thworld.planes) FreeMemory(thworld.planes);
00181     thworld.planes = NULL;
00182     thworld.numplanes = 0;
00183     if (thworld.edges) FreeMemory(thworld.edges);
00184     thworld.edges = NULL;
00185     thworld.numedges = 0;
00186     if (thworld.triangles) FreeMemory(thworld.triangles);
00187     thworld.triangles = NULL;
00188     thworld.numtriangles = 0;
00189     if (thworld.tetrahedrons) FreeMemory(thworld.tetrahedrons);
00190     thworld.tetrahedrons = NULL;
00191     thworld.numtetrahedrons = 0;
00192 } //end of the function TH_FreeMaxTH
00193 //===========================================================================
00194 //
00195 // Parameter:           -
00196 // Returns:             -
00197 // Changes Globals:     -
00198 //===========================================================================
00199 float TH_TriangleArea(th_triangle_t *tri)
00200 {
00201     return 0;
00202 } //end of the function TH_TriangleArea
00203 //===========================================================================
00204 //
00205 // Parameter:           -
00206 // Returns:             -
00207 // Changes Globals:     -
00208 //===========================================================================
00209 float TH_TetrahedronVolume(th_tetrahedron_t *tetrahedron)
00210 {
00211     int edgenum, verts[3], i, j, v2;
00212     float volume, d;
00213     th_triangle_t *tri, *tri2;
00214     th_plane_t *plane;
00215 
00216     tri = &thworld.triangles[abs(tetrahedron->triangles[0])];
00217     for (i = 0; i < 3; i++)
00218     {
00219         edgenum = tri->edges[i];
00220         if (edgenum < 0) verts[i] = thworld.edges[abs(edgenum)].v[1];
00221         else verts[i] = thworld.edges[edgenum].v[0];
00222     } //end for
00223     //
00224     tri2 = &thworld.triangles[abs(tetrahedron->triangles[1])];
00225     for (j = 0; j < 3; j++)
00226     {
00227         edgenum = tri2->edges[i];
00228         if (edgenum < 0) v2 = thworld.edges[abs(edgenum)].v[1];
00229         else v2 = thworld.edges[edgenum].v[0];
00230         if (v2 != verts[0] &&
00231             v2 != verts[1] &&
00232             v2 != verts[2]) break;
00233     } //end for
00234 
00235     plane = &thworld.planes[tri->planenum];
00236     d = -(DotProduct (thworld.vertexes[v2].v, plane->normal) - plane->dist);
00237     volume = TH_TriangleArea(tri) * d / 3;
00238     return volume;
00239 } //end of the function TH_TetrahedronVolume
00240 //===========================================================================
00241 //
00242 // Parameter:           -
00243 // Returns:             -
00244 // Changes Globals:     -
00245 //===========================================================================
00246 int TH_PlaneSignBits(vec3_t normal)
00247 {
00248     int i, signbits;
00249 
00250     signbits = 0;
00251     for (i = 2; i >= 0; i--)
00252     {
00253         signbits = (signbits << 1) + Sign(normal[i]);
00254     } //end for
00255     return signbits;
00256 } //end of the function TH_PlaneSignBits
00257 //===========================================================================
00258 //
00259 // Parameter:           -
00260 // Returns:             -
00261 // Changes Globals:     -
00262 //===========================================================================
00263 int TH_PlaneTypeForNormal(vec3_t normal)
00264 {
00265     vec_t   ax, ay, az;
00266     
00267 // NOTE: should these have an epsilon around 1.0?       
00268     if (normal[0] == 1.0 || normal[0] == -1.0)
00269         return PLANE_X;
00270     if (normal[1] == 1.0 || normal[1] == -1.0)
00271         return PLANE_Y;
00272     if (normal[2] == 1.0 || normal[2] == -1.0)
00273         return PLANE_Z;
00274         
00275     ax = fabs(normal[0]);
00276     ay = fabs(normal[1]);
00277     az = fabs(normal[2]);
00278     
00279     if (ax >= ay && ax >= az)
00280         return PLANE_ANYX;
00281     if (ay >= ax && ay >= az)
00282         return PLANE_ANYY;
00283     return PLANE_ANYZ;
00284 } //end of the function TH_PlaneTypeForNormal
00285 //===========================================================================
00286 //
00287 // Parameter:           -
00288 // Returns:             -
00289 // Changes Globals:     -
00290 //===========================================================================
00291 qboolean TH_PlaneEqual(th_plane_t *p, vec3_t normal, vec_t dist)
00292 {
00293     if (
00294        fabs(p->normal[0] - normal[0]) < NORMAL_EPSILON
00295     && fabs(p->normal[1] - normal[1]) < NORMAL_EPSILON
00296     && fabs(p->normal[2] - normal[2]) < NORMAL_EPSILON
00297     && fabs(p->dist - dist) < DIST_EPSILON )
00298         return true;
00299     return false;
00300 } //end of the function TH_PlaneEqual
00301 //===========================================================================
00302 //
00303 // Parameter:           -
00304 // Returns:             -
00305 // Changes Globals:     -
00306 //===========================================================================
00307 void TH_AddPlaneToHash(th_plane_t *p)
00308 {
00309     int hash;
00310 
00311     hash = (int)fabs(p->dist) / 8;
00312     hash &= (PLANEHASH_SIZE-1);
00313 
00314     p->hashnext = thworld.planehash[hash];
00315     thworld.planehash[hash] = p;
00316 } //end of the function TH_AddPlaneToHash
00317 //===========================================================================
00318 //
00319 // Parameter:           -
00320 // Returns:             -
00321 // Changes Globals:     -
00322 //===========================================================================
00323 int TH_CreateFloatPlane(vec3_t normal, vec_t dist)
00324 {
00325     th_plane_t *p, temp;
00326 
00327     if (VectorLength(normal) < 0.5)
00328         Error ("FloatPlane: bad normal");
00329     // create a new plane
00330     if (thworld.numplanes+2 > MAX_TH_PLANES)
00331         Error ("MAX_TH_PLANES");
00332 
00333     p = &thworld.planes[thworld.numplanes];
00334     VectorCopy (normal, p->normal);
00335     p->dist = dist;
00336     p->type = (p+1)->type = TH_PlaneTypeForNormal (p->normal);
00337     p->signbits = TH_PlaneSignBits(p->normal);
00338 
00339     VectorSubtract (vec3_origin, normal, (p+1)->normal);
00340     (p+1)->dist = -dist;
00341     (p+1)->signbits = TH_PlaneSignBits((p+1)->normal);
00342 
00343     thworld.numplanes += 2;
00344 
00345     // allways put axial planes facing positive first
00346     if (p->type < 3)
00347     {
00348         if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0)
00349         {
00350             // flip order
00351             temp = *p;
00352             *p = *(p+1);
00353             *(p+1) = temp;
00354 
00355             TH_AddPlaneToHash(p);
00356             TH_AddPlaneToHash(p+1);
00357             return thworld.numplanes - 1;
00358         } //end if
00359     } //end if
00360 
00361     TH_AddPlaneToHash(p);
00362     TH_AddPlaneToHash(p+1);
00363     return thworld.numplanes - 2;
00364 } //end of the function TH_CreateFloatPlane
00365 //===========================================================================
00366 //
00367 // Parameter:           -
00368 // Returns:             -
00369 // Changes Globals:     -
00370 //===========================================================================
00371 void TH_SnapVector(vec3_t normal)
00372 {
00373     int     i;
00374 
00375     for (i = 0; i < 3; i++)
00376     {
00377         if ( fabs(normal[i] - 1) < NORMAL_EPSILON )
00378         {
00379             VectorClear (normal);
00380             normal[i] = 1;
00381             break;
00382         } //end if
00383         if ( fabs(normal[i] - -1) < NORMAL_EPSILON )
00384         {
00385             VectorClear (normal);
00386             normal[i] = -1;
00387             break;
00388         } //end if
00389     } //end for
00390 } //end of the function TH_SnapVector
00391 //===========================================================================
00392 //
00393 // Parameter:           -
00394 // Returns:             -
00395 // Changes Globals:     -
00396 //===========================================================================
00397 void TH_SnapPlane(vec3_t normal, vec_t *dist)
00398 {
00399     TH_SnapVector(normal);
00400 
00401     if (fabs(*dist-Q_rint(*dist)) < DIST_EPSILON)
00402         *dist = Q_rint(*dist);
00403 } //end of the function TH_SnapPlane
00404 //===========================================================================
00405 //
00406 // Parameter:           -
00407 // Returns:             -
00408 // Changes Globals:     -
00409 //===========================================================================
00410 int TH_FindFloatPlane(vec3_t normal, vec_t dist)
00411 {
00412     int i;
00413     th_plane_t *p;
00414     int hash, h;
00415 
00416     TH_SnapPlane (normal, &dist);
00417     hash = (int)fabs(dist) / 8;
00418     hash &= (PLANEHASH_SIZE-1);
00419 
00420     // search the border bins as well
00421     for (i = -1; i <= 1; i++)
00422     {
00423         h = (hash+i)&(PLANEHASH_SIZE-1);
00424         for (p = thworld.planehash[h]; p; p = p->hashnext)
00425         {
00426             if (TH_PlaneEqual(p, normal, dist))
00427             {
00428                 return p - thworld.planes;
00429             } //end if
00430         } //end for
00431     } //end for
00432     return TH_CreateFloatPlane(normal, dist);
00433 } //end of the function TH_FindFloatPlane
00434 //===========================================================================
00435 //
00436 // Parameter:           -
00437 // Returns:             -
00438 // Changes Globals:     -
00439 //===========================================================================
00440 int TH_PlaneFromPoints(int v1, int v2, int v3)
00441 {
00442     vec3_t t1, t2, normal;
00443     vec_t dist;
00444     float *p0, *p1, *p2;
00445 
00446     p0 = thworld.vertexes[v1].v;
00447     p1 = thworld.vertexes[v2].v;
00448     p2 = thworld.vertexes[v3].v;
00449 
00450     VectorSubtract(p0, p1, t1);
00451     VectorSubtract(p2, p1, t2);
00452     CrossProduct(t1, t2, normal);
00453     VectorNormalize(normal);
00454 
00455     dist = DotProduct(p0, normal);
00456 
00457     return TH_FindFloatPlane(normal, dist);
00458 } //end of the function TH_PlaneFromPoints
00459 //===========================================================================
00460 //
00461 // Parameter:           -
00462 // Returns:             -
00463 // Changes Globals:     -
00464 //===========================================================================
00465 void TH_AddEdgeUser(int edgenum)
00466 {
00467     th_edge_t *edge;
00468 
00469     edge = &thworld.edges[abs(edgenum)];
00470     //increase edge user count
00471     edge->usercount++;
00472     //increase vertex user count as well
00473     thworld.vertexes[edge->v[0]].usercount++;
00474     thworld.vertexes[edge->v[1]].usercount++;
00475 } //end of the function TH_AddEdgeUser
00476 //===========================================================================
00477 //
00478 // Parameter:           -
00479 // Returns:             -
00480 // Changes Globals:     -
00481 //===========================================================================
00482 void TH_RemoveEdgeUser(int edgenum)
00483 {
00484     th_edge_t *edge;
00485 
00486     edge = &thworld.edges[abs(edgenum)];
00487     //decrease edge user count
00488     edge->usercount--;
00489     //decrease vertex user count as well
00490     thworld.vertexes[edge->v[0]].usercount--;
00491     thworld.vertexes[edge->v[1]].usercount--;
00492 } //end of the function TH_RemoveEdgeUser
00493 //===========================================================================
00494 //
00495 // Parameter:           -
00496 // Returns:             -
00497 // Changes Globals:     -
00498 //===========================================================================
00499 void TH_FreeTriangleEdges(th_triangle_t *tri)
00500 {
00501     int i;
00502 
00503     for (i = 0; i < 3; i++)
00504     {
00505         TH_RemoveEdgeUser(abs(tri->edges[i]));
00506     } //end for
00507 } //end of the function TH_FreeTriangleEdges
00508 //===========================================================================
00509 //
00510 // Parameter:           -
00511 // Returns:             -
00512 // Changes Globals:     -
00513 //===========================================================================
00514 unsigned TH_HashVec(vec3_t vec)
00515 {
00516     int x, y;
00517 
00518     x = (MAX_MAP_BOUNDS + (int)(vec[0]+0.5)) >> VERTEXHASH_SHIFT;
00519     y = (MAX_MAP_BOUNDS + (int)(vec[1]+0.5)) >> VERTEXHASH_SHIFT;
00520 
00521     if (x < 0 || x >= VERTEXHASH_SIZE || y < 0 || y >= VERTEXHASH_SIZE)
00522         Error("HashVec: point %f %f %f outside valid range", vec[0], vec[1], vec[2]);
00523     
00524     return y*VERTEXHASH_SIZE + x;
00525 } //end of the function TH_HashVec
00526 //===========================================================================
00527 //
00528 // Parameter:           -
00529 // Returns:             -
00530 // Changes Globals:     -
00531 //===========================================================================
00532 int TH_FindVertex(vec3_t v)
00533 {
00534     int i, h;
00535     th_vertex_t *vertex;
00536     vec3_t vert;
00537     
00538     for (i = 0; i < 3; i++)
00539     {
00540         if ( fabs(v[i] - Q_rint(v[i])) < INTEGRAL_EPSILON)
00541             vert[i] = Q_rint(v[i]);
00542         else
00543             vert[i] = v[i];
00544     } //end for
00545 
00546     h = TH_HashVec(vert);
00547 
00548     for (vertex = thworld.vertexhash[h]; vertex; vertex = vertex->hashnext)
00549     {
00550         if (fabs(vertex->v[0] - vert[0]) < VERTEX_EPSILON &&
00551             fabs(vertex->v[1] - vert[1]) < VERTEX_EPSILON &&
00552             fabs(vertex->v[2] - vert[2]) < VERTEX_EPSILON)
00553         {
00554             return vertex - thworld.vertexes;
00555         } //end if
00556     } //end for
00557     return 0;
00558 } //end of the function TH_FindVertex
00559 //===========================================================================
00560 //
00561 // Parameter:           -
00562 // Returns:             -
00563 // Changes Globals:     -
00564 //===========================================================================
00565 void TH_AddVertexToHash(th_vertex_t *vertex)
00566 {
00567     int hashvalue;
00568 
00569     hashvalue = TH_HashVec(vertex->v);
00570     vertex->hashnext = thworld.vertexhash[hashvalue];
00571     thworld.vertexhash[hashvalue] = vertex;
00572 } //end of the function TH_AddVertexToHash
00573 //===========================================================================
00574 //
00575 // Parameter:           -
00576 // Returns:             -
00577 // Changes Globals:     -
00578 //===========================================================================
00579 int TH_CreateVertex(vec3_t v)
00580 {
00581     if (thworld.numvertexes == 0) thworld.numvertexes = 1;
00582     if (thworld.numvertexes >= MAX_TH_VERTEXES)
00583         Error("MAX_TH_VERTEXES");
00584     VectorCopy(v, thworld.vertexes[thworld.numvertexes].v);
00585     thworld.vertexes[thworld.numvertexes].usercount = 0;
00586     TH_AddVertexToHash(&thworld.vertexes[thworld.numvertexes]);
00587     thworld.numvertexes++;
00588     return thworld.numvertexes-1;
00589 } //end of the function TH_CreateVertex
00590 //===========================================================================
00591 //
00592 // Parameter:           -
00593 // Returns:             -
00594 // Changes Globals:     -
00595 //===========================================================================
00596 int TH_FindOrCreateVertex(vec3_t v)
00597 {
00598     int vertexnum;
00599 
00600     vertexnum = TH_FindVertex(v);
00601     if (!vertexnum) vertexnum = TH_CreateVertex(v);
00602     return vertexnum;
00603 } //end of the function TH_FindOrCreateVertex
00604 //===========================================================================
00605 //
00606 // Parameter:           -
00607 // Returns:             -
00608 // Changes Globals:     -
00609 //===========================================================================
00610 int TH_FindEdge(int v1, int v2)
00611 {
00612     int hashvalue;
00613     th_edge_t *edge;
00614 
00615     hashvalue = (v1 + v2) & (EDGEHASH_SIZE-1);
00616 
00617     for (edge = thworld.edgehash[hashvalue]; edge; edge = edge->hashnext)
00618     {
00619         if (edge->v[0] == v1 && edge->v[1] == v2) return edge - thworld.edges;
00620         if (edge->v[1] == v1 && edge->v[0] == v2) return -(edge - thworld.edges);
00621     } //end for
00622     return 0;
00623 } //end of the function TH_FindEdge
00624 //===========================================================================
00625 //
00626 // Parameter:           -
00627 // Returns:             -
00628 // Changes Globals:     -
00629 //===========================================================================
00630 void TH_AddEdgeToHash(th_edge_t *edge)
00631 {
00632     int hashvalue;
00633 
00634     hashvalue = (edge->v[0] + edge->v[1]) & (EDGEHASH_SIZE-1);
00635     edge->hashnext = thworld.edgehash[hashvalue];
00636     thworld.edgehash[hashvalue] = edge;
00637 } //end of the function TH_AddEdgeToHash
00638 //===========================================================================
00639 //
00640 // Parameter:           -
00641 // Returns:             -
00642 // Changes Globals:     -
00643 //===========================================================================
00644 int TH_CreateEdge(int v1, int v2)
00645 {
00646     th_edge_t *edge;
00647 
00648     if (thworld.numedges == 0) thworld.numedges = 1;
00649     if (thworld.numedges >= MAX_TH_EDGES)
00650         Error("MAX_TH_EDGES");
00651     edge = &thworld.edges[thworld.numedges++];
00652     edge->v[0] = v1;
00653     edge->v[1] = v2;
00654     TH_AddEdgeToHash(edge);
00655     return thworld.numedges-1;
00656 } //end of the function TH_CreateEdge
00657 //===========================================================================
00658 //
00659 // Parameter:           -
00660 // Returns:             -
00661 // Changes Globals:     -
00662 //===========================================================================
00663 int TH_FindOrCreateEdge(int v1, int v2)
00664 {
00665     int edgenum;
00666 
00667     edgenum = TH_FindEdge(v1, v2);
00668     if (!edgenum) edgenum = TH_CreateEdge(v1, v2);
00669     return edgenum;
00670 } //end of the function TH_FindOrCreateEdge
00671 //===========================================================================
00672 //
00673 // Parameter:           -
00674 // Returns:             -
00675 // Changes Globals:     -
00676 //===========================================================================
00677 int TH_FindTriangle(int verts[3])
00678 {
00679     int i, hashvalue, edges[3];
00680     th_triangle_t *tri;
00681 
00682     for (i = 0; i < 3; i++)
00683     {
00684         edges[i] = TH_FindEdge(verts[i], verts[(i+1)%3]);
00685         if (!edges[i]) return false;
00686     } //end for
00687     hashvalue = (abs(edges[0]) + abs(edges[1]) + abs(edges[2])) & (TRIANGLEHASH_SIZE-1);
00688     for (tri = thworld.trianglehash[hashvalue]; tri; tri = tri->next)
00689     {
00690         for (i = 0; i < 3; i++)
00691         {
00692             if (abs(tri->edges[i]) != abs(edges[0]) &&
00693                 abs(tri->edges[i]) != abs(edges[1]) &&
00694                 abs(tri->edges[i]) != abs(edges[2])) break;
00695         } //end for
00696         if (i >= 3) return tri - thworld.triangles;
00697     } //end for
00698     return 0;
00699 } //end of the function TH_FindTriangle
00700 //===========================================================================
00701 //
00702 // Parameter:           -
00703 // Returns:             -
00704 // Changes Globals:     -
00705 //===========================================================================
00706 void TH_AddTriangleToHash(th_triangle_t *tri)
00707 {
00708     int hashvalue;
00709 
00710     hashvalue = (abs(tri->edges[0]) + abs(tri->edges[1]) + abs(tri->edges[2])) & (TRIANGLEHASH_SIZE-1);
00711     tri->hashnext = thworld.trianglehash[hashvalue];
00712     thworld.trianglehash[hashvalue] = tri;
00713 } //end of the function TH_AddTriangleToHash
00714 //===========================================================================
00715 //
00716 // Parameter:           -
00717 // Returns:             -
00718 // Changes Globals:     -
00719 //===========================================================================
00720 void TH_CreateTrianglePlanes(int verts[3], th_plane_t *triplane, th_plane_t *planes)
00721 {
00722     int i;
00723     vec3_t dir;
00724 
00725     for (i = 0; i < 3; i++)
00726     {
00727         VectorSubtract(thworld.vertexes[verts[(i+1)%3]].v, thworld.vertexes[verts[i]].v, dir);
00728         CrossProduct(dir, triplane->normal, planes[i].normal);
00729         VectorNormalize(planes[i].normal);
00730         planes[i].dist = DotProduct(thworld.vertexes[verts[i]].v, planes[i].normal);
00731     } //end for
00732 } //end of the function TH_CreateTrianglePlanes
00733 //===========================================================================
00734 //
00735 // Parameter:           -
00736 // Returns:             -
00737 // Changes Globals:     -
00738 //===========================================================================
00739 int TH_CreateTriangle(int verts[3])
00740 {
00741     th_triangle_t *tri;
00742     int i;
00743 
00744     if (thworld.numtriangles == 0) thworld.numtriangles = 1;
00745     if (thworld.numtriangles >= MAX_TH_TRIANGLES)
00746         Error("MAX_TH_TRIANGLES");
00747     tri = &thworld.triangles[thworld.numtriangles++];
00748     for (i = 0; i < 3; i++)
00749     {
00750         tri->edges[i] = TH_FindOrCreateEdge(verts[i], verts[(i+1)%3]);
00751         TH_AddEdgeUser(abs(tri->edges[i]));
00752     } //end for
00753     tri->front = 0;
00754     tri->back = 0;
00755     tri->planenum = TH_PlaneFromPoints(verts[0], verts[1], verts[2]);
00756     tri->prev = NULL;
00757     tri->next = NULL;
00758     tri->hashnext = NULL;
00759     TH_CreateTrianglePlanes(verts, &thworld.planes[tri->planenum], tri->planes);
00760     TH_AddTriangleToHash(tri);
00761     ClearBounds(tri->mins, tri->maxs);
00762     for (i = 0; i < 3; i++)
00763     {
00764         AddPointToBounds(thworld.vertexes[verts[i]].v, tri->mins, tri->maxs);
00765     } //end for
00766     return thworld.numtriangles-1;
00767 } //end of the function TH_CreateTriangle
00768 //===========================================================================
00769 //
00770 // Parameter:           -
00771 // Returns:             -
00772 // Changes Globals:     -
00773 //===========================================================================
00774 int TH_CreateTetrahedron(int triangles[4])
00775 {
00776     th_tetrahedron_t *tetrahedron;
00777     int i;
00778 
00779     if (thworld.numtetrahedrons == 0) thworld.numtetrahedrons = 1;
00780     if (thworld.numtetrahedrons >= MAX_TH_TETRAHEDRONS)
00781         Error("MAX_TH_TETRAHEDRONS");
00782     tetrahedron = &thworld.tetrahedrons[thworld.numtetrahedrons++];
00783     for (i = 0; i < 4; i++)
00784     {
00785         tetrahedron->triangles[i] = triangles[i];
00786         if (thworld.triangles[abs(triangles[i])].front)
00787         {
00788             thworld.triangles[abs(triangles[i])].back = thworld.numtetrahedrons-1;
00789         } //end if
00790         else
00791         {
00792             thworld.triangles[abs(triangles[i])].front = thworld.numtetrahedrons-1;
00793         } //end else
00794     } //end for
00795     tetrahedron->volume = 0;
00796     return thworld.numtetrahedrons-1;
00797 } //end of the function TH_CreateTetrahedron
00798 //===========================================================================
00799 //
00800 // Parameter:           -
00801 // Returns:             -
00802 // Changes Globals:     -
00803 //===========================================================================
00804 int TH_IntersectTrianglePlanes(int v1, int v2, th_plane_t *triplane, th_plane_t *planes)
00805 {
00806     float *p1, *p2, front, back, frac, d;
00807     int i, side, lastside;
00808     vec3_t mid;
00809 
00810     p1 = thworld.vertexes[v1].v;
00811     p2 = thworld.vertexes[v2].v;
00812 
00813     front = DotProduct(p1, triplane->normal) - triplane->dist;
00814     back = DotProduct(p2, triplane->normal) - triplane->dist;
00815     //if both points at the same side of the plane
00816     if (front < 0.1 && back < 0.1) return false;
00817     if (front > -0.1 && back > -0.1) return false;
00818     //
00819     frac = front/(front-back);
00820     mid[0] = p1[0] + (p2[0] - p1[0]) * frac;
00821     mid[1] = p1[1] + (p2[1] - p1[1]) * frac;
00822     mid[2] = p1[2] + (p2[2] - p1[2]) * frac;
00823     //if the mid point is at the same side of all the tri bounding planes
00824     lastside = 0;
00825     for (i = 0; i < 3; i++)
00826     {
00827         d = DotProduct(mid, planes[i].normal) - planes[i].dist;
00828         side = d < 0;
00829         if (i && side != lastside) return false;
00830         lastside = side;
00831     } //end for
00832     return true;
00833 } //end of the function TH_IntersectTrianglePlanes
00834 //===========================================================================
00835 //
00836 // Parameter:           -
00837 // Returns:             -
00838 // Changes Globals:     -
00839 //===========================================================================
00840 int TH_OutsideBoundingBox(int v1, int v2, vec3_t mins, vec3_t maxs)
00841 {
00842     float *p1, *p2;
00843     int i;
00844 
00845     p1 = thworld.vertexes[v1].v;
00846     p2 = thworld.vertexes[v2].v;
00847     //if both points are at the outer side of one of the bounding box planes
00848     for (i = 0; i < 3; i++)
00849     {
00850         if (p1[i] < mins[i] && p2[i] < mins[i]) return true;
00851         if (p1[i] > maxs[i] && p2[i] > maxs[i]) return true;
00852     } //end for
00853     return false;
00854 } //end of the function TH_OutsideBoundingBox
00855 //===========================================================================
00856 //
00857 // Parameter:           -
00858 // Returns:             -
00859 // Changes Globals:     -
00860 //===========================================================================
00861 int TH_TryEdge(int v1, int v2)
00862 {
00863     int i, j, v;
00864     th_plane_t *plane;
00865     th_triangle_t *tri;
00866 
00867     //if the edge already exists it must be valid
00868     if (TH_FindEdge(v1, v2)) return true;
00869     //test the edge with all existing triangles
00870     for (i = 1; i < thworld.numtriangles; i++)
00871     {
00872         tri = &thworld.triangles[i];
00873         //if triangle is enclosed by two tetrahedrons we don't have to test it
00874         //because the edge always has to go through another triangle of those
00875         //tetrahedrons first to reach the enclosed triangle
00876         if (tri->front && tri->back) continue;
00877         //if the edges is totally outside the triangle bounding box
00878         if (TH_OutsideBoundingBox(v1, v2, tri->mins, tri->maxs)) continue;
00879         //if one of the edge vertexes is used by this triangle
00880         for (j = 0; j < 3; j++)
00881         {
00882             v = thworld.edges[abs(tri->edges[j])].v[tri->edges[j] < 0];
00883             if (v == v1 || v == v2) break;
00884         } //end for
00885         if (j < 3) continue;
00886         //get the triangle plane
00887         plane = &thworld.planes[tri->planenum];
00888         //if the edge intersects with a triangle then it's not valid
00889         if (TH_IntersectTrianglePlanes(v1, v2, plane, tri->planes)) return false;
00890     } //end for
00891     return true;
00892 } //end of the function TH_TryEdge
00893 //===========================================================================
00894 //
00895 // Parameter:           -
00896 // Returns:             -
00897 // Changes Globals:     -
00898 //===========================================================================
00899 int TH_TryTriangle(int verts[3])
00900 {
00901     th_plane_t planes[3], triplane;
00902     vec3_t t1, t2;
00903     float *p0, *p1, *p2;
00904     int i, j;
00905 
00906     p0 = thworld.vertexes[verts[0]].v;
00907     p1 = thworld.vertexes[verts[1]].v;
00908     p2 = thworld.vertexes[verts[2]].v;
00909 
00910     VectorSubtract(p0, p1, t1);
00911     VectorSubtract(p2, p1, t2);
00912     CrossProduct(t1, t2, triplane.normal);
00913     VectorNormalize(triplane.normal);
00914     triplane.dist = DotProduct(p0, triplane.normal);
00915     //
00916     TH_CreateTrianglePlanes(verts, &triplane, planes);
00917     //test if any existing edge intersects with this triangle
00918     for (i = 1; i < thworld.numedges; i++)
00919     {
00920         //if the edge is only used by triangles with tetrahedrons at both sides
00921         if (!thworld.edges[i].usercount) continue;
00922         //if one of the triangle vertexes is used by this edge
00923         for (j = 0; j < 3; j++)
00924         {
00925             if (verts[j] == thworld.edges[j].v[0] ||
00926                 verts[j] == thworld.edges[j].v[1]) break;
00927         } //end for
00928         if (j < 3) continue;
00929         //if this edge intersects with the triangle
00930         if (TH_IntersectTrianglePlanes(thworld.edges[i].v[0], thworld.edges[i].v[1], &triplane, planes)) return false;
00931     } //end for
00932     return true;
00933 } //end of the function TH_TryTriangle
00934 //===========================================================================
00935 //
00936 // Parameter:           -
00937 // Returns:             -
00938 // Changes Globals:     -
00939 //===========================================================================
00940 void TH_AddTriangleToList(th_triangle_t **trianglelist, th_triangle_t *tri)
00941 {
00942     tri->prev = NULL;
00943     tri->next = *trianglelist;
00944     if (*trianglelist) (*trianglelist)->prev = tri;
00945     *trianglelist = tri;
00946 } //end of the function TH_AddTriangleToList
00947 //===========================================================================
00948 //
00949 // Parameter:           -
00950 // Returns:             -
00951 // Changes Globals:     -
00952 //===========================================================================
00953 void TH_RemoveTriangleFromList(th_triangle_t **trianglelist, th_triangle_t *tri)
00954 {
00955     if (tri->next) tri->next->prev = tri->prev;
00956     if (tri->prev) tri->prev->next = tri->next;
00957     else *trianglelist = tri->next;
00958 } //end of the function TH_RemoveTriangleFromList
00959 //===========================================================================
00960 //
00961 // Parameter:           -
00962 // Returns:             -
00963 // Changes Globals:     -
00964 //===========================================================================
00965 int TH_FindTetrahedron1(th_triangle_t *tri, int *triangles)
00966 {
00967     int i, j, edgenum, side, v1, v2, v3, v4;
00968     int verts1[3], verts2[3];
00969     th_triangle_t *tri2;
00970 
00971     //find another triangle with a shared edge
00972     for (tri2 = tri->next; tri2; tri2 = tri2->next)
00973     {
00974         //if the triangles are in the same plane
00975         if ((tri->planenum & ~1) == (tri2->planenum & ~1)) continue;
00976         //try to find a shared edge
00977         for (i = 0; i < 3; i++)
00978         {
00979             edgenum = abs(tri->edges[i]);
00980             for (j = 0; j < 3; j++)
00981             {
00982                 if (edgenum == abs(tri2->edges[j])) break;
00983             } //end for
00984             if (j < 3) break;
00985         } //end for
00986         //if the triangles have a shared edge
00987         if (i < 3)
00988         {
00989             edgenum = tri->edges[(i+1)%3];
00990             if (edgenum < 0) v1 = thworld.edges[abs(edgenum)].v[0];
00991             else v1 = thworld.edges[edgenum].v[1];
00992             edgenum = tri2->edges[(j+1)%3];
00993             if (edgenum < 0) v2 = thworld.edges[abs(edgenum)].v[0];
00994             else v2 = thworld.edges[edgenum].v[1];
00995             //try the new edge
00996             if (TH_TryEdge(v1, v2))
00997             {
00998                 edgenum = tri->edges[i];
00999                 side = edgenum < 0;
01000                 //get the vertexes of the shared edge
01001                 v3 = thworld.edges[abs(edgenum)].v[side];
01002                 v4 = thworld.edges[abs(edgenum)].v[!side];
01003                 //try the two new triangles
01004                 verts1[0] = v1;
01005                 verts1[1] = v2;
01006                 verts1[2] = v3;
01007                 triangles[2] = TH_FindTriangle(verts1);
01008                 if (triangles[2] || TH_TryTriangle(verts1))
01009                 {
01010                     verts2[0] = v2;
01011                     verts2[1] = v1;
01012                     verts2[2] = v4;
01013                     triangles[3] = TH_FindTriangle(verts2);
01014                     if (triangles[3] || TH_TryTriangle(verts2))
01015                     {
01016                         triangles[0] = tri - thworld.triangles;
01017                         triangles[1] = tri2 - thworld.triangles;
01018                         if (!triangles[2]) triangles[2] = TH_CreateTriangle(verts1);
01019                         if (!triangles[3]) triangles[3] = TH_CreateTriangle(verts2);
01020                         return true;
01021                     } //end if
01022                 } //end if
01023             } //end if
01024         } //end if
01025     } //end for
01026     return false;
01027 } //end of the function TH_FindTetrahedron
01028 //===========================================================================
01029 //
01030 // Parameter:           -
01031 // Returns:             -
01032 // Changes Globals:     -
01033 //===========================================================================
01034 int TH_FindTetrahedron2(th_triangle_t *tri, int *triangles)
01035 {
01036     int i, edgenum, v1, verts[3], triverts[3];
01037     float d;
01038     th_plane_t *plane;
01039 
01040     //get the verts of this triangle
01041     for (i = 0; i < 3; i++)
01042     {
01043         edgenum = tri->edges[i];
01044         if (edgenum < 0) verts[i] = thworld.edges[abs(edgenum)].v[1];
01045         else verts[i] = thworld.edges[edgenum].v[0];
01046     } //end for
01047     //
01048     plane = &thworld.planes[tri->planenum];
01049     for (v1 = 0; v1 < thworld.numvertexes; v1++)
01050     {
01051         //if the vertex is only used by triangles with tetrahedrons at both sides
01052         if (!thworld.vertexes[v1].usercount) continue;
01053         //check if the vertex is not coplanar with the triangle
01054         d = DotProduct(thworld.vertexes[v1].v, plane->normal) - plane->dist;
01055         if (fabs(d) < 1) continue;
01056         //check if we can create edges from the triangle towards this new vertex
01057         for (i = 0; i < 3; i++)
01058         {
01059             if (v1 == verts[i]) break;
01060             if (!TH_TryEdge(v1, verts[i])) break;
01061         } //end for
01062         if (i < 3) continue;
01063         //check if the triangles are valid
01064         for (i = 0; i < 3; i++)
01065         {
01066             triverts[0] = v1;
01067             triverts[1] = verts[i];
01068             triverts[2] = verts[(i+1)%3];
01069             //if the triangle already exists then it is valid
01070             triangles[i] = TH_FindTriangle(triverts);
01071             if (!triangles[i])
01072             {
01073                 if (!TH_TryTriangle(triverts)) break;
01074             } //end if
01075         } //end for
01076         if (i < 3) continue;
01077         //create the tetrahedron triangles using the new vertex
01078         for (i = 0; i < 3; i++)
01079         {
01080             if (!triangles[i])
01081             {
01082                 triverts[0] = v1;
01083                 triverts[1] = verts[i];
01084                 triverts[2] = verts[(i+1)%3];
01085                 triangles[i] = TH_CreateTriangle(triverts);
01086             } //end if
01087         } //end for
01088         //add the existing triangle
01089         triangles[3] = tri - thworld.triangles;
01090         //
01091         return true;
01092     } //end for
01093     return false;
01094 } //end of the function TH_FindTetrahedron2
01095 //===========================================================================
01096 //
01097 // Parameter:           -
01098 // Returns:             -
01099