/* =========================================================================== Copyright (C) 1999-2005 Id Software, Inc. This file is part of Quake III Arena source code. Quake III Arena source code is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Quake III Arena source code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Foobar; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ #include "qbsp.h" #include "../botlib/aasfile.h" #include "aas_file.h" #include "aas_store.h" #include "aas_create.h" #include "aas_cfg.h" //#define NOTHREEVERTEXFACES #define STOREPLANESDOUBLE #define VERTEX_EPSILON 0.1 //NOTE: changed from 0.5 #define DIST_EPSILON 0.05 //NOTE: changed from 0.9 #define NORMAL_EPSILON 0.0001 //NOTE: changed from 0.005 #define INTEGRAL_EPSILON 0.01 #define VERTEX_HASHING #define VERTEX_HASH_SHIFT 7 #define VERTEX_HASH_SIZE ((MAX_MAP_BOUNDS>>(VERTEX_HASH_SHIFT-1))+1) //was 64 // #define PLANE_HASHING #define PLANE_HASH_SIZE 1024 //must be power of 2 // #define EDGE_HASHING #define EDGE_HASH_SIZE 1024 //must be power of 2 aas_t aasworld; //vertex hash int *aas_vertexchain; // the next vertex in a hash chain int aas_hashverts[VERTEX_HASH_SIZE*VERTEX_HASH_SIZE]; // a vertex number, or 0 for no verts //plane hash int *aas_planechain; int aas_hashplanes[PLANE_HASH_SIZE]; //edge hash int *aas_edgechain; int aas_hashedges[EDGE_HASH_SIZE]; int allocatedaasmem = 0; int groundfacesonly = false;//true; // typedef struct max_aas_s { int max_bboxes; int max_vertexes; int max_planes; int max_edges; int max_edgeindexsize; int max_faces; int max_faceindexsize; int max_areas; int max_areasettings; int max_reachabilitysize; int max_nodes; int max_portals; int max_portalindexsize; int max_clusters; } max_aas_t; //maximums of everything max_aas_t max_aas; //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_CountTmpNodes(tmp_node_t *tmpnode) { if (!tmpnode) return 0; return AAS_CountTmpNodes(tmpnode->children[0]) + AAS_CountTmpNodes(tmpnode->children[1]) + 1; } //end of the function AAS_CountTmpNodes //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_InitMaxAAS(void) { int numfaces, numpoints, numareas; tmp_face_t *f; tmp_area_t *a; numpoints = 0; numfaces = 0; for (f = tmpaasworld.faces; f; f = f->l_next) { numfaces++; if (f->winding) numpoints += f->winding->numpoints; } //end for // numareas = 0; for (a = tmpaasworld.areas; a; a = a->l_next) { numareas++; } //end for max_aas.max_bboxes = AAS_MAX_BBOXES; max_aas.max_vertexes = numpoints + 1; max_aas.max_planes = nummapplanes; max_aas.max_edges = numpoints + 1; max_aas.max_edgeindexsize = (numpoints + 1) * 3; max_aas.max_faces = numfaces + 10; max_aas.max_faceindexsize = (numfaces + 10) * 2; max_aas.max_areas = numareas + 10; max_aas.max_areasettings = numareas + 10; max_aas.max_reachabilitysize = 0; max_aas.max_nodes = AAS_CountTmpNodes(tmpaasworld.nodes) + 10; max_aas.max_portals = 0; max_aas.max_portalindexsize = 0; max_aas.max_clusters = 0; } //end of the function AAS_InitMaxAAS //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_AllocMaxAAS(void) { int i; AAS_InitMaxAAS(); //bounding boxes aasworld.numbboxes = 0; aasworld.bboxes = (aas_bbox_t *) GetClearedMemory(max_aas.max_bboxes * sizeof(aas_bbox_t)); allocatedaasmem += max_aas.max_bboxes * sizeof(aas_bbox_t); //vertexes aasworld.numvertexes = 0; aasworld.vertexes = (aas_vertex_t *) GetClearedMemory(max_aas.max_vertexes * sizeof(aas_vertex_t)); allocatedaasmem += max_aas.max_vertexes * sizeof(aas_vertex_t); //planes aasworld.numplanes = 0; aasworld.planes = (aas_plane_t *) GetClearedMemory(max_aas.max_planes * sizeof(aas_plane_t)); allocatedaasmem += max_aas.max_planes * sizeof(aas_plane_t); //edges aasworld.numedges = 0; aasworld.edges = (aas_edge_t *) GetClearedMemory(max_aas.max_edges * sizeof(aas_edge_t)); allocatedaasmem += max_aas.max_edges * sizeof(aas_edge_t); //edge index aasworld.edgeindexsize = 0; aasworld.edgeindex = (aas_edgeindex_t *) GetClearedMemory(max_aas.max_edgeindexsize * sizeof(aas_edgeindex_t)); allocatedaasmem += max_aas.max_edgeindexsize * sizeof(aas_edgeindex_t); //faces aasworld.numfaces = 0; aasworld.faces = (aas_face_t *) GetClearedMemory(max_aas.max_faces * sizeof(aas_face_t)); allocatedaasmem += max_aas.max_faces * sizeof(aas_face_t); //face index aasworld.faceindexsize = 0; aasworld.faceindex = (aas_faceindex_t *) GetClearedMemory(max_aas.max_faceindexsize * sizeof(aas_faceindex_t)); allocatedaasmem += max_aas.max_faceindexsize * sizeof(aas_faceindex_t); //convex areas aasworld.numareas = 0; aasworld.areas = (aas_area_t *) GetClearedMemory(max_aas.max_areas * sizeof(aas_area_t)); allocatedaasmem += max_aas.max_areas * sizeof(aas_area_t); //convex area settings aasworld.numareasettings = 0; aasworld.areasettings = (aas_areasettings_t *) GetClearedMemory(max_aas.max_areasettings * sizeof(aas_areasettings_t)); allocatedaasmem += max_aas.max_areasettings * sizeof(aas_areasettings_t); //reachablity list aasworld.reachabilitysize = 0; aasworld.reachability = (aas_reachability_t *) GetClearedMemory(max_aas.max_reachabilitysize * sizeof(aas_reachability_t)); allocatedaasmem += max_aas.max_reachabilitysize * sizeof(aas_reachability_t); //nodes of the bsp tree aasworld.numnodes = 0; aasworld.nodes = (aas_node_t *) GetClearedMemory(max_aas.max_nodes * sizeof(aas_node_t)); allocatedaasmem += max_aas.max_nodes * sizeof(aas_node_t); //cluster portals aasworld.numportals = 0; aasworld.portals = (aas_portal_t *) GetClearedMemory(max_aas.max_portals * sizeof(aas_portal_t)); allocatedaasmem += max_aas.max_portals * sizeof(aas_portal_t); //cluster portal index aasworld.portalindexsize = 0; aasworld.portalindex = (aas_portalindex_t *) GetClearedMemory(max_aas.max_portalindexsize * sizeof(aas_portalindex_t)); allocatedaasmem += max_aas.max_portalindexsize * sizeof(aas_portalindex_t); //cluster aasworld.numclusters = 0; aasworld.clusters = (aas_cluster_t *) GetClearedMemory(max_aas.max_clusters * sizeof(aas_cluster_t)); allocatedaasmem += max_aas.max_clusters * sizeof(aas_cluster_t); // Log_Print("allocated "); PrintMemorySize(allocatedaasmem); Log_Print(" of AAS memory\n"); //reset the has stuff aas_vertexchain = (int *) GetClearedMemory(max_aas.max_vertexes * sizeof(int)); aas_planechain = (int *) GetClearedMemory(max_aas.max_planes * sizeof(int)); aas_edgechain = (int *) GetClearedMemory(max_aas.max_edges * sizeof(int)); // for (i = 0; i < max_aas.max_vertexes; i++) aas_vertexchain[i] = -1; for (i = 0; i < VERTEX_HASH_SIZE * VERTEX_HASH_SIZE; i++) aas_hashverts[i] = -1; // for (i = 0; i < max_aas.max_planes; i++) aas_planechain[i] = -1; for (i = 0; i < PLANE_HASH_SIZE; i++) aas_hashplanes[i] = -1; // for (i = 0; i < max_aas.max_edges; i++) aas_edgechain[i] = -1; for (i = 0; i < EDGE_HASH_SIZE; i++) aas_hashedges[i] = -1; } //end of the function AAS_AllocMaxAAS //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_FreeMaxAAS(void) { //bounding boxes if (aasworld.bboxes) FreeMemory(aasworld.bboxes); aasworld.bboxes = NULL; aasworld.numbboxes = 0; //vertexes if (aasworld.vertexes) FreeMemory(aasworld.vertexes); aasworld.vertexes = NULL; aasworld.numvertexes = 0; //planes if (aasworld.planes) FreeMemory(aasworld.planes); aasworld.planes = NULL; aasworld.numplanes = 0; //edges if (aasworld.edges) FreeMemory(aasworld.edges); aasworld.edges = NULL; aasworld.numedges = 0; //edge index if (aasworld.edgeindex) FreeMemory(aasworld.edgeindex); aasworld.edgeindex = NULL; aasworld.edgeindexsize = 0; //faces if (aasworld.faces) FreeMemory(aasworld.faces); aasworld.faces = NULL; aasworld.numfaces = 0; //face index if (aasworld.faceindex) FreeMemory(aasworld.faceindex); aasworld.faceindex = NULL; aasworld.faceindexsize = 0; //convex areas if (aasworld.areas) FreeMemory(aasworld.areas); aasworld.areas = NULL; aasworld.numareas = 0; //convex area settings if (aasworld.areasettings) FreeMemory(aasworld.areasettings); aasworld.areasettings = NULL; aasworld.numareasettings = 0; //reachablity list if (aasworld.reachability) FreeMemory(aasworld.reachability); aasworld.reachability = NULL; aasworld.reachabilitysize = 0; //nodes of the bsp tree if (aasworld.nodes) FreeMemory(aasworld.nodes); aasworld.nodes = NULL; aasworld.numnodes = 0; //cluster portals if (aasworld.portals) FreeMemory(aasworld.portals); aasworld.portals = NULL; aasworld.numportals = 0; //cluster portal index if (aasworld.portalindex) FreeMemory(aasworld.portalindex); aasworld.portalindex = NULL; aasworld.portalindexsize = 0; //clusters if (aasworld.clusters) FreeMemory(aasworld.clusters); aasworld.clusters = NULL; aasworld.numclusters = 0; Log_Print("freed "); PrintMemorySize(allocatedaasmem); Log_Print(" of AAS memory\n"); allocatedaasmem = 0; // if (aas_vertexchain) FreeMemory(aas_vertexchain); aas_vertexchain = NULL; if (aas_planechain) FreeMemory(aas_planechain); aas_planechain = NULL; if (aas_edgechain) FreeMemory(aas_edgechain); aas_edgechain = NULL; } //end of the function AAS_FreeMaxAAS //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== unsigned AAS_HashVec(vec3_t vec) { int x, y; x = (MAX_MAP_BOUNDS + (int)(vec[0]+0.5)) >> VERTEX_HASH_SHIFT; y = (MAX_MAP_BOUNDS + (int)(vec[1]+0.5)) >> VERTEX_HASH_SHIFT; if (x < 0 || x >= VERTEX_HASH_SIZE || y < 0 || y >= VERTEX_HASH_SIZE) { Log_Print("WARNING! HashVec: point %f %f %f outside valid range\n", vec[0], vec[1], vec[2]); Log_Print("This should never happen!\n"); return -1; } //end if return y*VERTEX_HASH_SIZE + x; } //end of the function AAS_HashVec //=========================================================================== // returns true if the vertex was found in the list // stores the vertex number in *vnum // stores a new vertex if not stored already // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== qboolean AAS_GetVertex(vec3_t v, int *vnum) { int i; #ifndef VERTEX_HASHING float diff; #endif //VERTEX_HASHING #ifdef VERTEX_HASHING int h, vn; vec3_t vert; for (i = 0; i < 3; i++) { if ( fabs(v[i] - Q_rint(v[i])) < INTEGRAL_EPSILON) vert[i] = Q_rint(v[i]); else vert[i] = v[i]; } //end for h = AAS_HashVec(vert); //if the vertex was outside the valid range if (h == -1) { *vnum = -1; return true; } //end if for (vn = aas_hashverts[h]; vn >= 0; vn = aas_vertexchain[vn]) { if (fabs(aasworld.vertexes[vn][0] - vert[0]) < VERTEX_EPSILON && fabs(aasworld.vertexes[vn][1] - vert[1]) < VERTEX_EPSILON && fabs(aasworld.vertexes[vn][2] - vert[2]) < VERTEX_EPSILON) { *vnum = vn; return true; } //end if } //end for #else //VERTEX_HASHING //check if the vertex is already stored //stupid linear search for (i = 0; i < aasworld.numvertexes; i++) { diff = vert[0] - aasworld.vertexes[i][0]; if (diff < VERTEX_EPSILON && diff > -VERTEX_EPSILON) { diff = vert[1] - aasworld.vertexes[i][1]; if (diff < VERTEX_EPSILON && diff > -VERTEX_EPSILON) { diff = vert[2] - aasworld.vertexes[i][2]; if (diff < VERTEX_EPSILON && diff > -VERTEX_EPSILON) { *vnum = i; return true; } //end if } //end if } //end if } //end for #endif //VERTEX_HASHING if (aasworld.numvertexes >= max_aas.max_vertexes) { Error("AAS_MAX_VERTEXES = %d", max_aas.max_vertexes); } //end if VectorCopy(vert, aasworld.vertexes[aasworld.numvertexes]); *vnum = aasworld.numvertexes; #ifdef VERTEX_HASHING aas_vertexchain[aasworld.numvertexes] = aas_hashverts[h]; aas_hashverts[h] = aasworld.numvertexes; #endif //VERTEX_HASHING aasworld.numvertexes++; return false; } //end of the function AAS_GetVertex //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== unsigned AAS_HashEdge(int v1, int v2) { int vnum1, vnum2; // if (v1 < v2) { vnum1 = v1; vnum2 = v2; } //end if else { vnum1 = v2; vnum2 = v1; } //end else return (vnum1 + vnum2) & (EDGE_HASH_SIZE-1); } //end of the function AAS_HashVec //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_AddEdgeToHash(int edgenum) { int hash; aas_edge_t *edge; edge = &aasworld.edges[edgenum]; hash = AAS_HashEdge(edge->v[0], edge->v[1]); aas_edgechain[edgenum] = aas_hashedges[hash]; aas_hashedges[hash] = edgenum; } //end of the function AAS_AddEdgeToHash //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== qboolean AAS_FindHashedEdge(int v1num, int v2num, int *edgenum) { int e, hash; aas_edge_t *edge; hash = AAS_HashEdge(v1num, v2num); for (e = aas_hashedges[hash]; e >= 0; e = aas_edgechain[e]) { edge = &aasworld.edges[e]; if (edge->v[0] == v1num) { if (edge->v[1] == v2num) { *edgenum = e; return true; } //end if } //end if else if (edge->v[1] == v1num) { if (edge->v[0] == v2num) { //negative for a reversed edge *edgenum = -e; return true; } //end if } //end else } //end for return false; } //end of the function AAS_FindHashedPlane //=========================================================================== // returns true if the edge was found // stores the edge number in *edgenum (negative if reversed edge) // stores new edge if not stored already // returns zero when the edge is degenerate // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== qboolean AAS_GetEdge(vec3_t v1, vec3_t v2, int *edgenum) { int v1num, v2num; qboolean found; //the first edge is a dummy if (aasworld.numedges == 0) aasworld.numedges = 1; found = AAS_GetVertex(v1, &v1num); found &= AAS_GetVertex(v2, &v2num); //if one of the vertexes was outside the valid range if (v1num == -1 || v2num == -1) { *edgenum = 0; return true; } //end if //if both vertexes are the same or snapped onto each other if (v1num == v2num) { *edgenum = 0; return true; } //end if //if both vertexes where already stored if (found) { #ifdef EDGE_HASHING if (AAS_FindHashedEdge(v1num, v2num, edgenum)) return true; #else int i; for (i = 1; i < aasworld.numedges; i++) { if (aasworld.edges[i].v[0] == v1num) { if (aasworld.edges[i].v[1] == v2num) { *edgenum = i; return true; } //end if } //end if else if (aasworld.edges[i].v[1] == v1num) { if (aasworld.edges[i].v[0] == v2num) { //negative for a reversed edge *edgenum = -i; return true; } //end if } //end else } //end for #endif //EDGE_HASHING } //end if if (aasworld.numedges >= max_aas.max_edges) { Error("AAS_MAX_EDGES = %d", max_aas.max_edges); } //end if aasworld.edges[aasworld.numedges].v[0] = v1num; aasworld.edges[aasworld.numedges].v[1] = v2num; *edgenum = aasworld.numedges; #ifdef EDGE_HASHING AAS_AddEdgeToHash(*edgenum); #endif //EDGE_HASHING aasworld.numedges++; return false; } //end of the function AAS_GetEdge //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_PlaneTypeForNormal(vec3_t normal) { vec_t ax, ay, az; //NOTE: epsilon used if ( (normal[0] >= 1.0 -NORMAL_EPSILON) || (normal[0] <= -1.0 + NORMAL_EPSILON)) return PLANE_X; if ( (normal[1] >= 1.0 -NORMAL_EPSILON) || (normal[1] <= -1.0 + NORMAL_EPSILON)) return PLANE_Y; if ( (normal[2] >= 1.0 -NORMAL_EPSILON) || (normal[2] <= -1.0 + NORMAL_EPSILON)) return PLANE_Z; ax = fabs(normal[0]); ay = fabs(normal[1]); az = fabs(normal[2]); if (ax >= ay && ax >= az) return PLANE_ANYX; if (ay >= ax && ay >= az) return PLANE_ANYY; return PLANE_ANYZ; } //end of the function AAS_PlaneTypeForNormal //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_AddPlaneToHash(int planenum) { int hash; aas_plane_t *plane; plane = &aasworld.planes[planenum]; hash = (int)fabs(plane->dist) / 8; hash &= (PLANE_HASH_SIZE-1); aas_planechain[planenum] = aas_hashplanes[hash]; aas_hashplanes[hash] = planenum; } //end of the function AAS_AddPlaneToHash //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_PlaneEqual(vec3_t normal, float dist, int planenum) { float diff; diff = dist - aasworld.planes[planenum].dist; if (diff > -DIST_EPSILON && diff < DIST_EPSILON) { diff = normal[0] - aasworld.planes[planenum].normal[0]; if (diff > -NORMAL_EPSILON && diff < NORMAL_EPSILON) { diff = normal[1] - aasworld.planes[planenum].normal[1]; if (diff > -NORMAL_EPSILON && diff < NORMAL_EPSILON) { diff = normal[2] - aasworld.planes[planenum].normal[2]; if (diff > -NORMAL_EPSILON && diff < NORMAL_EPSILON) { return true; } //end if } //end if } //end if } //end if return false; } //end of the function AAS_PlaneEqual //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== qboolean AAS_FindPlane(vec3_t normal, float dist, int *planenum) { int i; for (i = 0; i < aasworld.numplanes; i++) { if (AAS_PlaneEqual(normal, dist, i)) { *planenum = i; return true; } //end if } //end for return false; } //end of the function AAS_FindPlane //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== qboolean AAS_FindHashedPlane(vec3_t normal, float dist, int *planenum) { int i, p; aas_plane_t *plane; int hash, h; hash = (int)fabs(dist) / 8; hash &= (PLANE_HASH_SIZE-1); //search the border bins as well for (i = -1; i <= 1; i++) { h = (hash+i)&(PLANE_HASH_SIZE-1); for (p = aas_hashplanes[h]; p >= 0; p = aas_planechain[p]) { plane = &aasworld.planes[p]; if (AAS_PlaneEqual(normal, dist, p)) { *planenum = p; return true; } //end if } //end for } //end for return false; } //end of the function AAS_FindHashedPlane //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== qboolean AAS_GetPlane(vec3_t normal, vec_t dist, int *planenum) { aas_plane_t *plane, temp; //if (AAS_FindPlane(normal, dist, planenum)) return true; if (AAS_FindHashedPlane(normal, dist, planenum)) return true; if (aasworld.numplanes >= max_aas.max_planes-1) { Error("AAS_MAX_PLANES = %d", max_aas.max_planes); } //end if #ifdef STOREPLANESDOUBLE plane = &aasworld.planes[aasworld.numplanes]; VectorCopy(normal, plane->normal); plane->dist = dist; plane->type = (plane+1)->type = PlaneTypeForNormal(plane->normal); VectorCopy(normal, (plane+1)->normal); VectorNegate((plane+1)->normal, (plane+1)->normal); (plane+1)->dist = -dist; aasworld.numplanes += 2; //allways put axial planes facing positive first if (plane->type < 3) { if (plane->normal[0] < 0 || plane->normal[1] < 0 || plane->normal[2] < 0) { // flip order temp = *plane; *plane = *(plane+1); *(plane+1) = temp; *planenum = aasworld.numplanes - 1; return false; } //end if } //end if *planenum = aasworld.numplanes - 2; //add the planes to the hash AAS_AddPlaneToHash(aasworld.numplanes - 1); AAS_AddPlaneToHash(aasworld.numplanes - 2); return false; #else plane = &aasworld.planes[aasworld.numplanes]; VectorCopy(normal, plane->normal); plane->dist = dist; plane->type = AAS_PlaneTypeForNormal(normal); *planenum = aasworld.numplanes; aasworld.numplanes++; //add the plane to the hash AAS_AddPlaneToHash(aasworld.numplanes - 1); return false; #endif //STOREPLANESDOUBLE } //end of the function AAS_GetPlane //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== qboolean AAS_GetFace(winding_t *w, plane_t *p, int side, int *facenum) { int edgenum, i, j; aas_face_t *face; //face zero is a dummy, because of the face index with negative numbers if (aasworld.numfaces == 0) aasworld.numfaces = 1; if (aasworld.numfaces >= max_aas.max_faces) { Error("AAS_MAX_FACES = %d", max_aas.max_faces); } //end if face = &aasworld.faces[aasworld.numfaces]; AAS_GetPlane(p->normal, p->dist, &face->planenum); face->faceflags = 0; face->firstedge = aasworld.edgeindexsize; face->frontarea = 0; face->backarea = 0; face->numedges = 0; for (i = 0; i < w->numpoints; i++) { if (aasworld.edgeindexsize >= max_aas.max_edgeindexsize) { Error("AAS_MAX_EDGEINDEXSIZE = %d", max_aas.max_edgeindexsize); } //end if j = (i+1) % w->numpoints; AAS_GetEdge(w->p[i], w->p[j], &edgenum); //if the edge wasn't degenerate if (edgenum) { aasworld.edgeindex[aasworld.edgeindexsize++] = edgenum; face->numedges++; } //end if else if (verbose) { Log_Write("AAS_GetFace: face %d had degenerate edge %d-%d\r\n", aasworld.numfaces, i, j); } //end else } //end for if (face->numedges < 1 #ifdef NOTHREEVERTEXFACES || face->numedges < 3 #endif //NOTHREEVERTEXFACES ) { memset(&aasworld.faces[aasworld.numfaces], 0, sizeof(aas_face_t)); Log_Write("AAS_GetFace: face %d was tiny\r\n", aasworld.numfaces); return false; } //end if *facenum = aasworld.numfaces; aasworld.numfaces++; return true; } //end of the function AAS_GetFace //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== /* qboolean AAS_GetFace(winding_t *w, plane_t *p, int side, int *facenum) { aas_edgeindex_t edges[1024]; int planenum, numedges, i; int j, edgenum; qboolean foundplane, foundedges; aas_face_t *face; //face zero is a dummy, because of the face index with negative numbers if (aasworld.numfaces == 0) aasworld.numfaces = 1; foundplane = AAS_GetPlane(p->normal, p->dist, &planenum); foundedges = true; numedges = w->numpoints; for (i = 0; i < w->numpoints; i++) { if (i >= 1024) Error("AAS_GetFace: more than %d edges\n", 1024); foundedges &= AAS_GetEdge(w->p[i], w->p[(i+1 >= w->numpoints ? 0 : i+1)], &edges[i]); } //end for //FIXME: use portal number instead of a search //if the plane and all edges already existed if (foundplane && foundedges) { for (i = 0; i < aasworld.numfaces; i++) { face = &aasworld.faces[i]; if (planenum == face->planenum) { if (numedges == face->numedges) { for (j = 0; j < numedges; j++) { edgenum = abs(aasworld.edgeindex[face->firstedge + j]); if (abs(edges[i]) != edgenum) break; } //end for if (j == numedges) { //jippy found the face *facenum = -i; return true; } //end if } //end if } //end if } //end for } //end if if (aasworld.numfaces >= max_aas.max_faces) { Error("AAS_MAX_FACES = %d", max_aas.max_faces); } //end if face = &aasworld.faces[aasworld.numfaces]; face->planenum = planenum; face->faceflags = 0; face->numedges = numedges; face->firstedge = aasworld.edgeindexsize; face->frontarea = 0; face->backarea = 0; for (i = 0; i < numedges; i++) { if (aasworld.edgeindexsize >= max_aas.max_edgeindexsize) { Error("AAS_MAX_EDGEINDEXSIZE = %d", max_aas.max_edgeindexsize); } //end if aasworld.edgeindex[aasworld.edgeindexsize++] = edges[i]; } //end for *facenum = aasworld.numfaces; aasworld.numfaces++; return false; } //end of the function AAS_GetFace*/ //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_StoreAreaSettings(tmp_areasettings_t *tmpareasettings) { aas_areasettings_t *areasettings; if (aasworld.numareasettings == 0) aasworld.numareasettings = 1; areasettings = &aasworld.areasettings[aasworld.numareasettings++]; areasettings->areaflags = tmpareasettings->areaflags; areasettings->presencetype = tmpareasettings->presencetype; areasettings->contents = tmpareasettings->contents; if (tmpareasettings->modelnum > AREACONTENTS_MAXMODELNUM) Log_Print("WARNING: more than %d mover models\n", AREACONTENTS_MAXMODELNUM); areasettings->contents |= (tmpareasettings->modelnum & AREACONTENTS_MAXMODELNUM) << AREACONTENTS_MODELNUMSHIFT; } //end of the function AAS_StoreAreaSettings //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_StoreArea(tmp_area_t *tmparea) { int side, edgenum, i; plane_t *plane; tmp_face_t *tmpface; aas_area_t *aasarea; aas_edge_t *edge; aas_face_t *aasface; aas_faceindex_t aasfacenum; vec3_t facecenter; winding_t *w; //when the area is merged go to the merged area //FIXME: this isn't necessary anymore because the tree // is refreshed after area merging while(tmparea->mergedarea) tmparea = tmparea->mergedarea; // if (tmparea->invalid) Error("AAS_StoreArea: tried to store invalid area"); //if there is an aas area already stored for this tmp area if (tmparea->aasareanum) return -tmparea->aasareanum; // if (aasworld.numareas >= max_aas.max_areas) { Error("AAS_MAX_AREAS = %d", max_aas.max_areas); } //end if //area zero is a dummy if (aasworld.numareas == 0) aasworld.numareas = 1; //create an area from this leaf aasarea = &aasworld.areas[aasworld.numareas]; aasarea->areanum = aasworld.numareas; aasarea->numfaces = 0; aasarea->firstface = aasworld.faceindexsize; ClearBounds(aasarea->mins, aasarea->maxs); VectorClear(aasarea->center); // // Log_Write("tmparea %d became aasarea %d\r\n", tmparea->areanum, aasarea->areanum); //store the aas area number at the tmp area tmparea->aasareanum = aasarea->areanum; // for (tmpface = tmparea->tmpfaces; tmpface; tmpface = tmpface->next[side]) { side = tmpface->frontarea != tmparea; //if there's an aas face created for the tmp face already if (tmpface->aasfacenum) { //we're at the back of the face so use a negative index aasfacenum = -tmpface->aasfacenum; #ifdef DEBUG if (tmpface->aasfacenum < 0 || tmpface->aasfacenum > max_aas.max_faces) { Error("AAS_CreateTree_r: face number out of range"); } //end if #endif //DEBUG aasface = &aasworld.faces[tmpface->aasfacenum]; aasface->backarea = aasarea->areanum; } //end if else { plane = &mapplanes[tmpface->planenum ^ side]; if (side) { w = tmpface->winding; tmpface->winding = ReverseWinding(tmpface->winding); } //end if if (!AAS_GetFace(tmpface->winding, plane, 0, &aasfacenum)) continue; if (side) { FreeWinding(tmpface->winding); tmpface->winding = w; } //end if aasface = &aasworld.faces[aasfacenum]; aasface->frontarea = aasarea->areanum; aasface->backarea = 0; aasface->faceflags = tmpface->faceflags; //set the face number at the tmp face tmpface->aasfacenum = aasfacenum; } //end else //add face points to the area bounds and //calculate the face 'center' VectorClear(facecenter); for (edgenum = 0; edgenum < aasface->numedges; edgenum++) { edge = &aasworld.edges[abs(aasworld.edgeindex[aasface->firstedge + edgenum])]; for (i = 0; i < 2; i++) { AddPointToBounds(aasworld.vertexes[edge->v[i]], aasarea->mins, aasarea->maxs); VectorAdd(aasworld.vertexes[edge->v[i]], facecenter, facecenter); } //end for } //end for VectorScale(facecenter, 1.0 / (aasface->numedges * 2.0), facecenter); //add the face 'center' to the area 'center' VectorAdd(aasarea->center, facecenter, aasarea->center); // if (aasworld.faceindexsize >= max_aas.max_faceindexsize) { Error("AAS_MAX_FACEINDEXSIZE = %d", max_aas.max_faceindexsize); } //end if aasworld.faceindex[aasworld.faceindexsize++] = aasfacenum; aasarea->numfaces++; } //end for //if the area has no faces at all (return 0, = solid leaf) if (!aasarea->numfaces) return 0; // VectorScale(aasarea->center, 1.0 / aasarea->numfaces, aasarea->center); //Log_Write("area %d center %f %f %f\r\n", aasworld.numareas, // aasarea->center[0], aasarea->center[1], aasarea->center[2]); //store the area settings AAS_StoreAreaSettings(tmparea->settings); // //Log_Write("tmp area %d became aas area %d\r\n", tmpareanum, aasarea->areanum); qprintf("\r%6d", aasarea->areanum); // aasworld.numareas++; return -(aasworld.numareas - 1); } //end of the function AAS_StoreArea //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_StoreTree_r(tmp_node_t *tmpnode) { int aasnodenum; plane_t *plane; aas_node_t *aasnode; //if it is a solid leaf if (!tmpnode) return 0; //negative so it's an area if (tmpnode->tmparea) return AAS_StoreArea(tmpnode->tmparea); //it's another node //the first node is a dummy if (aasworld.numnodes == 0) aasworld.numnodes = 1; if (aasworld.numnodes >= max_aas.max_nodes) { Error("AAS_MAX_NODES = %d", max_aas.max_nodes); } //end if aasnodenum = aasworld.numnodes; aasnode = &aasworld.nodes[aasworld.numnodes++]; plane = &mapplanes[tmpnode->planenum]; AAS_GetPlane(plane->normal, plane->dist, &aasnode->planenum); aasnode->children[0] = AAS_StoreTree_r(tmpnode->children[0]); aasnode->children[1] = AAS_StoreTree_r(tmpnode->children[1]); return aasnodenum; } //end of the function AAS_StoreTree_r //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_StoreBoundingBoxes(void) { if (cfg.numbboxes > max_aas.max_bboxes) { Error("more than %d bounding boxes", max_aas.max_bboxes); } //end if aasworld.numbboxes = cfg.numbboxes; memcpy(aasworld.bboxes, cfg.bboxes, cfg.numbboxes * sizeof(aas_bbox_t)); } //end of the function AAS_StoreBoundingBoxes //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_StoreFile(char *filename) { AAS_AllocMaxAAS(); Log_Write("AAS_StoreFile\r\n"); // AAS_StoreBoundingBoxes(); // qprintf("%6d areas stored", 0); //start with node 1 because node zero is a dummy AAS_StoreTree_r(tmpaasworld.nodes); qprintf("\n"); Log_Write("%6d areas stored\r\n", aasworld.numareas); aasworld.loaded = true; } //end of the function AAS_StoreFile