Skip to content
Browse files

bspc from quake3 1.32b source tarball.

  • Loading branch information...
0 parents commit 6b5cfd96ea29fbd0ba1139a5055f67bd06b0e442 @bnoordhuis committed
Showing with 11,058 additions and 0 deletions.
  1. +75 −0 Conscript
  2. +114 −0 Makefile
  3. +63 −0 _files.c
  4. +390 −0 aas_areamerging.c
  5. +24 −0 aas_areamerging.h
  6. +252 −0 aas_cfg.c
  7. +73 −0 aas_cfg.h
  8. +1,142 −0 aas_create.c
  9. +136 −0 aas_create.h
  10. +108 −0 aas_edgemelting.c
  11. +24 −0 aas_edgemelting.h
  12. +282 −0 aas_facemerging.c
  13. +24 −0 aas_facemerging.h
  14. +549 −0 aas_file.c
  15. +25 −0 aas_file.h
  16. +656 −0 aas_gsubdiv.c
  17. +25 −0 aas_gsubdiv.h
  18. +849 −0 aas_map.c
  19. +23 −0 aas_map.h
  20. +89 −0 aas_prunenodes.c
  21. +24 −0 aas_prunenodes.h
  22. +1,082 −0 aas_store.c
  23. +107 −0 aas_store.h
  24. +252 −0 aasfile.h
  25. +292 −0 be_aas_bspc.c
  26. +23 −0 be_aas_bspc.h
  27. +1,871 −0 brushbsp.c
  28. +991 −0 bspc.c
  29. +28 −0 bspc.sln
  30. +1,381 −0 bspc.vcproj
  31. +84 −0 cfgq3.c
Sorry, we could not display the entire diff because it was too big.
75 Conscript
@@ -0,0 +1,75 @@
+# bspc compile
+
+Import qw( BSPC_BASE_CFLAGS BUILD_DIR INSTALL_DIR CC CXX LINK );
+
+@BSPC_FILES = qw(
+ aas_areamerging.c
+ aas_cfg.c
+ aas_create.c
+ aas_edgemelting.c
+ aas_facemerging.c
+ aas_file.c
+ aas_gsubdiv.c
+ aas_map.c
+ aas_prunenodes.c
+ aas_store.c
+ be_aas_bspc.c
+ ../botlib/be_aas_bspq3.c
+ ../botlib/be_aas_cluster.c
+ ../botlib/be_aas_move.c
+ ../botlib/be_aas_optimize.c
+ ../botlib/be_aas_reach.c
+ ../botlib/be_aas_sample.c
+ brushbsp.c
+ bspc.c
+ ../qcommon/cm_load.c
+ ../qcommon/cm_patch.c
+ ../qcommon/cm_test.c
+ ../qcommon/cm_trace.c
+ csg.c
+ glfile.c
+ l_bsp_ent.c
+ l_bsp_hl.c
+ l_bsp_q1.c
+ l_bsp_q2.c
+ l_bsp_q3.c
+ l_bsp_sin.c
+ l_cmd.c
+ ../botlib/l_libvar.c
+ l_log.c
+ l_math.c
+ l_mem.c
+ l_poly.c
+ ../botlib/l_precomp.c
+ l_qfiles.c
+ ../botlib/l_script.c
+ ../botlib/l_struct.c
+ l_threads.c
+ l_utils.c
+ leakfile.c
+ map.c
+ map_hl.c
+ map_q1.c
+ map_q2.c
+ map_q3.c
+ map_sin.c
+ ../qcommon/md4.c
+ nodraw.c
+ portals.c
+ textures.c
+ tree.c
+ ../qcommon/unzip.c
+ );
+$BSPC_REF = \@BSPC_FILES;
+
+$env = new cons(
+ CC => $CC,
+ CXX => $CXX,
+ LINK => $LINK,
+ CFLAGS => $BSPC_BASE_CFLAGS,
+ LIBS => '-ldl -lm -lpthread'
+);
+
+Program $env 'bspc', @$BSPC_REF;
+# this should install to Q3 or something?
+Install $env $INSTALL_DIR, 'bspc';
114 Makefile
@@ -0,0 +1,114 @@
+#
+# Makefile for the BSPC tool for the Gladiator Bot
+# Intended for gcc/Linux
+#
+# TTimo 5/15/2001
+# some cleanup .. only used on i386 for GtkRadiant setups AFAIK .. removing the i386 tag
+# TODO: the intermediate object files should go into their own directory
+# specially for ../botlib and ../qcommon, the compilation flags on those might not be what you expect
+
+#ARCH=i386
+CC=gcc
+BASE_CFLAGS=-Dstricmp=strcasecmp
+
+#use these cflags to optimize it
+CFLAGS=$(BASE_CFLAGS) -m486 -O6 -ffast-math -funroll-loops \
+ -fomit-frame-pointer -fexpensive-optimizations -malign-loops=2 \
+ -malign-jumps=2 -malign-functions=2 -DLINUX -DBSPC
+#use these when debugging
+#CFLAGS=$(BASE_CFLAGS) -g
+
+LDFLAGS=-ldl -lm -lpthread
+
+DO_CC=$(CC) $(CFLAGS) -o $@ -c $<
+
+#############################################################################
+# SETUP AND BUILD BSPC
+#############################################################################
+
+.c.o:
+ $(DO_CC)
+
+GAME_OBJS = \
+ _files.o\
+ aas_areamerging.o\
+ aas_cfg.o\
+ aas_create.o\
+ aas_edgemelting.o\
+ aas_facemerging.o\
+ aas_file.o\
+ aas_gsubdiv.o\
+ aas_map.o\
+ aas_prunenodes.o\
+ aas_store.o\
+ be_aas_bspc.o\
+ ../botlib/be_aas_bspq3.o\
+ ../botlib/be_aas_cluster.o\
+ ../botlib/be_aas_move.o\
+ ../botlib/be_aas_optimize.o\
+ ../botlib/be_aas_reach.o\
+ ../botlib/be_aas_sample.o\
+ brushbsp.o\
+ bspc.o\
+ ../qcommon/cm_load.o\
+ ../qcommon/cm_patch.o\
+ ../qcommon/cm_test.o\
+ ../qcommon/cm_trace.o\
+ csg.o\
+ glfile.o\
+ l_bsp_ent.o\
+ l_bsp_hl.o\
+ l_bsp_q1.o\
+ l_bsp_q2.o\
+ l_bsp_q3.o\
+ l_bsp_sin.o\
+ l_cmd.o\
+ ../botlib/l_libvar.o\
+ l_log.o\
+ l_math.o\
+ l_mem.o\
+ l_poly.o\
+ ../botlib/l_precomp.o\
+ l_qfiles.o\
+ ../botlib/l_script.o\
+ ../botlib/l_struct.o\
+ l_threads.o\
+ l_utils.o\
+ leakfile.o\
+ map.o\
+ map_hl.o\
+ map_q1.o\
+ map_q2.o\
+ map_q3.o\
+ map_sin.o\
+ ../qcommon/md4.o\
+ nodraw.o\
+ portals.o\
+ textures.o\
+ tree.o\
+ ../qcommon/unzip.o
+
+ #tetrahedron.o
+
+bspc : $(GAME_OBJS)
+ $(CC) $(CFLAGS) -o $@ $(GAME_OBJS) $(LDFLAGS)
+ strip $@
+
+
+#############################################################################
+# MISC
+#############################################################################
+
+clean:
+ -rm -f $(GAME_OBJS)
+
+depend:
+ gcc -MM $(GAME_OBJS:.o=.c)
+
+#install:
+# cp bspci386 ..
+
+#
+# From "make depend"
+#
+
63 _files.c
@@ -0,0 +1,63 @@
+//===========================================================================
+//
+// Name: _files.c
+// Function:
+// Programmer: Mr Elusive
+// Last update: 1999-12-02
+// Tab Size: 4
+//===========================================================================
+
+/*
+
+aas_areamerging.c //AAS area merging
+aas_cfg.c //AAS configuration for different games
+aas_create.c //AAS creating
+aas_edgemelting.c //AAS edge melting
+aas_facemerging.c //AAS face merging
+aas_file.c //AAS file writing
+aas_gsubdiv.c //AAS gravitational and ladder subdivision
+aas_map.c //AAS map brush creation
+aas_prunenodes.c //AAS node pruning
+aas_store.c //AAS file storing
+
+map.c //map file loading and writing
+map_hl.c //Half-Life map loading
+map_q1.c //Quake1 map loading
+map_q2.c //Quake2 map loading
+map_q3.c //Quake3 map loading
+map_sin.c //Sin map loading
+tree.c //BSP tree management + node pruning (*)
+brushbsp.c //brush bsp creation (*)
+portals.c //BSP portal creation and leaf filling (*)
+csg.c //Constructive Solid Geometry brush chopping (*)
+leakfile.c //leak file writing (*)
+textures.c //Quake2 BSP textures (*)
+
+l_bsp_ent.c //BSP entity parsing
+l_bsp_hl.c //Half-Life BSP loading and writing
+l_bsp_q1.c //Quake1 BSP loading and writing
+l_bsp_q2.c //Quake2 BSP loading and writing
+l_bsp_q3.c //Quake2 BSP loading and writing
+l_bsp_sin.c //Sin BSP loading and writing
+l_cmd.c //cmd library
+l_log.c //log file library
+l_math.c //math library
+l_mem.c //memory management library
+l_poly.c //polygon (winding) library
+l_script.c //script file parsing library
+l_threads.c //multi-threading library
+l_utils.c //utility library
+l_qfiles.c //loading of quake files
+
+gldraw.c //GL drawing (*)
+glfile.c //GL file writing (*)
+nodraw.c //no draw module (*)
+
+bspc.c //BSPC Win32 console version
+winbspc.c //WinBSPC Win32 GUI version
+win32_terminal.c //Win32 terminal output
+win32_qfiles.c //Win32 game file management (also .pak .sin)
+win32_font.c //Win32 fonts
+win32_folder.c //Win32 folder dialogs
+
+*/
390 aas_areamerging.c
@@ -0,0 +1,390 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#include "qbsp.h"
+#include "../botlib/aasfile.h"
+#include "aas_create.h"
+#include "aas_store.h"
+
+#define CONVEX_EPSILON 0.3
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+tmp_node_t *AAS_RefreshMergedTree_r(tmp_node_t *tmpnode)
+{
+ tmp_area_t *tmparea;
+
+ //if this is a solid leaf
+ if (!tmpnode) return NULL;
+ //if this is an area leaf
+ if (tmpnode->tmparea)
+ {
+ tmparea = tmpnode->tmparea;
+ while(tmparea->mergedarea) tmparea = tmparea->mergedarea;
+ tmpnode->tmparea = tmparea;
+ return tmpnode;
+ } //end if
+ //do the children recursively
+ tmpnode->children[0] = AAS_RefreshMergedTree_r(tmpnode->children[0]);
+ tmpnode->children[1] = AAS_RefreshMergedTree_r(tmpnode->children[1]);
+ return tmpnode;
+} //end of the function AAS_RefreshMergedTree_r
+//===========================================================================
+// returns true if the two given faces would create a non-convex area at
+// the given sides, otherwise false is returned
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int NonConvex(tmp_face_t *face1, tmp_face_t *face2, int side1, int side2)
+{
+ int i;
+ winding_t *w1, *w2;
+ plane_t *plane1, *plane2;
+
+ w1 = face1->winding;
+ w2 = face2->winding;
+
+ plane1 = &mapplanes[face1->planenum ^ side1];
+ plane2 = &mapplanes[face2->planenum ^ side2];
+
+ //check if one of the points of face1 is at the back of the plane of face2
+ for (i = 0; i < w1->numpoints; i++)
+ {
+ if (DotProduct(plane2->normal, w1->p[i]) - plane2->dist < -CONVEX_EPSILON) return true;
+ } //end for
+ //check if one of the points of face2 is at the back of the plane of face1
+ for (i = 0; i < w2->numpoints; i++)
+ {
+ if (DotProduct(plane1->normal, w2->p[i]) - plane1->dist < -CONVEX_EPSILON) return true;
+ } //end for
+
+ return false;
+} //end of the function NonConvex
+//===========================================================================
+// try to merge the areas at both sides of the given face
+//
+// Parameter: seperatingface : face that seperates two areas
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int AAS_TryMergeFaceAreas(tmp_face_t *seperatingface)
+{
+ int side1, side2, area1faceflags, area2faceflags;
+ tmp_area_t *tmparea1, *tmparea2, *newarea;
+ tmp_face_t *face1, *face2, *nextface1, *nextface2;
+
+ tmparea1 = seperatingface->frontarea;
+ tmparea2 = seperatingface->backarea;
+
+ //areas must have the same presence type
+ if (tmparea1->presencetype != tmparea2->presencetype) return false;
+ //areas must have the same area contents
+ if (tmparea1->contents != tmparea2->contents) return false;
+ //areas must have the same bsp model inside (or both none)
+ if (tmparea1->modelnum != tmparea2->modelnum) return false;
+
+ area1faceflags = 0;
+ area2faceflags = 0;
+ for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side1])
+ {
+ side1 = (face1->frontarea != tmparea1);
+ //debug: check if the area belongs to the area
+ if (face1->frontarea != tmparea1 &&
+ face1->backarea != tmparea1) Error("face does not belong to area1");
+ //just continue if the face is seperating the two areas
+ //NOTE: a result of this is that ground and gap areas can
+ // be merged if the seperating face is the gap
+ if ((face1->frontarea == tmparea1 &&
+ face1->backarea == tmparea2) ||
+ (face1->frontarea == tmparea2 &&
+ face1->backarea == tmparea1)) continue;
+ //get area1 face flags
+ area1faceflags |= face1->faceflags;
+ if (AAS_GapFace(face1, side1)) area1faceflags |= FACE_GAP;
+ //
+ for (face2 = tmparea2->tmpfaces; face2; face2 = face2->next[side2])
+ {
+ side2 = (face2->frontarea != tmparea2);
+ //debug: check if the area belongs to the area
+ if (face2->frontarea != tmparea2 &&
+ face2->backarea != tmparea2) Error("face does not belong to area2");
+ //just continue if the face is seperating the two areas
+ //NOTE: a result of this is that ground and gap areas can
+ // be merged if the seperating face is the gap
+ if ((face2->frontarea == tmparea1 &&
+ face2->backarea == tmparea2) ||
+ (face2->frontarea == tmparea2 &&
+ face2->backarea == tmparea1)) continue;
+ //get area2 face flags
+ area2faceflags |= face2->faceflags;
+ if (AAS_GapFace(face2, side2)) area2faceflags |= FACE_GAP;
+ //if the two faces would create a non-convex area
+ if (NonConvex(face1, face2, side1, side2)) return false;
+ } //end for
+ } //end for
+ //if one area has gap faces (that aren't seperating the two areas)
+ //and the other has ground faces (that aren't seperating the two areas),
+ //the areas can't be merged
+ if (((area1faceflags & FACE_GROUND) && (area2faceflags & FACE_GAP)) ||
+ ((area2faceflags & FACE_GROUND) && (area1faceflags & FACE_GAP)))
+ {
+// Log_Print(" can't merge: ground/gap\n");
+ return false;
+ } //end if
+
+// Log_Print("merged area %d & %d to %d with %d faces\n", tmparea1->areanum, tmparea2->areanum, newarea->areanum, numfaces);
+// return false;
+ //
+ //AAS_CheckArea(tmparea1);
+ //AAS_CheckArea(tmparea2);
+ //create the new area
+ newarea = AAS_AllocTmpArea();
+ newarea->presencetype = tmparea1->presencetype;
+ newarea->contents = tmparea1->contents;
+ newarea->modelnum = tmparea1->modelnum;
+ newarea->tmpfaces = NULL;
+
+ //add all the faces (except the seperating ones) from the first area
+ //to the new area
+ for (face1 = tmparea1->tmpfaces; face1; face1 = nextface1)
+ {
+ side1 = (face1->frontarea != tmparea1);
+ nextface1 = face1->next[side1];
+ //don't add seperating faces
+ if ((face1->frontarea == tmparea1 &&
+ face1->backarea == tmparea2) ||
+ (face1->frontarea == tmparea2 &&
+ face1->backarea == tmparea1))
+ {
+ continue;
+ } //end if
+ //
+ AAS_RemoveFaceFromArea(face1, tmparea1);
+ AAS_AddFaceSideToArea(face1, side1, newarea);
+ } //end for
+ //add all the faces (except the seperating ones) from the second area
+ //to the new area
+ for (face2 = tmparea2->tmpfaces; face2; face2 = nextface2)
+ {
+ side2 = (face2->frontarea != tmparea2);
+ nextface2 = face2->next[side2];
+ //don't add seperating faces
+ if ((face2->frontarea == tmparea1 &&
+ face2->backarea == tmparea2) ||
+ (face2->frontarea == tmparea2 &&
+ face2->backarea == tmparea1))
+ {
+ continue;
+ } //end if
+ //
+ AAS_RemoveFaceFromArea(face2, tmparea2);
+ AAS_AddFaceSideToArea(face2, side2, newarea);
+ } //end for
+ //free all shared faces
+ for (face1 = tmparea1->tmpfaces; face1; face1 = nextface1)
+ {
+ side1 = (face1->frontarea != tmparea1);
+ nextface1 = face1->next[side1];
+ //
+ AAS_RemoveFaceFromArea(face1, face1->frontarea);
+ AAS_RemoveFaceFromArea(face1, face1->backarea);
+ AAS_FreeTmpFace(face1);
+ } //end for
+ //
+ tmparea1->mergedarea = newarea;
+ tmparea1->invalid = true;
+ tmparea2->mergedarea = newarea;
+ tmparea2->invalid = true;
+ //
+ AAS_CheckArea(newarea);
+ AAS_FlipAreaFaces(newarea);
+// Log_Print("merged area %d & %d to %d with %d faces\n", tmparea1->areanum, tmparea2->areanum, newarea->areanum);
+ return true;
+} //end of the function AAS_TryMergeFaceAreas
+//===========================================================================
+// try to merge areas
+// merged areas are added to the end of the convex area list so merging
+// will be tried for those areas as well
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: tmpaasworld
+//===========================================================================
+/*
+void AAS_MergeAreas(void)
+{
+ int side, nummerges;
+ tmp_area_t *tmparea, *othertmparea;
+ tmp_face_t *face;
+
+ nummerges = 0;
+ Log_Write("AAS_MergeAreas\r\n");
+ qprintf("%6d areas merged", 1);
+ //first merge grounded areas only
+ //NOTE: this is useless because the area settings aren't available yet
+ for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
+ {
+// Log_Print("checking area %d\n", i);
+ //if the area is invalid
+ if (tmparea->invalid)
+ {
+// Log_Print(" area invalid\n");
+ continue;
+ } //end if
+ //
+// if (!(tmparea->settings->areaflags & AREA_GROUNDED)) continue;
+ //
+ for (face = tmparea->tmpfaces; face; face = face->next[side])
+ {
+ side = (face->frontarea != tmparea);
+ //if the face has both a front and back area
+ if (face->frontarea && face->backarea)
+ {
+ //
+ if (face->frontarea == tmparea) othertmparea = face->backarea;
+ else othertmparea = face->frontarea;
+// if (!(othertmparea->settings->areaflags & AREA_GROUNDED)) continue;
+// Log_Print(" checking area %d with %d\n", face->frontarea, face->backarea);
+ if (AAS_TryMergeFaceAreas(face))
+ {
+ qprintf("\r%6d", ++nummerges);
+ break;
+ } //end if
+ } //end if
+ } //end for
+ } //end for
+ //merge all areas
+ for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
+ {
+// Log_Print("checking area %d\n", i);
+ //if the area is invalid
+ if (tmparea->invalid)
+ {
+// Log_Print(" area invalid\n");
+ continue;
+ } //end if
+ //
+ for (face = tmparea->tmpfaces; face; face = face->next[side])
+ {
+ side = (face->frontarea != tmparea);
+ //if the face has both a front and back area
+ if (face->frontarea && face->backarea)
+ {
+// Log_Print(" checking area %d with %d\n", face->frontarea, face->backarea);
+ if (AAS_TryMergeFaceAreas(face))
+ {
+ qprintf("\r%6d", ++nummerges);
+ break;
+ } //end if
+ } //end if
+ } //end for
+ } //end for
+ Log_Print("\r%6d areas merged\n", nummerges);
+ //refresh the merged tree
+ AAS_RefreshMergedTree_r(tmpaasworld.nodes);
+} //end of the function AAS_MergeAreas*/
+
+int AAS_GroundArea(tmp_area_t *tmparea)
+{
+ tmp_face_t *face;
+ int side;
+
+ for (face = tmparea->tmpfaces; face; face = face->next[side])
+ {
+ side = (face->frontarea != tmparea);
+ if (face->faceflags & FACE_GROUND) return true;
+ } //end for
+ return false;
+} //end of the function AAS_GroundArea
+
+void AAS_MergeAreas(void)
+{
+ int side, nummerges, merges, groundfirst;
+ tmp_area_t *tmparea, *othertmparea;
+ tmp_face_t *face;
+
+ nummerges = 0;
+ Log_Write("AAS_MergeAreas\r\n");
+ qprintf("%6d areas merged", 1);
+ //
+ groundfirst = true;
+ //for (i = 0; i < 4 || merges; i++)
+ while(1)
+ {
+ //if (i < 2) groundfirst = true;
+ //else groundfirst = false;
+ //
+ merges = 0;
+ //first merge grounded areas only
+ for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
+ {
+ //if the area is invalid
+ if (tmparea->invalid)
+ {
+ continue;
+ } //end if
+ //
+ if (groundfirst)
+ {
+ if (!AAS_GroundArea(tmparea)) continue;
+ } //end if
+ //
+ for (face = tmparea->tmpfaces; face; face = face->next[side])
+ {
+ side = (face->frontarea != tmparea);
+ //if the face has both a front and back area
+ if (face->frontarea && face->backarea)
+ {
+ //
+ if (face->frontarea == tmparea) othertmparea = face->backarea;
+ else othertmparea = face->frontarea;
+ //
+ if (groundfirst)
+ {
+ if (!AAS_GroundArea(othertmparea)) continue;
+ } //end if
+ if (AAS_TryMergeFaceAreas(face))
+ {
+ qprintf("\r%6d", ++nummerges);
+ merges++;
+ break;
+ } //end if
+ } //end if
+ } //end for
+ } //end for
+ if (!merges)
+ {
+ if (groundfirst) groundfirst = false;
+ else break;
+ } //end if
+ } //end for
+ qprintf("\n");
+ Log_Write("%6d areas merged\r\n", nummerges);
+ //refresh the merged tree
+ AAS_RefreshMergedTree_r(tmpaasworld.nodes);
+} //end of the function AAS_MergeAreas
24 aas_areamerging.h
@@ -0,0 +1,24 @@
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+void AAS_MergeAreas(void);
+
252 aas_cfg.c
@@ -0,0 +1,252 @@
+/*
+===========================================================================
+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 "float.h"
+#include "../botlib/aasfile.h"
+#include "aas_store.h"
+#include "aas_cfg.h"
+#include "../botlib/l_precomp.h"
+#include "../botlib/l_struct.h"
+#include "../botlib/l_libvar.h"
+
+//structure field offsets
+#define BBOX_OFS(x) (int)&(((aas_bbox_t *)0)->x)
+#define CFG_OFS(x) (int)&(((cfg_t *)0)->x)
+
+//bounding box definition
+fielddef_t bbox_fields[] =
+{
+ {"presencetype", BBOX_OFS(presencetype), FT_INT},
+ {"flags", BBOX_OFS(flags), FT_INT},
+ {"mins", BBOX_OFS(mins), FT_FLOAT|FT_ARRAY, 3},
+ {"maxs", BBOX_OFS(maxs), FT_FLOAT|FT_ARRAY, 3},
+ {NULL, 0, 0, 0}
+};
+
+fielddef_t cfg_fields[] =
+{
+ {"phys_gravitydirection", CFG_OFS(phys_gravitydirection), FT_FLOAT|FT_ARRAY, 3},
+ {"phys_friction", CFG_OFS(phys_friction), FT_FLOAT},
+ {"phys_stopspeed", CFG_OFS(phys_stopspeed), FT_FLOAT},
+ {"phys_gravity", CFG_OFS(phys_gravity), FT_FLOAT},
+ {"phys_waterfriction", CFG_OFS(phys_waterfriction), FT_FLOAT},
+ {"phys_watergravity", CFG_OFS(phys_watergravity), FT_FLOAT},
+ {"phys_maxvelocity", CFG_OFS(phys_maxvelocity), FT_FLOAT},
+ {"phys_maxwalkvelocity", CFG_OFS(phys_maxwalkvelocity), FT_FLOAT},
+ {"phys_maxcrouchvelocity", CFG_OFS(phys_maxcrouchvelocity), FT_FLOAT},
+ {"phys_maxswimvelocity", CFG_OFS(phys_maxswimvelocity), FT_FLOAT},
+ {"phys_walkaccelerate", CFG_OFS(phys_walkaccelerate), FT_FLOAT},
+ {"phys_airaccelerate", CFG_OFS(phys_airaccelerate), FT_FLOAT},
+ {"phys_swimaccelerate", CFG_OFS(phys_swimaccelerate), FT_FLOAT},
+ {"phys_maxstep", CFG_OFS(phys_maxstep), FT_FLOAT},
+ {"phys_maxsteepness", CFG_OFS(phys_maxsteepness), FT_FLOAT},
+ {"phys_maxwaterjump", CFG_OFS(phys_maxwaterjump), FT_FLOAT},
+ {"phys_maxbarrier", CFG_OFS(phys_maxbarrier), FT_FLOAT},
+ {"phys_jumpvel", CFG_OFS(phys_jumpvel), FT_FLOAT},
+ {"phys_falldelta5", CFG_OFS(phys_falldelta5), FT_FLOAT},
+ {"phys_falldelta10", CFG_OFS(phys_falldelta10), FT_FLOAT},
+ {"rs_waterjump", CFG_OFS(rs_waterjump), FT_FLOAT},
+ {"rs_teleport", CFG_OFS(rs_teleport), FT_FLOAT},
+ {"rs_barrierjump", CFG_OFS(rs_barrierjump), FT_FLOAT},
+ {"rs_startcrouch", CFG_OFS(rs_startcrouch), FT_FLOAT},
+ {"rs_startgrapple", CFG_OFS(rs_startgrapple), FT_FLOAT},
+ {"rs_startwalkoffledge", CFG_OFS(rs_startwalkoffledge), FT_FLOAT},
+ {"rs_startjump", CFG_OFS(rs_startjump), FT_FLOAT},
+ {"rs_rocketjump", CFG_OFS(rs_rocketjump), FT_FLOAT},
+ {"rs_bfgjump", CFG_OFS(rs_bfgjump), FT_FLOAT},
+ {"rs_jumppad", CFG_OFS(rs_jumppad), FT_FLOAT},
+ {"rs_aircontrolledjumppad", CFG_OFS(rs_aircontrolledjumppad), FT_FLOAT},
+ {"rs_funcbob", CFG_OFS(rs_funcbob), FT_FLOAT},
+ {"rs_startelevator", CFG_OFS(rs_startelevator), FT_FLOAT},
+ {"rs_falldamage5", CFG_OFS(rs_falldamage5), FT_FLOAT},
+ {"rs_falldamage10", CFG_OFS(rs_falldamage10), FT_FLOAT},
+ {"rs_maxjumpfallheight", CFG_OFS(rs_maxjumpfallheight), FT_FLOAT},
+ {NULL, 0, 0, 0}
+};
+
+structdef_t bbox_struct =
+{
+ sizeof(aas_bbox_t), bbox_fields
+};
+structdef_t cfg_struct =
+{
+ sizeof(cfg_t), cfg_fields
+};
+
+//global cfg
+cfg_t cfg;
+
+//===========================================================================
+// the default Q3A configuration
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void DefaultCfg(void)
+{
+ int i;
+
+ // default all float values to infinite
+ for (i = 0; cfg_fields[i].name; i++)
+ {
+ if ((cfg_fields[i].type & FT_TYPE) == FT_FLOAT)
+ *(float *)( ((char*)&cfg) + cfg_fields[i].offset ) = FLT_MAX;
+ } //end for
+ //
+ cfg.numbboxes = 2;
+ //bbox 0
+ cfg.bboxes[0].presencetype = PRESENCE_NORMAL;
+ cfg.bboxes[0].flags = 0;
+ cfg.bboxes[0].mins[0] = -15;
+ cfg.bboxes[0].mins[1] = -15;
+ cfg.bboxes[0].mins[2] = -24;
+ cfg.bboxes[0].maxs[0] = 15;
+ cfg.bboxes[0].maxs[1] = 15;
+ cfg.bboxes[0].maxs[2] = 32;
+ //bbox 1
+ cfg.bboxes[1].presencetype = PRESENCE_CROUCH;
+ cfg.bboxes[1].flags = 1;
+ cfg.bboxes[1].mins[0] = -15;
+ cfg.bboxes[1].mins[1] = -15;
+ cfg.bboxes[1].mins[2] = -24;
+ cfg.bboxes[1].maxs[0] = 15;
+ cfg.bboxes[1].maxs[1] = 15;
+ cfg.bboxes[1].maxs[2] = 16;
+ //
+ cfg.allpresencetypes = PRESENCE_NORMAL|PRESENCE_CROUCH;
+ cfg.phys_gravitydirection[0] = 0;
+ cfg.phys_gravitydirection[1] = 0;
+ cfg.phys_gravitydirection[2] = -1;
+ cfg.phys_maxsteepness = 0.7;
+} //end of the function DefaultCfg
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+char * QDECL va( char *format, ... )
+{
+ va_list argptr;
+ static char string[2][32000]; // in case va is called by nested functions
+ static int index = 0;
+ char *buf;
+
+ buf = string[index & 1];
+ index++;
+
+ va_start (argptr, format);
+ vsprintf (buf, format,argptr);
+ va_end (argptr);
+
+ return buf;
+} //end of the function va
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void SetCfgLibVars(void)
+{
+ int i;
+ float value;
+
+ for (i = 0; cfg_fields[i].name; i++)
+ {
+ if ((cfg_fields[i].type & FT_TYPE) == FT_FLOAT)
+ {
+ value = *(float *)(((char*)&cfg) + cfg_fields[i].offset);
+ if (value != FLT_MAX)
+ {
+ LibVarSet(cfg_fields[i].name, va("%f", value));
+ } //end if
+ } //end if
+ } //end for
+} //end of the function SetCfgLibVars
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int LoadCfgFile(char *filename)
+{
+ source_t *source;
+ token_t token;
+ int settingsdefined;
+
+ source = LoadSourceFile(filename);
+ if (!source)
+ {
+ Log_Print("couldn't open cfg file %s\n", filename);
+ return false;
+ } //end if
+
+ settingsdefined = false;
+ memset(&cfg, 0, sizeof(cfg_t));
+
+ while(PC_ReadToken(source, &token))
+ {
+ if (!stricmp(token.string, "bbox"))
+ {
+ if (cfg.numbboxes >= AAS_MAX_BBOXES)
+ {
+ SourceError(source, "too many bounding box volumes defined");
+ } //end if
+ if (!ReadStructure(source, &bbox_struct, (char *) &cfg.bboxes[cfg.numbboxes]))
+ {
+ FreeSource(source);
+ return false;
+ } //end if
+ cfg.allpresencetypes |= cfg.bboxes[cfg.numbboxes].presencetype;
+ cfg.numbboxes++;
+ } //end if
+ else if (!stricmp(token.string, "settings"))
+ {
+ if (settingsdefined)
+ {
+ SourceWarning(source, "settings already defined\n");
+ } //end if
+ settingsdefined = true;
+ if (!ReadStructure(source, &cfg_struct, (char *) &cfg))
+ {
+ FreeSource(source);
+ return false;
+ } //end if
+ } //end else if
+ } //end while
+ if (VectorLength(cfg.phys_gravitydirection) < 0.9 || VectorLength(cfg.phys_gravitydirection) > 1.1)
+ {
+ SourceError(source, "invalid gravity direction specified");
+ } //end if
+ if (cfg.numbboxes <= 0)
+ {
+ SourceError(source, "no bounding volumes specified");
+ } //end if
+ FreeSource(source);
+ SetCfgLibVars();
+ Log_Print("using cfg file %s\n", filename);
+ return true;
+} //end of the function LoadCfgFile
73 aas_cfg.h
@@ -0,0 +1,73 @@
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+#define BBOXFL_GROUNDED 1 //bounding box only valid when on ground
+#define BBOXFL_NOTGROUNDED 2 //bounding box only valid when NOT on ground
+
+typedef struct cfg_s
+{
+ int numbboxes; //number of bounding boxes
+ aas_bbox_t bboxes[AAS_MAX_BBOXES]; //all the bounding boxes
+ int allpresencetypes; //or of all presence types
+ // aas settings
+ vec3_t phys_gravitydirection;
+ float phys_friction;
+ float phys_stopspeed;
+ float phys_gravity;
+ float phys_waterfriction;
+ float phys_watergravity;
+ float phys_maxvelocity;
+ float phys_maxwalkvelocity;
+ float phys_maxcrouchvelocity;
+ float phys_maxswimvelocity;
+ float phys_walkaccelerate;
+ float phys_airaccelerate;
+ float phys_swimaccelerate;
+ float phys_maxstep;
+ float phys_maxsteepness;
+ float phys_maxwaterjump;
+ float phys_maxbarrier;
+ float phys_jumpvel;
+ float phys_falldelta5;
+ float phys_falldelta10;
+ float rs_waterjump;
+ float rs_teleport;
+ float rs_barrierjump;
+ float rs_startcrouch;
+ float rs_startgrapple;
+ float rs_startwalkoffledge;
+ float rs_startjump;
+ float rs_rocketjump;
+ float rs_bfgjump;
+ float rs_jumppad;
+ float rs_aircontrolledjumppad;
+ float rs_funcbob;
+ float rs_startelevator;
+ float rs_falldamage5;
+ float rs_falldamage10;
+ float rs_maxjumpfallheight;
+} cfg_t;
+
+extern cfg_t cfg;
+
+void DefaultCfg(void);
+int LoadCfgFile(char *filename);
1,142 aas_create.c
@@ -0,0 +1,1142 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#include "qbsp.h"
+#include "../botlib/aasfile.h"
+#include "aas_create.h"
+#include "aas_store.h"
+#include "aas_gsubdiv.h"
+#include "aas_facemerging.h"
+#include "aas_areamerging.h"
+#include "aas_edgemelting.h"
+#include "aas_prunenodes.h"
+#include "aas_cfg.h"
+#include "../game/surfaceflags.h"
+
+//#define AW_DEBUG
+//#define L_DEBUG
+
+#define AREAONFACESIDE(face, area) (face->frontarea != area)
+
+tmp_aas_t tmpaasworld;
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_InitTmpAAS(void)
+{
+ //tmp faces
+ tmpaasworld.numfaces = 0;
+ tmpaasworld.facenum = 0;
+ tmpaasworld.faces = NULL;
+ //tmp convex areas
+ tmpaasworld.numareas = 0;
+ tmpaasworld.areanum = 0;
+ tmpaasworld.areas = NULL;
+ //tmp nodes
+ tmpaasworld.numnodes = 0;
+ tmpaasworld.nodes = NULL;
+ //
+ tmpaasworld.nodebuffer = NULL;
+} //end of the function AAS_InitTmpAAS
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_FreeTmpAAS(void)
+{
+ tmp_face_t *f, *nextf;
+ tmp_area_t *a, *nexta;
+ tmp_nodebuf_t *nb, *nextnb;
+
+ //free all the faces
+ for (f = tmpaasworld.faces; f; f = nextf)
+ {
+ nextf = f->l_next;
+ if (f->winding) FreeWinding(f->winding);
+ FreeMemory(f);
+ } //end if
+ //free all tmp areas
+ for (a = tmpaasworld.areas; a; a = nexta)
+ {
+ nexta = a->l_next;
+ if (a->settings) FreeMemory(a->settings);
+ FreeMemory(a);
+ } //end for
+ //free all the tmp nodes
+ for (nb = tmpaasworld.nodebuffer; nb; nb = nextnb)
+ {
+ nextnb = nb->next;
+ FreeMemory(nb);
+ } //end for
+} //end of the function AAS_FreeTmpAAS
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+tmp_face_t *AAS_AllocTmpFace(void)
+{
+ tmp_face_t *tmpface;
+
+ tmpface = (tmp_face_t *) GetClearedMemory(sizeof(tmp_face_t));
+ tmpface->num = tmpaasworld.facenum++;
+ tmpface->l_prev = NULL;
+ tmpface->l_next = tmpaasworld.faces;
+ if (tmpaasworld.faces) tmpaasworld.faces->l_prev = tmpface;
+ tmpaasworld.faces = tmpface;
+ tmpaasworld.numfaces++;
+ return tmpface;
+} //end of the function AAS_AllocTmpFace
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_FreeTmpFace(tmp_face_t *tmpface)
+{
+ if (tmpface->l_next) tmpface->l_next->l_prev = tmpface->l_prev;
+ if (tmpface->l_prev) tmpface->l_prev->l_next = tmpface->l_next;
+ else tmpaasworld.faces = tmpface->l_next;
+ //free the winding
+ if (tmpface->winding) FreeWinding(tmpface->winding);
+ //free the face
+ FreeMemory(tmpface);
+ tmpaasworld.numfaces--;
+} //end of the function AAS_FreeTmpFace
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+tmp_area_t *AAS_AllocTmpArea(void)
+{
+ tmp_area_t *tmparea;
+
+ tmparea = (tmp_area_t *) GetClearedMemory(sizeof(tmp_area_t));
+ tmparea->areanum = tmpaasworld.areanum++;
+ tmparea->l_prev = NULL;
+ tmparea->l_next = tmpaasworld.areas;
+ if (tmpaasworld.areas) tmpaasworld.areas->l_prev = tmparea;
+ tmpaasworld.areas = tmparea;
+ tmpaasworld.numareas++;
+ return tmparea;
+} //end of the function AAS_AllocTmpArea
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_FreeTmpArea(tmp_area_t *tmparea)
+{
+ if (tmparea->l_next) tmparea->l_next->l_prev = tmparea->l_prev;
+ if (tmparea->l_prev) tmparea->l_prev->l_next = tmparea->l_next;
+ else tmpaasworld.areas = tmparea->l_next;
+ if (tmparea->settings) FreeMemory(tmparea->settings);
+ FreeMemory(tmparea);
+ tmpaasworld.numareas--;
+} //end of the function AAS_FreeTmpArea
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+tmp_node_t *AAS_AllocTmpNode(void)
+{
+ tmp_nodebuf_t *nodebuf;
+
+ if (!tmpaasworld.nodebuffer ||
+ tmpaasworld.nodebuffer->numnodes >= NODEBUF_SIZE)
+ {
+ nodebuf = (tmp_nodebuf_t *) GetClearedMemory(sizeof(tmp_nodebuf_t));
+ nodebuf->next = tmpaasworld.nodebuffer;
+ nodebuf->numnodes = 0;
+ tmpaasworld.nodebuffer = nodebuf;
+ } //end if
+ tmpaasworld.numnodes++;
+ return &tmpaasworld.nodebuffer->nodes[tmpaasworld.nodebuffer->numnodes++];
+} //end of the function AAS_AllocTmpNode
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_FreeTmpNode(tmp_node_t *tmpnode)
+{
+ tmpaasworld.numnodes--;
+} //end of the function AAS_FreeTmpNode
+//===========================================================================
+// returns true if the face is a gap from the given side
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int AAS_GapFace(tmp_face_t *tmpface, int side)
+{
+ vec3_t invgravity;
+
+ //if the face is a solid or ground face it can't be a gap
+ if (tmpface->faceflags & (FACE_GROUND | FACE_SOLID)) return 0;
+
+ VectorCopy(cfg.phys_gravitydirection, invgravity);
+ VectorInverse(invgravity);
+
+ return (DotProduct(invgravity, mapplanes[tmpface->planenum ^ side].normal) > cfg.phys_maxsteepness);
+} //end of the function AAS_GapFace
+//===========================================================================
+// returns true if the face is a ground face
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int AAS_GroundFace(tmp_face_t *tmpface)
+{
+ vec3_t invgravity;
+
+ //must be a solid face
+ if (!(tmpface->faceflags & FACE_SOLID)) return 0;
+
+ VectorCopy(cfg.phys_gravitydirection, invgravity);
+ VectorInverse(invgravity);
+
+ return (DotProduct(invgravity, mapplanes[tmpface->planenum].normal) > cfg.phys_maxsteepness);
+} //end of the function AAS_GroundFace
+//===========================================================================
+// adds the side of a face to an area
+//
+// side : 0 = front side
+// 1 = back side
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_AddFaceSideToArea(tmp_face_t *tmpface, int side, tmp_area_t *tmparea)
+{
+ int tmpfaceside;
+
+ if (side)
+ {
+ if (tmpface->backarea) Error("AAS_AddFaceSideToArea: already a back area\n");
+ } //end if
+ else
+ {
+ if (tmpface->frontarea) Error("AAS_AddFaceSideToArea: already a front area\n");
+ } //end else
+
+ if (side) tmpface->backarea = tmparea;
+ else tmpface->frontarea = tmparea;
+
+ if (tmparea->tmpfaces)
+ {
+ tmpfaceside = tmparea->tmpfaces->frontarea != tmparea;
+ tmparea->tmpfaces->prev[tmpfaceside] = tmpface;
+ } //end if
+ tmpface->next[side] = tmparea->tmpfaces;
+ tmpface->prev[side] = NULL;
+ tmparea->tmpfaces = tmpface;
+} //end of the function AAS_AddFaceSideToArea
+//===========================================================================
+// remove (a side of) a face from an area
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_RemoveFaceFromArea(tmp_face_t *tmpface, tmp_area_t *tmparea)
+{
+ int side, prevside, nextside;
+
+ if (tmpface->frontarea != tmparea &&
+ tmpface->backarea != tmparea)
+ {
+ Error("AAS_RemoveFaceFromArea: face not part of the area");
+ } //end if
+ side = tmpface->frontarea != tmparea;
+ if (tmpface->prev[side])
+ {
+ prevside = tmpface->prev[side]->frontarea != tmparea;
+ tmpface->prev[side]->next[prevside] = tmpface->next[side];
+ } //end if
+ else
+ {
+ tmparea->tmpfaces = tmpface->next[side];
+ } //end else
+ if (tmpface->next[side])
+ {
+ nextside = tmpface->next[side]->frontarea != tmparea;
+ tmpface->next[side]->prev[nextside] = tmpface->prev[side];
+ } //end if
+ //remove the area number from the face depending on the side
+ if (side) tmpface->backarea = NULL;
+ else tmpface->frontarea = NULL;
+ tmpface->prev[side] = NULL;
+ tmpface->next[side] = NULL;
+} //end of the function AAS_RemoveFaceFromArea
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_CheckArea(tmp_area_t *tmparea)
+{
+ int side;
+ tmp_face_t *face;
+ plane_t *plane;
+ vec3_t wcenter, acenter = {0, 0, 0};
+ vec3_t normal;
+ float n, dist;
+
+ if (tmparea->invalid) Log_Print("AAS_CheckArea: invalid area\n");
+ for (n = 0, face = tmparea->tmpfaces; face; face = face->next[side])
+ {
+ //side of the face the area is on
+ side = face->frontarea != tmparea;
+ WindingCenter(face->winding, wcenter);
+ VectorAdd(acenter, wcenter, acenter);
+ n++;
+ } //end for
+ n = 1 / n;
+ VectorScale(acenter, n, acenter);
+ for (face = tmparea->tmpfaces; face; face = face->next[side])
+ {
+ //side of the face the area is on
+ side = face->frontarea != tmparea;
+
+#ifdef L_DEBUG
+ if (WindingError(face->winding))
+ {
+ Log_Write("AAS_CheckArea: area %d face %d: %s\r\n", tmparea->areanum,
+ face->num, WindingErrorString());
+ } //end if
+#endif L_DEBUG
+
+ plane = &mapplanes[face->planenum ^ side];
+
+ if (DotProduct(plane->normal, acenter) - plane->dist < 0)
+ {
+ Log_Print("AAS_CheckArea: area %d face %d is flipped\n", tmparea->areanum, face->num);
+ Log_Print("AAS_CheckArea: area %d center is %f %f %f\n", tmparea->areanum, acenter[0], acenter[1], acenter[2]);
+ } //end if
+ //check if the winding plane is the same as the face plane
+ WindingPlane(face->winding, normal, &dist);
+ plane = &mapplanes[face->planenum];
+#ifdef L_DEBUG
+ if (fabs(dist - plane->dist) > 0.4 ||
+ fabs(normal[0] - plane->normal[0]) > 0.0001 ||
+ fabs(normal[1] - plane->normal[1]) > 0.0001 ||
+ fabs(normal[2] - plane->normal[2]) > 0.0001)
+ {
+ Log_Write("AAS_CheckArea: area %d face %d winding plane unequal to face plane\r\n",
+ tmparea->areanum, face->num);
+ } //end if
+#endif L_DEBUG
+ } //end for
+} //end of the function AAS_CheckArea
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_CheckFaceWindingPlane(tmp_face_t *face)
+{
+ float dist, sign1, sign2;
+ vec3_t normal;
+ plane_t *plane;
+ winding_t *w;
+
+ //check if the winding plane is the same as the face plane
+ WindingPlane(face->winding, normal, &dist);
+ plane = &mapplanes[face->planenum];
+ //
+ sign1 = DotProduct(plane->normal, normal);
+ //
+ if (fabs(dist - plane->dist) > 0.4 ||
+ fabs(normal[0] - plane->normal[0]) > 0.0001 ||
+ fabs(normal[1] - plane->normal[1]) > 0.0001 ||
+ fabs(normal[2] - plane->normal[2]) > 0.0001)
+ {
+ VectorInverse(normal);
+ dist = -dist;
+ if (fabs(dist - plane->dist) > 0.4 ||
+ fabs(normal[0] - plane->normal[0]) > 0.0001 ||
+ fabs(normal[1] - plane->normal[1]) > 0.0001 ||
+ fabs(normal[2] - plane->normal[2]) > 0.0001)
+ {
+ Log_Write("AAS_CheckFaceWindingPlane: face %d winding plane unequal to face plane\r\n",
+ face->num);
+ //
+ sign2 = DotProduct(plane->normal, normal);
+ if ((sign1 < 0 && sign2 > 0) ||
+ (sign1 > 0 && sign2 < 0))
+ {
+ Log_Write("AAS_CheckFaceWindingPlane: face %d winding reversed\r\n",
+ face->num);
+ w = face->winding;
+ face->winding = ReverseWinding(w);
+ FreeWinding(w);
+ } //end if
+ } //end if
+ else
+ {
+ Log_Write("AAS_CheckFaceWindingPlane: face %d winding reversed\r\n",
+ face->num);
+ w = face->winding;
+ face->winding = ReverseWinding(w);
+ FreeWinding(w);
+ } //end else
+ } //end if
+} //end of the function AAS_CheckFaceWindingPlane
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_CheckAreaWindingPlanes(void)
+{
+ int side;
+ tmp_area_t *tmparea;
+ tmp_face_t *face;
+
+ Log_Write("AAS_CheckAreaWindingPlanes:\r\n");
+ for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
+ {
+ if (tmparea->invalid) continue;
+ for (face = tmparea->tmpfaces; face; face = face->next[side])
+ {
+ side = face->frontarea != tmparea;
+ AAS_CheckFaceWindingPlane(face);
+ } //end for
+ } //end for
+} //end of the function AAS_CheckAreaWindingPlanes
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_FlipAreaFaces(tmp_area_t *tmparea)
+{
+ int side;
+ tmp_face_t *face;
+ plane_t *plane;
+ vec3_t wcenter, acenter = {0, 0, 0};
+ //winding_t *w;
+ float n;
+
+ for (n = 0, face = tmparea->tmpfaces; face; face = face->next[side])
+ {
+ if (!face->frontarea) Error("face %d has no front area\n", face->num);
+ //side of the face the area is on
+ side = face->frontarea != tmparea;
+ WindingCenter(face->winding, wcenter);
+ VectorAdd(acenter, wcenter, acenter);
+ n++;
+ } //end for
+ n = 1 / n;
+ VectorScale(acenter, n, acenter);
+ for (face = tmparea->tmpfaces; face; face = face->next[side])
+ {
+ //side of the face the area is on
+ side = face->frontarea != tmparea;
+
+ plane = &mapplanes[face->planenum ^ side];
+
+ if (DotProduct(plane->normal, acenter) - plane->dist < 0)
+ {
+ Log_Print("area %d face %d flipped: front area %d, back area %d\n", tmparea->areanum, face->num,
+ face->frontarea ? face->frontarea->areanum : 0,
+ face->backarea ? face->backarea->areanum : 0);
+ /*
+ face->planenum = face->planenum ^ 1;
+ w = face->winding;
+ face->winding = ReverseWinding(w);
+ FreeWinding(w);
+ */
+ } //end if
+#ifdef L_DEBUG
+ {
+ float dist;
+ vec3_t normal;
+
+ //check if the winding plane is the same as the face plane
+ WindingPlane(face->winding, normal, &dist);
+ plane = &mapplanes[face->planenum];
+ if (fabs(dist - plane->dist) > 0.4 ||
+ fabs(normal[0] - plane->normal[0]) > 0.0001 ||
+ fabs(normal[1] - plane->normal[1]) > 0.0001 ||
+ fabs(normal[2] - plane->normal[2]) > 0.0001)
+ {
+ Log_Write("area %d face %d winding plane unequal to face plane\r\n",
+ tmparea->areanum, face->num);
+ } //end if
+ }
+#endif
+ } //end for
+} //end of the function AAS_FlipAreaFaces
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_RemoveAreaFaceColinearPoints(void)
+{
+ int side;
+ tmp_face_t *face;
+ tmp_area_t *tmparea;
+
+ //FIXME: loop over the faces instead of area->faces
+ for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
+ {
+ for (face = tmparea->tmpfaces; face; face = face->next[side])
+ {
+ side = face->frontarea != tmparea;
+ RemoveColinearPoints(face->winding);
+// RemoveEqualPoints(face->winding, 0.1);
+ } //end for
+ } //end for
+} //end of the function AAS_RemoveAreaFaceColinearPoints
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_RemoveTinyFaces(void)
+{
+ int side, num;
+ tmp_face_t *face, *nextface;
+ tmp_area_t *tmparea;
+
+ //FIXME: loop over the faces instead of area->faces
+ Log_Write("AAS_RemoveTinyFaces\r\n");
+ num = 0;
+ for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
+ {
+ for (face = tmparea->tmpfaces; face; face = nextface)
+ {
+ side = face->frontarea != tmparea;
+ nextface = face->next[side];
+ //
+ if (WindingArea(face->winding) < 1)
+ {
+ if (face->frontarea) AAS_RemoveFaceFromArea(face, face->frontarea);
+ if (face->backarea) AAS_RemoveFaceFromArea(face, face->backarea);
+ AAS_FreeTmpFace(face);
+ //Log_Write("area %d face %d is tiny\r\n", tmparea->areanum, face->num);
+ num++;
+ } //end if
+ } //end for
+ } //end for
+ Log_Write("%d tiny faces removed\r\n", num);
+} //end of the function AAS_RemoveTinyFaces
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_CreateAreaSettings(void)
+{
+ int i, flags, side, numgrounded, numladderareas, numliquidareas;
+ tmp_face_t *face;
+ tmp_area_t *tmparea;
+
+ numgrounded = 0;
+ numladderareas = 0;
+ numliquidareas = 0;
+ Log_Write("AAS_CreateAreaSettings\r\n");
+ i = 0;
+ qprintf("%6d areas provided with settings", i);
+ for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
+ {
+ //if the area is invalid there no need to create settings for it
+ if (tmparea->invalid) continue;
+
+ tmparea->settings = (tmp_areasettings_t *) GetClearedMemory(sizeof(tmp_areasettings_t));
+ tmparea->settings->contents = tmparea->contents;
+ tmparea->settings->modelnum = tmparea->modelnum;
+ flags = 0;
+ for (face = tmparea->tmpfaces; face; face = face->next[side])
+ {
+ side = face->frontarea != tmparea;
+ flags |= face->faceflags;
+ } //end for
+ tmparea->settings->areaflags = 0;
+ if (flags & FACE_GROUND)
+ {
+ tmparea->settings->areaflags |= AREA_GROUNDED;
+ numgrounded++;
+ } //end if
+ if (flags & FACE_LADDER)
+ {
+ tmparea->settings->areaflags |= AREA_LADDER;
+ numladderareas++;
+ } //end if
+ if (tmparea->contents & (AREACONTENTS_WATER |
+ AREACONTENTS_SLIME |
+ AREACONTENTS_LAVA))
+ {
+ tmparea->settings->areaflags |= AREA_LIQUID;
+ numliquidareas++;
+ } //end if
+ //presence type of the area
+ tmparea->settings->presencetype = tmparea->presencetype;
+ //
+ qprintf("\r%6d", ++i);
+ } //end for
+ qprintf("\n");
+#ifdef AASINFO
+ Log_Print("%6d grounded areas\n", numgrounded);
+ Log_Print("%6d ladder areas\n", numladderareas);
+ Log_Print("%6d liquid areas\n", numliquidareas);
+#endif //AASINFO
+} //end of the function AAS_CreateAreaSettings
+//===========================================================================
+// create a tmp AAS area from a leaf node
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+tmp_node_t *AAS_CreateArea(node_t *node)
+{
+ int pside;
+ int areafaceflags;
+ portal_t *p;
+ tmp_face_t *tmpface;
+ tmp_area_t *tmparea;
+ tmp_node_t *tmpnode;
+ vec3_t up = {0, 0, 1};
+
+ //create an area from this leaf
+ tmparea = AAS_AllocTmpArea();
+ tmparea->tmpfaces = NULL;
+ //clear the area face flags
+ areafaceflags = 0;
+ //make aas faces from the portals
+ for (p = node->portals; p; p = p->next[pside])
+ {
+ pside = (p->nodes[1] == node);
+ //don't create faces from very small portals
+// if (WindingArea(p->winding) < 1) continue;
+ //if there's already a face created for this portal
+ if (p->tmpface)
+ {
+ //add the back side of the face to the area
+ AAS_AddFaceSideToArea(p->tmpface, 1, tmparea);
+ } //end if
+ else
+ {
+ tmpface = AAS_AllocTmpFace();
+ //set the face pointer at the portal so we can see from
+ //the portal there's a face created for it
+ p->tmpface = tmpface;
+ //FIXME: test this change
+ //tmpface->planenum = (p->planenum & ~1) | pside;
+ tmpface->planenum = p->planenum ^ pside;
+ if (pside) tmpface->winding = ReverseWinding(p->winding);
+ else tmpface->winding = CopyWinding(p->winding);
+#ifdef L_DEBUG
+ //
+ AAS_CheckFaceWindingPlane(tmpface);
+#endif //L_DEBUG
+ //if there's solid at the other side of the portal
+ if (p->nodes[!pside]->contents & (CONTENTS_SOLID | CONTENTS_PLAYERCLIP))
+ {
+ tmpface->faceflags |= FACE_SOLID;
+ } //end if
+ //else there is no solid at the other side and if there
+ //is a liquid at this side
+ else if (node->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA))
+ {
+ tmpface->faceflags |= FACE_LIQUID;
+ //if there's no liquid at the other side
+ if (!(p->nodes[!pside]->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)))
+ {
+ tmpface->faceflags |= FACE_LIQUIDSURFACE;
+ } //end if
+ } //end else
+ //if there's ladder contents at other side of the portal
+ if ((p->nodes[pside]->contents & CONTENTS_LADDER) ||
+ (p->nodes[!pside]->contents & CONTENTS_LADDER))
+ {
+
+ //NOTE: doesn't have to be solid at the other side because
+ // when standing one can use a crouch area (which is not solid)
+ // as a ladder
+ // imagine a ladder one can walk underthrough,
+ // under the ladder against the ladder is a crouch area
+ // the (vertical) sides of this crouch area area also used as
+ // ladder sides when standing (not crouched)
+ tmpface->faceflags |= FACE_LADDER;
+ } //end if
+ //if it is possible to stand on the face
+ if (AAS_GroundFace(tmpface))
+ {
+ tmpface->faceflags |= FACE_GROUND;
+ } //end if
+ //
+ areafaceflags |= tmpface->faceflags;
+ //no aas face number yet (zero is a dummy in the aasworld faces)
+ tmpface->aasfacenum = 0;
+ //add the front side of the face to the area
+ AAS_AddFaceSideToArea(tmpface, 0, tmparea);
+ } //end else
+ } //end for
+ qprintf("\r%6d", tmparea->areanum);
+ //presence type in the area
+ tmparea->presencetype = ~node->expansionbboxes & cfg.allpresencetypes;
+ //
+ tmparea->contents = 0;
+ if (node->contents & CONTENTS_CLUSTERPORTAL) tmparea->contents |= AREACONTENTS_CLUSTERPORTAL;
+ if (node->contents & CONTENTS_MOVER) tmparea->contents |= AREACONTENTS_MOVER;
+ if (node->contents & CONTENTS_TELEPORTER) tmparea->contents |= AREACONTENTS_TELEPORTER;
+ if (node->contents & CONTENTS_JUMPPAD) tmparea->contents |= AREACONTENTS_JUMPPAD;
+ if (node->contents & CONTENTS_DONOTENTER) tmparea->contents |= AREACONTENTS_DONOTENTER;
+ if (node->contents & CONTENTS_WATER) tmparea->contents |= AREACONTENTS_WATER;
+ if (node->contents & CONTENTS_LAVA) tmparea->contents |= AREACONTENTS_LAVA;
+ if (node->contents & CONTENTS_SLIME) tmparea->contents |= AREACONTENTS_SLIME;
+ if (node->contents & CONTENTS_NOTTEAM1) tmparea->contents |= AREACONTENTS_NOTTEAM1;
+ if (node->contents & CONTENTS_NOTTEAM2) tmparea->contents |= AREACONTENTS_NOTTEAM2;
+
+ //store the bsp model that's inside this node
+ tmparea->modelnum = node->modelnum;
+ //sorta check for flipped area faces (remove??)
+ AAS_FlipAreaFaces(tmparea);
+ //check if the area is ok (remove??)
+ AAS_CheckArea(tmparea);
+ //
+ tmpnode = AAS_AllocTmpNode();
+ tmpnode->planenum = 0;
+ tmpnode->children[0] = 0;
+ tmpnode->children[1] = 0;
+ tmpnode->tmparea = tmparea;
+ //
+ return tmpnode;
+} //end of the function AAS_CreateArea
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+tmp_node_t *AAS_CreateAreas_r(node_t *node)
+{
+ tmp_node_t *tmpnode;
+
+ //recurse down to leafs
+ if (node->planenum != PLANENUM_LEAF)
+ {
+ //the first tmp node is a dummy
+ tmpnode = AAS_AllocTmpNode();
+ tmpnode->planenum = node->planenum;
+ tmpnode->children[0] = AAS_CreateAreas_r(node->children[0]);
+ tmpnode->children[1] = AAS_CreateAreas_r(node->children[1]);
+ return tmpnode;
+ } //end if
+ //areas won't be created for solid leafs
+ if (node->contents & CONTENTS_SOLID)
+ {
+ //just return zero for a solid leaf (in tmp AAS NULL is a solid leaf)
+ return NULL;
+ } //end if
+
+ return AAS_CreateArea(node);
+} //end of the function AAS_CreateAreas_r
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_CreateAreas(node_t *node)
+{
+ Log_Write("AAS_CreateAreas\r\n");
+ qprintf("%6d areas created", 0);
+ tmpaasworld.nodes = AAS_CreateAreas_r(node);
+ qprintf("\n");
+ Log_Write("%6d areas created\r\n", tmpaasworld.numareas);
+} //end of the function AAS_CreateAreas
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_PrintNumGroundFaces(void)
+{
+ tmp_face_t *tmpface;
+ int numgroundfaces = 0;
+
+ for (tmpface = tmpaasworld.faces; tmpface; tmpface = tmpface->l_next)
+ {
+ if (tmpface->faceflags & FACE_GROUND)
+ {
+ numgroundfaces++;
+ } //end if
+ } //end for
+ qprintf("%6d ground faces\n", numgroundfaces);
+} //end of the function AAS_PrintNumGroundFaces
+//===========================================================================
+// checks the number of shared faces between the given two areas
+// since areas are convex they should only have ONE shared face
+// however due to crappy face merging there are sometimes several
+// shared faces
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_CheckAreaSharedFaces(tmp_area_t *tmparea1, tmp_area_t *tmparea2)
+{
+ int numsharedfaces, side;
+ tmp_face_t *face1, *sharedface;
+
+ if (tmparea1->invalid || tmparea2->invalid) return;
+
+ sharedface = NULL;
+ numsharedfaces = 0;
+ for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side])
+ {
+ side = face1->frontarea != tmparea1;
+ if (face1->backarea == tmparea2 || face1->frontarea == tmparea2)
+ {
+ sharedface = face1;
+ numsharedfaces++;
+ } //end if
+ } //end if
+ if (!sharedface) return;
+ //the areas should only have one shared face
+ if (numsharedfaces > 1)
+ {
+ Log_Write("---- tmp area %d and %d have %d shared faces\r\n",
+ tmparea1->areanum, tmparea2->areanum, numsharedfaces);
+ for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side])
+ {
+ side = face1->frontarea != tmparea1;
+ if (face1->backarea == tmparea2 || face1->frontarea == tmparea2)
+ {
+ Log_Write("face %d, planenum = %d, face->frontarea = %d face->backarea = %d\r\n",
+ face1->num, face1->planenum, face1->frontarea->areanum, face1->backarea->areanum);
+ } //end if
+ } //end if
+ } //end if
+} //end of the function AAS_CheckAreaSharedFaces
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_CheckSharedFaces(void)
+{
+ tmp_area_t *tmparea1, *tmparea2;
+
+ for (tmparea1 = tmpaasworld.areas; tmparea1; tmparea1 = tmparea1->l_next)
+ {
+ for (tmparea2 = tmpaasworld.areas; tmparea2; tmparea2 = tmparea2->l_next)
+ {
+ if (tmparea1 == tmparea2) continue;
+ AAS_CheckAreaSharedFaces(tmparea1, tmparea2);
+ } //end for
+ } //end for
+} //end of the function AAS_CheckSharedFaces
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_FlipFace(tmp_face_t *face)
+{
+ tmp_area_t *frontarea, *backarea;
+ winding_t *w;
+
+ frontarea = face->frontarea;
+ backarea = face->backarea;
+ //must have an area at both sides before flipping is allowed
+ if (!frontarea || !backarea) return;
+ //flip the face winding
+ w = face->winding;
+ face->winding = ReverseWinding(w);
+ FreeWinding(w);
+ //flip the face plane
+ face->planenum ^= 1;
+ //flip the face areas
+ AAS_RemoveFaceFromArea(face, frontarea);
+ AAS_RemoveFaceFromArea(face, backarea);
+ AAS_AddFaceSideToArea(face, 1, frontarea);
+ AAS_AddFaceSideToArea(face, 0, backarea);
+} //end of the function AAS_FlipFace
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+/*
+void AAS_FlipAreaSharedFaces(tmp_area_t *tmparea1, tmp_area_t *tmparea2)
+{
+ int numsharedfaces, side, area1facing, area2facing;
+ tmp_face_t *face1, *sharedface;
+
+ if (tmparea1->invalid || tmparea2->invalid) return;
+
+ sharedface = NULL;
+ numsharedfaces = 0;
+ area1facing = 0; //number of shared faces facing towards area 1
+ area2facing = 0; //number of shared faces facing towards area 2
+ for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side])
+ {
+ side = face1->frontarea != tmparea1;
+ if (face1->backarea == tmparea2 || face1->frontarea == tmparea2)
+ {
+ sharedface = face1;
+ numsharedfaces++;
+ if (face1->frontarea == tmparea1) area1facing++;
+ else area2facing++;
+ } //end if
+ } //end if
+ if (!sharedface) return;
+ //if there's only one shared face
+ if (numsharedfaces <= 1) return;
+ //if all the shared faces are facing to the same area
+ if (numsharedfaces == area1facing || numsharedfaces == area2facing) return;
+ //
+ do
+ {
+ for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side])
+ {
+ side = face1->frontarea != tmparea1;
+ if (face1->backarea == tmparea2 || face1->frontarea == tmparea2)
+ {
+ if (face1->frontarea != tmparea1)
+ {
+ AAS_FlipFace(face1);
+ break;
+ } //end if
+ } //end if
+ } //end for
+ } while(face1);
+} //end of the function AAS_FlipAreaSharedFaces
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_FlipSharedFaces(void)
+{
+ int i;
+ tmp_area_t *tmparea1, *tmparea2;
+
+ i = 0;
+ qprintf("%6d areas checked for shared face flipping", i);
+ for (tmparea1 = tmpaasworld.areas; tmparea1; tmparea1 = tmparea1->l_next)
+ {
+ if (tmparea1->invalid) continue;
+ for (tmparea2 = tmpaasworld.areas; tmparea2; tmparea2 = tmparea2->l_next)
+ {
+ if (tmparea2->invalid) continue;
+ if (tmparea1 == tmparea2) continue;
+ AAS_FlipAreaSharedFaces(tmparea1, tmparea2);
+ } //end for
+ qprintf("\r%6d", ++i);
+ } //end for
+ Log_Print("\r%6d areas checked for shared face flipping\n", i);
+} //end of the function AAS_FlipSharedFaces
+*/
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_FlipSharedFaces(void)
+{
+ int i, side1, side2;
+ tmp_area_t *tmparea1;
+ tmp_face_t *face1, *face2;
+
+ i = 0;
+ qprintf("%6d areas checked for shared face flipping", i);
+ for (tmparea1 = tmpaasworld.areas; tmparea1; tmparea1 = tmparea1->l_next)
+ {
+ if (tmparea1->invalid) continue;
+ for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side1])
+ {
+ side1 = face1->frontarea != tmparea1;
+ if (!face1->frontarea || !face1->backarea) continue;
+ //
+ for (face2 = face1->next[side1]; face2; face2 = face2->next[side2])
+ {
+ side2 = face2->frontarea != tmparea1;
+ if (!face2->frontarea || !face2->backarea) continue;
+ //
+ if (face1->frontarea == face2->backarea &&
+ face1->backarea == face2->frontarea)
+ {
+ AAS_FlipFace(face2);
+ } //end if
+ //recheck side
+ side2 = face2->frontarea != tmparea1;
+ } //end for
+ } //end for
+ qprintf("\r%6d", ++i);
+ } //end for
+ qprintf("\n");
+ Log_Write("%6d areas checked for shared face flipping\r\n", i);
+} //end of the function AAS_FlipSharedFaces
+//===========================================================================
+// creates an .AAS file with the given name
+// a MAP should be loaded before calling this
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_Create(char *aasfile)
+{
+ entity_t *e;
+ tree_t *tree;
+ double start_time;
+
+ //for a possible leak file
+ strcpy(source, aasfile);
+ StripExtension(source);
+ //the time started
+ start_time = I_FloatTime();
+ //set the default number of threads (depends on number of processors)
+ ThreadSetDefault();
+ //set the global entity number to the world model
+ entity_num = 0;
+ //the world entity
+ e = &entities[entity_num];
+ //process the whole world
+ tree = ProcessWorldBrushes(e->firstbrush, e->firstbrush + e->numbrushes);
+ //if the conversion is cancelled
+ if (cancelconversion)
+ {
+ Tree_Free(tree);
+ return;
+ } //end if
+ //display BSP tree creation time
+ Log_Print("BSP tree created in %5.0f seconds\n", I_FloatTime() - start_time);
+ //prune the bsp tree
+ Tree_PruneNodes(tree->headnode);
+ //if the conversion is cancelled
+ if (cancelconversion)
+ {
+ Tree_Free(tree);
+ return;
+ } //end if
+ //create the tree portals
+ MakeTreePortals(tree);
+ //if the conversion is cancelled
+ if (cancelconversion)
+ {
+ Tree_Free(tree);
+ return;
+ } //end if
+ //Marks all nodes that can be reached by entites
+ if (FloodEntities(tree))
+ {
+ //fill out nodes that can't be reached
+ FillOutside(tree->headnode);
+ } //end if
+ else
+ {
+ LeakFile(tree);
+ Error("**** leaked ****\n");
+ return;
+ } //end else
+ //create AAS from the BSP tree
+ //==========================================
+ //initialize tmp aas
+ AAS_InitTmpAAS();
+ //create the convex areas from the leaves
+ AAS_CreateAreas(tree->headnode);
+ //free the BSP tree because it isn't used anymore
+ if (freetree) Tree_Free(tree);
+ //try to merge area faces
+ AAS_MergeAreaFaces();
+ //do gravitational subdivision
+ AAS_GravitationalSubdivision();
+ //merge faces if possible
+ AAS_MergeAreaFaces();
+ AAS_RemoveAreaFaceColinearPoints();
+ //merge areas if possible
+ AAS_MergeAreas();
+ //NOTE: prune nodes directly after area merging
+ AAS_PruneNodes();
+ //flip shared faces so they are all facing to the same area
+ AAS_FlipSharedFaces();
+ AAS_RemoveAreaFaceColinearPoints();
+ //merge faces if possible
+ AAS_MergeAreaFaces();
+ //merge area faces in the same plane
+ AAS_MergeAreaPlaneFaces();
+ //do ladder subdivision
+ AAS_LadderSubdivision();
+ //FIXME: melting is buggy
+ AAS_MeltAreaFaceWindings();
+ //remove tiny faces
+ AAS_RemoveTinyFaces();
+ //create area settings
+ AAS_CreateAreaSettings();
+ //check if the winding plane is equal to the face plane
+ //AAS_CheckAreaWindingPlanes();
+ //
+ //AAS_CheckSharedFaces();
+ //==========================================
+ //if the conversion is cancelled
+ if (cancelconversion)
+ {
+ Tree_Free(tree);
+ AAS_FreeTmpAAS();
+ return;
+ } //end if
+ //store the created AAS stuff in the AAS file format and write the file
+ AAS_StoreFile(aasfile);
+ //free the temporary AAS memory
+ AAS_FreeTmpAAS();
+ //display creation time
+ Log_Print("\nAAS created in %5.0f seconds\n", I_FloatTime() - start_time);
+} //end of the function AAS_Create
136 aas_create.h
@@ -0,0 +1,136 @@
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+#define AREA_PORTAL 1
+
+//temporary AAS face
+typedef struct tmp_face_s
+{
+ int num; //face number
+ int planenum; //number of the plane the face is in
+ winding_t *winding; //winding of the face
+ struct tmp_area_s *frontarea; //area at the front of the face
+ struct tmp_area_s *backarea; //area at the back of the face
+ int faceflags; //flags of this face
+ int aasfacenum; //the number of the aas face used for this face
+ //double link list pointers for front and back area
+ struct tmp_face_s *prev[2], *next[2];
+ //links in the list with faces
+ struct tmp_face_s *l_prev, *l_next;
+} tmp_face_t;
+
+//temporary AAS area settings
+typedef struct tmp_areasettings_s
+{
+ //could also add all kind of statistic fields
+ int contents; //contents of the area
+ int modelnum; //bsp model inside this area
+ int areaflags; //area flags
+ int presencetype; //how a bot can be present in this area
+ int numreachableareas; //number of reachable areas from this one
+ int firstreachablearea; //first reachable area in the reachable area index
+} tmp_areasettings_t;
+
+//temporary AAS area
+typedef struct tmp_area_s
+{
+ int areanum; //number of the area
+ struct tmp_face_s *tmpfaces; //the faces of the area
+ int presencetype; //presence type of the area
+ int contents; //area contents
+ int modelnum; //bsp model inside this area
+ int invalid; //true if the area is invalid
+ tmp_areasettings_t *settings; //area settings
+ struct tmp_area_s *mergedarea; //points to the new area after merging
+ //when mergedarea != 0 the area has only the
+ //seperating face of the merged areas
+ int aasareanum; //number of the aas area created for this tmp area
+ //links in the list with areas
+ struct tmp_area_s *l_prev, *l_next;
+} tmp_area_t;
+
+//temporary AAS node
+typedef struct tmp_node_s
+{
+ int planenum; //node plane number
+ struct tmp_area_s *tmparea; //points to an area if this node is an area
+ struct tmp_node_s *children[2]; //child nodes of this node
+} tmp_node_t;
+
+#define NODEBUF_SIZE 128
+//node buffer
+typedef struct tmp_nodebuf_s
+{
+ int numnodes;
+ struct tmp_nodebuf_s *next;
+ tmp_node_t nodes[NODEBUF_SIZE];
+} tmp_nodebuf_t;
+
+//the whole temorary AAS
+typedef struct tmp_aas_s
+{
+ //faces
+ int numfaces;
+ int facenum;
+ tmp_face_t *faces;
+ //areas
+ int numareas;
+ int areanum;
+ tmp_area_t *areas;
+ //area settings
+ int numareasettings;
+ tmp_areasettings_t *areasettings;
+ //nodes
+ int numnodes;
+ tmp_node_t *nodes;
+ //node buffer
+ tmp_nodebuf_t *nodebuffer;
+} tmp_aas_t;
+
+extern tmp_aas_t tmpaasworld;
+
+//creates a .AAS file with the given name from an already loaded map
+void AAS_Create(char *aasfile);
+//adds a face side to an area
+void AAS_AddFaceSideToArea(tmp_face_t *tmpface, int side, tmp_area_t *tmparea);
+//remvoes a face from an area
+void AAS_RemoveFaceFromArea(tmp_face_t *tmpface, tmp_area_t *tmparea);
+//allocate a tmp face
+tmp_face_t *AAS_AllocTmpFace(void);
+//free the tmp face
+void AAS_FreeTmpFace(tmp_face_t *tmpface);
+//allocate a tmp area
+tmp_area_t *AAS_AllocTmpArea(void);
+//free a tmp area
+void AAS_FreeTmpArea(tmp_area_t *tmparea);
+//allocate a tmp node
+tmp_node_t *AAS_AllocTmpNode(void);
+//free a tmp node
+void AAS_FreeTmpNode(tmp_node_t *node);
+//checks if an area is ok
+void AAS_CheckArea(tmp_area_t *tmparea);
+//flips the area faces where needed
+void AAS_FlipAreaFaces(tmp_area_t *tmparea);
+//returns true if the face is a gap seen from the given side
+int AAS_GapFace(tmp_face_t *tmpface, int side);
+//returns true if the face is a ground face
+int AAS_GroundFace(tmp_face_t *tmpface);
108 aas_edgemelting.c
@@ -0,0 +1,108 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#include "qbsp.h"
+#include "../botlib/aasfile.h"
+#include "aas_create.h"
+
+//===========================================================================
+// try to melt the windings of the two faces
+// FIXME: this is buggy
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int AAS_MeltFaceWinding(tmp_face_t *face1, tmp_face_t *face2)
+{
+ int i, n;
+ int splits = 0;
+ winding_t *w2, *neww;
+ plane_t *plane1;
+
+#ifdef DEBUG
+ if (!face1->winding) Error("face1 %d without winding", face1->num);
+ if (!face2->winding) Error("face2 %d without winding", face2->num);
+#endif //DEBUG
+ w2 = face2->winding;
+ plane1 = &mapplanes[face1->planenum];
+ for (i = 0; i < w2->numpoints; i++)
+ {
+ if (PointOnWinding(face1->winding, plane1->normal, plane1->dist, w2->p[i], &n))
+ {
+ neww = AddWindingPoint(face1->winding, w2->p[i], n);
+ FreeWinding(face1->winding);
+ face1->winding = neww;
+
+ splits++;
+ } //end if
+ } //end for
+ return splits;
+} //end of the function AAS_MeltFaceWinding
+//===========================================================================
+// melt the windings of the area faces
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int AAS_MeltFaceWindingsOfArea(tmp_area_t *tmparea)
+{
+ int side1, side2, num_windingsplits = 0;
+ tmp_face_t *face1, *face2;
+
+ for (face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1])
+ {
+ side1 = face1->frontarea != tmparea;
+ for (face2 = tmparea->tmpfaces; face2; face2 = face2->next[side2])
+ {
+ side2 = face2->frontarea != tmparea;
+ if (face1 == face2) continue;
+ num_windingsplits += AAS_MeltFaceWinding(face1, face2);
+ } //end for
+ } //end for
+ return num_windingsplits;
+} //end of the function AAS_MeltFaceWindingsOfArea
+//===========================================================================
+// melt the windings of the faces of all areas
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_MeltAreaFaceWindings(void)
+{
+ tmp_area_t *tmparea;
+ int num_windingsplits = 0;
+
+ Log_Write("AAS_MeltAreaFaceWindings\r\n");
+ qprintf("%6d edges melted", num_windingsplits);
+ //NOTE: first convex area (zero) is a dummy
+ for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
+ {
+ num_windingsplits += AAS_MeltFaceWindingsOfArea(tmparea);
+ qprintf("\r%6d", num_windingsplits);
+ } //end for
+ qprintf("\n");
+ Log_Write("%6d edges melted\r\n", num_windingsplits);
+} //end of the function AAS_MeltAreaFaceWindings
+
24 aas_edgemelting.h
@@ -0,0 +1,24 @@
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+void AAS_MeltAreaFaceWindings(void);
+
282 aas_facemerging.c
@@ -0,0 +1,282 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#include "qbsp.h"
+#include "../botlib/aasfile.h"
+#include "aas_create.h"
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int AAS_TryMergeFaces(tmp_face_t *face1, tmp_face_t *face2)
+{
+ winding_t *neww;
+
+#ifdef DEBUG
+ if (!face1->winding) Error("face1 %d without winding", face1->num);
+ if (!face2->winding) Error("face2 %d without winding", face2->num);
+#endif //DEBUG
+ //
+ if (face1->faceflags != face2->faceflags) return false;
+ //NOTE: if the front or back area is zero this doesn't mean there's
+ //a real area. It means there's solid at that side of the face
+ //if both faces have the same front area
+ if (face1->frontarea == face2->frontarea)
+ {
+ //if both faces have the same back area
+ if (face1->backarea == face2->backarea)
+ {
+ //if the faces are in the same plane
+ if (face1->planenum == face2->planenum)
+ {
+ //if they have both a front and a back area (no solid on either side)
+ if (face1->frontarea && face1->backarea)
+ {
+ neww = MergeWindings(face1->winding, face2->winding,
+ mapplanes[face1->planenum].normal);
+ } //end if
+ else
+ {
+ //this function is to be found in l_poly.c
+ neww = TryMergeWinding(face1->winding, face2->winding,
+ mapplanes[face1->planenum].normal);
+ } //end else
+ if (neww)
+ {
+ FreeWinding(face1->winding);
+ face1->winding = neww;
+ if (face2->frontarea) AAS_RemoveFaceFromArea(face2, face2->frontarea);
+ if (face2->backarea) AAS_RemoveFaceFromArea(face2, face2->backarea);
+ AAS_FreeTmpFace(face2);
+ return true;
+ } //end if
+ } //end if
+ else if ((face1->planenum & ~1) == (face2->planenum & ~1))
+ {
+ Log_Write("face %d and %d, same front and back area but flipped planes\r\n",
+ face1->num, face2->num);
+ } //end if
+ } //end if
+ } //end if
+ return false;
+} //end of the function AAS_TryMergeFaces
+/*
+int AAS_TryMergeFaces(tmp_face_t *face1, tmp_face_t *face2)
+{
+ winding_t *neww;
+
+#ifdef DEBUG
+ if (!face1->winding) Error("face1 %d without winding", face1->num);
+ if (!face2->winding) Error("face2 %d without winding", face2->num);
+#endif //DEBUG
+ //if the faces are in the same plane
+ if ((face1->planenum & ~1) != (face2->planenum & ~1)) return false;
+// if (face1->planenum != face2->planenum) return false;
+ //NOTE: if the front or back area is zero this doesn't mean there's
+ //a real area. It means there's solid at that side of the face