aboutsummaryrefslogtreecommitdiffstats
path: root/code/bspc
diff options
context:
space:
mode:
Diffstat (limited to 'code/bspc')
-rwxr-xr-xcode/bspc/Conscript150
-rwxr-xr-xcode/bspc/Makefile228
-rwxr-xr-xcode/bspc/aas_areamerging.c780
-rwxr-xr-xcode/bspc/aas_areamerging.h48
-rwxr-xr-xcode/bspc/aas_cfg.c504
-rwxr-xr-xcode/bspc/aas_cfg.h146
-rwxr-xr-xcode/bspc/aas_create.c2284
-rwxr-xr-xcode/bspc/aas_create.h272
-rwxr-xr-xcode/bspc/aas_edgemelting.c216
-rwxr-xr-xcode/bspc/aas_edgemelting.h48
-rwxr-xr-xcode/bspc/aas_facemerging.c564
-rwxr-xr-xcode/bspc/aas_facemerging.h48
-rwxr-xr-xcode/bspc/aas_file.c1098
-rwxr-xr-xcode/bspc/aas_file.h50
-rwxr-xr-xcode/bspc/aas_gsubdiv.c1312
-rwxr-xr-xcode/bspc/aas_gsubdiv.h50
-rwxr-xr-xcode/bspc/aas_map.c1698
-rwxr-xr-xcode/bspc/aas_map.h46
-rwxr-xr-xcode/bspc/aas_prunenodes.c178
-rwxr-xr-xcode/bspc/aas_prunenodes.h48
-rwxr-xr-xcode/bspc/aas_store.c2164
-rwxr-xr-xcode/bspc/aas_store.h214
-rwxr-xr-xcode/bspc/aasfile.h504
-rwxr-xr-xcode/bspc/be_aas_bspc.c584
-rwxr-xr-xcode/bspc/be_aas_bspc.h46
-rwxr-xr-xcode/bspc/brushbsp.c3742
-rwxr-xr-xcode/bspc/bspc.c1982
-rwxr-xr-xcode/bspc/bspc.sln56
-rwxr-xr-xcode/bspc/bspc.vcproj2762
-rwxr-xr-xcode/bspc/cfgq3.c168
-rwxr-xr-xcode/bspc/csg.c2010
-rwxr-xr-xcode/bspc/faces.c1956
-rwxr-xr-xcode/bspc/gldraw.c464
-rwxr-xr-xcode/bspc/glfile.c298
-rwxr-xr-xcode/bspc/l_bsp_ent.c360
-rwxr-xr-xcode/bspc/l_bsp_ent.h116
-rwxr-xr-xcode/bspc/l_bsp_hl.c1776
-rwxr-xr-xcode/bspc/l_bsp_hl.h628
-rwxr-xr-xcode/bspc/l_bsp_q1.c1240
-rwxr-xr-xcode/bspc/l_bsp_q1.h550
-rwxr-xr-xcode/bspc/l_bsp_q2.c2268
-rwxr-xr-xcode/bspc/l_bsp_q2.h196
-rwxr-xr-xcode/bspc/l_bsp_q3.c1648
-rwxr-xr-xcode/bspc/l_bsp_q3.h162
-rwxr-xr-xcode/bspc/l_bsp_sin.c2372
-rwxr-xr-xcode/bspc/l_bsp_sin.h212
-rwxr-xr-xcode/bspc/l_cmd.c2460
-rwxr-xr-xcode/bspc/l_cmd.h314
-rwxr-xr-xcode/bspc/l_log.c430
-rwxr-xr-xcode/bspc/l_log.h84
-rwxr-xr-xcode/bspc/l_math.c578
-rwxr-xr-xcode/bspc/l_math.h186
-rwxr-xr-xcode/bspc/l_mem.c882
-rwxr-xr-xcode/bspc/l_mem.h102
-rwxr-xr-xcode/bspc/l_poly.c2822
-rwxr-xr-xcode/bspc/l_poly.h240
-rwxr-xr-xcode/bspc/l_qfiles.c1326
-rwxr-xr-xcode/bspc/l_qfiles.h182
-rwxr-xr-xcode/bspc/l_threads.c3020
-rwxr-xr-xcode/bspc/l_threads.h90
-rwxr-xr-xcode/bspc/l_utils.c518
-rwxr-xr-xcode/bspc/l_utils.h158
-rwxr-xr-xcode/bspc/lcc.mak122
-rwxr-xr-xcode/bspc/leakfile.c202
-rwxr-xr-xcode/bspc/linux-i386.mak218
-rwxr-xr-xcode/bspc/map.c2534
-rwxr-xr-xcode/bspc/map_hl.c2228
-rwxr-xr-xcode/bspc/map_q1.c2348
-rwxr-xr-xcode/bspc/map_q2.c2324
-rwxr-xr-xcode/bspc/map_q3.c1362
-rwxr-xr-xcode/bspc/map_sin.c2422
-rwxr-xr-xcode/bspc/nodraw.c94
-rwxr-xr-xcode/bspc/portals.c2594
-rwxr-xr-xcode/bspc/prtfile.c574
-rwxr-xr-xcode/bspc/q2files.h974
-rwxr-xr-xcode/bspc/q3files.h748
-rwxr-xr-xcode/bspc/qbsp.h954
-rwxr-xr-xcode/bspc/qfiles.h974
-rwxr-xr-xcode/bspc/sinfiles.h730
-rwxr-xr-xcode/bspc/tetrahedron.c2778
-rwxr-xr-xcode/bspc/tetrahedron.h48
-rwxr-xr-xcode/bspc/textures.c456
-rwxr-xr-xcode/bspc/tree.c566
-rwxr-xr-xcode/bspc/writebsp.c1190
84 files changed, 39039 insertions, 39039 deletions
diff --git a/code/bspc/Conscript b/code/bspc/Conscript
index 08487ab..264e7c7 100755
--- a/code/bspc/Conscript
+++ b/code/bspc/Conscript
@@ -1,75 +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';
+# 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';
diff --git a/code/bspc/Makefile b/code/bspc/Makefile
index 2f16169..b6d3b94 100755
--- a/code/bspc/Makefile
+++ b/code/bspc/Makefile
@@ -1,114 +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"
-#
-
+#
+# 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"
+#
+
diff --git a/code/bspc/aas_areamerging.c b/code/bspc/aas_areamerging.c
index c5f82d2..f9de65f 100755
--- a/code/bspc/aas_areamerging.c
+++ b/code/bspc/aas_areamerging.c
@@ -1,390 +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
+/*
+===========================================================================
+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
diff --git a/code/bspc/aas_areamerging.h b/code/bspc/aas_areamerging.h
index c0b39a4..14cb8ed 100755
--- a/code/bspc/aas_areamerging.h
+++ b/code/bspc/aas_areamerging.h
@@ -1,24 +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);
-
+/*
+===========================================================================
+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);
+
diff --git a/code/bspc/aas_cfg.c b/code/bspc/aas_cfg.c
index 3aeb569..b805176 100755
--- a/code/bspc/aas_cfg.c
+++ b/code/bspc/aas_cfg.c
@@ -1,252 +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
+/*
+===========================================================================
+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
diff --git a/code/bspc/aas_cfg.h b/code/bspc/aas_cfg.h
index 25537c6..a5db5a8 100755
--- a/code/bspc/aas_cfg.h
+++ b/code/bspc/aas_cfg.h
@@ -1,73 +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);
+/*
+===========================================================================
+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);
diff --git a/code/bspc/aas_create.c b/code/bspc/aas_create.c
index 914b25b..1705362 100755
--- a/code/bspc/aas_create.c
+++ b/code/bspc/aas_create.c
@@ -1,1142 +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
+/*
+===========================================================================
+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
diff --git a/code/bspc/aas_create.h b/code/bspc/aas_create.h
index cc5693c..7f41f02 100755
--- a/code/bspc/aas_create.h
+++ b/code/bspc/aas_create.h
@@ -1,136 +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);
+/*
+===========================================================================
+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);
diff --git a/code/bspc/aas_edgemelting.c b/code/bspc/aas_edgemelting.c
index e84f48b..e59f4f9 100755
--- a/code/bspc/aas_edgemelting.c
+++ b/code/bspc/aas_edgemelting.c
@@ -1,108 +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
-
+/*
+===========================================================================
+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
+
diff --git a/code/bspc/aas_edgemelting.h b/code/bspc/aas_edgemelting.h
index 4c03e97..a296cb6 100755
--- a/code/bspc/aas_edgemelting.h
+++ b/code/bspc/aas_edgemelting.h
@@ -1,24 +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);
-
+/*
+===========================================================================
+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);
+
diff --git a/code/bspc/aas_facemerging.c b/code/bspc/aas_facemerging.c
index bf170de..2fb2903 100755
--- a/code/bspc/aas_facemerging.c
+++ b/code/bspc/aas_facemerging.c
@@ -1,282 +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
- //if both faces have the same front area
- if (face1->frontarea != face2->frontarea ||
- face1->backarea != face2->backarea)
- {
- if (!face1->frontarea || !face1->backarea ||
- !face2->frontarea || !face2->backarea) return false;
- else if (face1->frontarea != face2->backarea ||
- face1->backarea != face2->frontarea) return false;
-// return false;
- } //end if
- //this function is to be found in l_poly.c
- neww = TryMergeWinding(face1->winding, face2->winding,
- mapplanes[face1->planenum].normal);
- if (!neww) return false;
- //
- FreeWinding(face1->winding);
- face1->winding = neww;
- //remove face2
- if (face2->frontarea)
- AAS_RemoveFaceFromArea(face2, &tmpaasworld.areas[face2->frontarea]);
- if (face2->backarea)
- AAS_RemoveFaceFromArea(face2, &tmpaasworld.areas[face2->backarea]);
- return true;
-} //end of the function AAS_TryMergeFaces*/
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_MergeAreaFaces(void)
-{
- int num_facemerges = 0;
- int side1, side2, restart;
- tmp_area_t *tmparea, *lasttmparea;
- tmp_face_t *face1, *face2;
-
- Log_Write("AAS_MergeAreaFaces\r\n");
- qprintf("%6d face merges", num_facemerges);
- //NOTE: first convex area is a dummy
- lasttmparea = tmpaasworld.areas;
- for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
- {
- restart = false;
- //
- if (tmparea->invalid) continue;
- //
- for (face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1])
- {
- side1 = face1->frontarea != tmparea;
- for (face2 = face1->next[side1]; face2; face2 = face2->next[side2])
- {
- side2 = face2->frontarea != tmparea;
- //if succesfully merged
- if (AAS_TryMergeFaces(face1, face2))
- {
- //start over again after merging two faces
- restart = true;
- num_facemerges++;
- qprintf("\r%6d", num_facemerges);
- AAS_CheckArea(tmparea);
- break;
- } //end if
- } //end for
- if (restart)
- {
- tmparea = lasttmparea;
- break;
- } //end if
- } //end for
- lasttmparea = tmparea;
- } //end for
- qprintf("\n");
- Log_Write("%6d face merges\r\n", num_facemerges);
-} //end of the function AAS_MergeAreaFaces
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_MergePlaneFaces(tmp_area_t *tmparea, int planenum)
-{
- tmp_face_t *face1, *face2, *nextface2;
- winding_t *neww;
- int side1, side2;
-
- for (face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1])
- {
- side1 = face1->frontarea != tmparea;
- if (face1->planenum != planenum) continue;
- //
- for (face2 = face1->next[side1]; face2; face2 = nextface2)
- {
- side2 = face2->frontarea != tmparea;
- nextface2 = face2->next[side2];
- //
- if ((face2->planenum & ~1) != (planenum & ~1)) continue;
- //
- neww = MergeWindings(face1->winding, face2->winding,
- mapplanes[face1->planenum].normal);
- 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);
- //
- nextface2 = face1->next[side1];
- } //end for
- } //end for
-} //end of the function AAS_MergePlaneFaces
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_CanMergePlaneFaces(tmp_area_t *tmparea, int planenum)
-{
- tmp_area_t *frontarea, *backarea;
- tmp_face_t *face1;
- int side1, merge, faceflags;
-
- frontarea = backarea = NULL;
- merge = false;
- for (face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1])
- {
- side1 = face1->frontarea != tmparea;
- if ((face1->planenum & ~1) != (planenum & ~1)) continue;
- if (!frontarea && !backarea)
- {
- frontarea = face1->frontarea;
- backarea = face1->backarea;
- faceflags = face1->faceflags;
- } //end if
- else
- {
- if (frontarea != face1->frontarea) return false;
- if (backarea != face1->backarea) return false;
- if (faceflags != face1->faceflags) return false;
- merge = true;
- } //end else
- } //end for
- return merge;
-} //end of the function AAS_CanMergePlaneFaces
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_MergeAreaPlaneFaces(void)
-{
- int num_facemerges = 0;
- int side1;
- tmp_area_t *tmparea, *nexttmparea;
- tmp_face_t *face1;
-
- Log_Write("AAS_MergePlaneFaces\r\n");
- qprintf("%6d plane face merges", num_facemerges);
- //NOTE: first convex area is a dummy
- for (tmparea = tmpaasworld.areas; tmparea; tmparea = nexttmparea)
- {
- nexttmparea = tmparea->l_next;
- //
- if (tmparea->invalid) continue;
- //
- for (face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1])
- {
- side1 = face1->frontarea != tmparea;
- //
- if (AAS_CanMergePlaneFaces(tmparea, face1->planenum))
- {
- AAS_MergePlaneFaces(tmparea, face1->planenum);
- nexttmparea = tmparea;
- num_facemerges++;
- qprintf("\r%6d", num_facemerges);
- break;
- } //end if
- } //end for
- } //end for
- qprintf("\n");
- Log_Write("%6d plane face merges\r\n", num_facemerges);
-} //end of the function AAS_MergeAreaPlaneFaces
+/*
+===========================================================================
+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
+ //if both faces have the same front area
+ if (face1->frontarea != face2->frontarea ||
+ face1->backarea != face2->backarea)
+ {
+ if (!face1->frontarea || !face1->backarea ||
+ !face2->frontarea || !face2->backarea) return false;
+ else if (face1->frontarea != face2->backarea ||
+ face1->backarea != face2->frontarea) return false;
+// return false;
+ } //end if
+ //this function is to be found in l_poly.c
+ neww = TryMergeWinding(face1->winding, face2->winding,
+ mapplanes[face1->planenum].normal);
+ if (!neww) return false;
+ //
+ FreeWinding(face1->winding);
+ face1->winding = neww;
+ //remove face2
+ if (face2->frontarea)
+ AAS_RemoveFaceFromArea(face2, &tmpaasworld.areas[face2->frontarea]);
+ if (face2->backarea)
+ AAS_RemoveFaceFromArea(face2, &tmpaasworld.areas[face2->backarea]);
+ return true;
+} //end of the function AAS_TryMergeFaces*/
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_MergeAreaFaces(void)
+{
+ int num_facemerges = 0;
+ int side1, side2, restart;
+ tmp_area_t *tmparea, *lasttmparea;
+ tmp_face_t *face1, *face2;
+
+ Log_Write("AAS_MergeAreaFaces\r\n");
+ qprintf("%6d face merges", num_facemerges);
+ //NOTE: first convex area is a dummy
+ lasttmparea = tmpaasworld.areas;
+ for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
+ {
+ restart = false;
+ //
+ if (tmparea->invalid) continue;
+ //
+ for (face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1])
+ {
+ side1 = face1->frontarea != tmparea;
+ for (face2 = face1->next[side1]; face2; face2 = face2->next[side2])
+ {
+ side2 = face2->frontarea != tmparea;
+ //if succesfully merged
+ if (AAS_TryMergeFaces(face1, face2))
+ {
+ //start over again after merging two faces
+ restart = true;
+ num_facemerges++;
+ qprintf("\r%6d", num_facemerges);
+ AAS_CheckArea(tmparea);
+ break;
+ } //end if
+ } //end for
+ if (restart)
+ {
+ tmparea = lasttmparea;
+ break;
+ } //end if
+ } //end for
+ lasttmparea = tmparea;
+ } //end for
+ qprintf("\n");
+ Log_Write("%6d face merges\r\n", num_facemerges);
+} //end of the function AAS_MergeAreaFaces
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_MergePlaneFaces(tmp_area_t *tmparea, int planenum)
+{
+ tmp_face_t *face1, *face2, *nextface2;
+ winding_t *neww;
+ int side1, side2;
+
+ for (face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1])
+ {
+ side1 = face1->frontarea != tmparea;
+ if (face1->planenum != planenum) continue;
+ //
+ for (face2 = face1->next[side1]; face2; face2 = nextface2)
+ {
+ side2 = face2->frontarea != tmparea;
+ nextface2 = face2->next[side2];
+ //
+ if ((face2->planenum & ~1) != (planenum & ~1)) continue;
+ //
+ neww = MergeWindings(face1->winding, face2->winding,
+ mapplanes[face1->planenum].normal);
+ 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);
+ //
+ nextface2 = face1->next[side1];
+ } //end for
+ } //end for
+} //end of the function AAS_MergePlaneFaces
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int AAS_CanMergePlaneFaces(tmp_area_t *tmparea, int planenum)
+{
+ tmp_area_t *frontarea, *backarea;
+ tmp_face_t *face1;
+ int side1, merge, faceflags;
+
+ frontarea = backarea = NULL;
+ merge = false;
+ for (face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1])
+ {
+ side1 = face1->frontarea != tmparea;
+ if ((face1->planenum & ~1) != (planenum & ~1)) continue;
+ if (!frontarea && !backarea)
+ {
+ frontarea = face1->frontarea;
+ backarea = face1->backarea;
+ faceflags = face1->faceflags;
+ } //end if
+ else
+ {
+ if (frontarea != face1->frontarea) return false;
+ if (backarea != face1->backarea) return false;
+ if (faceflags != face1->faceflags) return false;
+ merge = true;
+ } //end else
+ } //end for
+ return merge;
+} //end of the function AAS_CanMergePlaneFaces
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_MergeAreaPlaneFaces(void)
+{
+ int num_facemerges = 0;
+ int side1;
+ tmp_area_t *tmparea, *nexttmparea;
+ tmp_face_t *face1;
+
+ Log_Write("AAS_MergePlaneFaces\r\n");
+ qprintf("%6d plane face merges", num_facemerges);
+ //NOTE: first convex area is a dummy
+ for (tmparea = tmpaasworld.areas; tmparea; tmparea = nexttmparea)
+ {
+ nexttmparea = tmparea->l_next;
+ //
+ if (tmparea->invalid) continue;
+ //
+ for (face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1])
+ {
+ side1 = face1->frontarea != tmparea;
+ //
+ if (AAS_CanMergePlaneFaces(tmparea, face1->planenum))
+ {
+ AAS_MergePlaneFaces(tmparea, face1->planenum);
+ nexttmparea = tmparea;
+ num_facemerges++;
+ qprintf("\r%6d", num_facemerges);
+ break;
+ } //end if
+ } //end for
+ } //end for
+ qprintf("\n");
+ Log_Write("%6d plane face merges\r\n", num_facemerges);
+} //end of the function AAS_MergeAreaPlaneFaces
diff --git a/code/bspc/aas_facemerging.h b/code/bspc/aas_facemerging.h
index 5a81735..b2e02e5 100755
--- a/code/bspc/aas_facemerging.h
+++ b/code/bspc/aas_facemerging.h
@@ -1,24 +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_MergeAreaFaces(void);
-void AAS_MergeAreaPlaneFaces(void);
+/*
+===========================================================================
+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_MergeAreaFaces(void);
+void AAS_MergeAreaPlaneFaces(void);
diff --git a/code/bspc/aas_file.c b/code/bspc/aas_file.c
index 9f41639..9dc6b12 100755
--- a/code/bspc/aas_file.c
+++ b/code/bspc/aas_file.c
@@ -1,549 +1,549 @@
-/*
-===========================================================================
-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"
-
-#define AAS_Error Error
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_SwapAASData(void)
-{
- int i, j;
- //bounding boxes
- for (i = 0; i < aasworld.numbboxes; i++)
- {
- aasworld.bboxes[i].presencetype = LittleLong(aasworld.bboxes[i].presencetype);
- aasworld.bboxes[i].flags = LittleLong(aasworld.bboxes[i].flags);
- for (j = 0; j < 3; j++)
- {
- aasworld.bboxes[i].mins[j] = LittleLong(aasworld.bboxes[i].mins[j]);
- aasworld.bboxes[i].maxs[j] = LittleLong(aasworld.bboxes[i].maxs[j]);
- } //end for
- } //end for
- //vertexes
- for (i = 0; i < aasworld.numvertexes; i++)
- {
- for (j = 0; j < 3; j++)
- aasworld.vertexes[i][j] = LittleFloat(aasworld.vertexes[i][j]);
- } //end for
- //planes
- for (i = 0; i < aasworld.numplanes; i++)
- {
- for (j = 0; j < 3; j++)
- aasworld.planes[i].normal[j] = LittleFloat(aasworld.planes[i].normal[j]);
- aasworld.planes[i].dist = LittleFloat(aasworld.planes[i].dist);
- aasworld.planes[i].type = LittleLong(aasworld.planes[i].type);
- } //end for
- //edges
- for (i = 0; i < aasworld.numedges; i++)
- {
- aasworld.edges[i].v[0] = LittleLong(aasworld.edges[i].v[0]);
- aasworld.edges[i].v[1] = LittleLong(aasworld.edges[i].v[1]);
- } //end for
- //edgeindex
- for (i = 0; i < aasworld.edgeindexsize; i++)
- {
- aasworld.edgeindex[i] = LittleLong(aasworld.edgeindex[i]);
- } //end for
- //faces
- for (i = 0; i < aasworld.numfaces; i++)
- {
- aasworld.faces[i].planenum = LittleLong(aasworld.faces[i].planenum);
- aasworld.faces[i].faceflags = LittleLong(aasworld.faces[i].faceflags);
- aasworld.faces[i].numedges = LittleLong(aasworld.faces[i].numedges);
- aasworld.faces[i].firstedge = LittleLong(aasworld.faces[i].firstedge);
- aasworld.faces[i].frontarea = LittleLong(aasworld.faces[i].frontarea);
- aasworld.faces[i].backarea = LittleLong(aasworld.faces[i].backarea);
- } //end for
- //face index
- for (i = 0; i < aasworld.faceindexsize; i++)
- {
- aasworld.faceindex[i] = LittleLong(aasworld.faceindex[i]);
- } //end for
- //convex areas
- for (i = 0; i < aasworld.numareas; i++)
- {
- aasworld.areas[i].areanum = LittleLong(aasworld.areas[i].areanum);
- aasworld.areas[i].numfaces = LittleLong(aasworld.areas[i].numfaces);
- aasworld.areas[i].firstface = LittleLong(aasworld.areas[i].firstface);
- for (j = 0; j < 3; j++)
- {
- aasworld.areas[i].mins[j] = LittleFloat(aasworld.areas[i].mins[j]);
- aasworld.areas[i].maxs[j] = LittleFloat(aasworld.areas[i].maxs[j]);
- aasworld.areas[i].center[j] = LittleFloat(aasworld.areas[i].center[j]);
- } //end for
- } //end for
- //area settings
- for (i = 0; i < aasworld.numareasettings; i++)
- {
- aasworld.areasettings[i].contents = LittleLong(aasworld.areasettings[i].contents);
- aasworld.areasettings[i].areaflags = LittleLong(aasworld.areasettings[i].areaflags);
- aasworld.areasettings[i].presencetype = LittleLong(aasworld.areasettings[i].presencetype);
- aasworld.areasettings[i].cluster = LittleLong(aasworld.areasettings[i].cluster);
- aasworld.areasettings[i].clusterareanum = LittleLong(aasworld.areasettings[i].clusterareanum);
- aasworld.areasettings[i].numreachableareas = LittleLong(aasworld.areasettings[i].numreachableareas);
- aasworld.areasettings[i].firstreachablearea = LittleLong(aasworld.areasettings[i].firstreachablearea);
- } //end for
- //area reachability
- for (i = 0; i < aasworld.reachabilitysize; i++)
- {
- aasworld.reachability[i].areanum = LittleLong(aasworld.reachability[i].areanum);
- aasworld.reachability[i].facenum = LittleLong(aasworld.reachability[i].facenum);
- aasworld.reachability[i].edgenum = LittleLong(aasworld.reachability[i].edgenum);
- for (j = 0; j < 3; j++)
- {
- aasworld.reachability[i].start[j] = LittleFloat(aasworld.reachability[i].start[j]);
- aasworld.reachability[i].end[j] = LittleFloat(aasworld.reachability[i].end[j]);
- } //end for
- aasworld.reachability[i].traveltype = LittleLong(aasworld.reachability[i].traveltype);
- aasworld.reachability[i].traveltime = LittleShort(aasworld.reachability[i].traveltime);
- } //end for
- //nodes
- for (i = 0; i < aasworld.numnodes; i++)
- {
- aasworld.nodes[i].planenum = LittleLong(aasworld.nodes[i].planenum);
- aasworld.nodes[i].children[0] = LittleLong(aasworld.nodes[i].children[0]);
- aasworld.nodes[i].children[1] = LittleLong(aasworld.nodes[i].children[1]);
- } //end for
- //cluster portals
- for (i = 0; i < aasworld.numportals; i++)
- {
- aasworld.portals[i].areanum = LittleLong(aasworld.portals[i].areanum);
- aasworld.portals[i].frontcluster = LittleLong(aasworld.portals[i].frontcluster);
- aasworld.portals[i].backcluster = LittleLong(aasworld.portals[i].backcluster);
- aasworld.portals[i].clusterareanum[0] = LittleLong(aasworld.portals[i].clusterareanum[0]);
- aasworld.portals[i].clusterareanum[1] = LittleLong(aasworld.portals[i].clusterareanum[1]);
- } //end for
- //cluster portal index
- for (i = 0; i < aasworld.portalindexsize; i++)
- {
- aasworld.portalindex[i] = LittleLong(aasworld.portalindex[i]);
- } //end for
- //cluster
- for (i = 0; i < aasworld.numclusters; i++)
- {
- aasworld.clusters[i].numareas = LittleLong(aasworld.clusters[i].numareas);
- aasworld.clusters[i].numportals = LittleLong(aasworld.clusters[i].numportals);
- aasworld.clusters[i].firstportal = LittleLong(aasworld.clusters[i].firstportal);
- } //end for
-} //end of the function AAS_SwapAASData
-//===========================================================================
-// dump the current loaded aas file
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_DumpAASData(void)
-{
- /*
- if (aasworld.vertexes) FreeMemory(aasworld.vertexes);
- aasworld.vertexes = NULL;
- if (aasworld.planes) FreeMemory(aasworld.planes);
- aasworld.planes = NULL;
- if (aasworld.edges) FreeMemory(aasworld.edges);
- aasworld.edges = NULL;
- if (aasworld.edgeindex) FreeMemory(aasworld.edgeindex);
- aasworld.edgeindex = NULL;
- if (aasworld.faces) FreeMemory(aasworld.faces);
- aasworld.faces = NULL;
- if (aasworld.faceindex) FreeMemory(aasworld.faceindex);
- aasworld.faceindex = NULL;
- if (aasworld.areas) FreeMemory(aasworld.areas);
- aasworld.areas = NULL;
- if (aasworld.areasettings) FreeMemory(aasworld.areasettings);
- aasworld.areasettings = NULL;
- if (aasworld.reachability) FreeMemory(aasworld.reachability);
- aasworld.reachability = NULL;
- */
- aasworld.loaded = false;
-} //end of the function AAS_DumpAASData
-//===========================================================================
-// allocate memory and read a lump of a AAS file
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-char *AAS_LoadAASLump(FILE *fp, int offset, int length, void *buf)
-{
- if (!length)
- {
- printf("lump size 0\n");
- return buf;
- } //end if
- //seek to the data
- if (fseek(fp, offset, SEEK_SET))
- {
- AAS_Error("can't seek to lump\n");
- AAS_DumpAASData();
- fclose(fp);
- return 0;
- } //end if
- //allocate memory
- if (!buf) buf = (void *) GetClearedMemory(length);
- //read the data
- if (fread((char *) buf, 1, length, fp) != length)
- {
- AAS_Error("can't read lump\n");
- FreeMemory(buf);
- AAS_DumpAASData();
- fclose(fp);
- return NULL;
- } //end if
- return buf;
-} //end of the function AAS_LoadAASLump
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_DData(unsigned char *data, int size)
-{
- int i;
-
- for (i = 0; i < size; i++)
- {
- data[i] ^= (unsigned char) i * 119;
- } //end for
-} //end of the function AAS_DData
-//===========================================================================
-// load an aas file
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean AAS_LoadAASFile(char *filename, int fpoffset, int fplength)
-{
- FILE *fp;
- aas_header_t header;
- int offset, length;
-
- //dump current loaded aas file
- AAS_DumpAASData();
- //open the file
- fp = fopen(filename, "rb");
- if (!fp)
- {
- AAS_Error("can't open %s\n", filename);
- return false;
- } //end if
- //seek to the correct position (in the pak file)
- if (fseek(fp, fpoffset, SEEK_SET))
- {
- AAS_Error("can't seek to file %s\n");
- fclose(fp);
- return false;
- } //end if
- //read the header
- if (fread(&header, sizeof(aas_header_t), 1, fp) != 1)
- {
- AAS_Error("can't read header of file %s\n", filename);
- fclose(fp);
- return false;
- } //end if
- //check header identification
- header.ident = LittleLong(header.ident);
- if (header.ident != AASID)
- {
- AAS_Error("%s is not an AAS file\n", filename);
- fclose(fp);
- return false;
- } //end if
- //check the version
- header.version = LittleLong(header.version);
- if (header.version != AASVERSION_OLD && header.version != AASVERSION)
- {
- AAS_Error("%s is version %i, not %i\n", filename, header.version, AASVERSION);
- fclose(fp);
- return false;
- } //end if
- //
- if (header.version == AASVERSION)
- {
- AAS_DData((unsigned char *) &header + 8, sizeof(aas_header_t) - 8);
- } //end if
- aasworld.bspchecksum = LittleLong(header.bspchecksum);
- //load the lumps:
- //bounding boxes
- offset = fpoffset + LittleLong(header.lumps[AASLUMP_BBOXES].fileofs);
- length = LittleLong(header.lumps[AASLUMP_BBOXES].filelen);
- aasworld.bboxes = (aas_bbox_t *) AAS_LoadAASLump(fp, offset, length, aasworld.bboxes);
- if (!aasworld.bboxes) return false;
- aasworld.numbboxes = length / sizeof(aas_bbox_t);
- //vertexes
- offset = fpoffset + LittleLong(header.lumps[AASLUMP_VERTEXES].fileofs);
- length = LittleLong(header.lumps[AASLUMP_VERTEXES].filelen);
- aasworld.vertexes = (aas_vertex_t *) AAS_LoadAASLump(fp, offset, length, aasworld.vertexes);
- if (!aasworld.vertexes) return false;
- aasworld.numvertexes = length / sizeof(aas_vertex_t);
- //planes
- offset = fpoffset + LittleLong(header.lumps[AASLUMP_PLANES].fileofs);
- length = LittleLong(header.lumps[AASLUMP_PLANES].filelen);
- aasworld.planes = (aas_plane_t *) AAS_LoadAASLump(fp, offset, length, aasworld.planes);
- if (!aasworld.planes) return false;
- aasworld.numplanes = length / sizeof(aas_plane_t);
- //edges
- offset = fpoffset + LittleLong(header.lumps[AASLUMP_EDGES].fileofs);
- length = LittleLong(header.lumps[AASLUMP_EDGES].filelen);
- aasworld.edges = (aas_edge_t *) AAS_LoadAASLump(fp, offset, length, aasworld.edges);
- if (!aasworld.edges) return false;
- aasworld.numedges = length / sizeof(aas_edge_t);
- //edgeindex
- offset = fpoffset + LittleLong(header.lumps[AASLUMP_EDGEINDEX].fileofs);
- length = LittleLong(header.lumps[AASLUMP_EDGEINDEX].filelen);
- aasworld.edgeindex = (aas_edgeindex_t *) AAS_LoadAASLump(fp, offset, length, aasworld.edgeindex);
- if (!aasworld.edgeindex) return false;
- aasworld.edgeindexsize = length / sizeof(aas_edgeindex_t);
- //faces
- offset = fpoffset + LittleLong(header.lumps[AASLUMP_FACES].fileofs);
- length = LittleLong(header.lumps[AASLUMP_FACES].filelen);
- aasworld.faces = (aas_face_t *) AAS_LoadAASLump(fp, offset, length, aasworld.faces);
- if (!aasworld.faces) return false;
- aasworld.numfaces = length / sizeof(aas_face_t);
- //faceindex
- offset = fpoffset + LittleLong(header.lumps[AASLUMP_FACEINDEX].fileofs);
- length = LittleLong(header.lumps[AASLUMP_FACEINDEX].filelen);
- aasworld.faceindex = (aas_faceindex_t *) AAS_LoadAASLump(fp, offset, length, aasworld.faceindex);
- if (!aasworld.faceindex) return false;
- aasworld.faceindexsize = length / sizeof(int);
- //convex areas
- offset = fpoffset + LittleLong(header.lumps[AASLUMP_AREAS].fileofs);
- length = LittleLong(header.lumps[AASLUMP_AREAS].filelen);
- aasworld.areas = (aas_area_t *) AAS_LoadAASLump(fp, offset, length, aasworld.areas);
- if (!aasworld.areas) return false;
- aasworld.numareas = length / sizeof(aas_area_t);
- //area settings
- offset = fpoffset + LittleLong(header.lumps[AASLUMP_AREASETTINGS].fileofs);
- length = LittleLong(header.lumps[AASLUMP_AREASETTINGS].filelen);
- aasworld.areasettings = (aas_areasettings_t *) AAS_LoadAASLump(fp, offset, length, aasworld.areasettings);
- if (!aasworld.areasettings) return false;
- aasworld.numareasettings = length / sizeof(aas_areasettings_t);
- //reachability list
- offset = fpoffset + LittleLong(header.lumps[AASLUMP_REACHABILITY].fileofs);
- length = LittleLong(header.lumps[AASLUMP_REACHABILITY].filelen);
- aasworld.reachability = (aas_reachability_t *) AAS_LoadAASLump(fp, offset, length, aasworld.reachability);
- if (length && !aasworld.reachability) return false;
- aasworld.reachabilitysize = length / sizeof(aas_reachability_t);
- //nodes
- offset = fpoffset + LittleLong(header.lumps[AASLUMP_NODES].fileofs);
- length = LittleLong(header.lumps[AASLUMP_NODES].filelen);
- aasworld.nodes = (aas_node_t *) AAS_LoadAASLump(fp, offset, length, aasworld.nodes);
- if (!aasworld.nodes) return false;
- aasworld.numnodes = length / sizeof(aas_node_t);
- //cluster portals
- offset = fpoffset + LittleLong(header.lumps[AASLUMP_PORTALS].fileofs);
- length = LittleLong(header.lumps[AASLUMP_PORTALS].filelen);
- aasworld.portals = (aas_portal_t *) AAS_LoadAASLump(fp, offset, length, aasworld.portals);
- if (length && !aasworld.portals) return false;
- aasworld.numportals = length / sizeof(aas_portal_t);
- //cluster portal index
- offset = fpoffset + LittleLong(header.lumps[AASLUMP_PORTALINDEX].fileofs);
- length = LittleLong(header.lumps[AASLUMP_PORTALINDEX].filelen);
- aasworld.portalindex = (aas_portalindex_t *) AAS_LoadAASLump(fp, offset, length, aasworld.portalindex);
- if (length && !aasworld.portalindex) return false;
- aasworld.portalindexsize = length / sizeof(aas_portalindex_t);
- //clusters
- offset = fpoffset + LittleLong(header.lumps[AASLUMP_CLUSTERS].fileofs);
- length = LittleLong(header.lumps[AASLUMP_CLUSTERS].filelen);
- aasworld.clusters = (aas_cluster_t *) AAS_LoadAASLump(fp, offset, length, aasworld.clusters);
- if (length && !aasworld.clusters) return false;
- aasworld.numclusters = length / sizeof(aas_cluster_t);
- //swap everything
- AAS_SwapAASData();
- //aas file is loaded
- aasworld.loaded = true;
- //close the file
- fclose(fp);
- return true;
-} //end of the function AAS_LoadAASFile
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_WriteAASLump(FILE *fp, aas_header_t *h, int lumpnum, void *data, int length)
-{
- aas_lump_t *lump;
-
- lump = &h->lumps[lumpnum];
-
- lump->fileofs = LittleLong(ftell(fp));
- lump->filelen = LittleLong(length);
-
- if (length > 0)
- {
- if (fwrite(data, length, 1, fp) < 1)
- {
- Log_Print("error writing lump %s\n", lumpnum);
- fclose(fp);
- return false;
- } //end if
- } //end if
- return true;
-} //end of the function AAS_WriteAASLump
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ShowNumReachabilities(int tt, char *name)
-{
- int i, num;
-
- num = 0;
- for (i = 0; i < aasworld.reachabilitysize; i++)
- {
- if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == tt)
- num++;
- } //end for
- Log_Print("%6d %s\n", num, name);
-} //end of the function AAS_ShowNumReachabilities
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ShowTotals(void)
-{
- Log_Print("numvertexes = %d\r\n", aasworld.numvertexes);
- Log_Print("numplanes = %d\r\n", aasworld.numplanes);
- Log_Print("numedges = %d\r\n", aasworld.numedges);
- Log_Print("edgeindexsize = %d\r\n", aasworld.edgeindexsize);
- Log_Print("numfaces = %d\r\n", aasworld.numfaces);
- Log_Print("faceindexsize = %d\r\n", aasworld.faceindexsize);
- Log_Print("numareas = %d\r\n", aasworld.numareas);
- Log_Print("numareasettings = %d\r\n", aasworld.numareasettings);
- Log_Print("reachabilitysize = %d\r\n", aasworld.reachabilitysize);
- Log_Print("numnodes = %d\r\n", aasworld.numnodes);
- Log_Print("numportals = %d\r\n", aasworld.numportals);
- Log_Print("portalindexsize = %d\r\n", aasworld.portalindexsize);
- Log_Print("numclusters = %d\r\n", aasworld.numclusters);
- AAS_ShowNumReachabilities(TRAVEL_WALK, "walk");
- AAS_ShowNumReachabilities(TRAVEL_CROUCH, "crouch");
- AAS_ShowNumReachabilities(TRAVEL_BARRIERJUMP, "barrier jump");
- AAS_ShowNumReachabilities(TRAVEL_JUMP, "jump");
- AAS_ShowNumReachabilities(TRAVEL_LADDER, "ladder");
- AAS_ShowNumReachabilities(TRAVEL_WALKOFFLEDGE, "walk off ledge");
- AAS_ShowNumReachabilities(TRAVEL_SWIM, "swim");
- AAS_ShowNumReachabilities(TRAVEL_WATERJUMP, "water jump");
- AAS_ShowNumReachabilities(TRAVEL_TELEPORT, "teleport");
- AAS_ShowNumReachabilities(TRAVEL_ELEVATOR, "elevator");
- AAS_ShowNumReachabilities(TRAVEL_ROCKETJUMP, "rocket jump");
- AAS_ShowNumReachabilities(TRAVEL_BFGJUMP, "bfg jump");
- AAS_ShowNumReachabilities(TRAVEL_GRAPPLEHOOK, "grapple hook");
- AAS_ShowNumReachabilities(TRAVEL_DOUBLEJUMP, "double jump");
- AAS_ShowNumReachabilities(TRAVEL_RAMPJUMP, "ramp jump");
- AAS_ShowNumReachabilities(TRAVEL_STRAFEJUMP, "strafe jump");
- AAS_ShowNumReachabilities(TRAVEL_JUMPPAD, "jump pad");
- AAS_ShowNumReachabilities(TRAVEL_FUNCBOB, "func bob");
-} //end of the function AAS_ShowTotals
-//===========================================================================
-// aas data is useless after writing to file because it is byte swapped
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean AAS_WriteAASFile(char *filename)
-{
- aas_header_t header;
- FILE *fp;
-
- Log_Print("writing %s\n", filename);
- AAS_ShowTotals();
- //swap the aas data
- AAS_SwapAASData();
- //initialize the file header
- memset(&header, 0, sizeof(aas_header_t));
- header.ident = LittleLong(AASID);
- header.version = LittleLong(AASVERSION);
- header.bspchecksum = LittleLong(aasworld.bspchecksum);
- //open a new file
- fp = fopen(filename, "wb");
- if (!fp)
- {
- Log_Print("error opening %s\n", filename);
- return false;
- } //end if
- //write the header
- if (fwrite(&header, sizeof(aas_header_t), 1, fp) < 1)
- {
- fclose(fp);
- return false;
- } //end if
- //add the data lumps to the file
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_BBOXES, aasworld.bboxes,
- aasworld.numbboxes * sizeof(aas_bbox_t))) return false;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_VERTEXES, aasworld.vertexes,
- aasworld.numvertexes * sizeof(aas_vertex_t))) return false;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_PLANES, aasworld.planes,
- aasworld.numplanes * sizeof(aas_plane_t))) return false;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_EDGES, aasworld.edges,
- aasworld.numedges * sizeof(aas_edge_t))) return false;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_EDGEINDEX, aasworld.edgeindex,
- aasworld.edgeindexsize * sizeof(aas_edgeindex_t))) return false;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_FACES, aasworld.faces,
- aasworld.numfaces * sizeof(aas_face_t))) return false;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_FACEINDEX, aasworld.faceindex,
- aasworld.faceindexsize * sizeof(aas_faceindex_t))) return false;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_AREAS, aasworld.areas,
- aasworld.numareas * sizeof(aas_area_t))) return false;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_AREASETTINGS, aasworld.areasettings,
- aasworld.numareasettings * sizeof(aas_areasettings_t))) return false;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_REACHABILITY, aasworld.reachability,
- aasworld.reachabilitysize * sizeof(aas_reachability_t))) return false;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_NODES, aasworld.nodes,
- aasworld.numnodes * sizeof(aas_node_t))) return false;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_PORTALS, aasworld.portals,
- aasworld.numportals * sizeof(aas_portal_t))) return false;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_PORTALINDEX, aasworld.portalindex,
- aasworld.portalindexsize * sizeof(aas_portalindex_t))) return false;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_CLUSTERS, aasworld.clusters,
- aasworld.numclusters * sizeof(aas_cluster_t))) return false;
- //rewrite the header with the added lumps
- fseek(fp, 0, SEEK_SET);
- AAS_DData((unsigned char *) &header + 8, sizeof(aas_header_t) - 8);
- if (fwrite(&header, sizeof(aas_header_t), 1, fp) < 1)
- {
- fclose(fp);
- return false;
- } //end if
- //close the file
- fclose(fp);
- return true;
-} //end of the function AAS_WriteAASFile
-
+/*
+===========================================================================
+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"
+
+#define AAS_Error Error
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_SwapAASData(void)
+{
+ int i, j;
+ //bounding boxes
+ for (i = 0; i < aasworld.numbboxes; i++)
+ {
+ aasworld.bboxes[i].presencetype = LittleLong(aasworld.bboxes[i].presencetype);
+ aasworld.bboxes[i].flags = LittleLong(aasworld.bboxes[i].flags);
+ for (j = 0; j < 3; j++)
+ {
+ aasworld.bboxes[i].mins[j] = LittleLong(aasworld.bboxes[i].mins[j]);
+ aasworld.bboxes[i].maxs[j] = LittleLong(aasworld.bboxes[i].maxs[j]);
+ } //end for
+ } //end for
+ //vertexes
+ for (i = 0; i < aasworld.numvertexes; i++)
+ {
+ for (j = 0; j < 3; j++)
+ aasworld.vertexes[i][j] = LittleFloat(aasworld.vertexes[i][j]);
+ } //end for
+ //planes
+ for (i = 0; i < aasworld.numplanes; i++)
+ {
+ for (j = 0; j < 3; j++)
+ aasworld.planes[i].normal[j] = LittleFloat(aasworld.planes[i].normal[j]);
+ aasworld.planes[i].dist = LittleFloat(aasworld.planes[i].dist);
+ aasworld.planes[i].type = LittleLong(aasworld.planes[i].type);
+ } //end for
+ //edges
+ for (i = 0; i < aasworld.numedges; i++)
+ {
+ aasworld.edges[i].v[0] = LittleLong(aasworld.edges[i].v[0]);
+ aasworld.edges[i].v[1] = LittleLong(aasworld.edges[i].v[1]);
+ } //end for
+ //edgeindex
+ for (i = 0; i < aasworld.edgeindexsize; i++)
+ {
+ aasworld.edgeindex[i] = LittleLong(aasworld.edgeindex[i]);
+ } //end for
+ //faces
+ for (i = 0; i < aasworld.numfaces; i++)
+ {
+ aasworld.faces[i].planenum = LittleLong(aasworld.faces[i].planenum);
+ aasworld.faces[i].faceflags = LittleLong(aasworld.faces[i].faceflags);
+ aasworld.faces[i].numedges = LittleLong(aasworld.faces[i].numedges);
+ aasworld.faces[i].firstedge = LittleLong(aasworld.faces[i].firstedge);
+ aasworld.faces[i].frontarea = LittleLong(aasworld.faces[i].frontarea);
+ aasworld.faces[i].backarea = LittleLong(aasworld.faces[i].backarea);
+ } //end for
+ //face index
+ for (i = 0; i < aasworld.faceindexsize; i++)
+ {
+ aasworld.faceindex[i] = LittleLong(aasworld.faceindex[i]);
+ } //end for
+ //convex areas
+ for (i = 0; i < aasworld.numareas; i++)
+ {
+ aasworld.areas[i].areanum = LittleLong(aasworld.areas[i].areanum);
+ aasworld.areas[i].numfaces = LittleLong(aasworld.areas[i].numfaces);
+ aasworld.areas[i].firstface = LittleLong(aasworld.areas[i].firstface);
+ for (j = 0; j < 3; j++)
+ {
+ aasworld.areas[i].mins[j] = LittleFloat(aasworld.areas[i].mins[j]);
+ aasworld.areas[i].maxs[j] = LittleFloat(aasworld.areas[i].maxs[j]);
+ aasworld.areas[i].center[j] = LittleFloat(aasworld.areas[i].center[j]);
+ } //end for
+ } //end for
+ //area settings
+ for (i = 0; i < aasworld.numareasettings; i++)
+ {
+ aasworld.areasettings[i].contents = LittleLong(aasworld.areasettings[i].contents);
+ aasworld.areasettings[i].areaflags = LittleLong(aasworld.areasettings[i].areaflags);
+ aasworld.areasettings[i].presencetype = LittleLong(aasworld.areasettings[i].presencetype);
+ aasworld.areasettings[i].cluster = LittleLong(aasworld.areasettings[i].cluster);
+ aasworld.areasettings[i].clusterareanum = LittleLong(aasworld.areasettings[i].clusterareanum);
+ aasworld.areasettings[i].numreachableareas = LittleLong(aasworld.areasettings[i].numreachableareas);
+ aasworld.areasettings[i].firstreachablearea = LittleLong(aasworld.areasettings[i].firstreachablearea);
+ } //end for
+ //area reachability
+ for (i = 0; i < aasworld.reachabilitysize; i++)
+ {
+ aasworld.reachability[i].areanum = LittleLong(aasworld.reachability[i].areanum);
+ aasworld.reachability[i].facenum = LittleLong(aasworld.reachability[i].facenum);
+ aasworld.reachability[i].edgenum = LittleLong(aasworld.reachability[i].edgenum);
+ for (j = 0; j < 3; j++)
+ {
+ aasworld.reachability[i].start[j] = LittleFloat(aasworld.reachability[i].start[j]);
+ aasworld.reachability[i].end[j] = LittleFloat(aasworld.reachability[i].end[j]);
+ } //end for
+ aasworld.reachability[i].traveltype = LittleLong(aasworld.reachability[i].traveltype);
+ aasworld.reachability[i].traveltime = LittleShort(aasworld.reachability[i].traveltime);
+ } //end for
+ //nodes
+ for (i = 0; i < aasworld.numnodes; i++)
+ {
+ aasworld.nodes[i].planenum = LittleLong(aasworld.nodes[i].planenum);
+ aasworld.nodes[i].children[0] = LittleLong(aasworld.nodes[i].children[0]);
+ aasworld.nodes[i].children[1] = LittleLong(aasworld.nodes[i].children[1]);
+ } //end for
+ //cluster portals
+ for (i = 0; i < aasworld.numportals; i++)
+ {
+ aasworld.portals[i].areanum = LittleLong(aasworld.portals[i].areanum);
+ aasworld.portals[i].frontcluster = LittleLong(aasworld.portals[i].frontcluster);
+ aasworld.portals[i].backcluster = LittleLong(aasworld.portals[i].backcluster);
+ aasworld.portals[i].clusterareanum[0] = LittleLong(aasworld.portals[i].clusterareanum[0]);
+ aasworld.portals[i].clusterareanum[1] = LittleLong(aasworld.portals[i].clusterareanum[1]);
+ } //end for
+ //cluster portal index
+ for (i = 0; i < aasworld.portalindexsize; i++)
+ {
+ aasworld.portalindex[i] = LittleLong(aasworld.portalindex[i]);
+ } //end for
+ //cluster
+ for (i = 0; i < aasworld.numclusters; i++)
+ {
+ aasworld.clusters[i].numareas = LittleLong(aasworld.clusters[i].numareas);
+ aasworld.clusters[i].numportals = LittleLong(aasworld.clusters[i].numportals);
+ aasworld.clusters[i].firstportal = LittleLong(aasworld.clusters[i].firstportal);
+ } //end for
+} //end of the function AAS_SwapAASData
+//===========================================================================
+// dump the current loaded aas file
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_DumpAASData(void)
+{
+ /*
+ if (aasworld.vertexes) FreeMemory(aasworld.vertexes);
+ aasworld.vertexes = NULL;
+ if (aasworld.planes) FreeMemory(aasworld.planes);
+ aasworld.planes = NULL;
+ if (aasworld.edges) FreeMemory(aasworld.edges);
+ aasworld.edges = NULL;
+ if (aasworld.edgeindex) FreeMemory(aasworld.edgeindex);
+ aasworld.edgeindex = NULL;
+ if (aasworld.faces) FreeMemory(aasworld.faces);
+ aasworld.faces = NULL;
+ if (aasworld.faceindex) FreeMemory(aasworld.faceindex);
+ aasworld.faceindex = NULL;
+ if (aasworld.areas) FreeMemory(aasworld.areas);
+ aasworld.areas = NULL;
+ if (aasworld.areasettings) FreeMemory(aasworld.areasettings);
+ aasworld.areasettings = NULL;
+ if (aasworld.reachability) FreeMemory(aasworld.reachability);
+ aasworld.reachability = NULL;
+ */
+ aasworld.loaded = false;
+} //end of the function AAS_DumpAASData
+//===========================================================================
+// allocate memory and read a lump of a AAS file
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+char *AAS_LoadAASLump(FILE *fp, int offset, int length, void *buf)
+{
+ if (!length)
+ {
+ printf("lump size 0\n");
+ return buf;
+ } //end if
+ //seek to the data
+ if (fseek(fp, offset, SEEK_SET))
+ {
+ AAS_Error("can't seek to lump\n");
+ AAS_DumpAASData();
+ fclose(fp);
+ return 0;
+ } //end if
+ //allocate memory
+ if (!buf) buf = (void *) GetClearedMemory(length);
+ //read the data
+ if (fread((char *) buf, 1, length, fp) != length)
+ {
+ AAS_Error("can't read lump\n");
+ FreeMemory(buf);
+ AAS_DumpAASData();
+ fclose(fp);
+ return NULL;
+ } //end if
+ return buf;
+} //end of the function AAS_LoadAASLump
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_DData(unsigned char *data, int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++)
+ {
+ data[i] ^= (unsigned char) i * 119;
+ } //end for
+} //end of the function AAS_DData
+//===========================================================================
+// load an aas file
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+qboolean AAS_LoadAASFile(char *filename, int fpoffset, int fplength)
+{
+ FILE *fp;
+ aas_header_t header;
+ int offset, length;
+
+ //dump current loaded aas file
+ AAS_DumpAASData();
+ //open the file
+ fp = fopen(filename, "rb");
+ if (!fp)
+ {
+ AAS_Error("can't open %s\n", filename);
+ return false;
+ } //end if
+ //seek to the correct position (in the pak file)
+ if (fseek(fp, fpoffset, SEEK_SET))
+ {
+ AAS_Error("can't seek to file %s\n");
+ fclose(fp);
+ return false;
+ } //end if
+ //read the header
+ if (fread(&header, sizeof(aas_header_t), 1, fp) != 1)
+ {
+ AAS_Error("can't read header of file %s\n", filename);
+ fclose(fp);
+ return false;
+ } //end if
+ //check header identification
+ header.ident = LittleLong(header.ident);
+ if (header.ident != AASID)
+ {
+ AAS_Error("%s is not an AAS file\n", filename);
+ fclose(fp);
+ return false;
+ } //end if
+ //check the version
+ header.version = LittleLong(header.version);
+ if (header.version != AASVERSION_OLD && header.version != AASVERSION)
+ {
+ AAS_Error("%s is version %i, not %i\n", filename, header.version, AASVERSION);
+ fclose(fp);
+ return false;
+ } //end if
+ //
+ if (header.version == AASVERSION)
+ {
+ AAS_DData((unsigned char *) &header + 8, sizeof(aas_header_t) - 8);
+ } //end if
+ aasworld.bspchecksum = LittleLong(header.bspchecksum);
+ //load the lumps:
+ //bounding boxes
+ offset = fpoffset + LittleLong(header.lumps[AASLUMP_BBOXES].fileofs);
+ length = LittleLong(header.lumps[AASLUMP_BBOXES].filelen);
+ aasworld.bboxes = (aas_bbox_t *) AAS_LoadAASLump(fp, offset, length, aasworld.bboxes);
+ if (!aasworld.bboxes) return false;
+ aasworld.numbboxes = length / sizeof(aas_bbox_t);
+ //vertexes
+ offset = fpoffset + LittleLong(header.lumps[AASLUMP_VERTEXES].fileofs);
+ length = LittleLong(header.lumps[AASLUMP_VERTEXES].filelen);
+ aasworld.vertexes = (aas_vertex_t *) AAS_LoadAASLump(fp, offset, length, aasworld.vertexes);
+ if (!aasworld.vertexes) return false;
+ aasworld.numvertexes = length / sizeof(aas_vertex_t);
+ //planes
+ offset = fpoffset + LittleLong(header.lumps[AASLUMP_PLANES].fileofs);
+ length = LittleLong(header.lumps[AASLUMP_PLANES].filelen);
+ aasworld.planes = (aas_plane_t *) AAS_LoadAASLump(fp, offset, length, aasworld.planes);
+ if (!aasworld.planes) return false;
+ aasworld.numplanes = length / sizeof(aas_plane_t);
+ //edges
+ offset = fpoffset + LittleLong(header.lumps[AASLUMP_EDGES].fileofs);
+ length = LittleLong(header.lumps[AASLUMP_EDGES].filelen);
+ aasworld.edges = (aas_edge_t *) AAS_LoadAASLump(fp, offset, length, aasworld.edges);
+ if (!aasworld.edges) return false;
+ aasworld.numedges = length / sizeof(aas_edge_t);
+ //edgeindex
+ offset = fpoffset + LittleLong(header.lumps[AASLUMP_EDGEINDEX].fileofs);
+ length = LittleLong(header.lumps[AASLUMP_EDGEINDEX].filelen);
+ aasworld.edgeindex = (aas_edgeindex_t *) AAS_LoadAASLump(fp, offset, length, aasworld.edgeindex);
+ if (!aasworld.edgeindex) return false;
+ aasworld.edgeindexsize = length / sizeof(aas_edgeindex_t);
+ //faces
+ offset = fpoffset + LittleLong(header.lumps[AASLUMP_FACES].fileofs);
+ length = LittleLong(header.lumps[AASLUMP_FACES].filelen);
+ aasworld.faces = (aas_face_t *) AAS_LoadAASLump(fp, offset, length, aasworld.faces);
+ if (!aasworld.faces) return false;
+ aasworld.numfaces = length / sizeof(aas_face_t);
+ //faceindex
+ offset = fpoffset + LittleLong(header.lumps[AASLUMP_FACEINDEX].fileofs);
+ length = LittleLong(header.lumps[AASLUMP_FACEINDEX].filelen);
+ aasworld.faceindex = (aas_faceindex_t *) AAS_LoadAASLump(fp, offset, length, aasworld.faceindex);
+ if (!aasworld.faceindex) return false;
+ aasworld.faceindexsize = length / sizeof(int);
+ //convex areas
+ offset = fpoffset + LittleLong(header.lumps[AASLUMP_AREAS].fileofs);
+ length = LittleLong(header.lumps[AASLUMP_AREAS].filelen);
+ aasworld.areas = (aas_area_t *) AAS_LoadAASLump(fp, offset, length, aasworld.areas);
+ if (!aasworld.areas) return false;
+ aasworld.numareas = length / sizeof(aas_area_t);
+ //area settings
+ offset = fpoffset + LittleLong(header.lumps[AASLUMP_AREASETTINGS].fileofs);
+ length = LittleLong(header.lumps[AASLUMP_AREASETTINGS].filelen);
+ aasworld.areasettings = (aas_areasettings_t *) AAS_LoadAASLump(fp, offset, length, aasworld.areasettings);
+ if (!aasworld.areasettings) return false;
+ aasworld.numareasettings = length / sizeof(aas_areasettings_t);
+ //reachability list
+ offset = fpoffset + LittleLong(header.lumps[AASLUMP_REACHABILITY].fileofs);
+ length = LittleLong(header.lumps[AASLUMP_REACHABILITY].filelen);
+ aasworld.reachability = (aas_reachability_t *) AAS_LoadAASLump(fp, offset, length, aasworld.reachability);
+ if (length && !aasworld.reachability) return false;
+ aasworld.reachabilitysize = length / sizeof(aas_reachability_t);
+ //nodes
+ offset = fpoffset + LittleLong(header.lumps[AASLUMP_NODES].fileofs);
+ length = LittleLong(header.lumps[AASLUMP_NODES].filelen);
+ aasworld.nodes = (aas_node_t *) AAS_LoadAASLump(fp, offset, length, aasworld.nodes);
+ if (!aasworld.nodes) return false;
+ aasworld.numnodes = length / sizeof(aas_node_t);
+ //cluster portals
+ offset = fpoffset + LittleLong(header.lumps[AASLUMP_PORTALS].fileofs);
+ length = LittleLong(header.lumps[AASLUMP_PORTALS].filelen);
+ aasworld.portals = (aas_portal_t *) AAS_LoadAASLump(fp, offset, length, aasworld.portals);
+ if (length && !aasworld.portals) return false;
+ aasworld.numportals = length / sizeof(aas_portal_t);
+ //cluster portal index
+ offset = fpoffset + LittleLong(header.lumps[AASLUMP_PORTALINDEX].fileofs);
+ length = LittleLong(header.lumps[AASLUMP_PORTALINDEX].filelen);
+ aasworld.portalindex = (aas_portalindex_t *) AAS_LoadAASLump(fp, offset, length, aasworld.portalindex);
+ if (length && !aasworld.portalindex) return false;
+ aasworld.portalindexsize = length / sizeof(aas_portalindex_t);
+ //clusters
+ offset = fpoffset + LittleLong(header.lumps[AASLUMP_CLUSTERS].fileofs);
+ length = LittleLong(header.lumps[AASLUMP_CLUSTERS].filelen);
+ aasworld.clusters = (aas_cluster_t *) AAS_LoadAASLump(fp, offset, length, aasworld.clusters);
+ if (length && !aasworld.clusters) return false;
+ aasworld.numclusters = length / sizeof(aas_cluster_t);
+ //swap everything
+ AAS_SwapAASData();
+ //aas file is loaded
+ aasworld.loaded = true;
+ //close the file
+ fclose(fp);
+ return true;
+} //end of the function AAS_LoadAASFile
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int AAS_WriteAASLump(FILE *fp, aas_header_t *h, int lumpnum, void *data, int length)
+{
+ aas_lump_t *lump;
+
+ lump = &h->lumps[lumpnum];
+
+ lump->fileofs = LittleLong(ftell(fp));
+ lump->filelen = LittleLong(length);
+
+ if (length > 0)
+ {
+ if (fwrite(data, length, 1, fp) < 1)
+ {
+ Log_Print("error writing lump %s\n", lumpnum);
+ fclose(fp);
+ return false;
+ } //end if
+ } //end if
+ return true;
+} //end of the function AAS_WriteAASLump
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_ShowNumReachabilities(int tt, char *name)
+{
+ int i, num;
+
+ num = 0;
+ for (i = 0; i < aasworld.reachabilitysize; i++)
+ {
+ if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == tt)
+ num++;
+ } //end for
+ Log_Print("%6d %s\n", num, name);
+} //end of the function AAS_ShowNumReachabilities
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_ShowTotals(void)
+{
+ Log_Print("numvertexes = %d\r\n", aasworld.numvertexes);
+ Log_Print("numplanes = %d\r\n", aasworld.numplanes);
+ Log_Print("numedges = %d\r\n", aasworld.numedges);
+ Log_Print("edgeindexsize = %d\r\n", aasworld.edgeindexsize);
+ Log_Print("numfaces = %d\r\n", aasworld.numfaces);
+ Log_Print("faceindexsize = %d\r\n", aasworld.faceindexsize);
+ Log_Print("numareas = %d\r\n", aasworld.numareas);
+ Log_Print("numareasettings = %d\r\n", aasworld.numareasettings);
+ Log_Print("reachabilitysize = %d\r\n", aasworld.reachabilitysize);
+ Log_Print("numnodes = %d\r\n", aasworld.numnodes);
+ Log_Print("numportals = %d\r\n", aasworld.numportals);
+ Log_Print("portalindexsize = %d\r\n", aasworld.portalindexsize);
+ Log_Print("numclusters = %d\r\n", aasworld.numclusters);
+ AAS_ShowNumReachabilities(TRAVEL_WALK, "walk");
+ AAS_ShowNumReachabilities(TRAVEL_CROUCH, "crouch");
+ AAS_ShowNumReachabilities(TRAVEL_BARRIERJUMP, "barrier jump");
+ AAS_ShowNumReachabilities(TRAVEL_JUMP, "jump");
+ AAS_ShowNumReachabilities(TRAVEL_LADDER, "ladder");
+ AAS_ShowNumReachabilities(TRAVEL_WALKOFFLEDGE, "walk off ledge");
+ AAS_ShowNumReachabilities(TRAVEL_SWIM, "swim");
+ AAS_ShowNumReachabilities(TRAVEL_WATERJUMP, "water jump");
+ AAS_ShowNumReachabilities(TRAVEL_TELEPORT, "teleport");
+ AAS_ShowNumReachabilities(TRAVEL_ELEVATOR, "elevator");
+ AAS_ShowNumReachabilities(TRAVEL_ROCKETJUMP, "rocket jump");
+ AAS_ShowNumReachabilities(TRAVEL_BFGJUMP, "bfg jump");
+ AAS_ShowNumReachabilities(TRAVEL_GRAPPLEHOOK, "grapple hook");
+ AAS_ShowNumReachabilities(TRAVEL_DOUBLEJUMP, "double jump");
+ AAS_ShowNumReachabilities(TRAVEL_RAMPJUMP, "ramp jump");
+ AAS_ShowNumReachabilities(TRAVEL_STRAFEJUMP, "strafe jump");
+ AAS_ShowNumReachabilities(TRAVEL_JUMPPAD, "jump pad");
+ AAS_ShowNumReachabilities(TRAVEL_FUNCBOB, "func bob");
+} //end of the function AAS_ShowTotals
+//===========================================================================
+// aas data is useless after writing to file because it is byte swapped
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+qboolean AAS_WriteAASFile(char *filename)
+{
+ aas_header_t header;
+ FILE *fp;
+
+ Log_Print("writing %s\n", filename);
+ AAS_ShowTotals();
+ //swap the aas data
+ AAS_SwapAASData();
+ //initialize the file header
+ memset(&header, 0, sizeof(aas_header_t));
+ header.ident = LittleLong(AASID);
+ header.version = LittleLong(AASVERSION);
+ header.bspchecksum = LittleLong(aasworld.bspchecksum);
+ //open a new file
+ fp = fopen(filename, "wb");
+ if (!fp)
+ {
+ Log_Print("error opening %s\n", filename);
+ return false;
+ } //end if
+ //write the header
+ if (fwrite(&header, sizeof(aas_header_t), 1, fp) < 1)
+ {
+ fclose(fp);
+ return false;
+ } //end if
+ //add the data lumps to the file
+ if (!AAS_WriteAASLump(fp, &header, AASLUMP_BBOXES, aasworld.bboxes,
+ aasworld.numbboxes * sizeof(aas_bbox_t))) return false;
+ if (!AAS_WriteAASLump(fp, &header, AASLUMP_VERTEXES, aasworld.vertexes,
+ aasworld.numvertexes * sizeof(aas_vertex_t))) return false;
+ if (!AAS_WriteAASLump(fp, &header, AASLUMP_PLANES, aasworld.planes,
+ aasworld.numplanes * sizeof(aas_plane_t))) return false;
+ if (!AAS_WriteAASLump(fp, &header, AASLUMP_EDGES, aasworld.edges,
+ aasworld.numedges * sizeof(aas_edge_t))) return false;
+ if (!AAS_WriteAASLump(fp, &header, AASLUMP_EDGEINDEX, aasworld.edgeindex,
+ aasworld.edgeindexsize * sizeof(aas_edgeindex_t))) return false;
+ if (!AAS_WriteAASLump(fp, &header, AASLUMP_FACES, aasworld.faces,
+ aasworld.numfaces * sizeof(aas_face_t))) return false;
+ if (!AAS_WriteAASLump(fp, &header, AASLUMP_FACEINDEX, aasworld.faceindex,
+ aasworld.faceindexsize * sizeof(aas_faceindex_t))) return false;
+ if (!AAS_WriteAASLump(fp, &header, AASLUMP_AREAS, aasworld.areas,
+ aasworld.numareas * sizeof(aas_area_t))) return false;
+ if (!AAS_WriteAASLump(fp, &header, AASLUMP_AREASETTINGS, aasworld.areasettings,
+ aasworld.numareasettings * sizeof(aas_areasettings_t))) return false;
+ if (!AAS_WriteAASLump(fp, &header, AASLUMP_REACHABILITY, aasworld.reachability,
+ aasworld.reachabilitysize * sizeof(aas_reachability_t))) return false;
+ if (!AAS_WriteAASLump(fp, &header, AASLUMP_NODES, aasworld.nodes,
+ aasworld.numnodes * sizeof(aas_node_t))) return false;
+ if (!AAS_WriteAASLump(fp, &header, AASLUMP_PORTALS, aasworld.portals,
+ aasworld.numportals * sizeof(aas_portal_t))) return false;
+ if (!AAS_WriteAASLump(fp, &header, AASLUMP_PORTALINDEX, aasworld.portalindex,
+ aasworld.portalindexsize * sizeof(aas_portalindex_t))) return false;
+ if (!AAS_WriteAASLump(fp, &header, AASLUMP_CLUSTERS, aasworld.clusters,
+ aasworld.numclusters * sizeof(aas_cluster_t))) return false;
+ //rewrite the header with the added lumps
+ fseek(fp, 0, SEEK_SET);
+ AAS_DData((unsigned char *) &header + 8, sizeof(aas_header_t) - 8);
+ if (fwrite(&header, sizeof(aas_header_t), 1, fp) < 1)
+ {
+ fclose(fp);
+ return false;
+ } //end if
+ //close the file
+ fclose(fp);
+ return true;
+} //end of the function AAS_WriteAASFile
+
diff --git a/code/bspc/aas_file.h b/code/bspc/aas_file.h
index 5176461..d3e15c2 100755
--- a/code/bspc/aas_file.h
+++ b/code/bspc/aas_file.h
@@ -1,25 +1,25 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-
-qboolean AAS_WriteAASFile(char *filename);
-qboolean AAS_LoadAASFile(char *filename, int fpoffset, int fplength);
-
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+qboolean AAS_WriteAASFile(char *filename);
+qboolean AAS_LoadAASFile(char *filename, int fpoffset, int fplength);
+
diff --git a/code/bspc/aas_gsubdiv.c b/code/bspc/aas_gsubdiv.c
index d9ba597..4cfb194 100755
--- a/code/bspc/aas_gsubdiv.c
+++ b/code/bspc/aas_gsubdiv.c
@@ -1,656 +1,656 @@
-/*
-===========================================================================
-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_cfg.h"
-
-#define FACECLIP_EPSILON 0.2
-#define FACE_EPSILON 1.0
-
-int numgravitationalsubdivisions = 0;
-int numladdersubdivisions = 0;
-
-//NOTE: only do gravitational subdivision BEFORE area merging!!!!!!!
-// because the bsp tree isn't refreshes like with ladder subdivision
-
-//===========================================================================
-// NOTE: the original face is invalid after splitting
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_SplitFace(tmp_face_t *face, vec3_t normal, float dist,
- tmp_face_t **frontface, tmp_face_t **backface)
-{
- winding_t *frontw, *backw;
-
- //
- *frontface = *backface = NULL;
-
- ClipWindingEpsilon(face->winding, normal, dist, FACECLIP_EPSILON, &frontw, &backw);
-
-#ifdef DEBUG
- //
- if (frontw)
- {
- if (WindingIsTiny(frontw))
- {
- Log_Write("AAS_SplitFace: tiny back face\r\n");
- FreeWinding(frontw);
- frontw = NULL;
- } //end if
- } //end if
- if (backw)
- {
- if (WindingIsTiny(backw))
- {
- Log_Write("AAS_SplitFace: tiny back face\r\n");
- FreeWinding(backw);
- backw = NULL;
- } //end if
- } //end if
-#endif //DEBUG
- //if the winding was split
- if (frontw)
- {
- //check bounds
- (*frontface) = AAS_AllocTmpFace();
- (*frontface)->planenum = face->planenum;
- (*frontface)->winding = frontw;
- (*frontface)->faceflags = face->faceflags;
- } //end if
- if (backw)
- {
- //check bounds
- (*backface) = AAS_AllocTmpFace();
- (*backface)->planenum = face->planenum;
- (*backface)->winding = backw;
- (*backface)->faceflags = face->faceflags;
- } //end if
-} //end of the function AAS_SplitFace
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-winding_t *AAS_SplitWinding(tmp_area_t *tmparea, int planenum)
-{
- tmp_face_t *face;
- plane_t *plane;
- int side;
- winding_t *splitwinding;
-
- //
- plane = &mapplanes[planenum];
- //create a split winding, first base winding for plane
- splitwinding = BaseWindingForPlane(plane->normal, plane->dist);
- //chop with all the faces of the area
- for (face = tmparea->tmpfaces; face && splitwinding; face = face->next[side])
- {
- //side of the face the original area was on
- side = face->frontarea != tmparea;
- plane = &mapplanes[face->planenum ^ side];
- ChopWindingInPlace(&splitwinding, plane->normal, plane->dist, 0); // PLANESIDE_EPSILON);
- } //end for
- return splitwinding;
-} //end of the function AAS_SplitWinding
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_TestSplitPlane(tmp_area_t *tmparea, vec3_t normal, float dist,
- int *facesplits, int *groundsplits, int *epsilonfaces)
-{
- int j, side, front, back, planenum;
- float d, d_front, d_back;
- tmp_face_t *face;
- winding_t *w;
-
- *facesplits = *groundsplits = *epsilonfaces = 0;
-
- planenum = FindFloatPlane(normal, dist);
-
- w = AAS_SplitWinding(tmparea, planenum);
- if (!w) return false;
- FreeWinding(w);
- //
- for (face = tmparea->tmpfaces; face; face = face->next[side])
- {
- //side of the face the area is on
- side = face->frontarea != tmparea;
-
- if ((face->planenum & ~1) == (planenum & ~1))
- {
- Log_Print("AAS_TestSplitPlane: tried face plane as splitter\n");
- return false;
- } //end if
- w = face->winding;
- //reset distance at front and back side of plane
- d_front = d_back = 0;
- //reset front and back flags
- front = back = 0;
- for (j = 0; j < w->numpoints; j++)
- {
- d = DotProduct(w->p[j], normal) - dist;
- if (d > d_front) d_front = d;
- if (d < d_back) d_back = d;
-
- if (d > 0.4) // PLANESIDE_EPSILON)
- front = 1;
- if (d < -0.4) // PLANESIDE_EPSILON)
- back = 1;
- } //end for
- //check for an epsilon face
- if ( (d_front > FACECLIP_EPSILON && d_front < FACE_EPSILON)
- || (d_back < -FACECLIP_EPSILON && d_back > -FACE_EPSILON) )
- {
- (*epsilonfaces)++;
- } //end if
- //if the face has points at both sides of the plane
- if (front && back)
- {
- (*facesplits)++;
- if (face->faceflags & FACE_GROUND)
- {
- (*groundsplits)++;
- } //end if
- } //end if
- } //end for
- return true;
-} //end of the function AAS_TestSplitPlane
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_SplitArea(tmp_area_t *tmparea, int planenum, tmp_area_t **frontarea, tmp_area_t **backarea)
-{
- int side;
- tmp_area_t *facefrontarea, *facebackarea, *faceotherarea;
- tmp_face_t *face, *frontface, *backface, *splitface, *nextface;
- winding_t *splitwinding;
- plane_t *splitplane;
-
-/*
-#ifdef AW_DEBUG
- int facesplits, groundsplits, epsilonface;
- Log_Print("\n----------------------\n");
- Log_Print("splitting area %d\n", areanum);
- Log_Print("with normal = \'%f %f %f\', dist = %f\n", normal[0], normal[1], normal[2], dist);
- AAS_TestSplitPlane(areanum, normal, dist,
- &facesplits, &groundsplits, &epsilonface);
- Log_Print("face splits = %d\nground splits = %d\n", facesplits, groundsplits);
- if (epsilonface) Log_Print("aaahh epsilon face\n");
-#endif //AW_DEBUG*/
- //the original area
-
- AAS_FlipAreaFaces(tmparea);
- AAS_CheckArea(tmparea);
- //
- splitplane = &mapplanes[planenum];
-/* //create a split winding, first base winding for plane
- splitwinding = BaseWindingForPlane(splitplane->normal, splitplane->dist);
- //chop with all the faces of the area
- for (face = tmparea->tmpfaces; face && splitwinding; face = face->next[side])
- {
- //side of the face the original area was on
- side = face->frontarea != tmparea->areanum;
- plane = &mapplanes[face->planenum ^ side];
- ChopWindingInPlace(&splitwinding, plane->normal, plane->dist, 0); // PLANESIDE_EPSILON);
- } //end for*/
- splitwinding = AAS_SplitWinding(tmparea, planenum);
- if (!splitwinding)
- {
-/*
-#ifdef DEBUG
- AAS_TestSplitPlane(areanum, normal, dist,
- &facesplits, &groundsplits, &epsilonface);
- Log_Print("\nface splits = %d\nground splits = %d\n", facesplits, groundsplits);
- if (epsilonface) Log_Print("aaahh epsilon face\n");
-#endif //DEBUG*/
- Error("AAS_SplitArea: no split winding when splitting area %d\n", tmparea->areanum);
- } //end if
- //create a split face
- splitface = AAS_AllocTmpFace();
- //get the map plane
- splitface->planenum = planenum;
- //store the split winding
- splitface->winding = splitwinding;
- //the new front area
- (*frontarea) = AAS_AllocTmpArea();
- (*frontarea)->presencetype = tmparea->presencetype;
- (*frontarea)->contents = tmparea->contents;
- (*frontarea)->modelnum = tmparea->modelnum;
- (*frontarea)->tmpfaces = NULL;
- //the new back area
- (*backarea) = AAS_AllocTmpArea();
- (*backarea)->presencetype = tmparea->presencetype;
- (*backarea)->contents = tmparea->contents;
- (*backarea)->modelnum = tmparea->modelnum;
- (*backarea)->tmpfaces = NULL;
- //add the split face to the new areas
- AAS_AddFaceSideToArea(splitface, 0, (*frontarea));
- AAS_AddFaceSideToArea(splitface, 1, (*backarea));
-
- //split all the faces of the original area
- for (face = tmparea->tmpfaces; face; face = nextface)
- {
- //side of the face the original area was on
- side = face->frontarea != tmparea;
- //next face of the original area
- nextface = face->next[side];
- //front area of the face
- facefrontarea = face->frontarea;
- //back area of the face
- facebackarea = face->backarea;
- //remove the face from both the front and back areas
- if (facefrontarea) AAS_RemoveFaceFromArea(face, facefrontarea);
- if (facebackarea) AAS_RemoveFaceFromArea(face, facebackarea);
- //split the face
- AAS_SplitFace(face, splitplane->normal, splitplane->dist, &frontface, &backface);
- //free the original face
- AAS_FreeTmpFace(face);
- //get the number of the area at the other side of the face
- if (side) faceotherarea = facefrontarea;
- else faceotherarea = facebackarea;
- //if there is an area at the other side of the original face
- if (faceotherarea)
- {
- if (frontface) AAS_AddFaceSideToArea(frontface, !side, faceotherarea);
- if (backface) AAS_AddFaceSideToArea(backface, !side, faceotherarea);
- } //end if
- //add the front and back part left after splitting the original face to the new areas
- if (frontface) AAS_AddFaceSideToArea(frontface, side, (*frontarea));
- if (backface) AAS_AddFaceSideToArea(backface, side, (*backarea));
- } //end for
-
- if (!(*frontarea)->tmpfaces) Log_Print("AAS_SplitArea: front area without faces\n");
- if (!(*backarea)->tmpfaces) Log_Print("AAS_SplitArea: back area without faces\n");
-
- tmparea->invalid = true;
-/*
-#ifdef AW_DEBUG
- for (i = 0, face = frontarea->tmpfaces; face; face = face->next[side])
- {
- side = face->frontarea != frontarea->areanum;
- i++;
- } //end for
- Log_Print("created front area %d with %d faces\n", frontarea->areanum, i);
-
- for (i = 0, face = backarea->tmpfaces; face; face = face->next[side])
- {
- side = face->frontarea != backarea->areanum;
- i++;
- } //end for
- Log_Print("created back area %d with %d faces\n", backarea->areanum, i);
-#endif //AW_DEBUG*/
-
- AAS_FlipAreaFaces((*frontarea));
- AAS_FlipAreaFaces((*backarea));
- //
- AAS_CheckArea((*frontarea));
- AAS_CheckArea((*backarea));
-} //end of the function AAS_SplitArea
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_FindBestAreaSplitPlane(tmp_area_t *tmparea, vec3_t normal, float *dist)
-{
- int side1, side2;
- int foundsplitter, facesplits, groundsplits, epsilonfaces, bestepsilonfaces;
- float bestvalue, value;
- tmp_face_t *face1, *face2;
- vec3_t tmpnormal, invgravity;
- float tmpdist;
-
- //get inverse of gravity direction
- VectorCopy(cfg.phys_gravitydirection, invgravity);
- VectorInverse(invgravity);
-
- foundsplitter = false;
- bestvalue = -999999;
- bestepsilonfaces = 0;
- //
-#ifdef AW_DEBUG
- Log_Print("finding split plane for area %d\n", tmparea->areanum);
-#endif //AW_DEBUG
- for (face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1])
- {
- //side of the face the area is on
- side1 = face1->frontarea != tmparea;
- //
- if (WindingIsTiny(face1->winding))
- {
- Log_Write("gsubdiv: area %d has a tiny winding\r\n", tmparea->areanum);
- continue;
- } //end if
- //if the face isn't a gap or ground there's no split edge
- if (!(face1->faceflags & FACE_GROUND) && !AAS_GapFace(face1, side1)) continue;
- //
- for (face2 = face1->next[side1]; face2; face2 = face2->next[side2])
- {
- //side of the face the area is on
- side2 = face2->frontarea != tmparea;
- //
- if (WindingIsTiny(face1->winding))
- {
- Log_Write("gsubdiv: area %d has a tiny winding\r\n", tmparea->areanum);
- continue;
- } //end if
- //if the face isn't a gap or ground there's no split edge
- if (!(face2->faceflags & FACE_GROUND) && !AAS_GapFace(face2, side2)) continue;
- //only split between gaps and ground
- if (!(((face1->faceflags & FACE_GROUND) && AAS_GapFace(face2, side2)) ||
- ((face2->faceflags & FACE_GROUND) && AAS_GapFace(face1, side1)))) continue;
- //find a plane seperating the windings of the faces
- if (!FindPlaneSeperatingWindings(face1->winding, face2->winding, invgravity,
- tmpnormal, &tmpdist)) continue;
-#ifdef AW_DEBUG
- Log_Print("normal = \'%f %f %f\', dist = %f\n",
- tmpnormal[0], tmpnormal[1], tmpnormal[2], tmpdist);
-#endif //AW_DEBUG
- //get metrics for this vertical plane
- if (!AAS_TestSplitPlane(tmparea, tmpnormal, tmpdist,
- &facesplits, &groundsplits, &epsilonfaces))
- {
- continue;
- } //end if
-#ifdef AW_DEBUG
- Log_Print("face splits = %d\nground splits = %d\n",
- facesplits, groundsplits);
-#endif //AW_DEBUG
- value = 100 - facesplits - 2 * groundsplits;
- //avoid epsilon faces
- value += epsilonfaces * -1000;
- if (value > bestvalue)
- {
- VectorCopy(tmpnormal, normal);
- *dist = tmpdist;
- bestvalue = value;
- bestepsilonfaces = epsilonfaces;
- foundsplitter = true;
- } //end if
- } //end for
- } //end for
- if (bestepsilonfaces)
- {
- Log_Write("found %d epsilon faces trying to split area %d\r\n",
- epsilonfaces, tmparea->areanum);
- } //end else
- return foundsplitter;
-} //end of the function AAS_FindBestAreaSplitPlane
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-tmp_node_t *AAS_SubdivideArea_r(tmp_node_t *tmpnode)
-{
- int planenum;
- tmp_area_t *frontarea, *backarea;
- tmp_node_t *tmpnode1, *tmpnode2;
- vec3_t normal;
- float dist;
-
- if (AAS_FindBestAreaSplitPlane(tmpnode->tmparea, normal, &dist))
- {
- qprintf("\r%6d", ++numgravitationalsubdivisions);
- //
- planenum = FindFloatPlane(normal, dist);
- //split the area
- AAS_SplitArea(tmpnode->tmparea, planenum, &frontarea, &backarea);
- //
- tmpnode->tmparea = NULL;
- tmpnode->planenum = FindFloatPlane(normal, dist);
- //
- tmpnode1 = AAS_AllocTmpNode();
- tmpnode1->planenum = 0;
- tmpnode1->tmparea = frontarea;
- //
- tmpnode2 = AAS_AllocTmpNode();
- tmpnode2->planenum = 0;
- tmpnode2->tmparea = backarea;
- //subdivide the areas created by splitting recursively
- tmpnode->children[0] = AAS_SubdivideArea_r(tmpnode1);
- tmpnode->children[1] = AAS_SubdivideArea_r(tmpnode2);
- } //end if
- return tmpnode;
-} //end of the function AAS_SubdivideArea_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-tmp_node_t *AAS_GravitationalSubdivision_r(tmp_node_t *tmpnode)
-{
- //if this is a solid leaf
- if (!tmpnode) return NULL;
- //negative so it's an area
- if (tmpnode->tmparea) return AAS_SubdivideArea_r(tmpnode);
- //do the children recursively
- tmpnode->children[0] = AAS_GravitationalSubdivision_r(tmpnode->children[0]);
- tmpnode->children[1] = AAS_GravitationalSubdivision_r(tmpnode->children[1]);
- return tmpnode;
-} //end of the function AAS_GravitationalSubdivision_r
-//===========================================================================
-// NOTE: merge faces and melt edges first
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_GravitationalSubdivision(void)
-{
- Log_Write("AAS_GravitationalSubdivision\r\n");
- numgravitationalsubdivisions = 0;
- qprintf("%6i gravitational subdivisions", numgravitationalsubdivisions);
- //start with the head node
- AAS_GravitationalSubdivision_r(tmpaasworld.nodes);
- qprintf("\n");
- Log_Write("%6i gravitational subdivisions\r\n", numgravitationalsubdivisions);
-} //end of the function AAS_GravitationalSubdivision
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-tmp_node_t *AAS_RefreshLadderSubdividedTree_r(tmp_node_t *tmpnode, tmp_area_t *tmparea,
- tmp_node_t *tmpnode1, tmp_node_t *tmpnode2, int planenum)
-{
- //if this is a solid leaf
- if (!tmpnode) return NULL;
- //negative so it's an area
- if (tmpnode->tmparea)
- {
- if (tmpnode->tmparea == tmparea)
- {
- tmpnode->tmparea = NULL;
- tmpnode->planenum = planenum;
- tmpnode->children[0] = tmpnode1;
- tmpnode->children[1] = tmpnode2;
- } //end if
- return tmpnode;
- } //end if
- //do the children recursively
- tmpnode->children[0] = AAS_RefreshLadderSubdividedTree_r(tmpnode->children[0],
- tmparea, tmpnode1, tmpnode2, planenum);
- tmpnode->children[1] = AAS_RefreshLadderSubdividedTree_r(tmpnode->children[1],
- tmparea, tmpnode1, tmpnode2, planenum);
- return tmpnode;
-} //end of the function AAS_RefreshLadderSubdividedTree_r
-//===========================================================================
-// find an area with ladder faces and ground faces that are not connected
-// split the area with a horizontal plane at the lowest vertex of all
-// ladder faces in the area
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-tmp_node_t *AAS_LadderSubdivideArea_r(tmp_node_t *tmpnode)
-{
- int side1, i, planenum;
- int foundladderface, foundgroundface;
- float dist;
- tmp_area_t *tmparea, *frontarea, *backarea;
- tmp_face_t *face1;
- tmp_node_t *tmpnode1, *tmpnode2;
- vec3_t lowestpoint, normal = {0, 0, 1};
- plane_t *plane;
- winding_t *w;
-
- tmparea = tmpnode->tmparea;
- //skip areas with a liquid
- if (tmparea->contents & (AREACONTENTS_WATER
- | AREACONTENTS_LAVA
- | AREACONTENTS_SLIME)) return tmpnode;
- //must be possible to stand in the area
- if (!(tmparea->presencetype & PRESENCE_NORMAL)) return tmpnode;
- //
- foundladderface = false;
- foundgroundface = false;
- lowestpoint[2] = 99999;
- //
- for (face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1])
- {
- //side of the face the area is on
- side1 = face1->frontarea != tmparea;
- //if the face is a ladder face
- if (face1->faceflags & FACE_LADDER)
- {
- plane = &mapplanes[face1->planenum];
- //the ladder face plane should be pretty much vertical
- if (DotProduct(plane->normal, normal) > -0.1)
- {
- foundladderface = true;
- //find lowest point
- for (i = 0; i < face1->winding->numpoints; i++)
- {
- if (face1->winding->p[i][2] < lowestpoint[2])
- {
- VectorCopy(face1->winding->p[i], lowestpoint);
- } //end if
- } //end for
- } //end if
- } //end if
- else if (face1->faceflags & FACE_GROUND)
- {
- foundgroundface = true;
- } //end else if
- } //end for
- //
- if ((!foundladderface) || (!foundgroundface)) return tmpnode;
- //
- for (face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1])
- {
- //side of the face the area is on
- side1 = face1->frontarea != tmparea;
- //if the face isn't a ground face
- if (!(face1->faceflags & FACE_GROUND)) continue;
- //the ground plane
- plane = &mapplanes[face1->planenum];
- //get the difference between the ground plane and the lowest point
- dist = DotProduct(plane->normal, lowestpoint) - plane->dist;
- //if the lowest point is very near one of the ground planes
- if (dist > -1 && dist < 1)
- {
- return tmpnode;
- } //end if
- } //end for
- //
- dist = DotProduct(normal, lowestpoint);
- planenum = FindFloatPlane(normal, dist);
- //
- w = AAS_SplitWinding(tmparea, planenum);
- if (!w) return tmpnode;
- FreeWinding(w);
- //split the area with a horizontal plane through the lowest point
- qprintf("\r%6d", ++numladdersubdivisions);
- //
- AAS_SplitArea(tmparea, planenum, &frontarea, &backarea);
- //
- tmpnode->tmparea = NULL;
- tmpnode->planenum = planenum;
- //
- tmpnode1 = AAS_AllocTmpNode();
- tmpnode1->planenum = 0;
- tmpnode1->tmparea = frontarea;
- //
- tmpnode2 = AAS_AllocTmpNode();
- tmpnode2->planenum = 0;
- tmpnode2->tmparea = backarea;
- //subdivide the areas created by splitting recursively
- tmpnode->children[0] = AAS_LadderSubdivideArea_r(tmpnode1);
- tmpnode->children[1] = AAS_LadderSubdivideArea_r(tmpnode2);
- //refresh the tree
- AAS_RefreshLadderSubdividedTree_r(tmpaasworld.nodes, tmparea, tmpnode1, tmpnode2, planenum);
- //
- return tmpnode;
-} //end of the function AAS_LadderSubdivideArea_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-tmp_node_t *AAS_LadderSubdivision_r(tmp_node_t *tmpnode)
-{
- //if this is a solid leaf
- if (!tmpnode) return 0;
- //negative so it's an area
- if (tmpnode->tmparea) return AAS_LadderSubdivideArea_r(tmpnode);
- //do the children recursively
- tmpnode->children[0] = AAS_LadderSubdivision_r(tmpnode->children[0]);
- tmpnode->children[1] = AAS_LadderSubdivision_r(tmpnode->children[1]);
- return tmpnode;
-} //end of the function AAS_LadderSubdivision_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_LadderSubdivision(void)
-{
- Log_Write("AAS_LadderSubdivision\r\n");
- numladdersubdivisions = 0;
- qprintf("%6i ladder subdivisions", numladdersubdivisions);
- //start with the head node
- AAS_LadderSubdivision_r(tmpaasworld.nodes);
- //
- qprintf("\n");
- Log_Write("%6i ladder subdivisions\r\n", numladdersubdivisions);
-} //end of the function AAS_LadderSubdivision
+/*
+===========================================================================
+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_cfg.h"
+
+#define FACECLIP_EPSILON 0.2
+#define FACE_EPSILON 1.0
+
+int numgravitationalsubdivisions = 0;
+int numladdersubdivisions = 0;
+
+//NOTE: only do gravitational subdivision BEFORE area merging!!!!!!!
+// because the bsp tree isn't refreshes like with ladder subdivision
+
+//===========================================================================
+// NOTE: the original face is invalid after splitting
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_SplitFace(tmp_face_t *face, vec3_t normal, float dist,
+ tmp_face_t **frontface, tmp_face_t **backface)
+{
+ winding_t *frontw, *backw;
+
+ //
+ *frontface = *backface = NULL;
+
+ ClipWindingEpsilon(face->winding, normal, dist, FACECLIP_EPSILON, &frontw, &backw);
+
+#ifdef DEBUG
+ //
+ if (frontw)
+ {
+ if (WindingIsTiny(frontw))
+ {
+ Log_Write("AAS_SplitFace: tiny back face\r\n");
+ FreeWinding(frontw);
+ frontw = NULL;
+ } //end if
+ } //end if
+ if (backw)
+ {
+ if (WindingIsTiny(backw))
+ {
+ Log_Write("AAS_SplitFace: tiny back face\r\n");
+ FreeWinding(backw);
+ backw = NULL;
+ } //end if
+ } //end if
+#endif //DEBUG
+ //if the winding was split
+ if (frontw)
+ {
+ //check bounds
+ (*frontface) = AAS_AllocTmpFace();
+ (*frontface)->planenum = face->planenum;
+ (*frontface)->winding = frontw;
+ (*frontface)->faceflags = face->faceflags;
+ } //end if
+ if (backw)
+ {
+ //check bounds
+ (*backface) = AAS_AllocTmpFace();
+ (*backface)->planenum = face->planenum;
+ (*backface)->winding = backw;
+ (*backface)->faceflags = face->faceflags;
+ } //end if
+} //end of the function AAS_SplitFace
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+winding_t *AAS_SplitWinding(tmp_area_t *tmparea, int planenum)
+{
+ tmp_face_t *face;
+ plane_t *plane;
+ int side;
+ winding_t *splitwinding;
+
+ //
+ plane = &mapplanes[planenum];
+ //create a split winding, first base winding for plane
+ splitwinding = BaseWindingForPlane(plane->normal, plane->dist);
+ //chop with all the faces of the area
+ for (face = tmparea->tmpfaces; face && splitwinding; face = face->next[side])
+ {
+ //side of the face the original area was on
+ side = face->frontarea != tmparea;
+ plane = &mapplanes[face->planenum ^ side];
+ ChopWindingInPlace(&splitwinding, plane->normal, plane->dist, 0); // PLANESIDE_EPSILON);
+ } //end for
+ return splitwinding;
+} //end of the function AAS_SplitWinding
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int AAS_TestSplitPlane(tmp_area_t *tmparea, vec3_t normal, float dist,
+ int *facesplits, int *groundsplits, int *epsilonfaces)
+{
+ int j, side, front, back, planenum;
+ float d, d_front, d_back;
+ tmp_face_t *face;
+ winding_t *w;
+
+ *facesplits = *groundsplits = *epsilonfaces = 0;
+
+ planenum = FindFloatPlane(normal, dist);
+
+ w = AAS_SplitWinding(tmparea, planenum);
+ if (!w) return false;
+ FreeWinding(w);
+ //
+ for (face = tmparea->tmpfaces; face; face = face->next[side])
+ {
+ //side of the face the area is on
+ side = face->frontarea != tmparea;
+
+ if ((face->planenum & ~1) == (planenum & ~1))
+ {
+ Log_Print("AAS_TestSplitPlane: tried face plane as splitter\n");
+ return false;
+ } //end if
+ w = face->winding;
+ //reset distance at front and back side of plane
+ d_front = d_back = 0;
+ //reset front and back flags
+ front = back = 0;
+ for (j = 0; j < w->numpoints; j++)
+ {
+ d = DotProduct(w->p[j], normal) - dist;
+ if (d > d_front) d_front = d;
+ if (d < d_back) d_back = d;
+
+ if (d > 0.4) // PLANESIDE_EPSILON)
+ front = 1;
+ if (d < -0.4) // PLANESIDE_EPSILON)
+ back = 1;
+ } //end for
+ //check for an epsilon face
+ if ( (d_front > FACECLIP_EPSILON && d_front < FACE_EPSILON)
+ || (d_back < -FACECLIP_EPSILON && d_back > -FACE_EPSILON) )
+ {
+ (*epsilonfaces)++;
+ } //end if
+ //if the face has points at both sides of the plane
+ if (front && back)
+ {
+ (*facesplits)++;
+ if (face->faceflags & FACE_GROUND)
+ {
+ (*groundsplits)++;
+ } //end if
+ } //end if
+ } //end for
+ return true;
+} //end of the function AAS_TestSplitPlane
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_SplitArea(tmp_area_t *tmparea, int planenum, tmp_area_t **frontarea, tmp_area_t **backarea)
+{
+ int side;
+ tmp_area_t *facefrontarea, *facebackarea, *faceotherarea;
+ tmp_face_t *face, *frontface, *backface, *splitface, *nextface;
+ winding_t *splitwinding;
+ plane_t *splitplane;
+
+/*
+#ifdef AW_DEBUG
+ int facesplits, groundsplits, epsilonface;
+ Log_Print("\n----------------------\n");
+ Log_Print("splitting area %d\n", areanum);
+ Log_Print("with normal = \'%f %f %f\', dist = %f\n", normal[0], normal[1], normal[2], dist);
+ AAS_TestSplitPlane(areanum, normal, dist,
+ &facesplits, &groundsplits, &epsilonface);
+ Log_Print("face splits = %d\nground splits = %d\n", facesplits, groundsplits);
+ if (epsilonface) Log_Print("aaahh epsilon face\n");
+#endif //AW_DEBUG*/
+ //the original area
+
+ AAS_FlipAreaFaces(tmparea);
+ AAS_CheckArea(tmparea);
+ //
+ splitplane = &mapplanes[planenum];
+/* //create a split winding, first base winding for plane
+ splitwinding = BaseWindingForPlane(splitplane->normal, splitplane->dist);
+ //chop with all the faces of the area
+ for (face = tmparea->tmpfaces; face && splitwinding; face = face->next[side])
+ {
+ //side of the face the original area was on
+ side = face->frontarea != tmparea->areanum;
+ plane = &mapplanes[face->planenum ^ side];
+ ChopWindingInPlace(&splitwinding, plane->normal, plane->dist, 0); // PLANESIDE_EPSILON);
+ } //end for*/
+ splitwinding = AAS_SplitWinding(tmparea, planenum);
+ if (!splitwinding)
+ {
+/*
+#ifdef DEBUG
+ AAS_TestSplitPlane(areanum, normal, dist,
+ &facesplits, &groundsplits, &epsilonface);
+ Log_Print("\nface splits = %d\nground splits = %d\n", facesplits, groundsplits);
+ if (epsilonface) Log_Print("aaahh epsilon face\n");
+#endif //DEBUG*/
+ Error("AAS_SplitArea: no split winding when splitting area %d\n", tmparea->areanum);
+ } //end if
+ //create a split face
+ splitface = AAS_AllocTmpFace();
+ //get the map plane
+ splitface->planenum = planenum;
+ //store the split winding
+ splitface->winding = splitwinding;
+ //the new front area
+ (*frontarea) = AAS_AllocTmpArea();
+ (*frontarea)->presencetype = tmparea->presencetype;
+ (*frontarea)->contents = tmparea->contents;
+ (*frontarea)->modelnum = tmparea->modelnum;
+ (*frontarea)->tmpfaces = NULL;
+ //the new back area
+ (*backarea) = AAS_AllocTmpArea();
+ (*backarea)->presencetype = tmparea->presencetype;
+ (*backarea)->contents = tmparea->contents;
+ (*backarea)->modelnum = tmparea->modelnum;
+ (*backarea)->tmpfaces = NULL;
+ //add the split face to the new areas
+ AAS_AddFaceSideToArea(splitface, 0, (*frontarea));
+ AAS_AddFaceSideToArea(splitface, 1, (*backarea));
+
+ //split all the faces of the original area
+ for (face = tmparea->tmpfaces; face; face = nextface)
+ {
+ //side of the face the original area was on
+ side = face->frontarea != tmparea;
+ //next face of the original area
+ nextface = face->next[side];
+ //front area of the face
+ facefrontarea = face->frontarea;
+ //back area of the face
+ facebackarea = face->backarea;
+ //remove the face from both the front and back areas
+ if (facefrontarea) AAS_RemoveFaceFromArea(face, facefrontarea);
+ if (facebackarea) AAS_RemoveFaceFromArea(face, facebackarea);
+ //split the face
+ AAS_SplitFace(face, splitplane->normal, splitplane->dist, &frontface, &backface);
+ //free the original face
+ AAS_FreeTmpFace(face);
+ //get the number of the area at the other side of the face
+ if (side) faceotherarea = facefrontarea;
+ else faceotherarea = facebackarea;
+ //if there is an area at the other side of the original face
+ if (faceotherarea)
+ {
+ if (frontface) AAS_AddFaceSideToArea(frontface, !side, faceotherarea);
+ if (backface) AAS_AddFaceSideToArea(backface, !side, faceotherarea);
+ } //end if
+ //add the front and back part left after splitting the original face to the new areas
+ if (frontface) AAS_AddFaceSideToArea(frontface, side, (*frontarea));
+ if (backface) AAS_AddFaceSideToArea(backface, side, (*backarea));
+ } //end for
+
+ if (!(*frontarea)->tmpfaces) Log_Print("AAS_SplitArea: front area without faces\n");
+ if (!(*backarea)->tmpfaces) Log_Print("AAS_SplitArea: back area without faces\n");
+
+ tmparea->invalid = true;
+/*
+#ifdef AW_DEBUG
+ for (i = 0, face = frontarea->tmpfaces; face; face = face->next[side])
+ {
+ side = face->frontarea != frontarea->areanum;
+ i++;
+ } //end for
+ Log_Print("created front area %d with %d faces\n", frontarea->areanum, i);
+
+ for (i = 0, face = backarea->tmpfaces; face; face = face->next[side])
+ {
+ side = face->frontarea != backarea->areanum;
+ i++;
+ } //end for
+ Log_Print("created back area %d with %d faces\n", backarea->areanum, i);
+#endif //AW_DEBUG*/
+
+ AAS_FlipAreaFaces((*frontarea));
+ AAS_FlipAreaFaces((*backarea));
+ //
+ AAS_CheckArea((*frontarea));
+ AAS_CheckArea((*backarea));
+} //end of the function AAS_SplitArea
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int AAS_FindBestAreaSplitPlane(tmp_area_t *tmparea, vec3_t normal, float *dist)
+{
+ int side1, side2;
+ int foundsplitter, facesplits, groundsplits, epsilonfaces, bestepsilonfaces;
+ float bestvalue, value;
+ tmp_face_t *face1, *face2;
+ vec3_t tmpnormal, invgravity;
+ float tmpdist;
+
+ //get inverse of gravity direction
+ VectorCopy(cfg.phys_gravitydirection, invgravity);
+ VectorInverse(invgravity);
+
+ foundsplitter = false;
+ bestvalue = -999999;
+ bestepsilonfaces = 0;
+ //
+#ifdef AW_DEBUG
+ Log_Print("finding split plane for area %d\n", tmparea->areanum);
+#endif //AW_DEBUG
+ for (face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1])
+ {
+ //side of the face the area is on
+ side1 = face1->frontarea != tmparea;
+ //
+ if (WindingIsTiny(face1->winding))
+ {
+ Log_Write("gsubdiv: area %d has a tiny winding\r\n", tmparea->areanum);
+ continue;
+ } //end if
+ //if the face isn't a gap or ground there's no split edge
+ if (!(face1->faceflags & FACE_GROUND) && !AAS_GapFace(face1, side1)) continue;
+ //
+ for (face2 = face1->next[side1]; face2; face2 = face2->next[side2])
+ {
+ //side of the face the area is on
+ side2 = face2->frontarea != tmparea;
+ //
+ if (WindingIsTiny(face1->winding))
+ {
+ Log_Write("gsubdiv: area %d has a tiny winding\r\n", tmparea->areanum);
+ continue;
+ } //end if
+ //if the face isn't a gap or ground there's no split edge
+ if (!(face2->faceflags & FACE_GROUND) && !AAS_GapFace(face2, side2)) continue;
+ //only split between gaps and ground
+ if (!(((face1->faceflags & FACE_GROUND) && AAS_GapFace(face2, side2)) ||
+ ((face2->faceflags & FACE_GROUND) && AAS_GapFace(face1, side1)))) continue;
+ //find a plane seperating the windings of the faces
+ if (!FindPlaneSeperatingWindings(face1->winding, face2->winding, invgravity,
+ tmpnormal, &tmpdist)) continue;
+#ifdef AW_DEBUG
+ Log_Print("normal = \'%f %f %f\', dist = %f\n",
+ tmpnormal[0], tmpnormal[1], tmpnormal[2], tmpdist);
+#endif //AW_DEBUG
+ //get metrics for this vertical plane
+ if (!AAS_TestSplitPlane(tmparea, tmpnormal, tmpdist,
+ &facesplits, &groundsplits, &epsilonfaces))
+ {
+ continue;
+ } //end if
+#ifdef AW_DEBUG
+ Log_Print("face splits = %d\nground splits = %d\n",
+ facesplits, groundsplits);
+#endif //AW_DEBUG
+ value = 100 - facesplits - 2 * groundsplits;
+ //avoid epsilon faces
+ value += epsilonfaces * -1000;
+ if (value > bestvalue)
+ {
+ VectorCopy(tmpnormal, normal);
+ *dist = tmpdist;
+ bestvalue = value;
+ bestepsilonfaces = epsilonfaces;
+ foundsplitter = true;
+ } //end if
+ } //end for
+ } //end for
+ if (bestepsilonfaces)
+ {
+ Log_Write("found %d epsilon faces trying to split area %d\r\n",
+ epsilonfaces, tmparea->areanum);
+ } //end else
+ return foundsplitter;
+} //end of the function AAS_FindBestAreaSplitPlane
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+tmp_node_t *AAS_SubdivideArea_r(tmp_node_t *tmpnode)
+{
+ int planenum;
+ tmp_area_t *frontarea, *backarea;
+ tmp_node_t *tmpnode1, *tmpnode2;
+ vec3_t normal;
+ float dist;
+
+ if (AAS_FindBestAreaSplitPlane(tmpnode->tmparea, normal, &dist))
+ {
+ qprintf("\r%6d", ++numgravitationalsubdivisions);
+ //
+ planenum = FindFloatPlane(normal, dist);
+ //split the area
+ AAS_SplitArea(tmpnode->tmparea, planenum, &frontarea, &backarea);
+ //
+ tmpnode->tmparea = NULL;
+ tmpnode->planenum = FindFloatPlane(normal, dist);
+ //
+ tmpnode1 = AAS_AllocTmpNode();
+ tmpnode1->planenum = 0;
+ tmpnode1->tmparea = frontarea;
+ //
+ tmpnode2 = AAS_AllocTmpNode();
+ tmpnode2->planenum = 0;
+ tmpnode2->tmparea = backarea;
+ //subdivide the areas created by splitting recursively
+ tmpnode->children[0] = AAS_SubdivideArea_r(tmpnode1);
+ tmpnode->children[1] = AAS_SubdivideArea_r(tmpnode2);
+ } //end if
+ return tmpnode;
+} //end of the function AAS_SubdivideArea_r
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+tmp_node_t *AAS_GravitationalSubdivision_r(tmp_node_t *tmpnode)
+{
+ //if this is a solid leaf
+ if (!tmpnode) return NULL;
+ //negative so it's an area
+ if (tmpnode->tmparea) return AAS_SubdivideArea_r(tmpnode);
+ //do the children recursively
+ tmpnode->children[0] = AAS_GravitationalSubdivision_r(tmpnode->children[0]);
+ tmpnode->children[1] = AAS_GravitationalSubdivision_r(tmpnode->children[1]);
+ return tmpnode;
+} //end of the function AAS_GravitationalSubdivision_r
+//===========================================================================
+// NOTE: merge faces and melt edges first
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_GravitationalSubdivision(void)
+{
+ Log_Write("AAS_GravitationalSubdivision\r\n");
+ numgravitationalsubdivisions = 0;
+ qprintf("%6i gravitational subdivisions", numgravitationalsubdivisions);
+ //start with the head node
+ AAS_GravitationalSubdivision_r(tmpaasworld.nodes);
+ qprintf("\n");
+ Log_Write("%6i gravitational subdivisions\r\n", numgravitationalsubdivisions);
+} //end of the function AAS_GravitationalSubdivision
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+tmp_node_t *AAS_RefreshLadderSubdividedTree_r(tmp_node_t *tmpnode, tmp_area_t *tmparea,
+ tmp_node_t *tmpnode1, tmp_node_t *tmpnode2, int planenum)
+{
+ //if this is a solid leaf
+ if (!tmpnode) return NULL;
+ //negative so it's an area
+ if (tmpnode->tmparea)
+ {
+ if (tmpnode->tmparea == tmparea)
+ {
+ tmpnode->tmparea = NULL;
+ tmpnode->planenum = planenum;
+ tmpnode->children[0] = tmpnode1;
+ tmpnode->children[1] = tmpnode2;
+ } //end if
+ return tmpnode;
+ } //end if
+ //do the children recursively
+ tmpnode->children[0] = AAS_RefreshLadderSubdividedTree_r(tmpnode->children[0],
+ tmparea, tmpnode1, tmpnode2, planenum);
+ tmpnode->children[1] = AAS_RefreshLadderSubdividedTree_r(tmpnode->children[1],
+ tmparea, tmpnode1, tmpnode2, planenum);
+ return tmpnode;
+} //end of the function AAS_RefreshLadderSubdividedTree_r
+//===========================================================================
+// find an area with ladder faces and ground faces that are not connected
+// split the area with a horizontal plane at the lowest vertex of all
+// ladder faces in the area
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+tmp_node_t *AAS_LadderSubdivideArea_r(tmp_node_t *tmpnode)
+{
+ int side1, i, planenum;
+ int foundladderface, foundgroundface;
+ float dist;
+ tmp_area_t *tmparea, *frontarea, *backarea;
+ tmp_face_t *face1;
+ tmp_node_t *tmpnode1, *tmpnode2;
+ vec3_t lowestpoint, normal = {0, 0, 1};
+ plane_t *plane;
+ winding_t *w;
+
+ tmparea = tmpnode->tmparea;
+ //skip areas with a liquid
+ if (tmparea->contents & (AREACONTENTS_WATER
+ | AREACONTENTS_LAVA
+ | AREACONTENTS_SLIME)) return tmpnode;
+ //must be possible to stand in the area
+ if (!(tmparea->presencetype & PRESENCE_NORMAL)) return tmpnode;
+ //
+ foundladderface = false;
+ foundgroundface = false;
+ lowestpoint[2] = 99999;
+ //
+ for (face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1])
+ {
+ //side of the face the area is on
+ side1 = face1->frontarea != tmparea;
+ //if the face is a ladder face
+ if (face1->faceflags & FACE_LADDER)
+ {
+ plane = &mapplanes[face1->planenum];
+ //the ladder face plane should be pretty much vertical
+ if (DotProduct(plane->normal, normal) > -0.1)
+ {
+ foundladderface = true;
+ //find lowest point
+ for (i = 0; i < face1->winding->numpoints; i++)
+ {
+ if (face1->winding->p[i][2] < lowestpoint[2])
+ {
+ VectorCopy(face1->winding->p[i], lowestpoint);
+ } //end if
+ } //end for
+ } //end if
+ } //end if
+ else if (face1->faceflags & FACE_GROUND)
+ {
+ foundgroundface = true;
+ } //end else if
+ } //end for
+ //
+ if ((!foundladderface) || (!foundgroundface)) return tmpnode;
+ //
+ for (face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1])
+ {
+ //side of the face the area is on
+ side1 = face1->frontarea != tmparea;
+ //if the face isn't a ground face
+ if (!(face1->faceflags & FACE_GROUND)) continue;
+ //the ground plane
+ plane = &mapplanes[face1->planenum];
+ //get the difference between the ground plane and the lowest point
+ dist = DotProduct(plane->normal, lowestpoint) - plane->dist;
+ //if the lowest point is very near one of the ground planes
+ if (dist > -1 && dist < 1)
+ {
+ return tmpnode;
+ } //end if
+ } //end for
+ //
+ dist = DotProduct(normal, lowestpoint);
+ planenum = FindFloatPlane(normal, dist);
+ //
+ w = AAS_SplitWinding(tmparea, planenum);
+ if (!w) return tmpnode;
+ FreeWinding(w);
+ //split the area with a horizontal plane through the lowest point
+ qprintf("\r%6d", ++numladdersubdivisions);
+ //
+ AAS_SplitArea(tmparea, planenum, &frontarea, &backarea);
+ //
+ tmpnode->tmparea = NULL;
+ tmpnode->planenum = planenum;
+ //
+ tmpnode1 = AAS_AllocTmpNode();
+ tmpnode1->planenum = 0;
+ tmpnode1->tmparea = frontarea;
+ //
+ tmpnode2 = AAS_AllocTmpNode();
+ tmpnode2->planenum = 0;
+ tmpnode2->tmparea = backarea;
+ //subdivide the areas created by splitting recursively
+ tmpnode->children[0] = AAS_LadderSubdivideArea_r(tmpnode1);
+ tmpnode->children[1] = AAS_LadderSubdivideArea_r(tmpnode2);
+ //refresh the tree
+ AAS_RefreshLadderSubdividedTree_r(tmpaasworld.nodes, tmparea, tmpnode1, tmpnode2, planenum);
+ //
+ return tmpnode;
+} //end of the function AAS_LadderSubdivideArea_r
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+tmp_node_t *AAS_LadderSubdivision_r(tmp_node_t *tmpnode)
+{
+ //if this is a solid leaf
+ if (!tmpnode) return 0;
+ //negative so it's an area
+ if (tmpnode->tmparea) return AAS_LadderSubdivideArea_r(tmpnode);
+ //do the children recursively
+ tmpnode->children[0] = AAS_LadderSubdivision_r(tmpnode->children[0]);
+ tmpnode->children[1] = AAS_LadderSubdivision_r(tmpnode->children[1]);
+ return tmpnode;
+} //end of the function AAS_LadderSubdivision_r
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_LadderSubdivision(void)
+{
+ Log_Write("AAS_LadderSubdivision\r\n");
+ numladdersubdivisions = 0;
+ qprintf("%6i ladder subdivisions", numladdersubdivisions);
+ //start with the head node
+ AAS_LadderSubdivision_r(tmpaasworld.nodes);
+ //
+ qprintf("\n");
+ Log_Write("%6i ladder subdivisions\r\n", numladdersubdivisions);
+} //end of the function AAS_LadderSubdivision
diff --git a/code/bspc/aas_gsubdiv.h b/code/bspc/aas_gsubdiv.h
index 0156a9a..bb2b095 100755
--- a/code/bspc/aas_gsubdiv.h
+++ b/code/bspc/aas_gsubdiv.h
@@ -1,25 +1,25 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-
-//works with the global tmpaasworld
-void AAS_GravitationalSubdivision(void);
-void AAS_LadderSubdivision(void);
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+//works with the global tmpaasworld
+void AAS_GravitationalSubdivision(void);
+void AAS_LadderSubdivision(void);
diff --git a/code/bspc/aas_map.c b/code/bspc/aas_map.c
index da16d1b..10c616a 100755
--- a/code/bspc/aas_map.c
+++ b/code/bspc/aas_map.c
@@ -1,849 +1,849 @@
-/*
-===========================================================================
-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 "l_mem.h"
-#include "../botlib/aasfile.h" //aas_bbox_t
-#include "aas_store.h" //AAS_MAX_BBOXES
-#include "aas_cfg.h"
-#include "../game/surfaceflags.h"
-
-#define SPAWNFLAG_NOT_EASY 0x00000100
-#define SPAWNFLAG_NOT_MEDIUM 0x00000200
-#define SPAWNFLAG_NOT_HARD 0x00000400
-#define SPAWNFLAG_NOT_DEATHMATCH 0x00000800
-#define SPAWNFLAG_NOT_COOP 0x00001000
-
-#define STATE_TOP 0
-#define STATE_BOTTOM 1
-#define STATE_UP 2
-#define STATE_DOWN 3
-
-#define DOOR_START_OPEN 1
-#define DOOR_REVERSE 2
-#define DOOR_CRUSHER 4
-#define DOOR_NOMONSTER 8
-#define DOOR_TOGGLE 32
-#define DOOR_X_AXIS 64
-#define DOOR_Y_AXIS 128
-
-#define BBOX_NORMAL_EPSILON 0.0001
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-vec_t BoxOriginDistanceFromPlane(vec3_t normal, vec3_t mins, vec3_t maxs, int side)
-{
- vec3_t v1, v2;
- int i;
-
- if (side)
- {
- for (i = 0; i < 3; i++)
- {
- if (normal[i] > BBOX_NORMAL_EPSILON) v1[i] = maxs[i];
- else if (normal[i] < -BBOX_NORMAL_EPSILON) v1[i] = mins[i];
- else v1[i] = 0;
- } //end for
- } //end if
- else
- {
- for (i = 0; i < 3; i++)
- {
- if (normal[i] > BBOX_NORMAL_EPSILON) v1[i] = mins[i];
- else if (normal[i] < -BBOX_NORMAL_EPSILON) v1[i] = maxs[i];
- else v1[i] = 0;
- } //end for
- } //end else
- VectorCopy(normal, v2);
- VectorInverse(v2);
- return DotProduct(v1, v2);
-} //end of the function BoxOriginDistanceFromPlane
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-vec_t CapsuleOriginDistanceFromPlane(vec3_t normal, vec3_t mins, vec3_t maxs)
-{
- float offset_up, offset_down, width, radius;
-
- width = maxs[0] - mins[0];
- // if the box is less high then it is wide
- if (maxs[2] - mins[2] < width) {
- width = maxs[2] - mins[2];
- }
- radius = width * 0.5;
- // offset to upper and lower sphere
- offset_up = maxs[2] - radius;
- offset_down = -mins[2] - radius;
-
- // if normal points upward
- if ( normal[2] > 0 ) {
- // touches lower sphere first
- return normal[2] * offset_down + radius;
- }
- else {
- // touched upper sphere first
- return -normal[2] * offset_up + radius;
- }
-}
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ExpandMapBrush(mapbrush_t *brush, vec3_t mins, vec3_t maxs)
-{
- int sn;
- float dist;
- side_t *s;
- plane_t *plane;
-
- for (sn = 0; sn < brush->numsides; sn++)
- {
- s = brush->original_sides + sn;
- plane = &mapplanes[s->planenum];
- dist = plane->dist;
- if (capsule_collision) {
- dist += CapsuleOriginDistanceFromPlane(plane->normal, mins, maxs);
- }
- else {
- dist += BoxOriginDistanceFromPlane(plane->normal, mins, maxs, 0);
- }
- s->planenum = FindFloatPlane(plane->normal, dist);
- //the side isn't a bevel after expanding
- s->flags &= ~SFL_BEVEL;
- //don't skip the surface
- s->surf &= ~SURF_SKIP;
- //make sure the texinfo is not TEXINFO_NODE
- //when player clip contents brushes are read from the bsp tree
- //they have the texinfo field set to TEXINFO_NODE
- //s->texinfo = 0;
- } //end for
-} //end of the function AAS_ExpandMapBrush
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_SetTexinfo(mapbrush_t *brush)
-{
- int n;
- side_t *side;
-
- if (brush->contents & (CONTENTS_LADDER
- | CONTENTS_AREAPORTAL
- | CONTENTS_CLUSTERPORTAL
- | CONTENTS_TELEPORTER
- | CONTENTS_JUMPPAD
- | CONTENTS_DONOTENTER
- | CONTENTS_WATER
- | CONTENTS_LAVA
- | CONTENTS_SLIME
- | CONTENTS_WINDOW
- | CONTENTS_PLAYERCLIP))
- {
- //we just set texinfo to 0 because these brush sides MUST be used as
- //bsp splitters textured or not textured
- for (n = 0; n < brush->numsides; n++)
- {
- side = brush->original_sides + n;
- //side->flags |= SFL_TEXTURED|SFL_VISIBLE;
- side->texinfo = 0;
- } //end for
- } //end if
- else
- {
- //only use brush sides as splitters if they are textured
- //texinfo of non-textured sides will be set to TEXINFO_NODE
- for (n = 0; n < brush->numsides; n++)
- {
- side = brush->original_sides + n;
- //don't use side as splitter (set texinfo to TEXINFO_NODE) if not textured
- if (side->flags & (SFL_TEXTURED|SFL_BEVEL)) side->texinfo = 0;
- else side->texinfo = TEXINFO_NODE;
- } //end for
- } //end else
-} //end of the function AAS_SetTexinfo
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void FreeBrushWindings(mapbrush_t *brush)
-{
- int n;
- side_t *side;
- //
- for (n = 0; n < brush->numsides; n++)
- {
- side = brush->original_sides + n;
- //
- if (side->winding) FreeWinding(side->winding);
- } //end for
-} //end of the function FreeBrushWindings
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_AddMapBrushSide(mapbrush_t *brush, int planenum)
-{
- side_t *side;
- //
- if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
- Error ("MAX_MAPFILE_BRUSHSIDES");
- //
- side = brush->original_sides + brush->numsides;
- side->original = NULL;
- side->winding = NULL;
- side->contents = brush->contents;
- side->flags &= ~(SFL_BEVEL|SFL_VISIBLE);
- side->surf = 0;
- side->planenum = planenum;
- side->texinfo = 0;
- //
- nummapbrushsides++;
- brush->numsides++;
-} //end of the function AAS_AddMapBrushSide
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_FixMapBrush(mapbrush_t *brush)
-{
- int i, j, planenum;
- float dist;
- winding_t *w;
- plane_t *plane, *plane1, *plane2;
- side_t *side;
- vec3_t normal;
-
- //calculate the brush bounds
- ClearBounds(brush->mins, brush->maxs);
- for (i = 0; i < brush->numsides; i++)
- {
- plane = &mapplanes[brush->original_sides[i].planenum];
- w = BaseWindingForPlane(plane->normal, plane->dist);
- for (j = 0; j < brush->numsides && w; j++)
- {
- if (i == j) continue;
- //there are no brush bevels marked but who cares :)
- if (brush->original_sides[j].flags & SFL_BEVEL) continue;
- plane = &mapplanes[brush->original_sides[j].planenum^1];
- ChopWindingInPlace(&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
- } //end for
-
- side = &brush->original_sides[i];
- side->winding = w;
- if (w)
- {
- for (j = 0; j < w->numpoints; j++)
- {
- AddPointToBounds(w->p[j], brush->mins, brush->maxs);
- } //end for
- } //end if
- } //end for
- //
- for (i = 0; i < brush->numsides; i++)
- {
- for (j = 0; j < brush->numsides; j++)
- {
- if (i == j) continue;
- plane1 = &mapplanes[brush->original_sides[i].planenum];
- plane2 = &mapplanes[brush->original_sides[j].planenum];
- if (WindingsNonConvex(brush->original_sides[i].winding,
- brush->original_sides[j].winding,
- plane1->normal, plane2->normal,
- plane1->dist, plane2->dist))
- {
- Log_Print("non convex brush");
- } //end if
- } //end for
- } //end for
-
- //NOW close the fucking brush!!
- for (i = 0; i < 3; i++)
- {
- if (brush->mins[i] < -MAX_MAP_BOUNDS)
- {
- VectorClear(normal);
- normal[i] = -1;
- dist = MAX_MAP_BOUNDS - 10;
- planenum = FindFloatPlane(normal, dist);
- //
- Log_Print("mins out of range: added extra brush side\n");
- AAS_AddMapBrushSide(brush, planenum);
- } //end if
- if (brush->maxs[i] > MAX_MAP_BOUNDS)
- {
- VectorClear(normal);
- normal[i] = 1;
- dist = MAX_MAP_BOUNDS - 10;
- planenum = FindFloatPlane(normal, dist);
- //
- Log_Print("maxs out of range: added extra brush side\n");
- AAS_AddMapBrushSide(brush, planenum);
- } //end if
- if (brush->mins[i] > MAX_MAP_BOUNDS || brush->maxs[i] < -MAX_MAP_BOUNDS)
- {
- Log_Print("entity %i, brush %i: no visible sides on brush\n", brush->entitynum, brush->brushnum);
- } //end if
- } //end for
- //free all the windings
- FreeBrushWindings(brush);
-} //end of the function AAS_FixMapBrush
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean AAS_MakeBrushWindings(mapbrush_t *ob)
-{
- int i, j;
- winding_t *w;
- side_t *side;
- plane_t *plane, *plane1, *plane2;
-
- ClearBounds (ob->mins, ob->maxs);
-
- for (i = 0; i < ob->numsides; i++)
- {
- plane = &mapplanes[ob->original_sides[i].planenum];
- w = BaseWindingForPlane(plane->normal, plane->dist);
- for (j = 0; j <ob->numsides && w; j++)
- {
- if (i == j) continue;
- if (ob->original_sides[j].flags & SFL_BEVEL) continue;
- plane = &mapplanes[ob->original_sides[j].planenum^1];
- ChopWindingInPlace(&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
- }
-
- side = &ob->original_sides[i];
- side->winding = w;
- if (w)
- {
- side->flags |= SFL_VISIBLE;
- for (j = 0; j < w->numpoints; j++)
- AddPointToBounds (w->p[j], ob->mins, ob->maxs);
- }
- }
- //check if the brush is convex
- for (i = 0; i < ob->numsides; i++)
- {
- for (j = 0; j < ob->numsides; j++)
- {
- if (i == j) continue;
- plane1 = &mapplanes[ob->original_sides[i].planenum];
- plane2 = &mapplanes[ob->original_sides[j].planenum];
- if (WindingsNonConvex(ob->original_sides[i].winding,
- ob->original_sides[j].winding,
- plane1->normal, plane2->normal,
- plane1->dist, plane2->dist))
- {
- Log_Print("non convex brush");
- } //end if
- } //end for
- } //end for
- //check for out of bound brushes
- for (i = 0; i < 3; i++)
- {
- //IDBUG: all the indexes into the mins and maxs were zero (not using i)
- if (ob->mins[i] < -MAX_MAP_BOUNDS || ob->maxs[i] > MAX_MAP_BOUNDS)
- {
- Log_Print("entity %i, brush %i: bounds out of range\n", ob->entitynum, ob->brushnum);
- Log_Print("ob->mins[%d] = %f, ob->maxs[%d] = %f\n", i, ob->mins[i], i, ob->maxs[i]);
- ob->numsides = 0; //remove the brush
- break;
- } //end if
- if (ob->mins[i] > MAX_MAP_BOUNDS || ob->maxs[i] < -MAX_MAP_BOUNDS)
- {
- Log_Print("entity %i, brush %i: no visible sides on brush\n", ob->entitynum, ob->brushnum);
- Log_Print("ob->mins[%d] = %f, ob->maxs[%d] = %f\n", i, ob->mins[i], i, ob->maxs[i]);
- ob->numsides = 0; //remove the brush
- break;
- } //end if
- } //end for
- return true;
-} //end of the function AAS_MakeBrushWindings
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-mapbrush_t *AAS_CopyMapBrush(mapbrush_t *brush, entity_t *mapent)
-{
- int n;
- mapbrush_t *newbrush;
- side_t *side, *newside;
-
- if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
- Error ("MAX_MAPFILE_BRUSHES");
-
- newbrush = &mapbrushes[nummapbrushes];
- newbrush->original_sides = &brushsides[nummapbrushsides];
- newbrush->entitynum = brush->entitynum;
- newbrush->brushnum = nummapbrushes - mapent->firstbrush;
- newbrush->numsides = brush->numsides;
- newbrush->contents = brush->contents;
-
- //copy the sides
- for (n = 0; n < brush->numsides; n++)
- {
- if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
- Error ("MAX_MAPFILE_BRUSHSIDES");
- side = brush->original_sides + n;
-
- newside = newbrush->original_sides + n;
- newside->original = NULL;
- newside->winding = NULL;
- newside->contents = side->contents;
- newside->flags = side->flags;
- newside->surf = side->surf;
- newside->planenum = side->planenum;
- newside->texinfo = side->texinfo;
- nummapbrushsides++;
- } //end for
- //
- nummapbrushes++;
- mapent->numbrushes++;
- return newbrush;
-} //end of the function AAS_CopyMapBrush
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int mark_entities[MAX_MAP_ENTITIES];
-
-int AAS_AlwaysTriggered_r(char *targetname)
-{
- int i;
-
- if (!strlen(targetname)) {
- return false;
- }
- //
- for (i = 0; i < num_entities; i++) {
- // if the entity will activate the given targetname
- if ( !strcmp(targetname, ValueForKey(&entities[i], "target")) ) {
- // if this activator is present in deathmatch
- if (!(atoi(ValueForKey(&entities[i], "spawnflags")) & SPAWNFLAG_NOT_DEATHMATCH)) {
- // if it is a trigger_always entity
- if (!strcmp("trigger_always", ValueForKey(&entities[i], "classname"))) {
- return true;
- }
- // check for possible trigger_always entities activating this entity
- if ( mark_entities[i] ) {
- Warning( "entity %d, classname %s has recursive targetname %s\n", i,
- ValueForKey(&entities[i], "classname"), targetname );
- return false;
- }
- mark_entities[i] = true;
- if ( AAS_AlwaysTriggered_r(ValueForKey(&entities[i], "targetname")) ) {
- return true;
- }
- }
- }
- }
- return false;
-}
-
-int AAS_AlwaysTriggered(char *targetname) {
- memset( mark_entities, 0, sizeof(mark_entities) );
- return AAS_AlwaysTriggered_r( targetname );
-}
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_ValidEntity(entity_t *mapent)
-{
- int i;
- char target[1024];
-
- //all world brushes are used for AAS
- if (mapent == &entities[0])
- {
- return true;
- } //end if
- //some of the func_wall brushes are also used for AAS
- else if (!strcmp("func_wall", ValueForKey(mapent, "classname")))
- {
- //Log_Print("found func_wall entity %d\n", mapent - entities);
- //if the func wall is used in deathmatch
- if (!(atoi(ValueForKey(mapent, "spawnflags")) & SPAWNFLAG_NOT_DEATHMATCH))
- {
- //Log_Print("func_wall USED in deathmatch mode %d\n", atoi(ValueForKey(mapent, "spawnflags")));
- return true;
- } //end if
- } //end else if
- else if (!strcmp("func_door_rotating", ValueForKey(mapent, "classname")))
- {
- //if the func_door_rotating is present in deathmatch
- if (!(atoi(ValueForKey(mapent, "spawnflags")) & SPAWNFLAG_NOT_DEATHMATCH))
- {
- //if the func_door_rotating is always activated in deathmatch
- if (AAS_AlwaysTriggered(ValueForKey(mapent, "targetname")))
- {
- //Log_Print("found func_door_rotating in deathmatch\ntargetname %s\n", ValueForKey(mapent, "targetname"));
- return true;
- } //end if
- } //end if
- } //end else if
- else if (!strcmp("trigger_hurt", ValueForKey(mapent, "classname")))
- {
- //"dmg" is the damage, for instance: "dmg" "666"
- return true;
- } //end else if
- else if (!strcmp("trigger_push", ValueForKey(mapent, "classname")))
- {
- return true;
- } //end else if
- else if (!strcmp("trigger_multiple", ValueForKey(mapent, "classname")))
- {
- //find out if the trigger_multiple is pointing to a target_teleporter
- strcpy(target, ValueForKey(mapent, "target"));
- for (i = 0; i < num_entities; i++)
- {
- //if the entity will activate the given targetname
- if (!strcmp(target, ValueForKey(&entities[i], "targetname")))
- {
- if (!strcmp("target_teleporter", ValueForKey(&entities[i], "classname")))
- {
- return true;
- } //end if
- } //end if
- } //end for
- } //end else if
- else if (!strcmp("trigger_teleport", ValueForKey(mapent, "classname")))
- {
- return true;
- } //end else if
- else if (!strcmp("func_static", ValueForKey(mapent, "classname")))
- {
- //FIXME: easy/medium/hard/deathmatch specific?
- return true;
- } //end else if
- else if (!strcmp("func_door", ValueForKey(mapent, "classname")))
- {
- return true;
- } //end else if
- return false;
-} //end of the function AAS_ValidEntity
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_TransformPlane(int planenum, vec3_t origin, vec3_t angles)
-{
- float newdist, matrix[3][3];
- vec3_t normal;
-
- //rotate the node plane
- VectorCopy(mapplanes[planenum].normal, normal);
- CreateRotationMatrix(angles, matrix);
- RotatePoint(normal, matrix);
- newdist = mapplanes[planenum].dist + DotProduct(normal, origin);
- return FindFloatPlane(normal, newdist);
-} //end of the function AAS_TransformPlane
-//===========================================================================
-// this function sets the func_rotating_door in it's final position
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_PositionFuncRotatingBrush(entity_t *mapent, mapbrush_t *brush)
-{
- int spawnflags, i;
- float distance;
- vec3_t movedir, angles, pos1, pos2;
- side_t *s;
-
- spawnflags = FloatForKey(mapent, "spawnflags");
- VectorClear(movedir);
- if (spawnflags & DOOR_X_AXIS)
- movedir[2] = 1.0; //roll
- else if (spawnflags & DOOR_Y_AXIS)
- movedir[0] = 1.0; //pitch
- else // Z_AXIS
- movedir[1] = 1.0; //yaw
-
- // check for reverse rotation
- if (spawnflags & DOOR_REVERSE)
- VectorInverse(movedir);
-
- distance = FloatForKey(mapent, "distance");
- if (!distance) distance = 90;
-
- GetVectorForKey(mapent, "angles", angles);
- VectorCopy(angles, pos1);
- VectorMA(angles, -distance, movedir, pos2);
- // if it starts open, switch the positions
- if (spawnflags & DOOR_START_OPEN)
- {
- VectorCopy(pos2, angles);
- VectorCopy(pos1, pos2);
- VectorCopy(angles, pos1);
- VectorInverse(movedir);
- } //end if
- //
- for (i = 0; i < brush->numsides; i++)
- {
- s = &brush->original_sides[i];
- s->planenum = AAS_TransformPlane(s->planenum, mapent->origin, pos2);
- } //end for
- //
- FreeBrushWindings(brush);
- AAS_MakeBrushWindings(brush);
- AddBrushBevels(brush);
- FreeBrushWindings(brush);
-} //end of the function AAS_PositionFuncRotatingBrush
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_PositionBrush(entity_t *mapent, mapbrush_t *brush)
-{
- side_t *s;
- float newdist;
- int i, notteam;
- char *model;
-
- if (!strcmp(ValueForKey(mapent, "classname"), "func_door_rotating"))
- {
- AAS_PositionFuncRotatingBrush(mapent, brush);
- } //end if
- else
- {
- if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2])
- {
- for (i = 0; i < brush->numsides; i++)
- {
- s = &brush->original_sides[i];
- newdist = mapplanes[s->planenum].dist +
- DotProduct(mapplanes[s->planenum].normal, mapent->origin);
- s->planenum = FindFloatPlane(mapplanes[s->planenum].normal, newdist);
- } //end for
- } //end if
- //if it's a trigger hurt
- if (!strcmp("trigger_hurt", ValueForKey(mapent, "classname")))
- {
- notteam = FloatForKey(mapent, "bot_notteam");
- if ( notteam == 1 ) {
- brush->contents |= CONTENTS_NOTTEAM1;
- }
- else if ( notteam == 2 ) {
- brush->contents |= CONTENTS_NOTTEAM2;
- }
- else {
- // always avoid so set lava contents
- brush->contents |= CONTENTS_LAVA;
- }
- } //end if
- //
- else if (!strcmp("trigger_push", ValueForKey(mapent, "classname")))
- {
- //set the jumppad contents
- brush->contents = CONTENTS_JUMPPAD;
- //Log_Print("found trigger_push brush\n");
- } //end if
- //
- else if (!strcmp("trigger_multiple", ValueForKey(mapent, "classname")))
- {
- //set teleporter contents
- brush->contents = CONTENTS_TELEPORTER;
- //Log_Print("found trigger_multiple teleporter brush\n");
- } //end if
- //
- else if (!strcmp("trigger_teleport", ValueForKey(mapent, "classname")))
- {
- //set teleporter contents
- brush->contents = CONTENTS_TELEPORTER;
- //Log_Print("found trigger_teleport teleporter brush\n");
- } //end if
- else if (!strcmp("func_door", ValueForKey(mapent, "classname")))
- {
- //set mover contents
- brush->contents = CONTENTS_MOVER;
- //get the model number
- model = ValueForKey(mapent, "model");
- brush->modelnum = atoi(model+1);
- } //end if
- } //end else
-} //end of the function AAS_PositionBrush
-//===========================================================================
-// uses the global cfg_t cfg
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_CreateMapBrushes(mapbrush_t *brush, entity_t *mapent, int addbevels)
-{
- int i;
- //side_t *s;
- mapbrush_t *bboxbrushes[16];
-
- //if the brushes are not from an entity used for AAS
- if (!AAS_ValidEntity(mapent))
- {
- nummapbrushsides -= brush->numsides;
- brush->numsides = 0;
- return;
- } //end if
- //
- AAS_PositionBrush(mapent, brush);
- //from all normal solid brushes only the textured brush sides will
- //be used as bsp splitters, so set the right texinfo reference here
- AAS_SetTexinfo(brush);
- //remove contents detail flag, otherwise player clip contents won't be
- //bsped correctly for AAS!
- brush->contents &= ~CONTENTS_DETAIL;
- //if the brush has contents area portal it should be the only contents
- if (brush->contents & (CONTENTS_AREAPORTAL|CONTENTS_CLUSTERPORTAL))
- {
- brush->contents = CONTENTS_CLUSTERPORTAL;
- brush->leafnum = -1;
- } //end if
- //window and playerclip are used for player clipping, make them solid
- if (brush->contents & (CONTENTS_WINDOW | CONTENTS_PLAYERCLIP))
- {
- //
- brush->contents &= ~(CONTENTS_WINDOW | CONTENTS_PLAYERCLIP);
- brush->contents |= CONTENTS_SOLID;
- brush->leafnum = -1;
- } //end if
- //
- if (brush->contents & CONTENTS_BOTCLIP)
- {
- brush->contents = CONTENTS_SOLID;
- brush->leafnum = -1;
- } //end if
- //
- //Log_Write("brush %d contents = ", brush->brushnum);
- //PrintContents(brush->contents);
- //Log_Write("\r\n");
- //if not one of the following brushes then the brush is NOT used for AAS
- if (!(brush->contents & (CONTENTS_SOLID
- | CONTENTS_LADDER
- | CONTENTS_CLUSTERPORTAL
- | CONTENTS_DONOTENTER
- | CONTENTS_TELEPORTER
- | CONTENTS_JUMPPAD
- | CONTENTS_WATER
- | CONTENTS_LAVA
- | CONTENTS_SLIME
- | CONTENTS_MOVER
- )))
- {
- nummapbrushsides -= brush->numsides;
- brush->numsides = 0;
- return;
- } //end if
- //fix the map brush
- //AAS_FixMapBrush(brush);
- //if brush bevels should be added (for real map brushes, not bsp map brushes)
- if (addbevels)
- {
- //NOTE: we first have to get the mins and maxs of the brush before
- // creating the brush bevels... the mins and maxs are used to
- // create them. so we call MakeBrushWindings to get the mins
- // and maxs and then after creating the bevels we free the
- // windings because they are created for all sides (including
- // bevels) a little later
- AAS_MakeBrushWindings(brush);
- AddBrushBevels(brush);
- FreeBrushWindings(brush);
- } //end if
- //NOTE: add the brush to the WORLD entity!!!
- mapent = &entities[0];
- //there's at least one new brush for now
- nummapbrushes++;
- mapent->numbrushes++;
- //liquid brushes are expanded for the maximum possible bounding box
- if (brush->contents & (CONTENTS_WATER
- | CONTENTS_LAVA
- | CONTENTS_SLIME
- | CONTENTS_TELEPORTER
- | CONTENTS_JUMPPAD
- | CONTENTS_DONOTENTER
- | CONTENTS_MOVER
- ))
- {
- brush->expansionbbox = 0;
- //NOTE: the first bounding box is the max
- //FIXME: use max bounding box created from all bboxes
- AAS_ExpandMapBrush(brush, cfg.bboxes[0].mins, cfg.bboxes[0].maxs);
- AAS_MakeBrushWindings(brush);
- } //end if
- //area portal brushes are NOT expanded
- else if (brush->contents & CONTENTS_CLUSTERPORTAL)
- {
- brush->expansionbbox = 0;
- //NOTE: the first bounding box is the max
- //FIXME: use max bounding box created from all bboxes
- AAS_ExpandMapBrush(brush, cfg.bboxes[0].mins, cfg.bboxes[0].maxs);
- AAS_MakeBrushWindings(brush);
- } //end if
- //all solid brushes are expanded for all bounding boxes
- else if (brush->contents & (CONTENTS_SOLID
- | CONTENTS_LADDER
- ))
- {
- //brush for the first bounding box
- bboxbrushes[0] = brush;
- //make a copy for the other bounding boxes
- for (i = 1; i < cfg.numbboxes; i++)
- {
- bboxbrushes[i] = AAS_CopyMapBrush(brush, mapent);
- } //end for
- //expand every brush for it's bounding box and create windings
- for (i = 0; i < cfg.numbboxes; i++)
- {
- AAS_ExpandMapBrush(bboxbrushes[i], cfg.bboxes[i].mins, cfg.bboxes[i].maxs);
- bboxbrushes[i]->expansionbbox = cfg.bboxes[i].presencetype;
- AAS_MakeBrushWindings(bboxbrushes[i]);
- } //end for
- } //end else
-} //end of the function AAS_CreateMapBrushes
+/*
+===========================================================================
+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 "l_mem.h"
+#include "../botlib/aasfile.h" //aas_bbox_t
+#include "aas_store.h" //AAS_MAX_BBOXES
+#include "aas_cfg.h"
+#include "../game/surfaceflags.h"
+
+#define SPAWNFLAG_NOT_EASY 0x00000100
+#define SPAWNFLAG_NOT_MEDIUM 0x00000200
+#define SPAWNFLAG_NOT_HARD 0x00000400
+#define SPAWNFLAG_NOT_DEATHMATCH 0x00000800
+#define SPAWNFLAG_NOT_COOP 0x00001000
+
+#define STATE_TOP 0
+#define STATE_BOTTOM 1
+#define STATE_UP 2
+#define STATE_DOWN 3
+
+#define DOOR_START_OPEN 1
+#define DOOR_REVERSE 2
+#define DOOR_CRUSHER 4
+#define DOOR_NOMONSTER 8
+#define DOOR_TOGGLE 32
+#define DOOR_X_AXIS 64
+#define DOOR_Y_AXIS 128
+
+#define BBOX_NORMAL_EPSILON 0.0001
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+vec_t BoxOriginDistanceFromPlane(vec3_t normal, vec3_t mins, vec3_t maxs, int side)
+{
+ vec3_t v1, v2;
+ int i;
+
+ if (side)
+ {
+ for (i = 0; i < 3; i++)
+ {
+ if (normal[i] > BBOX_NORMAL_EPSILON) v1[i] = maxs[i];
+ else if (normal[i] < -BBOX_NORMAL_EPSILON) v1[i] = mins[i];
+ else v1[i] = 0;
+ } //end for
+ } //end if
+ else
+ {
+ for (i = 0; i < 3; i++)
+ {
+ if (normal[i] > BBOX_NORMAL_EPSILON) v1[i] = mins[i];
+ else if (normal[i] < -BBOX_NORMAL_EPSILON) v1[i] = maxs[i];
+ else v1[i] = 0;
+ } //end for
+ } //end else
+ VectorCopy(normal, v2);
+ VectorInverse(v2);
+ return DotProduct(v1, v2);
+} //end of the function BoxOriginDistanceFromPlane
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+vec_t CapsuleOriginDistanceFromPlane(vec3_t normal, vec3_t mins, vec3_t maxs)
+{
+ float offset_up, offset_down, width, radius;
+
+ width = maxs[0] - mins[0];
+ // if the box is less high then it is wide
+ if (maxs[2] - mins[2] < width) {
+ width = maxs[2] - mins[2];
+ }
+ radius = width * 0.5;
+ // offset to upper and lower sphere
+ offset_up = maxs[2] - radius;
+ offset_down = -mins[2] - radius;
+
+ // if normal points upward
+ if ( normal[2] > 0 ) {
+ // touches lower sphere first
+ return normal[2] * offset_down + radius;
+ }
+ else {
+ // touched upper sphere first
+ return -normal[2] * offset_up + radius;
+ }
+}
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_ExpandMapBrush(mapbrush_t *brush, vec3_t mins, vec3_t maxs)
+{
+ int sn;
+ float dist;
+ side_t *s;
+ plane_t *plane;
+
+ for (sn = 0; sn < brush->numsides; sn++)
+ {
+ s = brush->original_sides + sn;
+ plane = &mapplanes[s->planenum];
+ dist = plane->dist;
+ if (capsule_collision) {
+ dist += CapsuleOriginDistanceFromPlane(plane->normal, mins, maxs);
+ }
+ else {
+ dist += BoxOriginDistanceFromPlane(plane->normal, mins, maxs, 0);
+ }
+ s->planenum = FindFloatPlane(plane->normal, dist);
+ //the side isn't a bevel after expanding
+ s->flags &= ~SFL_BEVEL;
+ //don't skip the surface
+ s->surf &= ~SURF_SKIP;
+ //make sure the texinfo is not TEXINFO_NODE
+ //when player clip contents brushes are read from the bsp tree
+ //they have the texinfo field set to TEXINFO_NODE
+ //s->texinfo = 0;
+ } //end for
+} //end of the function AAS_ExpandMapBrush
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_SetTexinfo(mapbrush_t *brush)
+{
+ int n;
+ side_t *side;
+
+ if (brush->contents & (CONTENTS_LADDER
+ | CONTENTS_AREAPORTAL
+ | CONTENTS_CLUSTERPORTAL
+ | CONTENTS_TELEPORTER
+ | CONTENTS_JUMPPAD
+ | CONTENTS_DONOTENTER
+ | CONTENTS_WATER
+ | CONTENTS_LAVA
+ | CONTENTS_SLIME
+ | CONTENTS_WINDOW
+ | CONTENTS_PLAYERCLIP))
+ {
+ //we just set texinfo to 0 because these brush sides MUST be used as
+ //bsp splitters textured or not textured
+ for (n = 0; n < brush->numsides; n++)
+ {
+ side = brush->original_sides + n;
+ //side->flags |= SFL_TEXTURED|SFL_VISIBLE;
+ side->texinfo = 0;
+ } //end for
+ } //end if
+ else
+ {
+ //only use brush sides as splitters if they are textured
+ //texinfo of non-textured sides will be set to TEXINFO_NODE
+ for (n = 0; n < brush->numsides; n++)
+ {
+ side = brush->original_sides + n;
+ //don't use side as splitter (set texinfo to TEXINFO_NODE) if not textured
+ if (side->flags & (SFL_TEXTURED|SFL_BEVEL)) side->texinfo = 0;
+ else side->texinfo = TEXINFO_NODE;
+ } //end for
+ } //end else
+} //end of the function AAS_SetTexinfo
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void FreeBrushWindings(mapbrush_t *brush)
+{
+ int n;
+ side_t *side;
+ //
+ for (n = 0; n < brush->numsides; n++)
+ {
+ side = brush->original_sides + n;
+ //
+ if (side->winding) FreeWinding(side->winding);
+ } //end for
+} //end of the function FreeBrushWindings
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_AddMapBrushSide(mapbrush_t *brush, int planenum)
+{
+ side_t *side;
+ //
+ if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
+ Error ("MAX_MAPFILE_BRUSHSIDES");
+ //
+ side = brush->original_sides + brush->numsides;
+ side->original = NULL;
+ side->winding = NULL;
+ side->contents = brush->contents;
+ side->flags &= ~(SFL_BEVEL|SFL_VISIBLE);
+ side->surf = 0;
+ side->planenum = planenum;
+ side->texinfo = 0;
+ //
+ nummapbrushsides++;
+ brush->numsides++;
+} //end of the function AAS_AddMapBrushSide
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_FixMapBrush(mapbrush_t *brush)
+{
+ int i, j, planenum;
+ float dist;
+ winding_t *w;
+ plane_t *plane, *plane1, *plane2;
+ side_t *side;
+ vec3_t normal;
+
+ //calculate the brush bounds
+ ClearBounds(brush->mins, brush->maxs);
+ for (i = 0; i < brush->numsides; i++)
+ {
+ plane = &mapplanes[brush->original_sides[i].planenum];
+ w = BaseWindingForPlane(plane->normal, plane->dist);
+ for (j = 0; j < brush->numsides && w; j++)
+ {
+ if (i == j) continue;
+ //there are no brush bevels marked but who cares :)
+ if (brush->original_sides[j].flags & SFL_BEVEL) continue;
+ plane = &mapplanes[brush->original_sides[j].planenum^1];
+ ChopWindingInPlace(&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
+ } //end for
+
+ side = &brush->original_sides[i];
+ side->winding = w;
+ if (w)
+ {
+ for (j = 0; j < w->numpoints; j++)
+ {
+ AddPointToBounds(w->p[j], brush->mins, brush->maxs);
+ } //end for
+ } //end if
+ } //end for
+ //
+ for (i = 0; i < brush->numsides; i++)
+ {
+ for (j = 0; j < brush->numsides; j++)
+ {
+ if (i == j) continue;
+ plane1 = &mapplanes[brush->original_sides[i].planenum];
+ plane2 = &mapplanes[brush->original_sides[j].planenum];
+ if (WindingsNonConvex(brush->original_sides[i].winding,
+ brush->original_sides[j].winding,
+ plane1->normal, plane2->normal,
+ plane1->dist, plane2->dist))
+ {
+ Log_Print("non convex brush");
+ } //end if
+ } //end for
+ } //end for
+
+ //NOW close the fucking brush!!
+ for (i = 0; i < 3; i++)
+ {
+ if (brush->mins[i] < -MAX_MAP_BOUNDS)
+ {
+ VectorClear(normal);
+ normal[i] = -1;
+ dist = MAX_MAP_BOUNDS - 10;
+ planenum = FindFloatPlane(normal, dist);
+ //
+ Log_Print("mins out of range: added extra brush side\n");
+ AAS_AddMapBrushSide(brush, planenum);
+ } //end if
+ if (brush->maxs[i] > MAX_MAP_BOUNDS)
+ {
+ VectorClear(normal);
+ normal[i] = 1;
+ dist = MAX_MAP_BOUNDS - 10;
+ planenum = FindFloatPlane(normal, dist);
+ //
+ Log_Print("maxs out of range: added extra brush side\n");
+ AAS_AddMapBrushSide(brush, planenum);
+ } //end if
+ if (brush->mins[i] > MAX_MAP_BOUNDS || brush->maxs[i] < -MAX_MAP_BOUNDS)
+ {
+ Log_Print("entity %i, brush %i: no visible sides on brush\n", brush->entitynum, brush->brushnum);
+ } //end if
+ } //end for
+ //free all the windings
+ FreeBrushWindings(brush);
+} //end of the function AAS_FixMapBrush
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+qboolean AAS_MakeBrushWindings(mapbrush_t *ob)
+{
+ int i, j;
+ winding_t *w;
+ side_t *side;
+ plane_t *plane, *plane1, *plane2;
+
+ ClearBounds (ob->mins, ob->maxs);
+
+ for (i = 0; i < ob->numsides; i++)
+ {
+ plane = &mapplanes[ob->original_sides[i].planenum];
+ w = BaseWindingForPlane(plane->normal, plane->dist);
+ for (j = 0; j <ob->numsides && w; j++)
+ {
+ if (i == j) continue;
+ if (ob->original_sides[j].flags & SFL_BEVEL) continue;
+ plane = &mapplanes[ob->original_sides[j].planenum^1];
+ ChopWindingInPlace(&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
+ }
+
+ side = &ob->original_sides[i];
+ side->winding = w;
+ if (w)
+ {
+ side->flags |= SFL_VISIBLE;
+ for (j = 0; j < w->numpoints; j++)
+ AddPointToBounds (w->p[j], ob->mins, ob->maxs);
+ }
+ }
+ //check if the brush is convex
+ for (i = 0; i < ob->numsides; i++)
+ {
+ for (j = 0; j < ob->numsides; j++)
+ {
+ if (i == j) continue;
+ plane1 = &mapplanes[ob->original_sides[i].planenum];
+ plane2 = &mapplanes[ob->original_sides[j].planenum];
+ if (WindingsNonConvex(ob->original_sides[i].winding,
+ ob->original_sides[j].winding,
+ plane1->normal, plane2->normal,
+ plane1->dist, plane2->dist))
+ {
+ Log_Print("non convex brush");
+ } //end if
+ } //end for
+ } //end for
+ //check for out of bound brushes
+ for (i = 0; i < 3; i++)
+ {
+ //IDBUG: all the indexes into the mins and maxs were zero (not using i)
+ if (ob->mins[i] < -MAX_MAP_BOUNDS || ob->maxs[i] > MAX_MAP_BOUNDS)
+ {
+ Log_Print("entity %i, brush %i: bounds out of range\n", ob->entitynum, ob->brushnum);
+ Log_Print("ob->mins[%d] = %f, ob->maxs[%d] = %f\n", i, ob->mins[i], i, ob->maxs[i]);
+ ob->numsides = 0; //remove the brush
+ break;
+ } //end if
+ if (ob->mins[i] > MAX_MAP_BOUNDS || ob->maxs[i] < -MAX_MAP_BOUNDS)
+ {
+ Log_Print("entity %i, brush %i: no visible sides on brush\n", ob->entitynum, ob->brushnum);
+ Log_Print("ob->mins[%d] = %f, ob->maxs[%d] = %f\n", i, ob->mins[i], i, ob->maxs[i]);
+ ob->numsides = 0; //remove the brush
+ break;
+ } //end if
+ } //end for
+ return true;
+} //end of the function AAS_MakeBrushWindings
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+mapbrush_t *AAS_CopyMapBrush(mapbrush_t *brush, entity_t *mapent)
+{
+ int n;
+ mapbrush_t *newbrush;
+ side_t *side, *newside;
+
+ if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
+ Error ("MAX_MAPFILE_BRUSHES");
+
+ newbrush = &mapbrushes[nummapbrushes];
+ newbrush->original_sides = &brushsides[nummapbrushsides];
+ newbrush->entitynum = brush->entitynum;
+ newbrush->brushnum = nummapbrushes - mapent->firstbrush;
+ newbrush->numsides = brush->numsides;
+ newbrush->contents = brush->contents;
+
+ //copy the sides
+ for (n = 0; n < brush->numsides; n++)
+ {
+ if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
+ Error ("MAX_MAPFILE_BRUSHSIDES");
+ side = brush->original_sides + n;
+
+ newside = newbrush->original_sides + n;
+ newside->original = NULL;
+ newside->winding = NULL;
+ newside->contents = side->contents;
+ newside->flags = side->flags;
+ newside->surf = side->surf;
+ newside->planenum = side->planenum;
+ newside->texinfo = side->texinfo;
+ nummapbrushsides++;
+ } //end for
+ //
+ nummapbrushes++;
+ mapent->numbrushes++;
+ return newbrush;
+} //end of the function AAS_CopyMapBrush
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int mark_entities[MAX_MAP_ENTITIES];
+
+int AAS_AlwaysTriggered_r(char *targetname)
+{
+ int i;
+
+ if (!strlen(targetname)) {
+ return false;
+ }
+ //
+ for (i = 0; i < num_entities; i++) {
+ // if the entity will activate the given targetname
+ if ( !strcmp(targetname, ValueForKey(&entities[i], "target")) ) {
+ // if this activator is present in deathmatch
+ if (!(atoi(ValueForKey(&entities[i], "spawnflags")) & SPAWNFLAG_NOT_DEATHMATCH)) {
+ // if it is a trigger_always entity
+ if (!strcmp("trigger_always", ValueForKey(&entities[i], "classname"))) {
+ return true;
+ }
+ // check for possible trigger_always entities activating this entity
+ if ( mark_entities[i] ) {
+ Warning( "entity %d, classname %s has recursive targetname %s\n", i,
+ ValueForKey(&entities[i], "classname"), targetname );
+ return false;
+ }
+ mark_entities[i] = true;
+ if ( AAS_AlwaysTriggered_r(ValueForKey(&entities[i], "targetname")) ) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+int AAS_AlwaysTriggered(char *targetname) {
+ memset( mark_entities, 0, sizeof(mark_entities) );
+ return AAS_AlwaysTriggered_r( targetname );
+}
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int AAS_ValidEntity(entity_t *mapent)
+{
+ int i;
+ char target[1024];
+
+ //all world brushes are used for AAS
+ if (mapent == &entities[0])
+ {
+ return true;
+ } //end if
+ //some of the func_wall brushes are also used for AAS
+ else if (!strcmp("func_wall", ValueForKey(mapent, "classname")))
+ {
+ //Log_Print("found func_wall entity %d\n", mapent - entities);
+ //if the func wall is used in deathmatch
+ if (!(atoi(ValueForKey(mapent, "spawnflags")) & SPAWNFLAG_NOT_DEATHMATCH))
+ {
+ //Log_Print("func_wall USED in deathmatch mode %d\n", atoi(ValueForKey(mapent, "spawnflags")));
+ return true;
+ } //end if
+ } //end else if
+ else if (!strcmp("func_door_rotating", ValueForKey(mapent, "classname")))
+ {
+ //if the func_door_rotating is present in deathmatch
+ if (!(atoi(ValueForKey(mapent, "spawnflags")) & SPAWNFLAG_NOT_DEATHMATCH))
+ {
+ //if the func_door_rotating is always activated in deathmatch
+ if (AAS_AlwaysTriggered(ValueForKey(mapent, "targetname")))
+ {
+ //Log_Print("found func_door_rotating in deathmatch\ntargetname %s\n", ValueForKey(mapent, "targetname"));
+ return true;
+ } //end if
+ } //end if
+ } //end else if
+ else if (!strcmp("trigger_hurt", ValueForKey(mapent, "classname")))
+ {
+ //"dmg" is the damage, for instance: "dmg" "666"
+ return true;
+ } //end else if
+ else if (!strcmp("trigger_push", ValueForKey(mapent, "classname")))
+ {
+ return true;
+ } //end else if
+ else if (!strcmp("trigger_multiple", ValueForKey(mapent, "classname")))
+ {
+ //find out if the trigger_multiple is pointing to a target_teleporter
+ strcpy(target, ValueForKey(mapent, "target"));
+ for (i = 0; i < num_entities; i++)
+ {
+ //if the entity will activate the given targetname
+ if (!strcmp(target, ValueForKey(&entities[i], "targetname")))
+ {
+ if (!strcmp("target_teleporter", ValueForKey(&entities[i], "classname")))
+ {
+ return true;
+ } //end if
+ } //end if
+ } //end for
+ } //end else if
+ else if (!strcmp("trigger_teleport", ValueForKey(mapent, "classname")))
+ {
+ return true;
+ } //end else if
+ else if (!strcmp("func_static", ValueForKey(mapent, "classname")))
+ {
+ //FIXME: easy/medium/hard/deathmatch specific?
+ return true;
+ } //end else if
+ else if (!strcmp("func_door", ValueForKey(mapent, "classname")))
+ {
+ return true;
+ } //end else if
+ return false;
+} //end of the function AAS_ValidEntity
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int AAS_TransformPlane(int planenum, vec3_t origin, vec3_t angles)
+{
+ float newdist, matrix[3][3];
+ vec3_t normal;
+
+ //rotate the node plane
+ VectorCopy(mapplanes[planenum].normal, normal);
+ CreateRotationMatrix(angles, matrix);
+ RotatePoint(normal, matrix);
+ newdist = mapplanes[planenum].dist + DotProduct(normal, origin);
+ return FindFloatPlane(normal, newdist);
+} //end of the function AAS_TransformPlane
+//===========================================================================
+// this function sets the func_rotating_door in it's final position
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_PositionFuncRotatingBrush(entity_t *mapent, mapbrush_t *brush)
+{
+ int spawnflags, i;
+ float distance;
+ vec3_t movedir, angles, pos1, pos2;
+ side_t *s;
+
+ spawnflags = FloatForKey(mapent, "spawnflags");
+ VectorClear(movedir);
+ if (spawnflags & DOOR_X_AXIS)
+ movedir[2] = 1.0; //roll
+ else if (spawnflags & DOOR_Y_AXIS)
+ movedir[0] = 1.0; //pitch
+ else // Z_AXIS
+ movedir[1] = 1.0; //yaw
+
+ // check for reverse rotation
+ if (spawnflags & DOOR_REVERSE)
+ VectorInverse(movedir);
+
+ distance = FloatForKey(mapent, "distance");
+ if (!distance) distance = 90;
+
+ GetVectorForKey(mapent, "angles", angles);
+ VectorCopy(angles, pos1);
+ VectorMA(angles, -distance, movedir, pos2);
+ // if it starts open, switch the positions
+ if (spawnflags & DOOR_START_OPEN)
+ {
+ VectorCopy(pos2, angles);
+ VectorCopy(pos1, pos2);
+ VectorCopy(angles, pos1);
+ VectorInverse(movedir);
+ } //end if
+ //
+ for (i = 0; i < brush->numsides; i++)
+ {
+ s = &brush->original_sides[i];
+ s->planenum = AAS_TransformPlane(s->planenum, mapent->origin, pos2);
+ } //end for
+ //
+ FreeBrushWindings(brush);
+ AAS_MakeBrushWindings(brush);
+ AddBrushBevels(brush);
+ FreeBrushWindings(brush);
+} //end of the function AAS_PositionFuncRotatingBrush
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_PositionBrush(entity_t *mapent, mapbrush_t *brush)
+{
+ side_t *s;
+ float newdist;
+ int i, notteam;
+ char *model;
+
+ if (!strcmp(ValueForKey(mapent, "classname"), "func_door_rotating"))
+ {
+ AAS_PositionFuncRotatingBrush(mapent, brush);
+ } //end if
+ else
+ {
+ if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2])
+ {
+ for (i = 0; i < brush->numsides; i++)
+ {
+ s = &brush->original_sides[i];
+ newdist = mapplanes[s->planenum].dist +
+ DotProduct(mapplanes[s->planenum].normal, mapent->origin);
+ s->planenum = FindFloatPlane(mapplanes[s->planenum].normal, newdist);
+ } //end for
+ } //end if
+ //if it's a trigger hurt
+ if (!strcmp("trigger_hurt", ValueForKey(mapent, "classname")))
+ {
+ notteam = FloatForKey(mapent, "bot_notteam");
+ if ( notteam == 1 ) {
+ brush->contents |= CONTENTS_NOTTEAM1;
+ }
+ else if ( notteam == 2 ) {
+ brush->contents |= CONTENTS_NOTTEAM2;
+ }
+ else {
+ // always avoid so set lava contents
+ brush->contents |= CONTENTS_LAVA;
+ }
+ } //end if
+ //
+ else if (!strcmp("trigger_push", ValueForKey(mapent, "classname")))
+ {
+ //set the jumppad contents
+ brush->contents = CONTENTS_JUMPPAD;
+ //Log_Print("found trigger_push brush\n");
+ } //end if
+ //
+ else if (!strcmp("trigger_multiple", ValueForKey(mapent, "classname")))
+ {
+ //set teleporter contents
+ brush->contents = CONTENTS_TELEPORTER;
+ //Log_Print("found trigger_multiple teleporter brush\n");
+ } //end if
+ //
+ else if (!strcmp("trigger_teleport", ValueForKey(mapent, "classname")))
+ {
+ //set teleporter contents
+ brush->contents = CONTENTS_TELEPORTER;
+ //Log_Print("found trigger_teleport teleporter brush\n");
+ } //end if
+ else if (!strcmp("func_door", ValueForKey(mapent, "classname")))
+ {
+ //set mover contents
+ brush->contents = CONTENTS_MOVER;
+ //get the model number
+ model = ValueForKey(mapent, "model");
+ brush->modelnum = atoi(model+1);
+ } //end if
+ } //end else
+} //end of the function AAS_PositionBrush
+//===========================================================================
+// uses the global cfg_t cfg
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_CreateMapBrushes(mapbrush_t *brush, entity_t *mapent, int addbevels)
+{
+ int i;
+ //side_t *s;
+ mapbrush_t *bboxbrushes[16];
+
+ //if the brushes are not from an entity used for AAS
+ if (!AAS_ValidEntity(mapent))
+ {
+ nummapbrushsides -= brush->numsides;
+ brush->numsides = 0;
+ return;
+ } //end if
+ //
+ AAS_PositionBrush(mapent, brush);
+ //from all normal solid brushes only the textured brush sides will
+ //be used as bsp splitters, so set the right texinfo reference here
+ AAS_SetTexinfo(brush);
+ //remove contents detail flag, otherwise player clip contents won't be
+ //bsped correctly for AAS!
+ brush->contents &= ~CONTENTS_DETAIL;
+ //if the brush has contents area portal it should be the only contents
+ if (brush->contents & (CONTENTS_AREAPORTAL|CONTENTS_CLUSTERPORTAL))
+ {
+ brush->contents = CONTENTS_CLUSTERPORTAL;
+ brush->leafnum = -1;
+ } //end if
+ //window and playerclip are used for player clipping, make them solid
+ if (brush->contents & (CONTENTS_WINDOW | CONTENTS_PLAYERCLIP))
+ {
+ //
+ brush->contents &= ~(CONTENTS_WINDOW | CONTENTS_PLAYERCLIP);
+ brush->contents |= CONTENTS_SOLID;
+ brush->leafnum = -1;
+ } //end if
+ //
+ if (brush->contents & CONTENTS_BOTCLIP)
+ {
+ brush->contents = CONTENTS_SOLID;
+ brush->leafnum = -1;
+ } //end if
+ //
+ //Log_Write("brush %d contents = ", brush->brushnum);
+ //PrintContents(brush->contents);
+ //Log_Write("\r\n");
+ //if not one of the following brushes then the brush is NOT used for AAS
+ if (!(brush->contents & (CONTENTS_SOLID
+ | CONTENTS_LADDER
+ | CONTENTS_CLUSTERPORTAL
+ | CONTENTS_DONOTENTER
+ | CONTENTS_TELEPORTER
+ | CONTENTS_JUMPPAD
+ | CONTENTS_WATER
+ | CONTENTS_LAVA
+ | CONTENTS_SLIME
+ | CONTENTS_MOVER
+ )))
+ {
+ nummapbrushsides -= brush->numsides;
+ brush->numsides = 0;
+ return;
+ } //end if
+ //fix the map brush
+ //AAS_FixMapBrush(brush);
+ //if brush bevels should be added (for real map brushes, not bsp map brushes)
+ if (addbevels)
+ {
+ //NOTE: we first have to get the mins and maxs of the brush before
+ // creating the brush bevels... the mins and maxs are used to
+ // create them. so we call MakeBrushWindings to get the mins
+ // and maxs and then after creating the bevels we free the
+ // windings because they are created for all sides (including
+ // bevels) a little later
+ AAS_MakeBrushWindings(brush);
+ AddBrushBevels(brush);
+ FreeBrushWindings(brush);
+ } //end if
+ //NOTE: add the brush to the WORLD entity!!!
+ mapent = &entities[0];
+ //there's at least one new brush for now
+ nummapbrushes++;
+ mapent->numbrushes++;
+ //liquid brushes are expanded for the maximum possible bounding box
+ if (brush->contents & (CONTENTS_WATER
+ | CONTENTS_LAVA
+ | CONTENTS_SLIME
+ | CONTENTS_TELEPORTER
+ | CONTENTS_JUMPPAD
+ | CONTENTS_DONOTENTER
+ | CONTENTS_MOVER
+ ))
+ {
+ brush->expansionbbox = 0;
+ //NOTE: the first bounding box is the max
+ //FIXME: use max bounding box created from all bboxes
+ AAS_ExpandMapBrush(brush, cfg.bboxes[0].mins, cfg.bboxes[0].maxs);
+ AAS_MakeBrushWindings(brush);
+ } //end if
+ //area portal brushes are NOT expanded
+ else if (brush->contents & CONTENTS_CLUSTERPORTAL)
+ {
+ brush->expansionbbox = 0;
+ //NOTE: the first bounding box is the max
+ //FIXME: use max bounding box created from all bboxes
+ AAS_ExpandMapBrush(brush, cfg.bboxes[0].mins, cfg.bboxes[0].maxs);
+ AAS_MakeBrushWindings(brush);
+ } //end if
+ //all solid brushes are expanded for all bounding boxes
+ else if (brush->contents & (CONTENTS_SOLID
+ | CONTENTS_LADDER
+ ))
+ {
+ //brush for the first bounding box
+ bboxbrushes[0] = brush;
+ //make a copy for the other bounding boxes
+ for (i = 1; i < cfg.numbboxes; i++)
+ {
+ bboxbrushes[i] = AAS_CopyMapBrush(brush, mapent);
+ } //end for
+ //expand every brush for it's bounding box and create windings
+ for (i = 0; i < cfg.numbboxes; i++)
+ {
+ AAS_ExpandMapBrush(bboxbrushes[i], cfg.bboxes[i].mins, cfg.bboxes[i].maxs);
+ bboxbrushes[i]->expansionbbox = cfg.bboxes[i].presencetype;
+ AAS_MakeBrushWindings(bboxbrushes[i]);
+ } //end for
+ } //end else
+} //end of the function AAS_CreateMapBrushes
diff --git a/code/bspc/aas_map.h b/code/bspc/aas_map.h
index 601cdfb..181f711 100755
--- a/code/bspc/aas_map.h
+++ b/code/bspc/aas_map.h
@@ -1,23 +1,23 @@
-/*
-===========================================================================
-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_CreateMapBrushes(mapbrush_t *brush, entity_t *mapent, int addbevels);
+/*
+===========================================================================
+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_CreateMapBrushes(mapbrush_t *brush, entity_t *mapent, int addbevels);
diff --git a/code/bspc/aas_prunenodes.c b/code/bspc/aas_prunenodes.c
index a03e9d2..1ba292a 100755
--- a/code/bspc/aas_prunenodes.c
+++ b/code/bspc/aas_prunenodes.c
@@ -1,89 +1,89 @@
-/*
-===========================================================================
-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"
-
-int c_numprunes;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-tmp_node_t *AAS_PruneNodes_r(tmp_node_t *tmpnode)
-{
- tmp_area_t *tmparea1, *tmparea2;
-
- //if it is a solid leaf
- if (!tmpnode) return NULL;
- //
- if (tmpnode->tmparea) return tmpnode;
- //process the children first
- tmpnode->children[0] = AAS_PruneNodes_r(tmpnode->children[0]);
- tmpnode->children[1] = AAS_PruneNodes_r(tmpnode->children[1]);
- //if both children are areas
- if (tmpnode->children[0] && tmpnode->children[1] &&
- tmpnode->children[0]->tmparea && tmpnode->children[1]->tmparea)
- {
- tmparea1 = tmpnode->children[0]->tmparea;
- while(tmparea1->mergedarea) tmparea1 = tmparea1->mergedarea;
-
- tmparea2 = tmpnode->children[1]->tmparea;
- while(tmparea2->mergedarea) tmparea2 = tmparea2->mergedarea;
-
- if (tmparea1 == tmparea2)
- {
- c_numprunes++;
- tmpnode->tmparea = tmparea1;
- tmpnode->planenum = 0;
- AAS_FreeTmpNode(tmpnode->children[0]);
- AAS_FreeTmpNode(tmpnode->children[1]);
- tmpnode->children[0] = NULL;
- tmpnode->children[1] = NULL;
- return tmpnode;
- } //end if
- } //end if
- //if both solid leafs
- if (!tmpnode->children[0] && !tmpnode->children[1])
- {
- c_numprunes++;
- AAS_FreeTmpNode(tmpnode);
- return NULL;
- } //end if
- //
- return tmpnode;
-} //end of the function AAS_PruneNodes_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_PruneNodes(void)
-{
- Log_Write("AAS_PruneNodes\r\n");
- AAS_PruneNodes_r(tmpaasworld.nodes);
- Log_Print("%6d nodes pruned\r\n", c_numprunes);
-} //end of the function AAS_PruneNodes
+/*
+===========================================================================
+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"
+
+int c_numprunes;
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+tmp_node_t *AAS_PruneNodes_r(tmp_node_t *tmpnode)
+{
+ tmp_area_t *tmparea1, *tmparea2;
+
+ //if it is a solid leaf
+ if (!tmpnode) return NULL;
+ //
+ if (tmpnode->tmparea) return tmpnode;
+ //process the children first
+ tmpnode->children[0] = AAS_PruneNodes_r(tmpnode->children[0]);
+ tmpnode->children[1] = AAS_PruneNodes_r(tmpnode->children[1]);
+ //if both children are areas
+ if (tmpnode->children[0] && tmpnode->children[1] &&
+ tmpnode->children[0]->tmparea && tmpnode->children[1]->tmparea)
+ {
+ tmparea1 = tmpnode->children[0]->tmparea;
+ while(tmparea1->mergedarea) tmparea1 = tmparea1->mergedarea;
+
+ tmparea2 = tmpnode->children[1]->tmparea;
+ while(tmparea2->mergedarea) tmparea2 = tmparea2->mergedarea;
+
+ if (tmparea1 == tmparea2)
+ {
+ c_numprunes++;
+ tmpnode->tmparea = tmparea1;
+ tmpnode->planenum = 0;
+ AAS_FreeTmpNode(tmpnode->children[0]);
+ AAS_FreeTmpNode(tmpnode->children[1]);
+ tmpnode->children[0] = NULL;
+ tmpnode->children[1] = NULL;
+ return tmpnode;
+ } //end if
+ } //end if
+ //if both solid leafs
+ if (!tmpnode->children[0] && !tmpnode->children[1])
+ {
+ c_numprunes++;
+ AAS_FreeTmpNode(tmpnode);
+ return NULL;
+ } //end if
+ //
+ return tmpnode;
+} //end of the function AAS_PruneNodes_r
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_PruneNodes(void)
+{
+ Log_Write("AAS_PruneNodes\r\n");
+ AAS_PruneNodes_r(tmpaasworld.nodes);
+ Log_Print("%6d nodes pruned\r\n", c_numprunes);
+} //end of the function AAS_PruneNodes
diff --git a/code/bspc/aas_prunenodes.h b/code/bspc/aas_prunenodes.h
index 36989ad..9433864 100755
--- a/code/bspc/aas_prunenodes.h
+++ b/code/bspc/aas_prunenodes.h
@@ -1,24 +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_PruneNodes(void);
-
+/*
+===========================================================================
+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_PruneNodes(void);
+
diff --git a/code/bspc/aas_store.c b/code/bspc/aas_store.c
index 4836d51..d549ab7 100755
--- a/code/bspc/aas_store.c
+++ b/code/bspc/aas_store.c
@@ -1,1082 +1,1082 @@
-/*
-===========================================================================
-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
+/*
+===========================================================================
+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
diff --git a/code/bspc/aas_store.h b/code/bspc/aas_store.h
index 26957e4..063adbe 100755
--- a/code/bspc/aas_store.h
+++ b/code/bspc/aas_store.h
@@ -1,107 +1,107 @@
-/*
-===========================================================================
-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 AAS_MAX_BBOXES 5
-#define AAS_MAX_VERTEXES 512000
-#define AAS_MAX_PLANES 65536
-#define AAS_MAX_EDGES 512000
-#define AAS_MAX_EDGEINDEXSIZE 512000
-#define AAS_MAX_FACES 512000
-#define AAS_MAX_FACEINDEXSIZE 512000
-#define AAS_MAX_AREAS 65536
-#define AAS_MAX_AREASETTINGS 65536
-#define AAS_MAX_REACHABILITYSIZE 65536
-#define AAS_MAX_NODES 256000
-#define AAS_MAX_PORTALS 65536
-#define AAS_MAX_PORTALINDEXSIZE 65536
-#define AAS_MAX_CLUSTERS 65536
-
-#define BSPCINCLUDE
-#include "../game/be_aas.h"
-#include "../botlib/be_aas_def.h"
-
-/*
-typedef struct bspc_aas_s
-{
- int loaded;
- int initialized; //true when AAS has been initialized
- int savefile; //set true when file should be saved
- //bounding boxes
- int numbboxes;
- aas_bbox_t *bboxes;
- //vertexes
- int numvertexes;
- aas_vertex_t *vertexes;
- //planes
- int numplanes;
- aas_plane_t *planes;
- //edges
- int numedges;
- aas_edge_t *edges;
- //edge index
- int edgeindexsize;
- aas_edgeindex_t *edgeindex;
- //faces
- int numfaces;
- aas_face_t *faces;
- //face index
- int faceindexsize;
- aas_faceindex_t *faceindex;
- //convex areas
- int numareas;
- aas_area_t *areas;
- //convex area settings
- int numareasettings;
- aas_areasettings_t *areasettings;
- //reachablity list
- int reachabilitysize;
- aas_reachability_t *reachability;
- //nodes of the bsp tree
- int numnodes;
- aas_node_t *nodes;
- //cluster portals
- int numportals;
- aas_portal_t *portals;
- //cluster portal index
- int portalindexsize;
- aas_portalindex_t *portalindex;
- //clusters
- int numclusters;
- aas_cluster_t *clusters;
- //
- int numreachabilityareas;
- float reachabilitytime;
-} bspc_aas_t;
-
-extern bspc_aas_t aasworld;
-//*/
-
-extern aas_t aasworld;
-
-//stores the AAS file from the temporary AAS
-void AAS_StoreFile(char *filename);
-//returns a number of the given plane
-qboolean AAS_FindPlane(vec3_t normal, float dist, int *planenum);
-//allocates the maximum AAS memory for storage
-void AAS_AllocMaxAAS(void);
-//frees the maximum AAS memory for storage
-void AAS_FreeMaxAAS(void);
+/*
+===========================================================================
+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 AAS_MAX_BBOXES 5
+#define AAS_MAX_VERTEXES 512000
+#define AAS_MAX_PLANES 65536
+#define AAS_MAX_EDGES 512000
+#define AAS_MAX_EDGEINDEXSIZE 512000
+#define AAS_MAX_FACES 512000
+#define AAS_MAX_FACEINDEXSIZE 512000
+#define AAS_MAX_AREAS 65536
+#define AAS_MAX_AREASETTINGS 65536
+#define AAS_MAX_REACHABILITYSIZE 65536
+#define AAS_MAX_NODES 256000
+#define AAS_MAX_PORTALS 65536
+#define AAS_MAX_PORTALINDEXSIZE 65536
+#define AAS_MAX_CLUSTERS 65536
+
+#define BSPCINCLUDE
+#include "../game/be_aas.h"
+#include "../botlib/be_aas_def.h"
+
+/*
+typedef struct bspc_aas_s
+{
+ int loaded;
+ int initialized; //true when AAS has been initialized
+ int savefile; //set true when file should be saved
+ //bounding boxes
+ int numbboxes;
+ aas_bbox_t *bboxes;
+ //vertexes
+ int numvertexes;
+ aas_vertex_t *vertexes;
+ //planes
+ int numplanes;
+ aas_plane_t *planes;
+ //edges
+ int numedges;
+ aas_edge_t *edges;
+ //edge index
+ int edgeindexsize;
+ aas_edgeindex_t *edgeindex;
+ //faces
+ int numfaces;
+ aas_face_t *faces;
+ //face index
+ int faceindexsize;
+ aas_faceindex_t *faceindex;
+ //convex areas
+ int numareas;
+ aas_area_t *areas;
+ //convex area settings
+ int numareasettings;
+ aas_areasettings_t *areasettings;
+ //reachablity list
+ int reachabilitysize;
+ aas_reachability_t *reachability;
+ //nodes of the bsp tree
+ int numnodes;
+ aas_node_t *nodes;
+ //cluster portals
+ int numportals;
+ aas_portal_t *portals;
+ //cluster portal index
+ int portalindexsize;
+ aas_portalindex_t *portalindex;
+ //clusters
+ int numclusters;
+ aas_cluster_t *clusters;
+ //
+ int numreachabilityareas;
+ float reachabilitytime;
+} bspc_aas_t;
+
+extern bspc_aas_t aasworld;
+//*/
+
+extern aas_t aasworld;
+
+//stores the AAS file from the temporary AAS
+void AAS_StoreFile(char *filename);
+//returns a number of the given plane
+qboolean AAS_FindPlane(vec3_t normal, float dist, int *planenum);
+//allocates the maximum AAS memory for storage
+void AAS_AllocMaxAAS(void);
+//frees the maximum AAS memory for storage
+void AAS_FreeMaxAAS(void);
diff --git a/code/bspc/aasfile.h b/code/bspc/aasfile.h
index 7ed8677..fc3dc77 100755
--- a/code/bspc/aasfile.h
+++ b/code/bspc/aasfile.h
@@ -1,252 +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
-===========================================================================
-*/
-
-
-//NOTE: int = default signed
-// default long
-
-#define AASID (('S'<<24)+('A'<<16)+('A'<<8)+'E')
-#define AASVERSION_OLD 4
-#define AASVERSION 5
-
-//presence types
-#define PRESENCE_NONE 1
-#define PRESENCE_NORMAL 2
-#define PRESENCE_CROUCH 4
-
-//travel types
-#define MAX_TRAVELTYPES 32
-#define TRAVEL_INVALID 1 //temporary not possible
-#define TRAVEL_WALK 2 //walking
-#define TRAVEL_CROUCH 3 //crouching
-#define TRAVEL_BARRIERJUMP 4 //jumping onto a barrier
-#define TRAVEL_JUMP 5 //jumping
-#define TRAVEL_LADDER 6 //climbing a ladder
-#define TRAVEL_WALKOFFLEDGE 7 //walking of a ledge
-#define TRAVEL_SWIM 8 //swimming
-#define TRAVEL_WATERJUMP 9 //jump out of the water
-#define TRAVEL_TELEPORT 10 //teleportation
-#define TRAVEL_ELEVATOR 11 //travel by elevator
-#define TRAVEL_ROCKETJUMP 12 //rocket jumping required for travel
-#define TRAVEL_BFGJUMP 13 //bfg jumping required for travel
-#define TRAVEL_GRAPPLEHOOK 14 //grappling hook required for travel
-#define TRAVEL_DOUBLEJUMP 15 //double jump
-#define TRAVEL_RAMPJUMP 16 //ramp jump
-#define TRAVEL_STRAFEJUMP 17 //strafe jump
-#define TRAVEL_JUMPPAD 18 //jump pad
-#define TRAVEL_FUNCBOB 19 //func bob
-
-//face flags
-#define FACE_SOLID 1 //just solid at the other side
-#define FACE_LADDER 2 //ladder
-#define FACE_GROUND 4 //standing on ground when in this face
-#define FACE_GAP 8 //gap in the ground
-#define FACE_LIQUID 16
-#define FACE_LIQUIDSURFACE 32
-
-//area contents
-#define AREACONTENTS_WATER 1
-#define AREACONTENTS_LAVA 2
-#define AREACONTENTS_SLIME 4
-#define AREACONTENTS_CLUSTERPORTAL 8
-#define AREACONTENTS_TELEPORTAL 16
-#define AREACONTENTS_ROUTEPORTAL 32
-#define AREACONTENTS_TELEPORTER 64
-#define AREACONTENTS_JUMPPAD 128
-#define AREACONTENTS_DONOTENTER 256
-#define AREACONTENTS_VIEWPORTAL 512
-
-//area flags
-#define AREA_GROUNDED 1 //bot can stand on the ground
-#define AREA_LADDER 2 //area contains one or more ladder faces
-#define AREA_LIQUID 4 //area contains a liquid
-
-//aas file header lumps
-#define AAS_LUMPS 14
-#define AASLUMP_BBOXES 0
-#define AASLUMP_VERTEXES 1
-#define AASLUMP_PLANES 2
-#define AASLUMP_EDGES 3
-#define AASLUMP_EDGEINDEX 4
-#define AASLUMP_FACES 5
-#define AASLUMP_FACEINDEX 6
-#define AASLUMP_AREAS 7
-#define AASLUMP_AREASETTINGS 8
-#define AASLUMP_REACHABILITY 9
-#define AASLUMP_NODES 10
-#define AASLUMP_PORTALS 11
-#define AASLUMP_PORTALINDEX 12
-#define AASLUMP_CLUSTERS 13
-
-//========== bounding box =========
-
-//bounding box
-typedef struct aas_bbox_s
-{
- int presencetype;
- int flags;
- vec3_t mins, maxs;
-} aas_bbox_t;
-
-//============ settings ===========
-
-//reachability to another area
-typedef struct aas_reachability_s
-{
- int areanum; //number of the reachable area
- int facenum; //number of the face towards the other area
- int edgenum; //number of the edge towards the other area
- vec3_t start; //start point of inter area movement
- vec3_t end; //end point of inter area movement
- int traveltype; //type of travel required to get to the area
- unsigned short int traveltime;//travel time of the inter area movement
-} aas_reachability_t;
-
-//area settings
-typedef struct aas_areasettings_s
-{
- //could also add all kind of statistic fields
- int contents; //contents of the convex area
- int areaflags; //several area flags
- int presencetype; //how a bot can be present in this convex area
- int cluster; //cluster the area belongs to, if negative it's a portal
- int clusterareanum; //number of the area in the cluster
- int numreachableareas; //number of reachable areas from this one
- int firstreachablearea; //first reachable area in the reachable area index
-} aas_areasettings_t;
-
-//cluster portal
-typedef struct aas_portal_s
-{
- int areanum; //area that is the actual portal
- int frontcluster; //cluster at front of portal
- int backcluster; //cluster at back of portal
- int clusterareanum[2]; //number of the area in the front and back cluster
-} aas_portal_t;
-
-//cluster portal index
-typedef int aas_portalindex_t;
-
-//cluster
-typedef struct aas_cluster_s
-{
- int numareas; //number of areas in the cluster
- int numreachabilityareas; //number of areas with reachabilities
- int numportals; //number of cluster portals
- int firstportal; //first cluster portal in the index
-} aas_cluster_t;
-
-//============ 3d definition ============
-
-typedef vec3_t aas_vertex_t;
-
-//just a plane in the third dimension
-typedef struct aas_plane_s
-{
- vec3_t normal; //normal vector of the plane
- float dist; //distance of the plane (normal vector * distance = point in plane)
- int type;
-} aas_plane_t;
-
-//edge
-typedef struct aas_edge_s
-{
- int v[2]; //numbers of the vertexes of this edge
-} aas_edge_t;
-
-//edge index, negative if vertexes are reversed
-typedef int aas_edgeindex_t;
-
-//a face bounds a convex area, often it will also seperate two convex areas
-typedef struct aas_face_s
-{
- int planenum; //number of the plane this face is in
- int faceflags; //face flags (no use to create face settings for just this field)
- int numedges; //number of edges in the boundary of the face
- int firstedge; //first edge in the edge index
- int frontarea; //convex area at the front of this face
- int backarea; //convex area at the back of this face
-} aas_face_t;
-
-//face index, stores a negative index if backside of face
-typedef int aas_faceindex_t;
-
-//convex area with a boundary of faces
-typedef struct aas_area_s
-{
- int areanum; //number of this area
- //3d definition
- int numfaces; //number of faces used for the boundary of the convex area
- int firstface; //first face in the face index used for the boundary of the convex area
- vec3_t mins; //mins of the convex area
- vec3_t maxs; //maxs of the convex area
- vec3_t center; //'center' of the convex area
-} aas_area_t;
-
-//nodes of the bsp tree
-typedef struct aas_node_s
-{
- int planenum;
- int children[2]; //child nodes of this node, or convex areas as leaves when negative
- //when a child is zero it's a solid leaf
-} aas_node_t;
-
-//=========== aas file ===============
-
-//header lump
-typedef struct
-{
- int fileofs;
- int filelen;
-} aas_lump_t;
-
-//aas file header
-typedef struct aas_header_s
-{
- int ident;
- int version;
- int bspchecksum;
- //data entries
- aas_lump_t lumps[AAS_LUMPS];
-} aas_header_t;
-
-
-//====== additional information ======
-/*
-
-- when a node child is a solid leaf the node child number is zero
-- two adjacent areas (sharing a plane at opposite sides) share a face
- this face is a portal between the areas
-- when an area uses a face from the faceindex with a positive index
- then the face plane normal points into the area
-- the face edges are stored counter clockwise using the edgeindex
-- two adjacent convex areas (sharing a face) only share One face
- this is a simple result of the areas being convex
-- the convex areas can't have a mixture of ground and gap faces
- other mixtures of faces in one area are allowed
-- areas with the AREACONTENTS_CLUSTERPORTAL in the settings have
- cluster number zero
-- edge zero is a dummy
-- face zero is a dummy
-- area zero is a dummy
-- node zero is a dummy
-*/
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+
+//NOTE: int = default signed
+// default long
+
+#define AASID (('S'<<24)+('A'<<16)+('A'<<8)+'E')
+#define AASVERSION_OLD 4
+#define AASVERSION 5
+
+//presence types
+#define PRESENCE_NONE 1
+#define PRESENCE_NORMAL 2
+#define PRESENCE_CROUCH 4
+
+//travel types
+#define MAX_TRAVELTYPES 32
+#define TRAVEL_INVALID 1 //temporary not possible
+#define TRAVEL_WALK 2 //walking
+#define TRAVEL_CROUCH 3 //crouching
+#define TRAVEL_BARRIERJUMP 4 //jumping onto a barrier
+#define TRAVEL_JUMP 5 //jumping
+#define TRAVEL_LADDER 6 //climbing a ladder
+#define TRAVEL_WALKOFFLEDGE 7 //walking of a ledge
+#define TRAVEL_SWIM 8 //swimming
+#define TRAVEL_WATERJUMP 9 //jump out of the water
+#define TRAVEL_TELEPORT 10 //teleportation
+#define TRAVEL_ELEVATOR 11 //travel by elevator
+#define TRAVEL_ROCKETJUMP 12 //rocket jumping required for travel
+#define TRAVEL_BFGJUMP 13 //bfg jumping required for travel
+#define TRAVEL_GRAPPLEHOOK 14 //grappling hook required for travel
+#define TRAVEL_DOUBLEJUMP 15 //double jump
+#define TRAVEL_RAMPJUMP 16 //ramp jump
+#define TRAVEL_STRAFEJUMP 17 //strafe jump
+#define TRAVEL_JUMPPAD 18 //jump pad
+#define TRAVEL_FUNCBOB 19 //func bob
+
+//face flags
+#define FACE_SOLID 1 //just solid at the other side
+#define FACE_LADDER 2 //ladder
+#define FACE_GROUND 4 //standing on ground when in this face
+#define FACE_GAP 8 //gap in the ground
+#define FACE_LIQUID 16
+#define FACE_LIQUIDSURFACE 32
+
+//area contents
+#define AREACONTENTS_WATER 1
+#define AREACONTENTS_LAVA 2
+#define AREACONTENTS_SLIME 4
+#define AREACONTENTS_CLUSTERPORTAL 8
+#define AREACONTENTS_TELEPORTAL 16
+#define AREACONTENTS_ROUTEPORTAL 32
+#define AREACONTENTS_TELEPORTER 64
+#define AREACONTENTS_JUMPPAD 128
+#define AREACONTENTS_DONOTENTER 256
+#define AREACONTENTS_VIEWPORTAL 512
+
+//area flags
+#define AREA_GROUNDED 1 //bot can stand on the ground
+#define AREA_LADDER 2 //area contains one or more ladder faces
+#define AREA_LIQUID 4 //area contains a liquid
+
+//aas file header lumps
+#define AAS_LUMPS 14
+#define AASLUMP_BBOXES 0
+#define AASLUMP_VERTEXES 1
+#define AASLUMP_PLANES 2
+#define AASLUMP_EDGES 3
+#define AASLUMP_EDGEINDEX 4
+#define AASLUMP_FACES 5
+#define AASLUMP_FACEINDEX 6
+#define AASLUMP_AREAS 7
+#define AASLUMP_AREASETTINGS 8
+#define AASLUMP_REACHABILITY 9
+#define AASLUMP_NODES 10
+#define AASLUMP_PORTALS 11
+#define AASLUMP_PORTALINDEX 12
+#define AASLUMP_CLUSTERS 13
+
+//========== bounding box =========
+
+//bounding box
+typedef struct aas_bbox_s
+{
+ int presencetype;
+ int flags;
+ vec3_t mins, maxs;
+} aas_bbox_t;
+
+//============ settings ===========
+
+//reachability to another area
+typedef struct aas_reachability_s
+{
+ int areanum; //number of the reachable area
+ int facenum; //number of the face towards the other area
+ int edgenum; //number of the edge towards the other area
+ vec3_t start; //start point of inter area movement
+ vec3_t end; //end point of inter area movement
+ int traveltype; //type of travel required to get to the area
+ unsigned short int traveltime;//travel time of the inter area movement
+} aas_reachability_t;
+
+//area settings
+typedef struct aas_areasettings_s
+{
+ //could also add all kind of statistic fields
+ int contents; //contents of the convex area
+ int areaflags; //several area flags
+ int presencetype; //how a bot can be present in this convex area
+ int cluster; //cluster the area belongs to, if negative it's a portal
+ int clusterareanum; //number of the area in the cluster
+ int numreachableareas; //number of reachable areas from this one
+ int firstreachablearea; //first reachable area in the reachable area index
+} aas_areasettings_t;
+
+//cluster portal
+typedef struct aas_portal_s
+{
+ int areanum; //area that is the actual portal
+ int frontcluster; //cluster at front of portal
+ int backcluster; //cluster at back of portal
+ int clusterareanum[2]; //number of the area in the front and back cluster
+} aas_portal_t;
+
+//cluster portal index
+typedef int aas_portalindex_t;
+
+//cluster
+typedef struct aas_cluster_s
+{
+ int numareas; //number of areas in the cluster
+ int numreachabilityareas; //number of areas with reachabilities
+ int numportals; //number of cluster portals
+ int firstportal; //first cluster portal in the index
+} aas_cluster_t;
+
+//============ 3d definition ============
+
+typedef vec3_t aas_vertex_t;
+
+//just a plane in the third dimension
+typedef struct aas_plane_s
+{
+ vec3_t normal; //normal vector of the plane
+ float dist; //distance of the plane (normal vector * distance = point in plane)
+ int type;
+} aas_plane_t;
+
+//edge
+typedef struct aas_edge_s
+{
+ int v[2]; //numbers of the vertexes of this edge
+} aas_edge_t;
+
+//edge index, negative if vertexes are reversed
+typedef int aas_edgeindex_t;
+
+//a face bounds a convex area, often it will also seperate two convex areas
+typedef struct aas_face_s
+{
+ int planenum; //number of the plane this face is in
+ int faceflags; //face flags (no use to create face settings for just this field)
+ int numedges; //number of edges in the boundary of the face
+ int firstedge; //first edge in the edge index
+ int frontarea; //convex area at the front of this face
+ int backarea; //convex area at the back of this face
+} aas_face_t;
+
+//face index, stores a negative index if backside of face
+typedef int aas_faceindex_t;
+
+//convex area with a boundary of faces
+typedef struct aas_area_s
+{
+ int areanum; //number of this area
+ //3d definition
+ int numfaces; //number of faces used for the boundary of the convex area
+ int firstface; //first face in the face index used for the boundary of the convex area
+ vec3_t mins; //mins of the convex area
+ vec3_t maxs; //maxs of the convex area
+ vec3_t center; //'center' of the convex area
+} aas_area_t;
+
+//nodes of the bsp tree
+typedef struct aas_node_s
+{
+ int planenum;
+ int children[2]; //child nodes of this node, or convex areas as leaves when negative
+ //when a child is zero it's a solid leaf
+} aas_node_t;
+
+//=========== aas file ===============
+
+//header lump
+typedef struct
+{
+ int fileofs;
+ int filelen;
+} aas_lump_t;
+
+//aas file header
+typedef struct aas_header_s
+{
+ int ident;
+ int version;
+ int bspchecksum;
+ //data entries
+ aas_lump_t lumps[AAS_LUMPS];
+} aas_header_t;
+
+
+//====== additional information ======
+/*
+
+- when a node child is a solid leaf the node child number is zero
+- two adjacent areas (sharing a plane at opposite sides) share a face
+ this face is a portal between the areas
+- when an area uses a face from the faceindex with a positive index
+ then the face plane normal points into the area
+- the face edges are stored counter clockwise using the edgeindex
+- two adjacent convex areas (sharing a face) only share One face
+ this is a simple result of the areas being convex
+- the convex areas can't have a mixture of ground and gap faces
+ other mixtures of faces in one area are allowed
+- areas with the AREACONTENTS_CLUSTERPORTAL in the settings have
+ cluster number zero
+- edge zero is a dummy
+- face zero is a dummy
+- area zero is a dummy
+- node zero is a dummy
+*/
diff --git a/code/bspc/be_aas_bspc.c b/code/bspc/be_aas_bspc.c
index 127549c..9473287 100755
--- a/code/bspc/be_aas_bspc.c
+++ b/code/bspc/be_aas_bspc.c
@@ -1,292 +1,292 @@
-/*
-===========================================================================
-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 "../game/q_shared.h"
-#include "../bspc/l_log.h"
-#include "../bspc/l_qfiles.h"
-#include "../botlib/l_memory.h"
-#include "../botlib/l_script.h"
-#include "../botlib/l_precomp.h"
-#include "../botlib/l_struct.h"
-#include "../botlib/aasfile.h"
-#include "../game/botlib.h"
-#include "../game/be_aas.h"
-#include "../botlib/be_aas_def.h"
-#include "../qcommon/cm_public.h"
-
-//#define BSPC
-
-extern botlib_import_t botimport;
-extern qboolean capsule_collision;
-
-botlib_import_t botimport;
-clipHandle_t worldmodel;
-
-void Error (char *error, ...);
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_Error(char *fmt, ...)
-{
- va_list argptr;
- char text[1024];
-
- va_start(argptr, fmt);
- vsprintf(text, fmt, argptr);
- va_end(argptr);
-
- Error(text);
-} //end of the function AAS_Error
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int Sys_MilliSeconds(void)
-{
- return clock() * 1000 / CLOCKS_PER_SEC;
-} //end of the function Sys_MilliSeconds
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_DebugLine(vec3_t start, vec3_t end, int color)
-{
-} //end of the function AAS_DebugLine
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ClearShownDebugLines(void)
-{
-} //end of the function AAS_ClearShownDebugLines
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-char *BotImport_BSPEntityData(void)
-{
- return CM_EntityString();
-} //end of the function AAS_GetEntityData
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotImport_Trace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask)
-{
- trace_t result;
-
- CM_BoxTrace(&result, start, end, mins, maxs, worldmodel, contentmask, capsule_collision);
-
- bsptrace->allsolid = result.allsolid;
- bsptrace->contents = result.contents;
- VectorCopy(result.endpos, bsptrace->endpos);
- bsptrace->ent = result.entityNum;
- bsptrace->fraction = result.fraction;
- bsptrace->exp_dist = 0;
- bsptrace->plane.dist = result.plane.dist;
- VectorCopy(result.plane.normal, bsptrace->plane.normal);
- bsptrace->plane.signbits = result.plane.signbits;
- bsptrace->plane.type = result.plane.type;
- bsptrace->sidenum = 0;
- bsptrace->startsolid = result.startsolid;
- bsptrace->surface.flags = result.surfaceFlags;
-} //end of the function BotImport_Trace
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotImport_PointContents(vec3_t p)
-{
- return CM_PointContents(p, worldmodel);
-} //end of the function BotImport_PointContents
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void *BotImport_GetMemory(int size)
-{
- return GetMemory(size);
-} //end of the function BotImport_GetMemory
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotImport_Print(int type, char *fmt, ...)
-{
- va_list argptr;
- char buf[1024];
-
- va_start(argptr, fmt);
- vsprintf(buf, fmt, argptr);
- printf(buf);
- if (buf[0] != '\r') Log_Write(buf);
- va_end(argptr);
-} //end of the function BotImport_Print
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotImport_BSPModelMinsMaxsOrigin(int modelnum, vec3_t angles, vec3_t outmins, vec3_t outmaxs, vec3_t origin)
-{
- clipHandle_t h;
- vec3_t mins, maxs;
- float max;
- int i;
-
- h = CM_InlineModel(modelnum);
- CM_ModelBounds(h, mins, maxs);
- //if the model is rotated
- if ((angles[0] || angles[1] || angles[2]))
- { // expand for rotation
-
- max = RadiusFromBounds(mins, maxs);
- for (i = 0; i < 3; i++)
- {
- mins[i] = (mins[i] + maxs[i]) * 0.5 - max;
- maxs[i] = (mins[i] + maxs[i]) * 0.5 + max;
- } //end for
- } //end if
- if (outmins) VectorCopy(mins, outmins);
- if (outmaxs) VectorCopy(maxs, outmaxs);
- if (origin) VectorClear(origin);
-} //end of the function BotImport_BSPModelMinsMaxsOrigin
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Com_DPrintf(char *fmt, ...)
-{
- va_list argptr;
- char buf[1024];
-
- va_start(argptr, fmt);
- vsprintf(buf, fmt, argptr);
- printf(buf);
- if (buf[0] != '\r') Log_Write(buf);
- va_end(argptr);
-} //end of the function Com_DPrintf
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int COM_Compress( char *data_p ) {
- return strlen(data_p);
-}
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Com_Memset (void* dest, const int val, const size_t count) {
- memset(dest, val, count);
-}
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Com_Memcpy (void* dest, const void* src, const size_t count) {
- memcpy(dest, src, count);
-}
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_InitBotImport(void)
-{
- botimport.BSPEntityData = BotImport_BSPEntityData;
- botimport.GetMemory = BotImport_GetMemory;
- botimport.FreeMemory = FreeMemory;
- botimport.Trace = BotImport_Trace;
- botimport.PointContents = BotImport_PointContents;
- botimport.Print = BotImport_Print;
- botimport.BSPModelMinsMaxsOrigin = BotImport_BSPModelMinsMaxsOrigin;
-} //end of the function AAS_InitBotImport
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_CalcReachAndClusters(struct quakefile_s *qf)
-{
- float time;
-
- Log_Print("loading collision map...\n");
- //
- if (!qf->pakfile[0]) strcpy(qf->pakfile, qf->filename);
- //load the map
- CM_LoadMap((char *) qf, qfalse, &aasworld.bspchecksum);
- //get a handle to the world model
- worldmodel = CM_InlineModel(0); // 0 = world, 1 + are bmodels
- //initialize bot import structure
- AAS_InitBotImport();
- //load the BSP entity string
- AAS_LoadBSPFile();
- //init physics settings
- AAS_InitSettings();
- //initialize AAS link heap
- AAS_InitAASLinkHeap();
- //initialize the AAS linked entities for the new map
- AAS_InitAASLinkedEntities();
- //reset all reachabilities and clusters
- aasworld.reachabilitysize = 0;
- aasworld.numclusters = 0;
- //set all view portals as cluster portals in case we re-calculate the reachabilities and clusters (with -reach)
- AAS_SetViewPortalsAsClusterPortals();
- //calculate reachabilities
- AAS_InitReachability();
- time = 0;
- while(AAS_ContinueInitReachability(time)) time++;
- //calculate clusters
- AAS_InitClustering();
-} //end of the function AAS_CalcReachAndClusters
+/*
+===========================================================================
+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 "../game/q_shared.h"
+#include "../bspc/l_log.h"
+#include "../bspc/l_qfiles.h"
+#include "../botlib/l_memory.h"
+#include "../botlib/l_script.h"
+#include "../botlib/l_precomp.h"
+#include "../botlib/l_struct.h"
+#include "../botlib/aasfile.h"
+#include "../game/botlib.h"
+#include "../game/be_aas.h"
+#include "../botlib/be_aas_def.h"
+#include "../qcommon/cm_public.h"
+
+//#define BSPC
+
+extern botlib_import_t botimport;
+extern qboolean capsule_collision;
+
+botlib_import_t botimport;
+clipHandle_t worldmodel;
+
+void Error (char *error, ...);
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_Error(char *fmt, ...)
+{
+ va_list argptr;
+ char text[1024];
+
+ va_start(argptr, fmt);
+ vsprintf(text, fmt, argptr);
+ va_end(argptr);
+
+ Error(text);
+} //end of the function AAS_Error
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int Sys_MilliSeconds(void)
+{
+ return clock() * 1000 / CLOCKS_PER_SEC;
+} //end of the function Sys_MilliSeconds
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_DebugLine(vec3_t start, vec3_t end, int color)
+{
+} //end of the function AAS_DebugLine
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_ClearShownDebugLines(void)
+{
+} //end of the function AAS_ClearShownDebugLines
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+char *BotImport_BSPEntityData(void)
+{
+ return CM_EntityString();
+} //end of the function AAS_GetEntityData
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void BotImport_Trace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask)
+{
+ trace_t result;
+
+ CM_BoxTrace(&result, start, end, mins, maxs, worldmodel, contentmask, capsule_collision);
+
+ bsptrace->allsolid = result.allsolid;
+ bsptrace->contents = result.contents;
+ VectorCopy(result.endpos, bsptrace->endpos);
+ bsptrace->ent = result.entityNum;
+ bsptrace->fraction = result.fraction;
+ bsptrace->exp_dist = 0;
+ bsptrace->plane.dist = result.plane.dist;
+ VectorCopy(result.plane.normal, bsptrace->plane.normal);
+ bsptrace->plane.signbits = result.plane.signbits;
+ bsptrace->plane.type = result.plane.type;
+ bsptrace->sidenum = 0;
+ bsptrace->startsolid = result.startsolid;
+ bsptrace->surface.flags = result.surfaceFlags;
+} //end of the function BotImport_Trace
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int BotImport_PointContents(vec3_t p)
+{
+ return CM_PointContents(p, worldmodel);
+} //end of the function BotImport_PointContents
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void *BotImport_GetMemory(int size)
+{
+ return GetMemory(size);
+} //end of the function BotImport_GetMemory
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void BotImport_Print(int type, char *fmt, ...)
+{
+ va_list argptr;
+ char buf[1024];
+
+ va_start(argptr, fmt);
+ vsprintf(buf, fmt, argptr);
+ printf(buf);
+ if (buf[0] != '\r') Log_Write(buf);
+ va_end(argptr);
+} //end of the function BotImport_Print
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void BotImport_BSPModelMinsMaxsOrigin(int modelnum, vec3_t angles, vec3_t outmins, vec3_t outmaxs, vec3_t origin)
+{
+ clipHandle_t h;
+ vec3_t mins, maxs;
+ float max;
+ int i;
+
+ h = CM_InlineModel(modelnum);
+ CM_ModelBounds(h, mins, maxs);
+ //if the model is rotated
+ if ((angles[0] || angles[1] || angles[2]))
+ { // expand for rotation
+
+ max = RadiusFromBounds(mins, maxs);
+ for (i = 0; i < 3; i++)
+ {
+ mins[i] = (mins[i] + maxs[i]) * 0.5 - max;
+ maxs[i] = (mins[i] + maxs[i]) * 0.5 + max;
+ } //end for
+ } //end if
+ if (outmins) VectorCopy(mins, outmins);
+ if (outmaxs) VectorCopy(maxs, outmaxs);
+ if (origin) VectorClear(origin);
+} //end of the function BotImport_BSPModelMinsMaxsOrigin
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Com_DPrintf(char *fmt, ...)
+{
+ va_list argptr;
+ char buf[1024];
+
+ va_start(argptr, fmt);
+ vsprintf(buf, fmt, argptr);
+ printf(buf);
+ if (buf[0] != '\r') Log_Write(buf);
+ va_end(argptr);
+} //end of the function Com_DPrintf
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int COM_Compress( char *data_p ) {
+ return strlen(data_p);
+}
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Com_Memset (void* dest, const int val, const size_t count) {
+ memset(dest, val, count);
+}
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Com_Memcpy (void* dest, const void* src, const size_t count) {
+ memcpy(dest, src, count);
+}
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_InitBotImport(void)
+{
+ botimport.BSPEntityData = BotImport_BSPEntityData;
+ botimport.GetMemory = BotImport_GetMemory;
+ botimport.FreeMemory = FreeMemory;
+ botimport.Trace = BotImport_Trace;
+ botimport.PointContents = BotImport_PointContents;
+ botimport.Print = BotImport_Print;
+ botimport.BSPModelMinsMaxsOrigin = BotImport_BSPModelMinsMaxsOrigin;
+} //end of the function AAS_InitBotImport
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_CalcReachAndClusters(struct quakefile_s *qf)
+{
+ float time;
+
+ Log_Print("loading collision map...\n");
+ //
+ if (!qf->pakfile[0]) strcpy(qf->pakfile, qf->filename);
+ //load the map
+ CM_LoadMap((char *) qf, qfalse, &aasworld.bspchecksum);
+ //get a handle to the world model
+ worldmodel = CM_InlineModel(0); // 0 = world, 1 + are bmodels
+ //initialize bot import structure
+ AAS_InitBotImport();
+ //load the BSP entity string
+ AAS_LoadBSPFile();
+ //init physics settings
+ AAS_InitSettings();
+ //initialize AAS link heap
+ AAS_InitAASLinkHeap();
+ //initialize the AAS linked entities for the new map
+ AAS_InitAASLinkedEntities();
+ //reset all reachabilities and clusters
+ aasworld.reachabilitysize = 0;
+ aasworld.numclusters = 0;
+ //set all view portals as cluster portals in case we re-calculate the reachabilities and clusters (with -reach)
+ AAS_SetViewPortalsAsClusterPortals();
+ //calculate reachabilities
+ AAS_InitReachability();
+ time = 0;
+ while(AAS_ContinueInitReachability(time)) time++;
+ //calculate clusters
+ AAS_InitClustering();
+} //end of the function AAS_CalcReachAndClusters
diff --git a/code/bspc/be_aas_bspc.h b/code/bspc/be_aas_bspc.h
index 72e488a..97e2921 100755
--- a/code/bspc/be_aas_bspc.h
+++ b/code/bspc/be_aas_bspc.h
@@ -1,23 +1,23 @@
-/*
-===========================================================================
-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_CalcReachAndClusters(struct quakefile_s *qf);
+/*
+===========================================================================
+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_CalcReachAndClusters(struct quakefile_s *qf);
diff --git a/code/bspc/brushbsp.c b/code/bspc/brushbsp.c
index 22cb0dd..d8accec 100755
--- a/code/bspc/brushbsp.c
+++ b/code/bspc/brushbsp.c
@@ -1,1871 +1,1871 @@
-/*
-===========================================================================
-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 "l_mem.h"
-#include "../botlib/aasfile.h"
-#include "aas_store.h"
-#include "aas_cfg.h"
-
-#include <assert.h>
-
-/*
-each side has a count of the other sides it splits
-
-the best split will be the one that minimizes the total split counts
-of all remaining sides
-
-precalc side on plane table
-
-evaluate split side
-{
-cost = 0
-for all sides
- for all sides
- get
- if side splits side and splitside is on same child
- cost++;
-}
-*/
-
-int c_nodes;
-int c_nonvis;
-int c_active_brushes;
-int c_solidleafnodes;
-int c_totalsides;
-int c_brushmemory;
-int c_peak_brushmemory;
-int c_nodememory;
-int c_peak_totalbspmemory;
-
-// if a brush just barely pokes onto the other side,
-// let it slide by without chopping
-#define PLANESIDE_EPSILON 0.001
-//0.1
-
-//#ifdef DEBUG
-typedef struct cname_s
-{
- int value;
- char *name;
-} cname_t;
-
-cname_t contentnames[] =
-{
- {CONTENTS_SOLID,"CONTENTS_SOLID"},
- {CONTENTS_WINDOW,"CONTENTS_WINDOW"},
- {CONTENTS_AUX,"CONTENTS_AUX"},
- {CONTENTS_LAVA,"CONTENTS_LAVA"},
- {CONTENTS_SLIME,"CONTENTS_SLIME"},
- {CONTENTS_WATER,"CONTENTS_WATER"},
- {CONTENTS_MIST,"CONTENTS_MIST"},
- {LAST_VISIBLE_CONTENTS,"LAST_VISIBLE_CONTENTS"},
-
- {CONTENTS_AREAPORTAL,"CONTENTS_AREAPORTAL"},
- {CONTENTS_PLAYERCLIP,"CONTENTS_PLAYERCLIP"},
- {CONTENTS_MONSTERCLIP,"CONTENTS_MONSTERCLIP"},
- {CONTENTS_CURRENT_0,"CONTENTS_CURRENT_0"},
- {CONTENTS_CURRENT_90,"CONTENTS_CURRENT_90"},
- {CONTENTS_CURRENT_180,"CONTENTS_CURRENT_180"},
- {CONTENTS_CURRENT_270,"CONTENTS_CURRENT_270"},
- {CONTENTS_CURRENT_UP,"CONTENTS_CURRENT_UP"},
- {CONTENTS_CURRENT_DOWN,"CONTENTS_CURRENT_DOWN"},
- {CONTENTS_ORIGIN,"CONTENTS_ORIGIN"},
- {CONTENTS_MONSTER,"CONTENTS_MONSTER"},
- {CONTENTS_DEADMONSTER,"CONTENTS_DEADMONSTER"},
- {CONTENTS_DETAIL,"CONTENTS_DETAIL"},
- {CONTENTS_Q2TRANSLUCENT,"CONTENTS_TRANSLUCENT"},
- {CONTENTS_LADDER,"CONTENTS_LADDER"},
- {0, 0}
-};
-
-void PrintContents(int contents)
-{
- int i;
-
- for (i = 0; contentnames[i].value; i++)
- {
- if (contents & contentnames[i].value)
- {
- Log_Write("%s,", contentnames[i].name);
- } //end if
- } //end for
-} //end of the function PrintContents
-
-//#endif DEBUG
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ResetBrushBSP(void)
-{
- c_nodes = 0;
- c_nonvis = 0;
- c_active_brushes = 0;
- c_solidleafnodes = 0;
- c_totalsides = 0;
- c_brushmemory = 0;
- c_peak_brushmemory = 0;
- c_nodememory = 0;
- c_peak_totalbspmemory = 0;
-} //end of the function ResetBrushBSP
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void FindBrushInTree (node_t *node, int brushnum)
-{
- bspbrush_t *b;
-
- if (node->planenum == PLANENUM_LEAF)
- {
- for (b=node->brushlist ; b ; b=b->next)
- if (b->original->brushnum == brushnum)
- Log_Print ("here\n");
- return;
- }
- FindBrushInTree(node->children[0], brushnum);
- FindBrushInTree(node->children[1], brushnum);
-} //end of the function FindBrushInTree
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void DrawBrushList (bspbrush_t *brush, node_t *node)
-{
- int i;
- side_t *s;
-
- GLS_BeginScene ();
- for ( ; brush ; brush=brush->next)
- {
- for (i=0 ; i<brush->numsides ; i++)
- {
- s = &brush->sides[i];
- if (!s->winding)
- continue;
- if (s->texinfo == TEXINFO_NODE)
- GLS_Winding (s->winding, 1);
- else if (!(s->flags & SFL_VISIBLE))
- GLS_Winding (s->winding, 2);
- else
- GLS_Winding (s->winding, 0);
- }
- }
- GLS_EndScene ();
-} //end of the function DrawBrushList
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void WriteBrushList (char *name, bspbrush_t *brush, qboolean onlyvis)
-{
- int i;
- side_t *s;
- FILE *f;
-
- qprintf ("writing %s\n", name);
- f = SafeOpenWrite (name);
-
- for ( ; brush ; brush=brush->next)
- {
- for (i=0 ; i<brush->numsides ; i++)
- {
- s = &brush->sides[i];
- if (!s->winding)
- continue;
- if (onlyvis && !(s->flags & SFL_VISIBLE))
- continue;
- OutputWinding (brush->sides[i].winding, f);
- }
- }
-
- fclose (f);
-} //end of the function WriteBrushList
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void PrintBrush (bspbrush_t *brush)
-{
- int i;
-
- printf ("brush: %p\n", brush);
- for (i=0;i<brush->numsides ; i++)
- {
- pw(brush->sides[i].winding);
- printf ("\n");
- } //end for
-} //end of the function PrintBrush
-//===========================================================================
-// Sets the mins/maxs based on the windings
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BoundBrush (bspbrush_t *brush)
-{
- int i, j;
- winding_t *w;
-
- ClearBounds (brush->mins, brush->maxs);
- for (i=0 ; i<brush->numsides ; i++)
- {
- w = brush->sides[i].winding;
- if (!w)
- continue;
- for (j=0 ; j<w->numpoints ; j++)
- AddPointToBounds (w->p[j], brush->mins, brush->maxs);
- }
-} //end of the function BoundBrush
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void CreateBrushWindings (bspbrush_t *brush)
-{
- int i, j;
- winding_t *w;
- side_t *side;
- plane_t *plane;
-
- for (i=0 ; i<brush->numsides ; i++)
- {
- side = &brush->sides[i];
- plane = &mapplanes[side->planenum];
- w = BaseWindingForPlane (plane->normal, plane->dist);
- for (j=0 ; j<brush->numsides && w; j++)
- {
- if (i == j)
- continue;
- if (brush->sides[j].flags & SFL_BEVEL)
- continue;
- plane = &mapplanes[brush->sides[j].planenum^1];
- ChopWindingInPlace (&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
- }
-
- side->winding = w;
- }
-
- BoundBrush (brush);
-} //end of the function CreateBrushWindings
-//===========================================================================
-// Creates a new axial brush
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *BrushFromBounds (vec3_t mins, vec3_t maxs)
-{
- bspbrush_t *b;
- int i;
- vec3_t normal;
- vec_t dist;
-
- b = AllocBrush (6);
- b->numsides = 6;
- for (i=0 ; i<3 ; i++)
- {
- VectorClear (normal);
- normal[i] = 1;
- dist = maxs[i];
- b->sides[i].planenum = FindFloatPlane (normal, dist);
-
- normal[i] = -1;
- dist = -mins[i];
- b->sides[3+i].planenum = FindFloatPlane (normal, dist);
- }
-
- CreateBrushWindings (b);
-
- return b;
-} //end of the function BrushFromBounds
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BrushOutOfBounds(bspbrush_t *brush, vec3_t mins, vec3_t maxs, float epsilon)
-{
- int i, j, n;
- winding_t *w;
- side_t *side;
-
- for (i = 0; i < brush->numsides; i++)
- {
- side = &brush->sides[i];
- w = side->winding;
- for (j = 0; j < w->numpoints; j++)
- {
- for (n = 0; n < 3; n++)
- {
- if (w->p[j][n] < (mins[n] + epsilon) || w->p[j][n] > (maxs[n] - epsilon)) return true;
- } //end for
- } //end for
- } //end for
- return false;
-} //end of the function BrushOutOfBounds
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-vec_t BrushVolume (bspbrush_t *brush)
-{
- int i;
- winding_t *w;
- vec3_t corner;
- vec_t d, area, volume;
- plane_t *plane;
-
- if (!brush) return 0;
-
- // grab the first valid point as the corner
- w = NULL;
- for (i = 0; i < brush->numsides; i++)
- {
- w = brush->sides[i].winding;
- if (w) break;
- } //end for
- if (!w) return 0;
- VectorCopy (w->p[0], corner);
-
- // make tetrahedrons to all other faces
- volume = 0;
- for ( ; i < brush->numsides; i++)
- {
- w = brush->sides[i].winding;
- if (!w) continue;
- plane = &mapplanes[brush->sides[i].planenum];
- d = -(DotProduct (corner, plane->normal) - plane->dist);
- area = WindingArea(w);
- volume += d * area;
- } //end for
-
- volume /= 3;
- return volume;
-} //end of the function BrushVolume
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int CountBrushList (bspbrush_t *brushes)
-{
- int c;
-
- c = 0;
- for ( ; brushes; brushes = brushes->next) c++;
- return c;
-} //end of the function CountBrushList
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-node_t *AllocNode (void)
-{
- node_t *node;
-
- node = GetMemory(sizeof(*node));
- memset (node, 0, sizeof(*node));
- if (numthreads == 1)
- {
- c_nodememory += MemorySize(node);
- } //end if
- return node;
-} //end of the function AllocNode
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *AllocBrush (int numsides)
-{
- bspbrush_t *bb;
- int c;
-
- c = (int)&(((bspbrush_t *)0)->sides[numsides]);
- bb = GetMemory(c);
- memset (bb, 0, c);
- if (numthreads == 1)
- {
- c_active_brushes++;
- c_brushmemory += MemorySize(bb);
- if (c_brushmemory > c_peak_brushmemory)
- c_peak_brushmemory = c_brushmemory;
- } //end if
- return bb;
-} //end of the function AllocBrush
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void FreeBrush (bspbrush_t *brushes)
-{
- int i;
-
- for (i=0 ; i<brushes->numsides ; i++)
- if (brushes->sides[i].winding)
- FreeWinding(brushes->sides[i].winding);
- if (numthreads == 1)
- {
- c_active_brushes--;
- c_brushmemory -= MemorySize(brushes);
- if (c_brushmemory < 0) c_brushmemory = 0;
- } //end if
- FreeMemory(brushes);
-} //end of the function FreeBrush
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void FreeBrushList (bspbrush_t *brushes)
-{
- bspbrush_t *next;
-
- for ( ; brushes; brushes = next)
- {
- next = brushes->next;
-
- FreeBrush(brushes);
- } //end for
-} //end of the function FreeBrushList
-//===========================================================================
-// Duplicates the brush, the sides, and the windings
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *CopyBrush (bspbrush_t *brush)
-{
- bspbrush_t *newbrush;
- int size;
- int i;
-
- size = (int)&(((bspbrush_t *)0)->sides[brush->numsides]);
-
- newbrush = AllocBrush (brush->numsides);
- memcpy (newbrush, brush, size);
-
- for (i=0 ; i<brush->numsides ; i++)
- {
- if (brush->sides[i].winding)
- newbrush->sides[i].winding = CopyWinding (brush->sides[i].winding);
- }
-
- return newbrush;
-} //end of the function CopyBrush
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-node_t *PointInLeaf (node_t *node, vec3_t point)
-{
- vec_t d;
- plane_t *plane;
-
- while (node->planenum != PLANENUM_LEAF)
- {
- plane = &mapplanes[node->planenum];
- d = DotProduct (point, plane->normal) - plane->dist;
- if (d > 0)
- node = node->children[0];
- else
- node = node->children[1];
- }
-
- return node;
-} //end of the function PointInLeaf
-//===========================================================================
-// Returns PSIDE_FRONT, PSIDE_BACK, or PSIDE_BOTH
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#if 0
-int BoxOnPlaneSide (vec3_t mins, vec3_t maxs, plane_t *plane)
-{
- int side;
- int i;
- vec3_t corners[2];
- vec_t dist1, dist2;
-
- // axial planes are easy
- if (plane->type < 3)
- {
- side = 0;
- if (maxs[plane->type] > plane->dist+PLANESIDE_EPSILON)
- side |= PSIDE_FRONT;
- if (mins[plane->type] < plane->dist-PLANESIDE_EPSILON)
- side |= PSIDE_BACK;
- return side;
- }
-
- // create the proper leading and trailing verts for the box
-
- for (i=0 ; i<3 ; i++)
- {
- if (plane->normal[i] < 0)
- {
- corners[0][i] = mins[i];
- corners[1][i] = maxs[i];
- }
- else
- {
- corners[1][i] = mins[i];
- corners[0][i] = maxs[i];
- }
- }
-
- dist1 = DotProduct (plane->normal, corners[0]) - plane->dist;
- dist2 = DotProduct (plane->normal, corners[1]) - plane->dist;
- side = 0;
- if (dist1 >= PLANESIDE_EPSILON)
- side = PSIDE_FRONT;
- if (dist2 < PLANESIDE_EPSILON)
- side |= PSIDE_BACK;
-
- return side;
-}
-#else
-int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, plane_t *p)
-{
- float dist1, dist2;
- int sides;
-
- // axial planes are easy
- if (p->type < 3)
- {
- sides = 0;
- if (emaxs[p->type] > p->dist+PLANESIDE_EPSILON) sides |= PSIDE_FRONT;
- if (emins[p->type] < p->dist-PLANESIDE_EPSILON) sides |= PSIDE_BACK;
- return sides;
- } //end if
-
-// general case
- switch (p->signbits)
- {
- case 0:
- dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
- dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
- break;
- case 1:
- dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
- dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
- break;
- case 2:
- dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
- dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
- break;
- case 3:
- dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
- dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
- break;
- case 4:
- dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
- dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
- break;
- case 5:
- dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
- dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
- break;
- case 6:
- dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
- dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
- break;
- case 7:
- dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
- dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
- break;
- default:
- dist1 = dist2 = 0; // shut up compiler
-// assert( 0 );
- break;
- }
-
- sides = 0;
- if (dist1 - p->dist >= PLANESIDE_EPSILON) sides = PSIDE_FRONT;
- if (dist2 - p->dist < PLANESIDE_EPSILON) sides |= PSIDE_BACK;
-
-// assert(sides != 0);
-
- return sides;
-}
-#endif
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int QuickTestBrushToPlanenum (bspbrush_t *brush, int planenum, int *numsplits)
-{
- int i, num;
- plane_t *plane;
- int s;
-
- *numsplits = 0;
-
- plane = &mapplanes[planenum];
-
-#ifdef ME
- //fast axial cases
- if (plane->type < 3)
- {
- if (plane->dist + PLANESIDE_EPSILON < brush->mins[plane->type])
- return PSIDE_FRONT;
- if (plane->dist - PLANESIDE_EPSILON > brush->maxs[plane->type])
- return PSIDE_BACK;
- } //end if
-#endif //ME*/
-
- // if the brush actually uses the planenum,
- // we can tell the side for sure
- for (i = 0; i < brush->numsides; i++)
- {
- num = brush->sides[i].planenum;
- if (num >= MAX_MAPFILE_PLANES)
- Error ("bad planenum");
- if (num == planenum)
- return PSIDE_BACK|PSIDE_FACING;
- if (num == (planenum ^ 1) )
- return PSIDE_FRONT|PSIDE_FACING;
-
- }
-
- // box on plane side
- s = BoxOnPlaneSide (brush->mins, brush->maxs, plane);
-
- // if both sides, count the visible faces split
- if (s == PSIDE_BOTH)
- {
- *numsplits += 3;
- }
-
- return s;
-} //end of the function QuickTestBrushToPlanenum
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TestBrushToPlanenum (bspbrush_t *brush, int planenum,
- int *numsplits, qboolean *hintsplit, int *epsilonbrush)
-{
- int i, j, num;
- plane_t *plane;
- int s = 0;
- winding_t *w;
- vec_t d, d_front, d_back;
- int front, back;
- int type;
- float dist;
-
- *numsplits = 0;
- *hintsplit = false;
-
- plane = &mapplanes[planenum];
-
-#ifdef ME
- //fast axial cases
- type = plane->type;
- if (type < 3)
- {
- dist = plane->dist;
- if (dist + PLANESIDE_EPSILON < brush->mins[type]) return PSIDE_FRONT;
- if (dist - PLANESIDE_EPSILON > brush->maxs[type]) return PSIDE_BACK;
- if (brush->mins[type] < dist - PLANESIDE_EPSILON &&
- brush->maxs[type] > dist + PLANESIDE_EPSILON) s = PSIDE_BOTH;
- } //end if
-
- if (s != PSIDE_BOTH)
-#endif //ME
- {
- // if the brush actually uses the planenum,
- // we can tell the side for sure
- for (i = 0; i < brush->numsides; i++)
- {
- num = brush->sides[i].planenum;
- if (num >= MAX_MAPFILE_PLANES) Error ("bad planenum");
- if (num == planenum)
- {
- //we don't need to test this side plane again
- brush->sides[i].flags |= SFL_TESTED;
- return PSIDE_BACK|PSIDE_FACING;
- } //end if
- if (num == (planenum ^ 1) )
- {
- //we don't need to test this side plane again
- brush->sides[i].flags |= SFL_TESTED;
- return PSIDE_FRONT|PSIDE_FACING;
- } //end if
- } //end for
-
- // box on plane side
- s = BoxOnPlaneSide (brush->mins, brush->maxs, plane);
-
- if (s != PSIDE_BOTH) return s;
- } //end if
-
- // if both sides, count the visible faces split
- d_front = d_back = 0;
-
- for (i = 0; i < brush->numsides; i++)
- {
- if (brush->sides[i].texinfo == TEXINFO_NODE)
- continue; // on node, don't worry about splits
- if (!(brush->sides[i].flags & SFL_VISIBLE))
- continue; // we don't care about non-visible
- w = brush->sides[i].winding;
- if (!w) continue;
- front = back = 0;
- for (j = 0; j < w->numpoints; j++)
- {
- d = DotProduct(w->p[j], plane->normal) - plane->dist;
- if (d > d_front) d_front = d;
- if (d < d_back) d_back = d;
- if (d > 0.1) // PLANESIDE_EPSILON)
- front = 1;
- if (d < -0.1) // PLANESIDE_EPSILON)
- back = 1;
- } //end for
- if (front && back)
- {
- if ( !(brush->sides[i].surf & SURF_SKIP) )
- {
- (*numsplits)++;
- if (brush->sides[i].surf & SURF_HINT)
- {
- *hintsplit = true;
- } //end if
- } //end if
- } //end if
- } //end for
-
- if ( (d_front > 0.0 && d_front < 1.0)
- || (d_back < 0.0 && d_back > -1.0) )
- (*epsilonbrush)++;
-
-#if 0
- if (*numsplits == 0)
- { // didn't really need to be split
- if (front) s = PSIDE_FRONT;
- else if (back) s = PSIDE_BACK;
- else s = 0;
- }
-#endif
-
- return s;
-} //end of the function TestBrushToPlanenum
-//===========================================================================
-// Returns true if the winding would be crunched out of
-// existance by the vertex snapping.
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#define EDGE_LENGTH 0.2
-qboolean WindingIsTiny (winding_t *w)
-{
-#if 0
- if (WindingArea (w) < 1)
- return true;
- return false;
-#else
- int i, j;
- vec_t len;
- vec3_t delta;
- int edges;
-
- edges = 0;
- for (i=0 ; i<w->numpoints ; i++)
- {
- j = i == w->numpoints - 1 ? 0 : i+1;
- VectorSubtract (w->p[j], w->p[i], delta);
- len = VectorLength (delta);
- if (len > EDGE_LENGTH)
- {
- if (++edges == 3)
- return false;
- }
- }
- return true;
-#endif
-} //end of the function WindingIsTiny
-//===========================================================================
-// Returns true if the winding still has one of the points
-// from basewinding for plane
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean WindingIsHuge (winding_t *w)
-{
- int i, j;
-
- for (i=0 ; i<w->numpoints ; i++)
- {
- for (j=0 ; j<3 ; j++)
- if (w->p[i][j] < -BOGUS_RANGE+1 || w->p[i][j] > BOGUS_RANGE-1)
- return true;
- }
- return false;
-} //end of the function WindingIsHuge
-//===========================================================================
-// creates a leaf out of the given nodes with the given brushes
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void LeafNode(node_t *node, bspbrush_t *brushes)
-{
- bspbrush_t *b;
- int i;
-
- node->side = NULL;
- node->planenum = PLANENUM_LEAF;
- node->contents = 0;
-
- for (b = brushes; b; b = b->next)
- {
- // if the brush is solid and all of its sides are on nodes,
- // it eats everything
- if (b->original->contents & CONTENTS_SOLID)
- {
- for (i=0 ; i<b->numsides ; i++)
- if (b->sides[i].texinfo != TEXINFO_NODE)
- break;
- if (i == b->numsides)
- {
- node->contents = CONTENTS_SOLID;
- break;
- } //end if
- } //end if
- node->contents |= b->original->contents;
- } //end for
-
- if (create_aas)
- {
- node->expansionbboxes = 0;
- node->contents = 0;
- for (b = brushes; b; b = b->next)
- {
- node->expansionbboxes |= b->original->expansionbbox;
- node->contents |= b->original->contents;
- if (b->original->modelnum)
- node->modelnum = b->original->modelnum;
- } //end for
- if (node->contents & CONTENTS_SOLID)
- {
- if (node->expansionbboxes != cfg.allpresencetypes)
- {
- node->contents &= ~CONTENTS_SOLID;
- } //end if
- } //end if
- } //end if
-
- node->brushlist = brushes;
-} //end of the function LeafNode
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void CheckPlaneAgainstParents (int pnum, node_t *node)
-{
- node_t *p;
-
- for (p = node->parent; p; p = p->parent)
- {
- if (p->planenum == pnum) Error("Tried parent");
- } //end for
-} //end of the function CheckPlaneAgainstParants
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean CheckPlaneAgainstVolume (int pnum, node_t *node)
-{
- bspbrush_t *front, *back;
- qboolean good;
-
- SplitBrush (node->volume, pnum, &front, &back);
-
- good = (front && back);
-
- if (front) FreeBrush (front);
- if (back) FreeBrush (back);
-
- return good;
-} //end of the function CheckPlaneAgaintsVolume
-//===========================================================================
-// Using a hueristic, choses one of the sides out of the brushlist
-// to partition the brushes with.
-// Returns NULL if there are no valid planes to split with..
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-side_t *SelectSplitSide (bspbrush_t *brushes, node_t *node)
-{
- int value, bestvalue;
- bspbrush_t *brush, *test;
- side_t *side, *bestside;
- int i, pass, numpasses;
- int pnum;
- int s;
- int front, back, both, facing, splits;
- int bsplits;
- int bestsplits;
- int epsilonbrush;
- qboolean hintsplit = false;
-
- bestside = NULL;
- bestvalue = -99999;
- bestsplits = 0;
-
- // the search order goes: visible-structural, visible-detail,
- // nonvisible-structural, nonvisible-detail.
- // If any valid plane is available in a pass, no further
- // passes will be tried.
- numpasses = 2;
- for (pass = 0; pass < numpasses; pass++)
- {
- for (brush = brushes; brush; brush = brush->next)
- {
- // only check detail the second pass
-// if ( (pass & 1) && !(brush->original->contents & CONTENTS_DETAIL) )
-// continue;
-// if ( !(pass & 1) && (brush->original->contents & CONTENTS_DETAIL) )
-// continue;
- for (i = 0; i < brush->numsides; i++)
- {
- side = brush->sides + i;
-// if (side->flags & SFL_BEVEL)
-// continue; // never use a bevel as a spliter
- if (!side->winding)
- continue; // nothing visible, so it can't split
- if (side->texinfo == TEXINFO_NODE)
- continue; // allready a node splitter
- if (side->flags & SFL_TESTED)
- continue; // we allready have metrics for this plane
-// if (side->surf & SURF_SKIP)
-// continue; // skip surfaces are never chosen
-
-// if (!(side->flags & SFL_VISIBLE) && (pass < 2))
-// continue; // only check visible faces on first pass
-
- if ((side->flags & SFL_CURVE) && (pass < 1))
- continue; // only check curves the second pass
-
- pnum = side->planenum;
- pnum &= ~1; // allways use positive facing plane
-
- CheckPlaneAgainstParents (pnum, node);
-
- if (!CheckPlaneAgainstVolume (pnum, node))
- continue; // would produce a tiny volume
-
- front = 0;
- back = 0;
- both = 0;
- facing = 0;
- splits = 0;
- epsilonbrush = 0;
-
- //inner loop: optimize
- for (test = brushes; test; test = test->next)
- {
- s = TestBrushToPlanenum (test, pnum, &bsplits, &hintsplit, &epsilonbrush);
-
- splits += bsplits;
-// if (bsplits && (s&PSIDE_FACING) )
-// Error ("PSIDE_FACING with splits");
-
- test->testside = s;
- //
- if (s & PSIDE_FACING) facing++;
- if (s & PSIDE_FRONT) front++;
- if (s & PSIDE_BACK) back++;
- if (s == PSIDE_BOTH) both++;
- } //end for
-
- // give a value estimate for using this plane
- value = 5*facing - 5*splits - abs(front-back);
-// value = -5*splits;
-// value = 5*facing - 5*splits;
- if (mapplanes[pnum].type < 3)
- value+=5; // axial is better
-
- value -= epsilonbrush * 1000; // avoid!
-
- // never split a hint side except with another hint
- if (hintsplit && !(side->surf & SURF_HINT) )
- value = -9999999;
-
- // save off the side test so we don't need
- // to recalculate it when we actually seperate
- // the brushes
- if (value > bestvalue)
- {
- bestvalue = value;
- bestside = side;
- bestsplits = splits;
- for (test = brushes; test ; test = test->next)
- test->side = test->testside;
- } //end if
- } //end for
- } //end for (brush = brushes;
-
- // if we found a good plane, don't bother trying any
- // other passes
- if (bestside)
- {
- if (pass > 1)
- {
- if (numthreads == 1) c_nonvis++;
- }
- if (pass > 0) node->detail_seperator = true; // not needed for vis
- break;
- } //end if
- } //end for (pass = 0;
-
- //
- // clear all the tested flags we set
- //
- for (brush = brushes ; brush ; brush=brush->next)
- {
- for (i = 0; i < brush->numsides; i++)
- {
- brush->sides[i].flags &= ~SFL_TESTED;
- } //end for
- } //end for
-
- return bestside;
-} //end of the function SelectSplitSide
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BrushMostlyOnSide (bspbrush_t *brush, plane_t *plane)
-{
- int i, j;
- winding_t *w;
- vec_t d, max;
- int side;
-
- max = 0;
- side = PSIDE_FRONT;
- for (i=0 ; i<brush->numsides ; i++)
- {
- w = brush->sides[i].winding;
- if (!w)
- continue;
- for (j=0 ; j<w->numpoints ; j++)
- {
- d = DotProduct (w->p[j], plane->normal) - plane->dist;
- if (d > max)
- {
- max = d;
- side = PSIDE_FRONT;
- }
- if (-d > max)
- {
- max = -d;
- side = PSIDE_BACK;
- }
- }
- }
- return side;
-} //end of the function BrushMostlyOnSide
-//===========================================================================
-// Generates two new brushes, leaving the original
-// unchanged
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void SplitBrush (bspbrush_t *brush, int planenum,
- bspbrush_t **front, bspbrush_t **back)
-{
- bspbrush_t *b[2];
- int i, j;
- winding_t *w, *cw[2], *midwinding;
- plane_t *plane, *plane2;
- side_t *s, *cs;
- float d, d_front, d_back;
-
- *front = *back = NULL;
- plane = &mapplanes[planenum];
-
- // check all points
- d_front = d_back = 0;
- for (i=0 ; i<brush->numsides ; i++)
- {
- w = brush->sides[i].winding;
- if (!w)
- continue;
- for (j=0 ; j<w->numpoints ; j++)
- {
- d = DotProduct (w->p[j], plane->normal) - plane->dist;
- if (d > 0 && d > d_front)
- d_front = d;
- if (d < 0 && d < d_back)
- d_back = d;
- }
- }
-
- if (d_front < 0.2) // PLANESIDE_EPSILON)
- { // only on back
- *back = CopyBrush (brush);
- return;
- }
- if (d_back > -0.2) // PLANESIDE_EPSILON)
- { // only on front
- *front = CopyBrush (brush);
- return;
- }
-
- // create a new winding from the split plane
-
- w = BaseWindingForPlane (plane->normal, plane->dist);
- for (i=0 ; i<brush->numsides && w ; i++)
- {
- plane2 = &mapplanes[brush->sides[i].planenum ^ 1];
- ChopWindingInPlace (&w, plane2->normal, plane2->dist, 0); // PLANESIDE_EPSILON);
- }
-
- if (!w || WindingIsTiny(w))
- { // the brush isn't really split
- int side;
-
- side = BrushMostlyOnSide (brush, plane);
- if (side == PSIDE_FRONT)
- *front = CopyBrush (brush);
- if (side == PSIDE_BACK)
- *back = CopyBrush (brush);
- //free a possible winding
- if (w) FreeWinding(w);
- return;
- }
-
- if (WindingIsHuge (w))
- {
- Log_Write("WARNING: huge winding\n");
- }
-
- midwinding = w;
-
- // split it for real
-
- for (i=0 ; i<2 ; i++)
- {
- b[i] = AllocBrush (brush->numsides+1);
- b[i]->original = brush->original;
- }
-
- // split all the current windings
-
- for (i=0 ; i<brush->numsides ; i++)
- {
- s = &brush->sides[i];
- w = s->winding;
- if (!w)
- continue;
- ClipWindingEpsilon (w, plane->normal, plane->dist,
- 0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]);
- for (j=0 ; j<2 ; j++)
- {
- if (!cw[j])
- continue;
-#if 0
- if (WindingIsTiny (cw[j]))
- {
- FreeWinding (cw[j]);
- continue;
- }
-#endif
- cs = &b[j]->sides[b[j]->numsides];
- b[j]->numsides++;
- *cs = *s;
-// cs->planenum = s->planenum;
-// cs->texinfo = s->texinfo;
-// cs->original = s->original;
- cs->winding = cw[j];
- cs->flags &= ~SFL_TESTED;
- }
- }
-
-
- // see if we have valid polygons on both sides
-
- for (i=0 ; i<2 ; i++)
- {
- BoundBrush (b[i]);
- for (j=0 ; j<3 ; j++)
- {
- if (b[i]->mins[j] < -MAX_MAP_BOUNDS || b[i]->maxs[j] > MAX_MAP_BOUNDS)
- {
- Log_Write("bogus brush after clip");
- break;
- }
- }
-
- if (b[i]->numsides < 3 || j < 3)
- {
- FreeBrush (b[i]);
- b[i] = NULL;
- }
- }
-
- if ( !(b[0] && b[1]) )
- {
- if (!b[0] && !b[1])
- Log_Write("split removed brush\r\n");
- else
- Log_Write("split not on both sides\r\n");
- if (b[0])
- {
- FreeBrush (b[0]);
- *front = CopyBrush (brush);
- }
- if (b[1])
- {
- FreeBrush (b[1]);
- *back = CopyBrush (brush);
- }
- return;
- }
-
- // add the midwinding to both sides
- for (i=0 ; i<2 ; i++)
- {
- cs = &b[i]->sides[b[i]->numsides];
- b[i]->numsides++;
-
- cs->planenum = planenum^i^1;
- cs->texinfo = TEXINFO_NODE; //never use these sides as splitters
- cs->flags &= ~SFL_VISIBLE;
- cs->flags &= ~SFL_TESTED;
- if (i==0)
- cs->winding = CopyWinding (midwinding);
- else
- cs->winding = midwinding;
- }
-
-{
- vec_t v1;
- int i;
-
- for (i = 0; i < 2; i++)
- {
- v1 = BrushVolume (b[i]);
- if (v1 < 1.0)
- {
- FreeBrush(b[i]);
- b[i] = NULL;
- //Log_Write("tiny volume after clip");
- }
- }
- if (!b[0] && !b[1])
- {
- Log_Write("two tiny brushes\r\n");
- } //end if
-}
-
- *front = b[0];
- *back = b[1];
-} //end of the function SplitBrush
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void SplitBrushList (bspbrush_t *brushes,
- node_t *node, bspbrush_t **front, bspbrush_t **back)
-{
- bspbrush_t *brush, *newbrush, *newbrush2;
- side_t *side;
- int sides;
- int i;
-
- *front = *back = NULL;
-
- for (brush = brushes; brush; brush = brush->next)
- {
- sides = brush->side;
-
- if (sides == PSIDE_BOTH)
- { // split into two brushes
- SplitBrush (brush, node->planenum, &newbrush, &newbrush2);
- if (newbrush)
- {
- newbrush->next = *front;
- *front = newbrush;
- } //end if
- if (newbrush2)
- {
- newbrush2->next = *back;
- *back = newbrush2;
- } //end if
- continue;
- } //end if
-
- newbrush = CopyBrush (brush);
-
- // if the planenum is actualy a part of the brush
- // find the plane and flag it as used so it won't be tried
- // as a splitter again
- if (sides & PSIDE_FACING)
- {
- for (i=0 ; i<newbrush->numsides ; i++)
- {
- side = newbrush->sides + i;
- if ( (side->planenum& ~1) == node->planenum)
- side->texinfo = TEXINFO_NODE;
- } //end for
- } //end if
- if (sides & PSIDE_FRONT)
- {
- newbrush->next = *front;
- *front = newbrush;
- continue;
- } //end if
- if (sides & PSIDE_BACK)
- {
- newbrush->next = *back;
- *back = newbrush;
- continue;
- } //end if
- } //end for
-} //end of the function SplitBrushList
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void CheckBrushLists(bspbrush_t *brushlist1, bspbrush_t *brushlist2)
-{
- bspbrush_t *brush1, *brush2;
-
- for (brush1 = brushlist1; brush1; brush1 = brush1->next)
- {
- for (brush2 = brushlist2; brush2; brush2 = brush2->next)
- {
- assert(brush1 != brush2);
- } //end for
- } //end for
-} //end of the function CheckBrushLists
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int numrecurse = 0;
-
-node_t *BuildTree_r (node_t *node, bspbrush_t *brushes)
-{
- node_t *newnode;
- side_t *bestside;
- int i, totalmem;
- bspbrush_t *children[2];
-
- qprintf("\r%6d", numrecurse);
- numrecurse++;
-
- if (numthreads == 1)
- {
- totalmem = WindingMemory() + c_nodememory + c_brushmemory;
- if (totalmem > c_peak_totalbspmemory)
- c_peak_totalbspmemory = totalmem;
- c_nodes++;
- } //endif
-
- if (drawflag)
- DrawBrushList(brushes, node);
-
- // find the best plane to use as a splitter
- bestside = SelectSplitSide (brushes, node);
- if (!bestside)
- {
- // leaf node
- node->side = NULL;
- node->planenum = -1;
- LeafNode(node, brushes);
- if (node->contents & CONTENTS_SOLID) c_solidleafnodes++;
- if (create_aas)
- {
- //free up memory!!!
- FreeBrushList(node->brushlist);
- node->brushlist = NULL;
- //free the node volume brush
- if (node->volume)
- {
- FreeBrush(node->volume);
- node->volume = NULL;
- } //end if
- } //end if
- return node;
- } //end if
-
- // this is a splitplane node
- node->side = bestside;
- node->planenum = bestside->planenum & ~1; // always use front facing
-
- //split the brush list in two for both children
- SplitBrushList (brushes, node, &children[0], &children[1]);
- //free the old brush list
- FreeBrushList (brushes);
-
- // allocate children before recursing
- for (i = 0; i < 2; i++)
- {
- newnode = AllocNode ();
- newnode->parent = node;
- node->children[i] = newnode;
- } //end for
-
- //split the volume brush of the node for the children
- SplitBrush (node->volume, node->planenum, &node->children[0]->volume,
- &node->children[1]->volume);
-
- if (create_aas)
- {
- //free the volume brush
- if (node->volume)
- {
- FreeBrush(node->volume);
- node->volume = NULL;
- } //end if
- } //end if
- // recursively process children
- for (i = 0; i < 2; i++)
- {
- node->children[i] = BuildTree_r(node->children[i], children[i]);
- } //end for
-
- return node;
-} //end of the function BuildTree_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-node_t *firstnode; //first node in the list
-node_t *lastnode; //last node in the list
-int nodelistsize; //number of nodes in the list
-int use_nodequeue = 0; //use nodequeue, otherwise a node stack is used
-int numwaiting = 0;
-
-void (*AddNodeToList)(node_t *node);
-
-//add the node to the front of the node list
-//(effectively using a node stack)
-void AddNodeToStack(node_t *node)
-{
- ThreadLock();
-
- node->next = firstnode;
- firstnode = node;
- if (!lastnode) lastnode = node;
- nodelistsize++;
-
- ThreadUnlock();
- //
- ThreadSemaphoreIncrease(1);
-} //end of the function AddNodeToStack
-//add the node to the end of the node list
-//(effectively using a node queue)
-void AddNodeToQueue(node_t *node)
-{
- ThreadLock();
-
- node->next = NULL;
- if (lastnode) lastnode->next = node;
- else firstnode = node;
- lastnode = node;
- nodelistsize++;
-
- ThreadUnlock();
- //
- ThreadSemaphoreIncrease(1);
-} //end of the function AddNodeToQueue
-//get the first node from the front of the node list
-node_t *NextNodeFromList(void)
-{
- node_t *node;
-
- ThreadLock();
- numwaiting++;
- if (!firstnode)
- {
- if (numwaiting >= GetNumThreads()) ThreadSemaphoreIncrease(GetNumThreads());
- } //end if
- ThreadUnlock();
-
- ThreadSemaphoreWait();
-
- ThreadLock();
-
- numwaiting--;
-
- node = firstnode;
- if (firstnode)
- {
- firstnode = firstnode->next;
- nodelistsize--;
- } //end if
- if (!firstnode) lastnode = NULL;
-
- ThreadUnlock();
-
- return node;
-} //end of the function NextNodeFromList
-//returns the size of the node list
-int NodeListSize(void)
-{
- int size;
-
- ThreadLock();
- size = nodelistsize;
- ThreadUnlock();
-
- return size;
-} //end of the function NodeListSize
-//
-void IncreaseNodeCounter(void)
-{
- ThreadLock();
- //if (verbose) printf("\r%6d", numrecurse++);
- qprintf("\r%6d", numrecurse++);
- //qprintf("\r%6d %d, %5d ", numrecurse++, GetNumThreads(), nodelistsize);
- ThreadUnlock();
-} //end of the function IncreaseNodeCounter
-//thread function, gets nodes from the nodelist and processes them
-void BuildTreeThread(int threadid)
-{
- node_t *newnode, *node;
- side_t *bestside;
- int i, totalmem;
- bspbrush_t *brushes;
-
- for (node = NextNodeFromList(); node; )
- {
- //if the nodelist isn't empty try to add another thread
- //if (NodeListSize() > 10) AddThread(BuildTreeThread);
- //display the number of nodes processed so far
- if (numthreads == 1)
- IncreaseNodeCounter();
-
- brushes = node->brushlist;
-
- if (numthreads == 1)
- {
- totalmem = WindingMemory() + c_nodememory + c_brushmemory;
- if (totalmem > c_peak_totalbspmemory)
- {
- c_peak_totalbspmemory = totalmem;
- } //end if
- c_nodes++;
- } //endif
-
- if (drawflag)
- {
- DrawBrushList(brushes, node);
- } //end if
-
- if (cancelconversion)
- {
- bestside = NULL;
- } //end if
- else
- {
- // find the best plane to use as a splitter
- bestside = SelectSplitSide(brushes, node);
- } //end else
- //if there's no split side left
- if (!bestside)
- {
- //create a leaf out of the node
- LeafNode(node, brushes);
- if (node->contents & CONTENTS_SOLID) c_solidleafnodes++;
- if (create_aas)
- {
- //free up memory!!!
- FreeBrushList(node->brushlist);
- node->brushlist = NULL;
- } //end if
- //free the node volume brush (it is not used anymore)
- if (node->volume)
- {
- FreeBrush(node->volume);
- node->volume = NULL;
- } //end if
- node = NextNodeFromList();
- continue;
- } //end if
-
- // this is a splitplane node
- node->side = bestside;
- node->planenum = bestside->planenum & ~1; //always use front facing
-
- //allocate children
- for (i = 0; i < 2; i++)
- {
- newnode = AllocNode();
- newnode->parent = node;
- node->children[i] = newnode;
- } //end for
-
- //split the brush list in two for both children
- SplitBrushList(brushes, node, &node->children[0]->brushlist, &node->children[1]->brushlist);
-
- CheckBrushLists(node->children[0]->brushlist, node->children[1]->brushlist);
- //free the old brush list
- FreeBrushList(brushes);
- node->brushlist = NULL;
-
- //split the volume brush of the node for the children
- SplitBrush(node->volume, node->planenum, &node->children[0]->volume,
- &node->children[1]->volume);
-
- if (!node->children[0]->volume || !node->children[1]->volume)
- {
- Error("child without volume brush");
- } //end if
-
- //free the volume brush
- if (node->volume)
- {
- FreeBrush(node->volume);
- node->volume = NULL;
- } //end if
- //add both children to the node list
- //AddNodeToList(node->children[0]);
- AddNodeToList(node->children[1]);
- node = node->children[0];
- } //end while
- RemoveThread(threadid);
-} //end of the function BuildTreeThread
-//===========================================================================
-// build the bsp tree using a node list
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BuildTree(tree_t *tree)
-{
- int i;
-
- firstnode = NULL;
- lastnode = NULL;
- //use a node queue or node stack
- if (use_nodequeue) AddNodeToList = AddNodeToQueue;
- else AddNodeToList = AddNodeToStack;
- //setup thread locking
- ThreadSetupLock();
- ThreadSetupSemaphore();
- numwaiting = 0;
- //
- Log_Print("%6d threads max\n", numthreads);
- if (use_nodequeue) Log_Print("breadth first bsp building\n");
- else Log_Print("depth first bsp building\n");
- qprintf("%6d splits", 0);
- //add the first node to the list
- AddNodeToList(tree->headnode);
- //start the threads
- for (i = 0; i < numthreads; i++)
- AddThread(BuildTreeThread);
- //wait for all added threads to be finished
- WaitForAllThreadsFinished();
- //shutdown the thread locking
- ThreadShutdownLock();
- ThreadShutdownSemaphore();
-} //end of the function BuildTree
-//===========================================================================
-// The incoming brush list will be freed before exiting
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-tree_t *BrushBSP(bspbrush_t *brushlist, vec3_t mins, vec3_t maxs)
-{
- int i, c_faces, c_nonvisfaces, c_brushes;
- bspbrush_t *b;
- node_t *node;
- tree_t *tree;
- vec_t volume;
-// vec3_t point;
-
- Log_Print("-------- Brush BSP ---------\n");
-
- tree = Tree_Alloc();
-
- c_faces = 0;
- c_nonvisfaces = 0;
- c_brushes = 0;
- c_totalsides = 0;
- for (b = brushlist; b; b = b->next)
- {
- c_brushes++;
-
- volume = BrushVolume(b);
- if (volume < microvolume)
- {
- Log_Print("WARNING: entity %i, brush %i: microbrush\n",
- b->original->entitynum, b->original->brushnum);
- } //end if
-
- for (i=0 ; i<b->numsides ; i++)
- {
- if (b->sides[i].flags & SFL_BEVEL)
- continue;
- if (!b->sides[i].winding)
- continue;
- if (b->sides[i].texinfo == TEXINFO_NODE)
- continue;
- if (b->sides[i].flags & SFL_VISIBLE)
- {
- c_faces++;
- } //end if
- else
- {
- c_nonvisfaces++;
- //if (create_aas) b->sides[i].texinfo = TEXINFO_NODE;
- } //end if
- } //end for
- c_totalsides += b->numsides;
-
- AddPointToBounds (b->mins, tree->mins, tree->maxs);
- AddPointToBounds (b->maxs, tree->mins, tree->maxs);
- } //end for
-
- Log_Print("%6i brushes\n", c_brushes);
- Log_Print("%6i visible faces\n", c_faces);
- Log_Print("%6i nonvisible faces\n", c_nonvisfaces);
- Log_Print("%6i total sides\n", c_totalsides);
-
- c_active_brushes = c_brushes;
- c_nodememory = 0;
- c_brushmemory = 0;
- c_peak_brushmemory = 0;
-
- c_nodes = 0;
- c_nonvis = 0;
- node = AllocNode ();
-
- //volume of first node (head node)
- node->volume = BrushFromBounds (mins, maxs);
- //
- tree->headnode = node;
- //just get some statistics and the mins/maxs of the node
- numrecurse = 0;
-// qprintf("%6d splits", numrecurse);
-
- tree->headnode->brushlist = brushlist;
- BuildTree(tree);
-
- //build the bsp tree with the start node from the brushlist
-// node = BuildTree_r(node, brushlist);
-
- //if the conversion is cancelled
- if (cancelconversion) return tree;
-
- qprintf("\n");
- Log_Write("%6d splits\r\n", numrecurse);
-// Log_Print("%6i visible nodes\n", c_nodes/2 - c_nonvis);
-// Log_Print("%6i nonvis nodes\n", c_nonvis);
-// Log_Print("%6i leaves\n", (c_nodes+1)/2);
-// Log_Print("%6i solid leaf nodes\n", c_solidleafnodes);
-// Log_Print("%6i active brushes\n", c_active_brushes);
- if (numthreads == 1)
- {
-// Log_Print("%6i KB of node memory\n", c_nodememory >> 10);
-// Log_Print("%6i KB of brush memory\n", c_brushmemory >> 10);
-// Log_Print("%6i KB of peak brush memory\n", c_peak_brushmemory >> 10);
-// Log_Print("%6i KB of winding memory\n", WindingMemory() >> 10);
-// Log_Print("%6i KB of peak winding memory\n", WindingPeakMemory() >> 10);
- Log_Print("%6i KB of peak total bsp memory\n", c_peak_totalbspmemory >> 10);
- } //end if
-
- /*
- point[0] = 1485;
- point[1] = 956.125;
- point[2] = 352.125;
- node = PointInLeaf(tree->headnode, point);
- if (node->planenum != PLANENUM_LEAF)
- {
- Log_Print("node not a leaf\n");
- } //end if
- Log_Print("at %f %f %f:\n", point[0], point[1], point[2]);
- PrintContents(node->contents);
- Log_Print("node->expansionbboxes = %d\n", node->expansionbboxes);
- //*/
- return tree;
-} //end of the function BrushBSP
-
+/*
+===========================================================================
+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 "l_mem.h"
+#include "../botlib/aasfile.h"
+#include "aas_store.h"
+#include "aas_cfg.h"
+
+#include <assert.h>
+
+/*
+each side has a count of the other sides it splits
+
+the best split will be the one that minimizes the total split counts
+of all remaining sides
+
+precalc side on plane table
+
+evaluate split side
+{
+cost = 0
+for all sides
+ for all sides
+ get
+ if side splits side and splitside is on same child
+ cost++;
+}
+*/
+
+int c_nodes;
+int c_nonvis;
+int c_active_brushes;
+int c_solidleafnodes;
+int c_totalsides;
+int c_brushmemory;
+int c_peak_brushmemory;
+int c_nodememory;
+int c_peak_totalbspmemory;
+
+// if a brush just barely pokes onto the other side,
+// let it slide by without chopping
+#define PLANESIDE_EPSILON 0.001
+//0.1
+
+//#ifdef DEBUG
+typedef struct cname_s
+{
+ int value;
+ char *name;
+} cname_t;
+
+cname_t contentnames[] =
+{
+ {CONTENTS_SOLID,"CONTENTS_SOLID"},
+ {CONTENTS_WINDOW,"CONTENTS_WINDOW"},
+ {CONTENTS_AUX,"CONTENTS_AUX"},
+ {CONTENTS_LAVA,"CONTENTS_LAVA"},
+ {CONTENTS_SLIME,"CONTENTS_SLIME"},
+ {CONTENTS_WATER,"CONTENTS_WATER"},
+ {CONTENTS_MIST,"CONTENTS_MIST"},
+ {LAST_VISIBLE_CONTENTS,"LAST_VISIBLE_CONTENTS"},
+
+ {CONTENTS_AREAPORTAL,"CONTENTS_AREAPORTAL"},
+ {CONTENTS_PLAYERCLIP,"CONTENTS_PLAYERCLIP"},
+ {CONTENTS_MONSTERCLIP,"CONTENTS_MONSTERCLIP"},
+ {CONTENTS_CURRENT_0,"CONTENTS_CURRENT_0"},
+ {CONTENTS_CURRENT_90,"CONTENTS_CURRENT_90"},
+ {CONTENTS_CURRENT_180,"CONTENTS_CURRENT_180"},
+ {CONTENTS_CURRENT_270,"CONTENTS_CURRENT_270"},
+ {CONTENTS_CURRENT_UP,"CONTENTS_CURRENT_UP"},
+ {CONTENTS_CURRENT_DOWN,"CONTENTS_CURRENT_DOWN"},
+ {CONTENTS_ORIGIN,"CONTENTS_ORIGIN"},
+ {CONTENTS_MONSTER,"CONTENTS_MONSTER"},
+ {CONTENTS_DEADMONSTER,"CONTENTS_DEADMONSTER"},
+ {CONTENTS_DETAIL,"CONTENTS_DETAIL"},
+ {CONTENTS_Q2TRANSLUCENT,"CONTENTS_TRANSLUCENT"},
+ {CONTENTS_LADDER,"CONTENTS_LADDER"},
+ {0, 0}
+};
+
+void PrintContents(int contents)
+{
+ int i;
+
+ for (i = 0; contentnames[i].value; i++)
+ {
+ if (contents & contentnames[i].value)
+ {
+ Log_Write("%s,", contentnames[i].name);
+ } //end if
+ } //end for
+} //end of the function PrintContents
+
+//#endif DEBUG
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ResetBrushBSP(void)
+{
+ c_nodes = 0;
+ c_nonvis = 0;
+ c_active_brushes = 0;
+ c_solidleafnodes = 0;
+ c_totalsides = 0;
+ c_brushmemory = 0;
+ c_peak_brushmemory = 0;
+ c_nodememory = 0;
+ c_peak_totalbspmemory = 0;
+} //end of the function ResetBrushBSP
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void FindBrushInTree (node_t *node, int brushnum)
+{
+ bspbrush_t *b;
+
+ if (node->planenum == PLANENUM_LEAF)
+ {
+ for (b=node->brushlist ; b ; b=b->next)
+ if (b->original->brushnum == brushnum)
+ Log_Print ("here\n");
+ return;
+ }
+ FindBrushInTree(node->children[0], brushnum);
+ FindBrushInTree(node->children[1], brushnum);
+} //end of the function FindBrushInTree
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void DrawBrushList (bspbrush_t *brush, node_t *node)
+{
+ int i;
+ side_t *s;
+
+ GLS_BeginScene ();
+ for ( ; brush ; brush=brush->next)
+ {
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ s = &brush->sides[i];
+ if (!s->winding)
+ continue;
+ if (s->texinfo == TEXINFO_NODE)
+ GLS_Winding (s->winding, 1);
+ else if (!(s->flags & SFL_VISIBLE))
+ GLS_Winding (s->winding, 2);
+ else
+ GLS_Winding (s->winding, 0);
+ }
+ }
+ GLS_EndScene ();
+} //end of the function DrawBrushList
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void WriteBrushList (char *name, bspbrush_t *brush, qboolean onlyvis)
+{
+ int i;
+ side_t *s;
+ FILE *f;
+
+ qprintf ("writing %s\n", name);
+ f = SafeOpenWrite (name);
+
+ for ( ; brush ; brush=brush->next)
+ {
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ s = &brush->sides[i];
+ if (!s->winding)
+ continue;
+ if (onlyvis && !(s->flags & SFL_VISIBLE))
+ continue;
+ OutputWinding (brush->sides[i].winding, f);
+ }
+ }
+
+ fclose (f);
+} //end of the function WriteBrushList
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void PrintBrush (bspbrush_t *brush)
+{
+ int i;
+
+ printf ("brush: %p\n", brush);
+ for (i=0;i<brush->numsides ; i++)
+ {
+ pw(brush->sides[i].winding);
+ printf ("\n");
+ } //end for
+} //end of the function PrintBrush
+//===========================================================================
+// Sets the mins/maxs based on the windings
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void BoundBrush (bspbrush_t *brush)
+{
+ int i, j;
+ winding_t *w;
+
+ ClearBounds (brush->mins, brush->maxs);
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ w = brush->sides[i].winding;
+ if (!w)
+ continue;
+ for (j=0 ; j<w->numpoints ; j++)
+ AddPointToBounds (w->p[j], brush->mins, brush->maxs);
+ }
+} //end of the function BoundBrush
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void CreateBrushWindings (bspbrush_t *brush)
+{
+ int i, j;
+ winding_t *w;
+ side_t *side;
+ plane_t *plane;
+
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ side = &brush->sides[i];
+ plane = &mapplanes[side->planenum];
+ w = BaseWindingForPlane (plane->normal, plane->dist);
+ for (j=0 ; j<brush->numsides && w; j++)
+ {
+ if (i == j)
+ continue;
+ if (brush->sides[j].flags & SFL_BEVEL)
+ continue;
+ plane = &mapplanes[brush->sides[j].planenum^1];
+ ChopWindingInPlace (&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
+ }
+
+ side->winding = w;
+ }
+
+ BoundBrush (brush);
+} //end of the function CreateBrushWindings
+//===========================================================================
+// Creates a new axial brush
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *BrushFromBounds (vec3_t mins, vec3_t maxs)
+{
+ bspbrush_t *b;
+ int i;
+ vec3_t normal;
+ vec_t dist;
+
+ b = AllocBrush (6);
+ b->numsides = 6;
+ for (i=0 ; i<3 ; i++)
+ {
+ VectorClear (normal);
+ normal[i] = 1;
+ dist = maxs[i];
+ b->sides[i].planenum = FindFloatPlane (normal, dist);
+
+ normal[i] = -1;
+ dist = -mins[i];
+ b->sides[3+i].planenum = FindFloatPlane (normal, dist);
+ }
+
+ CreateBrushWindings (b);
+
+ return b;
+} //end of the function BrushFromBounds
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int BrushOutOfBounds(bspbrush_t *brush, vec3_t mins, vec3_t maxs, float epsilon)
+{
+ int i, j, n;
+ winding_t *w;
+ side_t *side;
+
+ for (i = 0; i < brush->numsides; i++)
+ {
+ side = &brush->sides[i];
+ w = side->winding;
+ for (j = 0; j < w->numpoints; j++)
+ {
+ for (n = 0; n < 3; n++)
+ {
+ if (w->p[j][n] < (mins[n] + epsilon) || w->p[j][n] > (maxs[n] - epsilon)) return true;
+ } //end for
+ } //end for
+ } //end for
+ return false;
+} //end of the function BrushOutOfBounds
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+vec_t BrushVolume (bspbrush_t *brush)
+{
+ int i;
+ winding_t *w;
+ vec3_t corner;
+ vec_t d, area, volume;
+ plane_t *plane;
+
+ if (!brush) return 0;
+
+ // grab the first valid point as the corner
+ w = NULL;
+ for (i = 0; i < brush->numsides; i++)
+ {
+ w = brush->sides[i].winding;
+ if (w) break;
+ } //end for
+ if (!w) return 0;
+ VectorCopy (w->p[0], corner);
+
+ // make tetrahedrons to all other faces
+ volume = 0;
+ for ( ; i < brush->numsides; i++)
+ {
+ w = brush->sides[i].winding;
+ if (!w) continue;
+ plane = &mapplanes[brush->sides[i].planenum];
+ d = -(DotProduct (corner, plane->normal) - plane->dist);
+ area = WindingArea(w);
+ volume += d * area;
+ } //end for
+
+ volume /= 3;
+ return volume;
+} //end of the function BrushVolume
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int CountBrushList (bspbrush_t *brushes)
+{
+ int c;
+
+ c = 0;
+ for ( ; brushes; brushes = brushes->next) c++;
+ return c;
+} //end of the function CountBrushList
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+node_t *AllocNode (void)
+{
+ node_t *node;
+
+ node = GetMemory(sizeof(*node));
+ memset (node, 0, sizeof(*node));
+ if (numthreads == 1)
+ {
+ c_nodememory += MemorySize(node);
+ } //end if
+ return node;
+} //end of the function AllocNode
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *AllocBrush (int numsides)
+{
+ bspbrush_t *bb;
+ int c;
+
+ c = (int)&(((bspbrush_t *)0)->sides[numsides]);
+ bb = GetMemory(c);
+ memset (bb, 0, c);
+ if (numthreads == 1)
+ {
+ c_active_brushes++;
+ c_brushmemory += MemorySize(bb);
+ if (c_brushmemory > c_peak_brushmemory)
+ c_peak_brushmemory = c_brushmemory;
+ } //end if
+ return bb;
+} //end of the function AllocBrush
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void FreeBrush (bspbrush_t *brushes)
+{
+ int i;
+
+ for (i=0 ; i<brushes->numsides ; i++)
+ if (brushes->sides[i].winding)
+ FreeWinding(brushes->sides[i].winding);
+ if (numthreads == 1)
+ {
+ c_active_brushes--;
+ c_brushmemory -= MemorySize(brushes);
+ if (c_brushmemory < 0) c_brushmemory = 0;
+ } //end if
+ FreeMemory(brushes);
+} //end of the function FreeBrush
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void FreeBrushList (bspbrush_t *brushes)
+{
+ bspbrush_t *next;
+
+ for ( ; brushes; brushes = next)
+ {
+ next = brushes->next;
+
+ FreeBrush(brushes);
+ } //end for
+} //end of the function FreeBrushList
+//===========================================================================
+// Duplicates the brush, the sides, and the windings
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *CopyBrush (bspbrush_t *brush)
+{
+ bspbrush_t *newbrush;
+ int size;
+ int i;
+
+ size = (int)&(((bspbrush_t *)0)->sides[brush->numsides]);
+
+ newbrush = AllocBrush (brush->numsides);
+ memcpy (newbrush, brush, size);
+
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ if (brush->sides[i].winding)
+ newbrush->sides[i].winding = CopyWinding (brush->sides[i].winding);
+ }
+
+ return newbrush;
+} //end of the function CopyBrush
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+node_t *PointInLeaf (node_t *node, vec3_t point)
+{
+ vec_t d;
+ plane_t *plane;
+
+ while (node->planenum != PLANENUM_LEAF)
+ {
+ plane = &mapplanes[node->planenum];
+ d = DotProduct (point, plane->normal) - plane->dist;
+ if (d > 0)
+ node = node->children[0];
+ else
+ node = node->children[1];
+ }
+
+ return node;
+} //end of the function PointInLeaf
+//===========================================================================
+// Returns PSIDE_FRONT, PSIDE_BACK, or PSIDE_BOTH
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+#if 0
+int BoxOnPlaneSide (vec3_t mins, vec3_t maxs, plane_t *plane)
+{
+ int side;
+ int i;
+ vec3_t corners[2];
+ vec_t dist1, dist2;
+
+ // axial planes are easy
+ if (plane->type < 3)
+ {
+ side = 0;
+ if (maxs[plane->type] > plane->dist+PLANESIDE_EPSILON)
+ side |= PSIDE_FRONT;
+ if (mins[plane->type] < plane->dist-PLANESIDE_EPSILON)
+ side |= PSIDE_BACK;
+ return side;
+ }
+
+ // create the proper leading and trailing verts for the box
+
+ for (i=0 ; i<3 ; i++)
+ {
+ if (plane->normal[i] < 0)
+ {
+ corners[0][i] = mins[i];
+ corners[1][i] = maxs[i];
+ }
+ else
+ {
+ corners[1][i] = mins[i];
+ corners[0][i] = maxs[i];
+ }
+ }
+
+ dist1 = DotProduct (plane->normal, corners[0]) - plane->dist;
+ dist2 = DotProduct (plane->normal, corners[1]) - plane->dist;
+ side = 0;
+ if (dist1 >= PLANESIDE_EPSILON)
+ side = PSIDE_FRONT;
+ if (dist2 < PLANESIDE_EPSILON)
+ side |= PSIDE_BACK;
+
+ return side;
+}
+#else
+int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, plane_t *p)
+{
+ float dist1, dist2;
+ int sides;
+
+ // axial planes are easy
+ if (p->type < 3)
+ {
+ sides = 0;
+ if (emaxs[p->type] > p->dist+PLANESIDE_EPSILON) sides |= PSIDE_FRONT;
+ if (emins[p->type] < p->dist-PLANESIDE_EPSILON) sides |= PSIDE_BACK;
+ return sides;
+ } //end if
+
+// general case
+ switch (p->signbits)
+ {
+ case 0:
+ dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
+ dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
+ break;
+ case 1:
+ dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
+ dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
+ break;
+ case 2:
+ dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
+ dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
+ break;
+ case 3:
+ dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
+ dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
+ break;
+ case 4:
+ dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
+ dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
+ break;
+ case 5:
+ dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
+ dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
+ break;
+ case 6:
+ dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
+ dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
+ break;
+ case 7:
+ dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
+ dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
+ break;
+ default:
+ dist1 = dist2 = 0; // shut up compiler
+// assert( 0 );
+ break;
+ }
+
+ sides = 0;
+ if (dist1 - p->dist >= PLANESIDE_EPSILON) sides = PSIDE_FRONT;
+ if (dist2 - p->dist < PLANESIDE_EPSILON) sides |= PSIDE_BACK;
+
+// assert(sides != 0);
+
+ return sides;
+}
+#endif
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int QuickTestBrushToPlanenum (bspbrush_t *brush, int planenum, int *numsplits)
+{
+ int i, num;
+ plane_t *plane;
+ int s;
+
+ *numsplits = 0;
+
+ plane = &mapplanes[planenum];
+
+#ifdef ME
+ //fast axial cases
+ if (plane->type < 3)
+ {
+ if (plane->dist + PLANESIDE_EPSILON < brush->mins[plane->type])
+ return PSIDE_FRONT;
+ if (plane->dist - PLANESIDE_EPSILON > brush->maxs[plane->type])
+ return PSIDE_BACK;
+ } //end if
+#endif //ME*/
+
+ // if the brush actually uses the planenum,
+ // we can tell the side for sure
+ for (i = 0; i < brush->numsides; i++)
+ {
+ num = brush->sides[i].planenum;
+ if (num >= MAX_MAPFILE_PLANES)
+ Error ("bad planenum");
+ if (num == planenum)
+ return PSIDE_BACK|PSIDE_FACING;
+ if (num == (planenum ^ 1) )
+ return PSIDE_FRONT|PSIDE_FACING;
+
+ }
+
+ // box on plane side
+ s = BoxOnPlaneSide (brush->mins, brush->maxs, plane);
+
+ // if both sides, count the visible faces split
+ if (s == PSIDE_BOTH)
+ {
+ *numsplits += 3;
+ }
+
+ return s;
+} //end of the function QuickTestBrushToPlanenum
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TestBrushToPlanenum (bspbrush_t *brush, int planenum,
+ int *numsplits, qboolean *hintsplit, int *epsilonbrush)
+{
+ int i, j, num;
+ plane_t *plane;
+ int s = 0;
+ winding_t *w;
+ vec_t d, d_front, d_back;
+ int front, back;
+ int type;
+ float dist;
+
+ *numsplits = 0;
+ *hintsplit = false;
+
+ plane = &mapplanes[planenum];
+
+#ifdef ME
+ //fast axial cases
+ type = plane->type;
+ if (type < 3)
+ {
+ dist = plane->dist;
+ if (dist + PLANESIDE_EPSILON < brush->mins[type]) return PSIDE_FRONT;
+ if (dist - PLANESIDE_EPSILON > brush->maxs[type]) return PSIDE_BACK;
+ if (brush->mins[type] < dist - PLANESIDE_EPSILON &&
+ brush->maxs[type] > dist + PLANESIDE_EPSILON) s = PSIDE_BOTH;
+ } //end if
+
+ if (s != PSIDE_BOTH)
+#endif //ME
+ {
+ // if the brush actually uses the planenum,
+ // we can tell the side for sure
+ for (i = 0; i < brush->numsides; i++)
+ {
+ num = brush->sides[i].planenum;
+ if (num >= MAX_MAPFILE_PLANES) Error ("bad planenum");
+ if (num == planenum)
+ {
+ //we don't need to test this side plane again
+ brush->sides[i].flags |= SFL_TESTED;
+ return PSIDE_BACK|PSIDE_FACING;
+ } //end if
+ if (num == (planenum ^ 1) )
+ {
+ //we don't need to test this side plane again
+ brush->sides[i].flags |= SFL_TESTED;
+ return PSIDE_FRONT|PSIDE_FACING;
+ } //end if
+ } //end for
+
+ // box on plane side
+ s = BoxOnPlaneSide (brush->mins, brush->maxs, plane);
+
+ if (s != PSIDE_BOTH) return s;
+ } //end if
+
+ // if both sides, count the visible faces split
+ d_front = d_back = 0;
+
+ for (i = 0; i < brush->numsides; i++)
+ {
+ if (brush->sides[i].texinfo == TEXINFO_NODE)
+ continue; // on node, don't worry about splits
+ if (!(brush->sides[i].flags & SFL_VISIBLE))
+ continue; // we don't care about non-visible
+ w = brush->sides[i].winding;
+ if (!w) continue;
+ front = back = 0;
+ for (j = 0; j < w->numpoints; j++)
+ {
+ d = DotProduct(w->p[j], plane->normal) - plane->dist;
+ if (d > d_front) d_front = d;
+ if (d < d_back) d_back = d;
+ if (d > 0.1) // PLANESIDE_EPSILON)
+ front = 1;
+ if (d < -0.1) // PLANESIDE_EPSILON)
+ back = 1;
+ } //end for
+ if (front && back)
+ {
+ if ( !(brush->sides[i].surf & SURF_SKIP) )
+ {
+ (*numsplits)++;
+ if (brush->sides[i].surf & SURF_HINT)
+ {
+ *hintsplit = true;
+ } //end if
+ } //end if
+ } //end if
+ } //end for
+
+ if ( (d_front > 0.0 && d_front < 1.0)
+ || (d_back < 0.0 && d_back > -1.0) )
+ (*epsilonbrush)++;
+
+#if 0
+ if (*numsplits == 0)
+ { // didn't really need to be split
+ if (front) s = PSIDE_FRONT;
+ else if (back) s = PSIDE_BACK;
+ else s = 0;
+ }
+#endif
+
+ return s;
+} //end of the function TestBrushToPlanenum
+//===========================================================================
+// Returns true if the winding would be crunched out of
+// existance by the vertex snapping.
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+#define EDGE_LENGTH 0.2
+qboolean WindingIsTiny (winding_t *w)
+{
+#if 0
+ if (WindingArea (w) < 1)
+ return true;
+ return false;
+#else
+ int i, j;
+ vec_t len;
+ vec3_t delta;
+ int edges;
+
+ edges = 0;
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ j = i == w->numpoints - 1 ? 0 : i+1;
+ VectorSubtract (w->p[j], w->p[i], delta);
+ len = VectorLength (delta);
+ if (len > EDGE_LENGTH)
+ {
+ if (++edges == 3)
+ return false;
+ }
+ }
+ return true;
+#endif
+} //end of the function WindingIsTiny
+//===========================================================================
+// Returns true if the winding still has one of the points
+// from basewinding for plane
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+qboolean WindingIsHuge (winding_t *w)
+{
+ int i, j;
+
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ for (j=0 ; j<3 ; j++)
+ if (w->p[i][j] < -BOGUS_RANGE+1 || w->p[i][j] > BOGUS_RANGE-1)
+ return true;
+ }
+ return false;
+} //end of the function WindingIsHuge
+//===========================================================================
+// creates a leaf out of the given nodes with the given brushes
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void LeafNode(node_t *node, bspbrush_t *brushes)
+{
+ bspbrush_t *b;
+ int i;
+
+ node->side = NULL;
+ node->planenum = PLANENUM_LEAF;
+ node->contents = 0;
+
+ for (b = brushes; b; b = b->next)
+ {
+ // if the brush is solid and all of its sides are on nodes,
+ // it eats everything
+ if (b->original->contents & CONTENTS_SOLID)
+ {
+ for (i=0 ; i<b->numsides ; i++)
+ if (b->sides[i].texinfo != TEXINFO_NODE)
+ break;
+ if (i == b->numsides)
+ {
+ node->contents = CONTENTS_SOLID;
+ break;
+ } //end if
+ } //end if
+ node->contents |= b->original->contents;
+ } //end for
+
+ if (create_aas)
+ {
+ node->expansionbboxes = 0;
+ node->contents = 0;
+ for (b = brushes; b; b = b->next)
+ {
+ node->expansionbboxes |= b->original->expansionbbox;
+ node->contents |= b->original->contents;
+ if (b->original->modelnum)
+ node->modelnum = b->original->modelnum;
+ } //end for
+ if (node->contents & CONTENTS_SOLID)
+ {
+ if (node->expansionbboxes != cfg.allpresencetypes)
+ {
+ node->contents &= ~CONTENTS_SOLID;
+ } //end if
+ } //end if
+ } //end if
+
+ node->brushlist = brushes;
+} //end of the function LeafNode
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void CheckPlaneAgainstParents (int pnum, node_t *node)
+{
+ node_t *p;
+
+ for (p = node->parent; p; p = p->parent)
+ {
+ if (p->planenum == pnum) Error("Tried parent");
+ } //end for
+} //end of the function CheckPlaneAgainstParants
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+qboolean CheckPlaneAgainstVolume (int pnum, node_t *node)
+{
+ bspbrush_t *front, *back;
+ qboolean good;
+
+ SplitBrush (node->volume, pnum, &front, &back);
+
+ good = (front && back);
+
+ if (front) FreeBrush (front);
+ if (back) FreeBrush (back);
+
+ return good;
+} //end of the function CheckPlaneAgaintsVolume
+//===========================================================================
+// Using a hueristic, choses one of the sides out of the brushlist
+// to partition the brushes with.
+// Returns NULL if there are no valid planes to split with..
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+side_t *SelectSplitSide (bspbrush_t *brushes, node_t *node)
+{
+ int value, bestvalue;
+ bspbrush_t *brush, *test;
+ side_t *side, *bestside;
+ int i, pass, numpasses;
+ int pnum;
+ int s;
+ int front, back, both, facing, splits;
+ int bsplits;
+ int bestsplits;
+ int epsilonbrush;
+ qboolean hintsplit = false;
+
+ bestside = NULL;
+ bestvalue = -99999;
+ bestsplits = 0;
+
+ // the search order goes: visible-structural, visible-detail,
+ // nonvisible-structural, nonvisible-detail.
+ // If any valid plane is available in a pass, no further
+ // passes will be tried.
+ numpasses = 2;
+ for (pass = 0; pass < numpasses; pass++)
+ {
+ for (brush = brushes; brush; brush = brush->next)
+ {
+ // only check detail the second pass
+// if ( (pass & 1) && !(brush->original->contents & CONTENTS_DETAIL) )
+// continue;
+// if ( !(pass & 1) && (brush->original->contents & CONTENTS_DETAIL) )
+// continue;
+ for (i = 0; i < brush->numsides; i++)
+ {
+ side = brush->sides + i;
+// if (side->flags & SFL_BEVEL)
+// continue; // never use a bevel as a spliter
+ if (!side->winding)
+ continue; // nothing visible, so it can't split
+ if (side->texinfo == TEXINFO_NODE)
+ continue; // allready a node splitter
+ if (side->flags & SFL_TESTED)
+ continue; // we allready have metrics for this plane
+// if (side->surf & SURF_SKIP)
+// continue; // skip surfaces are never chosen
+
+// if (!(side->flags & SFL_VISIBLE) && (pass < 2))
+// continue; // only check visible faces on first pass
+
+ if ((side->flags & SFL_CURVE) && (pass < 1))
+ continue; // only check curves the second pass
+
+ pnum = side->planenum;
+ pnum &= ~1; // allways use positive facing plane
+
+ CheckPlaneAgainstParents (pnum, node);
+
+ if (!CheckPlaneAgainstVolume (pnum, node))
+ continue; // would produce a tiny volume
+
+ front = 0;
+ back = 0;
+ both = 0;
+ facing = 0;
+ splits = 0;
+ epsilonbrush = 0;
+
+ //inner loop: optimize
+ for (test = brushes; test; test = test->next)
+ {
+ s = TestBrushToPlanenum (test, pnum, &bsplits, &hintsplit, &epsilonbrush);
+
+ splits += bsplits;
+// if (bsplits && (s&PSIDE_FACING) )
+// Error ("PSIDE_FACING with splits");
+
+ test->testside = s;
+ //
+ if (s & PSIDE_FACING) facing++;
+ if (s & PSIDE_FRONT) front++;
+ if (s & PSIDE_BACK) back++;
+ if (s == PSIDE_BOTH) both++;
+ } //end for
+
+ // give a value estimate for using this plane
+ value = 5*facing - 5*splits - abs(front-back);
+// value = -5*splits;
+// value = 5*facing - 5*splits;
+ if (mapplanes[pnum].type < 3)
+ value+=5; // axial is better
+
+ value -= epsilonbrush * 1000; // avoid!
+
+ // never split a hint side except with another hint
+ if (hintsplit && !(side->surf & SURF_HINT) )
+ value = -9999999;
+
+ // save off the side test so we don't need
+ // to recalculate it when we actually seperate
+ // the brushes
+ if (value > bestvalue)
+ {
+ bestvalue = value;
+ bestside = side;
+ bestsplits = splits;
+ for (test = brushes; test ; test = test->next)
+ test->side = test->testside;
+ } //end if
+ } //end for
+ } //end for (brush = brushes;
+
+ // if we found a good plane, don't bother trying any
+ // other passes
+ if (bestside)
+ {
+ if (pass > 1)
+ {
+ if (numthreads == 1) c_nonvis++;
+ }
+ if (pass > 0) node->detail_seperator = true; // not needed for vis
+ break;
+ } //end if
+ } //end for (pass = 0;
+
+ //
+ // clear all the tested flags we set
+ //
+ for (brush = brushes ; brush ; brush=brush->next)
+ {
+ for (i = 0; i < brush->numsides; i++)
+ {
+ brush->sides[i].flags &= ~SFL_TESTED;
+ } //end for
+ } //end for
+
+ return bestside;
+} //end of the function SelectSplitSide
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int BrushMostlyOnSide (bspbrush_t *brush, plane_t *plane)
+{
+ int i, j;
+ winding_t *w;
+ vec_t d, max;
+ int side;
+
+ max = 0;
+ side = PSIDE_FRONT;
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ w = brush->sides[i].winding;
+ if (!w)
+ continue;
+ for (j=0 ; j<w->numpoints ; j++)
+ {
+ d = DotProduct (w->p[j], plane->normal) - plane->dist;
+ if (d > max)
+ {
+ max = d;
+ side = PSIDE_FRONT;
+ }
+ if (-d > max)
+ {
+ max = -d;
+ side = PSIDE_BACK;
+ }
+ }
+ }
+ return side;
+} //end of the function BrushMostlyOnSide
+//===========================================================================
+// Generates two new brushes, leaving the original
+// unchanged
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void SplitBrush (bspbrush_t *brush, int planenum,
+ bspbrush_t **front, bspbrush_t **back)
+{
+ bspbrush_t *b[2];
+ int i, j;
+ winding_t *w, *cw[2], *midwinding;
+ plane_t *plane, *plane2;
+ side_t *s, *cs;
+ float d, d_front, d_back;
+
+ *front = *back = NULL;
+ plane = &mapplanes[planenum];
+
+ // check all points
+ d_front = d_back = 0;
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ w = brush->sides[i].winding;
+ if (!w)
+ continue;
+ for (j=0 ; j<w->numpoints ; j++)
+ {
+ d = DotProduct (w->p[j], plane->normal) - plane->dist;
+ if (d > 0 && d > d_front)
+ d_front = d;
+ if (d < 0 && d < d_back)
+ d_back = d;
+ }
+ }
+
+ if (d_front < 0.2) // PLANESIDE_EPSILON)
+ { // only on back
+ *back = CopyBrush (brush);
+ return;
+ }
+ if (d_back > -0.2) // PLANESIDE_EPSILON)
+ { // only on front
+ *front = CopyBrush (brush);
+ return;
+ }
+
+ // create a new winding from the split plane
+
+ w = BaseWindingForPlane (plane->normal, plane->dist);
+ for (i=0 ; i<brush->numsides && w ; i++)
+ {
+ plane2 = &mapplanes[brush->sides[i].planenum ^ 1];
+ ChopWindingInPlace (&w, plane2->normal, plane2->dist, 0); // PLANESIDE_EPSILON);
+ }
+
+ if (!w || WindingIsTiny(w))
+ { // the brush isn't really split
+ int side;
+
+ side = BrushMostlyOnSide (brush, plane);
+ if (side == PSIDE_FRONT)
+ *front = CopyBrush (brush);
+ if (side == PSIDE_BACK)
+ *back = CopyBrush (brush);
+ //free a possible winding
+ if (w) FreeWinding(w);
+ return;
+ }
+
+ if (WindingIsHuge (w))
+ {
+ Log_Write("WARNING: huge winding\n");
+ }
+
+ midwinding = w;
+
+ // split it for real
+
+ for (i=0 ; i<2 ; i++)
+ {
+ b[i] = AllocBrush (brush->numsides+1);
+ b[i]->original = brush->original;
+ }
+
+ // split all the current windings
+
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ s = &brush->sides[i];
+ w = s->winding;
+ if (!w)
+ continue;
+ ClipWindingEpsilon (w, plane->normal, plane->dist,
+ 0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]);
+ for (j=0 ; j<2 ; j++)
+ {
+ if (!cw[j])
+ continue;
+#if 0
+ if (WindingIsTiny (cw[j]))
+ {
+ FreeWinding (cw[j]);
+ continue;
+ }
+#endif
+ cs = &b[j]->sides[b[j]->numsides];
+ b[j]->numsides++;
+ *cs = *s;
+// cs->planenum = s->planenum;
+// cs->texinfo = s->texinfo;
+// cs->original = s->original;
+ cs->winding = cw[j];
+ cs->flags &= ~SFL_TESTED;
+ }
+ }
+
+
+ // see if we have valid polygons on both sides
+
+ for (i=0 ; i<2 ; i++)
+ {
+ BoundBrush (b[i]);
+ for (j=0 ; j<3 ; j++)
+ {
+ if (b[i]->mins[j] < -MAX_MAP_BOUNDS || b[i]->maxs[j] > MAX_MAP_BOUNDS)
+ {
+ Log_Write("bogus brush after clip");
+ break;
+ }
+ }
+
+ if (b[i]->numsides < 3 || j < 3)
+ {
+ FreeBrush (b[i]);
+ b[i] = NULL;
+ }
+ }
+
+ if ( !(b[0] && b[1]) )
+ {
+ if (!b[0] && !b[1])
+ Log_Write("split removed brush\r\n");
+ else
+ Log_Write("split not on both sides\r\n");
+ if (b[0])
+ {
+ FreeBrush (b[0]);
+ *front = CopyBrush (brush);
+ }
+ if (b[1])
+ {
+ FreeBrush (b[1]);
+ *back = CopyBrush (brush);
+ }
+ return;
+ }
+
+ // add the midwinding to both sides
+ for (i=0 ; i<2 ; i++)
+ {
+ cs = &b[i]->sides[b[i]->numsides];
+ b[i]->numsides++;
+
+ cs->planenum = planenum^i^1;
+ cs->texinfo = TEXINFO_NODE; //never use these sides as splitters
+ cs->flags &= ~SFL_VISIBLE;
+ cs->flags &= ~SFL_TESTED;
+ if (i==0)
+ cs->winding = CopyWinding (midwinding);
+ else
+ cs->winding = midwinding;
+ }
+
+{
+ vec_t v1;
+ int i;
+
+ for (i = 0; i < 2; i++)
+ {
+ v1 = BrushVolume (b[i]);
+ if (v1 < 1.0)
+ {
+ FreeBrush(b[i]);
+ b[i] = NULL;
+ //Log_Write("tiny volume after clip");
+ }
+ }
+ if (!b[0] && !b[1])
+ {
+ Log_Write("two tiny brushes\r\n");
+ } //end if
+}
+
+ *front = b[0];
+ *back = b[1];
+} //end of the function SplitBrush
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void SplitBrushList (bspbrush_t *brushes,
+ node_t *node, bspbrush_t **front, bspbrush_t **back)
+{
+ bspbrush_t *brush, *newbrush, *newbrush2;
+ side_t *side;
+ int sides;
+ int i;
+
+ *front = *back = NULL;
+
+ for (brush = brushes; brush; brush = brush->next)
+ {
+ sides = brush->side;
+
+ if (sides == PSIDE_BOTH)
+ { // split into two brushes
+ SplitBrush (brush, node->planenum, &newbrush, &newbrush2);
+ if (newbrush)
+ {
+ newbrush->next = *front;
+ *front = newbrush;
+ } //end if
+ if (newbrush2)
+ {
+ newbrush2->next = *back;
+ *back = newbrush2;
+ } //end if
+ continue;
+ } //end if
+
+ newbrush = CopyBrush (brush);
+
+ // if the planenum is actualy a part of the brush
+ // find the plane and flag it as used so it won't be tried
+ // as a splitter again
+ if (sides & PSIDE_FACING)
+ {
+ for (i=0 ; i<newbrush->numsides ; i++)
+ {
+ side = newbrush->sides + i;
+ if ( (side->planenum& ~1) == node->planenum)
+ side->texinfo = TEXINFO_NODE;
+ } //end for
+ } //end if
+ if (sides & PSIDE_FRONT)
+ {
+ newbrush->next = *front;
+ *front = newbrush;
+ continue;
+ } //end if
+ if (sides & PSIDE_BACK)
+ {
+ newbrush->next = *back;
+ *back = newbrush;
+ continue;
+ } //end if
+ } //end for
+} //end of the function SplitBrushList
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void CheckBrushLists(bspbrush_t *brushlist1, bspbrush_t *brushlist2)
+{
+ bspbrush_t *brush1, *brush2;
+
+ for (brush1 = brushlist1; brush1; brush1 = brush1->next)
+ {
+ for (brush2 = brushlist2; brush2; brush2 = brush2->next)
+ {
+ assert(brush1 != brush2);
+ } //end for
+ } //end for
+} //end of the function CheckBrushLists
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int numrecurse = 0;
+
+node_t *BuildTree_r (node_t *node, bspbrush_t *brushes)
+{
+ node_t *newnode;
+ side_t *bestside;
+ int i, totalmem;
+ bspbrush_t *children[2];
+
+ qprintf("\r%6d", numrecurse);
+ numrecurse++;
+
+ if (numthreads == 1)
+ {
+ totalmem = WindingMemory() + c_nodememory + c_brushmemory;
+ if (totalmem > c_peak_totalbspmemory)
+ c_peak_totalbspmemory = totalmem;
+ c_nodes++;
+ } //endif
+
+ if (drawflag)
+ DrawBrushList(brushes, node);
+
+ // find the best plane to use as a splitter
+ bestside = SelectSplitSide (brushes, node);
+ if (!bestside)
+ {
+ // leaf node
+ node->side = NULL;
+ node->planenum = -1;
+ LeafNode(node, brushes);
+ if (node->contents & CONTENTS_SOLID) c_solidleafnodes++;
+ if (create_aas)
+ {
+ //free up memory!!!
+ FreeBrushList(node->brushlist);
+ node->brushlist = NULL;
+ //free the node volume brush
+ if (node->volume)
+ {
+ FreeBrush(node->volume);
+ node->volume = NULL;
+ } //end if
+ } //end if
+ return node;
+ } //end if
+
+ // this is a splitplane node
+ node->side = bestside;
+ node->planenum = bestside->planenum & ~1; // always use front facing
+
+ //split the brush list in two for both children
+ SplitBrushList (brushes, node, &children[0], &children[1]);
+ //free the old brush list
+ FreeBrushList (brushes);
+
+ // allocate children before recursing
+ for (i = 0; i < 2; i++)
+ {
+ newnode = AllocNode ();
+ newnode->parent = node;
+ node->children[i] = newnode;
+ } //end for
+
+ //split the volume brush of the node for the children
+ SplitBrush (node->volume, node->planenum, &node->children[0]->volume,
+ &node->children[1]->volume);
+
+ if (create_aas)
+ {
+ //free the volume brush
+ if (node->volume)
+ {
+ FreeBrush(node->volume);
+ node->volume = NULL;
+ } //end if
+ } //end if
+ // recursively process children
+ for (i = 0; i < 2; i++)
+ {
+ node->children[i] = BuildTree_r(node->children[i], children[i]);
+ } //end for
+
+ return node;
+} //end of the function BuildTree_r
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+node_t *firstnode; //first node in the list
+node_t *lastnode; //last node in the list
+int nodelistsize; //number of nodes in the list
+int use_nodequeue = 0; //use nodequeue, otherwise a node stack is used
+int numwaiting = 0;
+
+void (*AddNodeToList)(node_t *node);
+
+//add the node to the front of the node list
+//(effectively using a node stack)
+void AddNodeToStack(node_t *node)
+{
+ ThreadLock();
+
+ node->next = firstnode;
+ firstnode = node;
+ if (!lastnode) lastnode = node;
+ nodelistsize++;
+
+ ThreadUnlock();
+ //
+ ThreadSemaphoreIncrease(1);
+} //end of the function AddNodeToStack
+//add the node to the end of the node list
+//(effectively using a node queue)
+void AddNodeToQueue(node_t *node)
+{
+ ThreadLock();
+
+ node->next = NULL;
+ if (lastnode) lastnode->next = node;
+ else firstnode = node;
+ lastnode = node;
+ nodelistsize++;
+
+ ThreadUnlock();
+ //
+ ThreadSemaphoreIncrease(1);
+} //end of the function AddNodeToQueue
+//get the first node from the front of the node list
+node_t *NextNodeFromList(void)
+{
+ node_t *node;
+
+ ThreadLock();
+ numwaiting++;
+ if (!firstnode)
+ {
+ if (numwaiting >= GetNumThreads()) ThreadSemaphoreIncrease(GetNumThreads());
+ } //end if
+ ThreadUnlock();
+
+ ThreadSemaphoreWait();
+
+ ThreadLock();
+
+ numwaiting--;
+
+ node = firstnode;
+ if (firstnode)
+ {
+ firstnode = firstnode->next;
+ nodelistsize--;
+ } //end if
+ if (!firstnode) lastnode = NULL;
+
+ ThreadUnlock();
+
+ return node;
+} //end of the function NextNodeFromList
+//returns the size of the node list
+int NodeListSize(void)
+{
+ int size;
+
+ ThreadLock();
+ size = nodelistsize;
+ ThreadUnlock();
+
+ return size;
+} //end of the function NodeListSize
+//
+void IncreaseNodeCounter(void)
+{
+ ThreadLock();
+ //if (verbose) printf("\r%6d", numrecurse++);
+ qprintf("\r%6d", numrecurse++);
+ //qprintf("\r%6d %d, %5d ", numrecurse++, GetNumThreads(), nodelistsize);
+ ThreadUnlock();
+} //end of the function IncreaseNodeCounter
+//thread function, gets nodes from the nodelist and processes them
+void BuildTreeThread(int threadid)
+{
+ node_t *newnode, *node;
+ side_t *bestside;
+ int i, totalmem;
+ bspbrush_t *brushes;
+
+ for (node = NextNodeFromList(); node; )
+ {
+ //if the nodelist isn't empty try to add another thread
+ //if (NodeListSize() > 10) AddThread(BuildTreeThread);
+ //display the number of nodes processed so far
+ if (numthreads == 1)
+ IncreaseNodeCounter();
+
+ brushes = node->brushlist;
+
+ if (numthreads == 1)
+ {
+ totalmem = WindingMemory() + c_nodememory + c_brushmemory;
+ if (totalmem > c_peak_totalbspmemory)
+ {
+ c_peak_totalbspmemory = totalmem;
+ } //end if
+ c_nodes++;
+ } //endif
+
+ if (drawflag)
+ {
+ DrawBrushList(brushes, node);
+ } //end if
+
+ if (cancelconversion)
+ {
+ bestside = NULL;
+ } //end if
+ else
+ {
+ // find the best plane to use as a splitter
+ bestside = SelectSplitSide(brushes, node);
+ } //end else
+ //if there's no split side left
+ if (!bestside)
+ {
+ //create a leaf out of the node
+ LeafNode(node, brushes);
+ if (node->contents & CONTENTS_SOLID) c_solidleafnodes++;
+ if (create_aas)
+ {
+ //free up memory!!!
+ FreeBrushList(node->brushlist);
+ node->brushlist = NULL;
+ } //end if
+ //free the node volume brush (it is not used anymore)
+ if (node->volume)
+ {
+ FreeBrush(node->volume);
+ node->volume = NULL;
+ } //end if
+ node = NextNodeFromList();
+ continue;
+ } //end if
+
+ // this is a splitplane node
+ node->side = bestside;
+ node->planenum = bestside->planenum & ~1; //always use front facing
+
+ //allocate children
+ for (i = 0; i < 2; i++)
+ {
+ newnode = AllocNode();
+ newnode->parent = node;
+ node->children[i] = newnode;
+ } //end for
+
+ //split the brush list in two for both children
+ SplitBrushList(brushes, node, &node->children[0]->brushlist, &node->children[1]->brushlist);
+
+ CheckBrushLists(node->children[0]->brushlist, node->children[1]->brushlist);
+ //free the old brush list
+ FreeBrushList(brushes);
+ node->brushlist = NULL;
+
+ //split the volume brush of the node for the children
+ SplitBrush(node->volume, node->planenum, &node->children[0]->volume,
+ &node->children[1]->volume);
+
+ if (!node->children[0]->volume || !node->children[1]->volume)
+ {
+ Error("child without volume brush");
+ } //end if
+
+ //free the volume brush
+ if (node->volume)
+ {
+ FreeBrush(node->volume);
+ node->volume = NULL;
+ } //end if
+ //add both children to the node list
+ //AddNodeToList(node->children[0]);
+ AddNodeToList(node->children[1]);
+ node = node->children[0];
+ } //end while
+ RemoveThread(threadid);
+} //end of the function BuildTreeThread
+//===========================================================================
+// build the bsp tree using a node list
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void BuildTree(tree_t *tree)
+{
+ int i;
+
+ firstnode = NULL;
+ lastnode = NULL;
+ //use a node queue or node stack
+ if (use_nodequeue) AddNodeToList = AddNodeToQueue;
+ else AddNodeToList = AddNodeToStack;
+ //setup thread locking
+ ThreadSetupLock();
+ ThreadSetupSemaphore();
+ numwaiting = 0;
+ //
+ Log_Print("%6d threads max\n", numthreads);
+ if (use_nodequeue) Log_Print("breadth first bsp building\n");
+ else Log_Print("depth first bsp building\n");
+ qprintf("%6d splits", 0);
+ //add the first node to the list
+ AddNodeToList(tree->headnode);
+ //start the threads
+ for (i = 0; i < numthreads; i++)
+ AddThread(BuildTreeThread);
+ //wait for all added threads to be finished
+ WaitForAllThreadsFinished();
+ //shutdown the thread locking
+ ThreadShutdownLock();
+ ThreadShutdownSemaphore();
+} //end of the function BuildTree
+//===========================================================================
+// The incoming brush list will be freed before exiting
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+tree_t *BrushBSP(bspbrush_t *brushlist, vec3_t mins, vec3_t maxs)
+{
+ int i, c_faces, c_nonvisfaces, c_brushes;
+ bspbrush_t *b;
+ node_t *node;
+ tree_t *tree;
+ vec_t volume;
+// vec3_t point;
+
+ Log_Print("-------- Brush BSP ---------\n");
+
+ tree = Tree_Alloc();
+
+ c_faces = 0;
+ c_nonvisfaces = 0;
+ c_brushes = 0;
+ c_totalsides = 0;
+ for (b = brushlist; b; b = b->next)
+ {
+ c_brushes++;
+
+ volume = BrushVolume(b);
+ if (volume < microvolume)
+ {
+ Log_Print("WARNING: entity %i, brush %i: microbrush\n",
+ b->original->entitynum, b->original->brushnum);
+ } //end if
+
+ for (i=0 ; i<b->numsides ; i++)
+ {
+ if (b->sides[i].flags & SFL_BEVEL)
+ continue;
+ if (!b->sides[i].winding)
+ continue;
+ if (b->sides[i].texinfo == TEXINFO_NODE)
+ continue;
+ if (b->sides[i].flags & SFL_VISIBLE)
+ {
+ c_faces++;
+ } //end if
+ else
+ {
+ c_nonvisfaces++;
+ //if (create_aas) b->sides[i].texinfo = TEXINFO_NODE;
+ } //end if
+ } //end for
+ c_totalsides += b->numsides;
+
+ AddPointToBounds (b->mins, tree->mins, tree->maxs);
+ AddPointToBounds (b->maxs, tree->mins, tree->maxs);
+ } //end for
+
+ Log_Print("%6i brushes\n", c_brushes);
+ Log_Print("%6i visible faces\n", c_faces);
+ Log_Print("%6i nonvisible faces\n", c_nonvisfaces);
+ Log_Print("%6i total sides\n", c_totalsides);
+
+ c_active_brushes = c_brushes;
+ c_nodememory = 0;
+ c_brushmemory = 0;
+ c_peak_brushmemory = 0;
+
+ c_nodes = 0;
+ c_nonvis = 0;
+ node = AllocNode ();
+
+ //volume of first node (head node)
+ node->volume = BrushFromBounds (mins, maxs);
+ //
+ tree->headnode = node;
+ //just get some statistics and the mins/maxs of the node
+ numrecurse = 0;
+// qprintf("%6d splits", numrecurse);
+
+ tree->headnode->brushlist = brushlist;
+ BuildTree(tree);
+
+ //build the bsp tree with the start node from the brushlist
+// node = BuildTree_r(node, brushlist);
+
+ //if the conversion is cancelled
+ if (cancelconversion) return tree;
+
+ qprintf("\n");
+ Log_Write("%6d splits\r\n", numrecurse);
+// Log_Print("%6i visible nodes\n", c_nodes/2 - c_nonvis);
+// Log_Print("%6i nonvis nodes\n", c_nonvis);
+// Log_Print("%6i leaves\n", (c_nodes+1)/2);
+// Log_Print("%6i solid leaf nodes\n", c_solidleafnodes);
+// Log_Print("%6i active brushes\n", c_active_brushes);
+ if (numthreads == 1)
+ {
+// Log_Print("%6i KB of node memory\n", c_nodememory >> 10);
+// Log_Print("%6i KB of brush memory\n", c_brushmemory >> 10);
+// Log_Print("%6i KB of peak brush memory\n", c_peak_brushmemory >> 10);
+// Log_Print("%6i KB of winding memory\n", WindingMemory() >> 10);
+// Log_Print("%6i KB of peak winding memory\n", WindingPeakMemory() >> 10);
+ Log_Print("%6i KB of peak total bsp memory\n", c_peak_totalbspmemory >> 10);
+ } //end if
+
+ /*
+ point[0] = 1485;
+ point[1] = 956.125;
+ point[2] = 352.125;
+ node = PointInLeaf(tree->headnode, point);
+ if (node->planenum != PLANENUM_LEAF)
+ {
+ Log_Print("node not a leaf\n");
+ } //end if
+ Log_Print("at %f %f %f:\n", point[0], point[1], point[2]);
+ PrintContents(node->contents);
+ Log_Print("node->expansionbboxes = %d\n", node->expansionbboxes);
+ //*/
+ return tree;
+} //end of the function BrushBSP
+
diff --git a/code/bspc/bspc.c b/code/bspc/bspc.c
index 4f58b53..e19076e 100755
--- a/code/bspc/bspc.c
+++ b/code/bspc/bspc.c
@@ -1,991 +1,991 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-
-#if defined(WIN32) || defined(_WIN32)
-#include <direct.h>
-#include <windows.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#else
-#include <unistd.h>
-#include <glob.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#endif
-#include "qbsp.h"
-#include "l_mem.h"
-#include "../botlib/aasfile.h"
-#include "../botlib/be_aas_cluster.h"
-#include "../botlib/be_aas_optimize.h"
-#include "aas_create.h"
-#include "aas_store.h"
-#include "aas_file.h"
-#include "aas_cfg.h"
-#include "be_aas_bspc.h"
-
-extern int use_nodequeue; //brushbsp.c
-extern int calcgrapplereach; //be_aas_reach.c
-
-float subdivide_size = 240;
-char source[1024];
-char name[1024];
-vec_t microvolume = 1.0;
-char outbase[32];
-int entity_num;
-aas_settings_t aassettings;
-
-qboolean noprune; //don't prune nodes (bspc.c)
-qboolean glview; //create a gl view
-qboolean nodetail; //don't use detail brushes (map.c)
-qboolean fulldetail; //use but don't mark detail brushes (map.c)
-qboolean onlyents; //only process the entities (bspc.c)
-qboolean nomerge; //don't merge bsp node faces (faces.c)
-qboolean nowater; //don't use the water brushes (map.c)
-qboolean nocsg; //don't carve intersecting brushes (bspc.c)
-qboolean noweld; //use unique face vertexes (faces.c)
-qboolean noshare; //don't share bsp edges (faces.c)
-qboolean nosubdiv; //don't subdivide bsp node faces (faces.c)
-qboolean notjunc; //don't create tjunctions (edge melting) (faces.c)
-qboolean optimize; //enable optimisation
-qboolean leaktest; //perform a leak test
-qboolean verboseentities;
-qboolean freetree; //free the bsp tree when not needed anymore
-qboolean create_aas; //create an .AAS file
-qboolean nobrushmerge; //don't merge brushes
-qboolean lessbrushes; //create less brushes instead of correct texture placement
-qboolean cancelconversion; //true if the conversion is being cancelled
-qboolean noliquids; //no liquids when writing map file
-qboolean forcesidesvisible; //force all brush sides to be visible when loaded from bsp
-qboolean capsule_collision = 0;
-
-/*
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ProcessWorldModel (void)
-{
- entity_t *e;
- tree_t *tree;
- qboolean leaked;
- int brush_start, brush_end;
-
- e = &entities[entity_num];
-
- brush_start = e->firstbrush;
- brush_end = brush_start + e->numbrushes;
- leaked = false;
-
- //process the whole world in one time
- tree = ProcessWorldBrushes(brush_start, brush_end);
- //create the bsp tree portals
- MakeTreePortals(tree);
- //mark all leafs that can be reached by entities
- if (FloodEntities(tree))
- {
- FillOutside(tree->headnode);
- } //end if
- else
- {
- Log_Print("**** leaked ****\n");
- leaked = true;
- LeakFile(tree);
- if (leaktest)
- {
- Log_Print("--- MAP LEAKED ---\n");
- exit(0);
- } //end if
- } //end else
-
- MarkVisibleSides (tree, brush_start, brush_end);
-
- FloodAreas (tree);
-
-#ifndef ME
- if (glview) WriteGLView(tree, source);
-#endif
- MakeFaces(tree->headnode);
- FixTjuncs(tree->headnode);
-
- //NOTE: Never prune the nodes because the portals
- // are screwed when prunning is done and as
- // a result portal writing will crash
- //if (!noprune) PruneNodes(tree->headnode);
-
- WriteBSP(tree->headnode);
-
- if (!leaked) WritePortalFile(tree);
-
- Tree_Free(tree);
-} //end of the function ProcessWorldModel
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ProcessSubModel (void)
-{
- entity_t *e;
- int start, end;
- tree_t *tree;
- bspbrush_t *list;
- vec3_t mins, maxs;
-
- e = &entities[entity_num];
-
- start = e->firstbrush;
- end = start + e->numbrushes;
-
- mins[0] = mins[1] = mins[2] = -4096;
- maxs[0] = maxs[1] = maxs[2] = 4096;
- list = MakeBspBrushList(start, end, mins, maxs);
- if (!nocsg) list = ChopBrushes (list);
- tree = BrushBSP (list, mins, maxs);
- MakeTreePortals (tree);
- MarkVisibleSides (tree, start, end);
- MakeFaces (tree->headnode);
- FixTjuncs (tree->headnode);
- WriteBSP (tree->headnode);
- Tree_Free(tree);
-} //end of the function ProcessSubModel
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ProcessModels (void)
-{
- BeginBSPFile();
-
- for (entity_num = 0; entity_num < num_entities; entity_num++)
- {
- if (!entities[entity_num].numbrushes)
- continue;
-
- Log_Print("############### model %i ###############\n", nummodels);
- BeginModel();
- if (entity_num == 0) ProcessWorldModel();
- else ProcessSubModel();
- EndModel();
-
- if (!verboseentities)
- verbose = false; // don't bother printing submodels
- } //end for
- EndBSPFile();
-} //end of the function ProcessModels
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Win_Map2Bsp(char *bspfilename)
-{
- double start, end;
- char path[1024];
-
- start = I_FloatTime();
-
- ThreadSetDefault();
- //yeah sure Carmack
- //numthreads = 1; // multiple threads aren't helping...
-
- strcpy(source, ExpandArg(bspfilename));
- StripExtension(source);
-
- //delete portal and line files
- sprintf(path, "%s.prt", source);
- remove(path);
- sprintf(path, "%s.lin", source);
- remove(path);
-
- strcpy(name, ExpandArg(bspfilename));
- DefaultExtension(name, ".map"); // might be .reg
-
- Q2_AllocMaxBSP();
- //
- SetModelNumbers();
- SetLightStyles();
- ProcessModels();
- //write the BSP
- Q2_WriteBSPFile(bspfilename);
-
- Q2_FreeMaxBSP();
-
- end = I_FloatTime();
- Log_Print("%5.0f seconds elapsed\n", end-start);
-} //end of the function Win_Map2Bsp
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Map2Bsp(char *mapfilename, char *outputfilename)
-{
- double start, end;
- char path[1024];
-
- start = I_FloatTime ();
-
- ThreadSetDefault ();
- //yeah sure Carmack
- //numthreads = 1; //multiple threads aren't helping...
- //SetQdirFromPath(bspfilename);
-
- strcpy(source, ExpandArg(mapfilename));
- StripExtension(source);
-
- // delete portal and line files
- sprintf(path, "%s.prt", source);
- remove(path);
- sprintf(path, "%s.lin", source);
- remove(path);
-
- strcpy(name, ExpandArg(mapfilename));
- DefaultExtension(name, ".map"); // might be .reg
-
- //
- // if onlyents, just grab the entites and resave
- //
- if (onlyents)
- {
- char out[1024];
-
- Q2_AllocMaxBSP();
- sprintf (out, "%s.bsp", source);
- Q2_LoadBSPFile(out, 0, 0);
- num_entities = 0;
-
- Q2_LoadMapFile(name);
- SetModelNumbers();
- SetLightStyles();
-
- Q2_UnparseEntities();
-
- Q2_WriteBSPFile(out);
- //
- Q2_FreeMaxBSP();
- } //end if
- else
- {
- //
- // start from scratch
- //
- Q2_AllocMaxBSP();
- //load the map
- Q2_LoadMapFile(name);
- //create the .bsp file
- SetModelNumbers();
- SetLightStyles();
- ProcessModels();
- //write the BSP
- Q2_WriteBSPFile(outputfilename);
- //
- Q2_FreeMaxBSP();
- } //end else
-
- end = I_FloatTime();
- Log_Print("%5.0f seconds elapsed\n", end-start);
-} //end of the function Map2Bsp
-*/
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AASOuputFile(quakefile_t *qf, char *outputpath, char *filename)
-{
- char ext[MAX_PATH];
-
- //
- if (strlen(outputpath))
- {
- strcpy(filename, outputpath);
- //append the bsp file base
- AppendPathSeperator(filename, MAX_PATH);
- ExtractFileBase(qf->origname, &filename[strlen(filename)]);
- //append .aas
- strcat(filename, ".aas");
- return;
- } //end if
- //
- ExtractFileExtension(qf->filename, ext);
- if (!stricmp(ext, "pk3") || !stricmp(ext, "pak") || !stricmp(ext, "sin"))
- {
- strcpy(filename, qf->filename);
- while(strlen(filename) &&
- filename[strlen(filename)-1] != '\\' &&
- filename[strlen(filename)-1] != '/')
- {
- filename[strlen(filename)-1] = '\0';
- } //end while
- strcat(filename, "maps");
- if (access(filename, 0x04)) CreatePath(filename);
- //append the bsp file base
- AppendPathSeperator(filename, MAX_PATH);
- ExtractFileBase(qf->origname, &filename[strlen(filename)]);
- //append .aas
- strcat(filename, ".aas");
- } //end if
- else
- {
- strcpy(filename, qf->filename);
- while(strlen(filename) &&
- filename[strlen(filename)-1] != '.')
- {
- filename[strlen(filename)-1] = '\0';
- } //end while
- strcat(filename, "aas");
- } //end else
-} //end of the function AASOutputFile
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void CreateAASFilesForAllBSPFiles(char *quakepath)
-{
-#if defined(WIN32)|defined(_WIN32)
- WIN32_FIND_DATA filedata;
- HWND handle;
- struct _stat statbuf;
-#else
- glob_t globbuf;
- struct stat statbuf;
- int j;
-#endif
- int done;
- char filter[_MAX_PATH], bspfilter[_MAX_PATH], aasfilter[_MAX_PATH];
- char aasfile[_MAX_PATH], buf[_MAX_PATH], foldername[_MAX_PATH];
- quakefile_t *qf, *qf2, *files, *bspfiles, *aasfiles;
-
- strcpy(filter, quakepath);
- AppendPathSeperator(filter, sizeof(filter));
- strcat(filter, "*");
-
-#if defined(WIN32)|defined(_WIN32)
- handle = FindFirstFile(filter, &filedata);
- done = (handle == INVALID_HANDLE_VALUE);
- while(!done)
- {
- _splitpath(filter, foldername, NULL, NULL, NULL);
- _splitpath(filter, NULL, &foldername[strlen(foldername)], NULL, NULL);
- AppendPathSeperator(foldername, _MAX_PATH);
- strcat(foldername, filedata.cFileName);
- _stat(foldername, &statbuf);
-#else
- glob(filter, 0, NULL, &globbuf);
- for (j = 0; j < globbuf.gl_pathc; j++)
- {
- strcpy(foldername, globbuf.gl_pathv[j]);
- stat(foldername, &statbuf);
-#endif
- //if it is a folder
- if (statbuf.st_mode & S_IFDIR)
- {
- //
- AppendPathSeperator(foldername, sizeof(foldername));
- //get all the bsp files
- strcpy(bspfilter, foldername);
- strcat(bspfilter, "maps/*.bsp");
- files = FindQuakeFiles(bspfilter);
- strcpy(bspfilter, foldername);
- strcat(bspfilter, "*.pk3/maps/*.bsp");
- bspfiles = FindQuakeFiles(bspfilter);
- for (qf = bspfiles; qf; qf = qf->next) if (!qf->next) break;
- if (qf) qf->next = files;
- else bspfiles = files;
- //get all the aas files
- strcpy(aasfilter, foldername);
- strcat(aasfilter, "maps/*.aas");
- files = FindQuakeFiles(aasfilter);
- strcpy(aasfilter, foldername);
- strcat(aasfilter, "*.pk3/maps/*.aas");
- aasfiles = FindQuakeFiles(aasfilter);
- for (qf = aasfiles; qf; qf = qf->next) if (!qf->next) break;
- if (qf) qf->next = files;
- else aasfiles = files;
- //
- for (qf = bspfiles; qf; qf = qf->next)
- {
- sprintf(aasfile, "%s/%s", qf->pakfile, qf->origname);
- Log_Print("found %s\n", aasfile);
- strcpy(&aasfile[strlen(aasfile)-strlen(".bsp")], ".aas");
- for (qf2 = aasfiles; qf2; qf2 = qf2->next)
- {
- sprintf(buf, "%s/%s", qf2->pakfile, qf2->origname);
- if (!stricmp(aasfile, buf))
- {
- Log_Print("found %s\n", buf);
- break;
- } //end if
- } //end for
- } //end for
- } //end if
-#if defined(WIN32)|defined(_WIN32)
- //find the next file
- done = !FindNextFile(handle, &filedata);
- } //end while
-#else
- } //end for
- globfree(&globbuf);
-#endif
-} //end of the function CreateAASFilesForAllBSPFiles
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-quakefile_t *GetArgumentFiles(int argc, char *argv[], int *i, char *ext)
-{
- quakefile_t *qfiles, *lastqf, *qf;
- int j;
- char buf[1024];
-
- qfiles = NULL;
- lastqf = NULL;
- for (; (*i)+1 < argc && argv[(*i)+1][0] != '-'; (*i)++)
- {
- strcpy(buf, argv[(*i)+1]);
- for (j = strlen(buf)-1; j >= strlen(buf)-4; j--)
- if (buf[j] == '.') break;
- if (j >= strlen(buf)-4)
- strcpy(&buf[j+1], ext);
- qf = FindQuakeFiles(buf);
- if (!qf) continue;
- if (lastqf) lastqf->next = qf;
- else qfiles = qf;
- lastqf = qf;
- while(lastqf->next) lastqf = lastqf->next;
- } //end for
- return qfiles;
-} //end of the function GetArgumentFiles
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-
-#define COMP_BSP2MAP 1
-#define COMP_BSP2AAS 2
-#define COMP_REACH 3
-#define COMP_CLUSTER 4
-#define COMP_AASOPTIMIZE 5
-#define COMP_AASINFO 6
-
-int main (int argc, char **argv)
-{
- int i, comp = 0;
- char outputpath[MAX_PATH] = "";
- char filename[MAX_PATH] = "unknown";
- quakefile_t *qfiles, *qf;
- double start_time;
-
- myargc = argc;
- myargv = argv;
-
- start_time = I_FloatTime();
-
- Log_Open("bspc.log"); //open a log file
- Log_Print("BSPC version "BSPC_VERSION", %s %s\n", __DATE__, __TIME__);
-
- DefaultCfg();
- for (i = 1; i < argc; i++)
- {
- if (!stricmp(argv[i],"-threads"))
- {
- if (i + 1 >= argc) {i = 0; break;}
- numthreads = atoi(argv[++i]);
- Log_Print("threads = %d\n", numthreads);
- } //end if
- else if (!stricmp(argv[i], "-noverbose"))
- {
- Log_Print("verbose = false\n");
- verbose = false;
- } //end else if
- else if (!stricmp(argv[i], "-nocsg"))
- {
- Log_Print("nocsg = true\n");
- nocsg = true;
- } //end else if
- else if (!stricmp(argv[i], "-optimize"))
- {
- Log_Print("optimize = true\n");
- optimize = true;
- } //end else if
- /*
- else if (!stricmp(argv[i],"-glview"))
- {
- glview = true;
- } //end else if
- else if (!stricmp(argv[i], "-draw"))
- {
- Log_Print("drawflag = true\n");
- drawflag = true;
- } //end else if
- else if (!stricmp(argv[i], "-noweld"))
- {
- Log_Print("noweld = true\n");
- noweld = true;
- } //end else if
- else if (!stricmp(argv[i], "-noshare"))
- {
- Log_Print("noshare = true\n");
- noshare = true;
- } //end else if
- else if (!stricmp(argv[i], "-notjunc"))
- {
- Log_Print("notjunc = true\n");
- notjunc = true;
- } //end else if
- else if (!stricmp(argv[i], "-nowater"))
- {
- Log_Print("nowater = true\n");
- nowater = true;
- } //end else if
- else if (!stricmp(argv[i], "-noprune"))
- {
- Log_Print("noprune = true\n");
- noprune = true;
- } //end else if
- else if (!stricmp(argv[i], "-nomerge"))
- {
- Log_Print("nomerge = true\n");
- nomerge = true;
- } //end else if
- else if (!stricmp(argv[i], "-nosubdiv"))
- {
- Log_Print("nosubdiv = true\n");
- nosubdiv = true;
- } //end else if
- else if (!stricmp(argv[i], "-nodetail"))
- {
- Log_Print("nodetail = true\n");
- nodetail = true;
- } //end else if
- else if (!stricmp(argv[i], "-fulldetail"))
- {
- Log_Print("fulldetail = true\n");
- fulldetail = true;
- } //end else if
- else if (!stricmp(argv[i], "-onlyents"))
- {
- Log_Print("onlyents = true\n");
- onlyents = true;
- } //end else if
- else if (!stricmp(argv[i], "-micro"))
- {
- if (i + 1 >= argc) {i = 0; break;}
- microvolume = atof(argv[++i]);
- Log_Print("microvolume = %f\n", microvolume);
- } //end else if
- else if (!stricmp(argv[i], "-leaktest"))
- {
- Log_Print("leaktest = true\n");
- leaktest = true;
- } //end else if
- else if (!stricmp(argv[i], "-verboseentities"))
- {
- Log_Print("verboseentities = true\n");
- verboseentities = true;
- } //end else if
- else if (!stricmp(argv[i], "-chop"))
- {
- if (i + 1 >= argc) {i = 0; break;}
- subdivide_size = atof(argv[++i]);
- Log_Print("subdivide_size = %f\n", subdivide_size);
- } //end else if
- else if (!stricmp (argv[i], "-tmpout"))
- {
- strcpy (outbase, "/tmp");
- Log_Print("temp output\n");
- } //end else if
- */
-#ifdef ME
- else if (!stricmp(argv[i], "-freetree"))
- {
- freetree = true;
- Log_Print("freetree = true\n");
- } //end else if
- else if (!stricmp(argv[i], "-grapplereach"))
- {
- calcgrapplereach = true;
- Log_Print("grapplereach = true\n");
- } //end else if
- else if (!stricmp(argv[i], "-nobrushmerge"))
- {
- nobrushmerge = true;
- Log_Print("nobrushmerge = true\n");
- } //end else if
- else if (!stricmp(argv[i], "-noliquids"))
- {
- noliquids = true;
- Log_Print("noliquids = true\n");
- } //end else if
- else if (!stricmp(argv[i], "-forcesidesvisible"))
- {
- forcesidesvisible = true;
- Log_Print("forcesidesvisible = true\n");
- } //end else if
- else if (!stricmp(argv[i], "-output"))
- {
- if (i + 1 >= argc) {i = 0; break;}
- if (access(argv[i+1], 0x04)) Warning("the folder %s does not exist", argv[i+1]);
- strcpy(outputpath, argv[++i]);
- } //end else if
- else if (!stricmp(argv[i], "-breadthfirst"))
- {
- use_nodequeue = true;
- Log_Print("breadthfirst = true\n");
- } //end else if
- else if (!stricmp(argv[i], "-capsule"))
- {
- capsule_collision = true;
- Log_Print("capsule_collision = true\n");
- } //end else if
- else if (!stricmp(argv[i], "-cfg"))
- {
- if (i + 1 >= argc) {i = 0; break;}
- if (!LoadCfgFile(argv[++i]))
- exit(0);
- } //end else if
- else if (!stricmp(argv[i], "-bsp2map"))
- {
- if (i + 1 >= argc) {i = 0; break;}
- comp = COMP_BSP2MAP;
- qfiles = GetArgumentFiles(argc, argv, &i, "bsp");
- } //end else if
- else if (!stricmp(argv[i], "-bsp2aas"))
- {
- if (i + 1 >= argc) {i = 0; break;}
- comp = COMP_BSP2AAS;
- qfiles = GetArgumentFiles(argc, argv, &i, "bsp");
- } //end else if
- else if (!stricmp(argv[i], "-aasall"))
- {
- if (i + 1 >= argc) {i = 0; break;}
- CreateAASFilesForAllBSPFiles(argv[++i]);
- } //end else if
- else if (!stricmp(argv[i], "-reach"))
- {
- if (i + 1 >= argc) {i = 0; break;}
- comp = COMP_REACH;
- qfiles = GetArgumentFiles(argc, argv, &i, "bsp");
- } //end else if
- else if (!stricmp(argv[i], "-cluster"))
- {
- if (i + 1 >= argc) {i = 0; break;}
- comp = COMP_CLUSTER;
- qfiles = GetArgumentFiles(argc, argv, &i, "bsp");
- } //end else if
- else if (!stricmp(argv[i], "-aasinfo"))
- {
- if (i + 1 >= argc) {i = 0; break;}
- comp = COMP_AASINFO;
- qfiles = GetArgumentFiles(argc, argv, &i, "aas");
- } //end else if
- else if (!stricmp(argv[i], "-aasopt"))
- {
- if (i + 1 >= argc) {i = 0; break;}
- comp = COMP_AASOPTIMIZE;
- qfiles = GetArgumentFiles(argc, argv, &i, "aas");
- } //end else if
-#endif //ME
- else
- {
- Log_Print("unknown parameter %s\n", argv[i]);
- break;
- } //end else
- } //end for
-
- //if there are parameters and there's no mismatch in one of the parameters
- if (argc > 1 && i == argc)
- {
- switch(comp)
- {
- case COMP_BSP2MAP:
- {
- if (!qfiles) Log_Print("no files found\n");
- for (qf = qfiles; qf; qf = qf->next)
- {
- //copy the output path
- strcpy(filename, outputpath);
- //append the bsp file base
- AppendPathSeperator(filename, MAX_PATH);
- ExtractFileBase(qf->origname, &filename[strlen(filename)]);
- //append .map
- strcat(filename, ".map");
- //
- Log_Print("bsp2map: %s to %s\n", qf->origname, filename);
- if (qf->type != QFILETYPE_BSP) Warning("%s is probably not a BSP file\n", qf->origname);
- //
- LoadMapFromBSP(qf);
- //write the map file
- WriteMapFile(filename);
- } //end for
- break;
- } //end case
- case COMP_BSP2AAS:
- {
- if (!qfiles) Log_Print("no files found\n");
- for (qf = qfiles; qf; qf = qf->next)
- {
- AASOuputFile(qf, outputpath, filename);
- //
- Log_Print("bsp2aas: %s to %s\n", qf->origname, filename);
- if (qf->type != QFILETYPE_BSP) Warning("%s is probably not a BSP file\n", qf->origname);
- //set before map loading
- create_aas = 1;
- LoadMapFromBSP(qf);
- //create the AAS file
- AAS_Create(filename);
- //if it's a Quake3 map calculate the reachabilities and clusters
- if (loadedmaptype == MAPTYPE_QUAKE3) AAS_CalcReachAndClusters(qf);
- //
- if (optimize) AAS_Optimize();
- //
- //write out the stored AAS file
- if (!AAS_WriteAASFile(filename))
- {
- Error("error writing %s\n", filename);
- } //end if
- //deallocate memory
- AAS_FreeMaxAAS();
- } //end for
- break;
- } //end case
- case COMP_REACH:
- {
- if (!qfiles) Log_Print("no files found\n");
- for (qf = qfiles; qf; qf = qf->next)
- {
- AASOuputFile(qf, outputpath, filename);
- //
- Log_Print("reach: %s to %s\n", qf->origname, filename);
- if (qf->type != QFILETYPE_BSP) Warning("%s is probably not a BSP file\n", qf->origname);
- //if the AAS file exists in the output directory
- if (!access(filename, 0x04))
- {
- if (!AAS_LoadAASFile(filename, 0, 0))
- {
- Error("error loading aas file %s\n", filename);
- } //end if
- //assume it's a Quake3 BSP file
- loadedmaptype = MAPTYPE_QUAKE3;
- } //end if
- else
- {
- Warning("AAS file %s not found in output folder\n", filename);
- Log_Print("creating %s...\n", filename);
- //set before map loading
- create_aas = 1;
- LoadMapFromBSP(qf);
- //create the AAS file
- AAS_Create(filename);
- } //end else
- //if it's a Quake3 map calculate the reachabilities and clusters
- if (loadedmaptype == MAPTYPE_QUAKE3)
- {
- AAS_CalcReachAndClusters(qf);
- } //end if
- //
- if (optimize) AAS_Optimize();
- //write out the stored AAS file
- if (!AAS_WriteAASFile(filename))
- {
- Error("error writing %s\n", filename);
- } //end if
- //deallocate memory
- AAS_FreeMaxAAS();
- } //end for
- break;
- } //end case
- case COMP_CLUSTER:
- {
- if (!qfiles) Log_Print("no files found\n");
- for (qf = qfiles; qf; qf = qf->next)
- {
- AASOuputFile(qf, outputpath, filename);
- //
- Log_Print("cluster: %s to %s\n", qf->origname, filename);
- if (qf->type != QFILETYPE_BSP) Warning("%s is probably not a BSP file\n", qf->origname);
- //if the AAS file exists in the output directory
- if (!access(filename, 0x04))
- {
- if (!AAS_LoadAASFile(filename, 0, 0))
- {
- Error("error loading aas file %s\n", filename);
- } //end if
- //assume it's a Quake3 BSP file
- loadedmaptype = MAPTYPE_QUAKE3;
- //if it's a Quake3 map calculate the clusters
- if (loadedmaptype == MAPTYPE_QUAKE3)
- {
- aasworld.numclusters = 0;
- AAS_InitBotImport();
- AAS_InitClustering();
- } //end if
- } //end if
- else
- {
- Warning("AAS file %s not found in output folder\n", filename);
- Log_Print("creating %s...\n", filename);
- //set before map loading
- create_aas = 1;
- LoadMapFromBSP(qf);
- //create the AAS file
- AAS_Create(filename);
- //if it's a Quake3 map calculate the reachabilities and clusters
- if (loadedmaptype == MAPTYPE_QUAKE3) AAS_CalcReachAndClusters(qf);
- } //end else
- //
- if (optimize) AAS_Optimize();
- //write out the stored AAS file
- if (!AAS_WriteAASFile(filename))
- {
- Error("error writing %s\n", filename);
- } //end if
- //deallocate memory
- AAS_FreeMaxAAS();
- } //end for
- break;
- } //end case
- case COMP_AASOPTIMIZE:
- {
- if (!qfiles) Log_Print("no files found\n");
- for (qf = qfiles; qf; qf = qf->next)
- {
- AASOuputFile(qf, outputpath, filename);
- //
- Log_Print("optimizing: %s to %s\n", qf->origname, filename);
- if (qf->type != QFILETYPE_AAS) Warning("%s is probably not a AAS file\n", qf->origname);
- //
- AAS_InitBotImport();
- //
- if (!AAS_LoadAASFile(qf->filename, qf->offset, qf->length))
- {
- Error("error loading aas file %s\n", qf->filename);
- } //end if
- AAS_Optimize();
- //write out the stored AAS file
- if (!AAS_WriteAASFile(filename))
- {
- Error("error writing %s\n", filename);
- } //end if
- //deallocate memory
- AAS_FreeMaxAAS();
- } //end for
- break;
- } //end case
- case COMP_AASINFO:
- {
- if (!qfiles) Log_Print("no files found\n");
- for (qf = qfiles; qf; qf = qf->next)
- {
- AASOuputFile(qf, outputpath, filename);
- //
- Log_Print("aas info for: %s\n", filename);
- if (qf->type != QFILETYPE_AAS) Warning("%s is probably not a AAS file\n", qf->origname);
- //
- AAS_InitBotImport();
- //
- if (!AAS_LoadAASFile(qf->filename, qf->offset, qf->length))
- {
- Error("error loading aas file %s\n", qf->filename);
- } //end if
- AAS_ShowTotals();
- } //end for
- } //end case
- default:
- {
- Log_Print("don't know what to do\n");
- break;
- } //end default
- } //end switch
- } //end if
- else
- {
- Log_Print("Usage: bspc [-<switch> [-<switch> ...]]\n"
-#if defined(WIN32) || defined(_WIN32)
- "Example 1: bspc -bsp2aas d:\\quake3\\baseq3\\maps\\mymap?.bsp\n"
- "Example 2: bspc -bsp2aas d:\\quake3\\baseq3\\pak0.pk3\\maps/q3dm*.bsp\n"
-#else
- "Example 1: bspc -bsp2aas /quake3/baseq3/maps/mymap?.bsp\n"
- "Example 2: bspc -bsp2aas /quake3/baseq3/pak0.pk3/maps/q3dm*.bsp\n"
-#endif
- "\n"
- "Switches:\n"
- //" bsp2map <[pakfilter/]filter.bsp> = convert BSP to MAP\n"
- //" aasall <quake3folder> = create AAS files for all BSPs\n"
- " bsp2aas <[pakfilter/]filter.bsp> = convert BSP to AAS\n"
- " reach <filter.bsp> = compute reachability & clusters\n"
- " cluster <filter.aas> = compute clusters\n"
- " aasopt <filter.aas> = optimize aas file\n"
- " aasinfo <filter.aas> = show AAS file info\n"
- " output <output path> = set output path\n"
- " threads <X> = set number of threads to X\n"
- " cfg <filename> = use this cfg file\n"
- " optimize = enable optimization\n"
- " noverbose = disable verbose output\n"
- " breadthfirst = breadth first bsp building\n"
- " nobrushmerge = don't merge brushes\n"
- " noliquids = don't write liquids to map\n"
- " freetree = free the bsp tree\n"
- " nocsg = disables brush chopping\n"
- " forcesidesvisible = force all sides to be visible\n"
- " grapplereach = calculate grapple reachabilities\n"
-
-/* " glview = output a GL view\n"
- " draw = enables drawing\n"
- " noweld = disables weld\n"
- " noshare = disables sharing\n"
- " notjunc = disables juncs\n"
- " nowater = disables water brushes\n"
- " noprune = disables node prunes\n"
- " nomerge = disables face merging\n"
- " nosubdiv = disables subdeviding\n"
- " nodetail = disables detail brushes\n"
- " fulldetail = enables full detail\n"
- " onlyents = only compile entities with bsp\n"
- " micro <volume>\n"
- " = sets the micro volume to the given float\n"
- " leaktest = perform a leak test\n"
- " verboseentities\n"
- " = enable entity verbose mode\n"
- " chop <subdivide_size>\n"
- " = sets the subdivide size to the given float\n"*/
- "\n");
- } //end else
- Log_Print("BSPC run time is %5.0f seconds\n", I_FloatTime() - start_time);
- Log_Close(); //close the log file
- return 0;
-} //end of the function main
-
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+#if defined(WIN32) || defined(_WIN32)
+#include <direct.h>
+#include <windows.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#else
+#include <unistd.h>
+#include <glob.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+#include "qbsp.h"
+#include "l_mem.h"
+#include "../botlib/aasfile.h"
+#include "../botlib/be_aas_cluster.h"
+#include "../botlib/be_aas_optimize.h"
+#include "aas_create.h"
+#include "aas_store.h"
+#include "aas_file.h"
+#include "aas_cfg.h"
+#include "be_aas_bspc.h"
+
+extern int use_nodequeue; //brushbsp.c
+extern int calcgrapplereach; //be_aas_reach.c
+
+float subdivide_size = 240;
+char source[1024];
+char name[1024];
+vec_t microvolume = 1.0;
+char outbase[32];
+int entity_num;
+aas_settings_t aassettings;
+
+qboolean noprune; //don't prune nodes (bspc.c)
+qboolean glview; //create a gl view
+qboolean nodetail; //don't use detail brushes (map.c)
+qboolean fulldetail; //use but don't mark detail brushes (map.c)
+qboolean onlyents; //only process the entities (bspc.c)
+qboolean nomerge; //don't merge bsp node faces (faces.c)
+qboolean nowater; //don't use the water brushes (map.c)
+qboolean nocsg; //don't carve intersecting brushes (bspc.c)
+qboolean noweld; //use unique face vertexes (faces.c)
+qboolean noshare; //don't share bsp edges (faces.c)
+qboolean nosubdiv; //don't subdivide bsp node faces (faces.c)
+qboolean notjunc; //don't create tjunctions (edge melting) (faces.c)
+qboolean optimize; //enable optimisation
+qboolean leaktest; //perform a leak test
+qboolean verboseentities;
+qboolean freetree; //free the bsp tree when not needed anymore
+qboolean create_aas; //create an .AAS file
+qboolean nobrushmerge; //don't merge brushes
+qboolean lessbrushes; //create less brushes instead of correct texture placement
+qboolean cancelconversion; //true if the conversion is being cancelled
+qboolean noliquids; //no liquids when writing map file
+qboolean forcesidesvisible; //force all brush sides to be visible when loaded from bsp
+qboolean capsule_collision = 0;
+
+/*
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ProcessWorldModel (void)
+{
+ entity_t *e;
+ tree_t *tree;
+ qboolean leaked;
+ int brush_start, brush_end;
+
+ e = &entities[entity_num];
+
+ brush_start = e->firstbrush;
+ brush_end = brush_start + e->numbrushes;
+ leaked = false;
+
+ //process the whole world in one time
+ tree = ProcessWorldBrushes(brush_start, brush_end);
+ //create the bsp tree portals
+ MakeTreePortals(tree);
+ //mark all leafs that can be reached by entities
+ if (FloodEntities(tree))
+ {
+ FillOutside(tree->headnode);
+ } //end if
+ else
+ {
+ Log_Print("**** leaked ****\n");
+ leaked = true;
+ LeakFile(tree);
+ if (leaktest)
+ {
+ Log_Print("--- MAP LEAKED ---\n");
+ exit(0);
+ } //end if
+ } //end else
+
+ MarkVisibleSides (tree, brush_start, brush_end);
+
+ FloodAreas (tree);
+
+#ifndef ME
+ if (glview) WriteGLView(tree, source);
+#endif
+ MakeFaces(tree->headnode);
+ FixTjuncs(tree->headnode);
+
+ //NOTE: Never prune the nodes because the portals
+ // are screwed when prunning is done and as
+ // a result portal writing will crash
+ //if (!noprune) PruneNodes(tree->headnode);
+
+ WriteBSP(tree->headnode);
+
+ if (!leaked) WritePortalFile(tree);
+
+ Tree_Free(tree);
+} //end of the function ProcessWorldModel
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ProcessSubModel (void)
+{
+ entity_t *e;
+ int start, end;
+ tree_t *tree;
+ bspbrush_t *list;
+ vec3_t mins, maxs;
+
+ e = &entities[entity_num];
+
+ start = e->firstbrush;
+ end = start + e->numbrushes;
+
+ mins[0] = mins[1] = mins[2] = -4096;
+ maxs[0] = maxs[1] = maxs[2] = 4096;
+ list = MakeBspBrushList(start, end, mins, maxs);
+ if (!nocsg) list = ChopBrushes (list);
+ tree = BrushBSP (list, mins, maxs);
+ MakeTreePortals (tree);
+ MarkVisibleSides (tree, start, end);
+ MakeFaces (tree->headnode);
+ FixTjuncs (tree->headnode);
+ WriteBSP (tree->headnode);
+ Tree_Free(tree);
+} //end of the function ProcessSubModel
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ProcessModels (void)
+{
+ BeginBSPFile();
+
+ for (entity_num = 0; entity_num < num_entities; entity_num++)
+ {
+ if (!entities[entity_num].numbrushes)
+ continue;
+
+ Log_Print("############### model %i ###############\n", nummodels);
+ BeginModel();
+ if (entity_num == 0) ProcessWorldModel();
+ else ProcessSubModel();
+ EndModel();
+
+ if (!verboseentities)
+ verbose = false; // don't bother printing submodels
+ } //end for
+ EndBSPFile();
+} //end of the function ProcessModels
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Win_Map2Bsp(char *bspfilename)
+{
+ double start, end;
+ char path[1024];
+
+ start = I_FloatTime();
+
+ ThreadSetDefault();
+ //yeah sure Carmack
+ //numthreads = 1; // multiple threads aren't helping...
+
+ strcpy(source, ExpandArg(bspfilename));
+ StripExtension(source);
+
+ //delete portal and line files
+ sprintf(path, "%s.prt", source);
+ remove(path);
+ sprintf(path, "%s.lin", source);
+ remove(path);
+
+ strcpy(name, ExpandArg(bspfilename));
+ DefaultExtension(name, ".map"); // might be .reg
+
+ Q2_AllocMaxBSP();
+ //
+ SetModelNumbers();
+ SetLightStyles();
+ ProcessModels();
+ //write the BSP
+ Q2_WriteBSPFile(bspfilename);
+
+ Q2_FreeMaxBSP();
+
+ end = I_FloatTime();
+ Log_Print("%5.0f seconds elapsed\n", end-start);
+} //end of the function Win_Map2Bsp
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Map2Bsp(char *mapfilename, char *outputfilename)
+{
+ double start, end;
+ char path[1024];
+
+ start = I_FloatTime ();
+
+ ThreadSetDefault ();
+ //yeah sure Carmack
+ //numthreads = 1; //multiple threads aren't helping...
+ //SetQdirFromPath(bspfilename);
+
+ strcpy(source, ExpandArg(mapfilename));
+ StripExtension(source);
+
+ // delete portal and line files
+ sprintf(path, "%s.prt", source);
+ remove(path);
+ sprintf(path, "%s.lin", source);
+ remove(path);
+
+ strcpy(name, ExpandArg(mapfilename));
+ DefaultExtension(name, ".map"); // might be .reg
+
+ //
+ // if onlyents, just grab the entites and resave
+ //
+ if (onlyents)
+ {
+ char out[1024];
+
+ Q2_AllocMaxBSP();
+ sprintf (out, "%s.bsp", source);
+ Q2_LoadBSPFile(out, 0, 0);
+ num_entities = 0;
+
+ Q2_LoadMapFile(name);
+ SetModelNumbers();
+ SetLightStyles();
+
+ Q2_UnparseEntities();
+
+ Q2_WriteBSPFile(out);
+ //
+ Q2_FreeMaxBSP();
+ } //end if
+ else
+ {
+ //
+ // start from scratch
+ //
+ Q2_AllocMaxBSP();
+ //load the map
+ Q2_LoadMapFile(name);
+ //create the .bsp file
+ SetModelNumbers();
+ SetLightStyles();
+ ProcessModels();
+ //write the BSP
+ Q2_WriteBSPFile(outputfilename);
+ //
+ Q2_FreeMaxBSP();
+ } //end else
+
+ end = I_FloatTime();
+ Log_Print("%5.0f seconds elapsed\n", end-start);
+} //end of the function Map2Bsp
+*/
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AASOuputFile(quakefile_t *qf, char *outputpath, char *filename)
+{
+ char ext[MAX_PATH];
+
+ //
+ if (strlen(outputpath))
+ {
+ strcpy(filename, outputpath);
+ //append the bsp file base
+ AppendPathSeperator(filename, MAX_PATH);
+ ExtractFileBase(qf->origname, &filename[strlen(filename)]);
+ //append .aas
+ strcat(filename, ".aas");
+ return;
+ } //end if
+ //
+ ExtractFileExtension(qf->filename, ext);
+ if (!stricmp(ext, "pk3") || !stricmp(ext, "pak") || !stricmp(ext, "sin"))
+ {
+ strcpy(filename, qf->filename);
+ while(strlen(filename) &&
+ filename[strlen(filename)-1] != '\\' &&
+ filename[strlen(filename)-1] != '/')
+ {
+ filename[strlen(filename)-1] = '\0';
+ } //end while
+ strcat(filename, "maps");
+ if (access(filename, 0x04)) CreatePath(filename);
+ //append the bsp file base
+ AppendPathSeperator(filename, MAX_PATH);
+ ExtractFileBase(qf->origname, &filename[strlen(filename)]);
+ //append .aas
+ strcat(filename, ".aas");
+ } //end if
+ else
+ {
+ strcpy(filename, qf->filename);
+ while(strlen(filename) &&
+ filename[strlen(filename)-1] != '.')
+ {
+ filename[strlen(filename)-1] = '\0';
+ } //end while
+ strcat(filename, "aas");
+ } //end else
+} //end of the function AASOutputFile
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void CreateAASFilesForAllBSPFiles(char *quakepath)
+{
+#if defined(WIN32)|defined(_WIN32)
+ WIN32_FIND_DATA filedata;
+ HWND handle;
+ struct _stat statbuf;
+#else
+ glob_t globbuf;
+ struct stat statbuf;
+ int j;
+#endif
+ int done;
+ char filter[_MAX_PATH], bspfilter[_MAX_PATH], aasfilter[_MAX_PATH];
+ char aasfile[_MAX_PATH], buf[_MAX_PATH], foldername[_MAX_PATH];
+ quakefile_t *qf, *qf2, *files, *bspfiles, *aasfiles;
+
+ strcpy(filter, quakepath);
+ AppendPathSeperator(filter, sizeof(filter));
+ strcat(filter, "*");
+
+#if defined(WIN32)|defined(_WIN32)
+ handle = FindFirstFile(filter, &filedata);
+ done = (handle == INVALID_HANDLE_VALUE);
+ while(!done)
+ {
+ _splitpath(filter, foldername, NULL, NULL, NULL);
+ _splitpath(filter, NULL, &foldername[strlen(foldername)], NULL, NULL);
+ AppendPathSeperator(foldername, _MAX_PATH);
+ strcat(foldername, filedata.cFileName);
+ _stat(foldername, &statbuf);
+#else
+ glob(filter, 0, NULL, &globbuf);
+ for (j = 0; j < globbuf.gl_pathc; j++)
+ {
+ strcpy(foldername, globbuf.gl_pathv[j]);
+ stat(foldername, &statbuf);
+#endif
+ //if it is a folder
+ if (statbuf.st_mode & S_IFDIR)
+ {
+ //
+ AppendPathSeperator(foldername, sizeof(foldername));
+ //get all the bsp files
+ strcpy(bspfilter, foldername);
+ strcat(bspfilter, "maps/*.bsp");
+ files = FindQuakeFiles(bspfilter);
+ strcpy(bspfilter, foldername);
+ strcat(bspfilter, "*.pk3/maps/*.bsp");
+ bspfiles = FindQuakeFiles(bspfilter);
+ for (qf = bspfiles; qf; qf = qf->next) if (!qf->next) break;
+ if (qf) qf->next = files;
+ else bspfiles = files;
+ //get all the aas files
+ strcpy(aasfilter, foldername);
+ strcat(aasfilter, "maps/*.aas");
+ files = FindQuakeFiles(aasfilter);
+ strcpy(aasfilter, foldername);
+ strcat(aasfilter, "*.pk3/maps/*.aas");
+ aasfiles = FindQuakeFiles(aasfilter);
+ for (qf = aasfiles; qf; qf = qf->next) if (!qf->next) break;
+ if (qf) qf->next = files;
+ else aasfiles = files;
+ //
+ for (qf = bspfiles; qf; qf = qf->next)
+ {
+ sprintf(aasfile, "%s/%s", qf->pakfile, qf->origname);
+ Log_Print("found %s\n", aasfile);
+ strcpy(&aasfile[strlen(aasfile)-strlen(".bsp")], ".aas");
+ for (qf2 = aasfiles; qf2; qf2 = qf2->next)
+ {
+ sprintf(buf, "%s/%s", qf2->pakfile, qf2->origname);
+ if (!stricmp(aasfile, buf))
+ {
+ Log_Print("found %s\n", buf);
+ break;
+ } //end if
+ } //end for
+ } //end for
+ } //end if
+#if defined(WIN32)|defined(_WIN32)
+ //find the next file
+ done = !FindNextFile(handle, &filedata);
+ } //end while
+#else
+ } //end for
+ globfree(&globbuf);
+#endif
+} //end of the function CreateAASFilesForAllBSPFiles
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+quakefile_t *GetArgumentFiles(int argc, char *argv[], int *i, char *ext)
+{
+ quakefile_t *qfiles, *lastqf, *qf;
+ int j;
+ char buf[1024];
+
+ qfiles = NULL;
+ lastqf = NULL;
+ for (; (*i)+1 < argc && argv[(*i)+1][0] != '-'; (*i)++)
+ {
+ strcpy(buf, argv[(*i)+1]);
+ for (j = strlen(buf)-1; j >= strlen(buf)-4; j--)
+ if (buf[j] == '.') break;
+ if (j >= strlen(buf)-4)
+ strcpy(&buf[j+1], ext);
+ qf = FindQuakeFiles(buf);
+ if (!qf) continue;
+ if (lastqf) lastqf->next = qf;
+ else qfiles = qf;
+ lastqf = qf;
+ while(lastqf->next) lastqf = lastqf->next;
+ } //end for
+ return qfiles;
+} //end of the function GetArgumentFiles
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+
+#define COMP_BSP2MAP 1
+#define COMP_BSP2AAS 2
+#define COMP_REACH 3
+#define COMP_CLUSTER 4
+#define COMP_AASOPTIMIZE 5
+#define COMP_AASINFO 6
+
+int main (int argc, char **argv)
+{
+ int i, comp = 0;
+ char outputpath[MAX_PATH] = "";
+ char filename[MAX_PATH] = "unknown";
+ quakefile_t *qfiles, *qf;
+ double start_time;
+
+ myargc = argc;
+ myargv = argv;
+
+ start_time = I_FloatTime();
+
+ Log_Open("bspc.log"); //open a log file
+ Log_Print("BSPC version "BSPC_VERSION", %s %s\n", __DATE__, __TIME__);
+
+ DefaultCfg();
+ for (i = 1; i < argc; i++)
+ {
+ if (!stricmp(argv[i],"-threads"))
+ {
+ if (i + 1 >= argc) {i = 0; break;}
+ numthreads = atoi(argv[++i]);
+ Log_Print("threads = %d\n", numthreads);
+ } //end if
+ else if (!stricmp(argv[i], "-noverbose"))
+ {
+ Log_Print("verbose = false\n");
+ verbose = false;
+ } //end else if
+ else if (!stricmp(argv[i], "-nocsg"))
+ {
+ Log_Print("nocsg = true\n");
+ nocsg = true;
+ } //end else if
+ else if (!stricmp(argv[i], "-optimize"))
+ {
+ Log_Print("optimize = true\n");
+ optimize = true;
+ } //end else if
+ /*
+ else if (!stricmp(argv[i],"-glview"))
+ {
+ glview = true;
+ } //end else if
+ else if (!stricmp(argv[i], "-draw"))
+ {
+ Log_Print("drawflag = true\n");
+ drawflag = true;
+ } //end else if
+ else if (!stricmp(argv[i], "-noweld"))
+ {
+ Log_Print("noweld = true\n");
+ noweld = true;
+ } //end else if
+ else if (!stricmp(argv[i], "-noshare"))
+ {
+ Log_Print("noshare = true\n");
+ noshare = true;
+ } //end else if
+ else if (!stricmp(argv[i], "-notjunc"))
+ {
+ Log_Print("notjunc = true\n");
+ notjunc = true;
+ } //end else if
+ else if (!stricmp(argv[i], "-nowater"))
+ {
+ Log_Print("nowater = true\n");
+ nowater = true;
+ } //end else if
+ else if (!stricmp(argv[i], "-noprune"))
+ {
+ Log_Print("noprune = true\n");
+ noprune = true;
+ } //end else if
+ else if (!stricmp(argv[i], "-nomerge"))
+ {
+ Log_Print("nomerge = true\n");
+ nomerge = true;
+ } //end else if
+ else if (!stricmp(argv[i], "-nosubdiv"))
+ {
+ Log_Print("nosubdiv = true\n");
+ nosubdiv = true;
+ } //end else if
+ else if (!stricmp(argv[i], "-nodetail"))
+ {
+ Log_Print("nodetail = true\n");
+ nodetail = true;
+ } //end else if
+ else if (!stricmp(argv[i], "-fulldetail"))
+ {
+ Log_Print("fulldetail = true\n");
+ fulldetail = true;
+ } //end else if
+ else if (!stricmp(argv[i], "-onlyents"))
+ {
+ Log_Print("onlyents = true\n");
+ onlyents = true;
+ } //end else if
+ else if (!stricmp(argv[i], "-micro"))
+ {
+ if (i + 1 >= argc) {i = 0; break;}
+ microvolume = atof(argv[++i]);
+ Log_Print("microvolume = %f\n", microvolume);
+ } //end else if
+ else if (!stricmp(argv[i], "-leaktest"))
+ {
+ Log_Print("leaktest = true\n");
+ leaktest = true;
+ } //end else if
+ else if (!stricmp(argv[i], "-verboseentities"))
+ {
+ Log_Print("verboseentities = true\n");
+ verboseentities = true;
+ } //end else if
+ else if (!stricmp(argv[i], "-chop"))
+ {
+ if (i + 1 >= argc) {i = 0; break;}
+ subdivide_size = atof(argv[++i]);
+ Log_Print("subdivide_size = %f\n", subdivide_size);
+ } //end else if
+ else if (!stricmp (argv[i], "-tmpout"))
+ {
+ strcpy (outbase, "/tmp");
+ Log_Print("temp output\n");
+ } //end else if
+ */
+#ifdef ME
+ else if (!stricmp(argv[i], "-freetree"))
+ {
+ freetree = true;
+ Log_Print("freetree = true\n");
+ } //end else if
+ else if (!stricmp(argv[i], "-grapplereach"))
+ {
+ calcgrapplereach = true;
+ Log_Print("grapplereach = true\n");
+ } //end else if
+ else if (!stricmp(argv[i], "-nobrushmerge"))
+ {
+ nobrushmerge = true;
+ Log_Print("nobrushmerge = true\n");
+ } //end else if
+ else if (!stricmp(argv[i], "-noliquids"))
+ {
+ noliquids = true;
+ Log_Print("noliquids = true\n");
+ } //end else if
+ else if (!stricmp(argv[i], "-forcesidesvisible"))
+ {
+ forcesidesvisible = true;
+ Log_Print("forcesidesvisible = true\n");
+ } //end else if
+ else if (!stricmp(argv[i], "-output"))
+ {
+ if (i + 1 >= argc) {i = 0; break;}
+ if (access(argv[i+1], 0x04)) Warning("the folder %s does not exist", argv[i+1]);
+ strcpy(outputpath, argv[++i]);
+ } //end else if
+ else if (!stricmp(argv[i], "-breadthfirst"))
+ {
+ use_nodequeue = true;
+ Log_Print("breadthfirst = true\n");
+ } //end else if
+ else if (!stricmp(argv[i], "-capsule"))
+ {
+ capsule_collision = true;
+ Log_Print("capsule_collision = true\n");
+ } //end else if
+ else if (!stricmp(argv[i], "-cfg"))
+ {
+ if (i + 1 >= argc) {i = 0; break;}
+ if (!LoadCfgFile(argv[++i]))
+ exit(0);
+ } //end else if
+ else if (!stricmp(argv[i], "-bsp2map"))
+ {
+ if (i + 1 >= argc) {i = 0; break;}
+ comp = COMP_BSP2MAP;
+ qfiles = GetArgumentFiles(argc, argv, &i, "bsp");
+ } //end else if
+ else if (!stricmp(argv[i], "-bsp2aas"))
+ {
+ if (i + 1 >= argc) {i = 0; break;}
+ comp = COMP_BSP2AAS;
+ qfiles = GetArgumentFiles(argc, argv, &i, "bsp");
+ } //end else if
+ else if (!stricmp(argv[i], "-aasall"))
+ {
+ if (i + 1 >= argc) {i = 0; break;}
+ CreateAASFilesForAllBSPFiles(argv[++i]);
+ } //end else if
+ else if (!stricmp(argv[i], "-reach"))
+ {
+ if (i + 1 >= argc) {i = 0; break;}
+ comp = COMP_REACH;
+ qfiles = GetArgumentFiles(argc, argv, &i, "bsp");
+ } //end else if
+ else if (!stricmp(argv[i], "-cluster"))
+ {
+ if (i + 1 >= argc) {i = 0; break;}
+ comp = COMP_CLUSTER;
+ qfiles = GetArgumentFiles(argc, argv, &i, "bsp");
+ } //end else if
+ else if (!stricmp(argv[i], "-aasinfo"))
+ {
+ if (i + 1 >= argc) {i = 0; break;}
+ comp = COMP_AASINFO;
+ qfiles = GetArgumentFiles(argc, argv, &i, "aas");
+ } //end else if
+ else if (!stricmp(argv[i], "-aasopt"))
+ {
+ if (i + 1 >= argc) {i = 0; break;}
+ comp = COMP_AASOPTIMIZE;
+ qfiles = GetArgumentFiles(argc, argv, &i, "aas");
+ } //end else if
+#endif //ME
+ else
+ {
+ Log_Print("unknown parameter %s\n", argv[i]);
+ break;
+ } //end else
+ } //end for
+
+ //if there are parameters and there's no mismatch in one of the parameters
+ if (argc > 1 && i == argc)
+ {
+ switch(comp)
+ {
+ case COMP_BSP2MAP:
+ {
+ if (!qfiles) Log_Print("no files found\n");
+ for (qf = qfiles; qf; qf = qf->next)
+ {
+ //copy the output path
+ strcpy(filename, outputpath);
+ //append the bsp file base
+ AppendPathSeperator(filename, MAX_PATH);
+ ExtractFileBase(qf->origname, &filename[strlen(filename)]);
+ //append .map
+ strcat(filename, ".map");
+ //
+ Log_Print("bsp2map: %s to %s\n", qf->origname, filename);
+ if (qf->type != QFILETYPE_BSP) Warning("%s is probably not a BSP file\n", qf->origname);
+ //
+ LoadMapFromBSP(qf);
+ //write the map file
+ WriteMapFile(filename);
+ } //end for
+ break;
+ } //end case
+ case COMP_BSP2AAS:
+ {
+ if (!qfiles) Log_Print("no files found\n");
+ for (qf = qfiles; qf; qf = qf->next)
+ {
+ AASOuputFile(qf, outputpath, filename);
+ //
+ Log_Print("bsp2aas: %s to %s\n", qf->origname, filename);
+ if (qf->type != QFILETYPE_BSP) Warning("%s is probably not a BSP file\n", qf->origname);
+ //set before map loading
+ create_aas = 1;
+ LoadMapFromBSP(qf);
+ //create the AAS file
+ AAS_Create(filename);
+ //if it's a Quake3 map calculate the reachabilities and clusters
+ if (loadedmaptype == MAPTYPE_QUAKE3) AAS_CalcReachAndClusters(qf);
+ //
+ if (optimize) AAS_Optimize();
+ //
+ //write out the stored AAS file
+ if (!AAS_WriteAASFile(filename))
+ {
+ Error("error writing %s\n", filename);
+ } //end if
+ //deallocate memory
+ AAS_FreeMaxAAS();
+ } //end for
+ break;
+ } //end case
+ case COMP_REACH:
+ {
+ if (!qfiles) Log_Print("no files found\n");
+ for (qf = qfiles; qf; qf = qf->next)
+ {
+ AASOuputFile(qf, outputpath, filename);
+ //
+ Log_Print("reach: %s to %s\n", qf->origname, filename);
+ if (qf->type != QFILETYPE_BSP) Warning("%s is probably not a BSP file\n", qf->origname);
+ //if the AAS file exists in the output directory
+ if (!access(filename, 0x04))
+ {
+ if (!AAS_LoadAASFile(filename, 0, 0))
+ {
+ Error("error loading aas file %s\n", filename);
+ } //end if
+ //assume it's a Quake3 BSP file
+ loadedmaptype = MAPTYPE_QUAKE3;
+ } //end if
+ else
+ {
+ Warning("AAS file %s not found in output folder\n", filename);
+ Log_Print("creating %s...\n", filename);
+ //set before map loading
+ create_aas = 1;
+ LoadMapFromBSP(qf);
+ //create the AAS file
+ AAS_Create(filename);
+ } //end else
+ //if it's a Quake3 map calculate the reachabilities and clusters
+ if (loadedmaptype == MAPTYPE_QUAKE3)
+ {
+ AAS_CalcReachAndClusters(qf);
+ } //end if
+ //
+ if (optimize) AAS_Optimize();
+ //write out the stored AAS file
+ if (!AAS_WriteAASFile(filename))
+ {
+ Error("error writing %s\n", filename);
+ } //end if
+ //deallocate memory
+ AAS_FreeMaxAAS();
+ } //end for
+ break;
+ } //end case
+ case COMP_CLUSTER:
+ {
+ if (!qfiles) Log_Print("no files found\n");
+ for (qf = qfiles; qf; qf = qf->next)
+ {
+ AASOuputFile(qf, outputpath, filename);
+ //
+ Log_Print("cluster: %s to %s\n", qf->origname, filename);
+ if (qf->type != QFILETYPE_BSP) Warning("%s is probably not a BSP file\n", qf->origname);
+ //if the AAS file exists in the output directory
+ if (!access(filename, 0x04))
+ {
+ if (!AAS_LoadAASFile(filename, 0, 0))
+ {
+ Error("error loading aas file %s\n", filename);
+ } //end if
+ //assume it's a Quake3 BSP file
+ loadedmaptype = MAPTYPE_QUAKE3;
+ //if it's a Quake3 map calculate the clusters
+ if (loadedmaptype == MAPTYPE_QUAKE3)
+ {
+ aasworld.numclusters = 0;
+ AAS_InitBotImport();
+ AAS_InitClustering();
+ } //end if
+ } //end if
+ else
+ {
+ Warning("AAS file %s not found in output folder\n", filename);
+ Log_Print("creating %s...\n", filename);
+ //set before map loading
+ create_aas = 1;
+ LoadMapFromBSP(qf);
+ //create the AAS file
+ AAS_Create(filename);
+ //if it's a Quake3 map calculate the reachabilities and clusters
+ if (loadedmaptype == MAPTYPE_QUAKE3) AAS_CalcReachAndClusters(qf);
+ } //end else
+ //
+ if (optimize) AAS_Optimize();
+ //write out the stored AAS file
+ if (!AAS_WriteAASFile(filename))
+ {
+ Error("error writing %s\n", filename);
+ } //end if
+ //deallocate memory
+ AAS_FreeMaxAAS();
+ } //end for
+ break;
+ } //end case
+ case COMP_AASOPTIMIZE:
+ {
+ if (!qfiles) Log_Print("no files found\n");
+ for (qf = qfiles; qf; qf = qf->next)
+ {
+ AASOuputFile(qf, outputpath, filename);
+ //
+ Log_Print("optimizing: %s to %s\n", qf->origname, filename);
+ if (qf->type != QFILETYPE_AAS) Warning("%s is probably not a AAS file\n", qf->origname);
+ //
+ AAS_InitBotImport();
+ //
+ if (!AAS_LoadAASFile(qf->filename, qf->offset, qf->length))
+ {
+ Error("error loading aas file %s\n", qf->filename);
+ } //end if
+ AAS_Optimize();
+ //write out the stored AAS file
+ if (!AAS_WriteAASFile(filename))
+ {
+ Error("error writing %s\n", filename);
+ } //end if
+ //deallocate memory
+ AAS_FreeMaxAAS();
+ } //end for
+ break;
+ } //end case
+ case COMP_AASINFO:
+ {
+ if (!qfiles) Log_Print("no files found\n");
+ for (qf = qfiles; qf; qf = qf->next)
+ {
+ AASOuputFile(qf, outputpath, filename);
+ //
+ Log_Print("aas info for: %s\n", filename);
+ if (qf->type != QFILETYPE_AAS) Warning("%s is probably not a AAS file\n", qf->origname);
+ //
+ AAS_InitBotImport();
+ //
+ if (!AAS_LoadAASFile(qf->filename, qf->offset, qf->length))
+ {
+ Error("error loading aas file %s\n", qf->filename);
+ } //end if
+ AAS_ShowTotals();
+ } //end for
+ } //end case
+ default:
+ {
+ Log_Print("don't know what to do\n");
+ break;
+ } //end default
+ } //end switch
+ } //end if
+ else
+ {
+ Log_Print("Usage: bspc [-<switch> [-<switch> ...]]\n"
+#if defined(WIN32) || defined(_WIN32)
+ "Example 1: bspc -bsp2aas d:\\quake3\\baseq3\\maps\\mymap?.bsp\n"
+ "Example 2: bspc -bsp2aas d:\\quake3\\baseq3\\pak0.pk3\\maps/q3dm*.bsp\n"
+#else
+ "Example 1: bspc -bsp2aas /quake3/baseq3/maps/mymap?.bsp\n"
+ "Example 2: bspc -bsp2aas /quake3/baseq3/pak0.pk3/maps/q3dm*.bsp\n"
+#endif
+ "\n"
+ "Switches:\n"
+ //" bsp2map <[pakfilter/]filter.bsp> = convert BSP to MAP\n"
+ //" aasall <quake3folder> = create AAS files for all BSPs\n"
+ " bsp2aas <[pakfilter/]filter.bsp> = convert BSP to AAS\n"
+ " reach <filter.bsp> = compute reachability & clusters\n"
+ " cluster <filter.aas> = compute clusters\n"
+ " aasopt <filter.aas> = optimize aas file\n"
+ " aasinfo <filter.aas> = show AAS file info\n"
+ " output <output path> = set output path\n"
+ " threads <X> = set number of threads to X\n"
+ " cfg <filename> = use this cfg file\n"
+ " optimize = enable optimization\n"
+ " noverbose = disable verbose output\n"
+ " breadthfirst = breadth first bsp building\n"
+ " nobrushmerge = don't merge brushes\n"
+ " noliquids = don't write liquids to map\n"
+ " freetree = free the bsp tree\n"
+ " nocsg = disables brush chopping\n"
+ " forcesidesvisible = force all sides to be visible\n"
+ " grapplereach = calculate grapple reachabilities\n"
+
+/* " glview = output a GL view\n"
+ " draw = enables drawing\n"
+ " noweld = disables weld\n"
+ " noshare = disables sharing\n"
+ " notjunc = disables juncs\n"
+ " nowater = disables water brushes\n"
+ " noprune = disables node prunes\n"
+ " nomerge = disables face merging\n"
+ " nosubdiv = disables subdeviding\n"
+ " nodetail = disables detail brushes\n"
+ " fulldetail = enables full detail\n"
+ " onlyents = only compile entities with bsp\n"
+ " micro <volume>\n"
+ " = sets the micro volume to the given float\n"
+ " leaktest = perform a leak test\n"
+ " verboseentities\n"
+ " = enable entity verbose mode\n"
+ " chop <subdivide_size>\n"
+ " = sets the subdivide size to the given float\n"*/
+ "\n");
+ } //end else
+ Log_Print("BSPC run time is %5.0f seconds\n", I_FloatTime() - start_time);
+ Log_Close(); //close the log file
+ return 0;
+} //end of the function main
+
diff --git a/code/bspc/bspc.sln b/code/bspc/bspc.sln
index 79dc8ae..b09fb52 100755
--- a/code/bspc/bspc.sln
+++ b/code/bspc/bspc.sln
@@ -1,28 +1,28 @@
-Microsoft Visual Studio Solution File, Format Version 8.00
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bspc", "bspc.vcproj", "{4E4EBC16-F345-4667-84E1-86633BAFDAE6}"
- ProjectSection(ProjectDependencies) = postProject
- EndProjectSection
-EndProject
-Global
- GlobalSection(SourceCodeControl) = preSolution
- SccNumberOfProjects = 1
- SccProjectUniqueName0 = bspc.vcproj
- SccProjectName0 = \u0022$/source/code/bspc\u0022,\u0020IGAAAAAA
- SccLocalPath0 = .
- SccProvider0 = MSSCCI:Perforce\u0020SCM
- EndGlobalSection
- GlobalSection(SolutionConfiguration) = preSolution
- Debug = Debug
- Release = Release
- EndGlobalSection
- GlobalSection(ProjectConfiguration) = postSolution
- {4E4EBC16-F345-4667-84E1-86633BAFDAE6}.Debug.ActiveCfg = Debug|Win32
- {4E4EBC16-F345-4667-84E1-86633BAFDAE6}.Debug.Build.0 = Debug|Win32
- {4E4EBC16-F345-4667-84E1-86633BAFDAE6}.Release.ActiveCfg = Release|Win32
- {4E4EBC16-F345-4667-84E1-86633BAFDAE6}.Release.Build.0 = Release|Win32
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- EndGlobalSection
- GlobalSection(ExtensibilityAddIns) = postSolution
- EndGlobalSection
-EndGlobal
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bspc", "bspc.vcproj", "{4E4EBC16-F345-4667-84E1-86633BAFDAE6}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SourceCodeControl) = preSolution
+ SccNumberOfProjects = 1
+ SccProjectUniqueName0 = bspc.vcproj
+ SccProjectName0 = \u0022$/source/code/bspc\u0022,\u0020IGAAAAAA
+ SccLocalPath0 = .
+ SccProvider0 = MSSCCI:Perforce\u0020SCM
+ EndGlobalSection
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ Release = Release
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {4E4EBC16-F345-4667-84E1-86633BAFDAE6}.Debug.ActiveCfg = Debug|Win32
+ {4E4EBC16-F345-4667-84E1-86633BAFDAE6}.Debug.Build.0 = Debug|Win32
+ {4E4EBC16-F345-4667-84E1-86633BAFDAE6}.Release.ActiveCfg = Release|Win32
+ {4E4EBC16-F345-4667-84E1-86633BAFDAE6}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/code/bspc/bspc.vcproj b/code/bspc/bspc.vcproj
index 6171e1a..0fb1bd7 100755
--- a/code/bspc/bspc.vcproj
+++ b/code/bspc/bspc.vcproj
@@ -1,1381 +1,1381 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="7.10"
- Name="bspc"
- SccProjectName="&quot;$/source/code/bspc&quot;, IGAAAAAA"
- SccLocalPath=".">
- <Platforms>
- <Platform
- Name="Win32"/>
- </Platforms>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory=".\Debug"
- IntermediateDirectory=".\Debug"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;BSPC"
- BasicRuntimeChecks="3"
- RuntimeLibrary="1"
- UsePrecompiledHeader="2"
- PrecompiledHeaderFile=".\Debug/bspc.pch"
- AssemblerListingLocation=".\Debug/"
- ObjectFile=".\Debug/"
- ProgramDataBaseFileName=".\Debug/"
- WarningLevel="3"
- SuppressStartupBanner="TRUE"
- DebugInformationFormat="4"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- OutputFile="..\Debug\bspc.exe"
- LinkIncremental="1"
- SuppressStartupBanner="TRUE"
- GenerateDebugInformation="TRUE"
- ProgramDatabaseFile=".\Debug/bspc.pdb"
- SubSystem="1"
- TargetMachine="1"/>
- <Tool
- Name="VCMIDLTool"
- TypeLibraryName=".\Debug/bspc.tlb"
- HeaderFileName=""/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_DEBUG"
- Culture="1033"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory=".\Release"
- IntermediateDirectory=".\Release"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- InlineFunctionExpansion="1"
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;BSPC"
- StringPooling="TRUE"
- RuntimeLibrary="0"
- EnableFunctionLevelLinking="TRUE"
- UsePrecompiledHeader="2"
- PrecompiledHeaderFile=".\Release/bspc.pch"
- AssemblerListingLocation=".\Release/"
- ObjectFile=".\Release/"
- ProgramDataBaseFileName=".\Release/"
- WarningLevel="3"
- SuppressStartupBanner="TRUE"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- OutputFile="..\Release\bspc.exe"
- LinkIncremental="1"
- SuppressStartupBanner="TRUE"
- ProgramDatabaseFile=".\Release/bspc.pdb"
- SubSystem="1"
- TargetMachine="1"/>
- <Tool
- Name="VCMIDLTool"
- TypeLibraryName=".\Release/bspc.tlb"
- HeaderFileName=""/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="NDEBUG"
- Culture="1033"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="Source Files"
- Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
- <File
- RelativePath="_files.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="aas_areamerging.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="aas_cfg.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="aas_create.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="aas_edgemelting.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="aas_facemerging.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="aas_file.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="aas_gsubdiv.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="aas_map.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="aas_prunenodes.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="aas_store.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="be_aas_bspc.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\botlib\be_aas_bspq3.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\botlib\be_aas_cluster.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\botlib\be_aas_move.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\botlib\be_aas_optimize.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\botlib\be_aas_reach.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\botlib\be_aas_sample.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="brushbsp.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="bspc.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\qcommon\cm_load.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\qcommon\cm_patch.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\qcommon\cm_test.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\qcommon\cm_trace.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="csg.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="glfile.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="l_bsp_ent.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="l_bsp_hl.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="l_bsp_q1.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="l_bsp_q2.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="l_bsp_q3.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="l_bsp_sin.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="l_cmd.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\botlib\l_libvar.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="l_log.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="l_math.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="l_mem.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="l_poly.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\botlib\l_precomp.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="l_qfiles.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\botlib\l_script.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\botlib\l_struct.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="l_threads.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="l_utils.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="leakfile.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="map.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="map_hl.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="map_q1.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="map_q2.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="map_q3.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="map_sin.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\qcommon\md4.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="nodraw.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="portals.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="textures.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tree.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\qcommon\unzip.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="Header Files"
- Filter="h;hpp;hxx;hm;inl">
- <File
- RelativePath="aas_areamerging.h">
- </File>
- <File
- RelativePath="aas_cfg.h">
- </File>
- <File
- RelativePath="aas_create.h">
- </File>
- <File
- RelativePath="aas_edgemelting.h">
- </File>
- <File
- RelativePath="aas_facemerging.h">
- </File>
- <File
- RelativePath="aas_file.h">
- </File>
- <File
- RelativePath="aas_gsubdiv.h">
- </File>
- <File
- RelativePath="aas_map.h">
- </File>
- <File
- RelativePath="aas_prunenodes.h">
- </File>
- <File
- RelativePath="aas_store.h">
- </File>
- <File
- RelativePath="..\botlib\aasfile.h">
- </File>
- <File
- RelativePath="..\botlib\be_aas_bsp.h">
- </File>
- <File
- RelativePath="be_aas_bspc.h">
- </File>
- <File
- RelativePath="..\botlib\be_aas_cluster.h">
- </File>
- <File
- RelativePath="..\botlib\be_aas_debug.h">
- </File>
- <File
- RelativePath="..\botlib\be_aas_def.h">
- </File>
- <File
- RelativePath="..\botlib\be_aas_entity.h">
- </File>
- <File
- RelativePath="..\botlib\be_aas_file.h">
- </File>
- <File
- RelativePath="..\botlib\be_aas_funcs.h">
- </File>
- <File
- RelativePath="..\botlib\be_aas_main.h">
- </File>
- <File
- RelativePath="..\botlib\be_aas_move.h">
- </File>
- <File
- RelativePath="..\botlib\be_aas_optimize.h">
- </File>
- <File
- RelativePath="..\botlib\be_aas_reach.h">
- </File>
- <File
- RelativePath="..\botlib\be_aas_route.h">
- </File>
- <File
- RelativePath="..\botlib\be_aas_routealt.h">
- </File>
- <File
- RelativePath="..\botlib\be_aas_sample.h">
- </File>
- <File
- RelativePath="..\botlib\be_interface.h">
- </File>
- <File
- RelativePath="..\game\bg_public.h">
- </File>
- <File
- RelativePath="..\cgame\cg_public.h">
- </File>
- <File
- RelativePath="..\client\client.h">
- </File>
- <File
- RelativePath="..\qcommon\cm_local.h">
- </File>
- <File
- RelativePath="..\qcommon\cm_patch.h">
- </File>
- <File
- RelativePath="..\qcommon\cm_polylib.h">
- </File>
- <File
- RelativePath="..\qcommon\cm_public.h">
- </File>
- <File
- RelativePath="..\ui\keycodes.h">
- </File>
- <File
- RelativePath="..\client\keys.h">
- </File>
- <File
- RelativePath="l_bsp_ent.h">
- </File>
- <File
- RelativePath="l_bsp_hl.h">
- </File>
- <File
- RelativePath="l_bsp_q1.h">
- </File>
- <File
- RelativePath="l_bsp_q2.h">
- </File>
- <File
- RelativePath="l_bsp_q3.h">
- </File>
- <File
- RelativePath="l_bsp_sin.h">
- </File>
- <File
- RelativePath="l_cmd.h">
- </File>
- <File
- RelativePath="..\botlib\l_libvar.h">
- </File>
- <File
- RelativePath="l_log.h">
- </File>
- <File
- RelativePath="..\botlib\l_log.h">
- </File>
- <File
- RelativePath="l_math.h">
- </File>
- <File
- RelativePath="l_mem.h">
- </File>
- <File
- RelativePath="..\botlib\l_memory.h">
- </File>
- <File
- RelativePath="l_poly.h">
- </File>
- <File
- RelativePath="..\botlib\l_precomp.h">
- </File>
- <File
- RelativePath="l_qfiles.h">
- </File>
- <File
- RelativePath="..\botlib\l_script.h">
- </File>
- <File
- RelativePath="..\botlib\l_struct.h">
- </File>
- <File
- RelativePath="l_threads.h">
- </File>
- <File
- RelativePath="l_utils.h">
- </File>
- <File
- RelativePath="q2files.h">
- </File>
- <File
- RelativePath="q3files.h">
- </File>
- <File
- RelativePath="..\game\q_shared.h">
- </File>
- <File
- RelativePath="qbsp.h">
- </File>
- <File
- RelativePath="..\qcommon\qcommon.h">
- </File>
- <File
- RelativePath="..\qcommon\qfiles.h">
- </File>
- <File
- RelativePath="sinfiles.h">
- </File>
- <File
- RelativePath="..\client\snd_public.h">
- </File>
- <File
- RelativePath="..\game\surfaceflags.h">
- </File>
- <File
- RelativePath="..\renderer\tr_public.h">
- </File>
- <File
- RelativePath="..\cgame\tr_types.h">
- </File>
- <File
- RelativePath="..\ui\ui_public.h">
- </File>
- <File
- RelativePath="..\qcommon\unzip.h">
- </File>
- </Filter>
- <Filter
- Name="Resource Files"
- Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="bspc"
+ SccProjectName="&quot;$/source/code/bspc&quot;, IGAAAAAA"
+ SccLocalPath=".">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\Debug"
+ IntermediateDirectory=".\Debug"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;BSPC"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\Debug/bspc.pch"
+ AssemblerListingLocation=".\Debug/"
+ ObjectFile=".\Debug/"
+ ProgramDataBaseFileName=".\Debug/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="..\Debug\bspc.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\Debug/bspc.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\Debug/bspc.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\Release"
+ IntermediateDirectory=".\Release"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;BSPC"
+ StringPooling="TRUE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\Release/bspc.pch"
+ AssemblerListingLocation=".\Release/"
+ ObjectFile=".\Release/"
+ ProgramDataBaseFileName=".\Release/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="..\Release\bspc.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ ProgramDatabaseFile=".\Release/bspc.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\Release/bspc.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
+ <File
+ RelativePath="_files.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="aas_areamerging.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="aas_cfg.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="aas_create.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="aas_edgemelting.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="aas_facemerging.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="aas_file.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="aas_gsubdiv.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="aas_map.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="aas_prunenodes.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="aas_store.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="be_aas_bspc.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\botlib\be_aas_bspq3.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\botlib\be_aas_cluster.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\botlib\be_aas_move.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\botlib\be_aas_optimize.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\botlib\be_aas_reach.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\botlib\be_aas_sample.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="brushbsp.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="bspc.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\qcommon\cm_load.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\qcommon\cm_patch.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\qcommon\cm_test.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\qcommon\cm_trace.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="csg.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="glfile.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="l_bsp_ent.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="l_bsp_hl.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="l_bsp_q1.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="l_bsp_q2.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="l_bsp_q3.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="l_bsp_sin.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="l_cmd.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\botlib\l_libvar.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="l_log.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="l_math.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="l_mem.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="l_poly.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\botlib\l_precomp.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="l_qfiles.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\botlib\l_script.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\botlib\l_struct.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="l_threads.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="l_utils.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="leakfile.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="map.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="map_hl.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="map_q1.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="map_q2.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="map_q3.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="map_sin.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\qcommon\md4.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="nodraw.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="portals.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="textures.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="tree.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\qcommon\unzip.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl">
+ <File
+ RelativePath="aas_areamerging.h">
+ </File>
+ <File
+ RelativePath="aas_cfg.h">
+ </File>
+ <File
+ RelativePath="aas_create.h">
+ </File>
+ <File
+ RelativePath="aas_edgemelting.h">
+ </File>
+ <File
+ RelativePath="aas_facemerging.h">
+ </File>
+ <File
+ RelativePath="aas_file.h">
+ </File>
+ <File
+ RelativePath="aas_gsubdiv.h">
+ </File>
+ <File
+ RelativePath="aas_map.h">
+ </File>
+ <File
+ RelativePath="aas_prunenodes.h">
+ </File>
+ <File
+ RelativePath="aas_store.h">
+ </File>
+ <File
+ RelativePath="..\botlib\aasfile.h">
+ </File>
+ <File
+ RelativePath="..\botlib\be_aas_bsp.h">
+ </File>
+ <File
+ RelativePath="be_aas_bspc.h">
+ </File>
+ <File
+ RelativePath="..\botlib\be_aas_cluster.h">
+ </File>
+ <File
+ RelativePath="..\botlib\be_aas_debug.h">
+ </File>
+ <File
+ RelativePath="..\botlib\be_aas_def.h">
+ </File>
+ <File
+ RelativePath="..\botlib\be_aas_entity.h">
+ </File>
+ <File
+ RelativePath="..\botlib\be_aas_file.h">
+ </File>
+ <File
+ RelativePath="..\botlib\be_aas_funcs.h">
+ </File>
+ <File
+ RelativePath="..\botlib\be_aas_main.h">
+ </File>
+ <File
+ RelativePath="..\botlib\be_aas_move.h">
+ </File>
+ <File
+ RelativePath="..\botlib\be_aas_optimize.h">
+ </File>
+ <File
+ RelativePath="..\botlib\be_aas_reach.h">
+ </File>
+ <File
+ RelativePath="..\botlib\be_aas_route.h">
+ </File>
+ <File
+ RelativePath="..\botlib\be_aas_routealt.h">
+ </File>
+ <File
+ RelativePath="..\botlib\be_aas_sample.h">
+ </File>
+ <File
+ RelativePath="..\botlib\be_interface.h">
+ </File>
+ <File
+ RelativePath="..\game\bg_public.h">
+ </File>
+ <File
+ RelativePath="..\cgame\cg_public.h">
+ </File>
+ <File
+ RelativePath="..\client\client.h">
+ </File>
+ <File
+ RelativePath="..\qcommon\cm_local.h">
+ </File>
+ <File
+ RelativePath="..\qcommon\cm_patch.h">
+ </File>
+ <File
+ RelativePath="..\qcommon\cm_polylib.h">
+ </File>
+ <File
+ RelativePath="..\qcommon\cm_public.h">
+ </File>
+ <File
+ RelativePath="..\ui\keycodes.h">
+ </File>
+ <File
+ RelativePath="..\client\keys.h">
+ </File>
+ <File
+ RelativePath="l_bsp_ent.h">
+ </File>
+ <File
+ RelativePath="l_bsp_hl.h">
+ </File>
+ <File
+ RelativePath="l_bsp_q1.h">
+ </File>
+ <File
+ RelativePath="l_bsp_q2.h">
+ </File>
+ <File
+ RelativePath="l_bsp_q3.h">
+ </File>
+ <File
+ RelativePath="l_bsp_sin.h">
+ </File>
+ <File
+ RelativePath="l_cmd.h">
+ </File>
+ <File
+ RelativePath="..\botlib\l_libvar.h">
+ </File>
+ <File
+ RelativePath="l_log.h">
+ </File>
+ <File
+ RelativePath="..\botlib\l_log.h">
+ </File>
+ <File
+ RelativePath="l_math.h">
+ </File>
+ <File
+ RelativePath="l_mem.h">
+ </File>
+ <File
+ RelativePath="..\botlib\l_memory.h">
+ </File>
+ <File
+ RelativePath="l_poly.h">
+ </File>
+ <File
+ RelativePath="..\botlib\l_precomp.h">
+ </File>
+ <File
+ RelativePath="l_qfiles.h">
+ </File>
+ <File
+ RelativePath="..\botlib\l_script.h">
+ </File>
+ <File
+ RelativePath="..\botlib\l_struct.h">
+ </File>
+ <File
+ RelativePath="l_threads.h">
+ </File>
+ <File
+ RelativePath="l_utils.h">
+ </File>
+ <File
+ RelativePath="q2files.h">
+ </File>
+ <File
+ RelativePath="q3files.h">
+ </File>
+ <File
+ RelativePath="..\game\q_shared.h">
+ </File>
+ <File
+ RelativePath="qbsp.h">
+ </File>
+ <File
+ RelativePath="..\qcommon\qcommon.h">
+ </File>
+ <File
+ RelativePath="..\qcommon\qfiles.h">
+ </File>
+ <File
+ RelativePath="sinfiles.h">
+ </File>
+ <File
+ RelativePath="..\client\snd_public.h">
+ </File>
+ <File
+ RelativePath="..\game\surfaceflags.h">
+ </File>
+ <File
+ RelativePath="..\renderer\tr_public.h">
+ </File>
+ <File
+ RelativePath="..\cgame\tr_types.h">
+ </File>
+ <File
+ RelativePath="..\ui\ui_public.h">
+ </File>
+ <File
+ RelativePath="..\qcommon\unzip.h">
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/code/bspc/cfgq3.c b/code/bspc/cfgq3.c
index 588509c..c0598ae 100755
--- a/code/bspc/cfgq3.c
+++ b/code/bspc/cfgq3.c
@@ -1,84 +1,84 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-//===========================================================================
-// BSPC configuration file
-// Quake3
-//===========================================================================
-
-#define PRESENCE_NONE 1
-#define PRESENCE_NORMAL 2
-#define PRESENCE_CROUCH 4
-
-bbox //30x30x56
-{
- presencetype PRESENCE_NORMAL
- flags 0x0000
- mins {-15, -15, -24}
- maxs {15, 15, 32}
-} //end bbox
-
-bbox //30x30x40
-{
- presencetype PRESENCE_CROUCH
- flags 0x0001
- mins {-15, -15, -24}
- maxs {15, 15, 16}
-} //end bbox
-
-settings
-{
- phys_gravitydirection {0, 0, -1}
- phys_friction 6
- phys_stopspeed 100
- phys_gravity 800
- phys_waterfriction 1
- phys_watergravity 400
- phys_maxvelocity 320
- phys_maxwalkvelocity 320
- phys_maxcrouchvelocity 100
- phys_maxswimvelocity 150
- phys_maxacceleration 2200
- phys_airaccelerate 0
- phys_maxstep 18
- phys_maxsteepness 0.7
- phys_maxwaterjump 19
- phys_maxbarrier 33
- phys_jumpvel 270
- phys_falldelta5 40
- phys_falldelta10 60
- rs_waterjump 400
- rs_teleport 50
- rs_barrierjump 100
- rs_startcrouch 300
- rs_startgrapple 500
- rs_startwalkoffledge 70
- rs_startjump 300
- rs_rocketjump 500
- rs_bfgjump 500
- rs_jumppad 250
- rs_aircontrolledjumppad 300
- rs_funcbob 300
- rs_startelevator 50
- rs_falldamage5 300
- rs_falldamage10 500
- rs_maxjumpfallheight 450
-} //end settings
+/*
+===========================================================================
+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
+===========================================================================
+*/
+//===========================================================================
+// BSPC configuration file
+// Quake3
+//===========================================================================
+
+#define PRESENCE_NONE 1
+#define PRESENCE_NORMAL 2
+#define PRESENCE_CROUCH 4
+
+bbox //30x30x56
+{
+ presencetype PRESENCE_NORMAL
+ flags 0x0000
+ mins {-15, -15, -24}
+ maxs {15, 15, 32}
+} //end bbox
+
+bbox //30x30x40
+{
+ presencetype PRESENCE_CROUCH
+ flags 0x0001
+ mins {-15, -15, -24}
+ maxs {15, 15, 16}
+} //end bbox
+
+settings
+{
+ phys_gravitydirection {0, 0, -1}
+ phys_friction 6
+ phys_stopspeed 100
+ phys_gravity 800
+ phys_waterfriction 1
+ phys_watergravity 400
+ phys_maxvelocity 320
+ phys_maxwalkvelocity 320
+ phys_maxcrouchvelocity 100
+ phys_maxswimvelocity 150
+ phys_maxacceleration 2200
+ phys_airaccelerate 0
+ phys_maxstep 18
+ phys_maxsteepness 0.7
+ phys_maxwaterjump 19
+ phys_maxbarrier 33
+ phys_jumpvel 270
+ phys_falldelta5 40
+ phys_falldelta10 60
+ rs_waterjump 400
+ rs_teleport 50
+ rs_barrierjump 100
+ rs_startcrouch 300
+ rs_startgrapple 500
+ rs_startwalkoffledge 70
+ rs_startjump 300
+ rs_rocketjump 500
+ rs_bfgjump 500
+ rs_jumppad 250
+ rs_aircontrolledjumppad 300
+ rs_funcbob 300
+ rs_startelevator 50
+ rs_falldamage5 300
+ rs_falldamage10 500
+ rs_maxjumpfallheight 450
+} //end settings
diff --git a/code/bspc/csg.c b/code/bspc/csg.c
index c141075..fc7c327 100755
--- a/code/bspc/csg.c
+++ b/code/bspc/csg.c
@@ -1,1005 +1,1005 @@
-/*
-===========================================================================
-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"
-
-/*
-
-tag all brushes with original contents
-brushes may contain multiple contents
-there will be no brush overlap after csg phase
-
-*/
-
-int minplanenums[3];
-int maxplanenums[3];
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void CheckBSPBrush(bspbrush_t *brush)
-{
- int i, j;
- plane_t *plane1, *plane2;
-
- //check if the brush is convex... flipped planes make a brush non-convex
- for (i = 0; i < brush->numsides; i++)
- {
- for (j = 0; j < brush->numsides; j++)
- {
- if (i == j) continue;
- plane1 = &mapplanes[brush->sides[i].planenum];
- plane2 = &mapplanes[brush->sides[j].planenum];
- //
- if (WindingsNonConvex(brush->sides[i].winding,
- brush->sides[j].winding,
- plane1->normal, plane2->normal,
- plane1->dist, plane2->dist))
- {
- Log_Print("non convex brush");
- break;
- } //end if
- } //end for
- } //end for
- BoundBrush(brush);
- //check for out of bound brushes
- for (i = 0; i < 3; i++)
- {
- if (brush->mins[i] < -MAX_MAP_BOUNDS || brush->maxs[i] > MAX_MAP_BOUNDS)
- {
- Log_Print("brush: bounds out of range\n");
- Log_Print("ob->mins[%d] = %f, ob->maxs[%d] = %f\n", i, brush->mins[i], i, brush->maxs[i]);
- break;
- } //end if
- if (brush->mins[i] > MAX_MAP_BOUNDS || brush->maxs[i] < -MAX_MAP_BOUNDS)
- {
- Log_Print("brush: no visible sides on brush\n");
- Log_Print("ob->mins[%d] = %f, ob->maxs[%d] = %f\n", i, brush->mins[i], i, brush->maxs[i]);
- break;
- } //end if
- } //end for
-} //end of the function CheckBSPBrush
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BSPBrushWindings(bspbrush_t *brush)
-{
- int i, j;
- winding_t *w;
- plane_t *plane;
-
- for (i = 0; i < brush->numsides; i++)
- {
- plane = &mapplanes[brush->sides[i].planenum];
- w = BaseWindingForPlane(plane->normal, plane->dist);
- for (j = 0; j < brush->numsides && w; j++)
- {
- if (i == j) continue;
- plane = &mapplanes[brush->sides[j].planenum^1];
- ChopWindingInPlace(&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
- } //end for
- brush->sides[i].winding = w;
- } //end for
-} //end of the function BSPBrushWindings
-//===========================================================================
-// NOTE: can't keep brush->original intact
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *TryMergeBrushes(bspbrush_t *brush1, bspbrush_t *brush2)
-{
- int i, j, k, n, shared;
- side_t *side1, *side2, *cs;
- plane_t *plane1, *plane2;
- bspbrush_t *newbrush;
-
- //check for bounding box overlapp
- for (i = 0; i < 3; i++)
- {
- if (brush1->mins[i] > brush2->maxs[i] + 2
- || brush1->maxs[i] < brush2->mins[i] - 2)
- {
- return NULL;
- } //end if
- } //end for
- //
- shared = 0;
- //check if the brush is convex... flipped planes make a brush non-convex
- for (i = 0; i < brush1->numsides; i++)
- {
- side1 = &brush1->sides[i];
- //don't check the "shared" sides
- for (k = 0; k < brush2->numsides; k++)
- {
- side2 = &brush2->sides[k];
- if (side1->planenum == (side2->planenum^1))
- {
- shared++;
- //there may only be ONE shared side
- if (shared > 1) return NULL;
- break;
- } //end if
- } //end for
- if (k < brush2->numsides) continue;
- //
- for (j = 0; j < brush2->numsides; j++)
- {
- side2 = &brush2->sides[j];
- //don't check the "shared" sides
- for (n = 0; n < brush1->numsides; n++)
- {
- side1 = &brush1->sides[n];
- if (side1->planenum == (side2->planenum^1)) break;
- } //end for
- if (n < brush1->numsides) continue;
- //
- side1 = &brush1->sides[i];
- //if the side is in the same plane
- //*
- if (side1->planenum == side2->planenum)
- {
- if (side1->texinfo != TEXINFO_NODE &&
- side2->texinfo != TEXINFO_NODE &&
- side1->texinfo != side2->texinfo) return NULL;
- continue;
- } //end if
- //
- plane1 = &mapplanes[side1->planenum];
- plane2 = &mapplanes[side2->planenum];
- //
- if (WindingsNonConvex(side1->winding, side2->winding,
- plane1->normal, plane2->normal,
- plane1->dist, plane2->dist))
- {
- return NULL;
- } //end if
- } //end for
- } //end for
- newbrush = AllocBrush(brush1->numsides + brush2->numsides);
- newbrush->original = brush1->original;
- newbrush->numsides = 0;
- //newbrush->side = brush1->side; //brush contents
- //fix texinfos for sides lying in the same plane
- for (i = 0; i < brush1->numsides; i++)
- {
- side1 = &brush1->sides[i];
- //
- for (n = 0; n < brush2->numsides; n++)
- {
- side2 = &brush2->sides[n];
- //if both sides are in the same plane get the texinfo right
- if (side1->planenum == side2->planenum)
- {
- if (side1->texinfo == TEXINFO_NODE) side1->texinfo = side2->texinfo;
- if (side2->texinfo == TEXINFO_NODE) side2->texinfo = side1->texinfo;
- } //end if
- } //end for
- } //end for
- //
- for (i = 0; i < brush1->numsides; i++)
- {
- side1 = &brush1->sides[i];
- //don't add the "shared" sides
- for (n = 0; n < brush2->numsides; n++)
- {
- side2 = &brush2->sides[n];
- if (side1->planenum == (side2->planenum ^ 1)) break;
- } //end for
- if (n < brush2->numsides) continue;
- //
- for (n = 0; n < newbrush->numsides; n++)
- {
- cs = &newbrush->sides[n];
- if (cs->planenum == side1->planenum)
- {
- Log_Print("brush duplicate plane\n");
- break;
- } //end if
- } //end if
- if (n < newbrush->numsides) continue;
- //add this side
- cs = &newbrush->sides[newbrush->numsides];
- newbrush->numsides++;
- *cs = *side1;
- } //end for
- for (j = 0; j < brush2->numsides; j++)
- {
- side2 = &brush2->sides[j];
- for (n = 0; n < brush1->numsides; n++)
- {
- side1 = &brush1->sides[n];
- //if the side is in the same plane
- if (side2->planenum == side1->planenum) break;
- //don't add the "shared" sides
- if (side2->planenum == (side1->planenum ^ 1)) break;
- } //end for
- if (n < brush1->numsides) continue;
- //
- for (n = 0; n < newbrush->numsides; n++)
- {
- cs = &newbrush->sides[n];
- if (cs->planenum == side2->planenum)
- {
- Log_Print("brush duplicate plane\n");
- break;
- } //end if
- } //end if
- if (n < newbrush->numsides) continue;
- //add this side
- cs = &newbrush->sides[newbrush->numsides];
- newbrush->numsides++;
- *cs = *side2;
- } //end for
- BSPBrushWindings(newbrush);
- BoundBrush(newbrush);
- CheckBSPBrush(newbrush);
- return newbrush;
-} //end of the function TryMergeBrushes
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *MergeBrushes(bspbrush_t *brushlist)
-{
- int nummerges, merged;
- bspbrush_t *b1, *b2, *tail, *newbrush, *newbrushlist;
- bspbrush_t *lastb2;
-
- if (!brushlist) return NULL;
-
- qprintf("%5d brushes merged", nummerges = 0);
- do
- {
- for (tail = brushlist; tail; tail = tail->next)
- {
- if (!tail->next) break;
- } //end for
- merged = 0;
- newbrushlist = NULL;
- for (b1 = brushlist; b1; b1 = brushlist)
- {
- lastb2 = b1;
- for (b2 = b1->next; b2; b2 = b2->next)
- {
- //if the brushes don't have the same contents
- if (b1->original->contents != b2->original->contents ||
- b1->original->expansionbbox != b2->original->expansionbbox) newbrush = NULL;
- else newbrush = TryMergeBrushes(b1, b2);
- if (newbrush)
- {
- tail->next = newbrush;
- lastb2->next = b2->next;
- brushlist = brushlist->next;
- FreeBrush(b1);
- FreeBrush(b2);
- for (tail = brushlist; tail; tail = tail->next)
- {
- if (!tail->next) break;
- } //end for
- merged++;
- qprintf("\r%5d", nummerges++);
- break;
- } //end if
- lastb2 = b2;
- } //end for
- //if b1 can't be merged with any of the other brushes
- if (!b2)
- {
- brushlist = brushlist->next;
- //keep b1
- b1->next = newbrushlist;
- newbrushlist = b1;
- } //end else
- } //end for
- brushlist = newbrushlist;
- } while(merged);
- qprintf("\n");
- return newbrushlist;
-} //end of the function MergeBrushes
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void SplitBrush2 (bspbrush_t *brush, int planenum,
- bspbrush_t **front, bspbrush_t **back)
-{
- SplitBrush (brush, planenum, front, back);
-#if 0
- if (*front && (*front)->sides[(*front)->numsides-1].texinfo == -1)
- (*front)->sides[(*front)->numsides-1].texinfo = (*front)->sides[0].texinfo; // not -1
- if (*back && (*back)->sides[(*back)->numsides-1].texinfo == -1)
- (*back)->sides[(*back)->numsides-1].texinfo = (*back)->sides[0].texinfo; // not -1
-#endif
-} //end of the function SplitBrush2
-//===========================================================================
-// Returns a list of brushes that remain after B is subtracted from A.
-// May by empty if A is contained inside B.
-// The originals are undisturbed.
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *SubtractBrush (bspbrush_t *a, bspbrush_t *b)
-{ // a - b = out (list)
- int i;
- bspbrush_t *front, *back;
- bspbrush_t *out, *in;
-
- in = a;
- out = NULL;
- for (i = 0; i < b->numsides && in; i++)
- {
- SplitBrush2(in, b->sides[i].planenum, &front, &back);
- if (in != a) FreeBrush(in);
- if (front)
- { // add to list
- front->next = out;
- out = front;
- } //end if
- in = back;
- } //end for
- if (in)
- {
- FreeBrush (in);
- } //end if
- else
- { // didn't really intersect
- FreeBrushList (out);
- return a;
- } //end else
- return out;
-} //end of the function SubtractBrush
-//===========================================================================
-// Returns a single brush made up by the intersection of the
-// two provided brushes, or NULL if they are disjoint.
-//
-// The originals are undisturbed.
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *IntersectBrush (bspbrush_t *a, bspbrush_t *b)
-{
- int i;
- bspbrush_t *front, *back;
- bspbrush_t *in;
-
- in = a;
- for (i=0 ; i<b->numsides && in ; i++)
- {
- SplitBrush2(in, b->sides[i].planenum, &front, &back);
- if (in != a) FreeBrush(in);
- if (front) FreeBrush(front);
- in = back;
- } //end for
-
- if (in == a) return NULL;
-
- in->next = NULL;
- return in;
-} //end of the function IntersectBrush
-//===========================================================================
-// Returns true if the two brushes definately do not intersect.
-// There will be false negatives for some non-axial combinations.
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean BrushesDisjoint (bspbrush_t *a, bspbrush_t *b)
-{
- int i, j;
-
- // check bounding boxes
- for (i=0 ; i<3 ; i++)
- if (a->mins[i] >= b->maxs[i]
- || a->maxs[i] <= b->mins[i])
- return true; // bounding boxes don't overlap
-
- // check for opposing planes
- for (i=0 ; i<a->numsides ; i++)
- {
- for (j=0 ; j<b->numsides ; j++)
- {
- if (a->sides[i].planenum ==
- (b->sides[j].planenum^1) )
- return true; // opposite planes, so not touching
- }
- }
-
- return false; // might intersect
-} //end of the function BrushesDisjoint
-//===========================================================================
-// Returns a content word for the intersection of two brushes.
-// Some combinations will generate a combination (water + clip),
-// but most will be the stronger of the two contents.
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int IntersectionContents (int c1, int c2)
-{
- int out;
-
- out = c1 | c2;
-
- if (out & CONTENTS_SOLID) out = CONTENTS_SOLID;
-
- return out;
-} //end of the function IntersectionContents
-//===========================================================================
-// Any planes shared with the box edge will be set to no texinfo
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *ClipBrushToBox(bspbrush_t *brush, vec3_t clipmins, vec3_t clipmaxs)
-{
- int i, j;
- bspbrush_t *front, *back;
- int p;
-
- for (j=0 ; j<2 ; j++)
- {
- if (brush->maxs[j] > clipmaxs[j])
- {
- SplitBrush (brush, maxplanenums[j], &front, &back);
- if (front)
- FreeBrush (front);
- brush = back;
- if (!brush)
- return NULL;
- }
- if (brush->mins[j] < clipmins[j])
- {
- SplitBrush (brush, minplanenums[j], &front, &back);
- if (back)
- FreeBrush (back);
- brush = front;
- if (!brush)
- return NULL;
- }
- }
-
- // remove any colinear faces
-
- for (i=0 ; i<brush->numsides ; i++)
- {
- p = brush->sides[i].planenum & ~1;
- if (p == maxplanenums[0] || p == maxplanenums[1]
- || p == minplanenums[0] || p == minplanenums[1])
- {
- brush->sides[i].texinfo = TEXINFO_NODE;
- brush->sides[i].flags &= ~SFL_VISIBLE;
- }
- }
- return brush;
-} //end of the function ClipBrushToBox
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *MakeBspBrushList(int startbrush, int endbrush,
- vec3_t clipmins, vec3_t clipmaxs)
-{
- mapbrush_t *mb;
- bspbrush_t *brushlist, *newbrush;
- int i, j;
- int c_faces;
- int c_brushes;
- int numsides;
- int vis;
- vec3_t normal;
- float dist;
-
- for (i=0 ; i<2 ; i++)
- {
- VectorClear (normal);
- normal[i] = 1;
- dist = clipmaxs[i];
- maxplanenums[i] = FindFloatPlane(normal, dist);
- dist = clipmins[i];
- minplanenums[i] = FindFloatPlane(normal, dist);
- }
-
- brushlist = NULL;
- c_faces = 0;
- c_brushes = 0;
-
- for (i=startbrush ; i<endbrush ; i++)
- {
- mb = &mapbrushes[i];
-
- numsides = mb->numsides;
- if (!numsides)
- continue;
-
- // make sure the brush has at least one face showing
- vis = 0;
- for (j=0 ; j<numsides ; j++)
- if ((mb->original_sides[j].flags & SFL_VISIBLE) && mb->original_sides[j].winding)
- vis++;
-#if 0
- if (!vis)
- continue; // no faces at all
-#endif
- // if the brush is outside the clip area, skip it
- for (j=0 ; j<3 ; j++)
- if (mb->mins[j] >= clipmaxs[j]
- || mb->maxs[j] <= clipmins[j])
- break;
- if (j != 3)
- continue;
-
- //
- // make a copy of the brush
- //
- newbrush = AllocBrush (mb->numsides);
- newbrush->original = mb;
- newbrush->numsides = mb->numsides;
- memcpy (newbrush->sides, mb->original_sides, numsides*sizeof(side_t));
- for (j=0 ; j<numsides ; j++)
- {
- if (newbrush->sides[j].winding)
- newbrush->sides[j].winding = CopyWinding (newbrush->sides[j].winding);
- if (newbrush->sides[j].surf & SURF_HINT)
- newbrush->sides[j].flags |= SFL_VISIBLE; // hints are always visible
- }
- VectorCopy (mb->mins, newbrush->mins);
- VectorCopy (mb->maxs, newbrush->maxs);
-
- //
- // carve off anything outside the clip box
- //
- newbrush = ClipBrushToBox (newbrush, clipmins, clipmaxs);
- if (!newbrush)
- continue;
-
- c_faces += vis;
- c_brushes++;
-
- newbrush->next = brushlist;
- brushlist = newbrush;
- }
-
- return brushlist;
-} //end of the function MakeBspBrushList
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *AddBrushListToTail (bspbrush_t *list, bspbrush_t *tail)
-{
- bspbrush_t *walk, *next;
-
- for (walk=list ; walk ; walk=next)
- { // add to end of list
- next = walk->next;
- walk->next = NULL;
- tail->next = walk;
- tail = walk;
- } //end for
- return tail;
-} //end of the function AddBrushListToTail
-//===========================================================================
-// Builds a new list that doesn't hold the given brush
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *CullList(bspbrush_t *list, bspbrush_t *skip1)
-{
- bspbrush_t *newlist;
- bspbrush_t *next;
-
- newlist = NULL;
-
- for ( ; list ; list = next)
- {
- next = list->next;
- if (list == skip1)
- {
- FreeBrush (list);
- continue;
- }
- list->next = newlist;
- newlist = list;
- }
- return newlist;
-} //end of the function CullList
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-/*
-void WriteBrushMap(char *name, bspbrush_t *list)
-{
- FILE *f;
- side_t *s;
- int i;
- winding_t *w;
-
- Log_Print("writing %s\n", name);
- f = fopen (name, "wb");
- if (!f)
- Error ("Can't write %s\b", name);
-
- fprintf (f, "{\n\"classname\" \"worldspawn\"\n");
-
- for ( ; list ; list=list->next )
- {
- fprintf (f, "{\n");
- for (i=0,s=list->sides ; i<list->numsides ; i++,s++)
- {
- w = BaseWindingForPlane (mapplanes[s->planenum].normal, mapplanes[s->planenum].dist);
-
- fprintf (f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]);
- fprintf (f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]);
- fprintf (f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]);
-
- fprintf (f, "%s 0 0 0 1 1\n", texinfo[s->texinfo].texture);
- FreeWinding (w);
- }
- fprintf (f, "}\n");
- }
- fprintf (f, "}\n");
-
- fclose (f);
-} //end of the function WriteBrushMap
-*/
-//===========================================================================
-// Returns true if b1 is allowed to bite b2
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean BrushGE (bspbrush_t *b1, bspbrush_t *b2)
-{
-#ifdef ME
- if (create_aas)
- {
- if (b1->original->expansionbbox != b2->original->expansionbbox)
- {
- return false;
- } //end if
- //never have something else bite a ladder brush
- //never have a ladder brush bite something else
- if ( (b1->original->contents & CONTENTS_LADDER)
- && !(b2->original->contents & CONTENTS_LADDER))
- {
- return false;
- } //end if
- } //end if
-#endif //ME
- // detail brushes never bite structural brushes
- if ( (b1->original->contents & CONTENTS_DETAIL)
- && !(b2->original->contents & CONTENTS_DETAIL) )
- {
- return false;
- } //end if
- if (b1->original->contents & CONTENTS_SOLID)
- {
- return true;
- } //end if
- return false;
-} //end of the function BrushGE
-//===========================================================================
-// Carves any intersecting solid brushes into the minimum number
-// of non-intersecting brushes.
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *ChopBrushes (bspbrush_t *head)
-{
- bspbrush_t *b1, *b2, *next;
- bspbrush_t *tail;
- bspbrush_t *keep;
- bspbrush_t *sub, *sub2;
- int c1, c2;
- int num_csg_iterations;
-
- Log_Print("-------- Brush CSG ---------\n");
- Log_Print("%6d original brushes\n", CountBrushList (head));
-
- num_csg_iterations = 0;
- qprintf("%6d output brushes", num_csg_iterations);
-
-#if 0
- if (startbrush == 0)
- WriteBrushList ("before.gl", head, false);
-#endif
- keep = NULL;
-
-newlist:
- // find tail
- if (!head) return NULL;
-
- for (tail = head; tail->next; tail = tail->next)
- ;
-
- for (b1=head ; b1 ; b1=next)
- {
- next = b1->next;
-
- //if the conversion is cancelled
- if (cancelconversion)
- {
- b1->next = keep;
- keep = b1;
- continue;
- } //end if
-
- for (b2 = b1->next; b2; b2 = b2->next)
- {
- if (BrushesDisjoint (b1, b2))
- continue;
-
- sub = NULL;
- sub2 = NULL;
- c1 = 999999;
- c2 = 999999;
-
- if (BrushGE (b2, b1))
- {
- sub = SubtractBrush (b1, b2);
- if (sub == b1)
- {
- continue; // didn't really intersect
- } //end if
- if (!sub)
- { // b1 is swallowed by b2
- head = CullList (b1, b1);
- goto newlist;
- }
- c1 = CountBrushList (sub);
- }
-
- if ( BrushGE (b1, b2) )
- {
- sub2 = SubtractBrush (b2, b1);
- if (sub2 == b2)
- continue; // didn't really intersect
- if (!sub2)
- { // b2 is swallowed by b1
- FreeBrushList (sub);
- head = CullList (b1, b2);
- goto newlist;
- }
- c2 = CountBrushList (sub2);
- }
-
- if (!sub && !sub2)
- continue; // neither one can bite
-
- // only accept if it didn't fragment
- // (commenting this out allows full fragmentation)
- if (c1 > 1 && c2 > 1)
- {
- if (sub2)
- FreeBrushList (sub2);
- if (sub)
- FreeBrushList (sub);
- continue;
- }
-
- if (c1 < c2)
- {
- if (sub2) FreeBrushList (sub2);
- tail = AddBrushListToTail (sub, tail);
- head = CullList (b1, b1);
- goto newlist;
- } //end if
- else
- {
- if (sub) FreeBrushList (sub);
- tail = AddBrushListToTail (sub2, tail);
- head = CullList (b1, b2);
- goto newlist;
- } //end else
- } //end for
-
- if (!b2)
- { // b1 is no longer intersecting anything, so keep it
- b1->next = keep;
- keep = b1;
- } //end if
- num_csg_iterations++;
- qprintf("\r%6d", num_csg_iterations);
- } //end for
-
- if (cancelconversion) return keep;
- //
- qprintf("\n");
- Log_Write("%6d output brushes\r\n", num_csg_iterations);
-
-#if 0
- {
- WriteBrushList ("after.gl", keep, false);
- WriteBrushMap ("after.map", keep);
- }
-#endif
-
- return keep;
-} //end of the function ChopBrushes
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *InitialBrushList (bspbrush_t *list)
-{
- bspbrush_t *b;
- bspbrush_t *out, *newb;
- int i;
-
- // only return brushes that have visible faces
- out = NULL;
- for (b=list ; b ; b=b->next)
- {
-#if 0
- for (i=0 ; i<b->numsides ; i++)
- if (b->sides[i].flags & SFL_VISIBLE)
- break;
- if (i == b->numsides)
- continue;
-#endif
- newb = CopyBrush (b);
- newb->next = out;
- out = newb;
-
- // clear visible, so it must be set by MarkVisibleFaces_r
- // to be used in the optimized list
- for (i=0 ; i<b->numsides ; i++)
- {
- newb->sides[i].original = &b->sides[i];
-// newb->sides[i].visible = true;
- b->sides[i].flags &= ~SFL_VISIBLE;
- }
- }
-
- return out;
-} //end of the function InitialBrushList
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *OptimizedBrushList (bspbrush_t *list)
-{
- bspbrush_t *b;
- bspbrush_t *out, *newb;
- int i;
-
- // only return brushes that have visible faces
- out = NULL;
- for (b=list ; b ; b=b->next)
- {
- for (i=0 ; i<b->numsides ; i++)
- if (b->sides[i].flags & SFL_VISIBLE)
- break;
- if (i == b->numsides)
- continue;
- newb = CopyBrush (b);
- newb->next = out;
- out = newb;
- } //end for
-
-// WriteBrushList ("vis.gl", out, true);
- return out;
-} //end of the function OptimizeBrushList
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-tree_t *ProcessWorldBrushes(int brush_start, int brush_end)
-{
- bspbrush_t *brushes;
- tree_t *tree;
- node_t *node;
- vec3_t mins, maxs;
-
- //take the whole world
- mins[0] = map_mins[0] - 8;
- mins[1] = map_mins[1] - 8;
- mins[2] = map_mins[2] - 8;
-
- maxs[0] = map_maxs[0] + 8;
- maxs[1] = map_maxs[1] + 8;
- maxs[2] = map_maxs[2] + 8;
-
- //reset the brush bsp
- ResetBrushBSP();
-
- // the makelist and chopbrushes could be cached between the passes...
-
- //create a list with brushes that are within the given mins/maxs
- //some brushes will be cut and only the part that falls within the
- //mins/maxs will be in the bush list
- brushes = MakeBspBrushList(brush_start, brush_end, mins, maxs);
- //
-
- if (!brushes)
- {
- node = AllocNode ();
- node->planenum = PLANENUM_LEAF;
- node->contents = CONTENTS_SOLID;
-
- tree = Tree_Alloc();
- tree->headnode = node;
- VectorCopy(mins, tree->mins);
- VectorCopy(maxs, tree->maxs);
- } //end if
- else
- {
- //Carves any intersecting solid brushes into the minimum number
- //of non-intersecting brushes.
- if (!nocsg)
- {
- brushes = ChopBrushes(brushes);
- /*
- if (create_aas)
- {
- brushes = MergeBrushes(brushes);
- } //end if*/
- } //end if
- //if the conversion is cancelled
- if (cancelconversion)
- {
- FreeBrushList(brushes);
- return NULL;
- } //end if
- //create the actual bsp tree
- tree = BrushBSP(brushes, mins, maxs);
- } //end else
- //return the tree
- return tree;
-} //end of the function ProcessWorldBrushes
+/*
+===========================================================================
+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"
+
+/*
+
+tag all brushes with original contents
+brushes may contain multiple contents
+there will be no brush overlap after csg phase
+
+*/
+
+int minplanenums[3];
+int maxplanenums[3];
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void CheckBSPBrush(bspbrush_t *brush)
+{
+ int i, j;
+ plane_t *plane1, *plane2;
+
+ //check if the brush is convex... flipped planes make a brush non-convex
+ for (i = 0; i < brush->numsides; i++)
+ {
+ for (j = 0; j < brush->numsides; j++)
+ {
+ if (i == j) continue;
+ plane1 = &mapplanes[brush->sides[i].planenum];
+ plane2 = &mapplanes[brush->sides[j].planenum];
+ //
+ if (WindingsNonConvex(brush->sides[i].winding,
+ brush->sides[j].winding,
+ plane1->normal, plane2->normal,
+ plane1->dist, plane2->dist))
+ {
+ Log_Print("non convex brush");
+ break;
+ } //end if
+ } //end for
+ } //end for
+ BoundBrush(brush);
+ //check for out of bound brushes
+ for (i = 0; i < 3; i++)
+ {
+ if (brush->mins[i] < -MAX_MAP_BOUNDS || brush->maxs[i] > MAX_MAP_BOUNDS)
+ {
+ Log_Print("brush: bounds out of range\n");
+ Log_Print("ob->mins[%d] = %f, ob->maxs[%d] = %f\n", i, brush->mins[i], i, brush->maxs[i]);
+ break;
+ } //end if
+ if (brush->mins[i] > MAX_MAP_BOUNDS || brush->maxs[i] < -MAX_MAP_BOUNDS)
+ {
+ Log_Print("brush: no visible sides on brush\n");
+ Log_Print("ob->mins[%d] = %f, ob->maxs[%d] = %f\n", i, brush->mins[i], i, brush->maxs[i]);
+ break;
+ } //end if
+ } //end for
+} //end of the function CheckBSPBrush
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void BSPBrushWindings(bspbrush_t *brush)
+{
+ int i, j;
+ winding_t *w;
+ plane_t *plane;
+
+ for (i = 0; i < brush->numsides; i++)
+ {
+ plane = &mapplanes[brush->sides[i].planenum];
+ w = BaseWindingForPlane(plane->normal, plane->dist);
+ for (j = 0; j < brush->numsides && w; j++)
+ {
+ if (i == j) continue;
+ plane = &mapplanes[brush->sides[j].planenum^1];
+ ChopWindingInPlace(&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
+ } //end for
+ brush->sides[i].winding = w;
+ } //end for
+} //end of the function BSPBrushWindings
+//===========================================================================
+// NOTE: can't keep brush->original intact
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *TryMergeBrushes(bspbrush_t *brush1, bspbrush_t *brush2)
+{
+ int i, j, k, n, shared;
+ side_t *side1, *side2, *cs;
+ plane_t *plane1, *plane2;
+ bspbrush_t *newbrush;
+
+ //check for bounding box overlapp
+ for (i = 0; i < 3; i++)
+ {
+ if (brush1->mins[i] > brush2->maxs[i] + 2
+ || brush1->maxs[i] < brush2->mins[i] - 2)
+ {
+ return NULL;
+ } //end if
+ } //end for
+ //
+ shared = 0;
+ //check if the brush is convex... flipped planes make a brush non-convex
+ for (i = 0; i < brush1->numsides; i++)
+ {
+ side1 = &brush1->sides[i];
+ //don't check the "shared" sides
+ for (k = 0; k < brush2->numsides; k++)
+ {
+ side2 = &brush2->sides[k];
+ if (side1->planenum == (side2->planenum^1))
+ {
+ shared++;
+ //there may only be ONE shared side
+ if (shared > 1) return NULL;
+ break;
+ } //end if
+ } //end for
+ if (k < brush2->numsides) continue;
+ //
+ for (j = 0; j < brush2->numsides; j++)
+ {
+ side2 = &brush2->sides[j];
+ //don't check the "shared" sides
+ for (n = 0; n < brush1->numsides; n++)
+ {
+ side1 = &brush1->sides[n];
+ if (side1->planenum == (side2->planenum^1)) break;
+ } //end for
+ if (n < brush1->numsides) continue;
+ //
+ side1 = &brush1->sides[i];
+ //if the side is in the same plane
+ //*
+ if (side1->planenum == side2->planenum)
+ {
+ if (side1->texinfo != TEXINFO_NODE &&
+ side2->texinfo != TEXINFO_NODE &&
+ side1->texinfo != side2->texinfo) return NULL;
+ continue;
+ } //end if
+ //
+ plane1 = &mapplanes[side1->planenum];
+ plane2 = &mapplanes[side2->planenum];
+ //
+ if (WindingsNonConvex(side1->winding, side2->winding,
+ plane1->normal, plane2->normal,
+ plane1->dist, plane2->dist))
+ {
+ return NULL;
+ } //end if
+ } //end for
+ } //end for
+ newbrush = AllocBrush(brush1->numsides + brush2->numsides);
+ newbrush->original = brush1->original;
+ newbrush->numsides = 0;
+ //newbrush->side = brush1->side; //brush contents
+ //fix texinfos for sides lying in the same plane
+ for (i = 0; i < brush1->numsides; i++)
+ {
+ side1 = &brush1->sides[i];
+ //
+ for (n = 0; n < brush2->numsides; n++)
+ {
+ side2 = &brush2->sides[n];
+ //if both sides are in the same plane get the texinfo right
+ if (side1->planenum == side2->planenum)
+ {
+ if (side1->texinfo == TEXINFO_NODE) side1->texinfo = side2->texinfo;
+ if (side2->texinfo == TEXINFO_NODE) side2->texinfo = side1->texinfo;
+ } //end if
+ } //end for
+ } //end for
+ //
+ for (i = 0; i < brush1->numsides; i++)
+ {
+ side1 = &brush1->sides[i];
+ //don't add the "shared" sides
+ for (n = 0; n < brush2->numsides; n++)
+ {
+ side2 = &brush2->sides[n];
+ if (side1->planenum == (side2->planenum ^ 1)) break;
+ } //end for
+ if (n < brush2->numsides) continue;
+ //
+ for (n = 0; n < newbrush->numsides; n++)
+ {
+ cs = &newbrush->sides[n];
+ if (cs->planenum == side1->planenum)
+ {
+ Log_Print("brush duplicate plane\n");
+ break;
+ } //end if
+ } //end if
+ if (n < newbrush->numsides) continue;
+ //add this side
+ cs = &newbrush->sides[newbrush->numsides];
+ newbrush->numsides++;
+ *cs = *side1;
+ } //end for
+ for (j = 0; j < brush2->numsides; j++)
+ {
+ side2 = &brush2->sides[j];
+ for (n = 0; n < brush1->numsides; n++)
+ {
+ side1 = &brush1->sides[n];
+ //if the side is in the same plane
+ if (side2->planenum == side1->planenum) break;
+ //don't add the "shared" sides
+ if (side2->planenum == (side1->planenum ^ 1)) break;
+ } //end for
+ if (n < brush1->numsides) continue;
+ //
+ for (n = 0; n < newbrush->numsides; n++)
+ {
+ cs = &newbrush->sides[n];
+ if (cs->planenum == side2->planenum)
+ {
+ Log_Print("brush duplicate plane\n");
+ break;
+ } //end if
+ } //end if
+ if (n < newbrush->numsides) continue;
+ //add this side
+ cs = &newbrush->sides[newbrush->numsides];
+ newbrush->numsides++;
+ *cs = *side2;
+ } //end for
+ BSPBrushWindings(newbrush);
+ BoundBrush(newbrush);
+ CheckBSPBrush(newbrush);
+ return newbrush;
+} //end of the function TryMergeBrushes
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *MergeBrushes(bspbrush_t *brushlist)
+{
+ int nummerges, merged;
+ bspbrush_t *b1, *b2, *tail, *newbrush, *newbrushlist;
+ bspbrush_t *lastb2;
+
+ if (!brushlist) return NULL;
+
+ qprintf("%5d brushes merged", nummerges = 0);
+ do
+ {
+ for (tail = brushlist; tail; tail = tail->next)
+ {
+ if (!tail->next) break;
+ } //end for
+ merged = 0;
+ newbrushlist = NULL;
+ for (b1 = brushlist; b1; b1 = brushlist)
+ {
+ lastb2 = b1;
+ for (b2 = b1->next; b2; b2 = b2->next)
+ {
+ //if the brushes don't have the same contents
+ if (b1->original->contents != b2->original->contents ||
+ b1->original->expansionbbox != b2->original->expansionbbox) newbrush = NULL;
+ else newbrush = TryMergeBrushes(b1, b2);
+ if (newbrush)
+ {
+ tail->next = newbrush;
+ lastb2->next = b2->next;
+ brushlist = brushlist->next;
+ FreeBrush(b1);
+ FreeBrush(b2);
+ for (tail = brushlist; tail; tail = tail->next)
+ {
+ if (!tail->next) break;
+ } //end for
+ merged++;
+ qprintf("\r%5d", nummerges++);
+ break;
+ } //end if
+ lastb2 = b2;
+ } //end for
+ //if b1 can't be merged with any of the other brushes
+ if (!b2)
+ {
+ brushlist = brushlist->next;
+ //keep b1
+ b1->next = newbrushlist;
+ newbrushlist = b1;
+ } //end else
+ } //end for
+ brushlist = newbrushlist;
+ } while(merged);
+ qprintf("\n");
+ return newbrushlist;
+} //end of the function MergeBrushes
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void SplitBrush2 (bspbrush_t *brush, int planenum,
+ bspbrush_t **front, bspbrush_t **back)
+{
+ SplitBrush (brush, planenum, front, back);
+#if 0
+ if (*front && (*front)->sides[(*front)->numsides-1].texinfo == -1)
+ (*front)->sides[(*front)->numsides-1].texinfo = (*front)->sides[0].texinfo; // not -1
+ if (*back && (*back)->sides[(*back)->numsides-1].texinfo == -1)
+ (*back)->sides[(*back)->numsides-1].texinfo = (*back)->sides[0].texinfo; // not -1
+#endif
+} //end of the function SplitBrush2
+//===========================================================================
+// Returns a list of brushes that remain after B is subtracted from A.
+// May by empty if A is contained inside B.
+// The originals are undisturbed.
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *SubtractBrush (bspbrush_t *a, bspbrush_t *b)
+{ // a - b = out (list)
+ int i;
+ bspbrush_t *front, *back;
+ bspbrush_t *out, *in;
+
+ in = a;
+ out = NULL;
+ for (i = 0; i < b->numsides && in; i++)
+ {
+ SplitBrush2(in, b->sides[i].planenum, &front, &back);
+ if (in != a) FreeBrush(in);
+ if (front)
+ { // add to list
+ front->next = out;
+ out = front;
+ } //end if
+ in = back;
+ } //end for
+ if (in)
+ {
+ FreeBrush (in);
+ } //end if
+ else
+ { // didn't really intersect
+ FreeBrushList (out);
+ return a;
+ } //end else
+ return out;
+} //end of the function SubtractBrush
+//===========================================================================
+// Returns a single brush made up by the intersection of the
+// two provided brushes, or NULL if they are disjoint.
+//
+// The originals are undisturbed.
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *IntersectBrush (bspbrush_t *a, bspbrush_t *b)
+{
+ int i;
+ bspbrush_t *front, *back;
+ bspbrush_t *in;
+
+ in = a;
+ for (i=0 ; i<b->numsides && in ; i++)
+ {
+ SplitBrush2(in, b->sides[i].planenum, &front, &back);
+ if (in != a) FreeBrush(in);
+ if (front) FreeBrush(front);
+ in = back;
+ } //end for
+
+ if (in == a) return NULL;
+
+ in->next = NULL;
+ return in;
+} //end of the function IntersectBrush
+//===========================================================================
+// Returns true if the two brushes definately do not intersect.
+// There will be false negatives for some non-axial combinations.
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+qboolean BrushesDisjoint (bspbrush_t *a, bspbrush_t *b)
+{
+ int i, j;
+
+ // check bounding boxes
+ for (i=0 ; i<3 ; i++)
+ if (a->mins[i] >= b->maxs[i]
+ || a->maxs[i] <= b->mins[i])
+ return true; // bounding boxes don't overlap
+
+ // check for opposing planes
+ for (i=0 ; i<a->numsides ; i++)
+ {
+ for (j=0 ; j<b->numsides ; j++)
+ {
+ if (a->sides[i].planenum ==
+ (b->sides[j].planenum^1) )
+ return true; // opposite planes, so not touching
+ }
+ }
+
+ return false; // might intersect
+} //end of the function BrushesDisjoint
+//===========================================================================
+// Returns a content word for the intersection of two brushes.
+// Some combinations will generate a combination (water + clip),
+// but most will be the stronger of the two contents.
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int IntersectionContents (int c1, int c2)
+{
+ int out;
+
+ out = c1 | c2;
+
+ if (out & CONTENTS_SOLID) out = CONTENTS_SOLID;
+
+ return out;
+} //end of the function IntersectionContents
+//===========================================================================
+// Any planes shared with the box edge will be set to no texinfo
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *ClipBrushToBox(bspbrush_t *brush, vec3_t clipmins, vec3_t clipmaxs)
+{
+ int i, j;
+ bspbrush_t *front, *back;
+ int p;
+
+ for (j=0 ; j<2 ; j++)
+ {
+ if (brush->maxs[j] > clipmaxs[j])
+ {
+ SplitBrush (brush, maxplanenums[j], &front, &back);
+ if (front)
+ FreeBrush (front);
+ brush = back;
+ if (!brush)
+ return NULL;
+ }
+ if (brush->mins[j] < clipmins[j])
+ {
+ SplitBrush (brush, minplanenums[j], &front, &back);
+ if (back)
+ FreeBrush (back);
+ brush = front;
+ if (!brush)
+ return NULL;
+ }
+ }
+
+ // remove any colinear faces
+
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ p = brush->sides[i].planenum & ~1;
+ if (p == maxplanenums[0] || p == maxplanenums[1]
+ || p == minplanenums[0] || p == minplanenums[1])
+ {
+ brush->sides[i].texinfo = TEXINFO_NODE;
+ brush->sides[i].flags &= ~SFL_VISIBLE;
+ }
+ }
+ return brush;
+} //end of the function ClipBrushToBox
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *MakeBspBrushList(int startbrush, int endbrush,
+ vec3_t clipmins, vec3_t clipmaxs)
+{
+ mapbrush_t *mb;
+ bspbrush_t *brushlist, *newbrush;
+ int i, j;
+ int c_faces;
+ int c_brushes;
+ int numsides;
+ int vis;
+ vec3_t normal;
+ float dist;
+
+ for (i=0 ; i<2 ; i++)
+ {
+ VectorClear (normal);
+ normal[i] = 1;
+ dist = clipmaxs[i];
+ maxplanenums[i] = FindFloatPlane(normal, dist);
+ dist = clipmins[i];
+ minplanenums[i] = FindFloatPlane(normal, dist);
+ }
+
+ brushlist = NULL;
+ c_faces = 0;
+ c_brushes = 0;
+
+ for (i=startbrush ; i<endbrush ; i++)
+ {
+ mb = &mapbrushes[i];
+
+ numsides = mb->numsides;
+ if (!numsides)
+ continue;
+
+ // make sure the brush has at least one face showing
+ vis = 0;
+ for (j=0 ; j<numsides ; j++)
+ if ((mb->original_sides[j].flags & SFL_VISIBLE) && mb->original_sides[j].winding)
+ vis++;
+#if 0
+ if (!vis)
+ continue; // no faces at all
+#endif
+ // if the brush is outside the clip area, skip it
+ for (j=0 ; j<3 ; j++)
+ if (mb->mins[j] >= clipmaxs[j]
+ || mb->maxs[j] <= clipmins[j])
+ break;
+ if (j != 3)
+ continue;
+
+ //
+ // make a copy of the brush
+ //
+ newbrush = AllocBrush (mb->numsides);
+ newbrush->original = mb;
+ newbrush->numsides = mb->numsides;
+ memcpy (newbrush->sides, mb->original_sides, numsides*sizeof(side_t));
+ for (j=0 ; j<numsides ; j++)
+ {
+ if (newbrush->sides[j].winding)
+ newbrush->sides[j].winding = CopyWinding (newbrush->sides[j].winding);
+ if (newbrush->sides[j].surf & SURF_HINT)
+ newbrush->sides[j].flags |= SFL_VISIBLE; // hints are always visible
+ }
+ VectorCopy (mb->mins, newbrush->mins);
+ VectorCopy (mb->maxs, newbrush->maxs);
+
+ //
+ // carve off anything outside the clip box
+ //
+ newbrush = ClipBrushToBox (newbrush, clipmins, clipmaxs);
+ if (!newbrush)
+ continue;
+
+ c_faces += vis;
+ c_brushes++;
+
+ newbrush->next = brushlist;
+ brushlist = newbrush;
+ }
+
+ return brushlist;
+} //end of the function MakeBspBrushList
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *AddBrushListToTail (bspbrush_t *list, bspbrush_t *tail)
+{
+ bspbrush_t *walk, *next;
+
+ for (walk=list ; walk ; walk=next)
+ { // add to end of list
+ next = walk->next;
+ walk->next = NULL;
+ tail->next = walk;
+ tail = walk;
+ } //end for
+ return tail;
+} //end of the function AddBrushListToTail
+//===========================================================================
+// Builds a new list that doesn't hold the given brush
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *CullList(bspbrush_t *list, bspbrush_t *skip1)
+{
+ bspbrush_t *newlist;
+ bspbrush_t *next;
+
+ newlist = NULL;
+
+ for ( ; list ; list = next)
+ {
+ next = list->next;
+ if (list == skip1)
+ {
+ FreeBrush (list);
+ continue;
+ }
+ list->next = newlist;
+ newlist = list;
+ }
+ return newlist;
+} //end of the function CullList
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+/*
+void WriteBrushMap(char *name, bspbrush_t *list)
+{
+ FILE *f;
+ side_t *s;
+ int i;
+ winding_t *w;
+
+ Log_Print("writing %s\n", name);
+ f = fopen (name, "wb");
+ if (!f)
+ Error ("Can't write %s\b", name);
+
+ fprintf (f, "{\n\"classname\" \"worldspawn\"\n");
+
+ for ( ; list ; list=list->next )
+ {
+ fprintf (f, "{\n");
+ for (i=0,s=list->sides ; i<list->numsides ; i++,s++)
+ {
+ w = BaseWindingForPlane (mapplanes[s->planenum].normal, mapplanes[s->planenum].dist);
+
+ fprintf (f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]);
+ fprintf (f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]);
+ fprintf (f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]);
+
+ fprintf (f, "%s 0 0 0 1 1\n", texinfo[s->texinfo].texture);
+ FreeWinding (w);
+ }
+ fprintf (f, "}\n");
+ }
+ fprintf (f, "}\n");
+
+ fclose (f);
+} //end of the function WriteBrushMap
+*/
+//===========================================================================
+// Returns true if b1 is allowed to bite b2
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+qboolean BrushGE (bspbrush_t *b1, bspbrush_t *b2)
+{
+#ifdef ME
+ if (create_aas)
+ {
+ if (b1->original->expansionbbox != b2->original->expansionbbox)
+ {
+ return false;
+ } //end if
+ //never have something else bite a ladder brush
+ //never have a ladder brush bite something else
+ if ( (b1->original->contents & CONTENTS_LADDER)
+ && !(b2->original->contents & CONTENTS_LADDER))
+ {
+ return false;
+ } //end if
+ } //end if
+#endif //ME
+ // detail brushes never bite structural brushes
+ if ( (b1->original->contents & CONTENTS_DETAIL)
+ && !(b2->original->contents & CONTENTS_DETAIL) )
+ {
+ return false;
+ } //end if
+ if (b1->original->contents & CONTENTS_SOLID)
+ {
+ return true;
+ } //end if
+ return false;
+} //end of the function BrushGE
+//===========================================================================
+// Carves any intersecting solid brushes into the minimum number
+// of non-intersecting brushes.
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *ChopBrushes (bspbrush_t *head)
+{
+ bspbrush_t *b1, *b2, *next;
+ bspbrush_t *tail;
+ bspbrush_t *keep;
+ bspbrush_t *sub, *sub2;
+ int c1, c2;
+ int num_csg_iterations;
+
+ Log_Print("-------- Brush CSG ---------\n");
+ Log_Print("%6d original brushes\n", CountBrushList (head));
+
+ num_csg_iterations = 0;
+ qprintf("%6d output brushes", num_csg_iterations);
+
+#if 0
+ if (startbrush == 0)
+ WriteBrushList ("before.gl", head, false);
+#endif
+ keep = NULL;
+
+newlist:
+ // find tail
+ if (!head) return NULL;
+
+ for (tail = head; tail->next; tail = tail->next)
+ ;
+
+ for (b1=head ; b1 ; b1=next)
+ {
+ next = b1->next;
+
+ //if the conversion is cancelled
+ if (cancelconversion)
+ {
+ b1->next = keep;
+ keep = b1;
+ continue;
+ } //end if
+
+ for (b2 = b1->next; b2; b2 = b2->next)
+ {
+ if (BrushesDisjoint (b1, b2))
+ continue;
+
+ sub = NULL;
+ sub2 = NULL;
+ c1 = 999999;
+ c2 = 999999;
+
+ if (BrushGE (b2, b1))
+ {
+ sub = SubtractBrush (b1, b2);
+ if (sub == b1)
+ {
+ continue; // didn't really intersect
+ } //end if
+ if (!sub)
+ { // b1 is swallowed by b2
+ head = CullList (b1, b1);
+ goto newlist;
+ }
+ c1 = CountBrushList (sub);
+ }
+
+ if ( BrushGE (b1, b2) )
+ {
+ sub2 = SubtractBrush (b2, b1);
+ if (sub2 == b2)
+ continue; // didn't really intersect
+ if (!sub2)
+ { // b2 is swallowed by b1
+ FreeBrushList (sub);
+ head = CullList (b1, b2);
+ goto newlist;
+ }
+ c2 = CountBrushList (sub2);
+ }
+
+ if (!sub && !sub2)
+ continue; // neither one can bite
+
+ // only accept if it didn't fragment
+ // (commenting this out allows full fragmentation)
+ if (c1 > 1 && c2 > 1)
+ {
+ if (sub2)
+ FreeBrushList (sub2);
+ if (sub)
+ FreeBrushList (sub);
+ continue;
+ }
+
+ if (c1 < c2)
+ {
+ if (sub2) FreeBrushList (sub2);
+ tail = AddBrushListToTail (sub, tail);
+ head = CullList (b1, b1);
+ goto newlist;
+ } //end if
+ else
+ {
+ if (sub) FreeBrushList (sub);
+ tail = AddBrushListToTail (sub2, tail);
+ head = CullList (b1, b2);
+ goto newlist;
+ } //end else
+ } //end for
+
+ if (!b2)
+ { // b1 is no longer intersecting anything, so keep it
+ b1->next = keep;
+ keep = b1;
+ } //end if
+ num_csg_iterations++;
+ qprintf("\r%6d", num_csg_iterations);
+ } //end for
+
+ if (cancelconversion) return keep;
+ //
+ qprintf("\n");
+ Log_Write("%6d output brushes\r\n", num_csg_iterations);
+
+#if 0
+ {
+ WriteBrushList ("after.gl", keep, false);
+ WriteBrushMap ("after.map", keep);
+ }
+#endif
+
+ return keep;
+} //end of the function ChopBrushes
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *InitialBrushList (bspbrush_t *list)
+{
+ bspbrush_t *b;
+ bspbrush_t *out, *newb;
+ int i;
+
+ // only return brushes that have visible faces
+ out = NULL;
+ for (b=list ; b ; b=b->next)
+ {
+#if 0
+ for (i=0 ; i<b->numsides ; i++)
+ if (b->sides[i].flags & SFL_VISIBLE)
+ break;
+ if (i == b->numsides)
+ continue;
+#endif
+ newb = CopyBrush (b);
+ newb->next = out;
+ out = newb;
+
+ // clear visible, so it must be set by MarkVisibleFaces_r
+ // to be used in the optimized list
+ for (i=0 ; i<b->numsides ; i++)
+ {
+ newb->sides[i].original = &b->sides[i];
+// newb->sides[i].visible = true;
+ b->sides[i].flags &= ~SFL_VISIBLE;
+ }
+ }
+
+ return out;
+} //end of the function InitialBrushList
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *OptimizedBrushList (bspbrush_t *list)
+{
+ bspbrush_t *b;
+ bspbrush_t *out, *newb;
+ int i;
+
+ // only return brushes that have visible faces
+ out = NULL;
+ for (b=list ; b ; b=b->next)
+ {
+ for (i=0 ; i<b->numsides ; i++)
+ if (b->sides[i].flags & SFL_VISIBLE)
+ break;
+ if (i == b->numsides)
+ continue;
+ newb = CopyBrush (b);
+ newb->next = out;
+ out = newb;
+ } //end for
+
+// WriteBrushList ("vis.gl", out, true);
+ return out;
+} //end of the function OptimizeBrushList
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+tree_t *ProcessWorldBrushes(int brush_start, int brush_end)
+{
+ bspbrush_t *brushes;
+ tree_t *tree;
+ node_t *node;
+ vec3_t mins, maxs;
+
+ //take the whole world
+ mins[0] = map_mins[0] - 8;
+ mins[1] = map_mins[1] - 8;
+ mins[2] = map_mins[2] - 8;
+
+ maxs[0] = map_maxs[0] + 8;
+ maxs[1] = map_maxs[1] + 8;
+ maxs[2] = map_maxs[2] + 8;
+
+ //reset the brush bsp
+ ResetBrushBSP();
+
+ // the makelist and chopbrushes could be cached between the passes...
+
+ //create a list with brushes that are within the given mins/maxs
+ //some brushes will be cut and only the part that falls within the
+ //mins/maxs will be in the bush list
+ brushes = MakeBspBrushList(brush_start, brush_end, mins, maxs);
+ //
+
+ if (!brushes)
+ {
+ node = AllocNode ();
+ node->planenum = PLANENUM_LEAF;
+ node->contents = CONTENTS_SOLID;
+
+ tree = Tree_Alloc();
+ tree->headnode = node;
+ VectorCopy(mins, tree->mins);
+ VectorCopy(maxs, tree->maxs);
+ } //end if
+ else
+ {
+ //Carves any intersecting solid brushes into the minimum number
+ //of non-intersecting brushes.
+ if (!nocsg)
+ {
+ brushes = ChopBrushes(brushes);
+ /*
+ if (create_aas)
+ {
+ brushes = MergeBrushes(brushes);
+ } //end if*/
+ } //end if
+ //if the conversion is cancelled
+ if (cancelconversion)
+ {
+ FreeBrushList(brushes);
+ return NULL;
+ } //end if
+ //create the actual bsp tree
+ tree = BrushBSP(brushes, mins, maxs);
+ } //end else
+ //return the tree
+ return tree;
+} //end of the function ProcessWorldBrushes
diff --git a/code/bspc/faces.c b/code/bspc/faces.c
index bcd3ef9..f05f5ae 100755
--- a/code/bspc/faces.c
+++ b/code/bspc/faces.c
@@ -1,978 +1,978 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-// faces.c
-
-#include "qbsp.h"
-#include "l_mem.h"
-
-/*
-
- some faces will be removed before saving, but still form nodes:
-
- the insides of sky volumes
- meeting planes of different water current volumes
-
-*/
-
-// undefine for dumb linear searches
-#define USE_HASHING
-
-#define INTEGRAL_EPSILON 0.01
-#define POINT_EPSILON 0.5
-#define OFF_EPSILON 0.5
-
-int c_merge;
-int c_subdivide;
-
-int c_totalverts;
-int c_uniqueverts;
-int c_degenerate;
-int c_tjunctions;
-int c_faceoverflows;
-int c_facecollapse;
-int c_badstartverts;
-
-#define MAX_SUPERVERTS 512
-int superverts[MAX_SUPERVERTS];
-int numsuperverts;
-
-face_t *edgefaces[MAX_MAP_EDGES][2];
-int firstmodeledge = 1;
-int firstmodelface;
-
-int c_tryedges;
-
-vec3_t edge_dir;
-vec3_t edge_start;
-vec_t edge_len;
-
-int num_edge_verts;
-int edge_verts[MAX_MAP_VERTS];
-
-face_t *NewFaceFromFace (face_t *f);
-
-//===========================================================================
-
-typedef struct hashvert_s
-{
- struct hashvert_s *next;
- int num;
-} hashvert_t;
-
-
-#define HASH_SIZE 64
-
-
-int vertexchain[MAX_MAP_VERTS]; // the next vertex in a hash chain
-int hashverts[HASH_SIZE*HASH_SIZE]; // a vertex number, or 0 for no verts
-
-face_t *edgefaces[MAX_MAP_EDGES][2];
-
-//============================================================================
-
-
-unsigned HashVec (vec3_t vec)
-{
- int x, y;
-
- x = (4096 + (int)(vec[0]+0.5)) >> 7;
- y = (4096 + (int)(vec[1]+0.5)) >> 7;
-
- if ( x < 0 || x >= HASH_SIZE || y < 0 || y >= HASH_SIZE )
- Error ("HashVec: point outside valid range");
-
- return y*HASH_SIZE + x;
-}
-
-#ifdef USE_HASHING
-/*
-=============
-GetVertex
-
-Uses hashing
-=============
-*/
-int GetVertexnum (vec3_t in)
-{
- int h;
- int i;
- float *p;
- vec3_t vert;
- int vnum;
-
- c_totalverts++;
-
- for (i=0 ; i<3 ; i++)
- {
- if ( fabs(in[i] - Q_rint(in[i])) < INTEGRAL_EPSILON)
- vert[i] = Q_rint(in[i]);
- else
- vert[i] = in[i];
- }
-
- h = HashVec (vert);
-
- for (vnum=hashverts[h] ; vnum ; vnum=vertexchain[vnum])
- {
- p = dvertexes[vnum].point;
- if ( fabs(p[0]-vert[0])<POINT_EPSILON
- && fabs(p[1]-vert[1])<POINT_EPSILON
- && fabs(p[2]-vert[2])<POINT_EPSILON )
- return vnum;
- }
-
-// emit a vertex
- if (numvertexes == MAX_MAP_VERTS)
- Error ("numvertexes == MAX_MAP_VERTS");
-
- dvertexes[numvertexes].point[0] = vert[0];
- dvertexes[numvertexes].point[1] = vert[1];
- dvertexes[numvertexes].point[2] = vert[2];
-
- vertexchain[numvertexes] = hashverts[h];
- hashverts[h] = numvertexes;
-
- c_uniqueverts++;
-
- numvertexes++;
-
- return numvertexes-1;
-}
-#else
-/*
-==================
-GetVertexnum
-
-Dumb linear search
-==================
-*/
-int GetVertexnum (vec3_t v)
-{
- int i, j;
- dvertex_t *dv;
- vec_t d;
-
- c_totalverts++;
-
- // make really close values exactly integral
- for (i=0 ; i<3 ; i++)
- {
- if ( fabs(v[i] - (int)(v[i]+0.5)) < INTEGRAL_EPSILON )
- v[i] = (int)(v[i]+0.5);
- if (v[i] < -4096 || v[i] > 4096)
- Error ("GetVertexnum: outside +/- 4096");
- }
-
- // search for an existing vertex match
- for (i=0, dv=dvertexes ; i<numvertexes ; i++, dv++)
- {
- for (j=0 ; j<3 ; j++)
- {
- d = v[j] - dv->point[j];
- if ( d > POINT_EPSILON || d < -POINT_EPSILON)
- break;
- }
- if (j == 3)
- return i; // a match
- }
-
- // new point
- if (numvertexes == MAX_MAP_VERTS)
- Error ("MAX_MAP_VERTS");
- VectorCopy (v, dv->point);
- numvertexes++;
- c_uniqueverts++;
-
- return numvertexes-1;
-}
-#endif
-
-
-/*
-==================
-FaceFromSuperverts
-
-The faces vertexes have been added to the superverts[] array,
-and there may be more there than can be held in a face (MAXEDGES).
-
-If less, the faces vertexnums[] will be filled in, otherwise
-face will reference a tree of split[] faces until all of the
-vertexnums can be added.
-
-superverts[base] will become face->vertexnums[0], and the others
-will be circularly filled in.
-==================
-*/
-void FaceFromSuperverts (node_t *node, face_t *f, int base)
-{
- face_t *newf;
- int remaining;
- int i;
-
- remaining = numsuperverts;
- while (remaining > MAXEDGES)
- { // must split into two faces, because of vertex overload
- c_faceoverflows++;
-
- newf = f->split[0] = NewFaceFromFace (f);
- newf = f->split[0];
- newf->next = node->faces;
- node->faces = newf;
-
- newf->numpoints = MAXEDGES;
- for (i=0 ; i<MAXEDGES ; i++)
- newf->vertexnums[i] = superverts[(i+base)%numsuperverts];
-
- f->split[1] = NewFaceFromFace (f);
- f = f->split[1];
- f->next = node->faces;
- node->faces = f;
-
- remaining -= (MAXEDGES-2);
- base = (base+MAXEDGES-1)%numsuperverts;
- }
-
- // copy the vertexes back to the face
- f->numpoints = remaining;
- for (i=0 ; i<remaining ; i++)
- f->vertexnums[i] = superverts[(i+base)%numsuperverts];
-}
-
-
-/*
-==================
-EmitFaceVertexes
-==================
-*/
-void EmitFaceVertexes (node_t *node, face_t *f)
-{
- winding_t *w;
- int i;
-
- if (f->merged || f->split[0] || f->split[1])
- return;
-
- w = f->w;
- for (i=0 ; i<w->numpoints ; i++)
- {
- if (noweld)
- { // make every point unique
- if (numvertexes == MAX_MAP_VERTS)
- Error ("MAX_MAP_VERTS");
- superverts[i] = numvertexes;
- VectorCopy (w->p[i], dvertexes[numvertexes].point);
- numvertexes++;
- c_uniqueverts++;
- c_totalverts++;
- }
- else
- superverts[i] = GetVertexnum (w->p[i]);
- }
- numsuperverts = w->numpoints;
-
- // this may fragment the face if > MAXEDGES
- FaceFromSuperverts (node, f, 0);
-}
-
-/*
-==================
-EmitVertexes_r
-==================
-*/
-void EmitVertexes_r (node_t *node)
-{
- int i;
- face_t *f;
-
- if (node->planenum == PLANENUM_LEAF)
- return;
-
- for (f=node->faces ; f ; f=f->next)
- {
- EmitFaceVertexes (node, f);
- }
-
- for (i=0 ; i<2 ; i++)
- EmitVertexes_r (node->children[i]);
-}
-
-
-#ifdef USE_HASHING
-/*
-==========
-FindEdgeVerts
-
-Uses the hash tables to cut down to a small number
-==========
-*/
-void FindEdgeVerts (vec3_t v1, vec3_t v2)
-{
- int x1, x2, y1, y2, t;
- int x, y;
- int vnum;
-
-#if 0
-{
- int i;
- num_edge_verts = numvertexes-1;
- for (i=0 ; i<numvertexes-1 ; i++)
- edge_verts[i] = i+1;
-}
-#endif
-
- x1 = (4096 + (int)(v1[0]+0.5)) >> 7;
- y1 = (4096 + (int)(v1[1]+0.5)) >> 7;
- x2 = (4096 + (int)(v2[0]+0.5)) >> 7;
- y2 = (4096 + (int)(v2[1]+0.5)) >> 7;
-
- if (x1 > x2)
- {
- t = x1;
- x1 = x2;
- x2 = t;
- }
- if (y1 > y2)
- {
- t = y1;
- y1 = y2;
- y2 = t;
- }
-#if 0
- x1--;
- x2++;
- y1--;
- y2++;
- if (x1 < 0)
- x1 = 0;
- if (x2 >= HASH_SIZE)
- x2 = HASH_SIZE;
- if (y1 < 0)
- y1 = 0;
- if (y2 >= HASH_SIZE)
- y2 = HASH_SIZE;
-#endif
- num_edge_verts = 0;
- for (x=x1 ; x <= x2 ; x++)
- {
- for (y=y1 ; y <= y2 ; y++)
- {
- for (vnum=hashverts[y*HASH_SIZE+x] ; vnum ; vnum=vertexchain[vnum])
- {
- edge_verts[num_edge_verts++] = vnum;
- }
- }
- }
-}
-
-#else
-/*
-==========
-FindEdgeVerts
-
-Forced a dumb check of everything
-==========
-*/
-void FindEdgeVerts (vec3_t v1, vec3_t v2)
-{
- int i;
-
- num_edge_verts = numvertexes-1;
- for (i=0 ; i<num_edge_verts ; i++)
- edge_verts[i] = i+1;
-}
-#endif
-
-/*
-==========
-TestEdge
-
-Can be recursively reentered
-==========
-*/
-void TestEdge (vec_t start, vec_t end, int p1, int p2, int startvert)
-{
- int j, k;
- vec_t dist;
- vec3_t delta;
- vec3_t exact;
- vec3_t off;
- vec_t error;
- vec3_t p;
-
- if (p1 == p2)
- {
- c_degenerate++;
- return; // degenerate edge
- }
-
- for (k=startvert ; k<num_edge_verts ; k++)
- {
- j = edge_verts[k];
- if (j==p1 || j == p2)
- continue;
-
- VectorCopy (dvertexes[j].point, p);
-
- VectorSubtract (p, edge_start, delta);
- dist = DotProduct (delta, edge_dir);
- if (dist <=start || dist >= end)
- continue; // off an end
- VectorMA (edge_start, dist, edge_dir, exact);
- VectorSubtract (p, exact, off);
- error = VectorLength (off);
-
- if (fabs(error) > OFF_EPSILON)
- continue; // not on the edge
-
- // break the edge
- c_tjunctions++;
- TestEdge (start, dist, p1, j, k+1);
- TestEdge (dist, end, j, p2, k+1);
- return;
- }
-
- // the edge p1 to p2 is now free of tjunctions
- if (numsuperverts >= MAX_SUPERVERTS)
- Error ("MAX_SUPERVERTS");
- superverts[numsuperverts] = p1;
- numsuperverts++;
-}
-
-/*
-==================
-FixFaceEdges
-
-==================
-*/
-void FixFaceEdges (node_t *node, face_t *f)
-{
- int p1, p2;
- int i;
- vec3_t e2;
- vec_t len;
- int count[MAX_SUPERVERTS], start[MAX_SUPERVERTS];
- int base;
-
- if (f->merged || f->split[0] || f->split[1])
- return;
-
- numsuperverts = 0;
-
- for (i=0 ; i<f->numpoints ; i++)
- {
- p1 = f->vertexnums[i];
- p2 = f->vertexnums[(i+1)%f->numpoints];
-
- VectorCopy (dvertexes[p1].point, edge_start);
- VectorCopy (dvertexes[p2].point, e2);
-
- FindEdgeVerts (edge_start, e2);
-
- VectorSubtract (e2, edge_start, edge_dir);
- len = VectorNormalize(edge_dir);
-
- start[i] = numsuperverts;
- TestEdge (0, len, p1, p2, 0);
-
- count[i] = numsuperverts - start[i];
- }
-
- if (numsuperverts < 3)
- { // entire face collapsed
- f->numpoints = 0;
- c_facecollapse++;
- return;
- }
-
- // we want to pick a vertex that doesn't have tjunctions
- // on either side, which can cause artifacts on trifans,
- // especially underwater
- for (i=0 ; i<f->numpoints ; i++)
- {
- if (count[i] == 1 && count[(i+f->numpoints-1)%f->numpoints] == 1)
- break;
- }
- if (i == f->numpoints)
- {
- f->badstartvert = true;
- c_badstartverts++;
- base = 0;
- }
- else
- { // rotate the vertex order
- base = start[i];
- }
-
- // this may fragment the face if > MAXEDGES
- FaceFromSuperverts (node, f, base);
-}
-
-/*
-==================
-FixEdges_r
-==================
-*/
-void FixEdges_r (node_t *node)
-{
- int i;
- face_t *f;
-
- if (node->planenum == PLANENUM_LEAF)
- return;
-
- for (f=node->faces ; f ; f=f->next)
- FixFaceEdges (node, f);
-
- for (i=0 ; i<2 ; i++)
- FixEdges_r (node->children[i]);
-}
-
-/*
-===========
-FixTjuncs
-
-===========
-*/
-void FixTjuncs (node_t *headnode)
-{
- // snap and merge all vertexes
- qprintf ("---- snap verts ----\n");
- memset (hashverts, 0, sizeof(hashverts));
- c_totalverts = 0;
- c_uniqueverts = 0;
- c_faceoverflows = 0;
- EmitVertexes_r (headnode);
- qprintf ("%i unique from %i\n", c_uniqueverts, c_totalverts);
-
- // break edges on tjunctions
- qprintf ("---- tjunc ----\n");
- c_tryedges = 0;
- c_degenerate = 0;
- c_facecollapse = 0;
- c_tjunctions = 0;
- if (!notjunc)
- FixEdges_r (headnode);
- qprintf ("%5i edges degenerated\n", c_degenerate);
- qprintf ("%5i faces degenerated\n", c_facecollapse);
- qprintf ("%5i edges added by tjunctions\n", c_tjunctions);
- qprintf ("%5i faces added by tjunctions\n", c_faceoverflows);
- qprintf ("%5i bad start verts\n", c_badstartverts);
-}
-
-
-//========================================================
-
-int c_faces;
-
-face_t *AllocFace (void)
-{
- face_t *f;
-
- f = GetMemory(sizeof(*f));
- memset (f, 0, sizeof(*f));
- c_faces++;
-
- return f;
-}
-
-face_t *NewFaceFromFace (face_t *f)
-{
- face_t *newf;
-
- newf = AllocFace ();
- *newf = *f;
- newf->merged = NULL;
- newf->split[0] = newf->split[1] = NULL;
- newf->w = NULL;
- return newf;
-}
-
-void FreeFace (face_t *f)
-{
- if (f->w)
- FreeWinding (f->w);
- FreeMemory(f);
- c_faces--;
-}
-
-//========================================================
-
-/*
-==================
-GetEdge
-
-Called by writebsp.
-Don't allow four way edges
-==================
-*/
-int GetEdge2 (int v1, int v2, face_t *f)
-{
- dedge_t *edge;
- int i;
-
- c_tryedges++;
-
- if (!noshare)
- {
- for (i=firstmodeledge ; i < numedges ; i++)
- {
- edge = &dedges[i];
- if (v1 == edge->v[1] && v2 == edge->v[0]
- && edgefaces[i][0]->contents == f->contents)
- {
- if (edgefaces[i][1])
- // printf ("WARNING: multiple backward edge\n");
- continue;
- edgefaces[i][1] = f;
- return -i;
- }
- #if 0
- if (v1 == edge->v[0] && v2 == edge->v[1])
- {
- printf ("WARNING: multiple forward edge\n");
- return i;
- }
- #endif
- }
- }
-
-// emit an edge
- if (numedges >= MAX_MAP_EDGES)
- Error ("numedges == MAX_MAP_EDGES");
- edge = &dedges[numedges];
- numedges++;
- edge->v[0] = v1;
- edge->v[1] = v2;
- edgefaces[numedges-1][0] = f;
-
- return numedges-1;
-}
-
-/*
-===========================================================================
-
-FACE MERGING
-
-===========================================================================
-*/
-
-/*
-=============
-TryMerge
-
-If two polygons share a common edge and the edges that meet at the
-common points are both inside the other polygons, merge them
-
-Returns NULL if the faces couldn't be merged, or the new face.
-The originals will NOT be freed.
-=============
-*/
-face_t *TryMerge (face_t *f1, face_t *f2, vec3_t planenormal)
-{
- face_t *newf;
- winding_t *nw;
-
- if (!f1->w || !f2->w)
- return NULL;
- if (f1->texinfo != f2->texinfo)
- return NULL;
- if (f1->planenum != f2->planenum) // on front and back sides
- return NULL;
- if (f1->contents != f2->contents)
- return NULL;
-
-
- nw = TryMergeWinding (f1->w, f2->w, planenormal);
- if (!nw)
- return NULL;
-
- c_merge++;
- newf = NewFaceFromFace (f1);
- newf->w = nw;
-
- f1->merged = newf;
- f2->merged = newf;
-
- return newf;
-}
-
-/*
-===============
-MergeNodeFaces
-===============
-*/
-void MergeNodeFaces (node_t *node)
-{
- face_t *f1, *f2, *end;
- face_t *merged;
- plane_t *plane;
-
- plane = &mapplanes[node->planenum];
- merged = NULL;
-
- for (f1 = node->faces ; f1 ; f1 = f1->next)
- {
- if (f1->merged || f1->split[0] || f1->split[1])
- continue;
-
- for (f2 = node->faces ; f2 != f1 ; f2=f2->next)
- {
- if (f2->merged || f2->split[0] || f2->split[1])
- continue;
-
- //IDBUG: always passes the face's node's normal to TryMerge()
- //regardless of which side the face is on. Approximately 50% of
- //the time the face will be on the other side of node, and thus
- //the result of the convex/concave test in TryMergeWinding(),
- //which depends on the normal, is flipped. This causes faces
- //that shouldn't be merged to be merged and faces that
- //should be merged to not be merged.
- //the following added line fixes this bug
- //thanks to: Alexander Malmberg <alexander@malmberg.org>
- plane = &mapplanes[f1->planenum];
- //
- merged = TryMerge (f1, f2, plane->normal);
- if (!merged)
- continue;
-
- // add merged to the end of the node face list
- // so it will be checked against all the faces again
- for (end = node->faces ; end->next ; end = end->next)
- ;
- merged->next = NULL;
- end->next = merged;
- break;
- }
- }
-}
-
-//=====================================================================
-
-/*
-===============
-SubdivideFace
-
-Chop up faces that are larger than we want in the surface cache
-===============
-*/
-void SubdivideFace (node_t *node, face_t *f)
-{
- float mins, maxs;
- vec_t v;
- int axis, i;
- texinfo_t *tex;
- vec3_t temp;
- vec_t dist;
- winding_t *w, *frontw, *backw;
-
- if (f->merged)
- return;
-
-// special (non-surface cached) faces don't need subdivision
- tex = &texinfo[f->texinfo];
-
- if ( tex->flags & (SURF_WARP|SURF_SKY) )
- {
- return;
- }
-
- for (axis = 0 ; axis < 2 ; axis++)
- {
- while (1)
- {
- mins = 999999;
- maxs = -999999;
-
- VectorCopy (tex->vecs[axis], temp);
- w = f->w;
- for (i=0 ; i<w->numpoints ; i++)
- {
- v = DotProduct (w->p[i], temp);
- if (v < mins)
- mins = v;
- if (v > maxs)
- maxs = v;
- }
-#if 0
- if (maxs - mins <= 0)
- Error ("zero extents");
-#endif
- if (axis == 2)
- { // allow double high walls
- if (maxs - mins <= subdivide_size/* *2 */)
- break;
- }
- else if (maxs - mins <= subdivide_size)
- break;
-
- // split it
- c_subdivide++;
-
- v = VectorNormalize (temp);
-
- dist = (mins + subdivide_size - 16)/v;
-
- ClipWindingEpsilon (w, temp, dist, ON_EPSILON, &frontw, &backw);
- if (!frontw || !backw)
- Error ("SubdivideFace: didn't split the polygon");
-
- f->split[0] = NewFaceFromFace (f);
- f->split[0]->w = frontw;
- f->split[0]->next = node->faces;
- node->faces = f->split[0];
-
- f->split[1] = NewFaceFromFace (f);
- f->split[1]->w = backw;
- f->split[1]->next = node->faces;
- node->faces = f->split[1];
-
- SubdivideFace (node, f->split[0]);
- SubdivideFace (node, f->split[1]);
- return;
- }
- }
-}
-
-void SubdivideNodeFaces (node_t *node)
-{
- face_t *f;
-
- for (f = node->faces ; f ; f=f->next)
- {
- SubdivideFace (node, f);
- }
-}
-
-//===========================================================================
-
-int c_nodefaces;
-
-
-/*
-============
-FaceFromPortal
-
-============
-*/
-face_t *FaceFromPortal (portal_t *p, int pside)
-{
- face_t *f;
- side_t *side;
-
- side = p->side;
- if (!side)
- return NULL; // portal does not bridge different visible contents
-
- f = AllocFace ();
-
- f->texinfo = side->texinfo;
- f->planenum = (side->planenum & ~1) | pside;
- f->portal = p;
-
- if ( (p->nodes[pside]->contents & CONTENTS_WINDOW)
- && VisibleContents(p->nodes[!pside]->contents^p->nodes[pside]->contents) == CONTENTS_WINDOW )
- return NULL; // don't show insides of windows
-
- if (pside)
- {
- f->w = ReverseWinding(p->winding);
- f->contents = p->nodes[1]->contents;
- }
- else
- {
- f->w = CopyWinding(p->winding);
- f->contents = p->nodes[0]->contents;
- }
- return f;
-}
-
-
-/*
-===============
-MakeFaces_r
-
-If a portal will make a visible face,
-mark the side that originally created it
-
- solid / empty : solid
- solid / water : solid
- water / empty : water
- water / water : none
-===============
-*/
-void MakeFaces_r (node_t *node)
-{
- portal_t *p;
- int s;
-
- // recurse down to leafs
- if (node->planenum != PLANENUM_LEAF)
- {
- MakeFaces_r (node->children[0]);
- MakeFaces_r (node->children[1]);
-
- // merge together all visible faces on the node
- if (!nomerge)
- MergeNodeFaces (node);
- if (!nosubdiv)
- SubdivideNodeFaces (node);
-
- return;
- }
-
- // solid leafs never have visible faces
- if (node->contents & CONTENTS_SOLID)
- return;
-
- // see which portals are valid
- for (p=node->portals ; p ; p = p->next[s])
- {
- s = (p->nodes[1] == node);
-
- p->face[s] = FaceFromPortal (p, s);
- if (p->face[s])
- {
- c_nodefaces++;
- p->face[s]->next = p->onnode->faces;
- p->onnode->faces = p->face[s];
- }
- }
-}
-
-/*
-============
-MakeFaces
-============
-*/
-void MakeFaces (node_t *node)
-{
- qprintf ("--- MakeFaces ---\n");
- c_merge = 0;
- c_subdivide = 0;
- c_nodefaces = 0;
-
- MakeFaces_r (node);
-
- qprintf ("%5i makefaces\n", c_nodefaces);
- qprintf ("%5i merged\n", c_merge);
- qprintf ("%5i subdivided\n", c_subdivide);
-}
+/*
+===========================================================================
+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
+===========================================================================
+*/
+// faces.c
+
+#include "qbsp.h"
+#include "l_mem.h"
+
+/*
+
+ some faces will be removed before saving, but still form nodes:
+
+ the insides of sky volumes
+ meeting planes of different water current volumes
+
+*/
+
+// undefine for dumb linear searches
+#define USE_HASHING
+
+#define INTEGRAL_EPSILON 0.01
+#define POINT_EPSILON 0.5
+#define OFF_EPSILON 0.5
+
+int c_merge;
+int c_subdivide;
+
+int c_totalverts;
+int c_uniqueverts;
+int c_degenerate;
+int c_tjunctions;
+int c_faceoverflows;
+int c_facecollapse;
+int c_badstartverts;
+
+#define MAX_SUPERVERTS 512
+int superverts[MAX_SUPERVERTS];
+int numsuperverts;
+
+face_t *edgefaces[MAX_MAP_EDGES][2];
+int firstmodeledge = 1;
+int firstmodelface;
+
+int c_tryedges;
+
+vec3_t edge_dir;
+vec3_t edge_start;
+vec_t edge_len;
+
+int num_edge_verts;
+int edge_verts[MAX_MAP_VERTS];
+
+face_t *NewFaceFromFace (face_t *f);
+
+//===========================================================================
+
+typedef struct hashvert_s
+{
+ struct hashvert_s *next;
+ int num;
+} hashvert_t;
+
+
+#define HASH_SIZE 64
+
+
+int vertexchain[MAX_MAP_VERTS]; // the next vertex in a hash chain
+int hashverts[HASH_SIZE*HASH_SIZE]; // a vertex number, or 0 for no verts
+
+face_t *edgefaces[MAX_MAP_EDGES][2];
+
+//============================================================================
+
+
+unsigned HashVec (vec3_t vec)
+{
+ int x, y;
+
+ x = (4096 + (int)(vec[0]+0.5)) >> 7;
+ y = (4096 + (int)(vec[1]+0.5)) >> 7;
+
+ if ( x < 0 || x >= HASH_SIZE || y < 0 || y >= HASH_SIZE )
+ Error ("HashVec: point outside valid range");
+
+ return y*HASH_SIZE + x;
+}
+
+#ifdef USE_HASHING
+/*
+=============
+GetVertex
+
+Uses hashing
+=============
+*/
+int GetVertexnum (vec3_t in)
+{
+ int h;
+ int i;
+ float *p;
+ vec3_t vert;
+ int vnum;
+
+ c_totalverts++;
+
+ for (i=0 ; i<3 ; i++)
+ {
+ if ( fabs(in[i] - Q_rint(in[i])) < INTEGRAL_EPSILON)
+ vert[i] = Q_rint(in[i]);
+ else
+ vert[i] = in[i];
+ }
+
+ h = HashVec (vert);
+
+ for (vnum=hashverts[h] ; vnum ; vnum=vertexchain[vnum])
+ {
+ p = dvertexes[vnum].point;
+ if ( fabs(p[0]-vert[0])<POINT_EPSILON
+ && fabs(p[1]-vert[1])<POINT_EPSILON
+ && fabs(p[2]-vert[2])<POINT_EPSILON )
+ return vnum;
+ }
+
+// emit a vertex
+ if (numvertexes == MAX_MAP_VERTS)
+ Error ("numvertexes == MAX_MAP_VERTS");
+
+ dvertexes[numvertexes].point[0] = vert[0];
+ dvertexes[numvertexes].point[1] = vert[1];
+ dvertexes[numvertexes].point[2] = vert[2];
+
+ vertexchain[numvertexes] = hashverts[h];
+ hashverts[h] = numvertexes;
+
+ c_uniqueverts++;
+
+ numvertexes++;
+
+ return numvertexes-1;
+}
+#else
+/*
+==================
+GetVertexnum
+
+Dumb linear search
+==================
+*/
+int GetVertexnum (vec3_t v)
+{
+ int i, j;
+ dvertex_t *dv;
+ vec_t d;
+
+ c_totalverts++;
+
+ // make really close values exactly integral
+ for (i=0 ; i<3 ; i++)
+ {
+ if ( fabs(v[i] - (int)(v[i]+0.5)) < INTEGRAL_EPSILON )
+ v[i] = (int)(v[i]+0.5);
+ if (v[i] < -4096 || v[i] > 4096)
+ Error ("GetVertexnum: outside +/- 4096");
+ }
+
+ // search for an existing vertex match
+ for (i=0, dv=dvertexes ; i<numvertexes ; i++, dv++)
+ {
+ for (j=0 ; j<3 ; j++)
+ {
+ d = v[j] - dv->point[j];
+ if ( d > POINT_EPSILON || d < -POINT_EPSILON)
+ break;
+ }
+ if (j == 3)
+ return i; // a match
+ }
+
+ // new point
+ if (numvertexes == MAX_MAP_VERTS)
+ Error ("MAX_MAP_VERTS");
+ VectorCopy (v, dv->point);
+ numvertexes++;
+ c_uniqueverts++;
+
+ return numvertexes-1;
+}
+#endif
+
+
+/*
+==================
+FaceFromSuperverts
+
+The faces vertexes have been added to the superverts[] array,
+and there may be more there than can be held in a face (MAXEDGES).
+
+If less, the faces vertexnums[] will be filled in, otherwise
+face will reference a tree of split[] faces until all of the
+vertexnums can be added.
+
+superverts[base] will become face->vertexnums[0], and the others
+will be circularly filled in.
+==================
+*/
+void FaceFromSuperverts (node_t *node, face_t *f, int base)
+{
+ face_t *newf;
+ int remaining;
+ int i;
+
+ remaining = numsuperverts;
+ while (remaining > MAXEDGES)
+ { // must split into two faces, because of vertex overload
+ c_faceoverflows++;
+
+ newf = f->split[0] = NewFaceFromFace (f);
+ newf = f->split[0];
+ newf->next = node->faces;
+ node->faces = newf;
+
+ newf->numpoints = MAXEDGES;
+ for (i=0 ; i<MAXEDGES ; i++)
+ newf->vertexnums[i] = superverts[(i+base)%numsuperverts];
+
+ f->split[1] = NewFaceFromFace (f);
+ f = f->split[1];
+ f->next = node->faces;
+ node->faces = f;
+
+ remaining -= (MAXEDGES-2);
+ base = (base+MAXEDGES-1)%numsuperverts;
+ }
+
+ // copy the vertexes back to the face
+ f->numpoints = remaining;
+ for (i=0 ; i<remaining ; i++)
+ f->vertexnums[i] = superverts[(i+base)%numsuperverts];
+}
+
+
+/*
+==================
+EmitFaceVertexes
+==================
+*/
+void EmitFaceVertexes (node_t *node, face_t *f)
+{
+ winding_t *w;
+ int i;
+
+ if (f->merged || f->split[0] || f->split[1])
+ return;
+
+ w = f->w;
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ if (noweld)
+ { // make every point unique
+ if (numvertexes == MAX_MAP_VERTS)
+ Error ("MAX_MAP_VERTS");
+ superverts[i] = numvertexes;
+ VectorCopy (w->p[i], dvertexes[numvertexes].point);
+ numvertexes++;
+ c_uniqueverts++;
+ c_totalverts++;
+ }
+ else
+ superverts[i] = GetVertexnum (w->p[i]);
+ }
+ numsuperverts = w->numpoints;
+
+ // this may fragment the face if > MAXEDGES
+ FaceFromSuperverts (node, f, 0);
+}
+
+/*
+==================
+EmitVertexes_r
+==================
+*/
+void EmitVertexes_r (node_t *node)
+{
+ int i;
+ face_t *f;
+
+ if (node->planenum == PLANENUM_LEAF)
+ return;
+
+ for (f=node->faces ; f ; f=f->next)
+ {
+ EmitFaceVertexes (node, f);
+ }
+
+ for (i=0 ; i<2 ; i++)
+ EmitVertexes_r (node->children[i]);
+}
+
+
+#ifdef USE_HASHING
+/*
+==========
+FindEdgeVerts
+
+Uses the hash tables to cut down to a small number
+==========
+*/
+void FindEdgeVerts (vec3_t v1, vec3_t v2)
+{
+ int x1, x2, y1, y2, t;
+ int x, y;
+ int vnum;
+
+#if 0
+{
+ int i;
+ num_edge_verts = numvertexes-1;
+ for (i=0 ; i<numvertexes-1 ; i++)
+ edge_verts[i] = i+1;
+}
+#endif
+
+ x1 = (4096 + (int)(v1[0]+0.5)) >> 7;
+ y1 = (4096 + (int)(v1[1]+0.5)) >> 7;
+ x2 = (4096 + (int)(v2[0]+0.5)) >> 7;
+ y2 = (4096 + (int)(v2[1]+0.5)) >> 7;
+
+ if (x1 > x2)
+ {
+ t = x1;
+ x1 = x2;
+ x2 = t;
+ }
+ if (y1 > y2)
+ {
+ t = y1;
+ y1 = y2;
+ y2 = t;
+ }
+#if 0
+ x1--;
+ x2++;
+ y1--;
+ y2++;
+ if (x1 < 0)
+ x1 = 0;
+ if (x2 >= HASH_SIZE)
+ x2 = HASH_SIZE;
+ if (y1 < 0)
+ y1 = 0;
+ if (y2 >= HASH_SIZE)
+ y2 = HASH_SIZE;
+#endif
+ num_edge_verts = 0;
+ for (x=x1 ; x <= x2 ; x++)
+ {
+ for (y=y1 ; y <= y2 ; y++)
+ {
+ for (vnum=hashverts[y*HASH_SIZE+x] ; vnum ; vnum=vertexchain[vnum])
+ {
+ edge_verts[num_edge_verts++] = vnum;
+ }
+ }
+ }
+}
+
+#else
+/*
+==========
+FindEdgeVerts
+
+Forced a dumb check of everything
+==========
+*/
+void FindEdgeVerts (vec3_t v1, vec3_t v2)
+{
+ int i;
+
+ num_edge_verts = numvertexes-1;
+ for (i=0 ; i<num_edge_verts ; i++)
+ edge_verts[i] = i+1;
+}
+#endif
+
+/*
+==========
+TestEdge
+
+Can be recursively reentered
+==========
+*/
+void TestEdge (vec_t start, vec_t end, int p1, int p2, int startvert)
+{
+ int j, k;
+ vec_t dist;
+ vec3_t delta;
+ vec3_t exact;
+ vec3_t off;
+ vec_t error;
+ vec3_t p;
+
+ if (p1 == p2)
+ {
+ c_degenerate++;
+ return; // degenerate edge
+ }
+
+ for (k=startvert ; k<num_edge_verts ; k++)
+ {
+ j = edge_verts[k];
+ if (j==p1 || j == p2)
+ continue;
+
+ VectorCopy (dvertexes[j].point, p);
+
+ VectorSubtract (p, edge_start, delta);
+ dist = DotProduct (delta, edge_dir);
+ if (dist <=start || dist >= end)
+ continue; // off an end
+ VectorMA (edge_start, dist, edge_dir, exact);
+ VectorSubtract (p, exact, off);
+ error = VectorLength (off);
+
+ if (fabs(error) > OFF_EPSILON)
+ continue; // not on the edge
+
+ // break the edge
+ c_tjunctions++;
+ TestEdge (start, dist, p1, j, k+1);
+ TestEdge (dist, end, j, p2, k+1);
+ return;
+ }
+
+ // the edge p1 to p2 is now free of tjunctions
+ if (numsuperverts >= MAX_SUPERVERTS)
+ Error ("MAX_SUPERVERTS");
+ superverts[numsuperverts] = p1;
+ numsuperverts++;
+}
+
+/*
+==================
+FixFaceEdges
+
+==================
+*/
+void FixFaceEdges (node_t *node, face_t *f)
+{
+ int p1, p2;
+ int i;
+ vec3_t e2;
+ vec_t len;
+ int count[MAX_SUPERVERTS], start[MAX_SUPERVERTS];
+ int base;
+
+ if (f->merged || f->split[0] || f->split[1])
+ return;
+
+ numsuperverts = 0;
+
+ for (i=0 ; i<f->numpoints ; i++)
+ {
+ p1 = f->vertexnums[i];
+ p2 = f->vertexnums[(i+1)%f->numpoints];
+
+ VectorCopy (dvertexes[p1].point, edge_start);
+ VectorCopy (dvertexes[p2].point, e2);
+
+ FindEdgeVerts (edge_start, e2);
+
+ VectorSubtract (e2, edge_start, edge_dir);
+ len = VectorNormalize(edge_dir);
+
+ start[i] = numsuperverts;
+ TestEdge (0, len, p1, p2, 0);
+
+ count[i] = numsuperverts - start[i];
+ }
+
+ if (numsuperverts < 3)
+ { // entire face collapsed
+ f->numpoints = 0;
+ c_facecollapse++;
+ return;
+ }
+
+ // we want to pick a vertex that doesn't have tjunctions
+ // on either side, which can cause artifacts on trifans,
+ // especially underwater
+ for (i=0 ; i<f->numpoints ; i++)
+ {
+ if (count[i] == 1 && count[(i+f->numpoints-1)%f->numpoints] == 1)
+ break;
+ }
+ if (i == f->numpoints)
+ {
+ f->badstartvert = true;
+ c_badstartverts++;
+ base = 0;
+ }
+ else
+ { // rotate the vertex order
+ base = start[i];
+ }
+
+ // this may fragment the face if > MAXEDGES
+ FaceFromSuperverts (node, f, base);
+}
+
+/*
+==================
+FixEdges_r
+==================
+*/
+void FixEdges_r (node_t *node)
+{
+ int i;
+ face_t *f;
+
+ if (node->planenum == PLANENUM_LEAF)
+ return;
+
+ for (f=node->faces ; f ; f=f->next)
+ FixFaceEdges (node, f);
+
+ for (i=0 ; i<2 ; i++)
+ FixEdges_r (node->children[i]);
+}
+
+/*
+===========
+FixTjuncs
+
+===========
+*/
+void FixTjuncs (node_t *headnode)
+{
+ // snap and merge all vertexes
+ qprintf ("---- snap verts ----\n");
+ memset (hashverts, 0, sizeof(hashverts));
+ c_totalverts = 0;
+ c_uniqueverts = 0;
+ c_faceoverflows = 0;
+ EmitVertexes_r (headnode);
+ qprintf ("%i unique from %i\n", c_uniqueverts, c_totalverts);
+
+ // break edges on tjunctions
+ qprintf ("---- tjunc ----\n");
+ c_tryedges = 0;
+ c_degenerate = 0;
+ c_facecollapse = 0;
+ c_tjunctions = 0;
+ if (!notjunc)
+ FixEdges_r (headnode);
+ qprintf ("%5i edges degenerated\n", c_degenerate);
+ qprintf ("%5i faces degenerated\n", c_facecollapse);
+ qprintf ("%5i edges added by tjunctions\n", c_tjunctions);
+ qprintf ("%5i faces added by tjunctions\n", c_faceoverflows);
+ qprintf ("%5i bad start verts\n", c_badstartverts);
+}
+
+
+//========================================================
+
+int c_faces;
+
+face_t *AllocFace (void)
+{
+ face_t *f;
+
+ f = GetMemory(sizeof(*f));
+ memset (f, 0, sizeof(*f));
+ c_faces++;
+
+ return f;
+}
+
+face_t *NewFaceFromFace (face_t *f)
+{
+ face_t *newf;
+
+ newf = AllocFace ();
+ *newf = *f;
+ newf->merged = NULL;
+ newf->split[0] = newf->split[1] = NULL;
+ newf->w = NULL;
+ return newf;
+}
+
+void FreeFace (face_t *f)
+{
+ if (f->w)
+ FreeWinding (f->w);
+ FreeMemory(f);
+ c_faces--;
+}
+
+//========================================================
+
+/*
+==================
+GetEdge
+
+Called by writebsp.
+Don't allow four way edges
+==================
+*/
+int GetEdge2 (int v1, int v2, face_t *f)
+{
+ dedge_t *edge;
+ int i;
+
+ c_tryedges++;
+
+ if (!noshare)
+ {
+ for (i=firstmodeledge ; i < numedges ; i++)
+ {
+ edge = &dedges[i];
+ if (v1 == edge->v[1] && v2 == edge->v[0]
+ && edgefaces[i][0]->contents == f->contents)
+ {
+ if (edgefaces[i][1])
+ // printf ("WARNING: multiple backward edge\n");
+ continue;
+ edgefaces[i][1] = f;
+ return -i;
+ }
+ #if 0
+ if (v1 == edge->v[0] && v2 == edge->v[1])
+ {
+ printf ("WARNING: multiple forward edge\n");
+ return i;
+ }
+ #endif
+ }
+ }
+
+// emit an edge
+ if (numedges >= MAX_MAP_EDGES)
+ Error ("numedges == MAX_MAP_EDGES");
+ edge = &dedges[numedges];
+ numedges++;
+ edge->v[0] = v1;
+ edge->v[1] = v2;
+ edgefaces[numedges-1][0] = f;
+
+ return numedges-1;
+}
+
+/*
+===========================================================================
+
+FACE MERGING
+
+===========================================================================
+*/
+
+/*
+=============
+TryMerge
+
+If two polygons share a common edge and the edges that meet at the
+common points are both inside the other polygons, merge them
+
+Returns NULL if the faces couldn't be merged, or the new face.
+The originals will NOT be freed.
+=============
+*/
+face_t *TryMerge (face_t *f1, face_t *f2, vec3_t planenormal)
+{
+ face_t *newf;
+ winding_t *nw;
+
+ if (!f1->w || !f2->w)
+ return NULL;
+ if (f1->texinfo != f2->texinfo)
+ return NULL;
+ if (f1->planenum != f2->planenum) // on front and back sides
+ return NULL;
+ if (f1->contents != f2->contents)
+ return NULL;
+
+
+ nw = TryMergeWinding (f1->w, f2->w, planenormal);
+ if (!nw)
+ return NULL;
+
+ c_merge++;
+ newf = NewFaceFromFace (f1);
+ newf->w = nw;
+
+ f1->merged = newf;
+ f2->merged = newf;
+
+ return newf;
+}
+
+/*
+===============
+MergeNodeFaces
+===============
+*/
+void MergeNodeFaces (node_t *node)
+{
+ face_t *f1, *f2, *end;
+ face_t *merged;
+ plane_t *plane;
+
+ plane = &mapplanes[node->planenum];
+ merged = NULL;
+
+ for (f1 = node->faces ; f1 ; f1 = f1->next)
+ {
+ if (f1->merged || f1->split[0] || f1->split[1])
+ continue;
+
+ for (f2 = node->faces ; f2 != f1 ; f2=f2->next)
+ {
+ if (f2->merged || f2->split[0] || f2->split[1])
+ continue;
+
+ //IDBUG: always passes the face's node's normal to TryMerge()
+ //regardless of which side the face is on. Approximately 50% of
+ //the time the face will be on the other side of node, and thus
+ //the result of the convex/concave test in TryMergeWinding(),
+ //which depends on the normal, is flipped. This causes faces
+ //that shouldn't be merged to be merged and faces that
+ //should be merged to not be merged.
+ //the following added line fixes this bug
+ //thanks to: Alexander Malmberg <alexander@malmberg.org>
+ plane = &mapplanes[f1->planenum];
+ //
+ merged = TryMerge (f1, f2, plane->normal);
+ if (!merged)
+ continue;
+
+ // add merged to the end of the node face list
+ // so it will be checked against all the faces again
+ for (end = node->faces ; end->next ; end = end->next)
+ ;
+ merged->next = NULL;
+ end->next = merged;
+ break;
+ }
+ }
+}
+
+//=====================================================================
+
+/*
+===============
+SubdivideFace
+
+Chop up faces that are larger than we want in the surface cache
+===============
+*/
+void SubdivideFace (node_t *node, face_t *f)
+{
+ float mins, maxs;
+ vec_t v;
+ int axis, i;
+ texinfo_t *tex;
+ vec3_t temp;
+ vec_t dist;
+ winding_t *w, *frontw, *backw;
+
+ if (f->merged)
+ return;
+
+// special (non-surface cached) faces don't need subdivision
+ tex = &texinfo[f->texinfo];
+
+ if ( tex->flags & (SURF_WARP|SURF_SKY) )
+ {
+ return;
+ }
+
+ for (axis = 0 ; axis < 2 ; axis++)
+ {
+ while (1)
+ {
+ mins = 999999;
+ maxs = -999999;
+
+ VectorCopy (tex->vecs[axis], temp);
+ w = f->w;
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ v = DotProduct (w->p[i], temp);
+ if (v < mins)
+ mins = v;
+ if (v > maxs)
+ maxs = v;
+ }
+#if 0
+ if (maxs - mins <= 0)
+ Error ("zero extents");
+#endif
+ if (axis == 2)
+ { // allow double high walls
+ if (maxs - mins <= subdivide_size/* *2 */)
+ break;
+ }
+ else if (maxs - mins <= subdivide_size)
+ break;
+
+ // split it
+ c_subdivide++;
+
+ v = VectorNormalize (temp);
+
+ dist = (mins + subdivide_size - 16)/v;
+
+ ClipWindingEpsilon (w, temp, dist, ON_EPSILON, &frontw, &backw);
+ if (!frontw || !backw)
+ Error ("SubdivideFace: didn't split the polygon");
+
+ f->split[0] = NewFaceFromFace (f);
+ f->split[0]->w = frontw;
+ f->split[0]->next = node->faces;
+ node->faces = f->split[0];
+
+ f->split[1] = NewFaceFromFace (f);
+ f->split[1]->w = backw;
+ f->split[1]->next = node->faces;
+ node->faces = f->split[1];
+
+ SubdivideFace (node, f->split[0]);
+ SubdivideFace (node, f->split[1]);
+ return;
+ }
+ }
+}
+
+void SubdivideNodeFaces (node_t *node)
+{
+ face_t *f;
+
+ for (f = node->faces ; f ; f=f->next)
+ {
+ SubdivideFace (node, f);
+ }
+}
+
+//===========================================================================
+
+int c_nodefaces;
+
+
+/*
+============
+FaceFromPortal
+
+============
+*/
+face_t *FaceFromPortal (portal_t *p, int pside)
+{
+ face_t *f;
+ side_t *side;
+
+ side = p->side;
+ if (!side)
+ return NULL; // portal does not bridge different visible contents
+
+ f = AllocFace ();
+
+ f->texinfo = side->texinfo;
+ f->planenum = (side->planenum & ~1) | pside;
+ f->portal = p;
+
+ if ( (p->nodes[pside]->contents & CONTENTS_WINDOW)
+ && VisibleContents(p->nodes[!pside]->contents^p->nodes[pside]->contents) == CONTENTS_WINDOW )
+ return NULL; // don't show insides of windows
+
+ if (pside)
+ {
+ f->w = ReverseWinding(p->winding);
+ f->contents = p->nodes[1]->contents;
+ }
+ else
+ {
+ f->w = CopyWinding(p->winding);
+ f->contents = p->nodes[0]->contents;
+ }
+ return f;
+}
+
+
+/*
+===============
+MakeFaces_r
+
+If a portal will make a visible face,
+mark the side that originally created it
+
+ solid / empty : solid
+ solid / water : solid
+ water / empty : water
+ water / water : none
+===============
+*/
+void MakeFaces_r (node_t *node)
+{
+ portal_t *p;
+ int s;
+
+ // recurse down to leafs
+ if (node->planenum != PLANENUM_LEAF)
+ {
+ MakeFaces_r (node->children[0]);
+ MakeFaces_r (node->children[1]);
+
+ // merge together all visible faces on the node
+ if (!nomerge)
+ MergeNodeFaces (node);
+ if (!nosubdiv)
+ SubdivideNodeFaces (node);
+
+ return;
+ }
+
+ // solid leafs never have visible faces
+ if (node->contents & CONTENTS_SOLID)
+ return;
+
+ // see which portals are valid
+ for (p=node->portals ; p ; p = p->next[s])
+ {
+ s = (p->nodes[1] == node);
+
+ p->face[s] = FaceFromPortal (p, s);
+ if (p->face[s])
+ {
+ c_nodefaces++;
+ p->face[s]->next = p->onnode->faces;
+ p->onnode->faces = p->face[s];
+ }
+ }
+}
+
+/*
+============
+MakeFaces
+============
+*/
+void MakeFaces (node_t *node)
+{
+ qprintf ("--- MakeFaces ---\n");
+ c_merge = 0;
+ c_subdivide = 0;
+ c_nodefaces = 0;
+
+ MakeFaces_r (node);
+
+ qprintf ("%5i makefaces\n", c_nodefaces);
+ qprintf ("%5i merged\n", c_merge);
+ qprintf ("%5i subdivided\n", c_subdivide);
+}
diff --git a/code/bspc/gldraw.c b/code/bspc/gldraw.c
index 9f7d6f7..18ed2c8 100755
--- a/code/bspc/gldraw.c
+++ b/code/bspc/gldraw.c
@@ -1,232 +1,232 @@
-/*
-===========================================================================
-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 <windows.h>
-#include <GL/gl.h>
-#include <GL/glu.h>
-#include <GL/glaux.h>
-
-#include "qbsp.h"
-
-// can't use the glvertex3fv functions, because the vec3_t fields
-// could be either floats or doubles, depending on DOUBLEVEC_T
-
-qboolean drawflag;
-vec3_t draw_mins, draw_maxs;
-
-
-#define WIN_SIZE 512
-
-void InitWindow (void)
-{
- auxInitDisplayMode (AUX_SINGLE | AUX_RGB);
- auxInitPosition (0, 0, WIN_SIZE, WIN_SIZE);
- auxInitWindow ("qcsg");
-}
-
-void Draw_ClearWindow (void)
-{
- static int init;
- int w, h, g;
- vec_t mx, my;
-
- if (!drawflag)
- return;
-
- if (!init)
- {
- init = true;
- InitWindow ();
- }
-
- glClearColor (1,0.8,0.8,0);
- glClear (GL_COLOR_BUFFER_BIT);
-
- w = (draw_maxs[0] - draw_mins[0]);
- h = (draw_maxs[1] - draw_mins[1]);
-
- mx = draw_mins[0] + w/2;
- my = draw_mins[1] + h/2;
-
- g = w > h ? w : h;
-
- glLoadIdentity ();
- gluPerspective (90, 1, 2, 16384);
- gluLookAt (mx, my, draw_maxs[2] + g/2, mx , my, draw_maxs[2], 0, 1, 0);
-
- glColor3f (0,0,0);
-// glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
- glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
- glDisable (GL_DEPTH_TEST);
- glEnable (GL_BLEND);
- glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-#if 0
- glColor4f (1,0,0,0.5);
- glBegin (GL_POLYGON);
-
- glVertex3f (0, 500, 0);
- glVertex3f (0, 900, 0);
- glVertex3f (0, 900, 100);
- glVertex3f (0, 500, 100);
-
- glEnd ();
-#endif
-
- glFlush ();
-
-}
-
-void Draw_SetRed (void)
-{
- if (!drawflag)
- return;
-
- glColor3f (1,0,0);
-}
-
-void Draw_SetGrey (void)
-{
- if (!drawflag)
- return;
-
- glColor3f (0.5,0.5,0.5);
-}
-
-void Draw_SetBlack (void)
-{
- if (!drawflag)
- return;
-
- glColor3f (0,0,0);
-}
-
-void DrawWinding (winding_t *w)
-{
- int i;
-
- if (!drawflag)
- return;
-
- glColor4f (0,0,0,0.5);
- glBegin (GL_LINE_LOOP);
- for (i=0 ; i<w->numpoints ; i++)
- glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] );
- glEnd ();
-
- glColor4f (0,1,0,0.3);
- glBegin (GL_POLYGON);
- for (i=0 ; i<w->numpoints ; i++)
- glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] );
- glEnd ();
-
- glFlush ();
-}
-
-void DrawAuxWinding (winding_t *w)
-{
- int i;
-
- if (!drawflag)
- return;
-
- glColor4f (0,0,0,0.5);
- glBegin (GL_LINE_LOOP);
- for (i=0 ; i<w->numpoints ; i++)
- glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] );
- glEnd ();
-
- glColor4f (1,0,0,0.3);
- glBegin (GL_POLYGON);
- for (i=0 ; i<w->numpoints ; i++)
- glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] );
- glEnd ();
-
- glFlush ();
-}
-
-//============================================================
-
-#define GLSERV_PORT 25001
-
-qboolean wins_init;
-int draw_socket;
-
-void GLS_BeginScene (void)
-{
- WSADATA winsockdata;
- WORD wVersionRequested;
- struct sockaddr_in address;
- int r;
-
- if (!wins_init)
- {
- wins_init = true;
-
- wVersionRequested = MAKEWORD(1, 1);
-
- r = WSAStartup (MAKEWORD(1, 1), &winsockdata);
-
- if (r)
- Error ("Winsock initialization failed.");
-
- }
-
- // connect a socket to the server
-
- draw_socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (draw_socket == -1)
- Error ("draw_socket failed");
-
- address.sin_family = AF_INET;
- address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- address.sin_port = GLSERV_PORT;
- r = connect (draw_socket, (struct sockaddr *)&address, sizeof(address));
- if (r == -1)
- {
- closesocket (draw_socket);
- draw_socket = 0;
- }
-}
-
-void GLS_Winding (winding_t *w, int code)
-{
- byte buf[1024];
- int i, j;
-
- if (!draw_socket)
- return;
-
- ((int *)buf)[0] = w->numpoints;
- ((int *)buf)[1] = code;
- for (i=0 ; i<w->numpoints ; i++)
- for (j=0 ; j<3 ; j++)
- ((float *)buf)[2+i*3+j] = w->p[i][j];
-
- send (draw_socket, buf, w->numpoints*12+8, 0);
-}
-
-void GLS_EndScene (void)
-{
- closesocket (draw_socket);
- draw_socket = 0;
-}
+/*
+===========================================================================
+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 <windows.h>
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glaux.h>
+
+#include "qbsp.h"
+
+// can't use the glvertex3fv functions, because the vec3_t fields
+// could be either floats or doubles, depending on DOUBLEVEC_T
+
+qboolean drawflag;
+vec3_t draw_mins, draw_maxs;
+
+
+#define WIN_SIZE 512
+
+void InitWindow (void)
+{
+ auxInitDisplayMode (AUX_SINGLE | AUX_RGB);
+ auxInitPosition (0, 0, WIN_SIZE, WIN_SIZE);
+ auxInitWindow ("qcsg");
+}
+
+void Draw_ClearWindow (void)
+{
+ static int init;
+ int w, h, g;
+ vec_t mx, my;
+
+ if (!drawflag)
+ return;
+
+ if (!init)
+ {
+ init = true;
+ InitWindow ();
+ }
+
+ glClearColor (1,0.8,0.8,0);
+ glClear (GL_COLOR_BUFFER_BIT);
+
+ w = (draw_maxs[0] - draw_mins[0]);
+ h = (draw_maxs[1] - draw_mins[1]);
+
+ mx = draw_mins[0] + w/2;
+ my = draw_mins[1] + h/2;
+
+ g = w > h ? w : h;
+
+ glLoadIdentity ();
+ gluPerspective (90, 1, 2, 16384);
+ gluLookAt (mx, my, draw_maxs[2] + g/2, mx , my, draw_maxs[2], 0, 1, 0);
+
+ glColor3f (0,0,0);
+// glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
+ glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+ glDisable (GL_DEPTH_TEST);
+ glEnable (GL_BLEND);
+ glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+#if 0
+ glColor4f (1,0,0,0.5);
+ glBegin (GL_POLYGON);
+
+ glVertex3f (0, 500, 0);
+ glVertex3f (0, 900, 0);
+ glVertex3f (0, 900, 100);
+ glVertex3f (0, 500, 100);
+
+ glEnd ();
+#endif
+
+ glFlush ();
+
+}
+
+void Draw_SetRed (void)
+{
+ if (!drawflag)
+ return;
+
+ glColor3f (1,0,0);
+}
+
+void Draw_SetGrey (void)
+{
+ if (!drawflag)
+ return;
+
+ glColor3f (0.5,0.5,0.5);
+}
+
+void Draw_SetBlack (void)
+{
+ if (!drawflag)
+ return;
+
+ glColor3f (0,0,0);
+}
+
+void DrawWinding (winding_t *w)
+{
+ int i;
+
+ if (!drawflag)
+ return;
+
+ glColor4f (0,0,0,0.5);
+ glBegin (GL_LINE_LOOP);
+ for (i=0 ; i<w->numpoints ; i++)
+ glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] );
+ glEnd ();
+
+ glColor4f (0,1,0,0.3);
+ glBegin (GL_POLYGON);
+ for (i=0 ; i<w->numpoints ; i++)
+ glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] );
+ glEnd ();
+
+ glFlush ();
+}
+
+void DrawAuxWinding (winding_t *w)
+{
+ int i;
+
+ if (!drawflag)
+ return;
+
+ glColor4f (0,0,0,0.5);
+ glBegin (GL_LINE_LOOP);
+ for (i=0 ; i<w->numpoints ; i++)
+ glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] );
+ glEnd ();
+
+ glColor4f (1,0,0,0.3);
+ glBegin (GL_POLYGON);
+ for (i=0 ; i<w->numpoints ; i++)
+ glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] );
+ glEnd ();
+
+ glFlush ();
+}
+
+//============================================================
+
+#define GLSERV_PORT 25001
+
+qboolean wins_init;
+int draw_socket;
+
+void GLS_BeginScene (void)
+{
+ WSADATA winsockdata;
+ WORD wVersionRequested;
+ struct sockaddr_in address;
+ int r;
+
+ if (!wins_init)
+ {
+ wins_init = true;
+
+ wVersionRequested = MAKEWORD(1, 1);
+
+ r = WSAStartup (MAKEWORD(1, 1), &winsockdata);
+
+ if (r)
+ Error ("Winsock initialization failed.");
+
+ }
+
+ // connect a socket to the server
+
+ draw_socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (draw_socket == -1)
+ Error ("draw_socket failed");
+
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ address.sin_port = GLSERV_PORT;
+ r = connect (draw_socket, (struct sockaddr *)&address, sizeof(address));
+ if (r == -1)
+ {
+ closesocket (draw_socket);
+ draw_socket = 0;
+ }
+}
+
+void GLS_Winding (winding_t *w, int code)
+{
+ byte buf[1024];
+ int i, j;
+
+ if (!draw_socket)
+ return;
+
+ ((int *)buf)[0] = w->numpoints;
+ ((int *)buf)[1] = code;
+ for (i=0 ; i<w->numpoints ; i++)
+ for (j=0 ; j<3 ; j++)
+ ((float *)buf)[2+i*3+j] = w->p[i][j];
+
+ send (draw_socket, buf, w->numpoints*12+8, 0);
+}
+
+void GLS_EndScene (void)
+{
+ closesocket (draw_socket);
+ draw_socket = 0;
+}
diff --git a/code/bspc/glfile.c b/code/bspc/glfile.c
index 179a836..e32821b 100755
--- a/code/bspc/glfile.c
+++ b/code/bspc/glfile.c
@@ -1,149 +1,149 @@
-/*
-===========================================================================
-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"
-
-int c_glfaces;
-
-int PortalVisibleSides (portal_t *p)
-{
- int fcon, bcon;
-
- if (!p->onnode)
- return 0; // outside
-
- fcon = p->nodes[0]->contents;
- bcon = p->nodes[1]->contents;
-
- // same contents never create a face
- if (fcon == bcon)
- return 0;
-
- // FIXME: is this correct now?
- if (!fcon)
- return 1;
- if (!bcon)
- return 2;
- return 0;
-}
-
-void OutputWinding (winding_t *w, FILE *glview)
-{
- static int level = 128;
- vec_t light;
- int i;
-
- fprintf (glview, "%i\n", w->numpoints);
- level+=28;
- light = (level&255)/255.0;
- for (i=0 ; i<w->numpoints ; i++)
- {
- fprintf (glview, "%6.3f %6.3f %6.3f %6.3f %6.3f %6.3f\n",
- w->p[i][0],
- w->p[i][1],
- w->p[i][2],
- light,
- light,
- light);
- }
- fprintf (glview, "\n");
-}
-
-/*
-=============
-OutputPortal
-=============
-*/
-void OutputPortal (portal_t *p, FILE *glview)
-{
- winding_t *w;
- int sides;
-
- sides = PortalVisibleSides (p);
- if (!sides)
- return;
-
- c_glfaces++;
-
- w = p->winding;
-
- if (sides == 2) // back side
- w = ReverseWinding (w);
-
- OutputWinding (w, glview);
-
- if (sides == 2)
- FreeWinding(w);
-}
-
-/*
-=============
-WriteGLView_r
-=============
-*/
-void WriteGLView_r (node_t *node, FILE *glview)
-{
- portal_t *p, *nextp;
-
- if (node->planenum != PLANENUM_LEAF)
- {
- WriteGLView_r (node->children[0], glview);
- WriteGLView_r (node->children[1], glview);
- return;
- }
-
- // write all the portals
- for (p=node->portals ; p ; p=nextp)
- {
- if (p->nodes[0] == node)
- {
- OutputPortal (p, glview);
- nextp = p->next[0];
- }
- else
- nextp = p->next[1];
- }
-}
-
-/*
-=============
-WriteGLView
-=============
-*/
-void WriteGLView (tree_t *tree, char *source)
-{
- char name[1024];
- FILE *glview;
-
- c_glfaces = 0;
- sprintf (name, "%s%s.gl",outbase, source);
- printf ("Writing %s\n", name);
-
- glview = fopen (name, "w");
- if (!glview)
- Error ("Couldn't open %s", name);
- WriteGLView_r (tree->headnode, glview);
- fclose (glview);
-
- printf ("%5i c_glfaces\n", c_glfaces);
-}
-
+/*
+===========================================================================
+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"
+
+int c_glfaces;
+
+int PortalVisibleSides (portal_t *p)
+{
+ int fcon, bcon;
+
+ if (!p->onnode)
+ return 0; // outside
+
+ fcon = p->nodes[0]->contents;
+ bcon = p->nodes[1]->contents;
+
+ // same contents never create a face
+ if (fcon == bcon)
+ return 0;
+
+ // FIXME: is this correct now?
+ if (!fcon)
+ return 1;
+ if (!bcon)
+ return 2;
+ return 0;
+}
+
+void OutputWinding (winding_t *w, FILE *glview)
+{
+ static int level = 128;
+ vec_t light;
+ int i;
+
+ fprintf (glview, "%i\n", w->numpoints);
+ level+=28;
+ light = (level&255)/255.0;
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ fprintf (glview, "%6.3f %6.3f %6.3f %6.3f %6.3f %6.3f\n",
+ w->p[i][0],
+ w->p[i][1],
+ w->p[i][2],
+ light,
+ light,
+ light);
+ }
+ fprintf (glview, "\n");
+}
+
+/*
+=============
+OutputPortal
+=============
+*/
+void OutputPortal (portal_t *p, FILE *glview)
+{
+ winding_t *w;
+ int sides;
+
+ sides = PortalVisibleSides (p);
+ if (!sides)
+ return;
+
+ c_glfaces++;
+
+ w = p->winding;
+
+ if (sides == 2) // back side
+ w = ReverseWinding (w);
+
+ OutputWinding (w, glview);
+
+ if (sides == 2)
+ FreeWinding(w);
+}
+
+/*
+=============
+WriteGLView_r
+=============
+*/
+void WriteGLView_r (node_t *node, FILE *glview)
+{
+ portal_t *p, *nextp;
+
+ if (node->planenum != PLANENUM_LEAF)
+ {
+ WriteGLView_r (node->children[0], glview);
+ WriteGLView_r (node->children[1], glview);
+ return;
+ }
+
+ // write all the portals
+ for (p=node->portals ; p ; p=nextp)
+ {
+ if (p->nodes[0] == node)
+ {
+ OutputPortal (p, glview);
+ nextp = p->next[0];
+ }
+ else
+ nextp = p->next[1];
+ }
+}
+
+/*
+=============
+WriteGLView
+=============
+*/
+void WriteGLView (tree_t *tree, char *source)
+{
+ char name[1024];
+ FILE *glview;
+
+ c_glfaces = 0;
+ sprintf (name, "%s%s.gl",outbase, source);
+ printf ("Writing %s\n", name);
+
+ glview = fopen (name, "w");
+ if (!glview)
+ Error ("Couldn't open %s", name);
+ WriteGLView_r (tree->headnode, glview);
+ fclose (glview);
+
+ printf ("%5i c_glfaces\n", c_glfaces);
+}
+
diff --git a/code/bspc/l_bsp_ent.c b/code/bspc/l_bsp_ent.c
index 8260179..0cc8f8e 100755
--- a/code/bspc/l_bsp_ent.c
+++ b/code/bspc/l_bsp_ent.c
@@ -1,180 +1,180 @@
-/*
-===========================================================================
-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 "l_cmd.h"
-#include "l_math.h"
-#include "l_mem.h"
-#include "l_log.h"
-#include "../botlib/l_script.h"
-#include "l_bsp_ent.h"
-
-#define MAX_KEY 32
-#define MAX_VALUE 1024
-
-int num_entities;
-entity_t entities[MAX_MAP_ENTITIES];
-
-void StripTrailing(char *e)
-{
- char *s;
-
- s = e + strlen(e)-1;
- while (s >= e && *s <= 32)
- {
- *s = 0;
- s--;
- }
-}
-
-/*
-=================
-ParseEpair
-=================
-*/
-epair_t *ParseEpair(script_t *script)
-{
- epair_t *e;
- token_t token;
-
- e = GetMemory(sizeof(epair_t));
- memset (e, 0, sizeof(epair_t));
-
- PS_ExpectAnyToken(script, &token);
- StripDoubleQuotes(token.string);
- if (strlen(token.string) >= MAX_KEY-1)
- Error ("ParseEpair: token %s too long", token.string);
- e->key = copystring(token.string);
- PS_ExpectAnyToken(script, &token);
- StripDoubleQuotes(token.string);
- if (strlen(token.string) >= MAX_VALUE-1)
- Error ("ParseEpair: token %s too long", token.string);
- e->value = copystring(token.string);
-
- // strip trailing spaces
- StripTrailing(e->key);
- StripTrailing(e->value);
-
- return e;
-} //end of the function ParseEpair
-
-
-/*
-================
-ParseEntity
-================
-*/
-qboolean ParseEntity(script_t *script)
-{
- epair_t *e;
- entity_t *mapent;
- token_t token;
-
- if (!PS_ReadToken(script, &token))
- return false;
-
- if (strcmp(token.string, "{"))
- Error ("ParseEntity: { not found");
-
- if (num_entities == MAX_MAP_ENTITIES)
- Error ("num_entities == MAX_MAP_ENTITIES");
-
- mapent = &entities[num_entities];
- num_entities++;
-
- do
- {
- if (!PS_ReadToken(script, &token))
- Error ("ParseEntity: EOF without closing brace");
- if (!strcmp(token.string, "}") )
- break;
- PS_UnreadLastToken(script);
- e = ParseEpair(script);
- e->next = mapent->epairs;
- mapent->epairs = e;
- } while (1);
-
- return true;
-} //end of the function ParseEntity
-
-void PrintEntity (entity_t *ent)
-{
- epair_t *ep;
-
- printf ("------- entity %p -------\n", ent);
- for (ep=ent->epairs ; ep ; ep=ep->next)
- {
- printf ("%s = %s\n", ep->key, ep->value);
- }
-
-}
-
-void SetKeyValue (entity_t *ent, char *key, char *value)
-{
- epair_t *ep;
-
- for (ep=ent->epairs ; ep ; ep=ep->next)
- if (!strcmp (ep->key, key) )
- {
- FreeMemory(ep->value);
- ep->value = copystring(value);
- return;
- }
- ep = GetMemory(sizeof(*ep));
- ep->next = ent->epairs;
- ent->epairs = ep;
- ep->key = copystring(key);
- ep->value = copystring(value);
-}
-
-char *ValueForKey (entity_t *ent, char *key)
-{
- epair_t *ep;
-
- for (ep=ent->epairs ; ep ; ep=ep->next)
- if (!strcmp (ep->key, key) )
- return ep->value;
- return "";
-}
-
-vec_t FloatForKey (entity_t *ent, char *key)
-{
- char *k;
-
- k = ValueForKey (ent, key);
- return atof(k);
-}
-
-void GetVectorForKey (entity_t *ent, char *key, vec3_t vec)
-{
- char *k;
- double v1, v2, v3;
-
- k = ValueForKey (ent, key);
-// scanf into doubles, then assign, so it is vec_t size independent
- v1 = v2 = v3 = 0;
- sscanf (k, "%lf %lf %lf", &v1, &v2, &v3);
- vec[0] = v1;
- vec[1] = v2;
- vec[2] = v3;
-}
-
-
+/*
+===========================================================================
+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 "l_cmd.h"
+#include "l_math.h"
+#include "l_mem.h"
+#include "l_log.h"
+#include "../botlib/l_script.h"
+#include "l_bsp_ent.h"
+
+#define MAX_KEY 32
+#define MAX_VALUE 1024
+
+int num_entities;
+entity_t entities[MAX_MAP_ENTITIES];
+
+void StripTrailing(char *e)
+{
+ char *s;
+
+ s = e + strlen(e)-1;
+ while (s >= e && *s <= 32)
+ {
+ *s = 0;
+ s--;
+ }
+}
+
+/*
+=================
+ParseEpair
+=================
+*/
+epair_t *ParseEpair(script_t *script)
+{
+ epair_t *e;
+ token_t token;
+
+ e = GetMemory(sizeof(epair_t));
+ memset (e, 0, sizeof(epair_t));
+
+ PS_ExpectAnyToken(script, &token);
+ StripDoubleQuotes(token.string);
+ if (strlen(token.string) >= MAX_KEY-1)
+ Error ("ParseEpair: token %s too long", token.string);
+ e->key = copystring(token.string);
+ PS_ExpectAnyToken(script, &token);
+ StripDoubleQuotes(token.string);
+ if (strlen(token.string) >= MAX_VALUE-1)
+ Error ("ParseEpair: token %s too long", token.string);
+ e->value = copystring(token.string);
+
+ // strip trailing spaces
+ StripTrailing(e->key);
+ StripTrailing(e->value);
+
+ return e;
+} //end of the function ParseEpair
+
+
+/*
+================
+ParseEntity
+================
+*/
+qboolean ParseEntity(script_t *script)
+{
+ epair_t *e;
+ entity_t *mapent;
+ token_t token;
+
+ if (!PS_ReadToken(script, &token))
+ return false;
+
+ if (strcmp(token.string, "{"))
+ Error ("ParseEntity: { not found");
+
+ if (num_entities == MAX_MAP_ENTITIES)
+ Error ("num_entities == MAX_MAP_ENTITIES");
+
+ mapent = &entities[num_entities];
+ num_entities++;
+
+ do
+ {
+ if (!PS_ReadToken(script, &token))
+ Error ("ParseEntity: EOF without closing brace");
+ if (!strcmp(token.string, "}") )
+ break;
+ PS_UnreadLastToken(script);
+ e = ParseEpair(script);
+ e->next = mapent->epairs;
+ mapent->epairs = e;
+ } while (1);
+
+ return true;
+} //end of the function ParseEntity
+
+void PrintEntity (entity_t *ent)
+{
+ epair_t *ep;
+
+ printf ("------- entity %p -------\n", ent);
+ for (ep=ent->epairs ; ep ; ep=ep->next)
+ {
+ printf ("%s = %s\n", ep->key, ep->value);
+ }
+
+}
+
+void SetKeyValue (entity_t *ent, char *key, char *value)
+{
+ epair_t *ep;
+
+ for (ep=ent->epairs ; ep ; ep=ep->next)
+ if (!strcmp (ep->key, key) )
+ {
+ FreeMemory(ep->value);
+ ep->value = copystring(value);
+ return;
+ }
+ ep = GetMemory(sizeof(*ep));
+ ep->next = ent->epairs;
+ ent->epairs = ep;
+ ep->key = copystring(key);
+ ep->value = copystring(value);
+}
+
+char *ValueForKey (entity_t *ent, char *key)
+{
+ epair_t *ep;
+
+ for (ep=ent->epairs ; ep ; ep=ep->next)
+ if (!strcmp (ep->key, key) )
+ return ep->value;
+ return "";
+}
+
+vec_t FloatForKey (entity_t *ent, char *key)
+{
+ char *k;
+
+ k = ValueForKey (ent, key);
+ return atof(k);
+}
+
+void GetVectorForKey (entity_t *ent, char *key, vec3_t vec)
+{
+ char *k;
+ double v1, v2, v3;
+
+ k = ValueForKey (ent, key);
+// scanf into doubles, then assign, so it is vec_t size independent
+ v1 = v2 = v3 = 0;
+ sscanf (k, "%lf %lf %lf", &v1, &v2, &v3);
+ vec[0] = v1;
+ vec[1] = v2;
+ vec[2] = v3;
+}
+
+
diff --git a/code/bspc/l_bsp_ent.h b/code/bspc/l_bsp_ent.h
index 05dd162..461b91c 100755
--- a/code/bspc/l_bsp_ent.h
+++ b/code/bspc/l_bsp_ent.h
@@ -1,58 +1,58 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-
-#ifndef MAX_MAP_ENTITIES
-#define MAX_MAP_ENTITIES 2048
-#endif
-
-typedef struct epair_s
-{
- struct epair_s *next;
- char *key;
- char *value;
-} epair_t;
-
-typedef struct
-{
- vec3_t origin;
- int firstbrush;
- int numbrushes;
- epair_t *epairs;
- // only valid for func_areaportals
- int areaportalnum;
- int portalareas[2];
- int modelnum; //for bsp 2 map conversion
- qboolean wasdetail; //for SIN
-} entity_t;
-
-extern int num_entities;
-extern entity_t entities[MAX_MAP_ENTITIES];
-
-void StripTrailing(char *e);
-void SetKeyValue(entity_t *ent, char *key, char *value);
-char *ValueForKey(entity_t *ent, char *key); // will return "" if not present
-vec_t FloatForKey(entity_t *ent, char *key);
-void GetVectorForKey(entity_t *ent, char *key, vec3_t vec);
-qboolean ParseEntity(script_t *script);
-epair_t *ParseEpair(script_t *script);
-void PrintEntity(entity_t *ent);
-
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+#ifndef MAX_MAP_ENTITIES
+#define MAX_MAP_ENTITIES 2048
+#endif
+
+typedef struct epair_s
+{
+ struct epair_s *next;
+ char *key;
+ char *value;
+} epair_t;
+
+typedef struct
+{
+ vec3_t origin;
+ int firstbrush;
+ int numbrushes;
+ epair_t *epairs;
+ // only valid for func_areaportals
+ int areaportalnum;
+ int portalareas[2];
+ int modelnum; //for bsp 2 map conversion
+ qboolean wasdetail; //for SIN
+} entity_t;
+
+extern int num_entities;
+extern entity_t entities[MAX_MAP_ENTITIES];
+
+void StripTrailing(char *e);
+void SetKeyValue(entity_t *ent, char *key, char *value);
+char *ValueForKey(entity_t *ent, char *key); // will return "" if not present
+vec_t FloatForKey(entity_t *ent, char *key);
+void GetVectorForKey(entity_t *ent, char *key, vec3_t vec);
+qboolean ParseEntity(script_t *script);
+epair_t *ParseEpair(script_t *script);
+void PrintEntity(entity_t *ent);
+
diff --git a/code/bspc/l_bsp_hl.c b/code/bspc/l_bsp_hl.c
index 5b922b5..48cb7e8 100755
--- a/code/bspc/l_bsp_hl.c
+++ b/code/bspc/l_bsp_hl.c
@@ -1,888 +1,888 @@
-/*
-===========================================================================
-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 "l_cmd.h"
-#include "l_math.h"
-#include "l_mem.h"
-#include "l_log.h"
-#include "../botlib/l_script.h"
-#include "l_bsp_hl.h"
-#include "l_bsp_ent.h"
-
-//=============================================================================
-
-int hl_nummodels;
-hl_dmodel_t *hl_dmodels;//[HL_MAX_MAP_MODELS];
-int hl_dmodels_checksum;
-
-int hl_visdatasize;
-byte *hl_dvisdata;//[HL_MAX_MAP_VISIBILITY];
-int hl_dvisdata_checksum;
-
-int hl_lightdatasize;
-byte *hl_dlightdata;//[HL_MAX_MAP_LIGHTING];
-int hl_dlightdata_checksum;
-
-int hl_texdatasize;
-byte *hl_dtexdata;//[HL_MAX_MAP_MIPTEX]; // (dmiptexlump_t)
-int hl_dtexdata_checksum;
-
-int hl_entdatasize;
-char *hl_dentdata;//[HL_MAX_MAP_ENTSTRING];
-int hl_dentdata_checksum;
-
-int hl_numleafs;
-hl_dleaf_t *hl_dleafs;//[HL_MAX_MAP_LEAFS];
-int hl_dleafs_checksum;
-
-int hl_numplanes;
-hl_dplane_t *hl_dplanes;//[HL_MAX_MAP_PLANES];
-int hl_dplanes_checksum;
-
-int hl_numvertexes;
-hl_dvertex_t *hl_dvertexes;//[HL_MAX_MAP_VERTS];
-int hl_dvertexes_checksum;
-
-int hl_numnodes;
-hl_dnode_t *hl_dnodes;//[HL_MAX_MAP_NODES];
-int hl_dnodes_checksum;
-
-int hl_numtexinfo;
-hl_texinfo_t *hl_texinfo;//[HL_MAX_MAP_TEXINFO];
-int hl_texinfo_checksum;
-
-int hl_numfaces;
-hl_dface_t *hl_dfaces;//[HL_MAX_MAP_FACES];
-int hl_dfaces_checksum;
-
-int hl_numclipnodes;
-hl_dclipnode_t *hl_dclipnodes;//[HL_MAX_MAP_CLIPNODES];
-int hl_dclipnodes_checksum;
-
-int hl_numedges;
-hl_dedge_t *hl_dedges;//[HL_MAX_MAP_EDGES];
-int hl_dedges_checksum;
-
-int hl_nummarksurfaces;
-unsigned short *hl_dmarksurfaces;//[HL_MAX_MAP_MARKSURFACES];
-int hl_dmarksurfaces_checksum;
-
-int hl_numsurfedges;
-int *hl_dsurfedges;//[HL_MAX_MAP_SURFEDGES];
-int hl_dsurfedges_checksum;
-
-//int num_entities;
-//entity_t entities[HL_MAX_MAP_ENTITIES];
-
-
-//#ifdef //ME
-
-int hl_bspallocated = false;
-int hl_allocatedbspmem = 0;
-
-void HL_AllocMaxBSP(void)
-{
- //models
- hl_nummodels = 0;
- hl_dmodels = (hl_dmodel_t *) GetMemory(HL_MAX_MAP_MODELS * sizeof(hl_dmodel_t));
- hl_allocatedbspmem = HL_MAX_MAP_MODELS * sizeof(hl_dmodel_t);
- //visibility
- hl_visdatasize = 0;
- hl_dvisdata = (byte *) GetMemory(HL_MAX_MAP_VISIBILITY * sizeof(byte));
- hl_allocatedbspmem += HL_MAX_MAP_VISIBILITY * sizeof(byte);
- //light data
- hl_lightdatasize = 0;
- hl_dlightdata = (byte *) GetMemory(HL_MAX_MAP_LIGHTING * sizeof(byte));
- hl_allocatedbspmem += HL_MAX_MAP_LIGHTING * sizeof(byte);
- //texture data
- hl_texdatasize = 0;
- hl_dtexdata = (byte *) GetMemory(HL_MAX_MAP_MIPTEX * sizeof(byte)); // (dmiptexlump_t)
- hl_allocatedbspmem += HL_MAX_MAP_MIPTEX * sizeof(byte);
- //entities
- hl_entdatasize = 0;
- hl_dentdata = (char *) GetMemory(HL_MAX_MAP_ENTSTRING * sizeof(char));
- hl_allocatedbspmem += HL_MAX_MAP_ENTSTRING * sizeof(char);
- //leaves
- hl_numleafs = 0;
- hl_dleafs = (hl_dleaf_t *) GetMemory(HL_MAX_MAP_LEAFS * sizeof(hl_dleaf_t));
- hl_allocatedbspmem += HL_MAX_MAP_LEAFS * sizeof(hl_dleaf_t);
- //planes
- hl_numplanes = 0;
- hl_dplanes = (hl_dplane_t *) GetMemory(HL_MAX_MAP_PLANES * sizeof(hl_dplane_t));
- hl_allocatedbspmem += HL_MAX_MAP_PLANES * sizeof(hl_dplane_t);
- //vertexes
- hl_numvertexes = 0;
- hl_dvertexes = (hl_dvertex_t *) GetMemory(HL_MAX_MAP_VERTS * sizeof(hl_dvertex_t));
- hl_allocatedbspmem += HL_MAX_MAP_VERTS * sizeof(hl_dvertex_t);
- //nodes
- hl_numnodes = 0;
- hl_dnodes = (hl_dnode_t *) GetMemory(HL_MAX_MAP_NODES * sizeof(hl_dnode_t));
- hl_allocatedbspmem += HL_MAX_MAP_NODES * sizeof(hl_dnode_t);
- //texture info
- hl_numtexinfo = 0;
- hl_texinfo = (hl_texinfo_t *) GetMemory(HL_MAX_MAP_TEXINFO * sizeof(hl_texinfo_t));
- hl_allocatedbspmem += HL_MAX_MAP_TEXINFO * sizeof(hl_texinfo_t);
- //faces
- hl_numfaces = 0;
- hl_dfaces = (hl_dface_t *) GetMemory(HL_MAX_MAP_FACES * sizeof(hl_dface_t));
- hl_allocatedbspmem += HL_MAX_MAP_FACES * sizeof(hl_dface_t);
- //clip nodes
- hl_numclipnodes = 0;
- hl_dclipnodes = (hl_dclipnode_t *) GetMemory(HL_MAX_MAP_CLIPNODES * sizeof(hl_dclipnode_t));
- hl_allocatedbspmem += HL_MAX_MAP_CLIPNODES * sizeof(hl_dclipnode_t);
- //edges
- hl_numedges = 0;
- hl_dedges = (hl_dedge_t *) GetMemory(HL_MAX_MAP_EDGES * sizeof(hl_dedge_t));
- hl_allocatedbspmem += HL_MAX_MAP_EDGES, sizeof(hl_dedge_t);
- //mark surfaces
- hl_nummarksurfaces = 0;
- hl_dmarksurfaces = (unsigned short *) GetMemory(HL_MAX_MAP_MARKSURFACES * sizeof(unsigned short));
- hl_allocatedbspmem += HL_MAX_MAP_MARKSURFACES * sizeof(unsigned short);
- //surface edges
- hl_numsurfedges = 0;
- hl_dsurfedges = (int *) GetMemory(HL_MAX_MAP_SURFEDGES * sizeof(int));
- hl_allocatedbspmem += HL_MAX_MAP_SURFEDGES * sizeof(int);
- //print allocated memory
- Log_Print("allocated ");
- PrintMemorySize(hl_allocatedbspmem);
- Log_Print(" of BSP memory\n");
-} //end of the function HL_AllocMaxBSP
-
-void HL_FreeMaxBSP(void)
-{
- //models
- hl_nummodels = 0;
- FreeMemory(hl_dmodels);
- hl_dmodels = NULL;
- //visibility
- hl_visdatasize = 0;
- FreeMemory(hl_dvisdata);
- hl_dvisdata = NULL;
- //light data
- hl_lightdatasize = 0;
- FreeMemory(hl_dlightdata);
- hl_dlightdata = NULL;
- //texture data
- hl_texdatasize = 0;
- FreeMemory(hl_dtexdata);
- hl_dtexdata = NULL;
- //entities
- hl_entdatasize = 0;
- FreeMemory(hl_dentdata);
- hl_dentdata = NULL;
- //leaves
- hl_numleafs = 0;
- FreeMemory(hl_dleafs);
- hl_dleafs = NULL;
- //planes
- hl_numplanes = 0;
- FreeMemory(hl_dplanes);
- hl_dplanes = NULL;
- //vertexes
- hl_numvertexes = 0;
- FreeMemory(hl_dvertexes);
- hl_dvertexes = NULL;
- //nodes
- hl_numnodes = 0;
- FreeMemory(hl_dnodes);
- hl_dnodes = NULL;
- //texture info
- hl_numtexinfo = 0;
- FreeMemory(hl_texinfo);
- hl_texinfo = NULL;
- //faces
- hl_numfaces = 0;
- FreeMemory(hl_dfaces);
- hl_dfaces = NULL;
- //clip nodes
- hl_numclipnodes = 0;
- FreeMemory(hl_dclipnodes);
- hl_dclipnodes = NULL;
- //edges
- hl_numedges = 0;
- FreeMemory(hl_dedges);
- hl_dedges = NULL;
- //mark surfaces
- hl_nummarksurfaces = 0;
- FreeMemory(hl_dmarksurfaces);
- hl_dmarksurfaces = NULL;
- //surface edges
- hl_numsurfedges = 0;
- FreeMemory(hl_dsurfedges);
- hl_dsurfedges = NULL;
- //
- Log_Print("freed ");
- PrintMemorySize(hl_allocatedbspmem);
- Log_Print(" of BSP memory\n");
- hl_allocatedbspmem = 0;
-} //end of the function HL_FreeMaxBSP
-//#endif //ME
-
-/*
-===============
-FastChecksum
-===============
-*/
-
-int FastChecksum(void *buffer, int bytes)
-{
- int checksum = 0;
-
- while( bytes-- )
- checksum = (checksum << 4) ^ *((char *)buffer)++;
-
- return checksum;
-}
-
-/*
-===============
-HL_CompressVis
-===============
-*/
-int HL_CompressVis(byte *vis, byte *dest)
-{
- int j;
- int rep;
- int visrow;
- byte *dest_p;
-
- dest_p = dest;
- visrow = (hl_numleafs + 7)>>3;
-
- for (j=0 ; j<visrow ; j++)
- {
- *dest_p++ = vis[j];
- if (vis[j])
- continue;
-
- rep = 1;
- for ( j++; j<visrow ; j++)
- if (vis[j] || rep == 255)
- break;
- else
- rep++;
- *dest_p++ = rep;
- j--;
- }
-
- return dest_p - dest;
-}
-
-
-/*
-===================
-HL_DecompressVis
-===================
-*/
-void HL_DecompressVis (byte *in, byte *decompressed)
-{
- int c;
- byte *out;
- int row;
-
- row = (hl_numleafs+7)>>3;
- out = decompressed;
-
- do
- {
- if (*in)
- {
- *out++ = *in++;
- continue;
- }
-
- c = in[1];
- in += 2;
- while (c)
- {
- *out++ = 0;
- c--;
- }
- } while (out - decompressed < row);
-}
-
-//=============================================================================
-
-/*
-=============
-HL_SwapBSPFile
-
-Byte swaps all data in a bsp file.
-=============
-*/
-void HL_SwapBSPFile (qboolean todisk)
-{
- int i, j, c;
- hl_dmodel_t *d;
- hl_dmiptexlump_t *mtl;
-
-
-// models
- for (i = 0; i < hl_nummodels; i++)
- {
- d = &hl_dmodels[i];
-
- for (j = 0; j < HL_MAX_MAP_HULLS; j++)
- d->headnode[j] = LittleLong(d->headnode[j]);
-
- d->visleafs = LittleLong(d->visleafs);
- d->firstface = LittleLong(d->firstface);
- d->numfaces = LittleLong(d->numfaces);
-
- for (j = 0; j < 3; j++)
- {
- d->mins[j] = LittleFloat(d->mins[j]);
- d->maxs[j] = LittleFloat(d->maxs[j]);
- d->origin[j] = LittleFloat(d->origin[j]);
- }
- }
-
-//
-// vertexes
-//
- for (i = 0; i < hl_numvertexes; i++)
- {
- for (j = 0; j < 3; j++)
- hl_dvertexes[i].point[j] = LittleFloat (hl_dvertexes[i].point[j]);
- }
-
-//
-// planes
-//
- for (i=0 ; i<hl_numplanes ; i++)
- {
- for (j=0 ; j<3 ; j++)
- hl_dplanes[i].normal[j] = LittleFloat (hl_dplanes[i].normal[j]);
- hl_dplanes[i].dist = LittleFloat (hl_dplanes[i].dist);
- hl_dplanes[i].type = LittleLong (hl_dplanes[i].type);
- }
-
-//
-// texinfos
-//
- for (i=0 ; i<hl_numtexinfo ; i++)
- {
- for (j=0 ; j<8 ; j++)
- hl_texinfo[i].vecs[0][j] = LittleFloat (hl_texinfo[i].vecs[0][j]);
- hl_texinfo[i].miptex = LittleLong (hl_texinfo[i].miptex);
- hl_texinfo[i].flags = LittleLong (hl_texinfo[i].flags);
- }
-
-//
-// faces
-//
- for (i=0 ; i<hl_numfaces ; i++)
- {
- hl_dfaces[i].texinfo = LittleShort (hl_dfaces[i].texinfo);
- hl_dfaces[i].planenum = LittleShort (hl_dfaces[i].planenum);
- hl_dfaces[i].side = LittleShort (hl_dfaces[i].side);
- hl_dfaces[i].lightofs = LittleLong (hl_dfaces[i].lightofs);
- hl_dfaces[i].firstedge = LittleLong (hl_dfaces[i].firstedge);
- hl_dfaces[i].numedges = LittleShort (hl_dfaces[i].numedges);
- }
-
-//
-// nodes
-//
- for (i=0 ; i<hl_numnodes ; i++)
- {
- hl_dnodes[i].planenum = LittleLong (hl_dnodes[i].planenum);
- for (j=0 ; j<3 ; j++)
- {
- hl_dnodes[i].mins[j] = LittleShort (hl_dnodes[i].mins[j]);
- hl_dnodes[i].maxs[j] = LittleShort (hl_dnodes[i].maxs[j]);
- }
- hl_dnodes[i].children[0] = LittleShort (hl_dnodes[i].children[0]);
- hl_dnodes[i].children[1] = LittleShort (hl_dnodes[i].children[1]);
- hl_dnodes[i].firstface = LittleShort (hl_dnodes[i].firstface);
- hl_dnodes[i].numfaces = LittleShort (hl_dnodes[i].numfaces);
- }
-
-//
-// leafs
-//
- for (i=0 ; i<hl_numleafs ; i++)
- {
- hl_dleafs[i].contents = LittleLong (hl_dleafs[i].contents);
- for (j=0 ; j<3 ; j++)
- {
- hl_dleafs[i].mins[j] = LittleShort (hl_dleafs[i].mins[j]);
- hl_dleafs[i].maxs[j] = LittleShort (hl_dleafs[i].maxs[j]);
- }
-
- hl_dleafs[i].firstmarksurface = LittleShort (hl_dleafs[i].firstmarksurface);
- hl_dleafs[i].nummarksurfaces = LittleShort (hl_dleafs[i].nummarksurfaces);
- hl_dleafs[i].visofs = LittleLong (hl_dleafs[i].visofs);
- }
-
-//
-// clipnodes
-//
- for (i=0 ; i<hl_numclipnodes ; i++)
- {
- hl_dclipnodes[i].planenum = LittleLong (hl_dclipnodes[i].planenum);
- hl_dclipnodes[i].children[0] = LittleShort (hl_dclipnodes[i].children[0]);
- hl_dclipnodes[i].children[1] = LittleShort (hl_dclipnodes[i].children[1]);
- }
-
-//
-// miptex
-//
- if (hl_texdatasize)
- {
- mtl = (hl_dmiptexlump_t *)hl_dtexdata;
- if (todisk)
- c = mtl->nummiptex;
- else
- c = LittleLong(mtl->nummiptex);
- mtl->nummiptex = LittleLong (mtl->nummiptex);
- for (i=0 ; i<c ; i++)
- mtl->dataofs[i] = LittleLong(mtl->dataofs[i]);
- }
-
-//
-// marksurfaces
-//
- for (i=0 ; i<hl_nummarksurfaces ; i++)
- hl_dmarksurfaces[i] = LittleShort (hl_dmarksurfaces[i]);
-
-//
-// surfedges
-//
- for (i=0 ; i<hl_numsurfedges ; i++)
- hl_dsurfedges[i] = LittleLong (hl_dsurfedges[i]);
-
-//
-// edges
-//
- for (i=0 ; i<hl_numedges ; i++)
- {
- hl_dedges[i].v[0] = LittleShort (hl_dedges[i].v[0]);
- hl_dedges[i].v[1] = LittleShort (hl_dedges[i].v[1]);
- }
-} //end of the function HL_SwapBSPFile
-
-
-hl_dheader_t *hl_header;
-int hl_fileLength;
-
-int HL_CopyLump (int lump, void *dest, int size, int maxsize)
-{
- int length, ofs;
-
- length = hl_header->lumps[lump].filelen;
- ofs = hl_header->lumps[lump].fileofs;
-
- if (length % size) {
- Error ("LoadBSPFile: odd lump size");
- }
- // somehow things got out of range
- if ((length/size) > maxsize) {
- printf("WARNING: exceeded max size for lump %d size %d > maxsize %d\n", lump, (length/size), maxsize);
- length = maxsize * size;
- }
- if ( ofs + length > hl_fileLength ) {
- printf("WARNING: exceeded file length for lump %d\n", lump);
- length = hl_fileLength - ofs;
- if ( length <= 0 ) {
- return 0;
- }
- }
-
- memcpy (dest, (byte *)hl_header + ofs, length);
-
- return length / size;
-}
-
-/*
-=============
-HL_LoadBSPFile
-=============
-*/
-void HL_LoadBSPFile (char *filename, int offset, int length)
-{
- int i;
-
-//
-// load the file header
-//
- hl_fileLength = LoadFile (filename, (void **)&hl_header, offset, length);
-
-// swap the header
- for (i=0 ; i< sizeof(hl_dheader_t)/4 ; i++)
- ((int *)hl_header)[i] = LittleLong ( ((int *)hl_header)[i]);
-
- if (hl_header->version != HL_BSPVERSION)
- Error ("%s is version %i, not %i", filename, hl_header->version, HL_BSPVERSION);
-
- hl_nummodels = HL_CopyLump (HL_LUMP_MODELS, hl_dmodels, sizeof(hl_dmodel_t), HL_MAX_MAP_MODELS );
- hl_numvertexes = HL_CopyLump (HL_LUMP_VERTEXES, hl_dvertexes, sizeof(hl_dvertex_t), HL_MAX_MAP_VERTS );
- hl_numplanes = HL_CopyLump (HL_LUMP_PLANES, hl_dplanes, sizeof(hl_dplane_t), HL_MAX_MAP_PLANES );
- hl_numleafs = HL_CopyLump (HL_LUMP_LEAFS, hl_dleafs, sizeof(hl_dleaf_t), HL_MAX_MAP_LEAFS );
- hl_numnodes = HL_CopyLump (HL_LUMP_NODES, hl_dnodes, sizeof(hl_dnode_t), HL_MAX_MAP_NODES );
- hl_numtexinfo = HL_CopyLump (HL_LUMP_TEXINFO, hl_texinfo, sizeof(hl_texinfo_t), HL_MAX_MAP_TEXINFO );
- hl_numclipnodes = HL_CopyLump (HL_LUMP_CLIPNODES, hl_dclipnodes, sizeof(hl_dclipnode_t), HL_MAX_MAP_CLIPNODES );
- hl_numfaces = HL_CopyLump (HL_LUMP_FACES, hl_dfaces, sizeof(hl_dface_t), HL_MAX_MAP_FACES );
- hl_nummarksurfaces = HL_CopyLump (HL_LUMP_MARKSURFACES, hl_dmarksurfaces, sizeof(hl_dmarksurfaces[0]), HL_MAX_MAP_MARKSURFACES );
- hl_numsurfedges = HL_CopyLump (HL_LUMP_SURFEDGES, hl_dsurfedges, sizeof(hl_dsurfedges[0]), HL_MAX_MAP_SURFEDGES );
- hl_numedges = HL_CopyLump (HL_LUMP_EDGES, hl_dedges, sizeof(hl_dedge_t), HL_MAX_MAP_EDGES );
-
- hl_texdatasize = HL_CopyLump (HL_LUMP_TEXTURES, hl_dtexdata, 1, HL_MAX_MAP_MIPTEX );
- hl_visdatasize = HL_CopyLump (HL_LUMP_VISIBILITY, hl_dvisdata, 1, HL_MAX_MAP_VISIBILITY );
- hl_lightdatasize = HL_CopyLump (HL_LUMP_LIGHTING, hl_dlightdata, 1, HL_MAX_MAP_LIGHTING );
- hl_entdatasize = HL_CopyLump (HL_LUMP_ENTITIES, hl_dentdata, 1, HL_MAX_MAP_ENTSTRING );
-
- FreeMemory(hl_header); // everything has been copied out
-
-//
-// swap everything
-//
- HL_SwapBSPFile (false);
-
- hl_dmodels_checksum = FastChecksum( hl_dmodels, hl_nummodels*sizeof(hl_dmodels[0]) );
- hl_dvertexes_checksum = FastChecksum( hl_dvertexes, hl_numvertexes*sizeof(hl_dvertexes[0]) );
- hl_dplanes_checksum = FastChecksum( hl_dplanes, hl_numplanes*sizeof(hl_dplanes[0]) );
- hl_dleafs_checksum = FastChecksum( hl_dleafs, hl_numleafs*sizeof(hl_dleafs[0]) );
- hl_dnodes_checksum = FastChecksum( hl_dnodes, hl_numnodes*sizeof(hl_dnodes[0]) );
- hl_texinfo_checksum = FastChecksum( hl_texinfo, hl_numtexinfo*sizeof(hl_texinfo[0]) );
- hl_dclipnodes_checksum = FastChecksum( hl_dclipnodes, hl_numclipnodes*sizeof(hl_dclipnodes[0]) );
- hl_dfaces_checksum = FastChecksum( hl_dfaces, hl_numfaces*sizeof(hl_dfaces[0]) );
- hl_dmarksurfaces_checksum = FastChecksum( hl_dmarksurfaces, hl_nummarksurfaces*sizeof(hl_dmarksurfaces[0]) );
- hl_dsurfedges_checksum = FastChecksum( hl_dsurfedges, hl_numsurfedges*sizeof(hl_dsurfedges[0]) );
- hl_dedges_checksum = FastChecksum( hl_dedges, hl_numedges*sizeof(hl_dedges[0]) );
- hl_dtexdata_checksum = FastChecksum( hl_dtexdata, hl_numedges*sizeof(hl_dtexdata[0]) );
- hl_dvisdata_checksum = FastChecksum( hl_dvisdata, hl_visdatasize*sizeof(hl_dvisdata[0]) );
- hl_dlightdata_checksum = FastChecksum( hl_dlightdata, hl_lightdatasize*sizeof(hl_dlightdata[0]) );
- hl_dentdata_checksum = FastChecksum( hl_dentdata, hl_entdatasize*sizeof(hl_dentdata[0]) );
-
-}
-
-//============================================================================
-
-FILE *wadfile;
-hl_dheader_t outheader;
-
-void HL_AddLump (int lumpnum, void *data, int len)
-{
- hl_lump_t *lump;
-
- lump = &hl_header->lumps[lumpnum];
-
- lump->fileofs = LittleLong( ftell(wadfile) );
- lump->filelen = LittleLong(len);
- SafeWrite (wadfile, data, (len+3)&~3);
-}
-
-/*
-=============
-HL_WriteBSPFile
-
-Swaps the bsp file in place, so it should not be referenced again
-=============
-*/
-void HL_WriteBSPFile (char *filename)
-{
- hl_header = &outheader;
- memset (hl_header, 0, sizeof(hl_dheader_t));
-
- HL_SwapBSPFile (true);
-
- hl_header->version = LittleLong (HL_BSPVERSION);
-
- wadfile = SafeOpenWrite (filename);
- SafeWrite (wadfile, hl_header, sizeof(hl_dheader_t)); // overwritten later
-
- HL_AddLump (HL_LUMP_PLANES, hl_dplanes, hl_numplanes*sizeof(hl_dplane_t));
- HL_AddLump (HL_LUMP_LEAFS, hl_dleafs, hl_numleafs*sizeof(hl_dleaf_t));
- HL_AddLump (HL_LUMP_VERTEXES, hl_dvertexes, hl_numvertexes*sizeof(hl_dvertex_t));
- HL_AddLump (HL_LUMP_NODES, hl_dnodes, hl_numnodes*sizeof(hl_dnode_t));
- HL_AddLump (HL_LUMP_TEXINFO, hl_texinfo, hl_numtexinfo*sizeof(hl_texinfo_t));
- HL_AddLump (HL_LUMP_FACES, hl_dfaces, hl_numfaces*sizeof(hl_dface_t));
- HL_AddLump (HL_LUMP_CLIPNODES, hl_dclipnodes, hl_numclipnodes*sizeof(hl_dclipnode_t));
- HL_AddLump (HL_LUMP_MARKSURFACES, hl_dmarksurfaces, hl_nummarksurfaces*sizeof(hl_dmarksurfaces[0]));
- HL_AddLump (HL_LUMP_SURFEDGES, hl_dsurfedges, hl_numsurfedges*sizeof(hl_dsurfedges[0]));
- HL_AddLump (HL_LUMP_EDGES, hl_dedges, hl_numedges*sizeof(hl_dedge_t));
- HL_AddLump (HL_LUMP_MODELS, hl_dmodels, hl_nummodels*sizeof(hl_dmodel_t));
-
- HL_AddLump (HL_LUMP_LIGHTING, hl_dlightdata, hl_lightdatasize);
- HL_AddLump (HL_LUMP_VISIBILITY, hl_dvisdata, hl_visdatasize);
- HL_AddLump (HL_LUMP_ENTITIES, hl_dentdata, hl_entdatasize);
- HL_AddLump (HL_LUMP_TEXTURES, hl_dtexdata, hl_texdatasize);
-
- fseek (wadfile, 0, SEEK_SET);
- SafeWrite (wadfile, hl_header, sizeof(hl_dheader_t));
- fclose (wadfile);
-}
-
-//============================================================================
-
-#define ENTRIES(a) (sizeof(a)/sizeof(*(a)))
-#define ENTRYSIZE(a) (sizeof(*(a)))
-
-ArrayUsage( char *szItem, int items, int maxitems, int itemsize )
-{
- float percentage = maxitems ? items * 100.0 / maxitems : 0.0;
-
- qprintf("%-12s %7i/%-7i %7i/%-7i (%4.1f%%)",
- szItem, items, maxitems, items * itemsize, maxitems * itemsize, percentage );
- if ( percentage > 80.0 )
- qprintf( "VERY FULL!\n" );
- else if ( percentage > 95.0 )
- qprintf( "SIZE DANGER!\n" );
- else if ( percentage > 99.9 )
- qprintf( "SIZE OVERFLOW!!!\n" );
- else
- qprintf( "\n" );
- return items * itemsize;
-}
-
-GlobUsage( char *szItem, int itemstorage, int maxstorage )
-{
- float percentage = maxstorage ? itemstorage * 100.0 / maxstorage : 0.0;
-
- qprintf("%-12s [variable] %7i/%-7i (%4.1f%%)",
- szItem, itemstorage, maxstorage, percentage );
- if ( percentage > 80.0 )
- qprintf( "VERY FULL!\n" );
- else if ( percentage > 95.0 )
- qprintf( "SIZE DANGER!\n" );
- else if ( percentage > 99.9 )
- qprintf( "SIZE OVERFLOW!!!\n" );
- else
- qprintf( "\n" );
- return itemstorage;
-}
-
-/*
-=============
-HL_PrintBSPFileSizes
-
-Dumps info about current file
-=============
-*/
-void HL_PrintBSPFileSizes(void)
-{
- int numtextures = hl_texdatasize ? ((hl_dmiptexlump_t*)hl_dtexdata)->nummiptex : 0;
- int totalmemory = 0;
-
- qprintf("\n");
- qprintf("Object names Objects/Maxobjs Memory / Maxmem Fullness\n" );
- qprintf("------------ --------------- --------------- --------\n" );
-
- totalmemory += ArrayUsage( "models", hl_nummodels, ENTRIES(hl_dmodels), ENTRYSIZE(hl_dmodels) );
- totalmemory += ArrayUsage( "planes", hl_numplanes, ENTRIES(hl_dplanes), ENTRYSIZE(hl_dplanes) );
- totalmemory += ArrayUsage( "vertexes", hl_numvertexes, ENTRIES(hl_dvertexes), ENTRYSIZE(hl_dvertexes) );
- totalmemory += ArrayUsage( "nodes", hl_numnodes, ENTRIES(hl_dnodes), ENTRYSIZE(hl_dnodes) );
- totalmemory += ArrayUsage( "texinfos", hl_numtexinfo, ENTRIES(hl_texinfo), ENTRYSIZE(hl_texinfo) );
- totalmemory += ArrayUsage( "faces", hl_numfaces, ENTRIES(hl_dfaces), ENTRYSIZE(hl_dfaces) );
- totalmemory += ArrayUsage( "clipnodes", hl_numclipnodes, ENTRIES(hl_dclipnodes), ENTRYSIZE(hl_dclipnodes) );
- totalmemory += ArrayUsage( "leaves", hl_numleafs, ENTRIES(hl_dleafs), ENTRYSIZE(hl_dleafs) );
- totalmemory += ArrayUsage( "marksurfaces",hl_nummarksurfaces,ENTRIES(hl_dmarksurfaces),ENTRYSIZE(hl_dmarksurfaces) );
- totalmemory += ArrayUsage( "surfedges", hl_numsurfedges, ENTRIES(hl_dsurfedges), ENTRYSIZE(hl_dsurfedges) );
- totalmemory += ArrayUsage( "edges", hl_numedges, ENTRIES(hl_dedges), ENTRYSIZE(hl_dedges) );
-
- totalmemory += GlobUsage( "texdata", hl_texdatasize, sizeof(hl_dtexdata) );
- totalmemory += GlobUsage( "lightdata", hl_lightdatasize, sizeof(hl_dlightdata) );
- totalmemory += GlobUsage( "visdata", hl_visdatasize, sizeof(hl_dvisdata) );
- totalmemory += GlobUsage( "entdata", hl_entdatasize, sizeof(hl_dentdata) );
-
- qprintf( "=== Total BSP file data space used: %d bytes ===\n\n", totalmemory );
-}
-
-
-
-/*
-=================
-ParseEpair
-=================
-* /
-epair_t *ParseEpair (void)
-{
- epair_t *e;
-
- e = malloc (sizeof(epair_t));
- memset (e, 0, sizeof(epair_t));
-
- if (strlen(token) >= MAX_KEY-1)
- Error ("ParseEpar: token too long");
- e->key = copystring(token);
- GetToken (false);
- if (strlen(token) >= MAX_VALUE-1)
- Error ("ParseEpar: token too long");
- e->value = copystring(token);
-
- return e;
-} //*/
-
-
-/*
-================
-ParseEntity
-================
-* /
-qboolean ParseEntity (void)
-{
- epair_t *e;
- entity_t *mapent;
-
- if (!GetToken (true))
- return false;
-
- if (strcmp (token, "{") )
- Error ("ParseEntity: { not found");
-
- if (num_entities == HL_MAX_MAP_ENTITIES)
- Error ("num_entities == HL_MAX_MAP_ENTITIES");
-
- mapent = &entities[num_entities];
- num_entities++;
-
- do
- {
- if (!GetToken (true))
- Error ("ParseEntity: EOF without closing brace");
- if (!strcmp (token, "}") )
- break;
- e = ParseEpair ();
- e->next = mapent->epairs;
- mapent->epairs = e;
- } while (1);
-
- return true;
-} //*/
-
-/*
-================
-ParseEntities
-
-Parses the dentdata string into entities
-================
-*/
-void HL_ParseEntities (void)
-{
- script_t *script;
-
- num_entities = 0;
- script = LoadScriptMemory(hl_dentdata, hl_entdatasize, "*Half-Life bsp file");
- SetScriptFlags(script, SCFL_NOSTRINGWHITESPACES |
- SCFL_NOSTRINGESCAPECHARS);
-
- while(ParseEntity(script))
- {
- } //end while
-
- FreeScript(script);
-} //end of the function HL_ParseEntities
-
-
-/*
-================
-UnparseEntities
-
-Generates the dentdata string from all the entities
-================
-*/
-void HL_UnparseEntities (void)
-{
- char *buf, *end;
- epair_t *ep;
- char line[2048];
- int i;
-
- buf = hl_dentdata;
- end = buf;
- *end = 0;
-
- for (i=0 ; i<num_entities ; i++)
- {
- ep = entities[i].epairs;
- if (!ep)
- continue; // ent got removed
-
- strcat (end,"{\n");
- end += 2;
-
- for (ep = entities[i].epairs ; ep ; ep=ep->next)
- {
- sprintf (line, "\"%s\" \"%s\"\n", ep->key, ep->value);
- strcat (end, line);
- end += strlen(line);
- }
- strcat (end,"}\n");
- end += 2;
-
- if (end > buf + HL_MAX_MAP_ENTSTRING)
- Error ("Entity text too long");
- }
- hl_entdatasize = end - buf + 1;
-} //end of the function HL_UnparseEntities
-
-
-/*
-void SetKeyValue (entity_t *ent, char *key, char *value)
-{
- epair_t *ep;
-
- for (ep=ent->epairs ; ep ; ep=ep->next)
- if (!strcmp (ep->key, key) )
- {
- free (ep->value);
- ep->value = copystring(value);
- return;
- }
- ep = malloc (sizeof(*ep));
- ep->next = ent->epairs;
- ent->epairs = ep;
- ep->key = copystring(key);
- ep->value = copystring(value);
-}
-
-char *ValueForKey (entity_t *ent, char *key)
-{
- epair_t *ep;
-
- for (ep=ent->epairs ; ep ; ep=ep->next)
- if (!strcmp (ep->key, key) )
- return ep->value;
- return "";
-}
-
-vec_t FloatForKey (entity_t *ent, char *key)
-{
- char *k;
-
- k = ValueForKey (ent, key);
- return atof(k);
-}
-
-void GetVectorForKey (entity_t *ent, char *key, vec3_t vec)
-{
- char *k;
- double v1, v2, v3;
-
- k = ValueForKey (ent, key);
-// scanf into doubles, then assign, so it is vec_t size independent
- v1 = v2 = v3 = 0;
- sscanf (k, "%lf %lf %lf", &v1, &v2, &v3);
- vec[0] = v1;
- vec[1] = v2;
- vec[2] = v3;
-} //*/
+/*
+===========================================================================
+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 "l_cmd.h"
+#include "l_math.h"
+#include "l_mem.h"
+#include "l_log.h"
+#include "../botlib/l_script.h"
+#include "l_bsp_hl.h"
+#include "l_bsp_ent.h"
+
+//=============================================================================
+
+int hl_nummodels;
+hl_dmodel_t *hl_dmodels;//[HL_MAX_MAP_MODELS];
+int hl_dmodels_checksum;
+
+int hl_visdatasize;
+byte *hl_dvisdata;//[HL_MAX_MAP_VISIBILITY];
+int hl_dvisdata_checksum;
+
+int hl_lightdatasize;
+byte *hl_dlightdata;//[HL_MAX_MAP_LIGHTING];
+int hl_dlightdata_checksum;
+
+int hl_texdatasize;
+byte *hl_dtexdata;//[HL_MAX_MAP_MIPTEX]; // (dmiptexlump_t)
+int hl_dtexdata_checksum;
+
+int hl_entdatasize;
+char *hl_dentdata;//[HL_MAX_MAP_ENTSTRING];
+int hl_dentdata_checksum;
+
+int hl_numleafs;
+hl_dleaf_t *hl_dleafs;//[HL_MAX_MAP_LEAFS];
+int hl_dleafs_checksum;
+
+int hl_numplanes;
+hl_dplane_t *hl_dplanes;//[HL_MAX_MAP_PLANES];
+int hl_dplanes_checksum;
+
+int hl_numvertexes;
+hl_dvertex_t *hl_dvertexes;//[HL_MAX_MAP_VERTS];
+int hl_dvertexes_checksum;
+
+int hl_numnodes;
+hl_dnode_t *hl_dnodes;//[HL_MAX_MAP_NODES];
+int hl_dnodes_checksum;
+
+int hl_numtexinfo;
+hl_texinfo_t *hl_texinfo;//[HL_MAX_MAP_TEXINFO];
+int hl_texinfo_checksum;
+
+int hl_numfaces;
+hl_dface_t *hl_dfaces;//[HL_MAX_MAP_FACES];
+int hl_dfaces_checksum;
+
+int hl_numclipnodes;
+hl_dclipnode_t *hl_dclipnodes;//[HL_MAX_MAP_CLIPNODES];
+int hl_dclipnodes_checksum;
+
+int hl_numedges;
+hl_dedge_t *hl_dedges;//[HL_MAX_MAP_EDGES];
+int hl_dedges_checksum;
+
+int hl_nummarksurfaces;
+unsigned short *hl_dmarksurfaces;//[HL_MAX_MAP_MARKSURFACES];
+int hl_dmarksurfaces_checksum;
+
+int hl_numsurfedges;
+int *hl_dsurfedges;//[HL_MAX_MAP_SURFEDGES];
+int hl_dsurfedges_checksum;
+
+//int num_entities;
+//entity_t entities[HL_MAX_MAP_ENTITIES];
+
+
+//#ifdef //ME
+
+int hl_bspallocated = false;
+int hl_allocatedbspmem = 0;
+
+void HL_AllocMaxBSP(void)
+{
+ //models
+ hl_nummodels = 0;
+ hl_dmodels = (hl_dmodel_t *) GetMemory(HL_MAX_MAP_MODELS * sizeof(hl_dmodel_t));
+ hl_allocatedbspmem = HL_MAX_MAP_MODELS * sizeof(hl_dmodel_t);
+ //visibility
+ hl_visdatasize = 0;
+ hl_dvisdata = (byte *) GetMemory(HL_MAX_MAP_VISIBILITY * sizeof(byte));
+ hl_allocatedbspmem += HL_MAX_MAP_VISIBILITY * sizeof(byte);
+ //light data
+ hl_lightdatasize = 0;
+ hl_dlightdata = (byte *) GetMemory(HL_MAX_MAP_LIGHTING * sizeof(byte));
+ hl_allocatedbspmem += HL_MAX_MAP_LIGHTING * sizeof(byte);
+ //texture data
+ hl_texdatasize = 0;
+ hl_dtexdata = (byte *) GetMemory(HL_MAX_MAP_MIPTEX * sizeof(byte)); // (dmiptexlump_t)
+ hl_allocatedbspmem += HL_MAX_MAP_MIPTEX * sizeof(byte);
+ //entities
+ hl_entdatasize = 0;
+ hl_dentdata = (char *) GetMemory(HL_MAX_MAP_ENTSTRING * sizeof(char));
+ hl_allocatedbspmem += HL_MAX_MAP_ENTSTRING * sizeof(char);
+ //leaves
+ hl_numleafs = 0;
+ hl_dleafs = (hl_dleaf_t *) GetMemory(HL_MAX_MAP_LEAFS * sizeof(hl_dleaf_t));
+ hl_allocatedbspmem += HL_MAX_MAP_LEAFS * sizeof(hl_dleaf_t);
+ //planes
+ hl_numplanes = 0;
+ hl_dplanes = (hl_dplane_t *) GetMemory(HL_MAX_MAP_PLANES * sizeof(hl_dplane_t));
+ hl_allocatedbspmem += HL_MAX_MAP_PLANES * sizeof(hl_dplane_t);
+ //vertexes
+ hl_numvertexes = 0;
+ hl_dvertexes = (hl_dvertex_t *) GetMemory(HL_MAX_MAP_VERTS * sizeof(hl_dvertex_t));
+ hl_allocatedbspmem += HL_MAX_MAP_VERTS * sizeof(hl_dvertex_t);
+ //nodes
+ hl_numnodes = 0;
+ hl_dnodes = (hl_dnode_t *) GetMemory(HL_MAX_MAP_NODES * sizeof(hl_dnode_t));
+ hl_allocatedbspmem += HL_MAX_MAP_NODES * sizeof(hl_dnode_t);
+ //texture info
+ hl_numtexinfo = 0;
+ hl_texinfo = (hl_texinfo_t *) GetMemory(HL_MAX_MAP_TEXINFO * sizeof(hl_texinfo_t));
+ hl_allocatedbspmem += HL_MAX_MAP_TEXINFO * sizeof(hl_texinfo_t);
+ //faces
+ hl_numfaces = 0;
+ hl_dfaces = (hl_dface_t *) GetMemory(HL_MAX_MAP_FACES * sizeof(hl_dface_t));
+ hl_allocatedbspmem += HL_MAX_MAP_FACES * sizeof(hl_dface_t);
+ //clip nodes
+ hl_numclipnodes = 0;
+ hl_dclipnodes = (hl_dclipnode_t *) GetMemory(HL_MAX_MAP_CLIPNODES * sizeof(hl_dclipnode_t));
+ hl_allocatedbspmem += HL_MAX_MAP_CLIPNODES * sizeof(hl_dclipnode_t);
+ //edges
+ hl_numedges = 0;
+ hl_dedges = (hl_dedge_t *) GetMemory(HL_MAX_MAP_EDGES * sizeof(hl_dedge_t));
+ hl_allocatedbspmem += HL_MAX_MAP_EDGES, sizeof(hl_dedge_t);
+ //mark surfaces
+ hl_nummarksurfaces = 0;
+ hl_dmarksurfaces = (unsigned short *) GetMemory(HL_MAX_MAP_MARKSURFACES * sizeof(unsigned short));
+ hl_allocatedbspmem += HL_MAX_MAP_MARKSURFACES * sizeof(unsigned short);
+ //surface edges
+ hl_numsurfedges = 0;
+ hl_dsurfedges = (int *) GetMemory(HL_MAX_MAP_SURFEDGES * sizeof(int));
+ hl_allocatedbspmem += HL_MAX_MAP_SURFEDGES * sizeof(int);
+ //print allocated memory
+ Log_Print("allocated ");
+ PrintMemorySize(hl_allocatedbspmem);
+ Log_Print(" of BSP memory\n");
+} //end of the function HL_AllocMaxBSP
+
+void HL_FreeMaxBSP(void)
+{
+ //models
+ hl_nummodels = 0;
+ FreeMemory(hl_dmodels);
+ hl_dmodels = NULL;
+ //visibility
+ hl_visdatasize = 0;
+ FreeMemory(hl_dvisdata);
+ hl_dvisdata = NULL;
+ //light data
+ hl_lightdatasize = 0;
+ FreeMemory(hl_dlightdata);
+ hl_dlightdata = NULL;
+ //texture data
+ hl_texdatasize = 0;
+ FreeMemory(hl_dtexdata);
+ hl_dtexdata = NULL;
+ //entities
+ hl_entdatasize = 0;
+ FreeMemory(hl_dentdata);
+ hl_dentdata = NULL;
+ //leaves
+ hl_numleafs = 0;
+ FreeMemory(hl_dleafs);
+ hl_dleafs = NULL;
+ //planes
+ hl_numplanes = 0;
+ FreeMemory(hl_dplanes);
+ hl_dplanes = NULL;
+ //vertexes
+ hl_numvertexes = 0;
+ FreeMemory(hl_dvertexes);
+ hl_dvertexes = NULL;
+ //nodes
+ hl_numnodes = 0;
+ FreeMemory(hl_dnodes);
+ hl_dnodes = NULL;
+ //texture info
+ hl_numtexinfo = 0;
+ FreeMemory(hl_texinfo);
+ hl_texinfo = NULL;
+ //faces
+ hl_numfaces = 0;
+ FreeMemory(hl_dfaces);
+ hl_dfaces = NULL;
+ //clip nodes
+ hl_numclipnodes = 0;
+ FreeMemory(hl_dclipnodes);
+ hl_dclipnodes = NULL;
+ //edges
+ hl_numedges = 0;
+ FreeMemory(hl_dedges);
+ hl_dedges = NULL;
+ //mark surfaces
+ hl_nummarksurfaces = 0;
+ FreeMemory(hl_dmarksurfaces);
+ hl_dmarksurfaces = NULL;
+ //surface edges
+ hl_numsurfedges = 0;
+ FreeMemory(hl_dsurfedges);
+ hl_dsurfedges = NULL;
+ //
+ Log_Print("freed ");
+ PrintMemorySize(hl_allocatedbspmem);
+ Log_Print(" of BSP memory\n");
+ hl_allocatedbspmem = 0;
+} //end of the function HL_FreeMaxBSP
+//#endif //ME
+
+/*
+===============
+FastChecksum
+===============
+*/
+
+int FastChecksum(void *buffer, int bytes)
+{
+ int checksum = 0;
+
+ while( bytes-- )
+ checksum = (checksum << 4) ^ *((char *)buffer)++;
+
+ return checksum;
+}
+
+/*
+===============
+HL_CompressVis
+===============
+*/
+int HL_CompressVis(byte *vis, byte *dest)
+{
+ int j;
+ int rep;
+ int visrow;
+ byte *dest_p;
+
+ dest_p = dest;
+ visrow = (hl_numleafs + 7)>>3;
+
+ for (j=0 ; j<visrow ; j++)
+ {
+ *dest_p++ = vis[j];
+ if (vis[j])
+ continue;
+
+ rep = 1;
+ for ( j++; j<visrow ; j++)
+ if (vis[j] || rep == 255)
+ break;
+ else
+ rep++;
+ *dest_p++ = rep;
+ j--;
+ }
+
+ return dest_p - dest;
+}
+
+
+/*
+===================
+HL_DecompressVis
+===================
+*/
+void HL_DecompressVis (byte *in, byte *decompressed)
+{
+ int c;
+ byte *out;
+ int row;
+
+ row = (hl_numleafs+7)>>3;
+ out = decompressed;
+
+ do
+ {
+ if (*in)
+ {
+ *out++ = *in++;
+ continue;
+ }
+
+ c = in[1];
+ in += 2;
+ while (c)
+ {
+ *out++ = 0;
+ c--;
+ }
+ } while (out - decompressed < row);
+}
+
+//=============================================================================
+
+/*
+=============
+HL_SwapBSPFile
+
+Byte swaps all data in a bsp file.
+=============
+*/
+void HL_SwapBSPFile (qboolean todisk)
+{
+ int i, j, c;
+ hl_dmodel_t *d;
+ hl_dmiptexlump_t *mtl;
+
+
+// models
+ for (i = 0; i < hl_nummodels; i++)
+ {
+ d = &hl_dmodels[i];
+
+ for (j = 0; j < HL_MAX_MAP_HULLS; j++)
+ d->headnode[j] = LittleLong(d->headnode[j]);
+
+ d->visleafs = LittleLong(d->visleafs);
+ d->firstface = LittleLong(d->firstface);
+ d->numfaces = LittleLong(d->numfaces);
+
+ for (j = 0; j < 3; j++)
+ {
+ d->mins[j] = LittleFloat(d->mins[j]);
+ d->maxs[j] = LittleFloat(d->maxs[j]);
+ d->origin[j] = LittleFloat(d->origin[j]);
+ }
+ }
+
+//
+// vertexes
+//
+ for (i = 0; i < hl_numvertexes; i++)
+ {
+ for (j = 0; j < 3; j++)
+ hl_dvertexes[i].point[j] = LittleFloat (hl_dvertexes[i].point[j]);
+ }
+
+//
+// planes
+//
+ for (i=0 ; i<hl_numplanes ; i++)
+ {
+ for (j=0 ; j<3 ; j++)
+ hl_dplanes[i].normal[j] = LittleFloat (hl_dplanes[i].normal[j]);
+ hl_dplanes[i].dist = LittleFloat (hl_dplanes[i].dist);
+ hl_dplanes[i].type = LittleLong (hl_dplanes[i].type);
+ }
+
+//
+// texinfos
+//
+ for (i=0 ; i<hl_numtexinfo ; i++)
+ {
+ for (j=0 ; j<8 ; j++)
+ hl_texinfo[i].vecs[0][j] = LittleFloat (hl_texinfo[i].vecs[0][j]);
+ hl_texinfo[i].miptex = LittleLong (hl_texinfo[i].miptex);
+ hl_texinfo[i].flags = LittleLong (hl_texinfo[i].flags);
+ }
+
+//
+// faces
+//
+ for (i=0 ; i<hl_numfaces ; i++)
+ {
+ hl_dfaces[i].texinfo = LittleShort (hl_dfaces[i].texinfo);
+ hl_dfaces[i].planenum = LittleShort (hl_dfaces[i].planenum);
+ hl_dfaces[i].side = LittleShort (hl_dfaces[i].side);
+ hl_dfaces[i].lightofs = LittleLong (hl_dfaces[i].lightofs);
+ hl_dfaces[i].firstedge = LittleLong (hl_dfaces[i].firstedge);
+ hl_dfaces[i].numedges = LittleShort (hl_dfaces[i].numedges);
+ }
+
+//
+// nodes
+//
+ for (i=0 ; i<hl_numnodes ; i++)
+ {
+ hl_dnodes[i].planenum = LittleLong (hl_dnodes[i].planenum);
+ for (j=0 ; j<3 ; j++)
+ {
+ hl_dnodes[i].mins[j] = LittleShort (hl_dnodes[i].mins[j]);
+ hl_dnodes[i].maxs[j] = LittleShort (hl_dnodes[i].maxs[j]);
+ }
+ hl_dnodes[i].children[0] = LittleShort (hl_dnodes[i].children[0]);
+ hl_dnodes[i].children[1] = LittleShort (hl_dnodes[i].children[1]);
+ hl_dnodes[i].firstface = LittleShort (hl_dnodes[i].firstface);
+ hl_dnodes[i].numfaces = LittleShort (hl_dnodes[i].numfaces);
+ }
+
+//
+// leafs
+//
+ for (i=0 ; i<hl_numleafs ; i++)
+ {
+ hl_dleafs[i].contents = LittleLong (hl_dleafs[i].contents);
+ for (j=0 ; j<3 ; j++)
+ {
+ hl_dleafs[i].mins[j] = LittleShort (hl_dleafs[i].mins[j]);
+ hl_dleafs[i].maxs[j] = LittleShort (hl_dleafs[i].maxs[j]);
+ }
+
+ hl_dleafs[i].firstmarksurface = LittleShort (hl_dleafs[i].firstmarksurface);
+ hl_dleafs[i].nummarksurfaces = LittleShort (hl_dleafs[i].nummarksurfaces);
+ hl_dleafs[i].visofs = LittleLong (hl_dleafs[i].visofs);
+ }
+
+//
+// clipnodes
+//
+ for (i=0 ; i<hl_numclipnodes ; i++)
+ {
+ hl_dclipnodes[i].planenum = LittleLong (hl_dclipnodes[i].planenum);
+ hl_dclipnodes[i].children[0] = LittleShort (hl_dclipnodes[i].children[0]);
+ hl_dclipnodes[i].children[1] = LittleShort (hl_dclipnodes[i].children[1]);
+ }
+
+//
+// miptex
+//
+ if (hl_texdatasize)
+ {
+ mtl = (hl_dmiptexlump_t *)hl_dtexdata;
+ if (todisk)
+ c = mtl->nummiptex;
+ else
+ c = LittleLong(mtl->nummiptex);
+ mtl->nummiptex = LittleLong (mtl->nummiptex);
+ for (i=0 ; i<c ; i++)
+ mtl->dataofs[i] = LittleLong(mtl->dataofs[i]);
+ }
+
+//
+// marksurfaces
+//
+ for (i=0 ; i<hl_nummarksurfaces ; i++)
+ hl_dmarksurfaces[i] = LittleShort (hl_dmarksurfaces[i]);
+
+//
+// surfedges
+//
+ for (i=0 ; i<hl_numsurfedges ; i++)
+ hl_dsurfedges[i] = LittleLong (hl_dsurfedges[i]);
+
+//
+// edges
+//
+ for (i=0 ; i<hl_numedges ; i++)
+ {
+ hl_dedges[i].v[0] = LittleShort (hl_dedges[i].v[0]);
+ hl_dedges[i].v[1] = LittleShort (hl_dedges[i].v[1]);
+ }
+} //end of the function HL_SwapBSPFile
+
+
+hl_dheader_t *hl_header;
+int hl_fileLength;
+
+int HL_CopyLump (int lump, void *dest, int size, int maxsize)
+{
+ int length, ofs;
+
+ length = hl_header->lumps[lump].filelen;
+ ofs = hl_header->lumps[lump].fileofs;
+
+ if (length % size) {
+ Error ("LoadBSPFile: odd lump size");
+ }
+ // somehow things got out of range
+ if ((length/size) > maxsize) {
+ printf("WARNING: exceeded max size for lump %d size %d > maxsize %d\n", lump, (length/size), maxsize);
+ length = maxsize * size;
+ }
+ if ( ofs + length > hl_fileLength ) {
+ printf("WARNING: exceeded file length for lump %d\n", lump);
+ length = hl_fileLength - ofs;
+ if ( length <= 0 ) {
+ return 0;
+ }
+ }
+
+ memcpy (dest, (byte *)hl_header + ofs, length);
+
+ return length / size;
+}
+
+/*
+=============
+HL_LoadBSPFile
+=============
+*/
+void HL_LoadBSPFile (char *filename, int offset, int length)
+{
+ int i;
+
+//
+// load the file header
+//
+ hl_fileLength = LoadFile (filename, (void **)&hl_header, offset, length);
+
+// swap the header
+ for (i=0 ; i< sizeof(hl_dheader_t)/4 ; i++)
+ ((int *)hl_header)[i] = LittleLong ( ((int *)hl_header)[i]);
+
+ if (hl_header->version != HL_BSPVERSION)
+ Error ("%s is version %i, not %i", filename, hl_header->version, HL_BSPVERSION);
+
+ hl_nummodels = HL_CopyLump (HL_LUMP_MODELS, hl_dmodels, sizeof(hl_dmodel_t), HL_MAX_MAP_MODELS );
+ hl_numvertexes = HL_CopyLump (HL_LUMP_VERTEXES, hl_dvertexes, sizeof(hl_dvertex_t), HL_MAX_MAP_VERTS );
+ hl_numplanes = HL_CopyLump (HL_LUMP_PLANES, hl_dplanes, sizeof(hl_dplane_t), HL_MAX_MAP_PLANES );
+ hl_numleafs = HL_CopyLump (HL_LUMP_LEAFS, hl_dleafs, sizeof(hl_dleaf_t), HL_MAX_MAP_LEAFS );
+ hl_numnodes = HL_CopyLump (HL_LUMP_NODES, hl_dnodes, sizeof(hl_dnode_t), HL_MAX_MAP_NODES );
+ hl_numtexinfo = HL_CopyLump (HL_LUMP_TEXINFO, hl_texinfo, sizeof(hl_texinfo_t), HL_MAX_MAP_TEXINFO );
+ hl_numclipnodes = HL_CopyLump (HL_LUMP_CLIPNODES, hl_dclipnodes, sizeof(hl_dclipnode_t), HL_MAX_MAP_CLIPNODES );
+ hl_numfaces = HL_CopyLump (HL_LUMP_FACES, hl_dfaces, sizeof(hl_dface_t), HL_MAX_MAP_FACES );
+ hl_nummarksurfaces = HL_CopyLump (HL_LUMP_MARKSURFACES, hl_dmarksurfaces, sizeof(hl_dmarksurfaces[0]), HL_MAX_MAP_MARKSURFACES );
+ hl_numsurfedges = HL_CopyLump (HL_LUMP_SURFEDGES, hl_dsurfedges, sizeof(hl_dsurfedges[0]), HL_MAX_MAP_SURFEDGES );
+ hl_numedges = HL_CopyLump (HL_LUMP_EDGES, hl_dedges, sizeof(hl_dedge_t), HL_MAX_MAP_EDGES );
+
+ hl_texdatasize = HL_CopyLump (HL_LUMP_TEXTURES, hl_dtexdata, 1, HL_MAX_MAP_MIPTEX );
+ hl_visdatasize = HL_CopyLump (HL_LUMP_VISIBILITY, hl_dvisdata, 1, HL_MAX_MAP_VISIBILITY );
+ hl_lightdatasize = HL_CopyLump (HL_LUMP_LIGHTING, hl_dlightdata, 1, HL_MAX_MAP_LIGHTING );
+ hl_entdatasize = HL_CopyLump (HL_LUMP_ENTITIES, hl_dentdata, 1, HL_MAX_MAP_ENTSTRING );
+
+ FreeMemory(hl_header); // everything has been copied out
+
+//
+// swap everything
+//
+ HL_SwapBSPFile (false);
+
+ hl_dmodels_checksum = FastChecksum( hl_dmodels, hl_nummodels*sizeof(hl_dmodels[0]) );
+ hl_dvertexes_checksum = FastChecksum( hl_dvertexes, hl_numvertexes*sizeof(hl_dvertexes[0]) );
+ hl_dplanes_checksum = FastChecksum( hl_dplanes, hl_numplanes*sizeof(hl_dplanes[0]) );
+ hl_dleafs_checksum = FastChecksum( hl_dleafs, hl_numleafs*sizeof(hl_dleafs[0]) );
+ hl_dnodes_checksum = FastChecksum( hl_dnodes, hl_numnodes*sizeof(hl_dnodes[0]) );
+ hl_texinfo_checksum = FastChecksum( hl_texinfo, hl_numtexinfo*sizeof(hl_texinfo[0]) );
+ hl_dclipnodes_checksum = FastChecksum( hl_dclipnodes, hl_numclipnodes*sizeof(hl_dclipnodes[0]) );
+ hl_dfaces_checksum = FastChecksum( hl_dfaces, hl_numfaces*sizeof(hl_dfaces[0]) );
+ hl_dmarksurfaces_checksum = FastChecksum( hl_dmarksurfaces, hl_nummarksurfaces*sizeof(hl_dmarksurfaces[0]) );
+ hl_dsurfedges_checksum = FastChecksum( hl_dsurfedges, hl_numsurfedges*sizeof(hl_dsurfedges[0]) );
+ hl_dedges_checksum = FastChecksum( hl_dedges, hl_numedges*sizeof(hl_dedges[0]) );
+ hl_dtexdata_checksum = FastChecksum( hl_dtexdata, hl_numedges*sizeof(hl_dtexdata[0]) );
+ hl_dvisdata_checksum = FastChecksum( hl_dvisdata, hl_visdatasize*sizeof(hl_dvisdata[0]) );
+ hl_dlightdata_checksum = FastChecksum( hl_dlightdata, hl_lightdatasize*sizeof(hl_dlightdata[0]) );
+ hl_dentdata_checksum = FastChecksum( hl_dentdata, hl_entdatasize*sizeof(hl_dentdata[0]) );
+
+}
+
+//============================================================================
+
+FILE *wadfile;
+hl_dheader_t outheader;
+
+void HL_AddLump (int lumpnum, void *data, int len)
+{
+ hl_lump_t *lump;
+
+ lump = &hl_header->lumps[lumpnum];
+
+ lump->fileofs = LittleLong( ftell(wadfile) );
+ lump->filelen = LittleLong(len);
+ SafeWrite (wadfile, data, (len+3)&~3);
+}
+
+/*
+=============
+HL_WriteBSPFile
+
+Swaps the bsp file in place, so it should not be referenced again
+=============
+*/
+void HL_WriteBSPFile (char *filename)
+{
+ hl_header = &outheader;
+ memset (hl_header, 0, sizeof(hl_dheader_t));
+
+ HL_SwapBSPFile (true);
+
+ hl_header->version = LittleLong (HL_BSPVERSION);
+
+ wadfile = SafeOpenWrite (filename);
+ SafeWrite (wadfile, hl_header, sizeof(hl_dheader_t)); // overwritten later
+
+ HL_AddLump (HL_LUMP_PLANES, hl_dplanes, hl_numplanes*sizeof(hl_dplane_t));
+ HL_AddLump (HL_LUMP_LEAFS, hl_dleafs, hl_numleafs*sizeof(hl_dleaf_t));
+ HL_AddLump (HL_LUMP_VERTEXES, hl_dvertexes, hl_numvertexes*sizeof(hl_dvertex_t));
+ HL_AddLump (HL_LUMP_NODES, hl_dnodes, hl_numnodes*sizeof(hl_dnode_t));
+ HL_AddLump (HL_LUMP_TEXINFO, hl_texinfo, hl_numtexinfo*sizeof(hl_texinfo_t));
+ HL_AddLump (HL_LUMP_FACES, hl_dfaces, hl_numfaces*sizeof(hl_dface_t));
+ HL_AddLump (HL_LUMP_CLIPNODES, hl_dclipnodes, hl_numclipnodes*sizeof(hl_dclipnode_t));
+ HL_AddLump (HL_LUMP_MARKSURFACES, hl_dmarksurfaces, hl_nummarksurfaces*sizeof(hl_dmarksurfaces[0]));
+ HL_AddLump (HL_LUMP_SURFEDGES, hl_dsurfedges, hl_numsurfedges*sizeof(hl_dsurfedges[0]));
+ HL_AddLump (HL_LUMP_EDGES, hl_dedges, hl_numedges*sizeof(hl_dedge_t));
+ HL_AddLump (HL_LUMP_MODELS, hl_dmodels, hl_nummodels*sizeof(hl_dmodel_t));
+
+ HL_AddLump (HL_LUMP_LIGHTING, hl_dlightdata, hl_lightdatasize);
+ HL_AddLump (HL_LUMP_VISIBILITY, hl_dvisdata, hl_visdatasize);
+ HL_AddLump (HL_LUMP_ENTITIES, hl_dentdata, hl_entdatasize);
+ HL_AddLump (HL_LUMP_TEXTURES, hl_dtexdata, hl_texdatasize);
+
+ fseek (wadfile, 0, SEEK_SET);
+ SafeWrite (wadfile, hl_header, sizeof(hl_dheader_t));
+ fclose (wadfile);
+}
+
+//============================================================================
+
+#define ENTRIES(a) (sizeof(a)/sizeof(*(a)))
+#define ENTRYSIZE(a) (sizeof(*(a)))
+
+ArrayUsage( char *szItem, int items, int maxitems, int itemsize )
+{
+ float percentage = maxitems ? items * 100.0 / maxitems : 0.0;
+
+ qprintf("%-12s %7i/%-7i %7i/%-7i (%4.1f%%)",
+ szItem, items, maxitems, items * itemsize, maxitems * itemsize, percentage );
+ if ( percentage > 80.0 )
+ qprintf( "VERY FULL!\n" );
+ else if ( percentage > 95.0 )
+ qprintf( "SIZE DANGER!\n" );
+ else if ( percentage > 99.9 )
+ qprintf( "SIZE OVERFLOW!!!\n" );
+ else
+ qprintf( "\n" );
+ return items * itemsize;
+}
+
+GlobUsage( char *szItem, int itemstorage, int maxstorage )
+{
+ float percentage = maxstorage ? itemstorage * 100.0 / maxstorage : 0.0;
+
+ qprintf("%-12s [variable] %7i/%-7i (%4.1f%%)",
+ szItem, itemstorage, maxstorage, percentage );
+ if ( percentage > 80.0 )
+ qprintf( "VERY FULL!\n" );
+ else if ( percentage > 95.0 )
+ qprintf( "SIZE DANGER!\n" );
+ else if ( percentage > 99.9 )
+ qprintf( "SIZE OVERFLOW!!!\n" );
+ else
+ qprintf( "\n" );
+ return itemstorage;
+}
+
+/*
+=============
+HL_PrintBSPFileSizes
+
+Dumps info about current file
+=============
+*/
+void HL_PrintBSPFileSizes(void)
+{
+ int numtextures = hl_texdatasize ? ((hl_dmiptexlump_t*)hl_dtexdata)->nummiptex : 0;
+ int totalmemory = 0;
+
+ qprintf("\n");
+ qprintf("Object names Objects/Maxobjs Memory / Maxmem Fullness\n" );
+ qprintf("------------ --------------- --------------- --------\n" );
+
+ totalmemory += ArrayUsage( "models", hl_nummodels, ENTRIES(hl_dmodels), ENTRYSIZE(hl_dmodels) );
+ totalmemory += ArrayUsage( "planes", hl_numplanes, ENTRIES(hl_dplanes), ENTRYSIZE(hl_dplanes) );
+ totalmemory += ArrayUsage( "vertexes", hl_numvertexes, ENTRIES(hl_dvertexes), ENTRYSIZE(hl_dvertexes) );
+ totalmemory += ArrayUsage( "nodes", hl_numnodes, ENTRIES(hl_dnodes), ENTRYSIZE(hl_dnodes) );
+ totalmemory += ArrayUsage( "texinfos", hl_numtexinfo, ENTRIES(hl_texinfo), ENTRYSIZE(hl_texinfo) );
+ totalmemory += ArrayUsage( "faces", hl_numfaces, ENTRIES(hl_dfaces), ENTRYSIZE(hl_dfaces) );
+ totalmemory += ArrayUsage( "clipnodes", hl_numclipnodes, ENTRIES(hl_dclipnodes), ENTRYSIZE(hl_dclipnodes) );
+ totalmemory += ArrayUsage( "leaves", hl_numleafs, ENTRIES(hl_dleafs), ENTRYSIZE(hl_dleafs) );
+ totalmemory += ArrayUsage( "marksurfaces",hl_nummarksurfaces,ENTRIES(hl_dmarksurfaces),ENTRYSIZE(hl_dmarksurfaces) );
+ totalmemory += ArrayUsage( "surfedges", hl_numsurfedges, ENTRIES(hl_dsurfedges), ENTRYSIZE(hl_dsurfedges) );
+ totalmemory += ArrayUsage( "edges", hl_numedges, ENTRIES(hl_dedges), ENTRYSIZE(hl_dedges) );
+
+ totalmemory += GlobUsage( "texdata", hl_texdatasize, sizeof(hl_dtexdata) );
+ totalmemory += GlobUsage( "lightdata", hl_lightdatasize, sizeof(hl_dlightdata) );
+ totalmemory += GlobUsage( "visdata", hl_visdatasize, sizeof(hl_dvisdata) );
+ totalmemory += GlobUsage( "entdata", hl_entdatasize, sizeof(hl_dentdata) );
+
+ qprintf( "=== Total BSP file data space used: %d bytes ===\n\n", totalmemory );
+}
+
+
+
+/*
+=================
+ParseEpair
+=================
+* /
+epair_t *ParseEpair (void)
+{
+ epair_t *e;
+
+ e = malloc (sizeof(epair_t));
+ memset (e, 0, sizeof(epair_t));
+
+ if (strlen(token) >= MAX_KEY-1)
+ Error ("ParseEpar: token too long");
+ e->key = copystring(token);
+ GetToken (false);
+ if (strlen(token) >= MAX_VALUE-1)
+ Error ("ParseEpar: token too long");
+ e->value = copystring(token);
+
+ return e;
+} //*/
+
+
+/*
+================
+ParseEntity
+================
+* /
+qboolean ParseEntity (void)
+{
+ epair_t *e;
+ entity_t *mapent;
+
+ if (!GetToken (true))
+ return false;
+
+ if (strcmp (token, "{") )
+ Error ("ParseEntity: { not found");
+
+ if (num_entities == HL_MAX_MAP_ENTITIES)
+ Error ("num_entities == HL_MAX_MAP_ENTITIES");
+
+ mapent = &entities[num_entities];
+ num_entities++;
+
+ do
+ {
+ if (!GetToken (true))
+ Error ("ParseEntity: EOF without closing brace");
+ if (!strcmp (token, "}") )
+ break;
+ e = ParseEpair ();
+ e->next = mapent->epairs;
+ mapent->epairs = e;
+ } while (1);
+
+ return true;
+} //*/
+
+/*
+================
+ParseEntities
+
+Parses the dentdata string into entities
+================
+*/
+void HL_ParseEntities (void)
+{
+ script_t *script;
+
+ num_entities = 0;
+ script = LoadScriptMemory(hl_dentdata, hl_entdatasize, "*Half-Life bsp file");
+ SetScriptFlags(script, SCFL_NOSTRINGWHITESPACES |
+ SCFL_NOSTRINGESCAPECHARS);
+
+ while(ParseEntity(script))
+ {
+ } //end while
+
+ FreeScript(script);
+} //end of the function HL_ParseEntities
+
+
+/*
+================
+UnparseEntities
+
+Generates the dentdata string from all the entities
+================
+*/
+void HL_UnparseEntities (void)
+{
+ char *buf, *end;
+ epair_t *ep;
+ char line[2048];
+ int i;
+
+ buf = hl_dentdata;
+ end = buf;
+ *end = 0;
+
+ for (i=0 ; i<num_entities ; i++)
+ {
+ ep = entities[i].epairs;
+ if (!ep)
+ continue; // ent got removed
+
+ strcat (end,"{\n");
+ end += 2;
+
+ for (ep = entities[i].epairs ; ep ; ep=ep->next)
+ {
+ sprintf (line, "\"%s\" \"%s\"\n", ep->key, ep->value);
+ strcat (end, line);
+ end += strlen(line);
+ }
+ strcat (end,"}\n");
+ end += 2;
+
+ if (end > buf + HL_MAX_MAP_ENTSTRING)
+ Error ("Entity text too long");
+ }
+ hl_entdatasize = end - buf + 1;
+} //end of the function HL_UnparseEntities
+
+
+/*
+void SetKeyValue (entity_t *ent, char *key, char *value)
+{
+ epair_t *ep;
+
+ for (ep=ent->epairs ; ep ; ep=ep->next)
+ if (!strcmp (ep->key, key) )
+ {
+ free (ep->value);
+ ep->value = copystring(value);
+ return;
+ }
+ ep = malloc (sizeof(*ep));
+ ep->next = ent->epairs;
+ ent->epairs = ep;
+ ep->key = copystring(key);
+ ep->value = copystring(value);
+}
+
+char *ValueForKey (entity_t *ent, char *key)
+{
+ epair_t *ep;
+
+ for (ep=ent->epairs ; ep ; ep=ep->next)
+ if (!strcmp (ep->key, key) )
+ return ep->value;
+ return "";
+}
+
+vec_t FloatForKey (entity_t *ent, char *key)
+{
+ char *k;
+
+ k = ValueForKey (ent, key);
+ return atof(k);
+}
+
+void GetVectorForKey (entity_t *ent, char *key, vec3_t vec)
+{
+ char *k;
+ double v1, v2, v3;
+
+ k = ValueForKey (ent, key);
+// scanf into doubles, then assign, so it is vec_t size independent
+ v1 = v2 = v3 = 0;
+ sscanf (k, "%lf %lf %lf", &v1, &v2, &v3);
+ vec[0] = v1;
+ vec[1] = v2;
+ vec[2] = v3;
+} //*/
diff --git a/code/bspc/l_bsp_hl.h b/code/bspc/l_bsp_hl.h
index 0089b1e..4146202 100755
--- a/code/bspc/l_bsp_hl.h
+++ b/code/bspc/l_bsp_hl.h
@@ -1,314 +1,314 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-// upper design bounds
-
-#define HL_MAX_MAP_HULLS 4
-
-#define HL_MAX_MAP_MODELS 400
-#define HL_MAX_MAP_BRUSHES 4096
-#define HL_MAX_MAP_ENTITIES 1024
-#define HL_MAX_MAP_ENTSTRING (128*1024)
-
-#define HL_MAX_MAP_PLANES 32767
-#define HL_MAX_MAP_NODES 32767 // because negative shorts are contents
-#define HL_MAX_MAP_CLIPNODES 32767 //
-#define HL_MAX_MAP_LEAFS 8192
-#define HL_MAX_MAP_VERTS 65535
-#define HL_MAX_MAP_FACES 65535
-#define HL_MAX_MAP_MARKSURFACES 65535
-#define HL_MAX_MAP_TEXINFO 8192
-#define HL_MAX_MAP_EDGES 256000
-#define HL_MAX_MAP_SURFEDGES 512000
-#define HL_MAX_MAP_TEXTURES 512
-#define HL_MAX_MAP_MIPTEX 0x200000
-#define HL_MAX_MAP_LIGHTING 0x200000
-#define HL_MAX_MAP_VISIBILITY 0x200000
-
-#define HL_MAX_MAP_PORTALS 65536
-
-// key / value pair sizes
-
-#define MAX_KEY 32
-#define MAX_VALUE 1024
-
-//=============================================================================
-
-
-#define HL_BSPVERSION 30
-#define HL_TOOLVERSION 2
-
-
-typedef struct
-{
- int fileofs, filelen;
-} hl_lump_t;
-
-#define HL_LUMP_ENTITIES 0
-#define HL_LUMP_PLANES 1
-#define HL_LUMP_TEXTURES 2
-#define HL_LUMP_VERTEXES 3
-#define HL_LUMP_VISIBILITY 4
-#define HL_LUMP_NODES 5
-#define HL_LUMP_TEXINFO 6
-#define HL_LUMP_FACES 7
-#define HL_LUMP_LIGHTING 8
-#define HL_LUMP_CLIPNODES 9
-#define HL_LUMP_LEAFS 10
-#define HL_LUMP_MARKSURFACES 11
-#define HL_LUMP_EDGES 12
-#define HL_LUMP_SURFEDGES 13
-#define HL_LUMP_MODELS 14
-
-#define HL_HEADER_LUMPS 15
-
-typedef struct
-{
- float mins[3], maxs[3];
- float origin[3];
- int headnode[HL_MAX_MAP_HULLS];
- int visleafs; // not including the solid leaf 0
- int firstface, numfaces;
-} hl_dmodel_t;
-
-typedef struct
-{
- int version;
- hl_lump_t lumps[HL_HEADER_LUMPS];
-} hl_dheader_t;
-
-typedef struct
-{
- int nummiptex;
- int dataofs[4]; // [nummiptex]
-} hl_dmiptexlump_t;
-
-#define MIPLEVELS 4
-typedef struct hl_miptex_s
-{
- char name[16];
- unsigned width, height;
- unsigned offsets[MIPLEVELS]; // four mip maps stored
-} hl_miptex_t;
-
-
-typedef struct
-{
- float point[3];
-} hl_dvertex_t;
-
-
-// 0-2 are axial planes
-#define PLANE_X 0
-#define PLANE_Y 1
-#define PLANE_Z 2
-
-// 3-5 are non-axial planes snapped to the nearest
-#define PLANE_ANYX 3
-#define PLANE_ANYY 4
-#define PLANE_ANYZ 5
-
-typedef struct
-{
- float normal[3];
- float dist;
- int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
-} hl_dplane_t;
-
-
-
-#define HL_CONTENTS_EMPTY -1
-#define HL_CONTENTS_SOLID -2
-#define HL_CONTENTS_WATER -3
-#define HL_CONTENTS_SLIME -4
-#define HL_CONTENTS_LAVA -5
-#define HL_CONTENTS_SKY -6
-#define HL_CONTENTS_ORIGIN -7 // removed at csg time
-#define HL_CONTENTS_CLIP -8 // changed to contents_solid
-
-#define HL_CONTENTS_CURRENT_0 -9
-#define HL_CONTENTS_CURRENT_90 -10
-#define HL_CONTENTS_CURRENT_180 -11
-#define HL_CONTENTS_CURRENT_270 -12
-#define HL_CONTENTS_CURRENT_UP -13
-#define HL_CONTENTS_CURRENT_DOWN -14
-
-#define HL_CONTENTS_TRANSLUCENT -15
-
-// !!! if this is changed, it must be changed in asm_i386.h too !!!
-typedef struct
-{
- int planenum;
- short children[2]; // negative numbers are -(leafs+1), not nodes
- short mins[3]; // for sphere culling
- short maxs[3];
- unsigned short firstface;
- unsigned short numfaces; // counting both sides
-} hl_dnode_t;
-
-typedef struct
-{
- int planenum;
- short children[2]; // negative numbers are contents
-} hl_dclipnode_t;
-
-
-typedef struct hl_texinfo_s
-{
- float vecs[2][4]; // [s/t][xyz offset]
- int miptex;
- int flags;
-} hl_texinfo_t;
-#define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision
-
-// note that edge 0 is never used, because negative edge nums are used for
-// counterclockwise use of the edge in a face
-typedef struct
-{
- unsigned short v[2]; // vertex numbers
-} hl_dedge_t;
-
-#define MAXLIGHTMAPS 4
-typedef struct
-{
- short planenum;
- short side;
-
- int firstedge; // we must support > 64k edges
- short numedges;
- short texinfo;
-
-// lighting info
- byte styles[MAXLIGHTMAPS];
- int lightofs; // start of [numstyles*surfsize] samples
-} hl_dface_t;
-
-
-#define AMBIENT_WATER 0
-#define AMBIENT_SKY 1
-#define AMBIENT_SLIME 2
-#define AMBIENT_LAVA 3
-
-#define NUM_AMBIENTS 4 // automatic ambient sounds
-
-// leaf 0 is the generic HL_CONTENTS_SOLID leaf, used for all solid areas
-// all other leafs need visibility info
-typedef struct
-{
- int contents;
- int visofs; // -1 = no visibility info
-
- short mins[3]; // for frustum culling
- short maxs[3];
-
- unsigned short firstmarksurface;
- unsigned short nummarksurfaces;
-
- byte ambient_level[NUM_AMBIENTS];
-} hl_dleaf_t;
-
-
-//============================================================================
-
-#ifndef QUAKE_GAME
-
-#define ANGLE_UP -1
-#define ANGLE_DOWN -2
-
-
-// the utilities get to be lazy and just use large static arrays
-
-extern int hl_nummodels;
-extern hl_dmodel_t *hl_dmodels;//[MAX_MAP_MODELS];
-extern int hl_dmodels_checksum;
-
-extern int hl_visdatasize;
-extern byte *hl_dvisdata;//[MAX_MAP_VISIBILITY];
-extern int hl_dvisdata_checksum;
-
-extern int hl_lightdatasize;
-extern byte *hl_dlightdata;//[MAX_MAP_LIGHTING];
-extern int hl_dlightdata_checksum;
-
-extern int hl_texdatasize;
-extern byte *hl_dtexdata;//[MAX_MAP_MIPTEX]; // (dmiptexlump_t)
-extern int hl_dtexdata_checksum;
-
-extern int hl_entdatasize;
-extern char *hl_dentdata;//[MAX_MAP_ENTSTRING];
-extern int hl_dentdata_checksum;
-
-extern int hl_numleafs;
-extern hl_dleaf_t *hl_dleafs;//[MAX_MAP_LEAFS];
-extern int hl_dleafs_checksum;
-
-extern int hl_numplanes;
-extern hl_dplane_t *hl_dplanes;//[MAX_MAP_PLANES];
-extern int hl_dplanes_checksum;
-
-extern int hl_numvertexes;
-extern hl_dvertex_t *hl_dvertexes;//[MAX_MAP_VERTS];
-extern int hl_dvertexes_checksum;
-
-extern int hl_numnodes;
-extern hl_dnode_t *hl_dnodes;//[MAX_MAP_NODES];
-extern int hl_dnodes_checksum;
-
-extern int hl_numtexinfo;
-extern hl_texinfo_t *hl_texinfo;//[MAX_MAP_TEXINFO];
-extern int hl_texinfo_checksum;
-
-extern int hl_numfaces;
-extern hl_dface_t *hl_dfaces;//[MAX_MAP_FACES];
-extern int hl_dfaces_checksum;
-
-extern int hl_numclipnodes;
-extern hl_dclipnode_t *hl_dclipnodes;//[MAX_MAP_CLIPNODES];
-extern int hl_dclipnodes_checksum;
-
-extern int hl_numedges;
-extern hl_dedge_t *hl_dedges;//[MAX_MAP_EDGES];
-extern int hl_dedges_checksum;
-
-extern int hl_nummarksurfaces;
-extern unsigned short *hl_dmarksurfaces;//[MAX_MAP_MARKSURFACES];
-extern int hl_dmarksurfaces_checksum;
-
-extern int hl_numsurfedges;
-extern int *hl_dsurfedges;//[MAX_MAP_SURFEDGES];
-extern int hl_dsurfedges_checksum;
-
-int FastChecksum(void *buffer, int bytes);
-
-void HL_AllocMaxBSP(void);
-void HL_FreeMaxBSP(void);
-
-void HL_DecompressVis(byte *in, byte *decompressed);
-int HL_CompressVis(byte *vis, byte *dest);
-
-void HL_LoadBSPFile(char *filename, int offset, int length);
-void HL_WriteBSPFile(char *filename);
-void HL_PrintBSPFileSizes(void);
-void HL_PrintBSPFileSizes(void);
-void HL_ParseEntities(void);
-void HL_UnparseEntities(void);
-
-#endif
+/*
+===========================================================================
+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
+===========================================================================
+*/
+// upper design bounds
+
+#define HL_MAX_MAP_HULLS 4
+
+#define HL_MAX_MAP_MODELS 400
+#define HL_MAX_MAP_BRUSHES 4096
+#define HL_MAX_MAP_ENTITIES 1024
+#define HL_MAX_MAP_ENTSTRING (128*1024)
+
+#define HL_MAX_MAP_PLANES 32767
+#define HL_MAX_MAP_NODES 32767 // because negative shorts are contents
+#define HL_MAX_MAP_CLIPNODES 32767 //
+#define HL_MAX_MAP_LEAFS 8192
+#define HL_MAX_MAP_VERTS 65535
+#define HL_MAX_MAP_FACES 65535
+#define HL_MAX_MAP_MARKSURFACES 65535
+#define HL_MAX_MAP_TEXINFO 8192
+#define HL_MAX_MAP_EDGES 256000
+#define HL_MAX_MAP_SURFEDGES 512000
+#define HL_MAX_MAP_TEXTURES 512
+#define HL_MAX_MAP_MIPTEX 0x200000
+#define HL_MAX_MAP_LIGHTING 0x200000
+#define HL_MAX_MAP_VISIBILITY 0x200000
+
+#define HL_MAX_MAP_PORTALS 65536
+
+// key / value pair sizes
+
+#define MAX_KEY 32
+#define MAX_VALUE 1024
+
+//=============================================================================
+
+
+#define HL_BSPVERSION 30
+#define HL_TOOLVERSION 2
+
+
+typedef struct
+{
+ int fileofs, filelen;
+} hl_lump_t;
+
+#define HL_LUMP_ENTITIES 0
+#define HL_LUMP_PLANES 1
+#define HL_LUMP_TEXTURES 2
+#define HL_LUMP_VERTEXES 3
+#define HL_LUMP_VISIBILITY 4
+#define HL_LUMP_NODES 5
+#define HL_LUMP_TEXINFO 6
+#define HL_LUMP_FACES 7
+#define HL_LUMP_LIGHTING 8
+#define HL_LUMP_CLIPNODES 9
+#define HL_LUMP_LEAFS 10
+#define HL_LUMP_MARKSURFACES 11
+#define HL_LUMP_EDGES 12
+#define HL_LUMP_SURFEDGES 13
+#define HL_LUMP_MODELS 14
+
+#define HL_HEADER_LUMPS 15
+
+typedef struct
+{
+ float mins[3], maxs[3];
+ float origin[3];
+ int headnode[HL_MAX_MAP_HULLS];
+ int visleafs; // not including the solid leaf 0
+ int firstface, numfaces;
+} hl_dmodel_t;
+
+typedef struct
+{
+ int version;
+ hl_lump_t lumps[HL_HEADER_LUMPS];
+} hl_dheader_t;
+
+typedef struct
+{
+ int nummiptex;
+ int dataofs[4]; // [nummiptex]
+} hl_dmiptexlump_t;
+
+#define MIPLEVELS 4
+typedef struct hl_miptex_s
+{
+ char name[16];
+ unsigned width, height;
+ unsigned offsets[MIPLEVELS]; // four mip maps stored
+} hl_miptex_t;
+
+
+typedef struct
+{
+ float point[3];
+} hl_dvertex_t;
+
+
+// 0-2 are axial planes
+#define PLANE_X 0
+#define PLANE_Y 1
+#define PLANE_Z 2
+
+// 3-5 are non-axial planes snapped to the nearest
+#define PLANE_ANYX 3
+#define PLANE_ANYY 4
+#define PLANE_ANYZ 5
+
+typedef struct
+{
+ float normal[3];
+ float dist;
+ int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
+} hl_dplane_t;
+
+
+
+#define HL_CONTENTS_EMPTY -1
+#define HL_CONTENTS_SOLID -2
+#define HL_CONTENTS_WATER -3
+#define HL_CONTENTS_SLIME -4
+#define HL_CONTENTS_LAVA -5
+#define HL_CONTENTS_SKY -6
+#define HL_CONTENTS_ORIGIN -7 // removed at csg time
+#define HL_CONTENTS_CLIP -8 // changed to contents_solid
+
+#define HL_CONTENTS_CURRENT_0 -9
+#define HL_CONTENTS_CURRENT_90 -10
+#define HL_CONTENTS_CURRENT_180 -11
+#define HL_CONTENTS_CURRENT_270 -12
+#define HL_CONTENTS_CURRENT_UP -13
+#define HL_CONTENTS_CURRENT_DOWN -14
+
+#define HL_CONTENTS_TRANSLUCENT -15
+
+// !!! if this is changed, it must be changed in asm_i386.h too !!!
+typedef struct
+{
+ int planenum;
+ short children[2]; // negative numbers are -(leafs+1), not nodes
+ short mins[3]; // for sphere culling
+ short maxs[3];
+ unsigned short firstface;
+ unsigned short numfaces; // counting both sides
+} hl_dnode_t;
+
+typedef struct
+{
+ int planenum;
+ short children[2]; // negative numbers are contents
+} hl_dclipnode_t;
+
+
+typedef struct hl_texinfo_s
+{
+ float vecs[2][4]; // [s/t][xyz offset]
+ int miptex;
+ int flags;
+} hl_texinfo_t;
+#define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision
+
+// note that edge 0 is never used, because negative edge nums are used for
+// counterclockwise use of the edge in a face
+typedef struct
+{
+ unsigned short v[2]; // vertex numbers
+} hl_dedge_t;
+
+#define MAXLIGHTMAPS 4
+typedef struct
+{
+ short planenum;
+ short side;
+
+ int firstedge; // we must support > 64k edges
+ short numedges;
+ short texinfo;
+
+// lighting info
+ byte styles[MAXLIGHTMAPS];
+ int lightofs; // start of [numstyles*surfsize] samples
+} hl_dface_t;
+
+
+#define AMBIENT_WATER 0
+#define AMBIENT_SKY 1
+#define AMBIENT_SLIME 2
+#define AMBIENT_LAVA 3
+
+#define NUM_AMBIENTS 4 // automatic ambient sounds
+
+// leaf 0 is the generic HL_CONTENTS_SOLID leaf, used for all solid areas
+// all other leafs need visibility info
+typedef struct
+{
+ int contents;
+ int visofs; // -1 = no visibility info
+
+ short mins[3]; // for frustum culling
+ short maxs[3];
+
+ unsigned short firstmarksurface;
+ unsigned short nummarksurfaces;
+
+ byte ambient_level[NUM_AMBIENTS];
+} hl_dleaf_t;
+
+
+//============================================================================
+
+#ifndef QUAKE_GAME
+
+#define ANGLE_UP -1
+#define ANGLE_DOWN -2
+
+
+// the utilities get to be lazy and just use large static arrays
+
+extern int hl_nummodels;
+extern hl_dmodel_t *hl_dmodels;//[MAX_MAP_MODELS];
+extern int hl_dmodels_checksum;
+
+extern int hl_visdatasize;
+extern byte *hl_dvisdata;//[MAX_MAP_VISIBILITY];
+extern int hl_dvisdata_checksum;
+
+extern int hl_lightdatasize;
+extern byte *hl_dlightdata;//[MAX_MAP_LIGHTING];
+extern int hl_dlightdata_checksum;
+
+extern int hl_texdatasize;
+extern byte *hl_dtexdata;//[MAX_MAP_MIPTEX]; // (dmiptexlump_t)
+extern int hl_dtexdata_checksum;
+
+extern int hl_entdatasize;
+extern char *hl_dentdata;//[MAX_MAP_ENTSTRING];
+extern int hl_dentdata_checksum;
+
+extern int hl_numleafs;
+extern hl_dleaf_t *hl_dleafs;//[MAX_MAP_LEAFS];
+extern int hl_dleafs_checksum;
+
+extern int hl_numplanes;
+extern hl_dplane_t *hl_dplanes;//[MAX_MAP_PLANES];
+extern int hl_dplanes_checksum;
+
+extern int hl_numvertexes;
+extern hl_dvertex_t *hl_dvertexes;//[MAX_MAP_VERTS];
+extern int hl_dvertexes_checksum;
+
+extern int hl_numnodes;
+extern hl_dnode_t *hl_dnodes;//[MAX_MAP_NODES];
+extern int hl_dnodes_checksum;
+
+extern int hl_numtexinfo;
+extern hl_texinfo_t *hl_texinfo;//[MAX_MAP_TEXINFO];
+extern int hl_texinfo_checksum;
+
+extern int hl_numfaces;
+extern hl_dface_t *hl_dfaces;//[MAX_MAP_FACES];
+extern int hl_dfaces_checksum;
+
+extern int hl_numclipnodes;
+extern hl_dclipnode_t *hl_dclipnodes;//[MAX_MAP_CLIPNODES];
+extern int hl_dclipnodes_checksum;
+
+extern int hl_numedges;
+extern hl_dedge_t *hl_dedges;//[MAX_MAP_EDGES];
+extern int hl_dedges_checksum;
+
+extern int hl_nummarksurfaces;
+extern unsigned short *hl_dmarksurfaces;//[MAX_MAP_MARKSURFACES];
+extern int hl_dmarksurfaces_checksum;
+
+extern int hl_numsurfedges;
+extern int *hl_dsurfedges;//[MAX_MAP_SURFEDGES];
+extern int hl_dsurfedges_checksum;
+
+int FastChecksum(void *buffer, int bytes);
+
+void HL_AllocMaxBSP(void);
+void HL_FreeMaxBSP(void);
+
+void HL_DecompressVis(byte *in, byte *decompressed);
+int HL_CompressVis(byte *vis, byte *dest);
+
+void HL_LoadBSPFile(char *filename, int offset, int length);
+void HL_WriteBSPFile(char *filename);
+void HL_PrintBSPFileSizes(void);
+void HL_PrintBSPFileSizes(void);
+void HL_ParseEntities(void);
+void HL_UnparseEntities(void);
+
+#endif
diff --git a/code/bspc/l_bsp_q1.c b/code/bspc/l_bsp_q1.c
index c68b5c8..7ac1553 100755
--- a/code/bspc/l_bsp_q1.c
+++ b/code/bspc/l_bsp_q1.c
@@ -1,620 +1,620 @@
-/*
-===========================================================================
-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 "l_cmd.h"
-#include "l_math.h"
-#include "l_mem.h"
-#include "l_log.h"
-#include "../botlib/l_script.h"
-#include "l_bsp_q1.h"
-#include "l_bsp_ent.h"
-
-//=============================================================================
-
-int q1_nummodels;
-q1_dmodel_t *q1_dmodels;//[MAX_MAP_MODELS];
-
-int q1_visdatasize;
-byte *q1_dvisdata;//[MAX_MAP_VISIBILITY];
-
-int q1_lightdatasize;
-byte *q1_dlightdata;//[MAX_MAP_LIGHTING];
-
-int q1_texdatasize;
-byte *q1_dtexdata;//[MAX_MAP_MIPTEX]; // (dmiptexlump_t)
-
-int q1_entdatasize;
-char *q1_dentdata;//[MAX_MAP_ENTSTRING];
-
-int q1_numleafs;
-q1_dleaf_t *q1_dleafs;//[MAX_MAP_LEAFS];
-
-int q1_numplanes;
-q1_dplane_t *q1_dplanes;//[MAX_MAP_PLANES];
-
-int q1_numvertexes;
-q1_dvertex_t *q1_dvertexes;//[MAX_MAP_VERTS];
-
-int q1_numnodes;
-q1_dnode_t *q1_dnodes;//[MAX_MAP_NODES];
-
-int q1_numtexinfo;
-q1_texinfo_t *q1_texinfo;//[MAX_MAP_TEXINFO];
-
-int q1_numfaces;
-q1_dface_t *q1_dfaces;//[MAX_MAP_FACES];
-
-int q1_numclipnodes;
-q1_dclipnode_t *q1_dclipnodes;//[MAX_MAP_CLIPNODES];
-
-int q1_numedges;
-q1_dedge_t *q1_dedges;//[MAX_MAP_EDGES];
-
-int q1_nummarksurfaces;
-unsigned short *q1_dmarksurfaces;//[MAX_MAP_MARKSURFACES];
-
-int q1_numsurfedges;
-int *q1_dsurfedges;//[MAX_MAP_SURFEDGES];
-
-//=============================================================================
-
-int q1_bspallocated = false;
-int q1_allocatedbspmem = 0;
-
-void Q1_AllocMaxBSP(void)
-{
- //models
- q1_nummodels = 0;
- q1_dmodels = (q1_dmodel_t *) GetMemory(Q1_MAX_MAP_MODELS * sizeof(q1_dmodel_t));
- q1_allocatedbspmem = Q1_MAX_MAP_MODELS * sizeof(q1_dmodel_t);
- //visibility
- q1_visdatasize = 0;
- q1_dvisdata = (byte *) GetMemory(Q1_MAX_MAP_VISIBILITY * sizeof(byte));
- q1_allocatedbspmem += Q1_MAX_MAP_VISIBILITY * sizeof(byte);
- //light data
- q1_lightdatasize = 0;
- q1_dlightdata = (byte *) GetMemory(Q1_MAX_MAP_LIGHTING * sizeof(byte));
- q1_allocatedbspmem += Q1_MAX_MAP_LIGHTING * sizeof(byte);
- //texture data
- q1_texdatasize = 0;
- q1_dtexdata = (byte *) GetMemory(Q1_MAX_MAP_MIPTEX * sizeof(byte)); // (dmiptexlump_t)
- q1_allocatedbspmem += Q1_MAX_MAP_MIPTEX * sizeof(byte);
- //entities
- q1_entdatasize = 0;
- q1_dentdata = (char *) GetMemory(Q1_MAX_MAP_ENTSTRING * sizeof(char));
- q1_allocatedbspmem += Q1_MAX_MAP_ENTSTRING * sizeof(char);
- //leaves
- q1_numleafs = 0;
- q1_dleafs = (q1_dleaf_t *) GetMemory(Q1_MAX_MAP_LEAFS * sizeof(q1_dleaf_t));
- q1_allocatedbspmem += Q1_MAX_MAP_LEAFS * sizeof(q1_dleaf_t);
- //planes
- q1_numplanes = 0;
- q1_dplanes = (q1_dplane_t *) GetMemory(Q1_MAX_MAP_PLANES * sizeof(q1_dplane_t));
- q1_allocatedbspmem += Q1_MAX_MAP_PLANES * sizeof(q1_dplane_t);
- //vertexes
- q1_numvertexes = 0;
- q1_dvertexes = (q1_dvertex_t *) GetMemory(Q1_MAX_MAP_VERTS * sizeof(q1_dvertex_t));
- q1_allocatedbspmem += Q1_MAX_MAP_VERTS * sizeof(q1_dvertex_t);
- //nodes
- q1_numnodes = 0;
- q1_dnodes = (q1_dnode_t *) GetMemory(Q1_MAX_MAP_NODES * sizeof(q1_dnode_t));
- q1_allocatedbspmem += Q1_MAX_MAP_NODES * sizeof(q1_dnode_t);
- //texture info
- q1_numtexinfo = 0;
- q1_texinfo = (q1_texinfo_t *) GetMemory(Q1_MAX_MAP_TEXINFO * sizeof(q1_texinfo_t));
- q1_allocatedbspmem += Q1_MAX_MAP_TEXINFO * sizeof(q1_texinfo_t);
- //faces
- q1_numfaces = 0;
- q1_dfaces = (q1_dface_t *) GetMemory(Q1_MAX_MAP_FACES * sizeof(q1_dface_t));
- q1_allocatedbspmem += Q1_MAX_MAP_FACES * sizeof(q1_dface_t);
- //clip nodes
- q1_numclipnodes = 0;
- q1_dclipnodes = (q1_dclipnode_t *) GetMemory(Q1_MAX_MAP_CLIPNODES * sizeof(q1_dclipnode_t));
- q1_allocatedbspmem += Q1_MAX_MAP_CLIPNODES * sizeof(q1_dclipnode_t);
- //edges
- q1_numedges = 0;
- q1_dedges = (q1_dedge_t *) GetMemory(Q1_MAX_MAP_EDGES * sizeof(q1_dedge_t));
- q1_allocatedbspmem += Q1_MAX_MAP_EDGES, sizeof(q1_dedge_t);
- //mark surfaces
- q1_nummarksurfaces = 0;
- q1_dmarksurfaces = (unsigned short *) GetMemory(Q1_MAX_MAP_MARKSURFACES * sizeof(unsigned short));
- q1_allocatedbspmem += Q1_MAX_MAP_MARKSURFACES * sizeof(unsigned short);
- //surface edges
- q1_numsurfedges = 0;
- q1_dsurfedges = (int *) GetMemory(Q1_MAX_MAP_SURFEDGES * sizeof(int));
- q1_allocatedbspmem += Q1_MAX_MAP_SURFEDGES * sizeof(int);
- //print allocated memory
- Log_Print("allocated ");
- PrintMemorySize(q1_allocatedbspmem);
- Log_Print(" of BSP memory\n");
-} //end of the function Q1_AllocMaxBSP
-
-void Q1_FreeMaxBSP(void)
-{
- //models
- q1_nummodels = 0;
- FreeMemory(q1_dmodels);
- q1_dmodels = NULL;
- //visibility
- q1_visdatasize = 0;
- FreeMemory(q1_dvisdata);
- q1_dvisdata = NULL;
- //light data
- q1_lightdatasize = 0;
- FreeMemory(q1_dlightdata);
- q1_dlightdata = NULL;
- //texture data
- q1_texdatasize = 0;
- FreeMemory(q1_dtexdata);
- q1_dtexdata = NULL;
- //entities
- q1_entdatasize = 0;
- FreeMemory(q1_dentdata);
- q1_dentdata = NULL;
- //leaves
- q1_numleafs = 0;
- FreeMemory(q1_dleafs);
- q1_dleafs = NULL;
- //planes
- q1_numplanes = 0;
- FreeMemory(q1_dplanes);
- q1_dplanes = NULL;
- //vertexes
- q1_numvertexes = 0;
- FreeMemory(q1_dvertexes);
- q1_dvertexes = NULL;
- //nodes
- q1_numnodes = 0;
- FreeMemory(q1_dnodes);
- q1_dnodes = NULL;
- //texture info
- q1_numtexinfo = 0;
- FreeMemory(q1_texinfo);
- q1_texinfo = NULL;
- //faces
- q1_numfaces = 0;
- FreeMemory(q1_dfaces);
- q1_dfaces = NULL;
- //clip nodes
- q1_numclipnodes = 0;
- FreeMemory(q1_dclipnodes);
- q1_dclipnodes = NULL;
- //edges
- q1_numedges = 0;
- FreeMemory(q1_dedges);
- q1_dedges = NULL;
- //mark surfaces
- q1_nummarksurfaces = 0;
- FreeMemory(q1_dmarksurfaces);
- q1_dmarksurfaces = NULL;
- //surface edges
- q1_numsurfedges = 0;
- FreeMemory(q1_dsurfedges);
- q1_dsurfedges = NULL;
- //
- Log_Print("freed ");
- PrintMemorySize(q1_allocatedbspmem);
- Log_Print(" of BSP memory\n");
- q1_allocatedbspmem = 0;
-} //end of the function Q1_FreeMaxBSP
-//#endif //ME
-
-/*
-=============
-Q1_SwapBSPFile
-
-Byte swaps all data in a bsp file.
-=============
-*/
-void Q1_SwapBSPFile (qboolean todisk)
-{
- int i, j, c;
- q1_dmodel_t *d;
- q1_dmiptexlump_t *mtl;
-
-
-// models
- for (i=0 ; i<q1_nummodels ; i++)
- {
- d = &q1_dmodels[i];
-
- for (j=0 ; j<Q1_MAX_MAP_HULLS ; j++)
- d->headnode[j] = LittleLong (d->headnode[j]);
-
- d->visleafs = LittleLong (d->visleafs);
- d->firstface = LittleLong (d->firstface);
- d->numfaces = LittleLong (d->numfaces);
-
- for (j=0 ; j<3 ; j++)
- {
- d->mins[j] = LittleFloat(d->mins[j]);
- d->maxs[j] = LittleFloat(d->maxs[j]);
- d->origin[j] = LittleFloat(d->origin[j]);
- }
- }
-
-//
-// vertexes
-//
- for (i=0 ; i<q1_numvertexes ; i++)
- {
- for (j=0 ; j<3 ; j++)
- q1_dvertexes[i].point[j] = LittleFloat(q1_dvertexes[i].point[j]);
- }
-
-//
-// planes
-//
- for (i=0 ; i<q1_numplanes ; i++)
- {
- for (j=0 ; j<3 ; j++)
- q1_dplanes[i].normal[j] = LittleFloat(q1_dplanes[i].normal[j]);
- q1_dplanes[i].dist = LittleFloat(q1_dplanes[i].dist);
- q1_dplanes[i].type = LittleLong(q1_dplanes[i].type);
- }
-
-//
-// texinfos
-//
- for (i=0 ; i<q1_numtexinfo ; i++)
- {
- for (j=0 ; j<8 ; j++)
- q1_texinfo[i].vecs[0][j] = LittleFloat(q1_texinfo[i].vecs[0][j]);
- q1_texinfo[i].miptex = LittleLong(q1_texinfo[i].miptex);
- q1_texinfo[i].flags = LittleLong(q1_texinfo[i].flags);
- }
-
-//
-// faces
-//
- for (i=0 ; i<q1_numfaces ; i++)
- {
- q1_dfaces[i].texinfo = LittleShort(q1_dfaces[i].texinfo);
- q1_dfaces[i].planenum = LittleShort(q1_dfaces[i].planenum);
- q1_dfaces[i].side = LittleShort(q1_dfaces[i].side);
- q1_dfaces[i].lightofs = LittleLong(q1_dfaces[i].lightofs);
- q1_dfaces[i].firstedge = LittleLong(q1_dfaces[i].firstedge);
- q1_dfaces[i].numedges = LittleShort(q1_dfaces[i].numedges);
- }
-
-//
-// nodes
-//
- for (i=0 ; i<q1_numnodes ; i++)
- {
- q1_dnodes[i].planenum = LittleLong(q1_dnodes[i].planenum);
- for (j=0 ; j<3 ; j++)
- {
- q1_dnodes[i].mins[j] = LittleShort(q1_dnodes[i].mins[j]);
- q1_dnodes[i].maxs[j] = LittleShort(q1_dnodes[i].maxs[j]);
- }
- q1_dnodes[i].children[0] = LittleShort(q1_dnodes[i].children[0]);
- q1_dnodes[i].children[1] = LittleShort(q1_dnodes[i].children[1]);
- q1_dnodes[i].firstface = LittleShort(q1_dnodes[i].firstface);
- q1_dnodes[i].numfaces = LittleShort(q1_dnodes[i].numfaces);
- }
-
-//
-// leafs
-//
- for (i=0 ; i<q1_numleafs ; i++)
- {
- q1_dleafs[i].contents = LittleLong(q1_dleafs[i].contents);
- for (j=0 ; j<3 ; j++)
- {
- q1_dleafs[i].mins[j] = LittleShort(q1_dleafs[i].mins[j]);
- q1_dleafs[i].maxs[j] = LittleShort(q1_dleafs[i].maxs[j]);
- }
-
- q1_dleafs[i].firstmarksurface = LittleShort(q1_dleafs[i].firstmarksurface);
- q1_dleafs[i].nummarksurfaces = LittleShort(q1_dleafs[i].nummarksurfaces);
- q1_dleafs[i].visofs = LittleLong(q1_dleafs[i].visofs);
- }
-
-//
-// clipnodes
-//
- for (i=0 ; i<q1_numclipnodes ; i++)
- {
- q1_dclipnodes[i].planenum = LittleLong(q1_dclipnodes[i].planenum);
- q1_dclipnodes[i].children[0] = LittleShort(q1_dclipnodes[i].children[0]);
- q1_dclipnodes[i].children[1] = LittleShort(q1_dclipnodes[i].children[1]);
- }
-
-//
-// miptex
-//
- if (q1_texdatasize)
- {
- mtl = (q1_dmiptexlump_t *)q1_dtexdata;
- if (todisk)
- c = mtl->nummiptex;
- else
- c = LittleLong(mtl->nummiptex);
- mtl->nummiptex = LittleLong (mtl->nummiptex);
- for (i=0 ; i<c ; i++)
- mtl->dataofs[i] = LittleLong(mtl->dataofs[i]);
- }
-
-//
-// marksurfaces
-//
- for (i=0 ; i<q1_nummarksurfaces ; i++)
- q1_dmarksurfaces[i] = LittleShort(q1_dmarksurfaces[i]);
-
-//
-// surfedges
-//
- for (i=0 ; i<q1_numsurfedges ; i++)
- q1_dsurfedges[i] = LittleLong(q1_dsurfedges[i]);
-
-//
-// edges
-//
- for (i=0 ; i<q1_numedges ; i++)
- {
- q1_dedges[i].v[0] = LittleShort(q1_dedges[i].v[0]);
- q1_dedges[i].v[1] = LittleShort(q1_dedges[i].v[1]);
- }
-}
-
-
-q1_dheader_t *q1_header;
-int q1_fileLength;
-
-int Q1_CopyLump (int lump, void *dest, int size, int maxsize)
-{
- int length, ofs;
-
- length = q1_header->lumps[lump].filelen;
- ofs = q1_header->lumps[lump].fileofs;
-
- if (length % size) {
- Error ("LoadBSPFile: odd lump size");
- }
- // somehow things got out of range
- if ((length/size) > maxsize) {
- printf("WARNING: exceeded max size for lump %d size %d > maxsize %d\n", lump, (length/size), maxsize);
- length = maxsize * size;
- }
- if ( ofs + length > q1_fileLength ) {
- printf("WARNING: exceeded file length for lump %d\n", lump);
- length = q1_fileLength - ofs;
- if ( length <= 0 ) {
- return 0;
- }
- }
-
- memcpy (dest, (byte *)q1_header + ofs, length);
-
- return length / size;
-}
-
-/*
-=============
-Q1_LoadBSPFile
-=============
-*/
-void Q1_LoadBSPFile(char *filename, int offset, int length)
-{
- int i;
-
-//
-// load the file header
-//
- q1_fileLength = LoadFile(filename, (void **)&q1_header, offset, length);
-
-// swap the header
- for (i=0 ; i< sizeof(q1_dheader_t)/4 ; i++)
- ((int *)q1_header)[i] = LittleLong ( ((int *)q1_header)[i]);
-
- if (q1_header->version != Q1_BSPVERSION)
- Error ("%s is version %i, not %i", filename, i, Q1_BSPVERSION);
-
- q1_nummodels = Q1_CopyLump (Q1_LUMP_MODELS, q1_dmodels, sizeof(q1_dmodel_t), Q1_MAX_MAP_MODELS );
- q1_numvertexes = Q1_CopyLump (Q1_LUMP_VERTEXES, q1_dvertexes, sizeof(q1_dvertex_t), Q1_MAX_MAP_VERTS );
- q1_numplanes = Q1_CopyLump (Q1_LUMP_PLANES, q1_dplanes, sizeof(q1_dplane_t), Q1_MAX_MAP_PLANES );
- q1_numleafs = Q1_CopyLump (Q1_LUMP_LEAFS, q1_dleafs, sizeof(q1_dleaf_t), Q1_MAX_MAP_LEAFS );
- q1_numnodes = Q1_CopyLump (Q1_LUMP_NODES, q1_dnodes, sizeof(q1_dnode_t), Q1_MAX_MAP_NODES );
- q1_numtexinfo = Q1_CopyLump (Q1_LUMP_TEXINFO, q1_texinfo, sizeof(q1_texinfo_t), Q1_MAX_MAP_TEXINFO );
- q1_numclipnodes = Q1_CopyLump (Q1_LUMP_CLIPNODES, q1_dclipnodes, sizeof(q1_dclipnode_t), Q1_MAX_MAP_CLIPNODES );
- q1_numfaces = Q1_CopyLump (Q1_LUMP_FACES, q1_dfaces, sizeof(q1_dface_t), Q1_MAX_MAP_FACES );
- q1_nummarksurfaces = Q1_CopyLump (Q1_LUMP_MARKSURFACES, q1_dmarksurfaces, sizeof(q1_dmarksurfaces[0]), Q1_MAX_MAP_MARKSURFACES );
- q1_numsurfedges = Q1_CopyLump (Q1_LUMP_SURFEDGES, q1_dsurfedges, sizeof(q1_dsurfedges[0]), Q1_MAX_MAP_SURFEDGES );
- q1_numedges = Q1_CopyLump (Q1_LUMP_EDGES, q1_dedges, sizeof(q1_dedge_t), Q1_MAX_MAP_EDGES );
-
- q1_texdatasize = Q1_CopyLump (Q1_LUMP_TEXTURES, q1_dtexdata, 1, Q1_MAX_MAP_MIPTEX );
- q1_visdatasize = Q1_CopyLump (Q1_LUMP_VISIBILITY, q1_dvisdata, 1, Q1_MAX_MAP_VISIBILITY );
- q1_lightdatasize = Q1_CopyLump (Q1_LUMP_LIGHTING, q1_dlightdata, 1, Q1_MAX_MAP_LIGHTING );
- q1_entdatasize = Q1_CopyLump (Q1_LUMP_ENTITIES, q1_dentdata, 1, Q1_MAX_MAP_ENTSTRING );
-
- FreeMemory(q1_header); // everything has been copied out
-
-//
-// swap everything
-//
- Q1_SwapBSPFile (false);
-}
-
-//============================================================================
-
-FILE *q1_wadfile;
-q1_dheader_t q1_outheader;
-
-void Q1_AddLump (int lumpnum, void *data, int len)
-{
- q1_lump_t *lump;
-
- lump = &q1_header->lumps[lumpnum];
-
- lump->fileofs = LittleLong(ftell(q1_wadfile));
- lump->filelen = LittleLong(len);
- SafeWrite(q1_wadfile, data, (len+3)&~3);
-}
-
-/*
-=============
-Q1_WriteBSPFile
-
-Swaps the bsp file in place, so it should not be referenced again
-=============
-*/
-void Q1_WriteBSPFile (char *filename)
-{
- q1_header = &q1_outheader;
- memset (q1_header, 0, sizeof(q1_dheader_t));
-
- Q1_SwapBSPFile (true);
-
- q1_header->version = LittleLong (Q1_BSPVERSION);
-
- q1_wadfile = SafeOpenWrite (filename);
- SafeWrite (q1_wadfile, q1_header, sizeof(q1_dheader_t)); // overwritten later
-
- Q1_AddLump (Q1_LUMP_PLANES, q1_dplanes, q1_numplanes*sizeof(q1_dplane_t));
- Q1_AddLump (Q1_LUMP_LEAFS, q1_dleafs, q1_numleafs*sizeof(q1_dleaf_t));
- Q1_AddLump (Q1_LUMP_VERTEXES, q1_dvertexes, q1_numvertexes*sizeof(q1_dvertex_t));
- Q1_AddLump (Q1_LUMP_NODES, q1_dnodes, q1_numnodes*sizeof(q1_dnode_t));
- Q1_AddLump (Q1_LUMP_TEXINFO, q1_texinfo, q1_numtexinfo*sizeof(q1_texinfo_t));
- Q1_AddLump (Q1_LUMP_FACES, q1_dfaces, q1_numfaces*sizeof(q1_dface_t));
- Q1_AddLump (Q1_LUMP_CLIPNODES, q1_dclipnodes, q1_numclipnodes*sizeof(q1_dclipnode_t));
- Q1_AddLump (Q1_LUMP_MARKSURFACES, q1_dmarksurfaces, q1_nummarksurfaces*sizeof(q1_dmarksurfaces[0]));
- Q1_AddLump (Q1_LUMP_SURFEDGES, q1_dsurfedges, q1_numsurfedges*sizeof(q1_dsurfedges[0]));
- Q1_AddLump (Q1_LUMP_EDGES, q1_dedges, q1_numedges*sizeof(q1_dedge_t));
- Q1_AddLump (Q1_LUMP_MODELS, q1_dmodels, q1_nummodels*sizeof(q1_dmodel_t));
-
- Q1_AddLump (Q1_LUMP_LIGHTING, q1_dlightdata, q1_lightdatasize);
- Q1_AddLump (Q1_LUMP_VISIBILITY, q1_dvisdata, q1_visdatasize);
- Q1_AddLump (Q1_LUMP_ENTITIES, q1_dentdata, q1_entdatasize);
- Q1_AddLump (Q1_LUMP_TEXTURES, q1_dtexdata, q1_texdatasize);
-
- fseek (q1_wadfile, 0, SEEK_SET);
- SafeWrite (q1_wadfile, q1_header, sizeof(q1_dheader_t));
- fclose (q1_wadfile);
-}
-
-//============================================================================
-
-/*
-=============
-Q1_PrintBSPFileSizes
-
-Dumps info about current file
-=============
-*/
-void Q1_PrintBSPFileSizes (void)
-{
- printf ("%5i planes %6i\n"
- ,q1_numplanes, (int)(q1_numplanes*sizeof(q1_dplane_t)));
- printf ("%5i vertexes %6i\n"
- ,q1_numvertexes, (int)(q1_numvertexes*sizeof(q1_dvertex_t)));
- printf ("%5i nodes %6i\n"
- ,q1_numnodes, (int)(q1_numnodes*sizeof(q1_dnode_t)));
- printf ("%5i texinfo %6i\n"
- ,q1_numtexinfo, (int)(q1_numtexinfo*sizeof(q1_texinfo_t)));
- printf ("%5i faces %6i\n"
- ,q1_numfaces, (int)(q1_numfaces*sizeof(q1_dface_t)));
- printf ("%5i clipnodes %6i\n"
- ,q1_numclipnodes, (int)(q1_numclipnodes*sizeof(q1_dclipnode_t)));
- printf ("%5i leafs %6i\n"
- ,q1_numleafs, (int)(q1_numleafs*sizeof(q1_dleaf_t)));
- printf ("%5i marksurfaces %6i\n"
- ,q1_nummarksurfaces, (int)(q1_nummarksurfaces*sizeof(q1_dmarksurfaces[0])));
- printf ("%5i surfedges %6i\n"
- ,q1_numsurfedges, (int)(q1_numsurfedges*sizeof(q1_dmarksurfaces[0])));
- printf ("%5i edges %6i\n"
- ,q1_numedges, (int)(q1_numedges*sizeof(q1_dedge_t)));
- if (!q1_texdatasize)
- printf (" 0 textures 0\n");
- else
- printf ("%5i textures %6i\n",((q1_dmiptexlump_t*)q1_dtexdata)->nummiptex, q1_texdatasize);
- printf (" lightdata %6i\n", q1_lightdatasize);
- printf (" visdata %6i\n", q1_visdatasize);
- printf (" entdata %6i\n", q1_entdatasize);
-} //end of the function Q1_PrintBSPFileSizes
-
-
-/*
-================
-Q1_ParseEntities
-
-Parses the dentdata string into entities
-================
-*/
-void Q1_ParseEntities (void)
-{
- script_t *script;
-
- num_entities = 0;
- script = LoadScriptMemory(q1_dentdata, q1_entdatasize, "*Quake1 bsp file");
- SetScriptFlags(script, SCFL_NOSTRINGWHITESPACES |
- SCFL_NOSTRINGESCAPECHARS);
-
- while(ParseEntity(script))
- {
- } //end while
-
- FreeScript(script);
-} //end of the function Q1_ParseEntities
-
-
-/*
-================
-Q1_UnparseEntities
-
-Generates the dentdata string from all the entities
-================
-*/
-void Q1_UnparseEntities (void)
-{
- char *buf, *end;
- epair_t *ep;
- char line[2048];
- int i;
-
- buf = q1_dentdata;
- end = buf;
- *end = 0;
-
- for (i=0 ; i<num_entities ; i++)
- {
- ep = entities[i].epairs;
- if (!ep)
- continue; // ent got removed
-
- strcat (end,"{\n");
- end += 2;
-
- for (ep = entities[i].epairs ; ep ; ep=ep->next)
- {
- sprintf (line, "\"%s\" \"%s\"\n", ep->key, ep->value);
- strcat (end, line);
- end += strlen(line);
- }
- strcat (end,"}\n");
- end += 2;
-
- if (end > buf + Q1_MAX_MAP_ENTSTRING)
- Error ("Entity text too long");
- }
- q1_entdatasize = end - buf + 1;
-} //end of the function Q1_UnparseEntities
+/*
+===========================================================================
+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 "l_cmd.h"
+#include "l_math.h"
+#include "l_mem.h"
+#include "l_log.h"
+#include "../botlib/l_script.h"
+#include "l_bsp_q1.h"
+#include "l_bsp_ent.h"
+
+//=============================================================================
+
+int q1_nummodels;
+q1_dmodel_t *q1_dmodels;//[MAX_MAP_MODELS];
+
+int q1_visdatasize;
+byte *q1_dvisdata;//[MAX_MAP_VISIBILITY];
+
+int q1_lightdatasize;
+byte *q1_dlightdata;//[MAX_MAP_LIGHTING];
+
+int q1_texdatasize;
+byte *q1_dtexdata;//[MAX_MAP_MIPTEX]; // (dmiptexlump_t)
+
+int q1_entdatasize;
+char *q1_dentdata;//[MAX_MAP_ENTSTRING];
+
+int q1_numleafs;
+q1_dleaf_t *q1_dleafs;//[MAX_MAP_LEAFS];
+
+int q1_numplanes;
+q1_dplane_t *q1_dplanes;//[MAX_MAP_PLANES];
+
+int q1_numvertexes;
+q1_dvertex_t *q1_dvertexes;//[MAX_MAP_VERTS];
+
+int q1_numnodes;
+q1_dnode_t *q1_dnodes;//[MAX_MAP_NODES];
+
+int q1_numtexinfo;
+q1_texinfo_t *q1_texinfo;//[MAX_MAP_TEXINFO];
+
+int q1_numfaces;
+q1_dface_t *q1_dfaces;//[MAX_MAP_FACES];
+
+int q1_numclipnodes;
+q1_dclipnode_t *q1_dclipnodes;//[MAX_MAP_CLIPNODES];
+
+int q1_numedges;
+q1_dedge_t *q1_dedges;//[MAX_MAP_EDGES];
+
+int q1_nummarksurfaces;
+unsigned short *q1_dmarksurfaces;//[MAX_MAP_MARKSURFACES];
+
+int q1_numsurfedges;
+int *q1_dsurfedges;//[MAX_MAP_SURFEDGES];
+
+//=============================================================================
+
+int q1_bspallocated = false;
+int q1_allocatedbspmem = 0;
+
+void Q1_AllocMaxBSP(void)
+{
+ //models
+ q1_nummodels = 0;
+ q1_dmodels = (q1_dmodel_t *) GetMemory(Q1_MAX_MAP_MODELS * sizeof(q1_dmodel_t));
+ q1_allocatedbspmem = Q1_MAX_MAP_MODELS * sizeof(q1_dmodel_t);
+ //visibility
+ q1_visdatasize = 0;
+ q1_dvisdata = (byte *) GetMemory(Q1_MAX_MAP_VISIBILITY * sizeof(byte));
+ q1_allocatedbspmem += Q1_MAX_MAP_VISIBILITY * sizeof(byte);
+ //light data
+ q1_lightdatasize = 0;
+ q1_dlightdata = (byte *) GetMemory(Q1_MAX_MAP_LIGHTING * sizeof(byte));
+ q1_allocatedbspmem += Q1_MAX_MAP_LIGHTING * sizeof(byte);
+ //texture data
+ q1_texdatasize = 0;
+ q1_dtexdata = (byte *) GetMemory(Q1_MAX_MAP_MIPTEX * sizeof(byte)); // (dmiptexlump_t)
+ q1_allocatedbspmem += Q1_MAX_MAP_MIPTEX * sizeof(byte);
+ //entities
+ q1_entdatasize = 0;
+ q1_dentdata = (char *) GetMemory(Q1_MAX_MAP_ENTSTRING * sizeof(char));
+ q1_allocatedbspmem += Q1_MAX_MAP_ENTSTRING * sizeof(char);
+ //leaves
+ q1_numleafs = 0;
+ q1_dleafs = (q1_dleaf_t *) GetMemory(Q1_MAX_MAP_LEAFS * sizeof(q1_dleaf_t));
+ q1_allocatedbspmem += Q1_MAX_MAP_LEAFS * sizeof(q1_dleaf_t);
+ //planes
+ q1_numplanes = 0;
+ q1_dplanes = (q1_dplane_t *) GetMemory(Q1_MAX_MAP_PLANES * sizeof(q1_dplane_t));
+ q1_allocatedbspmem += Q1_MAX_MAP_PLANES * sizeof(q1_dplane_t);
+ //vertexes
+ q1_numvertexes = 0;
+ q1_dvertexes = (q1_dvertex_t *) GetMemory(Q1_MAX_MAP_VERTS * sizeof(q1_dvertex_t));
+ q1_allocatedbspmem += Q1_MAX_MAP_VERTS * sizeof(q1_dvertex_t);
+ //nodes
+ q1_numnodes = 0;
+ q1_dnodes = (q1_dnode_t *) GetMemory(Q1_MAX_MAP_NODES * sizeof(q1_dnode_t));
+ q1_allocatedbspmem += Q1_MAX_MAP_NODES * sizeof(q1_dnode_t);
+ //texture info
+ q1_numtexinfo = 0;
+ q1_texinfo = (q1_texinfo_t *) GetMemory(Q1_MAX_MAP_TEXINFO * sizeof(q1_texinfo_t));
+ q1_allocatedbspmem += Q1_MAX_MAP_TEXINFO * sizeof(q1_texinfo_t);
+ //faces
+ q1_numfaces = 0;
+ q1_dfaces = (q1_dface_t *) GetMemory(Q1_MAX_MAP_FACES * sizeof(q1_dface_t));
+ q1_allocatedbspmem += Q1_MAX_MAP_FACES * sizeof(q1_dface_t);
+ //clip nodes
+ q1_numclipnodes = 0;
+ q1_dclipnodes = (q1_dclipnode_t *) GetMemory(Q1_MAX_MAP_CLIPNODES * sizeof(q1_dclipnode_t));
+ q1_allocatedbspmem += Q1_MAX_MAP_CLIPNODES * sizeof(q1_dclipnode_t);
+ //edges
+ q1_numedges = 0;
+ q1_dedges = (q1_dedge_t *) GetMemory(Q1_MAX_MAP_EDGES * sizeof(q1_dedge_t));
+ q1_allocatedbspmem += Q1_MAX_MAP_EDGES, sizeof(q1_dedge_t);
+ //mark surfaces
+ q1_nummarksurfaces = 0;
+ q1_dmarksurfaces = (unsigned short *) GetMemory(Q1_MAX_MAP_MARKSURFACES * sizeof(unsigned short));
+ q1_allocatedbspmem += Q1_MAX_MAP_MARKSURFACES * sizeof(unsigned short);
+ //surface edges
+ q1_numsurfedges = 0;
+ q1_dsurfedges = (int *) GetMemory(Q1_MAX_MAP_SURFEDGES * sizeof(int));
+ q1_allocatedbspmem += Q1_MAX_MAP_SURFEDGES * sizeof(int);
+ //print allocated memory
+ Log_Print("allocated ");
+ PrintMemorySize(q1_allocatedbspmem);
+ Log_Print(" of BSP memory\n");
+} //end of the function Q1_AllocMaxBSP
+
+void Q1_FreeMaxBSP(void)
+{
+ //models
+ q1_nummodels = 0;
+ FreeMemory(q1_dmodels);
+ q1_dmodels = NULL;
+ //visibility
+ q1_visdatasize = 0;
+ FreeMemory(q1_dvisdata);
+ q1_dvisdata = NULL;
+ //light data
+ q1_lightdatasize = 0;
+ FreeMemory(q1_dlightdata);
+ q1_dlightdata = NULL;
+ //texture data
+ q1_texdatasize = 0;
+ FreeMemory(q1_dtexdata);
+ q1_dtexdata = NULL;
+ //entities
+ q1_entdatasize = 0;
+ FreeMemory(q1_dentdata);
+ q1_dentdata = NULL;
+ //leaves
+ q1_numleafs = 0;
+ FreeMemory(q1_dleafs);
+ q1_dleafs = NULL;
+ //planes
+ q1_numplanes = 0;
+ FreeMemory(q1_dplanes);
+ q1_dplanes = NULL;
+ //vertexes
+ q1_numvertexes = 0;
+ FreeMemory(q1_dvertexes);
+ q1_dvertexes = NULL;
+ //nodes
+ q1_numnodes = 0;
+ FreeMemory(q1_dnodes);
+ q1_dnodes = NULL;
+ //texture info
+ q1_numtexinfo = 0;
+ FreeMemory(q1_texinfo);
+ q1_texinfo = NULL;
+ //faces
+ q1_numfaces = 0;
+ FreeMemory(q1_dfaces);
+ q1_dfaces = NULL;
+ //clip nodes
+ q1_numclipnodes = 0;
+ FreeMemory(q1_dclipnodes);
+ q1_dclipnodes = NULL;
+ //edges
+ q1_numedges = 0;
+ FreeMemory(q1_dedges);
+ q1_dedges = NULL;
+ //mark surfaces
+ q1_nummarksurfaces = 0;
+ FreeMemory(q1_dmarksurfaces);
+ q1_dmarksurfaces = NULL;
+ //surface edges
+ q1_numsurfedges = 0;
+ FreeMemory(q1_dsurfedges);
+ q1_dsurfedges = NULL;
+ //
+ Log_Print("freed ");
+ PrintMemorySize(q1_allocatedbspmem);
+ Log_Print(" of BSP memory\n");
+ q1_allocatedbspmem = 0;
+} //end of the function Q1_FreeMaxBSP
+//#endif //ME
+
+/*
+=============
+Q1_SwapBSPFile
+
+Byte swaps all data in a bsp file.
+=============
+*/
+void Q1_SwapBSPFile (qboolean todisk)
+{
+ int i, j, c;
+ q1_dmodel_t *d;
+ q1_dmiptexlump_t *mtl;
+
+
+// models
+ for (i=0 ; i<q1_nummodels ; i++)
+ {
+ d = &q1_dmodels[i];
+
+ for (j=0 ; j<Q1_MAX_MAP_HULLS ; j++)
+ d->headnode[j] = LittleLong (d->headnode[j]);
+
+ d->visleafs = LittleLong (d->visleafs);
+ d->firstface = LittleLong (d->firstface);
+ d->numfaces = LittleLong (d->numfaces);
+
+ for (j=0 ; j<3 ; j++)
+ {
+ d->mins[j] = LittleFloat(d->mins[j]);
+ d->maxs[j] = LittleFloat(d->maxs[j]);
+ d->origin[j] = LittleFloat(d->origin[j]);
+ }
+ }
+
+//
+// vertexes
+//
+ for (i=0 ; i<q1_numvertexes ; i++)
+ {
+ for (j=0 ; j<3 ; j++)
+ q1_dvertexes[i].point[j] = LittleFloat(q1_dvertexes[i].point[j]);
+ }
+
+//
+// planes
+//
+ for (i=0 ; i<q1_numplanes ; i++)
+ {
+ for (j=0 ; j<3 ; j++)
+ q1_dplanes[i].normal[j] = LittleFloat(q1_dplanes[i].normal[j]);
+ q1_dplanes[i].dist = LittleFloat(q1_dplanes[i].dist);
+ q1_dplanes[i].type = LittleLong(q1_dplanes[i].type);
+ }
+
+//
+// texinfos
+//
+ for (i=0 ; i<q1_numtexinfo ; i++)
+ {
+ for (j=0 ; j<8 ; j++)
+ q1_texinfo[i].vecs[0][j] = LittleFloat(q1_texinfo[i].vecs[0][j]);
+ q1_texinfo[i].miptex = LittleLong(q1_texinfo[i].miptex);
+ q1_texinfo[i].flags = LittleLong(q1_texinfo[i].flags);
+ }
+
+//
+// faces
+//
+ for (i=0 ; i<q1_numfaces ; i++)
+ {
+ q1_dfaces[i].texinfo = LittleShort(q1_dfaces[i].texinfo);
+ q1_dfaces[i].planenum = LittleShort(q1_dfaces[i].planenum);
+ q1_dfaces[i].side = LittleShort(q1_dfaces[i].side);
+ q1_dfaces[i].lightofs = LittleLong(q1_dfaces[i].lightofs);
+ q1_dfaces[i].firstedge = LittleLong(q1_dfaces[i].firstedge);
+ q1_dfaces[i].numedges = LittleShort(q1_dfaces[i].numedges);
+ }
+
+//
+// nodes
+//
+ for (i=0 ; i<q1_numnodes ; i++)
+ {
+ q1_dnodes[i].planenum = LittleLong(q1_dnodes[i].planenum);
+ for (j=0 ; j<3 ; j++)
+ {
+ q1_dnodes[i].mins[j] = LittleShort(q1_dnodes[i].mins[j]);
+ q1_dnodes[i].maxs[j] = LittleShort(q1_dnodes[i].maxs[j]);
+ }
+ q1_dnodes[i].children[0] = LittleShort(q1_dnodes[i].children[0]);
+ q1_dnodes[i].children[1] = LittleShort(q1_dnodes[i].children[1]);
+ q1_dnodes[i].firstface = LittleShort(q1_dnodes[i].firstface);
+ q1_dnodes[i].numfaces = LittleShort(q1_dnodes[i].numfaces);
+ }
+
+//
+// leafs
+//
+ for (i=0 ; i<q1_numleafs ; i++)
+ {
+ q1_dleafs[i].contents = LittleLong(q1_dleafs[i].contents);
+ for (j=0 ; j<3 ; j++)
+ {
+ q1_dleafs[i].mins[j] = LittleShort(q1_dleafs[i].mins[j]);
+ q1_dleafs[i].maxs[j] = LittleShort(q1_dleafs[i].maxs[j]);
+ }
+
+ q1_dleafs[i].firstmarksurface = LittleShort(q1_dleafs[i].firstmarksurface);
+ q1_dleafs[i].nummarksurfaces = LittleShort(q1_dleafs[i].nummarksurfaces);
+ q1_dleafs[i].visofs = LittleLong(q1_dleafs[i].visofs);
+ }
+
+//
+// clipnodes
+//
+ for (i=0 ; i<q1_numclipnodes ; i++)
+ {
+ q1_dclipnodes[i].planenum = LittleLong(q1_dclipnodes[i].planenum);
+ q1_dclipnodes[i].children[0] = LittleShort(q1_dclipnodes[i].children[0]);
+ q1_dclipnodes[i].children[1] = LittleShort(q1_dclipnodes[i].children[1]);
+ }
+
+//
+// miptex
+//
+ if (q1_texdatasize)
+ {
+ mtl = (q1_dmiptexlump_t *)q1_dtexdata;
+ if (todisk)
+ c = mtl->nummiptex;
+ else
+ c = LittleLong(mtl->nummiptex);
+ mtl->nummiptex = LittleLong (mtl->nummiptex);
+ for (i=0 ; i<c ; i++)
+ mtl->dataofs[i] = LittleLong(mtl->dataofs[i]);
+ }
+
+//
+// marksurfaces
+//
+ for (i=0 ; i<q1_nummarksurfaces ; i++)
+ q1_dmarksurfaces[i] = LittleShort(q1_dmarksurfaces[i]);
+
+//
+// surfedges
+//
+ for (i=0 ; i<q1_numsurfedges ; i++)
+ q1_dsurfedges[i] = LittleLong(q1_dsurfedges[i]);
+
+//
+// edges
+//
+ for (i=0 ; i<q1_numedges ; i++)
+ {
+ q1_dedges[i].v[0] = LittleShort(q1_dedges[i].v[0]);
+ q1_dedges[i].v[1] = LittleShort(q1_dedges[i].v[1]);
+ }
+}
+
+
+q1_dheader_t *q1_header;
+int q1_fileLength;
+
+int Q1_CopyLump (int lump, void *dest, int size, int maxsize)
+{
+ int length, ofs;
+
+ length = q1_header->lumps[lump].filelen;
+ ofs = q1_header->lumps[lump].fileofs;
+
+ if (length % size) {
+ Error ("LoadBSPFile: odd lump size");
+ }
+ // somehow things got out of range
+ if ((length/size) > maxsize) {
+ printf("WARNING: exceeded max size for lump %d size %d > maxsize %d\n", lump, (length/size), maxsize);
+ length = maxsize * size;
+ }
+ if ( ofs + length > q1_fileLength ) {
+ printf("WARNING: exceeded file length for lump %d\n", lump);
+ length = q1_fileLength - ofs;
+ if ( length <= 0 ) {
+ return 0;
+ }
+ }
+
+ memcpy (dest, (byte *)q1_header + ofs, length);
+
+ return length / size;
+}
+
+/*
+=============
+Q1_LoadBSPFile
+=============
+*/
+void Q1_LoadBSPFile(char *filename, int offset, int length)
+{
+ int i;
+
+//
+// load the file header
+//
+ q1_fileLength = LoadFile(filename, (void **)&q1_header, offset, length);
+
+// swap the header
+ for (i=0 ; i< sizeof(q1_dheader_t)/4 ; i++)
+ ((int *)q1_header)[i] = LittleLong ( ((int *)q1_header)[i]);
+
+ if (q1_header->version != Q1_BSPVERSION)
+ Error ("%s is version %i, not %i", filename, i, Q1_BSPVERSION);
+
+ q1_nummodels = Q1_CopyLump (Q1_LUMP_MODELS, q1_dmodels, sizeof(q1_dmodel_t), Q1_MAX_MAP_MODELS );
+ q1_numvertexes = Q1_CopyLump (Q1_LUMP_VERTEXES, q1_dvertexes, sizeof(q1_dvertex_t), Q1_MAX_MAP_VERTS );
+ q1_numplanes = Q1_CopyLump (Q1_LUMP_PLANES, q1_dplanes, sizeof(q1_dplane_t), Q1_MAX_MAP_PLANES );
+ q1_numleafs = Q1_CopyLump (Q1_LUMP_LEAFS, q1_dleafs, sizeof(q1_dleaf_t), Q1_MAX_MAP_LEAFS );
+ q1_numnodes = Q1_CopyLump (Q1_LUMP_NODES, q1_dnodes, sizeof(q1_dnode_t), Q1_MAX_MAP_NODES );
+ q1_numtexinfo = Q1_CopyLump (Q1_LUMP_TEXINFO, q1_texinfo, sizeof(q1_texinfo_t), Q1_MAX_MAP_TEXINFO );
+ q1_numclipnodes = Q1_CopyLump (Q1_LUMP_CLIPNODES, q1_dclipnodes, sizeof(q1_dclipnode_t), Q1_MAX_MAP_CLIPNODES );
+ q1_numfaces = Q1_CopyLump (Q1_LUMP_FACES, q1_dfaces, sizeof(q1_dface_t), Q1_MAX_MAP_FACES );
+ q1_nummarksurfaces = Q1_CopyLump (Q1_LUMP_MARKSURFACES, q1_dmarksurfaces, sizeof(q1_dmarksurfaces[0]), Q1_MAX_MAP_MARKSURFACES );
+ q1_numsurfedges = Q1_CopyLump (Q1_LUMP_SURFEDGES, q1_dsurfedges, sizeof(q1_dsurfedges[0]), Q1_MAX_MAP_SURFEDGES );
+ q1_numedges = Q1_CopyLump (Q1_LUMP_EDGES, q1_dedges, sizeof(q1_dedge_t), Q1_MAX_MAP_EDGES );
+
+ q1_texdatasize = Q1_CopyLump (Q1_LUMP_TEXTURES, q1_dtexdata, 1, Q1_MAX_MAP_MIPTEX );
+ q1_visdatasize = Q1_CopyLump (Q1_LUMP_VISIBILITY, q1_dvisdata, 1, Q1_MAX_MAP_VISIBILITY );
+ q1_lightdatasize = Q1_CopyLump (Q1_LUMP_LIGHTING, q1_dlightdata, 1, Q1_MAX_MAP_LIGHTING );
+ q1_entdatasize = Q1_CopyLump (Q1_LUMP_ENTITIES, q1_dentdata, 1, Q1_MAX_MAP_ENTSTRING );
+
+ FreeMemory(q1_header); // everything has been copied out
+
+//
+// swap everything
+//
+ Q1_SwapBSPFile (false);
+}
+
+//============================================================================
+
+FILE *q1_wadfile;
+q1_dheader_t q1_outheader;
+
+void Q1_AddLump (int lumpnum, void *data, int len)
+{
+ q1_lump_t *lump;
+
+ lump = &q1_header->lumps[lumpnum];
+
+ lump->fileofs = LittleLong(ftell(q1_wadfile));
+ lump->filelen = LittleLong(len);
+ SafeWrite(q1_wadfile, data, (len+3)&~3);
+}
+
+/*
+=============
+Q1_WriteBSPFile
+
+Swaps the bsp file in place, so it should not be referenced again
+=============
+*/
+void Q1_WriteBSPFile (char *filename)
+{
+ q1_header = &q1_outheader;
+ memset (q1_header, 0, sizeof(q1_dheader_t));
+
+ Q1_SwapBSPFile (true);
+
+ q1_header->version = LittleLong (Q1_BSPVERSION);
+
+ q1_wadfile = SafeOpenWrite (filename);
+ SafeWrite (q1_wadfile, q1_header, sizeof(q1_dheader_t)); // overwritten later
+
+ Q1_AddLump (Q1_LUMP_PLANES, q1_dplanes, q1_numplanes*sizeof(q1_dplane_t));
+ Q1_AddLump (Q1_LUMP_LEAFS, q1_dleafs, q1_numleafs*sizeof(q1_dleaf_t));
+ Q1_AddLump (Q1_LUMP_VERTEXES, q1_dvertexes, q1_numvertexes*sizeof(q1_dvertex_t));
+ Q1_AddLump (Q1_LUMP_NODES, q1_dnodes, q1_numnodes*sizeof(q1_dnode_t));
+ Q1_AddLump (Q1_LUMP_TEXINFO, q1_texinfo, q1_numtexinfo*sizeof(q1_texinfo_t));
+ Q1_AddLump (Q1_LUMP_FACES, q1_dfaces, q1_numfaces*sizeof(q1_dface_t));
+ Q1_AddLump (Q1_LUMP_CLIPNODES, q1_dclipnodes, q1_numclipnodes*sizeof(q1_dclipnode_t));
+ Q1_AddLump (Q1_LUMP_MARKSURFACES, q1_dmarksurfaces, q1_nummarksurfaces*sizeof(q1_dmarksurfaces[0]));
+ Q1_AddLump (Q1_LUMP_SURFEDGES, q1_dsurfedges, q1_numsurfedges*sizeof(q1_dsurfedges[0]));
+ Q1_AddLump (Q1_LUMP_EDGES, q1_dedges, q1_numedges*sizeof(q1_dedge_t));
+ Q1_AddLump (Q1_LUMP_MODELS, q1_dmodels, q1_nummodels*sizeof(q1_dmodel_t));
+
+ Q1_AddLump (Q1_LUMP_LIGHTING, q1_dlightdata, q1_lightdatasize);
+ Q1_AddLump (Q1_LUMP_VISIBILITY, q1_dvisdata, q1_visdatasize);
+ Q1_AddLump (Q1_LUMP_ENTITIES, q1_dentdata, q1_entdatasize);
+ Q1_AddLump (Q1_LUMP_TEXTURES, q1_dtexdata, q1_texdatasize);
+
+ fseek (q1_wadfile, 0, SEEK_SET);
+ SafeWrite (q1_wadfile, q1_header, sizeof(q1_dheader_t));
+ fclose (q1_wadfile);
+}
+
+//============================================================================
+
+/*
+=============
+Q1_PrintBSPFileSizes
+
+Dumps info about current file
+=============
+*/
+void Q1_PrintBSPFileSizes (void)
+{
+ printf ("%5i planes %6i\n"
+ ,q1_numplanes, (int)(q1_numplanes*sizeof(q1_dplane_t)));
+ printf ("%5i vertexes %6i\n"
+ ,q1_numvertexes, (int)(q1_numvertexes*sizeof(q1_dvertex_t)));
+ printf ("%5i nodes %6i\n"
+ ,q1_numnodes, (int)(q1_numnodes*sizeof(q1_dnode_t)));
+ printf ("%5i texinfo %6i\n"
+ ,q1_numtexinfo, (int)(q1_numtexinfo*sizeof(q1_texinfo_t)));
+ printf ("%5i faces %6i\n"
+ ,q1_numfaces, (int)(q1_numfaces*sizeof(q1_dface_t)));
+ printf ("%5i clipnodes %6i\n"
+ ,q1_numclipnodes, (int)(q1_numclipnodes*sizeof(q1_dclipnode_t)));
+ printf ("%5i leafs %6i\n"
+ ,q1_numleafs, (int)(q1_numleafs*sizeof(q1_dleaf_t)));
+ printf ("%5i marksurfaces %6i\n"
+ ,q1_nummarksurfaces, (int)(q1_nummarksurfaces*sizeof(q1_dmarksurfaces[0])));
+ printf ("%5i surfedges %6i\n"
+ ,q1_numsurfedges, (int)(q1_numsurfedges*sizeof(q1_dmarksurfaces[0])));
+ printf ("%5i edges %6i\n"
+ ,q1_numedges, (int)(q1_numedges*sizeof(q1_dedge_t)));
+ if (!q1_texdatasize)
+ printf (" 0 textures 0\n");
+ else
+ printf ("%5i textures %6i\n",((q1_dmiptexlump_t*)q1_dtexdata)->nummiptex, q1_texdatasize);
+ printf (" lightdata %6i\n", q1_lightdatasize);
+ printf (" visdata %6i\n", q1_visdatasize);
+ printf (" entdata %6i\n", q1_entdatasize);
+} //end of the function Q1_PrintBSPFileSizes
+
+
+/*
+================
+Q1_ParseEntities
+
+Parses the dentdata string into entities
+================
+*/
+void Q1_ParseEntities (void)
+{
+ script_t *script;
+
+ num_entities = 0;
+ script = LoadScriptMemory(q1_dentdata, q1_entdatasize, "*Quake1 bsp file");
+ SetScriptFlags(script, SCFL_NOSTRINGWHITESPACES |
+ SCFL_NOSTRINGESCAPECHARS);
+
+ while(ParseEntity(script))
+ {
+ } //end while
+
+ FreeScript(script);
+} //end of the function Q1_ParseEntities
+
+
+/*
+================
+Q1_UnparseEntities
+
+Generates the dentdata string from all the entities
+================
+*/
+void Q1_UnparseEntities (void)
+{
+ char *buf, *end;
+ epair_t *ep;
+ char line[2048];
+ int i;
+
+ buf = q1_dentdata;
+ end = buf;
+ *end = 0;
+
+ for (i=0 ; i<num_entities ; i++)
+ {
+ ep = entities[i].epairs;
+ if (!ep)
+ continue; // ent got removed
+
+ strcat (end,"{\n");
+ end += 2;
+
+ for (ep = entities[i].epairs ; ep ; ep=ep->next)
+ {
+ sprintf (line, "\"%s\" \"%s\"\n", ep->key, ep->value);
+ strcat (end, line);
+ end += strlen(line);
+ }
+ strcat (end,"}\n");
+ end += 2;
+
+ if (end > buf + Q1_MAX_MAP_ENTSTRING)
+ Error ("Entity text too long");
+ }
+ q1_entdatasize = end - buf + 1;
+} //end of the function Q1_UnparseEntities
diff --git a/code/bspc/l_bsp_q1.h b/code/bspc/l_bsp_q1.h
index 1c2cd92..7cf459c 100755
--- a/code/bspc/l_bsp_q1.h
+++ b/code/bspc/l_bsp_q1.h
@@ -1,275 +1,275 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-
-
-// upper design bounds
-
-#define Q1_MAX_MAP_HULLS 4
-
-#define Q1_MAX_MAP_MODELS 256
-#define Q1_MAX_MAP_BRUSHES 4096
-#define Q1_MAX_MAP_ENTITIES 1024
-#define Q1_MAX_MAP_ENTSTRING 65536
-
-#define Q1_MAX_MAP_PLANES 8192
-#define Q1_MAX_MAP_NODES 32767 // because negative shorts are contents
-#define Q1_MAX_MAP_CLIPNODES 32767 //
-#define Q1_MAX_MAP_LEAFS 32767 //
-#define Q1_MAX_MAP_VERTS 65535
-#define Q1_MAX_MAP_FACES 65535
-#define Q1_MAX_MAP_MARKSURFACES 65535
-#define Q1_MAX_MAP_TEXINFO 4096
-#define Q1_MAX_MAP_EDGES 256000
-#define Q1_MAX_MAP_SURFEDGES 512000
-#define Q1_MAX_MAP_MIPTEX 0x200000
-#define Q1_MAX_MAP_LIGHTING 0x100000
-#define Q1_MAX_MAP_VISIBILITY 0x100000
-
-// key / value pair sizes
-
-#define MAX_KEY 32
-#define MAX_VALUE 1024
-
-//=============================================================================
-
-
-#define Q1_BSPVERSION 29
-
-typedef struct
-{
- int fileofs, filelen;
-} q1_lump_t;
-
-#define Q1_LUMP_ENTITIES 0
-#define Q1_LUMP_PLANES 1
-#define Q1_LUMP_TEXTURES 2
-#define Q1_LUMP_VERTEXES 3
-#define Q1_LUMP_VISIBILITY 4
-#define Q1_LUMP_NODES 5
-#define Q1_LUMP_TEXINFO 6
-#define Q1_LUMP_FACES 7
-#define Q1_LUMP_LIGHTING 8
-#define Q1_LUMP_CLIPNODES 9
-#define Q1_LUMP_LEAFS 10
-#define Q1_LUMP_MARKSURFACES 11
-#define Q1_LUMP_EDGES 12
-#define Q1_LUMP_SURFEDGES 13
-#define Q1_LUMP_MODELS 14
-
-#define Q1_HEADER_LUMPS 15
-
-typedef struct
-{
- float mins[3], maxs[3];
- float origin[3];
- int headnode[Q1_MAX_MAP_HULLS];
- int visleafs; // not including the solid leaf 0
- int firstface, numfaces;
-} q1_dmodel_t;
-
-typedef struct
-{
- int version;
- q1_lump_t lumps[Q1_HEADER_LUMPS];
-} q1_dheader_t;
-
-typedef struct
-{
- int nummiptex;
- int dataofs[4]; // [nummiptex]
-} q1_dmiptexlump_t;
-
-#define MIPLEVELS 4
-typedef struct q1_miptex_s
-{
- char name[16];
- unsigned width, height;
- unsigned offsets[MIPLEVELS]; // four mip maps stored
-} q1_miptex_t;
-
-
-typedef struct
-{
- float point[3];
-} q1_dvertex_t;
-
-
-// 0-2 are axial planes
-#define PLANE_X 0
-#define PLANE_Y 1
-#define PLANE_Z 2
-
-// 3-5 are non-axial planes snapped to the nearest
-#define PLANE_ANYX 3
-#define PLANE_ANYY 4
-#define PLANE_ANYZ 5
-
-typedef struct
-{
- float normal[3];
- float dist;
- int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
-} q1_dplane_t;
-
-
-
-#define Q1_CONTENTS_EMPTY -1
-#define Q1_CONTENTS_SOLID -2
-#define Q1_CONTENTS_WATER -3
-#define Q1_CONTENTS_SLIME -4
-#define Q1_CONTENTS_LAVA -5
-#define Q1_CONTENTS_SKY -6
-
-// !!! if this is changed, it must be changed in asm_i386.h too !!!
-typedef struct
-{
- int planenum;
- short children[2]; // negative numbers are -(leafs+1), not nodes
- short mins[3]; // for sphere culling
- short maxs[3];
- unsigned short firstface;
- unsigned short numfaces; // counting both sides
-} q1_dnode_t;
-
-typedef struct
-{
- int planenum;
- short children[2]; // negative numbers are contents
-} q1_dclipnode_t;
-
-
-typedef struct q1_texinfo_s
-{
- float vecs[2][4]; // [s/t][xyz offset]
- int miptex;
- int flags;
-} q1_texinfo_t;
-#define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision
-
-// note that edge 0 is never used, because negative edge nums are used for
-// counterclockwise use of the edge in a face
-typedef struct
-{
- unsigned short v[2]; // vertex numbers
-} q1_dedge_t;
-
-#define MAXLIGHTMAPS 4
-typedef struct
-{
- short planenum;
- short side;
-
- int firstedge; // we must support > 64k edges
- short numedges;
- short texinfo;
-
-// lighting info
- byte styles[MAXLIGHTMAPS];
- int lightofs; // start of [numstyles*surfsize] samples
-} q1_dface_t;
-
-
-
-#define AMBIENT_WATER 0
-#define AMBIENT_SKY 1
-#define AMBIENT_SLIME 2
-#define AMBIENT_LAVA 3
-
-#define NUM_AMBIENTS 4 // automatic ambient sounds
-
-// leaf 0 is the generic Q1_CONTENTS_SOLID leaf, used for all solid areas
-// all other leafs need visibility info
-typedef struct
-{
- int contents;
- int visofs; // -1 = no visibility info
-
- short mins[3]; // for frustum culling
- short maxs[3];
-
- unsigned short firstmarksurface;
- unsigned short nummarksurfaces;
-
- byte ambient_level[NUM_AMBIENTS];
-} q1_dleaf_t;
-
-//============================================================================
-
-#ifndef QUAKE_GAME
-
-// the utilities get to be lazy and just use large static arrays
-
-extern int q1_nummodels;
-extern q1_dmodel_t *q1_dmodels;//[MAX_MAP_MODELS];
-
-extern int q1_visdatasize;
-extern byte *q1_dvisdata;//[MAX_MAP_VISIBILITY];
-
-extern int q1_lightdatasize;
-extern byte *q1_dlightdata;//[MAX_MAP_LIGHTING];
-
-extern int q1_texdatasize;
-extern byte *q1_dtexdata;//[MAX_MAP_MIPTEX]; // (dmiptexlump_t)
-
-extern int q1_entdatasize;
-extern char *q1_dentdata;//[MAX_MAP_ENTSTRING];
-
-extern int q1_numleafs;
-extern q1_dleaf_t *q1_dleafs;//[MAX_MAP_LEAFS];
-
-extern int q1_numplanes;
-extern q1_dplane_t *q1_dplanes;//[MAX_MAP_PLANES];
-
-extern int q1_numvertexes;
-extern q1_dvertex_t *q1_dvertexes;//[MAX_MAP_VERTS];
-
-extern int q1_numnodes;
-extern q1_dnode_t *q1_dnodes;//[MAX_MAP_NODES];
-
-extern int q1_numtexinfo;
-extern q1_texinfo_t *q1_texinfo;//[MAX_MAP_TEXINFO];
-
-extern int q1_numfaces;
-extern q1_dface_t *q1_dfaces;//[MAX_MAP_FACES];
-
-extern int q1_numclipnodes;
-extern q1_dclipnode_t *q1_dclipnodes;//[MAX_MAP_CLIPNODES];
-
-extern int q1_numedges;
-extern q1_dedge_t *q1_dedges;//[MAX_MAP_EDGES];
-
-extern int q1_nummarksurfaces;
-extern unsigned short *q1_dmarksurfaces;//[MAX_MAP_MARKSURFACES];
-
-extern int q1_numsurfedges;
-extern int *q1_dsurfedges;//[MAX_MAP_SURFEDGES];
-
-
-void Q1_AllocMaxBSP(void);
-void Q1_FreeMaxBSP(void);
-void Q1_LoadBSPFile(char *filename, int offset, int length);
-void Q1_WriteBSPFile(char *filename);
-void Q1_PrintBSPFileSizes(void);
-void Q1_ParseEntities(void);
-void Q1_UnparseEntities(void);
-
-#endif
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+
+// upper design bounds
+
+#define Q1_MAX_MAP_HULLS 4
+
+#define Q1_MAX_MAP_MODELS 256
+#define Q1_MAX_MAP_BRUSHES 4096
+#define Q1_MAX_MAP_ENTITIES 1024
+#define Q1_MAX_MAP_ENTSTRING 65536
+
+#define Q1_MAX_MAP_PLANES 8192
+#define Q1_MAX_MAP_NODES 32767 // because negative shorts are contents
+#define Q1_MAX_MAP_CLIPNODES 32767 //
+#define Q1_MAX_MAP_LEAFS 32767 //
+#define Q1_MAX_MAP_VERTS 65535
+#define Q1_MAX_MAP_FACES 65535
+#define Q1_MAX_MAP_MARKSURFACES 65535
+#define Q1_MAX_MAP_TEXINFO 4096
+#define Q1_MAX_MAP_EDGES 256000
+#define Q1_MAX_MAP_SURFEDGES 512000
+#define Q1_MAX_MAP_MIPTEX 0x200000
+#define Q1_MAX_MAP_LIGHTING 0x100000
+#define Q1_MAX_MAP_VISIBILITY 0x100000
+
+// key / value pair sizes
+
+#define MAX_KEY 32
+#define MAX_VALUE 1024
+
+//=============================================================================
+
+
+#define Q1_BSPVERSION 29
+
+typedef struct
+{
+ int fileofs, filelen;
+} q1_lump_t;
+
+#define Q1_LUMP_ENTITIES 0
+#define Q1_LUMP_PLANES 1
+#define Q1_LUMP_TEXTURES 2
+#define Q1_LUMP_VERTEXES 3
+#define Q1_LUMP_VISIBILITY 4
+#define Q1_LUMP_NODES 5
+#define Q1_LUMP_TEXINFO 6
+#define Q1_LUMP_FACES 7
+#define Q1_LUMP_LIGHTING 8
+#define Q1_LUMP_CLIPNODES 9
+#define Q1_LUMP_LEAFS 10
+#define Q1_LUMP_MARKSURFACES 11
+#define Q1_LUMP_EDGES 12
+#define Q1_LUMP_SURFEDGES 13
+#define Q1_LUMP_MODELS 14
+
+#define Q1_HEADER_LUMPS 15
+
+typedef struct
+{
+ float mins[3], maxs[3];
+ float origin[3];
+ int headnode[Q1_MAX_MAP_HULLS];
+ int visleafs; // not including the solid leaf 0
+ int firstface, numfaces;
+} q1_dmodel_t;
+
+typedef struct
+{
+ int version;
+ q1_lump_t lumps[Q1_HEADER_LUMPS];
+} q1_dheader_t;
+
+typedef struct
+{
+ int nummiptex;
+ int dataofs[4]; // [nummiptex]
+} q1_dmiptexlump_t;
+
+#define MIPLEVELS 4
+typedef struct q1_miptex_s
+{
+ char name[16];
+ unsigned width, height;
+ unsigned offsets[MIPLEVELS]; // four mip maps stored
+} q1_miptex_t;
+
+
+typedef struct
+{
+ float point[3];
+} q1_dvertex_t;
+
+
+// 0-2 are axial planes
+#define PLANE_X 0
+#define PLANE_Y 1
+#define PLANE_Z 2
+
+// 3-5 are non-axial planes snapped to the nearest
+#define PLANE_ANYX 3
+#define PLANE_ANYY 4
+#define PLANE_ANYZ 5
+
+typedef struct
+{
+ float normal[3];
+ float dist;
+ int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
+} q1_dplane_t;
+
+
+
+#define Q1_CONTENTS_EMPTY -1
+#define Q1_CONTENTS_SOLID -2
+#define Q1_CONTENTS_WATER -3
+#define Q1_CONTENTS_SLIME -4
+#define Q1_CONTENTS_LAVA -5
+#define Q1_CONTENTS_SKY -6
+
+// !!! if this is changed, it must be changed in asm_i386.h too !!!
+typedef struct
+{
+ int planenum;
+ short children[2]; // negative numbers are -(leafs+1), not nodes
+ short mins[3]; // for sphere culling
+ short maxs[3];
+ unsigned short firstface;
+ unsigned short numfaces; // counting both sides
+} q1_dnode_t;
+
+typedef struct
+{
+ int planenum;
+ short children[2]; // negative numbers are contents
+} q1_dclipnode_t;
+
+
+typedef struct q1_texinfo_s
+{
+ float vecs[2][4]; // [s/t][xyz offset]
+ int miptex;
+ int flags;
+} q1_texinfo_t;
+#define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision
+
+// note that edge 0 is never used, because negative edge nums are used for
+// counterclockwise use of the edge in a face
+typedef struct
+{
+ unsigned short v[2]; // vertex numbers
+} q1_dedge_t;
+
+#define MAXLIGHTMAPS 4
+typedef struct
+{
+ short planenum;
+ short side;
+
+ int firstedge; // we must support > 64k edges
+ short numedges;
+ short texinfo;
+
+// lighting info
+ byte styles[MAXLIGHTMAPS];
+ int lightofs; // start of [numstyles*surfsize] samples
+} q1_dface_t;
+
+
+
+#define AMBIENT_WATER 0
+#define AMBIENT_SKY 1
+#define AMBIENT_SLIME 2
+#define AMBIENT_LAVA 3
+
+#define NUM_AMBIENTS 4 // automatic ambient sounds
+
+// leaf 0 is the generic Q1_CONTENTS_SOLID leaf, used for all solid areas
+// all other leafs need visibility info
+typedef struct
+{
+ int contents;
+ int visofs; // -1 = no visibility info
+
+ short mins[3]; // for frustum culling
+ short maxs[3];
+
+ unsigned short firstmarksurface;
+ unsigned short nummarksurfaces;
+
+ byte ambient_level[NUM_AMBIENTS];
+} q1_dleaf_t;
+
+//============================================================================
+
+#ifndef QUAKE_GAME
+
+// the utilities get to be lazy and just use large static arrays
+
+extern int q1_nummodels;
+extern q1_dmodel_t *q1_dmodels;//[MAX_MAP_MODELS];
+
+extern int q1_visdatasize;
+extern byte *q1_dvisdata;//[MAX_MAP_VISIBILITY];
+
+extern int q1_lightdatasize;
+extern byte *q1_dlightdata;//[MAX_MAP_LIGHTING];
+
+extern int q1_texdatasize;
+extern byte *q1_dtexdata;//[MAX_MAP_MIPTEX]; // (dmiptexlump_t)
+
+extern int q1_entdatasize;
+extern char *q1_dentdata;//[MAX_MAP_ENTSTRING];
+
+extern int q1_numleafs;
+extern q1_dleaf_t *q1_dleafs;//[MAX_MAP_LEAFS];
+
+extern int q1_numplanes;
+extern q1_dplane_t *q1_dplanes;//[MAX_MAP_PLANES];
+
+extern int q1_numvertexes;
+extern q1_dvertex_t *q1_dvertexes;//[MAX_MAP_VERTS];
+
+extern int q1_numnodes;
+extern q1_dnode_t *q1_dnodes;//[MAX_MAP_NODES];
+
+extern int q1_numtexinfo;
+extern q1_texinfo_t *q1_texinfo;//[MAX_MAP_TEXINFO];
+
+extern int q1_numfaces;
+extern q1_dface_t *q1_dfaces;//[MAX_MAP_FACES];
+
+extern int q1_numclipnodes;
+extern q1_dclipnode_t *q1_dclipnodes;//[MAX_MAP_CLIPNODES];
+
+extern int q1_numedges;
+extern q1_dedge_t *q1_dedges;//[MAX_MAP_EDGES];
+
+extern int q1_nummarksurfaces;
+extern unsigned short *q1_dmarksurfaces;//[MAX_MAP_MARKSURFACES];
+
+extern int q1_numsurfedges;
+extern int *q1_dsurfedges;//[MAX_MAP_SURFEDGES];
+
+
+void Q1_AllocMaxBSP(void);
+void Q1_FreeMaxBSP(void);
+void Q1_LoadBSPFile(char *filename, int offset, int length);
+void Q1_WriteBSPFile(char *filename);
+void Q1_PrintBSPFileSizes(void);
+void Q1_ParseEntities(void);
+void Q1_UnparseEntities(void);
+
+#endif
diff --git a/code/bspc/l_bsp_q2.c b/code/bspc/l_bsp_q2.c
index d5e9844..2d97579 100755
--- a/code/bspc/l_bsp_q2.c
+++ b/code/bspc/l_bsp_q2.c
@@ -1,1134 +1,1134 @@
-/*
-===========================================================================
-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 "l_cmd.h"
-#include "l_math.h"
-#include "l_mem.h"
-#include "l_log.h"
-#include "l_poly.h"
-#include "../botlib/l_script.h"
-#include "q2files.h"
-#include "l_bsp_q2.h"
-#include "l_bsp_ent.h"
-
-#define q2_dmodel_t dmodel_t
-#define q2_lump_t lump_t
-#define q2_dheader_t dheader_t
-#define q2_dmodel_t dmodel_t
-#define q2_dvertex_t dvertex_t
-#define q2_dplane_t dplane_t
-#define q2_dnode_t dnode_t
-#define q2_texinfo_t texinfo_t
-#define q2_dedge_t dedge_t
-#define q2_dface_t dface_t
-#define q2_dleaf_t dleaf_t
-#define q2_dbrushside_t dbrushside_t
-#define q2_dbrush_t dbrush_t
-#define q2_dvis_t dvis_t
-#define q2_dareaportal_t dareaportal_t
-#define q2_darea_t darea_t
-
-#define q2_nummodels nummodels
-#define q2_dmodels dmodels
-#define q2_numleafs numleafs
-#define q2_dleafs dleafs
-#define q2_numplanes numplanes
-#define q2_dplanes dplanes
-#define q2_numvertexes numvertexes
-#define q2_dvertexes dvertexes
-#define q2_numnodes numnodes
-#define q2_dnodes dnodes
-#define q2_numtexinfo numtexinfo
-#define q2_texinfo texinfo
-#define q2_numfaces numfaces
-#define q2_dfaces dfaces
-#define q2_numedges numedges
-#define q2_dedges dedges
-#define q2_numleaffaces numleaffaces
-#define q2_dleaffaces dleaffaces
-#define q2_numleafbrushes numleafbrushes
-#define q2_dleafbrushes dleafbrushes
-#define q2_dsurfedges dsurfedges
-#define q2_numbrushes numbrushes
-#define q2_dbrushes dbrushes
-#define q2_numbrushsides numbrushsides
-#define q2_dbrushsides dbrushsides
-#define q2_numareas numareas
-#define q2_dareas dareas
-#define q2_numareaportals numareaportals
-#define q2_dareaportals dareaportals
-
-void GetLeafNums (void);
-
-//=============================================================================
-
-int nummodels;
-dmodel_t *dmodels;//[MAX_MAP_MODELS];
-
-int visdatasize;
-byte *dvisdata;//[MAX_MAP_VISIBILITY];
-dvis_t *dvis;// = (dvis_t *)dvisdata;
-
-int lightdatasize;
-byte *dlightdata;//[MAX_MAP_LIGHTING];
-
-int entdatasize;
-char *dentdata;//[MAX_MAP_ENTSTRING];
-
-int numleafs;
-dleaf_t *dleafs;//[MAX_MAP_LEAFS];
-
-int numplanes;
-dplane_t *dplanes;//[MAX_MAP_PLANES];
-
-int numvertexes;
-dvertex_t *dvertexes;//[MAX_MAP_VERTS];
-
-int numnodes;
-dnode_t *dnodes;//[MAX_MAP_NODES];
-
-//NOTE: must be static for q2 .map to q2 .bsp
-int numtexinfo;
-texinfo_t texinfo[MAX_MAP_TEXINFO];
-
-int numfaces;
-dface_t *dfaces;//[MAX_MAP_FACES];
-
-int numedges;
-dedge_t *dedges;//[MAX_MAP_EDGES];
-
-int numleaffaces;
-unsigned short *dleaffaces;//[MAX_MAP_LEAFFACES];
-
-int numleafbrushes;
-unsigned short *dleafbrushes;//[MAX_MAP_LEAFBRUSHES];
-
-int numsurfedges;
-int *dsurfedges;//[MAX_MAP_SURFEDGES];
-
-int numbrushes;
-dbrush_t *dbrushes;//[MAX_MAP_BRUSHES];
-
-int numbrushsides;
-dbrushside_t *dbrushsides;//[MAX_MAP_BRUSHSIDES];
-
-int numareas;
-darea_t *dareas;//[MAX_MAP_AREAS];
-
-int numareaportals;
-dareaportal_t *dareaportals;//[MAX_MAP_AREAPORTALS];
-
-#define MAX_MAP_DPOP 256
-byte dpop[MAX_MAP_DPOP];
-
-//
-char brushsidetextured[MAX_MAP_BRUSHSIDES];
-
-//#ifdef ME
-
-int bspallocated = false;
-int allocatedbspmem = 0;
-
-void Q2_AllocMaxBSP(void)
-{
- //models
- nummodels = 0;
- dmodels = (dmodel_t *) GetClearedMemory(MAX_MAP_MODELS * sizeof(dmodel_t));
- allocatedbspmem += MAX_MAP_MODELS * sizeof(dmodel_t);
- //vis data
- visdatasize = 0;
- dvisdata = (byte *) GetClearedMemory(MAX_MAP_VISIBILITY * sizeof(byte));
- dvis = (dvis_t *) dvisdata;
- allocatedbspmem += MAX_MAP_VISIBILITY * sizeof(byte);
- //light data
- lightdatasize = 0;
- dlightdata = (byte *) GetClearedMemory(MAX_MAP_LIGHTING * sizeof(byte));
- allocatedbspmem += MAX_MAP_LIGHTING * sizeof(byte);
- //entity data
- entdatasize = 0;
- dentdata = (char *) GetClearedMemory(MAX_MAP_ENTSTRING * sizeof(char));
- allocatedbspmem += MAX_MAP_ENTSTRING * sizeof(char);
- //leafs
- numleafs = 0;
- dleafs = (dleaf_t *) GetClearedMemory(MAX_MAP_LEAFS * sizeof(dleaf_t));
- allocatedbspmem += MAX_MAP_LEAFS * sizeof(dleaf_t);
- //planes
- numplanes = 0;
- dplanes = (dplane_t *) GetClearedMemory(MAX_MAP_PLANES * sizeof(dplane_t));
- allocatedbspmem += MAX_MAP_PLANES * sizeof(dplane_t);
- //vertexes
- numvertexes = 0;
- dvertexes = (dvertex_t *) GetClearedMemory(MAX_MAP_VERTS * sizeof(dvertex_t));
- allocatedbspmem += MAX_MAP_VERTS * sizeof(dvertex_t);
- //nodes
- numnodes = 0;
- dnodes = (dnode_t *) GetClearedMemory(MAX_MAP_NODES * sizeof(dnode_t));
- allocatedbspmem += MAX_MAP_NODES * sizeof(dnode_t);
- /*
- //texture info
- numtexinfo = 0;
- texinfo = (texinfo_t *) GetClearedMemory(MAX_MAP_TEXINFO * sizeof(texinfo_t));
- allocatedbspmem += MAX_MAP_TEXINFO * sizeof(texinfo_t);
- //*/
- //faces
- numfaces = 0;
- dfaces = (dface_t *) GetClearedMemory(MAX_MAP_FACES * sizeof(dface_t));
- allocatedbspmem += MAX_MAP_FACES * sizeof(dface_t);
- //edges
- numedges = 0;
- dedges = (dedge_t *) GetClearedMemory(MAX_MAP_EDGES * sizeof(dedge_t));
- allocatedbspmem += MAX_MAP_EDGES * sizeof(dedge_t);
- //leaf faces
- numleaffaces = 0;
- dleaffaces = (unsigned short *) GetClearedMemory(MAX_MAP_LEAFFACES * sizeof(unsigned short));
- allocatedbspmem += MAX_MAP_LEAFFACES * sizeof(unsigned short);
- //leaf brushes
- numleafbrushes = 0;
- dleafbrushes = (unsigned short *) GetClearedMemory(MAX_MAP_LEAFBRUSHES * sizeof(unsigned short));
- allocatedbspmem += MAX_MAP_LEAFBRUSHES * sizeof(unsigned short);
- //surface edges
- numsurfedges = 0;
- dsurfedges = (int *) GetClearedMemory(MAX_MAP_SURFEDGES * sizeof(int));
- allocatedbspmem += MAX_MAP_SURFEDGES * sizeof(int);
- //brushes
- numbrushes = 0;
- dbrushes = (dbrush_t *) GetClearedMemory(MAX_MAP_BRUSHES * sizeof(dbrush_t));
- allocatedbspmem += MAX_MAP_BRUSHES * sizeof(dbrush_t);
- //brushsides
- numbrushsides = 0;
- dbrushsides = (dbrushside_t *) GetClearedMemory(MAX_MAP_BRUSHSIDES * sizeof(dbrushside_t));
- allocatedbspmem += MAX_MAP_BRUSHSIDES * sizeof(dbrushside_t);
- //areas
- numareas = 0;
- dareas = (darea_t *) GetClearedMemory(MAX_MAP_AREAS * sizeof(darea_t));
- allocatedbspmem += MAX_MAP_AREAS * sizeof(darea_t);
- //area portals
- numareaportals = 0;
- dareaportals = (dareaportal_t *) GetClearedMemory(MAX_MAP_AREAPORTALS * sizeof(dareaportal_t));
- allocatedbspmem += MAX_MAP_AREAPORTALS * sizeof(dareaportal_t);
- //print allocated memory
- Log_Print("allocated ");
- PrintMemorySize(allocatedbspmem);
- Log_Print(" of BSP memory\n");
-} //end of the function Q2_AllocMaxBSP
-
-void Q2_FreeMaxBSP(void)
-{
- //models
- nummodels = 0;
- FreeMemory(dmodels);
- dmodels = NULL;
- //vis data
- visdatasize = 0;
- FreeMemory(dvisdata);
- dvisdata = NULL;
- dvis = NULL;
- //light data
- lightdatasize = 0;
- FreeMemory(dlightdata);
- dlightdata = NULL;
- //entity data
- entdatasize = 0;
- FreeMemory(dentdata);
- dentdata = NULL;
- //leafs
- numleafs = 0;
- FreeMemory(dleafs);
- dleafs = NULL;
- //planes
- numplanes = 0;
- FreeMemory(dplanes);
- dplanes = NULL;
- //vertexes
- numvertexes = 0;
- FreeMemory(dvertexes);
- dvertexes = NULL;
- //nodes
- numnodes = 0;
- FreeMemory(dnodes);
- dnodes = NULL;
- /*
- //texture info
- numtexinfo = 0;
- FreeMemory(texinfo);
- texinfo = NULL;
- //*/
- //faces
- numfaces = 0;
- FreeMemory(dfaces);
- dfaces = NULL;
- //edges
- numedges = 0;
- FreeMemory(dedges);
- dedges = NULL;
- //leaf faces
- numleaffaces = 0;
- FreeMemory(dleaffaces);
- dleaffaces = NULL;
- //leaf brushes
- numleafbrushes = 0;
- FreeMemory(dleafbrushes);
- dleafbrushes = NULL;
- //surface edges
- numsurfedges = 0;
- FreeMemory(dsurfedges);
- dsurfedges = NULL;
- //brushes
- numbrushes = 0;
- FreeMemory(dbrushes);
- dbrushes = NULL;
- //brushsides
- numbrushsides = 0;
- FreeMemory(dbrushsides);
- dbrushsides = NULL;
- //areas
- numareas = 0;
- FreeMemory(dareas);
- dareas = NULL;
- //area portals
- numareaportals = 0;
- FreeMemory(dareaportals);
- dareaportals = NULL;
- //
- Log_Print("freed ");
- PrintMemorySize(allocatedbspmem);
- Log_Print(" of BSP memory\n");
- allocatedbspmem = 0;
-} //end of the function Q2_FreeMaxBSP
-
-#define WCONVEX_EPSILON 0.5
-
-int InsideWinding(winding_t *w, vec3_t point, int planenum)
-{
- int i;
- float dist;
- vec_t *v1, *v2;
- vec3_t normal, edgevec;
- dplane_t *plane;
-
- for (i = 1; i <= w->numpoints; i++)
- {
- v1 = w->p[i % w->numpoints];
- v2 = w->p[(i + 1) % w->numpoints];
-
- VectorSubtract(v2, v1, edgevec);
- plane = &dplanes[planenum];
- CrossProduct(plane->normal, edgevec, normal);
- VectorNormalize(normal);
- dist = DotProduct(normal, v1);
- //
- if (DotProduct(normal, point) - dist > WCONVEX_EPSILON) return false;
- } //end for
- return true;
-} //end of the function InsideWinding
-
-int InsideFace(dface_t *face, vec3_t point)
-{
- int i, edgenum, side;
- float dist;
- vec_t *v1, *v2;
- vec3_t normal, edgevec;
- dplane_t *plane;
-
- for (i = 0; i < face->numedges; i++)
- {
- //get the first and second vertex of the edge
- edgenum = dsurfedges[face->firstedge + i];
- side = edgenum < 0;
- v1 = dvertexes[dedges[abs(edgenum)].v[side]].point;
- v2 = dvertexes[dedges[abs(edgenum)].v[!side]].point;
- //create a plane through the edge vector, orthogonal to the face plane
- //and with the normal vector pointing out of the face
- VectorSubtract(v1, v2, edgevec);
- plane = &dplanes[face->planenum];
- CrossProduct(plane->normal, edgevec, normal);
- VectorNormalize(normal);
- dist = DotProduct(normal, v1);
- //
- if (DotProduct(normal, point) - dist > WCONVEX_EPSILON) return false;
- } //end for
- return true;
-} //end of the function InsideFace
-//===========================================================================
-// returns the amount the face and the winding overlap
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float Q2_FaceOnWinding(q2_dface_t *face, winding_t *winding)
-{
- int i, edgenum, side;
- float dist, area;
- q2_dplane_t plane;
- vec_t *v1, *v2;
- vec3_t normal, edgevec;
- winding_t *w;
-
- //
- w = CopyWinding(winding);
- memcpy(&plane, &q2_dplanes[face->planenum], sizeof(q2_dplane_t));
- //check on which side of the plane the face is
- if (face->side)
- {
- VectorNegate(plane.normal, plane.normal);
- plane.dist = -plane.dist;
- } //end if
- for (i = 0; i < face->numedges && w; i++)
- {
- //get the first and second vertex of the edge
- edgenum = q2_dsurfedges[face->firstedge + i];
- side = edgenum > 0;
- //if the face plane is flipped
- v1 = q2_dvertexes[q2_dedges[abs(edgenum)].v[side]].point;
- v2 = q2_dvertexes[q2_dedges[abs(edgenum)].v[!side]].point;
- //create a plane through the edge vector, orthogonal to the face plane
- //and with the normal vector pointing inward
- VectorSubtract(v1, v2, edgevec);
- CrossProduct(edgevec, plane.normal, normal);
- VectorNormalize(normal);
- dist = DotProduct(normal, v1);
- //
- ChopWindingInPlace(&w, normal, dist, -0.1); //CLIP_EPSILON
- } //end for
- if (w)
- {
- area = WindingArea(w);
- FreeWinding(w);
- return area;
- } //end if
- return 0;
-} //end of the function Q2_FaceOnWinding
-//===========================================================================
-// creates a winding for the given brush side on the given brush
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-winding_t *Q2_BrushSideWinding(dbrush_t *brush, dbrushside_t *baseside)
-{
- int i;
- dplane_t *baseplane, *plane;
- winding_t *w;
- dbrushside_t *side;
-
- //create a winding for the brush side with the given planenumber
- baseplane = &dplanes[baseside->planenum];
- w = BaseWindingForPlane(baseplane->normal, baseplane->dist);
- for (i = 0; i < brush->numsides && w; i++)
- {
- side = &dbrushsides[brush->firstside + i];
- //don't chop with the base plane
- if (side->planenum == baseside->planenum) continue;
- //also don't use planes that are almost equal
- plane = &dplanes[side->planenum];
- if (DotProduct(baseplane->normal, plane->normal) > 0.999
- && fabs(baseplane->dist - plane->dist) < 0.01) continue;
- //
- plane = &dplanes[side->planenum^1];
- ChopWindingInPlace(&w, plane->normal, plane->dist, -0.1); //CLIP_EPSILON);
- } //end for
- return w;
-} //end of the function Q2_BrushSideWinding
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int Q2_HintSkipBrush(dbrush_t *brush)
-{
- int j;
- dbrushside_t *brushside;
-
- for (j = 0; j < brush->numsides; j++)
- {
- brushside = &dbrushsides[brush->firstside + j];
- if (brushside->texinfo > 0)
- {
- if (texinfo[brushside->texinfo].flags & (SURF_SKIP|SURF_HINT))
- {
- return true;
- } //end if
- } //end if
- } //end for
- return false;
-} //end of the function Q2_HintSkipBrush
-//===========================================================================
-// fix screwed brush texture references
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean WindingIsTiny(winding_t *w);
-
-void Q2_FixTextureReferences(void)
-{
- int i, j, k, we;
- dbrushside_t *brushside;
- dbrush_t *brush;
- dface_t *face;
- winding_t *w;
-
- memset(brushsidetextured, false, MAX_MAP_BRUSHSIDES);
- //go over all the brushes
- for (i = 0; i < numbrushes; i++)
- {
- brush = &dbrushes[i];
- //hint brushes are not textured
- if (Q2_HintSkipBrush(brush)) continue;
- //go over all the sides of the brush
- for (j = 0; j < brush->numsides; j++)
- {
- brushside = &dbrushsides[brush->firstside + j];
- //
- w = Q2_BrushSideWinding(brush, brushside);
- if (!w)
- {
- brushsidetextured[brush->firstside + j] = true;
- continue;
- } //end if
- else
- {
- //RemoveEqualPoints(w, 0.2);
- if (WindingIsTiny(w))
- {
- FreeWinding(w);
- brushsidetextured[brush->firstside + j] = true;
- continue;
- } //end if
- else
- {
- we = WindingError(w);
- if (we == WE_NOTENOUGHPOINTS
- || we == WE_SMALLAREA
- || we == WE_POINTBOGUSRANGE
-// || we == WE_NONCONVEX
- )
- {
- FreeWinding(w);
- brushsidetextured[brush->firstside + j] = true;
- continue;
- } //end if
- } //end else
- } //end else
- if (WindingArea(w) < 20)
- {
- brushsidetextured[brush->firstside + j] = true;
- } //end if
- //find a face for texturing this brush
- for (k = 0; k < numfaces; k++)
- {
- face = &dfaces[k];
- //if the face is in the same plane as the brush side
- if ((face->planenum&~1) != (brushside->planenum&~1)) continue;
- //if the face is partly or totally on the brush side
- if (Q2_FaceOnWinding(face, w))
- {
- brushside->texinfo = face->texinfo;
- brushsidetextured[brush->firstside + j] = true;
- break;
- } //end if
- } //end for
- FreeWinding(w);
- } //end for
- } //end for
-} //end of the function Q2_FixTextureReferences*/
-
-//#endif //ME
-
-
-/*
-===============
-CompressVis
-
-===============
-*/
-int Q2_CompressVis (byte *vis, byte *dest)
-{
- int j;
- int rep;
- int visrow;
- byte *dest_p;
-
- dest_p = dest;
-// visrow = (r_numvisleafs + 7)>>3;
- visrow = (dvis->numclusters + 7)>>3;
-
- for (j=0 ; j<visrow ; j++)
- {
- *dest_p++ = vis[j];
- if (vis[j])
- continue;
-
- rep = 1;
- for ( j++; j<visrow ; j++)
- if (vis[j] || rep == 255)
- break;
- else
- rep++;
- *dest_p++ = rep;
- j--;
- }
-
- return dest_p - dest;
-}
-
-
-/*
-===================
-DecompressVis
-===================
-*/
-void Q2_DecompressVis (byte *in, byte *decompressed)
-{
- int c;
- byte *out;
- int row;
-
-// row = (r_numvisleafs+7)>>3;
- row = (dvis->numclusters+7)>>3;
- out = decompressed;
-
- do
- {
- if (*in)
- {
- *out++ = *in++;
- continue;
- }
-
- c = in[1];
- if (!c)
- Error ("DecompressVis: 0 repeat");
- in += 2;
- while (c)
- {
- *out++ = 0;
- c--;
- }
- } while (out - decompressed < row);
-}
-
-//=============================================================================
-
-/*
-=============
-SwapBSPFile
-
-Byte swaps all data in a bsp file.
-=============
-*/
-void Q2_SwapBSPFile (qboolean todisk)
-{
- int i, j;
- dmodel_t *d;
-
-
-// models
- for (i=0 ; i<nummodels ; i++)
- {
- d = &dmodels[i];
-
- d->firstface = LittleLong (d->firstface);
- d->numfaces = LittleLong (d->numfaces);
- d->headnode = LittleLong (d->headnode);
-
- for (j=0 ; j<3 ; j++)
- {
- d->mins[j] = LittleFloat(d->mins[j]);
- d->maxs[j] = LittleFloat(d->maxs[j]);
- d->origin[j] = LittleFloat(d->origin[j]);
- }
- }
-
-//
-// vertexes
-//
- for (i=0 ; i<numvertexes ; i++)
- {
- for (j=0 ; j<3 ; j++)
- dvertexes[i].point[j] = LittleFloat (dvertexes[i].point[j]);
- }
-
-//
-// planes
-//
- for (i=0 ; i<numplanes ; i++)
- {
- for (j=0 ; j<3 ; j++)
- dplanes[i].normal[j] = LittleFloat (dplanes[i].normal[j]);
- dplanes[i].dist = LittleFloat (dplanes[i].dist);
- dplanes[i].type = LittleLong (dplanes[i].type);
- }
-
-//
-// texinfos
-//
- for (i=0 ; i<numtexinfo ; i++)
- {
- for (j=0 ; j<8 ; j++)
- texinfo[i].vecs[0][j] = LittleFloat (texinfo[i].vecs[0][j]);
- texinfo[i].flags = LittleLong (texinfo[i].flags);
- texinfo[i].value = LittleLong (texinfo[i].value);
- texinfo[i].nexttexinfo = LittleLong (texinfo[i].nexttexinfo);
- }
-
-//
-// faces
-//
- for (i=0 ; i<numfaces ; i++)
- {
- dfaces[i].texinfo = LittleShort (dfaces[i].texinfo);
- dfaces[i].planenum = LittleShort (dfaces[i].planenum);
- dfaces[i].side = LittleShort (dfaces[i].side);
- dfaces[i].lightofs = LittleLong (dfaces[i].lightofs);
- dfaces[i].firstedge = LittleLong (dfaces[i].firstedge);
- dfaces[i].numedges = LittleShort (dfaces[i].numedges);
- }
-
-//
-// nodes
-//
- for (i=0 ; i<numnodes ; i++)
- {
- dnodes[i].planenum = LittleLong (dnodes[i].planenum);
- for (j=0 ; j<3 ; j++)
- {
- dnodes[i].mins[j] = LittleShort (dnodes[i].mins[j]);
- dnodes[i].maxs[j] = LittleShort (dnodes[i].maxs[j]);
- }
- dnodes[i].children[0] = LittleLong (dnodes[i].children[0]);
- dnodes[i].children[1] = LittleLong (dnodes[i].children[1]);
- dnodes[i].firstface = LittleShort (dnodes[i].firstface);
- dnodes[i].numfaces = LittleShort (dnodes[i].numfaces);
- }
-
-//
-// leafs
-//
- for (i=0 ; i<numleafs ; i++)
- {
- dleafs[i].contents = LittleLong (dleafs[i].contents);
- dleafs[i].cluster = LittleShort (dleafs[i].cluster);
- dleafs[i].area = LittleShort (dleafs[i].area);
- for (j=0 ; j<3 ; j++)
- {
- dleafs[i].mins[j] = LittleShort (dleafs[i].mins[j]);
- dleafs[i].maxs[j] = LittleShort (dleafs[i].maxs[j]);
- }
-
- dleafs[i].firstleafface = LittleShort (dleafs[i].firstleafface);
- dleafs[i].numleaffaces = LittleShort (dleafs[i].numleaffaces);
- dleafs[i].firstleafbrush = LittleShort (dleafs[i].firstleafbrush);
- dleafs[i].numleafbrushes = LittleShort (dleafs[i].numleafbrushes);
- }
-
-//
-// leaffaces
-//
- for (i=0 ; i<numleaffaces ; i++)
- dleaffaces[i] = LittleShort (dleaffaces[i]);
-
-//
-// leafbrushes
-//
- for (i=0 ; i<numleafbrushes ; i++)
- dleafbrushes[i] = LittleShort (dleafbrushes[i]);
-
-//
-// surfedges
-//
- for (i=0 ; i<numsurfedges ; i++)
- dsurfedges[i] = LittleLong (dsurfedges[i]);
-
-//
-// edges
-//
- for (i=0 ; i<numedges ; i++)
- {
- dedges[i].v[0] = LittleShort (dedges[i].v[0]);
- dedges[i].v[1] = LittleShort (dedges[i].v[1]);
- }
-
-//
-// brushes
-//
- for (i=0 ; i<numbrushes ; i++)
- {
- dbrushes[i].firstside = LittleLong (dbrushes[i].firstside);
- dbrushes[i].numsides = LittleLong (dbrushes[i].numsides);
- dbrushes[i].contents = LittleLong (dbrushes[i].contents);
- }
-
-//
-// areas
-//
- for (i=0 ; i<numareas ; i++)
- {
- dareas[i].numareaportals = LittleLong (dareas[i].numareaportals);
- dareas[i].firstareaportal = LittleLong (dareas[i].firstareaportal);
- }
-
-//
-// areasportals
-//
- for (i=0 ; i<numareaportals ; i++)
- {
- dareaportals[i].portalnum = LittleLong (dareaportals[i].portalnum);
- dareaportals[i].otherarea = LittleLong (dareaportals[i].otherarea);
- }
-
-//
-// brushsides
-//
- for (i=0 ; i<numbrushsides ; i++)
- {
- dbrushsides[i].planenum = LittleShort (dbrushsides[i].planenum);
- dbrushsides[i].texinfo = LittleShort (dbrushsides[i].texinfo);
- }
-
-//
-// visibility
-//
- if (todisk)
- j = dvis->numclusters;
- else
- j = LittleLong(dvis->numclusters);
- dvis->numclusters = LittleLong (dvis->numclusters);
- for (i=0 ; i<j ; i++)
- {
- dvis->bitofs[i][0] = LittleLong (dvis->bitofs[i][0]);
- dvis->bitofs[i][1] = LittleLong (dvis->bitofs[i][1]);
- }
-} //end of the function Q2_SwapBSPFile
-
-
-dheader_t *header;
-
-int Q2_CopyLump (int lump, void *dest, int size, int maxsize)
-{
- int length, ofs;
-
- length = header->lumps[lump].filelen;
- ofs = header->lumps[lump].fileofs;
-
- if (length % size)
- Error ("LoadBSPFile: odd lump size");
-
- if ((length/size) > maxsize)
- Error ("Q2_LoadBSPFile: exceeded max size for lump %d size %d > maxsize %d\n", lump, (length/size), maxsize);
-
- memcpy (dest, (byte *)header + ofs, length);
-
- return length / size;
-} //end of the function Q2_CopyLump
-
-/*
-=============
-LoadBSPFile
-=============
-*/
-void Q2_LoadBSPFile(char *filename, int offset, int length)
-{
- int i;
-
-//
-// load the file header
-//
- LoadFile (filename, (void **)&header, offset, length);
-
-// swap the header
- for (i=0 ; i< sizeof(dheader_t)/4 ; i++)
- ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
-
- if (header->ident != IDBSPHEADER)
- Error ("%s is not a IBSP file", filename);
- if (header->version != BSPVERSION)
- Error ("%s is version %i, not %i", filename, header->version, BSPVERSION);
-
- nummodels = Q2_CopyLump (LUMP_MODELS, dmodels, sizeof(dmodel_t), MAX_MAP_MODELS);
- numvertexes = Q2_CopyLump (LUMP_VERTEXES, dvertexes, sizeof(dvertex_t), MAX_MAP_VERTS);
- numplanes = Q2_CopyLump (LUMP_PLANES, dplanes, sizeof(dplane_t), MAX_MAP_PLANES);
- numleafs = Q2_CopyLump (LUMP_LEAFS, dleafs, sizeof(dleaf_t), MAX_MAP_LEAFS);
- numnodes = Q2_CopyLump (LUMP_NODES, dnodes, sizeof(dnode_t), MAX_MAP_NODES);
- numtexinfo = Q2_CopyLump (LUMP_TEXINFO, texinfo, sizeof(texinfo_t), MAX_MAP_TEXINFO);
- numfaces = Q2_CopyLump (LUMP_FACES, dfaces, sizeof(dface_t), MAX_MAP_FACES);
- numleaffaces = Q2_CopyLump (LUMP_LEAFFACES, dleaffaces, sizeof(dleaffaces[0]), MAX_MAP_LEAFFACES);
- numleafbrushes = Q2_CopyLump (LUMP_LEAFBRUSHES, dleafbrushes, sizeof(dleafbrushes[0]), MAX_MAP_LEAFBRUSHES);
- numsurfedges = Q2_CopyLump (LUMP_SURFEDGES, dsurfedges, sizeof(dsurfedges[0]), MAX_MAP_SURFEDGES);
- numedges = Q2_CopyLump (LUMP_EDGES, dedges, sizeof(dedge_t), MAX_MAP_EDGES);
- numbrushes = Q2_CopyLump (LUMP_BRUSHES, dbrushes, sizeof(dbrush_t), MAX_MAP_BRUSHES);
- numbrushsides = Q2_CopyLump (LUMP_BRUSHSIDES, dbrushsides, sizeof(dbrushside_t), MAX_MAP_BRUSHSIDES);
- numareas = Q2_CopyLump (LUMP_AREAS, dareas, sizeof(darea_t), MAX_MAP_AREAS);
- numareaportals = Q2_CopyLump (LUMP_AREAPORTALS, dareaportals, sizeof(dareaportal_t), MAX_MAP_AREAPORTALS);
-
- visdatasize = Q2_CopyLump (LUMP_VISIBILITY, dvisdata, 1, MAX_MAP_VISIBILITY);
- lightdatasize = Q2_CopyLump (LUMP_LIGHTING, dlightdata, 1, MAX_MAP_LIGHTING);
- entdatasize = Q2_CopyLump (LUMP_ENTITIES, dentdata, 1, MAX_MAP_ENTSTRING);
-
- Q2_CopyLump (LUMP_POP, dpop, 1, MAX_MAP_DPOP);
-
- FreeMemory(header); // everything has been copied out
-
-//
-// swap everything
-//
- Q2_SwapBSPFile (false);
-
- Q2_FixTextureReferences();
-} //end of the function Q2_LoadBSPFile
-
-
-/*
-=============
-LoadBSPFileTexinfo
-
-Only loads the texinfo lump, so qdata can scan for textures
-=============
-*/
-void Q2_LoadBSPFileTexinfo (char *filename)
-{
- int i;
- FILE *f;
- int length, ofs;
-
- header = GetMemory(sizeof(dheader_t));
-
- f = fopen (filename, "rb");
- fread (header, sizeof(dheader_t), 1, f);
-
-// swap the header
- for (i=0 ; i< sizeof(dheader_t)/4 ; i++)
- ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
-
- if (header->ident != IDBSPHEADER)
- Error ("%s is not a IBSP file", filename);
- if (header->version != BSPVERSION)
- Error ("%s is version %i, not %i", filename, header->version, BSPVERSION);
-
-
- length = header->lumps[LUMP_TEXINFO].filelen;
- ofs = header->lumps[LUMP_TEXINFO].fileofs;
-
- fseek (f, ofs, SEEK_SET);
- fread (texinfo, length, 1, f);
- fclose (f);
-
- numtexinfo = length / sizeof(texinfo_t);
-
- FreeMemory(header); // everything has been copied out
-
- Q2_SwapBSPFile (false);
-} //end of the function Q2_LoadBSPFileTexinfo
-
-
-//============================================================================
-
-FILE *wadfile;
-dheader_t outheader;
-
-void Q2_AddLump (int lumpnum, void *data, int len)
-{
- lump_t *lump;
-
- lump = &header->lumps[lumpnum];
-
- lump->fileofs = LittleLong( ftell(wadfile) );
- lump->filelen = LittleLong(len);
- SafeWrite (wadfile, data, (len+3)&~3);
-} //end of the function Q2_AddLump
-
-/*
-=============
-WriteBSPFile
-
-Swaps the bsp file in place, so it should not be referenced again
-=============
-*/
-void Q2_WriteBSPFile (char *filename)
-{
- header = &outheader;
- memset (header, 0, sizeof(dheader_t));
-
- Q2_SwapBSPFile (true);
-
- header->ident = LittleLong (IDBSPHEADER);
- header->version = LittleLong (BSPVERSION);
-
- wadfile = SafeOpenWrite (filename);
- SafeWrite (wadfile, header, sizeof(dheader_t)); // overwritten later
-
- Q2_AddLump (LUMP_PLANES, dplanes, numplanes*sizeof(dplane_t));
- Q2_AddLump (LUMP_LEAFS, dleafs, numleafs*sizeof(dleaf_t));
- Q2_AddLump (LUMP_VERTEXES, dvertexes, numvertexes*sizeof(dvertex_t));
- Q2_AddLump (LUMP_NODES, dnodes, numnodes*sizeof(dnode_t));
- Q2_AddLump (LUMP_TEXINFO, texinfo, numtexinfo*sizeof(texinfo_t));
- Q2_AddLump (LUMP_FACES, dfaces, numfaces*sizeof(dface_t));
- Q2_AddLump (LUMP_BRUSHES, dbrushes, numbrushes*sizeof(dbrush_t));
- Q2_AddLump (LUMP_BRUSHSIDES, dbrushsides, numbrushsides*sizeof(dbrushside_t));
- Q2_AddLump (LUMP_LEAFFACES, dleaffaces, numleaffaces*sizeof(dleaffaces[0]));
- Q2_AddLump (LUMP_LEAFBRUSHES, dleafbrushes, numleafbrushes*sizeof(dleafbrushes[0]));
- Q2_AddLump (LUMP_SURFEDGES, dsurfedges, numsurfedges*sizeof(dsurfedges[0]));
- Q2_AddLump (LUMP_EDGES, dedges, numedges*sizeof(dedge_t));
- Q2_AddLump (LUMP_MODELS, dmodels, nummodels*sizeof(dmodel_t));
- Q2_AddLump (LUMP_AREAS, dareas, numareas*sizeof(darea_t));
- Q2_AddLump (LUMP_AREAPORTALS, dareaportals, numareaportals*sizeof(dareaportal_t));
-
- Q2_AddLump (LUMP_LIGHTING, dlightdata, lightdatasize);
- Q2_AddLump (LUMP_VISIBILITY, dvisdata, visdatasize);
- Q2_AddLump (LUMP_ENTITIES, dentdata, entdatasize);
- Q2_AddLump (LUMP_POP, dpop, sizeof(dpop));
-
- fseek (wadfile, 0, SEEK_SET);
- SafeWrite (wadfile, header, sizeof(dheader_t));
- fclose (wadfile);
-} //end of the function Q2_WriteBSPFile
-
-//============================================================================
-
-/*
-=============
-PrintBSPFileSizes
-
-Dumps info about current file
-=============
-*/
-void Q2_PrintBSPFileSizes (void)
-{
- if (!num_entities)
- Q2_ParseEntities();
-
- printf ("%6i models %7i\n"
- ,nummodels, (int)(nummodels*sizeof(dmodel_t)));
- printf ("%6i brushes %7i\n"
- ,numbrushes, (int)(numbrushes*sizeof(dbrush_t)));
- printf ("%6i brushsides %7i\n"
- ,numbrushsides, (int)(numbrushsides*sizeof(dbrushside_t)));
- printf ("%6i planes %7i\n"
- ,numplanes, (int)(numplanes*sizeof(dplane_t)));
- printf ("%6i texinfo %7i\n"
- ,numtexinfo, (int)(numtexinfo*sizeof(texinfo_t)));
- printf ("%6i entdata %7i\n", num_entities, entdatasize);
-
- printf ("\n");
-
- printf ("%6i vertexes %7i\n"
- ,numvertexes, (int)(numvertexes*sizeof(dvertex_t)));
- printf ("%6i nodes %7i\n"
- ,numnodes, (int)(numnodes*sizeof(dnode_t)));
- printf ("%6i faces %7i\n"
- ,numfaces, (int)(numfaces*sizeof(dface_t)));
- printf ("%6i leafs %7i\n"
- ,numleafs, (int)(numleafs*sizeof(dleaf_t)));
- printf ("%6i leaffaces %7i\n"
- ,numleaffaces, (int)(numleaffaces*sizeof(dleaffaces[0])));
- printf ("%6i leafbrushes %7i\n"
- ,numleafbrushes, (int)(numleafbrushes*sizeof(dleafbrushes[0])));
- printf ("%6i surfedges %7i\n"
- ,numsurfedges, (int)(numsurfedges*sizeof(dsurfedges[0])));
- printf ("%6i edges %7i\n"
- ,numedges, (int)(numedges*sizeof(dedge_t)));
-//NEW
- printf ("%6i areas %7i\n"
- ,numareas, (int)(numareas*sizeof(darea_t)));
- printf ("%6i areaportals %7i\n"
- ,numareaportals, (int)(numareaportals*sizeof(dareaportal_t)));
-//ENDNEW
- printf (" lightdata %7i\n", lightdatasize);
- printf (" visdata %7i\n", visdatasize);
-} //end of the function Q2_PrintBSPFileSizes
-
-/*
-================
-ParseEntities
-
-Parses the dentdata string into entities
-================
-*/
-void Q2_ParseEntities (void)
-{
- script_t *script;
-
- num_entities = 0;
- script = LoadScriptMemory(dentdata, entdatasize, "*Quake2 bsp file");
- SetScriptFlags(script, SCFL_NOSTRINGWHITESPACES |
- SCFL_NOSTRINGESCAPECHARS);
-
- while(ParseEntity(script))
- {
- } //end while
-
- FreeScript(script);
-} //end of the function Q2_ParseEntities
-
-
-/*
-================
-UnparseEntities
-
-Generates the dentdata string from all the entities
-================
-*/
-void Q2_UnparseEntities (void)
-{
- char *buf, *end;
- epair_t *ep;
- char line[2048];
- int i;
- char key[1024], value[1024];
-
- buf = dentdata;
- end = buf;
- *end = 0;
-
- for (i=0 ; i<num_entities ; i++)
- {
- ep = entities[i].epairs;
- if (!ep)
- continue; // ent got removed
-
- strcat (end,"{\n");
- end += 2;
-
- for (ep = entities[i].epairs ; ep ; ep=ep->next)
- {
- strcpy (key, ep->key);
- StripTrailing (key);
- strcpy (value, ep->value);
- StripTrailing (value);
-
- sprintf (line, "\"%s\" \"%s\"\n", key, value);
- strcat (end, line);
- end += strlen(line);
- }
- strcat (end,"}\n");
- end += 2;
-
- if (end > buf + MAX_MAP_ENTSTRING)
- Error ("Entity text too long");
- }
- entdatasize = end - buf + 1;
-} //end of the function Q2_UnparseEntities
-
+/*
+===========================================================================
+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 "l_cmd.h"
+#include "l_math.h"
+#include "l_mem.h"
+#include "l_log.h"
+#include "l_poly.h"
+#include "../botlib/l_script.h"
+#include "q2files.h"
+#include "l_bsp_q2.h"
+#include "l_bsp_ent.h"
+
+#define q2_dmodel_t dmodel_t
+#define q2_lump_t lump_t
+#define q2_dheader_t dheader_t
+#define q2_dmodel_t dmodel_t
+#define q2_dvertex_t dvertex_t
+#define q2_dplane_t dplane_t
+#define q2_dnode_t dnode_t
+#define q2_texinfo_t texinfo_t
+#define q2_dedge_t dedge_t
+#define q2_dface_t dface_t
+#define q2_dleaf_t dleaf_t
+#define q2_dbrushside_t dbrushside_t
+#define q2_dbrush_t dbrush_t
+#define q2_dvis_t dvis_t
+#define q2_dareaportal_t dareaportal_t
+#define q2_darea_t darea_t
+
+#define q2_nummodels nummodels
+#define q2_dmodels dmodels
+#define q2_numleafs numleafs
+#define q2_dleafs dleafs
+#define q2_numplanes numplanes
+#define q2_dplanes dplanes
+#define q2_numvertexes numvertexes
+#define q2_dvertexes dvertexes
+#define q2_numnodes numnodes
+#define q2_dnodes dnodes
+#define q2_numtexinfo numtexinfo
+#define q2_texinfo texinfo
+#define q2_numfaces numfaces
+#define q2_dfaces dfaces
+#define q2_numedges numedges
+#define q2_dedges dedges
+#define q2_numleaffaces numleaffaces
+#define q2_dleaffaces dleaffaces
+#define q2_numleafbrushes numleafbrushes
+#define q2_dleafbrushes dleafbrushes
+#define q2_dsurfedges dsurfedges
+#define q2_numbrushes numbrushes
+#define q2_dbrushes dbrushes
+#define q2_numbrushsides numbrushsides
+#define q2_dbrushsides dbrushsides
+#define q2_numareas numareas
+#define q2_dareas dareas
+#define q2_numareaportals numareaportals
+#define q2_dareaportals dareaportals
+
+void GetLeafNums (void);
+
+//=============================================================================
+
+int nummodels;
+dmodel_t *dmodels;//[MAX_MAP_MODELS];
+
+int visdatasize;
+byte *dvisdata;//[MAX_MAP_VISIBILITY];
+dvis_t *dvis;// = (dvis_t *)dvisdata;
+
+int lightdatasize;
+byte *dlightdata;//[MAX_MAP_LIGHTING];
+
+int entdatasize;
+char *dentdata;//[MAX_MAP_ENTSTRING];
+
+int numleafs;
+dleaf_t *dleafs;//[MAX_MAP_LEAFS];
+
+int numplanes;
+dplane_t *dplanes;//[MAX_MAP_PLANES];
+
+int numvertexes;
+dvertex_t *dvertexes;//[MAX_MAP_VERTS];
+
+int numnodes;
+dnode_t *dnodes;//[MAX_MAP_NODES];
+
+//NOTE: must be static for q2 .map to q2 .bsp
+int numtexinfo;
+texinfo_t texinfo[MAX_MAP_TEXINFO];
+
+int numfaces;
+dface_t *dfaces;//[MAX_MAP_FACES];
+
+int numedges;
+dedge_t *dedges;//[MAX_MAP_EDGES];
+
+int numleaffaces;
+unsigned short *dleaffaces;//[MAX_MAP_LEAFFACES];
+
+int numleafbrushes;
+unsigned short *dleafbrushes;//[MAX_MAP_LEAFBRUSHES];
+
+int numsurfedges;
+int *dsurfedges;//[MAX_MAP_SURFEDGES];
+
+int numbrushes;
+dbrush_t *dbrushes;//[MAX_MAP_BRUSHES];
+
+int numbrushsides;
+dbrushside_t *dbrushsides;//[MAX_MAP_BRUSHSIDES];
+
+int numareas;
+darea_t *dareas;//[MAX_MAP_AREAS];
+
+int numareaportals;
+dareaportal_t *dareaportals;//[MAX_MAP_AREAPORTALS];
+
+#define MAX_MAP_DPOP 256
+byte dpop[MAX_MAP_DPOP];
+
+//
+char brushsidetextured[MAX_MAP_BRUSHSIDES];
+
+//#ifdef ME
+
+int bspallocated = false;
+int allocatedbspmem = 0;
+
+void Q2_AllocMaxBSP(void)
+{
+ //models
+ nummodels = 0;
+ dmodels = (dmodel_t *) GetClearedMemory(MAX_MAP_MODELS * sizeof(dmodel_t));
+ allocatedbspmem += MAX_MAP_MODELS * sizeof(dmodel_t);
+ //vis data
+ visdatasize = 0;
+ dvisdata = (byte *) GetClearedMemory(MAX_MAP_VISIBILITY * sizeof(byte));
+ dvis = (dvis_t *) dvisdata;
+ allocatedbspmem += MAX_MAP_VISIBILITY * sizeof(byte);
+ //light data
+ lightdatasize = 0;
+ dlightdata = (byte *) GetClearedMemory(MAX_MAP_LIGHTING * sizeof(byte));
+ allocatedbspmem += MAX_MAP_LIGHTING * sizeof(byte);
+ //entity data
+ entdatasize = 0;
+ dentdata = (char *) GetClearedMemory(MAX_MAP_ENTSTRING * sizeof(char));
+ allocatedbspmem += MAX_MAP_ENTSTRING * sizeof(char);
+ //leafs
+ numleafs = 0;
+ dleafs = (dleaf_t *) GetClearedMemory(MAX_MAP_LEAFS * sizeof(dleaf_t));
+ allocatedbspmem += MAX_MAP_LEAFS * sizeof(dleaf_t);
+ //planes
+ numplanes = 0;
+ dplanes = (dplane_t *) GetClearedMemory(MAX_MAP_PLANES * sizeof(dplane_t));
+ allocatedbspmem += MAX_MAP_PLANES * sizeof(dplane_t);
+ //vertexes
+ numvertexes = 0;
+ dvertexes = (dvertex_t *) GetClearedMemory(MAX_MAP_VERTS * sizeof(dvertex_t));
+ allocatedbspmem += MAX_MAP_VERTS * sizeof(dvertex_t);
+ //nodes
+ numnodes = 0;
+ dnodes = (dnode_t *) GetClearedMemory(MAX_MAP_NODES * sizeof(dnode_t));
+ allocatedbspmem += MAX_MAP_NODES * sizeof(dnode_t);
+ /*
+ //texture info
+ numtexinfo = 0;
+ texinfo = (texinfo_t *) GetClearedMemory(MAX_MAP_TEXINFO * sizeof(texinfo_t));
+ allocatedbspmem += MAX_MAP_TEXINFO * sizeof(texinfo_t);
+ //*/
+ //faces
+ numfaces = 0;
+ dfaces = (dface_t *) GetClearedMemory(MAX_MAP_FACES * sizeof(dface_t));
+ allocatedbspmem += MAX_MAP_FACES * sizeof(dface_t);
+ //edges
+ numedges = 0;
+ dedges = (dedge_t *) GetClearedMemory(MAX_MAP_EDGES * sizeof(dedge_t));
+ allocatedbspmem += MAX_MAP_EDGES * sizeof(dedge_t);
+ //leaf faces
+ numleaffaces = 0;
+ dleaffaces = (unsigned short *) GetClearedMemory(MAX_MAP_LEAFFACES * sizeof(unsigned short));
+ allocatedbspmem += MAX_MAP_LEAFFACES * sizeof(unsigned short);
+ //leaf brushes
+ numleafbrushes = 0;
+ dleafbrushes = (unsigned short *) GetClearedMemory(MAX_MAP_LEAFBRUSHES * sizeof(unsigned short));
+ allocatedbspmem += MAX_MAP_LEAFBRUSHES * sizeof(unsigned short);
+ //surface edges
+ numsurfedges = 0;
+ dsurfedges = (int *) GetClearedMemory(MAX_MAP_SURFEDGES * sizeof(int));
+ allocatedbspmem += MAX_MAP_SURFEDGES * sizeof(int);
+ //brushes
+ numbrushes = 0;
+ dbrushes = (dbrush_t *) GetClearedMemory(MAX_MAP_BRUSHES * sizeof(dbrush_t));
+ allocatedbspmem += MAX_MAP_BRUSHES * sizeof(dbrush_t);
+ //brushsides
+ numbrushsides = 0;
+ dbrushsides = (dbrushside_t *) GetClearedMemory(MAX_MAP_BRUSHSIDES * sizeof(dbrushside_t));
+ allocatedbspmem += MAX_MAP_BRUSHSIDES * sizeof(dbrushside_t);
+ //areas
+ numareas = 0;
+ dareas = (darea_t *) GetClearedMemory(MAX_MAP_AREAS * sizeof(darea_t));
+ allocatedbspmem += MAX_MAP_AREAS * sizeof(darea_t);
+ //area portals
+ numareaportals = 0;
+ dareaportals = (dareaportal_t *) GetClearedMemory(MAX_MAP_AREAPORTALS * sizeof(dareaportal_t));
+ allocatedbspmem += MAX_MAP_AREAPORTALS * sizeof(dareaportal_t);
+ //print allocated memory
+ Log_Print("allocated ");
+ PrintMemorySize(allocatedbspmem);
+ Log_Print(" of BSP memory\n");
+} //end of the function Q2_AllocMaxBSP
+
+void Q2_FreeMaxBSP(void)
+{
+ //models
+ nummodels = 0;
+ FreeMemory(dmodels);
+ dmodels = NULL;
+ //vis data
+ visdatasize = 0;
+ FreeMemory(dvisdata);
+ dvisdata = NULL;
+ dvis = NULL;
+ //light data
+ lightdatasize = 0;
+ FreeMemory(dlightdata);
+ dlightdata = NULL;
+ //entity data
+ entdatasize = 0;
+ FreeMemory(dentdata);
+ dentdata = NULL;
+ //leafs
+ numleafs = 0;
+ FreeMemory(dleafs);
+ dleafs = NULL;
+ //planes
+ numplanes = 0;
+ FreeMemory(dplanes);
+ dplanes = NULL;
+ //vertexes
+ numvertexes = 0;
+ FreeMemory(dvertexes);
+ dvertexes = NULL;
+ //nodes
+ numnodes = 0;
+ FreeMemory(dnodes);
+ dnodes = NULL;
+ /*
+ //texture info
+ numtexinfo = 0;
+ FreeMemory(texinfo);
+ texinfo = NULL;
+ //*/
+ //faces
+ numfaces = 0;
+ FreeMemory(dfaces);
+ dfaces = NULL;
+ //edges
+ numedges = 0;
+ FreeMemory(dedges);
+ dedges = NULL;
+ //leaf faces
+ numleaffaces = 0;
+ FreeMemory(dleaffaces);
+ dleaffaces = NULL;
+ //leaf brushes
+ numleafbrushes = 0;
+ FreeMemory(dleafbrushes);
+ dleafbrushes = NULL;
+ //surface edges
+ numsurfedges = 0;
+ FreeMemory(dsurfedges);
+ dsurfedges = NULL;
+ //brushes
+ numbrushes = 0;
+ FreeMemory(dbrushes);
+ dbrushes = NULL;
+ //brushsides
+ numbrushsides = 0;
+ FreeMemory(dbrushsides);
+ dbrushsides = NULL;
+ //areas
+ numareas = 0;
+ FreeMemory(dareas);
+ dareas = NULL;
+ //area portals
+ numareaportals = 0;
+ FreeMemory(dareaportals);
+ dareaportals = NULL;
+ //
+ Log_Print("freed ");
+ PrintMemorySize(allocatedbspmem);
+ Log_Print(" of BSP memory\n");
+ allocatedbspmem = 0;
+} //end of the function Q2_FreeMaxBSP
+
+#define WCONVEX_EPSILON 0.5
+
+int InsideWinding(winding_t *w, vec3_t point, int planenum)
+{
+ int i;
+ float dist;
+ vec_t *v1, *v2;
+ vec3_t normal, edgevec;
+ dplane_t *plane;
+
+ for (i = 1; i <= w->numpoints; i++)
+ {
+ v1 = w->p[i % w->numpoints];
+ v2 = w->p[(i + 1) % w->numpoints];
+
+ VectorSubtract(v2, v1, edgevec);
+ plane = &dplanes[planenum];
+ CrossProduct(plane->normal, edgevec, normal);
+ VectorNormalize(normal);
+ dist = DotProduct(normal, v1);
+ //
+ if (DotProduct(normal, point) - dist > WCONVEX_EPSILON) return false;
+ } //end for
+ return true;
+} //end of the function InsideWinding
+
+int InsideFace(dface_t *face, vec3_t point)
+{
+ int i, edgenum, side;
+ float dist;
+ vec_t *v1, *v2;
+ vec3_t normal, edgevec;
+ dplane_t *plane;
+
+ for (i = 0; i < face->numedges; i++)
+ {
+ //get the first and second vertex of the edge
+ edgenum = dsurfedges[face->firstedge + i];
+ side = edgenum < 0;
+ v1 = dvertexes[dedges[abs(edgenum)].v[side]].point;
+ v2 = dvertexes[dedges[abs(edgenum)].v[!side]].point;
+ //create a plane through the edge vector, orthogonal to the face plane
+ //and with the normal vector pointing out of the face
+ VectorSubtract(v1, v2, edgevec);
+ plane = &dplanes[face->planenum];
+ CrossProduct(plane->normal, edgevec, normal);
+ VectorNormalize(normal);
+ dist = DotProduct(normal, v1);
+ //
+ if (DotProduct(normal, point) - dist > WCONVEX_EPSILON) return false;
+ } //end for
+ return true;
+} //end of the function InsideFace
+//===========================================================================
+// returns the amount the face and the winding overlap
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+float Q2_FaceOnWinding(q2_dface_t *face, winding_t *winding)
+{
+ int i, edgenum, side;
+ float dist, area;
+ q2_dplane_t plane;
+ vec_t *v1, *v2;
+ vec3_t normal, edgevec;
+ winding_t *w;
+
+ //
+ w = CopyWinding(winding);
+ memcpy(&plane, &q2_dplanes[face->planenum], sizeof(q2_dplane_t));
+ //check on which side of the plane the face is
+ if (face->side)
+ {
+ VectorNegate(plane.normal, plane.normal);
+ plane.dist = -plane.dist;
+ } //end if
+ for (i = 0; i < face->numedges && w; i++)
+ {
+ //get the first and second vertex of the edge
+ edgenum = q2_dsurfedges[face->firstedge + i];
+ side = edgenum > 0;
+ //if the face plane is flipped
+ v1 = q2_dvertexes[q2_dedges[abs(edgenum)].v[side]].point;
+ v2 = q2_dvertexes[q2_dedges[abs(edgenum)].v[!side]].point;
+ //create a plane through the edge vector, orthogonal to the face plane
+ //and with the normal vector pointing inward
+ VectorSubtract(v1, v2, edgevec);
+ CrossProduct(edgevec, plane.normal, normal);
+ VectorNormalize(normal);
+ dist = DotProduct(normal, v1);
+ //
+ ChopWindingInPlace(&w, normal, dist, -0.1); //CLIP_EPSILON
+ } //end for
+ if (w)
+ {
+ area = WindingArea(w);
+ FreeWinding(w);
+ return area;
+ } //end if
+ return 0;
+} //end of the function Q2_FaceOnWinding
+//===========================================================================
+// creates a winding for the given brush side on the given brush
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+winding_t *Q2_BrushSideWinding(dbrush_t *brush, dbrushside_t *baseside)
+{
+ int i;
+ dplane_t *baseplane, *plane;
+ winding_t *w;
+ dbrushside_t *side;
+
+ //create a winding for the brush side with the given planenumber
+ baseplane = &dplanes[baseside->planenum];
+ w = BaseWindingForPlane(baseplane->normal, baseplane->dist);
+ for (i = 0; i < brush->numsides && w; i++)
+ {
+ side = &dbrushsides[brush->firstside + i];
+ //don't chop with the base plane
+ if (side->planenum == baseside->planenum) continue;
+ //also don't use planes that are almost equal
+ plane = &dplanes[side->planenum];
+ if (DotProduct(baseplane->normal, plane->normal) > 0.999
+ && fabs(baseplane->dist - plane->dist) < 0.01) continue;
+ //
+ plane = &dplanes[side->planenum^1];
+ ChopWindingInPlace(&w, plane->normal, plane->dist, -0.1); //CLIP_EPSILON);
+ } //end for
+ return w;
+} //end of the function Q2_BrushSideWinding
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int Q2_HintSkipBrush(dbrush_t *brush)
+{
+ int j;
+ dbrushside_t *brushside;
+
+ for (j = 0; j < brush->numsides; j++)
+ {
+ brushside = &dbrushsides[brush->firstside + j];
+ if (brushside->texinfo > 0)
+ {
+ if (texinfo[brushside->texinfo].flags & (SURF_SKIP|SURF_HINT))
+ {
+ return true;
+ } //end if
+ } //end if
+ } //end for
+ return false;
+} //end of the function Q2_HintSkipBrush
+//===========================================================================
+// fix screwed brush texture references
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+qboolean WindingIsTiny(winding_t *w);
+
+void Q2_FixTextureReferences(void)
+{
+ int i, j, k, we;
+ dbrushside_t *brushside;
+ dbrush_t *brush;
+ dface_t *face;
+ winding_t *w;
+
+ memset(brushsidetextured, false, MAX_MAP_BRUSHSIDES);
+ //go over all the brushes
+ for (i = 0; i < numbrushes; i++)
+ {
+ brush = &dbrushes[i];
+ //hint brushes are not textured
+ if (Q2_HintSkipBrush(brush)) continue;
+ //go over all the sides of the brush
+ for (j = 0; j < brush->numsides; j++)
+ {
+ brushside = &dbrushsides[brush->firstside + j];
+ //
+ w = Q2_BrushSideWinding(brush, brushside);
+ if (!w)
+ {
+ brushsidetextured[brush->firstside + j] = true;
+ continue;
+ } //end if
+ else
+ {
+ //RemoveEqualPoints(w, 0.2);
+ if (WindingIsTiny(w))
+ {
+ FreeWinding(w);
+ brushsidetextured[brush->firstside + j] = true;
+ continue;
+ } //end if
+ else
+ {
+ we = WindingError(w);
+ if (we == WE_NOTENOUGHPOINTS
+ || we == WE_SMALLAREA
+ || we == WE_POINTBOGUSRANGE
+// || we == WE_NONCONVEX
+ )
+ {
+ FreeWinding(w);
+ brushsidetextured[brush->firstside + j] = true;
+ continue;
+ } //end if
+ } //end else
+ } //end else
+ if (WindingArea(w) < 20)
+ {
+ brushsidetextured[brush->firstside + j] = true;
+ } //end if
+ //find a face for texturing this brush
+ for (k = 0; k < numfaces; k++)
+ {
+ face = &dfaces[k];
+ //if the face is in the same plane as the brush side
+ if ((face->planenum&~1) != (brushside->planenum&~1)) continue;
+ //if the face is partly or totally on the brush side
+ if (Q2_FaceOnWinding(face, w))
+ {
+ brushside->texinfo = face->texinfo;
+ brushsidetextured[brush->firstside + j] = true;
+ break;
+ } //end if
+ } //end for
+ FreeWinding(w);
+ } //end for
+ } //end for
+} //end of the function Q2_FixTextureReferences*/
+
+//#endif //ME
+
+
+/*
+===============
+CompressVis
+
+===============
+*/
+int Q2_CompressVis (byte *vis, byte *dest)
+{
+ int j;
+ int rep;
+ int visrow;
+ byte *dest_p;
+
+ dest_p = dest;
+// visrow = (r_numvisleafs + 7)>>3;
+ visrow = (dvis->numclusters + 7)>>3;
+
+ for (j=0 ; j<visrow ; j++)
+ {
+ *dest_p++ = vis[j];
+ if (vis[j])
+ continue;
+
+ rep = 1;
+ for ( j++; j<visrow ; j++)
+ if (vis[j] || rep == 255)
+ break;
+ else
+ rep++;
+ *dest_p++ = rep;
+ j--;
+ }
+
+ return dest_p - dest;
+}
+
+
+/*
+===================
+DecompressVis
+===================
+*/
+void Q2_DecompressVis (byte *in, byte *decompressed)
+{
+ int c;
+ byte *out;
+ int row;
+
+// row = (r_numvisleafs+7)>>3;
+ row = (dvis->numclusters+7)>>3;
+ out = decompressed;
+
+ do
+ {
+ if (*in)
+ {
+ *out++ = *in++;
+ continue;
+ }
+
+ c = in[1];
+ if (!c)
+ Error ("DecompressVis: 0 repeat");
+ in += 2;
+ while (c)
+ {
+ *out++ = 0;
+ c--;
+ }
+ } while (out - decompressed < row);
+}
+
+//=============================================================================
+
+/*
+=============
+SwapBSPFile
+
+Byte swaps all data in a bsp file.
+=============
+*/
+void Q2_SwapBSPFile (qboolean todisk)
+{
+ int i, j;
+ dmodel_t *d;
+
+
+// models
+ for (i=0 ; i<nummodels ; i++)
+ {
+ d = &dmodels[i];
+
+ d->firstface = LittleLong (d->firstface);
+ d->numfaces = LittleLong (d->numfaces);
+ d->headnode = LittleLong (d->headnode);
+
+ for (j=0 ; j<3 ; j++)
+ {
+ d->mins[j] = LittleFloat(d->mins[j]);
+ d->maxs[j] = LittleFloat(d->maxs[j]);
+ d->origin[j] = LittleFloat(d->origin[j]);
+ }
+ }
+
+//
+// vertexes
+//
+ for (i=0 ; i<numvertexes ; i++)
+ {
+ for (j=0 ; j<3 ; j++)
+ dvertexes[i].point[j] = LittleFloat (dvertexes[i].point[j]);
+ }
+
+//
+// planes
+//
+ for (i=0 ; i<numplanes ; i++)
+ {
+ for (j=0 ; j<3 ; j++)
+ dplanes[i].normal[j] = LittleFloat (dplanes[i].normal[j]);
+ dplanes[i].dist = LittleFloat (dplanes[i].dist);
+ dplanes[i].type = LittleLong (dplanes[i].type);
+ }
+
+//
+// texinfos
+//
+ for (i=0 ; i<numtexinfo ; i++)
+ {
+ for (j=0 ; j<8 ; j++)
+ texinfo[i].vecs[0][j] = LittleFloat (texinfo[i].vecs[0][j]);
+ texinfo[i].flags = LittleLong (texinfo[i].flags);
+ texinfo[i].value = LittleLong (texinfo[i].value);
+ texinfo[i].nexttexinfo = LittleLong (texinfo[i].nexttexinfo);
+ }
+
+//
+// faces
+//
+ for (i=0 ; i<numfaces ; i++)
+ {
+ dfaces[i].texinfo = LittleShort (dfaces[i].texinfo);
+ dfaces[i].planenum = LittleShort (dfaces[i].planenum);
+ dfaces[i].side = LittleShort (dfaces[i].side);
+ dfaces[i].lightofs = LittleLong (dfaces[i].lightofs);
+ dfaces[i].firstedge = LittleLong (dfaces[i].firstedge);
+ dfaces[i].numedges = LittleShort (dfaces[i].numedges);
+ }
+
+//
+// nodes
+//
+ for (i=0 ; i<numnodes ; i++)
+ {
+ dnodes[i].planenum = LittleLong (dnodes[i].planenum);
+ for (j=0 ; j<3 ; j++)
+ {
+ dnodes[i].mins[j] = LittleShort (dnodes[i].mins[j]);
+ dnodes[i].maxs[j] = LittleShort (dnodes[i].maxs[j]);
+ }
+ dnodes[i].children[0] = LittleLong (dnodes[i].children[0]);
+ dnodes[i].children[1] = LittleLong (dnodes[i].children[1]);
+ dnodes[i].firstface = LittleShort (dnodes[i].firstface);
+ dnodes[i].numfaces = LittleShort (dnodes[i].numfaces);
+ }
+
+//
+// leafs
+//
+ for (i=0 ; i<numleafs ; i++)
+ {
+ dleafs[i].contents = LittleLong (dleafs[i].contents);
+ dleafs[i].cluster = LittleShort (dleafs[i].cluster);
+ dleafs[i].area = LittleShort (dleafs[i].area);
+ for (j=0 ; j<3 ; j++)
+ {
+ dleafs[i].mins[j] = LittleShort (dleafs[i].mins[j]);
+ dleafs[i].maxs[j] = LittleShort (dleafs[i].maxs[j]);
+ }
+
+ dleafs[i].firstleafface = LittleShort (dleafs[i].firstleafface);
+ dleafs[i].numleaffaces = LittleShort (dleafs[i].numleaffaces);
+ dleafs[i].firstleafbrush = LittleShort (dleafs[i].firstleafbrush);
+ dleafs[i].numleafbrushes = LittleShort (dleafs[i].numleafbrushes);
+ }
+
+//
+// leaffaces
+//
+ for (i=0 ; i<numleaffaces ; i++)
+ dleaffaces[i] = LittleShort (dleaffaces[i]);
+
+//
+// leafbrushes
+//
+ for (i=0 ; i<numleafbrushes ; i++)
+ dleafbrushes[i] = LittleShort (dleafbrushes[i]);
+
+//
+// surfedges
+//
+ for (i=0 ; i<numsurfedges ; i++)
+ dsurfedges[i] = LittleLong (dsurfedges[i]);
+
+//
+// edges
+//
+ for (i=0 ; i<numedges ; i++)
+ {
+ dedges[i].v[0] = LittleShort (dedges[i].v[0]);
+ dedges[i].v[1] = LittleShort (dedges[i].v[1]);
+ }
+
+//
+// brushes
+//
+ for (i=0 ; i<numbrushes ; i++)
+ {
+ dbrushes[i].firstside = LittleLong (dbrushes[i].firstside);
+ dbrushes[i].numsides = LittleLong (dbrushes[i].numsides);
+ dbrushes[i].contents = LittleLong (dbrushes[i].contents);
+ }
+
+//
+// areas
+//
+ for (i=0 ; i<numareas ; i++)
+ {
+ dareas[i].numareaportals = LittleLong (dareas[i].numareaportals);
+ dareas[i].firstareaportal = LittleLong (dareas[i].firstareaportal);
+ }
+
+//
+// areasportals
+//
+ for (i=0 ; i<numareaportals ; i++)
+ {
+ dareaportals[i].portalnum = LittleLong (dareaportals[i].portalnum);
+ dareaportals[i].otherarea = LittleLong (dareaportals[i].otherarea);
+ }
+
+//
+// brushsides
+//
+ for (i=0 ; i<numbrushsides ; i++)
+ {
+ dbrushsides[i].planenum = LittleShort (dbrushsides[i].planenum);
+ dbrushsides[i].texinfo = LittleShort (dbrushsides[i].texinfo);
+ }
+
+//
+// visibility
+//
+ if (todisk)
+ j = dvis->numclusters;
+ else
+ j = LittleLong(dvis->numclusters);
+ dvis->numclusters = LittleLong (dvis->numclusters);
+ for (i=0 ; i<j ; i++)
+ {
+ dvis->bitofs[i][0] = LittleLong (dvis->bitofs[i][0]);
+ dvis->bitofs[i][1] = LittleLong (dvis->bitofs[i][1]);
+ }
+} //end of the function Q2_SwapBSPFile
+
+
+dheader_t *header;
+
+int Q2_CopyLump (int lump, void *dest, int size, int maxsize)
+{
+ int length, ofs;
+
+ length = header->lumps[lump].filelen;
+ ofs = header->lumps[lump].fileofs;
+
+ if (length % size)
+ Error ("LoadBSPFile: odd lump size");
+
+ if ((length/size) > maxsize)
+ Error ("Q2_LoadBSPFile: exceeded max size for lump %d size %d > maxsize %d\n", lump, (length/size), maxsize);
+
+ memcpy (dest, (byte *)header + ofs, length);
+
+ return length / size;
+} //end of the function Q2_CopyLump
+
+/*
+=============
+LoadBSPFile
+=============
+*/
+void Q2_LoadBSPFile(char *filename, int offset, int length)
+{
+ int i;
+
+//
+// load the file header
+//
+ LoadFile (filename, (void **)&header, offset, length);
+
+// swap the header
+ for (i=0 ; i< sizeof(dheader_t)/4 ; i++)
+ ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
+
+ if (header->ident != IDBSPHEADER)
+ Error ("%s is not a IBSP file", filename);
+ if (header->version != BSPVERSION)
+ Error ("%s is version %i, not %i", filename, header->version, BSPVERSION);
+
+ nummodels = Q2_CopyLump (LUMP_MODELS, dmodels, sizeof(dmodel_t), MAX_MAP_MODELS);
+ numvertexes = Q2_CopyLump (LUMP_VERTEXES, dvertexes, sizeof(dvertex_t), MAX_MAP_VERTS);
+ numplanes = Q2_CopyLump (LUMP_PLANES, dplanes, sizeof(dplane_t), MAX_MAP_PLANES);
+ numleafs = Q2_CopyLump (LUMP_LEAFS, dleafs, sizeof(dleaf_t), MAX_MAP_LEAFS);
+ numnodes = Q2_CopyLump (LUMP_NODES, dnodes, sizeof(dnode_t), MAX_MAP_NODES);
+ numtexinfo = Q2_CopyLump (LUMP_TEXINFO, texinfo, sizeof(texinfo_t), MAX_MAP_TEXINFO);
+ numfaces = Q2_CopyLump (LUMP_FACES, dfaces, sizeof(dface_t), MAX_MAP_FACES);
+ numleaffaces = Q2_CopyLump (LUMP_LEAFFACES, dleaffaces, sizeof(dleaffaces[0]), MAX_MAP_LEAFFACES);
+ numleafbrushes = Q2_CopyLump (LUMP_LEAFBRUSHES, dleafbrushes, sizeof(dleafbrushes[0]), MAX_MAP_LEAFBRUSHES);
+ numsurfedges = Q2_CopyLump (LUMP_SURFEDGES, dsurfedges, sizeof(dsurfedges[0]), MAX_MAP_SURFEDGES);
+ numedges = Q2_CopyLump (LUMP_EDGES, dedges, sizeof(dedge_t), MAX_MAP_EDGES);
+ numbrushes = Q2_CopyLump (LUMP_BRUSHES, dbrushes, sizeof(dbrush_t), MAX_MAP_BRUSHES);
+ numbrushsides = Q2_CopyLump (LUMP_BRUSHSIDES, dbrushsides, sizeof(dbrushside_t), MAX_MAP_BRUSHSIDES);
+ numareas = Q2_CopyLump (LUMP_AREAS, dareas, sizeof(darea_t), MAX_MAP_AREAS);
+ numareaportals = Q2_CopyLump (LUMP_AREAPORTALS, dareaportals, sizeof(dareaportal_t), MAX_MAP_AREAPORTALS);
+
+ visdatasize = Q2_CopyLump (LUMP_VISIBILITY, dvisdata, 1, MAX_MAP_VISIBILITY);
+ lightdatasize = Q2_CopyLump (LUMP_LIGHTING, dlightdata, 1, MAX_MAP_LIGHTING);
+ entdatasize = Q2_CopyLump (LUMP_ENTITIES, dentdata, 1, MAX_MAP_ENTSTRING);
+
+ Q2_CopyLump (LUMP_POP, dpop, 1, MAX_MAP_DPOP);
+
+ FreeMemory(header); // everything has been copied out
+
+//
+// swap everything
+//
+ Q2_SwapBSPFile (false);
+
+ Q2_FixTextureReferences();
+} //end of the function Q2_LoadBSPFile
+
+
+/*
+=============
+LoadBSPFileTexinfo
+
+Only loads the texinfo lump, so qdata can scan for textures
+=============
+*/
+void Q2_LoadBSPFileTexinfo (char *filename)
+{
+ int i;
+ FILE *f;
+ int length, ofs;
+
+ header = GetMemory(sizeof(dheader_t));
+
+ f = fopen (filename, "rb");
+ fread (header, sizeof(dheader_t), 1, f);
+
+// swap the header
+ for (i=0 ; i< sizeof(dheader_t)/4 ; i++)
+ ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
+
+ if (header->ident != IDBSPHEADER)
+ Error ("%s is not a IBSP file", filename);
+ if (header->version != BSPVERSION)
+ Error ("%s is version %i, not %i", filename, header->version, BSPVERSION);
+
+
+ length = header->lumps[LUMP_TEXINFO].filelen;
+ ofs = header->lumps[LUMP_TEXINFO].fileofs;
+
+ fseek (f, ofs, SEEK_SET);
+ fread (texinfo, length, 1, f);
+ fclose (f);
+
+ numtexinfo = length / sizeof(texinfo_t);
+
+ FreeMemory(header); // everything has been copied out
+
+ Q2_SwapBSPFile (false);
+} //end of the function Q2_LoadBSPFileTexinfo
+
+
+//============================================================================
+
+FILE *wadfile;
+dheader_t outheader;
+
+void Q2_AddLump (int lumpnum, void *data, int len)
+{
+ lump_t *lump;
+
+ lump = &header->lumps[lumpnum];
+
+ lump->fileofs = LittleLong( ftell(wadfile) );
+ lump->filelen = LittleLong(len);
+ SafeWrite (wadfile, data, (len+3)&~3);
+} //end of the function Q2_AddLump
+
+/*
+=============
+WriteBSPFile
+
+Swaps the bsp file in place, so it should not be referenced again
+=============
+*/
+void Q2_WriteBSPFile (char *filename)
+{
+ header = &outheader;
+ memset (header, 0, sizeof(dheader_t));
+
+ Q2_SwapBSPFile (true);
+
+ header->ident = LittleLong (IDBSPHEADER);
+ header->version = LittleLong (BSPVERSION);
+
+ wadfile = SafeOpenWrite (filename);
+ SafeWrite (wadfile, header, sizeof(dheader_t)); // overwritten later
+
+ Q2_AddLump (LUMP_PLANES, dplanes, numplanes*sizeof(dplane_t));
+ Q2_AddLump (LUMP_LEAFS, dleafs, numleafs*sizeof(dleaf_t));
+ Q2_AddLump (LUMP_VERTEXES, dvertexes, numvertexes*sizeof(dvertex_t));
+ Q2_AddLump (LUMP_NODES, dnodes, numnodes*sizeof(dnode_t));
+ Q2_AddLump (LUMP_TEXINFO, texinfo, numtexinfo*sizeof(texinfo_t));
+ Q2_AddLump (LUMP_FACES, dfaces, numfaces*sizeof(dface_t));
+ Q2_AddLump (LUMP_BRUSHES, dbrushes, numbrushes*sizeof(dbrush_t));
+ Q2_AddLump (LUMP_BRUSHSIDES, dbrushsides, numbrushsides*sizeof(dbrushside_t));
+ Q2_AddLump (LUMP_LEAFFACES, dleaffaces, numleaffaces*sizeof(dleaffaces[0]));
+ Q2_AddLump (LUMP_LEAFBRUSHES, dleafbrushes, numleafbrushes*sizeof(dleafbrushes[0]));
+ Q2_AddLump (LUMP_SURFEDGES, dsurfedges, numsurfedges*sizeof(dsurfedges[0]));
+ Q2_AddLump (LUMP_EDGES, dedges, numedges*sizeof(dedge_t));
+ Q2_AddLump (LUMP_MODELS, dmodels, nummodels*sizeof(dmodel_t));
+ Q2_AddLump (LUMP_AREAS, dareas, numareas*sizeof(darea_t));
+ Q2_AddLump (LUMP_AREAPORTALS, dareaportals, numareaportals*sizeof(dareaportal_t));
+
+ Q2_AddLump (LUMP_LIGHTING, dlightdata, lightdatasize);
+ Q2_AddLump (LUMP_VISIBILITY, dvisdata, visdatasize);
+ Q2_AddLump (LUMP_ENTITIES, dentdata, entdatasize);
+ Q2_AddLump (LUMP_POP, dpop, sizeof(dpop));
+
+ fseek (wadfile, 0, SEEK_SET);
+ SafeWrite (wadfile, header, sizeof(dheader_t));
+ fclose (wadfile);
+} //end of the function Q2_WriteBSPFile
+
+//============================================================================
+
+/*
+=============
+PrintBSPFileSizes
+
+Dumps info about current file
+=============
+*/
+void Q2_PrintBSPFileSizes (void)
+{
+ if (!num_entities)
+ Q2_ParseEntities();
+
+ printf ("%6i models %7i\n"
+ ,nummodels, (int)(nummodels*sizeof(dmodel_t)));
+ printf ("%6i brushes %7i\n"
+ ,numbrushes, (int)(numbrushes*sizeof(dbrush_t)));
+ printf ("%6i brushsides %7i\n"
+ ,numbrushsides, (int)(numbrushsides*sizeof(dbrushside_t)));
+ printf ("%6i planes %7i\n"
+ ,numplanes, (int)(numplanes*sizeof(dplane_t)));
+ printf ("%6i texinfo %7i\n"
+ ,numtexinfo, (int)(numtexinfo*sizeof(texinfo_t)));
+ printf ("%6i entdata %7i\n", num_entities, entdatasize);
+
+ printf ("\n");
+
+ printf ("%6i vertexes %7i\n"
+ ,numvertexes, (int)(numvertexes*sizeof(dvertex_t)));
+ printf ("%6i nodes %7i\n"
+ ,numnodes, (int)(numnodes*sizeof(dnode_t)));
+ printf ("%6i faces %7i\n"
+ ,numfaces, (int)(numfaces*sizeof(dface_t)));
+ printf ("%6i leafs %7i\n"
+ ,numleafs, (int)(numleafs*sizeof(dleaf_t)));
+ printf ("%6i leaffaces %7i\n"
+ ,numleaffaces, (int)(numleaffaces*sizeof(dleaffaces[0])));
+ printf ("%6i leafbrushes %7i\n"
+ ,numleafbrushes, (int)(numleafbrushes*sizeof(dleafbrushes[0])));
+ printf ("%6i surfedges %7i\n"
+ ,numsurfedges, (int)(numsurfedges*sizeof(dsurfedges[0])));
+ printf ("%6i edges %7i\n"
+ ,numedges, (int)(numedges*sizeof(dedge_t)));
+//NEW
+ printf ("%6i areas %7i\n"
+ ,numareas, (int)(numareas*sizeof(darea_t)));
+ printf ("%6i areaportals %7i\n"
+ ,numareaportals, (int)(numareaportals*sizeof(dareaportal_t)));
+//ENDNEW
+ printf (" lightdata %7i\n", lightdatasize);
+ printf (" visdata %7i\n", visdatasize);
+} //end of the function Q2_PrintBSPFileSizes
+
+/*
+================
+ParseEntities
+
+Parses the dentdata string into entities
+================
+*/
+void Q2_ParseEntities (void)
+{
+ script_t *script;
+
+ num_entities = 0;
+ script = LoadScriptMemory(dentdata, entdatasize, "*Quake2 bsp file");
+ SetScriptFlags(script, SCFL_NOSTRINGWHITESPACES |
+ SCFL_NOSTRINGESCAPECHARS);
+
+ while(ParseEntity(script))
+ {
+ } //end while
+
+ FreeScript(script);
+} //end of the function Q2_ParseEntities
+
+
+/*
+================
+UnparseEntities
+
+Generates the dentdata string from all the entities
+================
+*/
+void Q2_UnparseEntities (void)
+{
+ char *buf, *end;
+ epair_t *ep;
+ char line[2048];
+ int i;
+ char key[1024], value[1024];
+
+ buf = dentdata;
+ end = buf;
+ *end = 0;
+
+ for (i=0 ; i<num_entities ; i++)
+ {
+ ep = entities[i].epairs;
+ if (!ep)
+ continue; // ent got removed
+
+ strcat (end,"{\n");
+ end += 2;
+
+ for (ep = entities[i].epairs ; ep ; ep=ep->next)
+ {
+ strcpy (key, ep->key);
+ StripTrailing (key);
+ strcpy (value, ep->value);
+ StripTrailing (value);
+
+ sprintf (line, "\"%s\" \"%s\"\n", key, value);
+ strcat (end, line);
+ end += strlen(line);
+ }
+ strcat (end,"}\n");
+ end += 2;
+
+ if (end > buf + MAX_MAP_ENTSTRING)
+ Error ("Entity text too long");
+ }
+ entdatasize = end - buf + 1;
+} //end of the function Q2_UnparseEntities
+
diff --git a/code/bspc/l_bsp_q2.h b/code/bspc/l_bsp_q2.h
index 8d937a8..f0720df 100755
--- a/code/bspc/l_bsp_q2.h
+++ b/code/bspc/l_bsp_q2.h
@@ -1,98 +1,98 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-
-#ifndef ME
-#define ME
-#endif //ME
-
-extern int nummodels;
-extern dmodel_t *dmodels;//[MAX_MAP_MODELS];
-
-extern int visdatasize;
-extern byte *dvisdata;//[MAX_MAP_VISIBILITY];
-extern dvis_t *dvis;
-
-extern int lightdatasize;
-extern byte *dlightdata;//[MAX_MAP_LIGHTING];
-
-extern int entdatasize;
-extern char *dentdata;//[MAX_MAP_ENTSTRING];
-
-extern int numleafs;
-extern dleaf_t *dleafs;//[MAX_MAP_LEAFS];
-
-extern int numplanes;
-extern dplane_t *dplanes;//[MAX_MAP_PLANES];
-
-extern int numvertexes;
-extern dvertex_t *dvertexes;//[MAX_MAP_VERTS];
-
-extern int numnodes;
-extern dnode_t *dnodes;//[MAX_MAP_NODES];
-
-extern int numtexinfo;
-extern texinfo_t texinfo[MAX_MAP_TEXINFO];
-
-extern int numfaces;
-extern dface_t *dfaces;//[MAX_MAP_FACES];
-
-extern int numedges;
-extern dedge_t *dedges;//[MAX_MAP_EDGES];
-
-extern int numleaffaces;
-extern unsigned short *dleaffaces;//[MAX_MAP_LEAFFACES];
-
-extern int numleafbrushes;
-extern unsigned short *dleafbrushes;//[MAX_MAP_LEAFBRUSHES];
-
-extern int numsurfedges;
-extern int *dsurfedges;//[MAX_MAP_SURFEDGES];
-
-extern int numareas;
-extern darea_t *dareas;//[MAX_MAP_AREAS];
-
-extern int numareaportals;
-extern dareaportal_t *dareaportals;//[MAX_MAP_AREAPORTALS];
-
-extern int numbrushes;
-extern dbrush_t *dbrushes;//[MAX_MAP_BRUSHES];
-
-extern int numbrushsides;
-extern dbrushside_t *dbrushsides;//[MAX_MAP_BRUSHSIDES];
-
-extern byte dpop[256];
-
-extern char brushsidetextured[MAX_MAP_BRUSHSIDES];
-
-void Q2_AllocMaxBSP(void);
-void Q2_FreeMaxBSP(void);
-
-void Q2_DecompressVis(byte *in, byte *decompressed);
-int Q2_CompressVis(byte *vis, byte *dest);
-
-void Q2_LoadBSPFile(char *filename, int offset, int length);
-void Q2_LoadBSPFileTexinfo(char *filename); // just for qdata
-void Q2_WriteBSPFile(char *filename);
-void Q2_PrintBSPFileSizes(void);
-void Q2_ParseEntities(void);
-void Q2_UnparseEntities(void);
-
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+#ifndef ME
+#define ME
+#endif //ME
+
+extern int nummodels;
+extern dmodel_t *dmodels;//[MAX_MAP_MODELS];
+
+extern int visdatasize;
+extern byte *dvisdata;//[MAX_MAP_VISIBILITY];
+extern dvis_t *dvis;
+
+extern int lightdatasize;
+extern byte *dlightdata;//[MAX_MAP_LIGHTING];
+
+extern int entdatasize;
+extern char *dentdata;//[MAX_MAP_ENTSTRING];
+
+extern int numleafs;
+extern dleaf_t *dleafs;//[MAX_MAP_LEAFS];
+
+extern int numplanes;
+extern dplane_t *dplanes;//[MAX_MAP_PLANES];
+
+extern int numvertexes;
+extern dvertex_t *dvertexes;//[MAX_MAP_VERTS];
+
+extern int numnodes;
+extern dnode_t *dnodes;//[MAX_MAP_NODES];
+
+extern int numtexinfo;
+extern texinfo_t texinfo[MAX_MAP_TEXINFO];
+
+extern int numfaces;
+extern dface_t *dfaces;//[MAX_MAP_FACES];
+
+extern int numedges;
+extern dedge_t *dedges;//[MAX_MAP_EDGES];
+
+extern int numleaffaces;
+extern unsigned short *dleaffaces;//[MAX_MAP_LEAFFACES];
+
+extern int numleafbrushes;
+extern unsigned short *dleafbrushes;//[MAX_MAP_LEAFBRUSHES];
+
+extern int numsurfedges;
+extern int *dsurfedges;//[MAX_MAP_SURFEDGES];
+
+extern int numareas;
+extern darea_t *dareas;//[MAX_MAP_AREAS];
+
+extern int numareaportals;
+extern dareaportal_t *dareaportals;//[MAX_MAP_AREAPORTALS];
+
+extern int numbrushes;
+extern dbrush_t *dbrushes;//[MAX_MAP_BRUSHES];
+
+extern int numbrushsides;
+extern dbrushside_t *dbrushsides;//[MAX_MAP_BRUSHSIDES];
+
+extern byte dpop[256];
+
+extern char brushsidetextured[MAX_MAP_BRUSHSIDES];
+
+void Q2_AllocMaxBSP(void);
+void Q2_FreeMaxBSP(void);
+
+void Q2_DecompressVis(byte *in, byte *decompressed);
+int Q2_CompressVis(byte *vis, byte *dest);
+
+void Q2_LoadBSPFile(char *filename, int offset, int length);
+void Q2_LoadBSPFileTexinfo(char *filename); // just for qdata
+void Q2_WriteBSPFile(char *filename);
+void Q2_PrintBSPFileSizes(void);
+void Q2_ParseEntities(void);
+void Q2_UnparseEntities(void);
+
diff --git a/code/bspc/l_bsp_q3.c b/code/bspc/l_bsp_q3.c
index 19a3941..24bb766 100755
--- a/code/bspc/l_bsp_q3.c
+++ b/code/bspc/l_bsp_q3.c
@@ -1,824 +1,824 @@
-/*
-===========================================================================
-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 "l_cmd.h"
-#include "l_math.h"
-#include "l_mem.h"
-#include "l_log.h"
-#include "l_poly.h"
-#include "../botlib/l_script.h"
-#include "l_qfiles.h"
-#include "l_bsp_q3.h"
-#include "l_bsp_ent.h"
-
-void Q3_ParseEntities (void);
-void Q3_PrintBSPFileSizes(void);
-
-void GetLeafNums (void);
-
-//=============================================================================
-
-#define WCONVEX_EPSILON 0.5
-
-
-int q3_nummodels;
-q3_dmodel_t *q3_dmodels;//[MAX_MAP_MODELS];
-
-int q3_numShaders;
-q3_dshader_t *q3_dshaders;//[Q3_MAX_MAP_SHADERS];
-
-int q3_entdatasize;
-char *q3_dentdata;//[Q3_MAX_MAP_ENTSTRING];
-
-int q3_numleafs;
-q3_dleaf_t *q3_dleafs;//[Q3_MAX_MAP_LEAFS];
-
-int q3_numplanes;
-q3_dplane_t *q3_dplanes;//[Q3_MAX_MAP_PLANES];
-
-int q3_numnodes;
-q3_dnode_t *q3_dnodes;//[Q3_MAX_MAP_NODES];
-
-int q3_numleafsurfaces;
-int *q3_dleafsurfaces;//[Q3_MAX_MAP_LEAFFACES];
-
-int q3_numleafbrushes;
-int *q3_dleafbrushes;//[Q3_MAX_MAP_LEAFBRUSHES];
-
-int q3_numbrushes;
-q3_dbrush_t *q3_dbrushes;//[Q3_MAX_MAP_BRUSHES];
-
-int q3_numbrushsides;
-q3_dbrushside_t *q3_dbrushsides;//[Q3_MAX_MAP_BRUSHSIDES];
-
-int q3_numLightBytes;
-byte *q3_lightBytes;//[Q3_MAX_MAP_LIGHTING];
-
-int q3_numGridPoints;
-byte *q3_gridData;//[Q3_MAX_MAP_LIGHTGRID];
-
-int q3_numVisBytes;
-byte *q3_visBytes;//[Q3_MAX_MAP_VISIBILITY];
-
-int q3_numDrawVerts;
-q3_drawVert_t *q3_drawVerts;//[Q3_MAX_MAP_DRAW_VERTS];
-
-int q3_numDrawIndexes;
-int *q3_drawIndexes;//[Q3_MAX_MAP_DRAW_INDEXES];
-
-int q3_numDrawSurfaces;
-q3_dsurface_t *q3_drawSurfaces;//[Q3_MAX_MAP_DRAW_SURFS];
-
-int q3_numFogs;
-q3_dfog_t *q3_dfogs;//[Q3_MAX_MAP_FOGS];
-
-char q3_dbrushsidetextured[Q3_MAX_MAP_BRUSHSIDES];
-
-extern qboolean forcesidesvisible;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q3_FreeMaxBSP(void)
-{
- if (q3_dmodels) FreeMemory(q3_dmodels);
- q3_dmodels = NULL;
- q3_nummodels = 0;
- if (q3_dshaders) FreeMemory(q3_dshaders);
- q3_dshaders = NULL;
- q3_numShaders = 0;
- if (q3_dentdata) FreeMemory(q3_dentdata);
- q3_dentdata = NULL;
- q3_entdatasize = 0;
- if (q3_dleafs) FreeMemory(q3_dleafs);
- q3_dleafs = NULL;
- q3_numleafs = 0;
- if (q3_dplanes) FreeMemory(q3_dplanes);
- q3_dplanes = NULL;
- q3_numplanes = 0;
- if (q3_dnodes) FreeMemory(q3_dnodes);
- q3_dnodes = NULL;
- q3_numnodes = 0;
- if (q3_dleafsurfaces) FreeMemory(q3_dleafsurfaces);
- q3_dleafsurfaces = NULL;
- q3_numleafsurfaces = 0;
- if (q3_dleafbrushes) FreeMemory(q3_dleafbrushes);
- q3_dleafbrushes = NULL;
- q3_numleafbrushes = 0;
- if (q3_dbrushes) FreeMemory(q3_dbrushes);
- q3_dbrushes = NULL;
- q3_numbrushes = 0;
- if (q3_dbrushsides) FreeMemory(q3_dbrushsides);
- q3_dbrushsides = NULL;
- q3_numbrushsides = 0;
- if (q3_lightBytes) FreeMemory(q3_lightBytes);
- q3_lightBytes = NULL;
- q3_numLightBytes = 0;
- if (q3_gridData) FreeMemory(q3_gridData);
- q3_gridData = NULL;
- q3_numGridPoints = 0;
- if (q3_visBytes) FreeMemory(q3_visBytes);
- q3_visBytes = NULL;
- q3_numVisBytes = 0;
- if (q3_drawVerts) FreeMemory(q3_drawVerts);
- q3_drawVerts = NULL;
- q3_numDrawVerts = 0;
- if (q3_drawIndexes) FreeMemory(q3_drawIndexes);
- q3_drawIndexes = NULL;
- q3_numDrawIndexes = 0;
- if (q3_drawSurfaces) FreeMemory(q3_drawSurfaces);
- q3_drawSurfaces = NULL;
- q3_numDrawSurfaces = 0;
- if (q3_dfogs) FreeMemory(q3_dfogs);
- q3_dfogs = NULL;
- q3_numFogs = 0;
-} //end of the function Q3_FreeMaxBSP
-
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q3_PlaneFromPoints(vec3_t p0, vec3_t p1, vec3_t p2, vec3_t normal, float *dist)
-{
- vec3_t t1, t2;
-
- VectorSubtract(p0, p1, t1);
- VectorSubtract(p2, p1, t2);
- CrossProduct(t1, t2, normal);
- VectorNormalize(normal);
-
- *dist = DotProduct(p0, normal);
-} //end of the function PlaneFromPoints
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q3_SurfacePlane(q3_dsurface_t *surface, vec3_t normal, float *dist)
-{
- int i;
- float *p0, *p1, *p2;
- vec3_t t1, t2;
-
- p0 = q3_drawVerts[surface->firstVert].xyz;
- for (i = 1; i < surface->numVerts-1; i++)
- {
- p1 = q3_drawVerts[surface->firstVert + ((i) % surface->numVerts)].xyz;
- p2 = q3_drawVerts[surface->firstVert + ((i+1) % surface->numVerts)].xyz;
- VectorSubtract(p0, p1, t1);
- VectorSubtract(p2, p1, t2);
- CrossProduct(t1, t2, normal);
- VectorNormalize(normal);
- if (VectorLength(normal)) break;
- } //end for*/
-/*
- float dot;
- for (i = 0; i < surface->numVerts; i++)
- {
- p0 = q3_drawVerts[surface->firstVert + ((i) % surface->numVerts)].xyz;
- p1 = q3_drawVerts[surface->firstVert + ((i+1) % surface->numVerts)].xyz;
- p2 = q3_drawVerts[surface->firstVert + ((i+2) % surface->numVerts)].xyz;
- VectorSubtract(p0, p1, t1);
- VectorSubtract(p2, p1, t2);
- VectorNormalize(t1);
- VectorNormalize(t2);
- dot = DotProduct(t1, t2);
- if (dot > -0.9 && dot < 0.9 &&
- VectorLength(t1) > 0.1 && VectorLength(t2) > 0.1) break;
- } //end for
- CrossProduct(t1, t2, normal);
- VectorNormalize(normal);
-*/
- if (VectorLength(normal) < 0.9)
- {
- printf("surface %d bogus normal vector %f %f %f\n", surface - q3_drawSurfaces, normal[0], normal[1], normal[2]);
- printf("t1 = %f %f %f, t2 = %f %f %f\n", t1[0], t1[1], t1[2], t2[0], t2[1], t2[2]);
- for (i = 0; i < surface->numVerts; i++)
- {
- p1 = q3_drawVerts[surface->firstVert + ((i) % surface->numVerts)].xyz;
- Log_Print("p%d = %f %f %f\n", i, p1[0], p1[1], p1[2]);
- } //end for
- } //end if
- *dist = DotProduct(p0, normal);
-} //end of the function Q3_SurfacePlane
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-q3_dplane_t *q3_surfaceplanes;
-
-void Q3_CreatePlanarSurfacePlanes(void)
-{
- int i;
- q3_dsurface_t *surface;
-
- Log_Print("creating planar surface planes...\n");
- q3_surfaceplanes = (q3_dplane_t *) GetClearedMemory(q3_numDrawSurfaces * sizeof(q3_dplane_t));
-
- for (i = 0; i < q3_numDrawSurfaces; i++)
- {
- surface = &q3_drawSurfaces[i];
- if (surface->surfaceType != MST_PLANAR) continue;
- Q3_SurfacePlane(surface, q3_surfaceplanes[i].normal, &q3_surfaceplanes[i].dist);
- //Log_Print("normal = %f %f %f, dist = %f\n", q3_surfaceplanes[i].normal[0],
- // q3_surfaceplanes[i].normal[1],
- // q3_surfaceplanes[i].normal[2], q3_surfaceplanes[i].dist);
- } //end for
-} //end of the function Q3_CreatePlanarSurfacePlanes
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-/*
-void Q3_SurfacePlane(q3_dsurface_t *surface, vec3_t normal, float *dist)
-{
- //take the plane information from the lightmap vector
- //VectorCopy(surface->lightmapVecs[2], normal);
- //calculate plane dist with first surface vertex
- //*dist = DotProduct(q3_drawVerts[surface->firstVert].xyz, normal);
- Q3_PlaneFromPoints(q3_drawVerts[surface->firstVert].xyz,
- q3_drawVerts[surface->firstVert+1].xyz,
- q3_drawVerts[surface->firstVert+2].xyz, normal, dist);
-} //end of the function Q3_SurfacePlane*/
-//===========================================================================
-// returns the amount the face and the winding overlap
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float Q3_FaceOnWinding(q3_dsurface_t *surface, winding_t *winding)
-{
- int i;
- float dist, area;
- q3_dplane_t plane;
- vec_t *v1, *v2;
- vec3_t normal, edgevec;
- winding_t *w;
-
- //copy the winding before chopping
- w = CopyWinding(winding);
- //retrieve the surface plane
- Q3_SurfacePlane(surface, plane.normal, &plane.dist);
- //chop the winding with the surface edge planes
- for (i = 0; i < surface->numVerts && w; i++)
- {
- v1 = q3_drawVerts[surface->firstVert + ((i) % surface->numVerts)].xyz;
- v2 = q3_drawVerts[surface->firstVert + ((i+1) % surface->numVerts)].xyz;
- //create a plane through the edge from v1 to v2, orthogonal to the
- //surface plane and with the normal vector pointing inward
- VectorSubtract(v2, v1, edgevec);
- CrossProduct(edgevec, plane.normal, normal);
- VectorNormalize(normal);
- dist = DotProduct(normal, v1);
- //
- ChopWindingInPlace(&w, normal, dist, -0.1); //CLIP_EPSILON
- } //end for
- if (w)
- {
- area = WindingArea(w);
- FreeWinding(w);
- return area;
- } //end if
- return 0;
-} //end of the function Q3_FaceOnWinding
-//===========================================================================
-// creates a winding for the given brush side on the given brush
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-winding_t *Q3_BrushSideWinding(q3_dbrush_t *brush, q3_dbrushside_t *baseside)
-{
- int i;
- q3_dplane_t *baseplane, *plane;
- winding_t *w;
- q3_dbrushside_t *side;
-
- //create a winding for the brush side with the given planenumber
- baseplane = &q3_dplanes[baseside->planeNum];
- w = BaseWindingForPlane(baseplane->normal, baseplane->dist);
- for (i = 0; i < brush->numSides && w; i++)
- {
- side = &q3_dbrushsides[brush->firstSide + i];
- //don't chop with the base plane
- if (side->planeNum == baseside->planeNum) continue;
- //also don't use planes that are almost equal
- plane = &q3_dplanes[side->planeNum];
- if (DotProduct(baseplane->normal, plane->normal) > 0.999
- && fabs(baseplane->dist - plane->dist) < 0.01) continue;
- //
- plane = &q3_dplanes[side->planeNum^1];
- ChopWindingInPlace(&w, plane->normal, plane->dist, -0.1); //CLIP_EPSILON);
- } //end for
- return w;
-} //end of the function Q3_BrushSideWinding
-//===========================================================================
-// fix screwed brush texture references
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean WindingIsTiny(winding_t *w);
-
-void Q3_FindVisibleBrushSides(void)
-{
- int i, j, k, we, numtextured, numsides;
- float dot;
- q3_dplane_t *plane;
- q3_dbrushside_t *brushside;
- q3_dbrush_t *brush;
- q3_dsurface_t *surface;
- winding_t *w;
-
- memset(q3_dbrushsidetextured, false, Q3_MAX_MAP_BRUSHSIDES);
- //
- numsides = 0;
- //create planes for the planar surfaces
- Q3_CreatePlanarSurfacePlanes();
- Log_Print("searching visible brush sides...\n");
- Log_Print("%6d brush sides", numsides);
- //go over all the brushes
- for (i = 0; i < q3_numbrushes; i++)
- {
- brush = &q3_dbrushes[i];
- //go over all the sides of the brush
- for (j = 0; j < brush->numSides; j++)
- {
- qprintf("\r%6d", numsides++);
- brushside = &q3_dbrushsides[brush->firstSide + j];
- //
- w = Q3_BrushSideWinding(brush, brushside);
- if (!w)
- {
- q3_dbrushsidetextured[brush->firstSide + j] = true;
- continue;
- } //end if
- else
- {
- //RemoveEqualPoints(w, 0.2);
- if (WindingIsTiny(w))
- {
- FreeWinding(w);
- q3_dbrushsidetextured[brush->firstSide + j] = true;
- continue;
- } //end if
- else
- {
- we = WindingError(w);
- if (we == WE_NOTENOUGHPOINTS
- || we == WE_SMALLAREA
- || we == WE_POINTBOGUSRANGE
-// || we == WE_NONCONVEX
- )
- {
- FreeWinding(w);
- q3_dbrushsidetextured[brush->firstSide + j] = true;
- continue;
- } //end if
- } //end else
- } //end else
- if (WindingArea(w) < 20)
- {
- q3_dbrushsidetextured[brush->firstSide + j] = true;
- continue;
- } //end if
- //find a face for texturing this brush
- for (k = 0; k < q3_numDrawSurfaces; k++)
- {
- surface = &q3_drawSurfaces[k];
- if (surface->surfaceType != MST_PLANAR) continue;
- //
- //Q3_SurfacePlane(surface, plane.normal, &plane.dist);
- plane = &q3_surfaceplanes[k];
- //the surface plane and the brush side plane should be pretty much the same
- if (fabs(fabs(plane->dist) - fabs(q3_dplanes[brushside->planeNum].dist)) > 5) continue;
- dot = DotProduct(plane->normal, q3_dplanes[brushside->planeNum].normal);
- if (dot > -0.9 && dot < 0.9) continue;
- //if the face is partly or totally on the brush side
- if (Q3_FaceOnWinding(surface, w))
- {
- q3_dbrushsidetextured[brush->firstSide + j] = true;
- //Log_Write("Q3_FaceOnWinding");
- break;
- } //end if
- } //end for
- FreeWinding(w);
- } //end for
- } //end for
- qprintf("\r%6d brush sides\n", numsides);
- numtextured = 0;
- for (i = 0; i < q3_numbrushsides; i++)
- {
- if (forcesidesvisible) q3_dbrushsidetextured[i] = true;
- if (q3_dbrushsidetextured[i]) numtextured++;
- } //end for
- Log_Print("%d brush sides textured out of %d\n", numtextured, q3_numbrushsides);
-} //end of the function Q3_FindVisibleBrushSides
-
-/*
-=============
-Q3_SwapBlock
-
-If all values are 32 bits, this can be used to swap everything
-=============
-*/
-void Q3_SwapBlock( int *block, int sizeOfBlock ) {
- int i;
-
- sizeOfBlock >>= 2;
- for ( i = 0 ; i < sizeOfBlock ; i++ ) {
- block[i] = LittleLong( block[i] );
- }
-} //end of the function Q3_SwapBlock
-
-/*
-=============
-Q3_SwapBSPFile
-
-Byte swaps all data in a bsp file.
-=============
-*/
-void Q3_SwapBSPFile( void ) {
- int i;
-
- // models
- Q3_SwapBlock( (int *)q3_dmodels, q3_nummodels * sizeof( q3_dmodels[0] ) );
-
- // shaders (don't swap the name)
- for ( i = 0 ; i < q3_numShaders ; i++ ) {
- q3_dshaders[i].contentFlags = LittleLong( q3_dshaders[i].contentFlags );
- q3_dshaders[i].surfaceFlags = LittleLong( q3_dshaders[i].surfaceFlags );
- }
-
- // planes
- Q3_SwapBlock( (int *)q3_dplanes, q3_numplanes * sizeof( q3_dplanes[0] ) );
-
- // nodes
- Q3_SwapBlock( (int *)q3_dnodes, q3_numnodes * sizeof( q3_dnodes[0] ) );
-
- // leafs
- Q3_SwapBlock( (int *)q3_dleafs, q3_numleafs * sizeof( q3_dleafs[0] ) );
-
- // leaffaces
- Q3_SwapBlock( (int *)q3_dleafsurfaces, q3_numleafsurfaces * sizeof( q3_dleafsurfaces[0] ) );
-
- // leafbrushes
- Q3_SwapBlock( (int *)q3_dleafbrushes, q3_numleafbrushes * sizeof( q3_dleafbrushes[0] ) );
-
- // brushes
- Q3_SwapBlock( (int *)q3_dbrushes, q3_numbrushes * sizeof( q3_dbrushes[0] ) );
-
- // brushsides
- Q3_SwapBlock( (int *)q3_dbrushsides, q3_numbrushsides * sizeof( q3_dbrushsides[0] ) );
-
- // vis
- ((int *)&q3_visBytes)[0] = LittleLong( ((int *)&q3_visBytes)[0] );
- ((int *)&q3_visBytes)[1] = LittleLong( ((int *)&q3_visBytes)[1] );
-
- // drawverts (don't swap colors )
- for ( i = 0 ; i < q3_numDrawVerts ; i++ ) {
- q3_drawVerts[i].lightmap[0] = LittleFloat( q3_drawVerts[i].lightmap[0] );
- q3_drawVerts[i].lightmap[1] = LittleFloat( q3_drawVerts[i].lightmap[1] );
- q3_drawVerts[i].st[0] = LittleFloat( q3_drawVerts[i].st[0] );
- q3_drawVerts[i].st[1] = LittleFloat( q3_drawVerts[i].st[1] );
- q3_drawVerts[i].xyz[0] = LittleFloat( q3_drawVerts[i].xyz[0] );
- q3_drawVerts[i].xyz[1] = LittleFloat( q3_drawVerts[i].xyz[1] );
- q3_drawVerts[i].xyz[2] = LittleFloat( q3_drawVerts[i].xyz[2] );
- q3_drawVerts[i].normal[0] = LittleFloat( q3_drawVerts[i].normal[0] );
- q3_drawVerts[i].normal[1] = LittleFloat( q3_drawVerts[i].normal[1] );
- q3_drawVerts[i].normal[2] = LittleFloat( q3_drawVerts[i].normal[2] );
- }
-
- // drawindexes
- Q3_SwapBlock( (int *)q3_drawIndexes, q3_numDrawIndexes * sizeof( q3_drawIndexes[0] ) );
-
- // drawsurfs
- Q3_SwapBlock( (int *)q3_drawSurfaces, q3_numDrawSurfaces * sizeof( q3_drawSurfaces[0] ) );
-
- // fogs
- for ( i = 0 ; i < q3_numFogs ; i++ ) {
- q3_dfogs[i].brushNum = LittleLong( q3_dfogs[i].brushNum );
- }
-}
-
-
-
-/*
-=============
-Q3_CopyLump
-=============
-*/
-int Q3_CopyLump( q3_dheader_t *header, int lump, void **dest, int size ) {
- int length, ofs;
-
- length = header->lumps[lump].filelen;
- ofs = header->lumps[lump].fileofs;
-
- if ( length % size ) {
- Error ("Q3_LoadBSPFile: odd lump size");
- }
-
- *dest = GetMemory(length);
-
- memcpy( *dest, (byte *)header + ofs, length );
-
- return length / size;
-}
-
-/*
-=============
-CountTriangles
-=============
-*/
-void CountTriangles( void ) {
- int i, numTris, numPatchTris;
- q3_dsurface_t *surface;
-
- numTris = numPatchTris = 0;
- for ( i = 0; i < q3_numDrawSurfaces; i++ ) {
- surface = &q3_drawSurfaces[i];
-
- numTris += surface->numIndexes / 3;
-
- if ( surface->patchWidth ) {
- numPatchTris += surface->patchWidth * surface->patchHeight * 2;
- }
- }
-
- Log_Print( "%6d triangles\n", numTris );
- Log_Print( "%6d patch tris\n", numPatchTris );
-}
-
-/*
-=============
-Q3_LoadBSPFile
-=============
-*/
-void Q3_LoadBSPFile(struct quakefile_s *qf)
-{
- q3_dheader_t *header;
-
- // load the file header
- //LoadFile(filename, (void **)&header, offset, length);
- //
- LoadQuakeFile(qf, (void **)&header);
-
- // swap the header
- Q3_SwapBlock( (int *)header, sizeof(*header) );
-
- if ( header->ident != Q3_BSP_IDENT ) {
- Error( "%s is not a IBSP file", qf->filename );
- }
- if ( header->version != Q3_BSP_VERSION ) {
- Error( "%s is version %i, not %i", qf->filename, header->version, Q3_BSP_VERSION );
- }
-
- q3_numShaders = Q3_CopyLump( header, Q3_LUMP_SHADERS, (void *) &q3_dshaders, sizeof(q3_dshader_t) );
- q3_nummodels = Q3_CopyLump( header, Q3_LUMP_MODELS, (void *) &q3_dmodels, sizeof(q3_dmodel_t) );
- q3_numplanes = Q3_CopyLump( header, Q3_LUMP_PLANES, (void *) &q3_dplanes, sizeof(q3_dplane_t) );
- q3_numleafs = Q3_CopyLump( header, Q3_LUMP_LEAFS, (void *) &q3_dleafs, sizeof(q3_dleaf_t) );
- q3_numnodes = Q3_CopyLump( header, Q3_LUMP_NODES, (void *) &q3_dnodes, sizeof(q3_dnode_t) );
- q3_numleafsurfaces = Q3_CopyLump( header, Q3_LUMP_LEAFSURFACES, (void *) &q3_dleafsurfaces, sizeof(q3_dleafsurfaces[0]) );
- q3_numleafbrushes = Q3_CopyLump( header, Q3_LUMP_LEAFBRUSHES, (void *) &q3_dleafbrushes, sizeof(q3_dleafbrushes[0]) );
- q3_numbrushes = Q3_CopyLump( header, Q3_LUMP_BRUSHES, (void *) &q3_dbrushes, sizeof(q3_dbrush_t) );
- q3_numbrushsides = Q3_CopyLump( header, Q3_LUMP_BRUSHSIDES, (void *) &q3_dbrushsides, sizeof(q3_dbrushside_t) );
- q3_numDrawVerts = Q3_CopyLump( header, Q3_LUMP_DRAWVERTS, (void *) &q3_drawVerts, sizeof(q3_drawVert_t) );
- q3_numDrawSurfaces = Q3_CopyLump( header, Q3_LUMP_SURFACES, (void *) &q3_drawSurfaces, sizeof(q3_dsurface_t) );
- q3_numFogs = Q3_CopyLump( header, Q3_LUMP_FOGS, (void *) &q3_dfogs, sizeof(q3_dfog_t) );
- q3_numDrawIndexes = Q3_CopyLump( header, Q3_LUMP_DRAWINDEXES, (void *) &q3_drawIndexes, sizeof(q3_drawIndexes[0]) );
-
- q3_numVisBytes = Q3_CopyLump( header, Q3_LUMP_VISIBILITY, (void *) &q3_visBytes, 1 );
- q3_numLightBytes = Q3_CopyLump( header, Q3_LUMP_LIGHTMAPS, (void *) &q3_lightBytes, 1 );
- q3_entdatasize = Q3_CopyLump( header, Q3_LUMP_ENTITIES, (void *) &q3_dentdata, 1);
-
- q3_numGridPoints = Q3_CopyLump( header, Q3_LUMP_LIGHTGRID, (void *) &q3_gridData, 8 );
-
- CountTriangles();
-
- FreeMemory( header ); // everything has been copied out
-
- // swap everything
- Q3_SwapBSPFile();
-
- Q3_FindVisibleBrushSides();
-
- //Q3_PrintBSPFileSizes();
-}
-
-
-//============================================================================
-
-/*
-=============
-Q3_AddLump
-=============
-*/
-void Q3_AddLump( FILE *bspfile, q3_dheader_t *header, int lumpnum, void *data, int len ) {
- q3_lump_t *lump;
-
- lump = &header->lumps[lumpnum];
-
- lump->fileofs = LittleLong( ftell(bspfile) );
- lump->filelen = LittleLong( len );
- SafeWrite( bspfile, data, (len+3)&~3 );
-}
-
-/*
-=============
-Q3_WriteBSPFile
-
-Swaps the bsp file in place, so it should not be referenced again
-=============
-*/
-void Q3_WriteBSPFile( char *filename )
-{
- q3_dheader_t outheader, *header;
- FILE *bspfile;
-
- header = &outheader;
- memset( header, 0, sizeof(q3_dheader_t) );
-
- Q3_SwapBSPFile();
-
- header->ident = LittleLong( Q3_BSP_IDENT );
- header->version = LittleLong( Q3_BSP_VERSION );
-
- bspfile = SafeOpenWrite( filename );
- SafeWrite( bspfile, header, sizeof(q3_dheader_t) ); // overwritten later
-
- Q3_AddLump( bspfile, header, Q3_LUMP_SHADERS, q3_dshaders, q3_numShaders*sizeof(q3_dshader_t) );
- Q3_AddLump( bspfile, header, Q3_LUMP_PLANES, q3_dplanes, q3_numplanes*sizeof(q3_dplane_t) );
- Q3_AddLump( bspfile, header, Q3_LUMP_LEAFS, q3_dleafs, q3_numleafs*sizeof(q3_dleaf_t) );
- Q3_AddLump( bspfile, header, Q3_LUMP_NODES, q3_dnodes, q3_numnodes*sizeof(q3_dnode_t) );
- Q3_AddLump( bspfile, header, Q3_LUMP_BRUSHES, q3_dbrushes, q3_numbrushes*sizeof(q3_dbrush_t) );
- Q3_AddLump( bspfile, header, Q3_LUMP_BRUSHSIDES, q3_dbrushsides, q3_numbrushsides*sizeof(q3_dbrushside_t) );
- Q3_AddLump( bspfile, header, Q3_LUMP_LEAFSURFACES, q3_dleafsurfaces, q3_numleafsurfaces*sizeof(q3_dleafsurfaces[0]) );
- Q3_AddLump( bspfile, header, Q3_LUMP_LEAFBRUSHES, q3_dleafbrushes, q3_numleafbrushes*sizeof(q3_dleafbrushes[0]) );
- Q3_AddLump( bspfile, header, Q3_LUMP_MODELS, q3_dmodels, q3_nummodels*sizeof(q3_dmodel_t) );
- Q3_AddLump( bspfile, header, Q3_LUMP_DRAWVERTS, q3_drawVerts, q3_numDrawVerts*sizeof(q3_drawVert_t) );
- Q3_AddLump( bspfile, header, Q3_LUMP_SURFACES, q3_drawSurfaces, q3_numDrawSurfaces*sizeof(q3_dsurface_t) );
- Q3_AddLump( bspfile, header, Q3_LUMP_VISIBILITY, q3_visBytes, q3_numVisBytes );
- Q3_AddLump( bspfile, header, Q3_LUMP_LIGHTMAPS, q3_lightBytes, q3_numLightBytes );
- Q3_AddLump( bspfile, header, Q3_LUMP_LIGHTGRID, q3_gridData, 8 * q3_numGridPoints );
- Q3_AddLump( bspfile, header, Q3_LUMP_ENTITIES, q3_dentdata, q3_entdatasize );
- Q3_AddLump( bspfile, header, Q3_LUMP_FOGS, q3_dfogs, q3_numFogs * sizeof(q3_dfog_t) );
- Q3_AddLump( bspfile, header, Q3_LUMP_DRAWINDEXES, q3_drawIndexes, q3_numDrawIndexes * sizeof(q3_drawIndexes[0]) );
-
- fseek (bspfile, 0, SEEK_SET);
- SafeWrite (bspfile, header, sizeof(q3_dheader_t));
- fclose (bspfile);
-}
-
-//============================================================================
-
-/*
-=============
-Q3_PrintBSPFileSizes
-
-Dumps info about current file
-=============
-*/
-void Q3_PrintBSPFileSizes( void )
-{
- if ( !num_entities )
- {
- Q3_ParseEntities();
- }
-
- Log_Print ("%6i models %7i\n"
- ,q3_nummodels, (int)(q3_nummodels*sizeof(q3_dmodel_t)));
- Log_Print ("%6i shaders %7i\n"
- ,q3_numShaders, (int)(q3_numShaders*sizeof(q3_dshader_t)));
- Log_Print ("%6i brushes %7i\n"
- ,q3_numbrushes, (int)(q3_numbrushes*sizeof(q3_dbrush_t)));
- Log_Print ("%6i brushsides %7i\n"
- ,q3_numbrushsides, (int)(q3_numbrushsides*sizeof(q3_dbrushside_t)));
- Log_Print ("%6i fogs %7i\n"
- ,q3_numFogs, (int)(q3_numFogs*sizeof(q3_dfog_t)));
- Log_Print ("%6i planes %7i\n"
- ,q3_numplanes, (int)(q3_numplanes*sizeof(q3_dplane_t)));
- Log_Print ("%6i entdata %7i\n", num_entities, q3_entdatasize);
-
- Log_Print ("\n");
-
- Log_Print ("%6i nodes %7i\n"
- ,q3_numnodes, (int)(q3_numnodes*sizeof(q3_dnode_t)));
- Log_Print ("%6i leafs %7i\n"
- ,q3_numleafs, (int)(q3_numleafs*sizeof(q3_dleaf_t)));
- Log_Print ("%6i leafsurfaces %7i\n"
- ,q3_numleafsurfaces, (int)(q3_numleafsurfaces*sizeof(q3_dleafsurfaces[0])));
- Log_Print ("%6i leafbrushes %7i\n"
- ,q3_numleafbrushes, (int)(q3_numleafbrushes*sizeof(q3_dleafbrushes[0])));
- Log_Print ("%6i drawverts %7i\n"
- ,q3_numDrawVerts, (int)(q3_numDrawVerts*sizeof(q3_drawVerts[0])));
- Log_Print ("%6i drawindexes %7i\n"
- ,q3_numDrawIndexes, (int)(q3_numDrawIndexes*sizeof(q3_drawIndexes[0])));
- Log_Print ("%6i drawsurfaces %7i\n"
- ,q3_numDrawSurfaces, (int)(q3_numDrawSurfaces*sizeof(q3_drawSurfaces[0])));
-
- Log_Print ("%6i lightmaps %7i\n"
- ,q3_numLightBytes / (LIGHTMAP_WIDTH*LIGHTMAP_HEIGHT*3), q3_numLightBytes );
- Log_Print (" visibility %7i\n"
- , q3_numVisBytes );
-}
-
-/*
-================
-Q3_ParseEntities
-
-Parses the q3_dentdata string into entities
-================
-*/
-void Q3_ParseEntities (void)
-{
- script_t *script;
-
- num_entities = 0;
- script = LoadScriptMemory(q3_dentdata, q3_entdatasize, "*Quake3 bsp file");
- SetScriptFlags(script, SCFL_NOSTRINGWHITESPACES |
- SCFL_NOSTRINGESCAPECHARS);
-
- while(ParseEntity(script))
- {
- } //end while
-
- FreeScript(script);
-} //end of the function Q3_ParseEntities
-
-
-/*
-================
-Q3_UnparseEntities
-
-Generates the q3_dentdata string from all the entities
-================
-*/
-void Q3_UnparseEntities (void)
-{
- char *buf, *end;
- epair_t *ep;
- char line[2048];
- int i;
-
- buf = q3_dentdata;
- end = buf;
- *end = 0;
-
- for (i=0 ; i<num_entities ; i++)
- {
- ep = entities[i].epairs;
- if (!ep)
- continue; // ent got removed
-
- strcat (end,"{\n");
- end += 2;
-
- for (ep = entities[i].epairs ; ep ; ep=ep->next)
- {
- sprintf (line, "\"%s\" \"%s\"\n", ep->key, ep->value);
- strcat (end, line);
- end += strlen(line);
- }
- strcat (end,"}\n");
- end += 2;
-
- if (end > buf + Q3_MAX_MAP_ENTSTRING)
- Error ("Entity text too long");
- }
- q3_entdatasize = end - buf + 1;
-} //end of the function Q3_UnparseEntities
-
-
+/*
+===========================================================================
+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 "l_cmd.h"
+#include "l_math.h"
+#include "l_mem.h"
+#include "l_log.h"
+#include "l_poly.h"
+#include "../botlib/l_script.h"
+#include "l_qfiles.h"
+#include "l_bsp_q3.h"
+#include "l_bsp_ent.h"
+
+void Q3_ParseEntities (void);
+void Q3_PrintBSPFileSizes(void);
+
+void GetLeafNums (void);
+
+//=============================================================================
+
+#define WCONVEX_EPSILON 0.5
+
+
+int q3_nummodels;
+q3_dmodel_t *q3_dmodels;//[MAX_MAP_MODELS];
+
+int q3_numShaders;
+q3_dshader_t *q3_dshaders;//[Q3_MAX_MAP_SHADERS];
+
+int q3_entdatasize;
+char *q3_dentdata;//[Q3_MAX_MAP_ENTSTRING];
+
+int q3_numleafs;
+q3_dleaf_t *q3_dleafs;//[Q3_MAX_MAP_LEAFS];
+
+int q3_numplanes;
+q3_dplane_t *q3_dplanes;//[Q3_MAX_MAP_PLANES];
+
+int q3_numnodes;
+q3_dnode_t *q3_dnodes;//[Q3_MAX_MAP_NODES];
+
+int q3_numleafsurfaces;
+int *q3_dleafsurfaces;//[Q3_MAX_MAP_LEAFFACES];
+
+int q3_numleafbrushes;
+int *q3_dleafbrushes;//[Q3_MAX_MAP_LEAFBRUSHES];
+
+int q3_numbrushes;
+q3_dbrush_t *q3_dbrushes;//[Q3_MAX_MAP_BRUSHES];
+
+int q3_numbrushsides;
+q3_dbrushside_t *q3_dbrushsides;//[Q3_MAX_MAP_BRUSHSIDES];
+
+int q3_numLightBytes;
+byte *q3_lightBytes;//[Q3_MAX_MAP_LIGHTING];
+
+int q3_numGridPoints;
+byte *q3_gridData;//[Q3_MAX_MAP_LIGHTGRID];
+
+int q3_numVisBytes;
+byte *q3_visBytes;//[Q3_MAX_MAP_VISIBILITY];
+
+int q3_numDrawVerts;
+q3_drawVert_t *q3_drawVerts;//[Q3_MAX_MAP_DRAW_VERTS];
+
+int q3_numDrawIndexes;
+int *q3_drawIndexes;//[Q3_MAX_MAP_DRAW_INDEXES];
+
+int q3_numDrawSurfaces;
+q3_dsurface_t *q3_drawSurfaces;//[Q3_MAX_MAP_DRAW_SURFS];
+
+int q3_numFogs;
+q3_dfog_t *q3_dfogs;//[Q3_MAX_MAP_FOGS];
+
+char q3_dbrushsidetextured[Q3_MAX_MAP_BRUSHSIDES];
+
+extern qboolean forcesidesvisible;
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q3_FreeMaxBSP(void)
+{
+ if (q3_dmodels) FreeMemory(q3_dmodels);
+ q3_dmodels = NULL;
+ q3_nummodels = 0;
+ if (q3_dshaders) FreeMemory(q3_dshaders);
+ q3_dshaders = NULL;
+ q3_numShaders = 0;
+ if (q3_dentdata) FreeMemory(q3_dentdata);
+ q3_dentdata = NULL;
+ q3_entdatasize = 0;
+ if (q3_dleafs) FreeMemory(q3_dleafs);
+ q3_dleafs = NULL;
+ q3_numleafs = 0;
+ if (q3_dplanes) FreeMemory(q3_dplanes);
+ q3_dplanes = NULL;
+ q3_numplanes = 0;
+ if (q3_dnodes) FreeMemory(q3_dnodes);
+ q3_dnodes = NULL;
+ q3_numnodes = 0;
+ if (q3_dleafsurfaces) FreeMemory(q3_dleafsurfaces);
+ q3_dleafsurfaces = NULL;
+ q3_numleafsurfaces = 0;
+ if (q3_dleafbrushes) FreeMemory(q3_dleafbrushes);
+ q3_dleafbrushes = NULL;
+ q3_numleafbrushes = 0;
+ if (q3_dbrushes) FreeMemory(q3_dbrushes);
+ q3_dbrushes = NULL;
+ q3_numbrushes = 0;
+ if (q3_dbrushsides) FreeMemory(q3_dbrushsides);
+ q3_dbrushsides = NULL;
+ q3_numbrushsides = 0;
+ if (q3_lightBytes) FreeMemory(q3_lightBytes);
+ q3_lightBytes = NULL;
+ q3_numLightBytes = 0;
+ if (q3_gridData) FreeMemory(q3_gridData);
+ q3_gridData = NULL;
+ q3_numGridPoints = 0;
+ if (q3_visBytes) FreeMemory(q3_visBytes);
+ q3_visBytes = NULL;
+ q3_numVisBytes = 0;
+ if (q3_drawVerts) FreeMemory(q3_drawVerts);
+ q3_drawVerts = NULL;
+ q3_numDrawVerts = 0;
+ if (q3_drawIndexes) FreeMemory(q3_drawIndexes);
+ q3_drawIndexes = NULL;
+ q3_numDrawIndexes = 0;
+ if (q3_drawSurfaces) FreeMemory(q3_drawSurfaces);
+ q3_drawSurfaces = NULL;
+ q3_numDrawSurfaces = 0;
+ if (q3_dfogs) FreeMemory(q3_dfogs);
+ q3_dfogs = NULL;
+ q3_numFogs = 0;
+} //end of the function Q3_FreeMaxBSP
+
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q3_PlaneFromPoints(vec3_t p0, vec3_t p1, vec3_t p2, vec3_t normal, float *dist)
+{
+ vec3_t t1, t2;
+
+ VectorSubtract(p0, p1, t1);
+ VectorSubtract(p2, p1, t2);
+ CrossProduct(t1, t2, normal);
+ VectorNormalize(normal);
+
+ *dist = DotProduct(p0, normal);
+} //end of the function PlaneFromPoints
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q3_SurfacePlane(q3_dsurface_t *surface, vec3_t normal, float *dist)
+{
+ int i;
+ float *p0, *p1, *p2;
+ vec3_t t1, t2;
+
+ p0 = q3_drawVerts[surface->firstVert].xyz;
+ for (i = 1; i < surface->numVerts-1; i++)
+ {
+ p1 = q3_drawVerts[surface->firstVert + ((i) % surface->numVerts)].xyz;
+ p2 = q3_drawVerts[surface->firstVert + ((i+1) % surface->numVerts)].xyz;
+ VectorSubtract(p0, p1, t1);
+ VectorSubtract(p2, p1, t2);
+ CrossProduct(t1, t2, normal);
+ VectorNormalize(normal);
+ if (VectorLength(normal)) break;
+ } //end for*/
+/*
+ float dot;
+ for (i = 0; i < surface->numVerts; i++)
+ {
+ p0 = q3_drawVerts[surface->firstVert + ((i) % surface->numVerts)].xyz;
+ p1 = q3_drawVerts[surface->firstVert + ((i+1) % surface->numVerts)].xyz;
+ p2 = q3_drawVerts[surface->firstVert + ((i+2) % surface->numVerts)].xyz;
+ VectorSubtract(p0, p1, t1);
+ VectorSubtract(p2, p1, t2);
+ VectorNormalize(t1);
+ VectorNormalize(t2);
+ dot = DotProduct(t1, t2);
+ if (dot > -0.9 && dot < 0.9 &&
+ VectorLength(t1) > 0.1 && VectorLength(t2) > 0.1) break;
+ } //end for
+ CrossProduct(t1, t2, normal);
+ VectorNormalize(normal);
+*/
+ if (VectorLength(normal) < 0.9)
+ {
+ printf("surface %d bogus normal vector %f %f %f\n", surface - q3_drawSurfaces, normal[0], normal[1], normal[2]);
+ printf("t1 = %f %f %f, t2 = %f %f %f\n", t1[0], t1[1], t1[2], t2[0], t2[1], t2[2]);
+ for (i = 0; i < surface->numVerts; i++)
+ {
+ p1 = q3_drawVerts[surface->firstVert + ((i) % surface->numVerts)].xyz;
+ Log_Print("p%d = %f %f %f\n", i, p1[0], p1[1], p1[2]);
+ } //end for
+ } //end if
+ *dist = DotProduct(p0, normal);
+} //end of the function Q3_SurfacePlane
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+q3_dplane_t *q3_surfaceplanes;
+
+void Q3_CreatePlanarSurfacePlanes(void)
+{
+ int i;
+ q3_dsurface_t *surface;
+
+ Log_Print("creating planar surface planes...\n");
+ q3_surfaceplanes = (q3_dplane_t *) GetClearedMemory(q3_numDrawSurfaces * sizeof(q3_dplane_t));
+
+ for (i = 0; i < q3_numDrawSurfaces; i++)
+ {
+ surface = &q3_drawSurfaces[i];
+ if (surface->surfaceType != MST_PLANAR) continue;
+ Q3_SurfacePlane(surface, q3_surfaceplanes[i].normal, &q3_surfaceplanes[i].dist);
+ //Log_Print("normal = %f %f %f, dist = %f\n", q3_surfaceplanes[i].normal[0],
+ // q3_surfaceplanes[i].normal[1],
+ // q3_surfaceplanes[i].normal[2], q3_surfaceplanes[i].dist);
+ } //end for
+} //end of the function Q3_CreatePlanarSurfacePlanes
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+/*
+void Q3_SurfacePlane(q3_dsurface_t *surface, vec3_t normal, float *dist)
+{
+ //take the plane information from the lightmap vector
+ //VectorCopy(surface->lightmapVecs[2], normal);
+ //calculate plane dist with first surface vertex
+ //*dist = DotProduct(q3_drawVerts[surface->firstVert].xyz, normal);
+ Q3_PlaneFromPoints(q3_drawVerts[surface->firstVert].xyz,
+ q3_drawVerts[surface->firstVert+1].xyz,
+ q3_drawVerts[surface->firstVert+2].xyz, normal, dist);
+} //end of the function Q3_SurfacePlane*/
+//===========================================================================
+// returns the amount the face and the winding overlap
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+float Q3_FaceOnWinding(q3_dsurface_t *surface, winding_t *winding)
+{
+ int i;
+ float dist, area;
+ q3_dplane_t plane;
+ vec_t *v1, *v2;
+ vec3_t normal, edgevec;
+ winding_t *w;
+
+ //copy the winding before chopping
+ w = CopyWinding(winding);
+ //retrieve the surface plane
+ Q3_SurfacePlane(surface, plane.normal, &plane.dist);
+ //chop the winding with the surface edge planes
+ for (i = 0; i < surface->numVerts && w; i++)
+ {
+ v1 = q3_drawVerts[surface->firstVert + ((i) % surface->numVerts)].xyz;
+ v2 = q3_drawVerts[surface->firstVert + ((i+1) % surface->numVerts)].xyz;
+ //create a plane through the edge from v1 to v2, orthogonal to the
+ //surface plane and with the normal vector pointing inward
+ VectorSubtract(v2, v1, edgevec);
+ CrossProduct(edgevec, plane.normal, normal);
+ VectorNormalize(normal);
+ dist = DotProduct(normal, v1);
+ //
+ ChopWindingInPlace(&w, normal, dist, -0.1); //CLIP_EPSILON
+ } //end for
+ if (w)
+ {
+ area = WindingArea(w);
+ FreeWinding(w);
+ return area;
+ } //end if
+ return 0;
+} //end of the function Q3_FaceOnWinding
+//===========================================================================
+// creates a winding for the given brush side on the given brush
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+winding_t *Q3_BrushSideWinding(q3_dbrush_t *brush, q3_dbrushside_t *baseside)
+{
+ int i;
+ q3_dplane_t *baseplane, *plane;
+ winding_t *w;
+ q3_dbrushside_t *side;
+
+ //create a winding for the brush side with the given planenumber
+ baseplane = &q3_dplanes[baseside->planeNum];
+ w = BaseWindingForPlane(baseplane->normal, baseplane->dist);
+ for (i = 0; i < brush->numSides && w; i++)
+ {
+ side = &q3_dbrushsides[brush->firstSide + i];
+ //don't chop with the base plane
+ if (side->planeNum == baseside->planeNum) continue;
+ //also don't use planes that are almost equal
+ plane = &q3_dplanes[side->planeNum];
+ if (DotProduct(baseplane->normal, plane->normal) > 0.999
+ && fabs(baseplane->dist - plane->dist) < 0.01) continue;
+ //
+ plane = &q3_dplanes[side->planeNum^1];
+ ChopWindingInPlace(&w, plane->normal, plane->dist, -0.1); //CLIP_EPSILON);
+ } //end for
+ return w;
+} //end of the function Q3_BrushSideWinding
+//===========================================================================
+// fix screwed brush texture references
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+qboolean WindingIsTiny(winding_t *w);
+
+void Q3_FindVisibleBrushSides(void)
+{
+ int i, j, k, we, numtextured, numsides;
+ float dot;
+ q3_dplane_t *plane;
+ q3_dbrushside_t *brushside;
+ q3_dbrush_t *brush;
+ q3_dsurface_t *surface;
+ winding_t *w;
+
+ memset(q3_dbrushsidetextured, false, Q3_MAX_MAP_BRUSHSIDES);
+ //
+ numsides = 0;
+ //create planes for the planar surfaces
+ Q3_CreatePlanarSurfacePlanes();
+ Log_Print("searching visible brush sides...\n");
+ Log_Print("%6d brush sides", numsides);
+ //go over all the brushes
+ for (i = 0; i < q3_numbrushes; i++)
+ {
+ brush = &q3_dbrushes[i];
+ //go over all the sides of the brush
+ for (j = 0; j < brush->numSides; j++)
+ {
+ qprintf("\r%6d", numsides++);
+ brushside = &q3_dbrushsides[brush->firstSide + j];
+ //
+ w = Q3_BrushSideWinding(brush, brushside);
+ if (!w)
+ {
+ q3_dbrushsidetextured[brush->firstSide + j] = true;
+ continue;
+ } //end if
+ else
+ {
+ //RemoveEqualPoints(w, 0.2);
+ if (WindingIsTiny(w))
+ {
+ FreeWinding(w);
+ q3_dbrushsidetextured[brush->firstSide + j] = true;
+ continue;
+ } //end if
+ else
+ {
+ we = WindingError(w);
+ if (we == WE_NOTENOUGHPOINTS
+ || we == WE_SMALLAREA
+ || we == WE_POINTBOGUSRANGE
+// || we == WE_NONCONVEX
+ )
+ {
+ FreeWinding(w);
+ q3_dbrushsidetextured[brush->firstSide + j] = true;
+ continue;
+ } //end if
+ } //end else
+ } //end else
+ if (WindingArea(w) < 20)
+ {
+ q3_dbrushsidetextured[brush->firstSide + j] = true;
+ continue;
+ } //end if
+ //find a face for texturing this brush
+ for (k = 0; k < q3_numDrawSurfaces; k++)
+ {
+ surface = &q3_drawSurfaces[k];
+ if (surface->surfaceType != MST_PLANAR) continue;
+ //
+ //Q3_SurfacePlane(surface, plane.normal, &plane.dist);
+ plane = &q3_surfaceplanes[k];
+ //the surface plane and the brush side plane should be pretty much the same
+ if (fabs(fabs(plane->dist) - fabs(q3_dplanes[brushside->planeNum].dist)) > 5) continue;
+ dot = DotProduct(plane->normal, q3_dplanes[brushside->planeNum].normal);
+ if (dot > -0.9 && dot < 0.9) continue;
+ //if the face is partly or totally on the brush side
+ if (Q3_FaceOnWinding(surface, w))
+ {
+ q3_dbrushsidetextured[brush->firstSide + j] = true;
+ //Log_Write("Q3_FaceOnWinding");
+ break;
+ } //end if
+ } //end for
+ FreeWinding(w);
+ } //end for
+ } //end for
+ qprintf("\r%6d brush sides\n", numsides);
+ numtextured = 0;
+ for (i = 0; i < q3_numbrushsides; i++)
+ {
+ if (forcesidesvisible) q3_dbrushsidetextured[i] = true;
+ if (q3_dbrushsidetextured[i]) numtextured++;
+ } //end for
+ Log_Print("%d brush sides textured out of %d\n", numtextured, q3_numbrushsides);
+} //end of the function Q3_FindVisibleBrushSides
+
+/*
+=============
+Q3_SwapBlock
+
+If all values are 32 bits, this can be used to swap everything
+=============
+*/
+void Q3_SwapBlock( int *block, int sizeOfBlock ) {
+ int i;
+
+ sizeOfBlock >>= 2;
+ for ( i = 0 ; i < sizeOfBlock ; i++ ) {
+ block[i] = LittleLong( block[i] );
+ }
+} //end of the function Q3_SwapBlock
+
+/*
+=============
+Q3_SwapBSPFile
+
+Byte swaps all data in a bsp file.
+=============
+*/
+void Q3_SwapBSPFile( void ) {
+ int i;
+
+ // models
+ Q3_SwapBlock( (int *)q3_dmodels, q3_nummodels * sizeof( q3_dmodels[0] ) );
+
+ // shaders (don't swap the name)
+ for ( i = 0 ; i < q3_numShaders ; i++ ) {
+ q3_dshaders[i].contentFlags = LittleLong( q3_dshaders[i].contentFlags );
+ q3_dshaders[i].surfaceFlags = LittleLong( q3_dshaders[i].surfaceFlags );
+ }
+
+ // planes
+ Q3_SwapBlock( (int *)q3_dplanes, q3_numplanes * sizeof( q3_dplanes[0] ) );
+
+ // nodes
+ Q3_SwapBlock( (int *)q3_dnodes, q3_numnodes * sizeof( q3_dnodes[0] ) );
+
+ // leafs
+ Q3_SwapBlock( (int *)q3_dleafs, q3_numleafs * sizeof( q3_dleafs[0] ) );
+
+ // leaffaces
+ Q3_SwapBlock( (int *)q3_dleafsurfaces, q3_numleafsurfaces * sizeof( q3_dleafsurfaces[0] ) );
+
+ // leafbrushes
+ Q3_SwapBlock( (int *)q3_dleafbrushes, q3_numleafbrushes * sizeof( q3_dleafbrushes[0] ) );
+
+ // brushes
+ Q3_SwapBlock( (int *)q3_dbrushes, q3_numbrushes * sizeof( q3_dbrushes[0] ) );
+
+ // brushsides
+ Q3_SwapBlock( (int *)q3_dbrushsides, q3_numbrushsides * sizeof( q3_dbrushsides[0] ) );
+
+ // vis
+ ((int *)&q3_visBytes)[0] = LittleLong( ((int *)&q3_visBytes)[0] );
+ ((int *)&q3_visBytes)[1] = LittleLong( ((int *)&q3_visBytes)[1] );
+
+ // drawverts (don't swap colors )
+ for ( i = 0 ; i < q3_numDrawVerts ; i++ ) {
+ q3_drawVerts[i].lightmap[0] = LittleFloat( q3_drawVerts[i].lightmap[0] );
+ q3_drawVerts[i].lightmap[1] = LittleFloat( q3_drawVerts[i].lightmap[1] );
+ q3_drawVerts[i].st[0] = LittleFloat( q3_drawVerts[i].st[0] );
+ q3_drawVerts[i].st[1] = LittleFloat( q3_drawVerts[i].st[1] );
+ q3_drawVerts[i].xyz[0] = LittleFloat( q3_drawVerts[i].xyz[0] );
+ q3_drawVerts[i].xyz[1] = LittleFloat( q3_drawVerts[i].xyz[1] );
+ q3_drawVerts[i].xyz[2] = LittleFloat( q3_drawVerts[i].xyz[2] );
+ q3_drawVerts[i].normal[0] = LittleFloat( q3_drawVerts[i].normal[0] );
+ q3_drawVerts[i].normal[1] = LittleFloat( q3_drawVerts[i].normal[1] );
+ q3_drawVerts[i].normal[2] = LittleFloat( q3_drawVerts[i].normal[2] );
+ }
+
+ // drawindexes
+ Q3_SwapBlock( (int *)q3_drawIndexes, q3_numDrawIndexes * sizeof( q3_drawIndexes[0] ) );
+
+ // drawsurfs
+ Q3_SwapBlock( (int *)q3_drawSurfaces, q3_numDrawSurfaces * sizeof( q3_drawSurfaces[0] ) );
+
+ // fogs
+ for ( i = 0 ; i < q3_numFogs ; i++ ) {
+ q3_dfogs[i].brushNum = LittleLong( q3_dfogs[i].brushNum );
+ }
+}
+
+
+
+/*
+=============
+Q3_CopyLump
+=============
+*/
+int Q3_CopyLump( q3_dheader_t *header, int lump, void **dest, int size ) {
+ int length, ofs;
+
+ length = header->lumps[lump].filelen;
+ ofs = header->lumps[lump].fileofs;
+
+ if ( length % size ) {
+ Error ("Q3_LoadBSPFile: odd lump size");
+ }
+
+ *dest = GetMemory(length);
+
+ memcpy( *dest, (byte *)header + ofs, length );
+
+ return length / size;
+}
+
+/*
+=============
+CountTriangles
+=============
+*/
+void CountTriangles( void ) {
+ int i, numTris, numPatchTris;
+ q3_dsurface_t *surface;
+
+ numTris = numPatchTris = 0;
+ for ( i = 0; i < q3_numDrawSurfaces; i++ ) {
+ surface = &q3_drawSurfaces[i];
+
+ numTris += surface->numIndexes / 3;
+
+ if ( surface->patchWidth ) {
+ numPatchTris += surface->patchWidth * surface->patchHeight * 2;
+ }
+ }
+
+ Log_Print( "%6d triangles\n", numTris );
+ Log_Print( "%6d patch tris\n", numPatchTris );
+}
+
+/*
+=============
+Q3_LoadBSPFile
+=============
+*/
+void Q3_LoadBSPFile(struct quakefile_s *qf)
+{
+ q3_dheader_t *header;
+
+ // load the file header
+ //LoadFile(filename, (void **)&header, offset, length);
+ //
+ LoadQuakeFile(qf, (void **)&header);
+
+ // swap the header
+ Q3_SwapBlock( (int *)header, sizeof(*header) );
+
+ if ( header->ident != Q3_BSP_IDENT ) {
+ Error( "%s is not a IBSP file", qf->filename );
+ }
+ if ( header->version != Q3_BSP_VERSION ) {
+ Error( "%s is version %i, not %i", qf->filename, header->version, Q3_BSP_VERSION );
+ }
+
+ q3_numShaders = Q3_CopyLump( header, Q3_LUMP_SHADERS, (void *) &q3_dshaders, sizeof(q3_dshader_t) );
+ q3_nummodels = Q3_CopyLump( header, Q3_LUMP_MODELS, (void *) &q3_dmodels, sizeof(q3_dmodel_t) );
+ q3_numplanes = Q3_CopyLump( header, Q3_LUMP_PLANES, (void *) &q3_dplanes, sizeof(q3_dplane_t) );
+ q3_numleafs = Q3_CopyLump( header, Q3_LUMP_LEAFS, (void *) &q3_dleafs, sizeof(q3_dleaf_t) );
+ q3_numnodes = Q3_CopyLump( header, Q3_LUMP_NODES, (void *) &q3_dnodes, sizeof(q3_dnode_t) );
+ q3_numleafsurfaces = Q3_CopyLump( header, Q3_LUMP_LEAFSURFACES, (void *) &q3_dleafsurfaces, sizeof(q3_dleafsurfaces[0]) );
+ q3_numleafbrushes = Q3_CopyLump( header, Q3_LUMP_LEAFBRUSHES, (void *) &q3_dleafbrushes, sizeof(q3_dleafbrushes[0]) );
+ q3_numbrushes = Q3_CopyLump( header, Q3_LUMP_BRUSHES, (void *) &q3_dbrushes, sizeof(q3_dbrush_t) );
+ q3_numbrushsides = Q3_CopyLump( header, Q3_LUMP_BRUSHSIDES, (void *) &q3_dbrushsides, sizeof(q3_dbrushside_t) );
+ q3_numDrawVerts = Q3_CopyLump( header, Q3_LUMP_DRAWVERTS, (void *) &q3_drawVerts, sizeof(q3_drawVert_t) );
+ q3_numDrawSurfaces = Q3_CopyLump( header, Q3_LUMP_SURFACES, (void *) &q3_drawSurfaces, sizeof(q3_dsurface_t) );
+ q3_numFogs = Q3_CopyLump( header, Q3_LUMP_FOGS, (void *) &q3_dfogs, sizeof(q3_dfog_t) );
+ q3_numDrawIndexes = Q3_CopyLump( header, Q3_LUMP_DRAWINDEXES, (void *) &q3_drawIndexes, sizeof(q3_drawIndexes[0]) );
+
+ q3_numVisBytes = Q3_CopyLump( header, Q3_LUMP_VISIBILITY, (void *) &q3_visBytes, 1 );
+ q3_numLightBytes = Q3_CopyLump( header, Q3_LUMP_LIGHTMAPS, (void *) &q3_lightBytes, 1 );
+ q3_entdatasize = Q3_CopyLump( header, Q3_LUMP_ENTITIES, (void *) &q3_dentdata, 1);
+
+ q3_numGridPoints = Q3_CopyLump( header, Q3_LUMP_LIGHTGRID, (void *) &q3_gridData, 8 );
+
+ CountTriangles();
+
+ FreeMemory( header ); // everything has been copied out
+
+ // swap everything
+ Q3_SwapBSPFile();
+
+ Q3_FindVisibleBrushSides();
+
+ //Q3_PrintBSPFileSizes();
+}
+
+
+//============================================================================
+
+/*
+=============
+Q3_AddLump
+=============
+*/
+void Q3_AddLump( FILE *bspfile, q3_dheader_t *header, int lumpnum, void *data, int len ) {
+ q3_lump_t *lump;
+
+ lump = &header->lumps[lumpnum];
+
+ lump->fileofs = LittleLong( ftell(bspfile) );
+ lump->filelen = LittleLong( len );
+ SafeWrite( bspfile, data, (len+3)&~3 );
+}
+
+/*
+=============
+Q3_WriteBSPFile
+
+Swaps the bsp file in place, so it should not be referenced again
+=============
+*/
+void Q3_WriteBSPFile( char *filename )
+{
+ q3_dheader_t outheader, *header;
+ FILE *bspfile;
+
+ header = &outheader;
+ memset( header, 0, sizeof(q3_dheader_t) );
+
+ Q3_SwapBSPFile();
+
+ header->ident = LittleLong( Q3_BSP_IDENT );
+ header->version = LittleLong( Q3_BSP_VERSION );
+
+ bspfile = SafeOpenWrite( filename );
+ SafeWrite( bspfile, header, sizeof(q3_dheader_t) ); // overwritten later
+
+ Q3_AddLump( bspfile, header, Q3_LUMP_SHADERS, q3_dshaders, q3_numShaders*sizeof(q3_dshader_t) );
+ Q3_AddLump( bspfile, header, Q3_LUMP_PLANES, q3_dplanes, q3_numplanes*sizeof(q3_dplane_t) );
+ Q3_AddLump( bspfile, header, Q3_LUMP_LEAFS, q3_dleafs, q3_numleafs*sizeof(q3_dleaf_t) );
+ Q3_AddLump( bspfile, header, Q3_LUMP_NODES, q3_dnodes, q3_numnodes*sizeof(q3_dnode_t) );
+ Q3_AddLump( bspfile, header, Q3_LUMP_BRUSHES, q3_dbrushes, q3_numbrushes*sizeof(q3_dbrush_t) );
+ Q3_AddLump( bspfile, header, Q3_LUMP_BRUSHSIDES, q3_dbrushsides, q3_numbrushsides*sizeof(q3_dbrushside_t) );
+ Q3_AddLump( bspfile, header, Q3_LUMP_LEAFSURFACES, q3_dleafsurfaces, q3_numleafsurfaces*sizeof(q3_dleafsurfaces[0]) );
+ Q3_AddLump( bspfile, header, Q3_LUMP_LEAFBRUSHES, q3_dleafbrushes, q3_numleafbrushes*sizeof(q3_dleafbrushes[0]) );
+ Q3_AddLump( bspfile, header, Q3_LUMP_MODELS, q3_dmodels, q3_nummodels*sizeof(q3_dmodel_t) );
+ Q3_AddLump( bspfile, header, Q3_LUMP_DRAWVERTS, q3_drawVerts, q3_numDrawVerts*sizeof(q3_drawVert_t) );
+ Q3_AddLump( bspfile, header, Q3_LUMP_SURFACES, q3_drawSurfaces, q3_numDrawSurfaces*sizeof(q3_dsurface_t) );
+ Q3_AddLump( bspfile, header, Q3_LUMP_VISIBILITY, q3_visBytes, q3_numVisBytes );
+ Q3_AddLump( bspfile, header, Q3_LUMP_LIGHTMAPS, q3_lightBytes, q3_numLightBytes );
+ Q3_AddLump( bspfile, header, Q3_LUMP_LIGHTGRID, q3_gridData, 8 * q3_numGridPoints );
+ Q3_AddLump( bspfile, header, Q3_LUMP_ENTITIES, q3_dentdata, q3_entdatasize );
+ Q3_AddLump( bspfile, header, Q3_LUMP_FOGS, q3_dfogs, q3_numFogs * sizeof(q3_dfog_t) );
+ Q3_AddLump( bspfile, header, Q3_LUMP_DRAWINDEXES, q3_drawIndexes, q3_numDrawIndexes * sizeof(q3_drawIndexes[0]) );
+
+ fseek (bspfile, 0, SEEK_SET);
+ SafeWrite (bspfile, header, sizeof(q3_dheader_t));
+ fclose (bspfile);
+}
+
+//============================================================================
+
+/*
+=============
+Q3_PrintBSPFileSizes
+
+Dumps info about current file
+=============
+*/
+void Q3_PrintBSPFileSizes( void )
+{
+ if ( !num_entities )
+ {
+ Q3_ParseEntities();
+ }
+
+ Log_Print ("%6i models %7i\n"
+ ,q3_nummodels, (int)(q3_nummodels*sizeof(q3_dmodel_t)));
+ Log_Print ("%6i shaders %7i\n"
+ ,q3_numShaders, (int)(q3_numShaders*sizeof(q3_dshader_t)));
+ Log_Print ("%6i brushes %7i\n"
+ ,q3_numbrushes, (int)(q3_numbrushes*sizeof(q3_dbrush_t)));
+ Log_Print ("%6i brushsides %7i\n"
+ ,q3_numbrushsides, (int)(q3_numbrushsides*sizeof(q3_dbrushside_t)));
+ Log_Print ("%6i fogs %7i\n"
+ ,q3_numFogs, (int)(q3_numFogs*sizeof(q3_dfog_t)));
+ Log_Print ("%6i planes %7i\n"
+ ,q3_numplanes, (int)(q3_numplanes*sizeof(q3_dplane_t)));
+ Log_Print ("%6i entdata %7i\n", num_entities, q3_entdatasize);
+
+ Log_Print ("\n");
+
+ Log_Print ("%6i nodes %7i\n"
+ ,q3_numnodes, (int)(q3_numnodes*sizeof(q3_dnode_t)));
+ Log_Print ("%6i leafs %7i\n"
+ ,q3_numleafs, (int)(q3_numleafs*sizeof(q3_dleaf_t)));
+ Log_Print ("%6i leafsurfaces %7i\n"
+ ,q3_numleafsurfaces, (int)(q3_numleafsurfaces*sizeof(q3_dleafsurfaces[0])));
+ Log_Print ("%6i leafbrushes %7i\n"
+ ,q3_numleafbrushes, (int)(q3_numleafbrushes*sizeof(q3_dleafbrushes[0])));
+ Log_Print ("%6i drawverts %7i\n"
+ ,q3_numDrawVerts, (int)(q3_numDrawVerts*sizeof(q3_drawVerts[0])));
+ Log_Print ("%6i drawindexes %7i\n"
+ ,q3_numDrawIndexes, (int)(q3_numDrawIndexes*sizeof(q3_drawIndexes[0])));
+ Log_Print ("%6i drawsurfaces %7i\n"
+ ,q3_numDrawSurfaces, (int)(q3_numDrawSurfaces*sizeof(q3_drawSurfaces[0])));
+
+ Log_Print ("%6i lightmaps %7i\n"
+ ,q3_numLightBytes / (LIGHTMAP_WIDTH*LIGHTMAP_HEIGHT*3), q3_numLightBytes );
+ Log_Print (" visibility %7i\n"
+ , q3_numVisBytes );
+}
+
+/*
+================
+Q3_ParseEntities
+
+Parses the q3_dentdata string into entities
+================
+*/
+void Q3_ParseEntities (void)
+{
+ script_t *script;
+
+ num_entities = 0;
+ script = LoadScriptMemory(q3_dentdata, q3_entdatasize, "*Quake3 bsp file");
+ SetScriptFlags(script, SCFL_NOSTRINGWHITESPACES |
+ SCFL_NOSTRINGESCAPECHARS);
+
+ while(ParseEntity(script))
+ {
+ } //end while
+
+ FreeScript(script);
+} //end of the function Q3_ParseEntities
+
+
+/*
+================
+Q3_UnparseEntities
+
+Generates the q3_dentdata string from all the entities
+================
+*/
+void Q3_UnparseEntities (void)
+{
+ char *buf, *end;
+ epair_t *ep;
+ char line[2048];
+ int i;
+
+ buf = q3_dentdata;
+ end = buf;
+ *end = 0;
+
+ for (i=0 ; i<num_entities ; i++)
+ {
+ ep = entities[i].epairs;
+ if (!ep)
+ continue; // ent got removed
+
+ strcat (end,"{\n");
+ end += 2;
+
+ for (ep = entities[i].epairs ; ep ; ep=ep->next)
+ {
+ sprintf (line, "\"%s\" \"%s\"\n", ep->key, ep->value);
+ strcat (end, line);
+ end += strlen(line);
+ }
+ strcat (end,"}\n");
+ end += 2;
+
+ if (end > buf + Q3_MAX_MAP_ENTSTRING)
+ Error ("Entity text too long");
+ }
+ q3_entdatasize = end - buf + 1;
+} //end of the function Q3_UnparseEntities
+
+
diff --git a/code/bspc/l_bsp_q3.h b/code/bspc/l_bsp_q3.h
index 6ac175c..3573c87 100755
--- a/code/bspc/l_bsp_q3.h
+++ b/code/bspc/l_bsp_q3.h
@@ -1,81 +1,81 @@
-/*
-===========================================================================
-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 "q3files.h"
-//#include "surfaceflags.h"
-
-extern int q3_nummodels;
-extern q3_dmodel_t *q3_dmodels;//[MAX_MAP_MODELS];
-
-extern int q3_numShaders;
-extern q3_dshader_t *q3_dshaders;//[Q3_MAX_MAP_SHADERS];
-
-extern int q3_entdatasize;
-extern char *q3_dentdata;//[Q3_MAX_MAP_ENTSTRING];
-
-extern int q3_numleafs;
-extern q3_dleaf_t *q3_dleafs;//[Q3_MAX_MAP_LEAFS];
-
-extern int q3_numplanes;
-extern q3_dplane_t *q3_dplanes;//[Q3_MAX_MAP_PLANES];
-
-extern int q3_numnodes;
-extern q3_dnode_t *q3_dnodes;//[Q3_MAX_MAP_NODES];
-
-extern int q3_numleafsurfaces;
-extern int *q3_dleafsurfaces;//[Q3_MAX_MAP_LEAFFACES];
-
-extern int q3_numleafbrushes;
-extern int *q3_dleafbrushes;//[Q3_MAX_MAP_LEAFBRUSHES];
-
-extern int q3_numbrushes;
-extern q3_dbrush_t *q3_dbrushes;//[Q3_MAX_MAP_BRUSHES];
-
-extern int q3_numbrushsides;
-extern q3_dbrushside_t *q3_dbrushsides;//[Q3_MAX_MAP_BRUSHSIDES];
-
-extern int q3_numLightBytes;
-extern byte *q3_lightBytes;//[Q3_MAX_MAP_LIGHTING];
-
-extern int q3_numGridPoints;
-extern byte *q3_gridData;//[Q3_MAX_MAP_LIGHTGRID];
-
-extern int q3_numVisBytes;
-extern byte *q3_visBytes;//[Q3_MAX_MAP_VISIBILITY];
-
-extern int q3_numDrawVerts;
-extern q3_drawVert_t *q3_drawVerts;//[Q3_MAX_MAP_DRAW_VERTS];
-
-extern int q3_numDrawIndexes;
-extern int *q3_drawIndexes;//[Q3_MAX_MAP_DRAW_INDEXES];
-
-extern int q3_numDrawSurfaces;
-extern q3_dsurface_t *q3_drawSurfaces;//[Q3_MAX_MAP_DRAW_SURFS];
-
-extern int q3_numFogs;
-extern q3_dfog_t *q3_dfogs;//[Q3_MAX_MAP_FOGS];
-
-extern char q3_dbrushsidetextured[Q3_MAX_MAP_BRUSHSIDES];
-
-void Q3_LoadBSPFile(struct quakefile_s *qf);
-void Q3_FreeMaxBSP(void);
-void Q3_ParseEntities (void);
+/*
+===========================================================================
+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 "q3files.h"
+//#include "surfaceflags.h"
+
+extern int q3_nummodels;
+extern q3_dmodel_t *q3_dmodels;//[MAX_MAP_MODELS];
+
+extern int q3_numShaders;
+extern q3_dshader_t *q3_dshaders;//[Q3_MAX_MAP_SHADERS];
+
+extern int q3_entdatasize;
+extern char *q3_dentdata;//[Q3_MAX_MAP_ENTSTRING];
+
+extern int q3_numleafs;
+extern q3_dleaf_t *q3_dleafs;//[Q3_MAX_MAP_LEAFS];
+
+extern int q3_numplanes;
+extern q3_dplane_t *q3_dplanes;//[Q3_MAX_MAP_PLANES];
+
+extern int q3_numnodes;
+extern q3_dnode_t *q3_dnodes;//[Q3_MAX_MAP_NODES];
+
+extern int q3_numleafsurfaces;
+extern int *q3_dleafsurfaces;//[Q3_MAX_MAP_LEAFFACES];
+
+extern int q3_numleafbrushes;
+extern int *q3_dleafbrushes;//[Q3_MAX_MAP_LEAFBRUSHES];
+
+extern int q3_numbrushes;
+extern q3_dbrush_t *q3_dbrushes;//[Q3_MAX_MAP_BRUSHES];
+
+extern int q3_numbrushsides;
+extern q3_dbrushside_t *q3_dbrushsides;//[Q3_MAX_MAP_BRUSHSIDES];
+
+extern int q3_numLightBytes;
+extern byte *q3_lightBytes;//[Q3_MAX_MAP_LIGHTING];
+
+extern int q3_numGridPoints;
+extern byte *q3_gridData;//[Q3_MAX_MAP_LIGHTGRID];
+
+extern int q3_numVisBytes;
+extern byte *q3_visBytes;//[Q3_MAX_MAP_VISIBILITY];
+
+extern int q3_numDrawVerts;
+extern q3_drawVert_t *q3_drawVerts;//[Q3_MAX_MAP_DRAW_VERTS];
+
+extern int q3_numDrawIndexes;
+extern int *q3_drawIndexes;//[Q3_MAX_MAP_DRAW_INDEXES];
+
+extern int q3_numDrawSurfaces;
+extern q3_dsurface_t *q3_drawSurfaces;//[Q3_MAX_MAP_DRAW_SURFS];
+
+extern int q3_numFogs;
+extern q3_dfog_t *q3_dfogs;//[Q3_MAX_MAP_FOGS];
+
+extern char q3_dbrushsidetextured[Q3_MAX_MAP_BRUSHSIDES];
+
+void Q3_LoadBSPFile(struct quakefile_s *qf);
+void Q3_FreeMaxBSP(void);
+void Q3_ParseEntities (void);
diff --git a/code/bspc/l_bsp_sin.c b/code/bspc/l_bsp_sin.c
index de51528..2c3c223 100755
--- a/code/bspc/l_bsp_sin.c
+++ b/code/bspc/l_bsp_sin.c
@@ -1,1186 +1,1186 @@
-/*
-===========================================================================
-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 "l_cmd.h"
-#include "l_math.h"
-#include "l_mem.h"
-#include "l_log.h"
-#include "l_poly.h"
-#include "../botlib/l_script.h"
-#include "l_bsp_ent.h"
-#include "l_bsp_sin.h"
-
-void GetLeafNums (void);
-
-//=============================================================================
-
-int sin_nummodels;
-sin_dmodel_t *sin_dmodels;//[SIN_MAX_MAP_MODELS];
-
-int sin_visdatasize;
-byte *sin_dvisdata;//[SIN_MAX_MAP_VISIBILITY];
-sin_dvis_t *sin_dvis;// = (sin_dvis_t *)sin_sin_dvisdata;
-
-int sin_lightdatasize;
-byte *sin_dlightdata;//[SIN_MAX_MAP_LIGHTING];
-
-int sin_entdatasize;
-char *sin_dentdata;//[SIN_MAX_MAP_ENTSTRING];
-
-int sin_numleafs;
-sin_dleaf_t *sin_dleafs;//[SIN_MAX_MAP_LEAFS];
-
-int sin_numplanes;
-sin_dplane_t *sin_dplanes;//[SIN_MAX_MAP_PLANES];
-
-int sin_numvertexes;
-sin_dvertex_t *sin_dvertexes;//[SIN_MAX_MAP_VERTS];
-
-int sin_numnodes;
-sin_dnode_t *sin_dnodes;//[SIN_MAX_MAP_NODES];
-
-int sin_numtexinfo;
-sin_texinfo_t *sin_texinfo;//[SIN_MAX_MAP_sin_texinfo];
-
-int sin_numfaces;
-sin_dface_t *sin_dfaces;//[SIN_MAX_MAP_FACES];
-
-int sin_numedges;
-sin_dedge_t *sin_dedges;//[SIN_MAX_MAP_EDGES];
-
-int sin_numleaffaces;
-unsigned short *sin_dleaffaces;//[SIN_MAX_MAP_LEAFFACES];
-
-int sin_numleafbrushes;
-unsigned short *sin_dleafbrushes;//[SIN_MAX_MAP_LEAFBRUSHES];
-
-int sin_numsurfedges;
-int *sin_dsurfedges;//[SIN_MAX_MAP_SURFEDGES];
-
-int sin_numbrushes;
-sin_dbrush_t *sin_dbrushes;//[SIN_MAX_MAP_BRUSHES];
-
-int sin_numbrushsides;
-sin_dbrushside_t *sin_dbrushsides;//[SIN_MAX_MAP_BRUSHSIDES];
-
-int sin_numareas;
-sin_darea_t *sin_dareas;//[SIN_MAX_MAP_AREAS];
-
-int sin_numareaportals;
-sin_dareaportal_t *sin_dareaportals;//[SIN_MAX_MAP_AREAPORTALS];
-
-int sin_numlightinfo;
-sin_lightvalue_t *sin_lightinfo;//[SIN_MAX_MAP_LIGHTINFO];
-
-byte sin_dpop[256];
-
-char sin_dbrushsidetextured[SIN_MAX_MAP_BRUSHSIDES];
-
-int sin_bspallocated = false;
-int sin_allocatedbspmem = 0;
-
-void Sin_AllocMaxBSP(void)
-{
- //models
- sin_nummodels = 0;
- sin_dmodels = (sin_dmodel_t *) GetClearedMemory(SIN_MAX_MAP_MODELS * sizeof(sin_dmodel_t));
- sin_allocatedbspmem += SIN_MAX_MAP_MODELS * sizeof(sin_dmodel_t);
- //vis data
- sin_visdatasize = 0;
- sin_dvisdata = (byte *) GetClearedMemory(SIN_MAX_MAP_VISIBILITY * sizeof(byte));
- sin_dvis = (sin_dvis_t *) sin_dvisdata;
- sin_allocatedbspmem += SIN_MAX_MAP_VISIBILITY * sizeof(byte);
- //light data
- sin_lightdatasize = 0;
- sin_dlightdata = (byte *) GetClearedMemory(SIN_MAX_MAP_LIGHTING * sizeof(byte));
- sin_allocatedbspmem += SIN_MAX_MAP_LIGHTING * sizeof(byte);
- //entity data
- sin_entdatasize = 0;
- sin_dentdata = (char *) GetClearedMemory(SIN_MAX_MAP_ENTSTRING * sizeof(char));
- sin_allocatedbspmem += SIN_MAX_MAP_ENTSTRING * sizeof(char);
- //leafs
- sin_numleafs = 0;
- sin_dleafs = (sin_dleaf_t *) GetClearedMemory(SIN_MAX_MAP_LEAFS * sizeof(sin_dleaf_t));
- sin_allocatedbspmem += SIN_MAX_MAP_LEAFS * sizeof(sin_dleaf_t);
- //planes
- sin_numplanes = 0;
- sin_dplanes = (sin_dplane_t *) GetClearedMemory(SIN_MAX_MAP_PLANES * sizeof(sin_dplane_t));
- sin_allocatedbspmem += SIN_MAX_MAP_PLANES * sizeof(sin_dplane_t);
- //vertexes
- sin_numvertexes = 0;
- sin_dvertexes = (sin_dvertex_t *) GetClearedMemory(SIN_MAX_MAP_VERTS * sizeof(sin_dvertex_t));
- sin_allocatedbspmem += SIN_MAX_MAP_VERTS * sizeof(sin_dvertex_t);
- //nodes
- sin_numnodes = 0;
- sin_dnodes = (sin_dnode_t *) GetClearedMemory(SIN_MAX_MAP_NODES * sizeof(sin_dnode_t));
- sin_allocatedbspmem += SIN_MAX_MAP_NODES * sizeof(sin_dnode_t);
- //texture info
- sin_numtexinfo = 0;
- sin_texinfo = (sin_texinfo_t *) GetClearedMemory(SIN_MAX_MAP_TEXINFO * sizeof(sin_texinfo_t));
- sin_allocatedbspmem += SIN_MAX_MAP_TEXINFO * sizeof(sin_texinfo_t);
- //faces
- sin_numfaces = 0;
- sin_dfaces = (sin_dface_t *) GetClearedMemory(SIN_MAX_MAP_FACES * sizeof(sin_dface_t));
- sin_allocatedbspmem += SIN_MAX_MAP_FACES * sizeof(sin_dface_t);
- //edges
- sin_numedges = 0;
- sin_dedges = (sin_dedge_t *) GetClearedMemory(SIN_MAX_MAP_EDGES * sizeof(sin_dedge_t));
- sin_allocatedbspmem += SIN_MAX_MAP_EDGES * sizeof(sin_dedge_t);
- //leaf faces
- sin_numleaffaces = 0;
- sin_dleaffaces = (unsigned short *) GetClearedMemory(SIN_MAX_MAP_LEAFFACES * sizeof(unsigned short));
- sin_allocatedbspmem += SIN_MAX_MAP_LEAFFACES * sizeof(unsigned short);
- //leaf brushes
- sin_numleafbrushes = 0;
- sin_dleafbrushes = (unsigned short *) GetClearedMemory(SIN_MAX_MAP_LEAFBRUSHES * sizeof(unsigned short));
- sin_allocatedbspmem += SIN_MAX_MAP_LEAFBRUSHES * sizeof(unsigned short);
- //surface edges
- sin_numsurfedges = 0;
- sin_dsurfedges = (int *) GetClearedMemory(SIN_MAX_MAP_SURFEDGES * sizeof(int));
- sin_allocatedbspmem += SIN_MAX_MAP_SURFEDGES * sizeof(int);
- //brushes
- sin_numbrushes = 0;
- sin_dbrushes = (sin_dbrush_t *) GetClearedMemory(SIN_MAX_MAP_BRUSHES * sizeof(sin_dbrush_t));
- sin_allocatedbspmem += SIN_MAX_MAP_BRUSHES * sizeof(sin_dbrush_t);
- //brushsides
- sin_numbrushsides = 0;
- sin_dbrushsides = (sin_dbrushside_t *) GetClearedMemory(SIN_MAX_MAP_BRUSHSIDES * sizeof(sin_dbrushside_t));
- sin_allocatedbspmem += SIN_MAX_MAP_BRUSHSIDES * sizeof(sin_dbrushside_t);
- //areas
- sin_numareas = 0;
- sin_dareas = (sin_darea_t *) GetClearedMemory(SIN_MAX_MAP_AREAS * sizeof(sin_darea_t));
- sin_allocatedbspmem += SIN_MAX_MAP_AREAS * sizeof(sin_darea_t);
- //area portals
- sin_numareaportals = 0;
- sin_dareaportals = (sin_dareaportal_t *) GetClearedMemory(SIN_MAX_MAP_AREAPORTALS * sizeof(sin_dareaportal_t));
- sin_allocatedbspmem += SIN_MAX_MAP_AREAPORTALS * sizeof(sin_dareaportal_t);
- //light info
- sin_numlightinfo = 0;
- sin_lightinfo = (sin_lightvalue_t *) GetClearedMemory(SIN_MAX_MAP_LIGHTINFO * sizeof(sin_lightvalue_t));
- sin_allocatedbspmem += SIN_MAX_MAP_LIGHTINFO * sizeof(sin_lightvalue_t);
- //print allocated memory
- Log_Print("allocated ");
- PrintMemorySize(sin_allocatedbspmem);
- Log_Print(" of BSP memory\n");
-} //end of the function Sin_AllocMaxBSP
-
-void Sin_FreeMaxBSP(void)
-{
- //models
- sin_nummodels = 0;
- FreeMemory(sin_dmodels);
- sin_dmodels = NULL;
- //vis data
- sin_visdatasize = 0;
- FreeMemory(sin_dvisdata);
- sin_dvisdata = NULL;
- sin_dvis = NULL;
- //light data
- sin_lightdatasize = 0;
- FreeMemory(sin_dlightdata);
- sin_dlightdata = NULL;
- //entity data
- sin_entdatasize = 0;
- FreeMemory(sin_dentdata);
- sin_dentdata = NULL;
- //leafs
- sin_numleafs = 0;
- FreeMemory(sin_dleafs);
- sin_dleafs = NULL;
- //planes
- sin_numplanes = 0;
- FreeMemory(sin_dplanes);
- sin_dplanes = NULL;
- //vertexes
- sin_numvertexes = 0;
- FreeMemory(sin_dvertexes);
- sin_dvertexes = NULL;
- //nodes
- sin_numnodes = 0;
- FreeMemory(sin_dnodes);
- sin_dnodes = NULL;
- //texture info
- sin_numtexinfo = 0;
- FreeMemory(sin_texinfo);
- sin_texinfo = NULL;
- //faces
- sin_numfaces = 0;
- FreeMemory(sin_dfaces);
- sin_dfaces = NULL;
- //edges
- sin_numedges = 0;
- FreeMemory(sin_dedges);
- sin_dedges = NULL;
- //leaf faces
- sin_numleaffaces = 0;
- FreeMemory(sin_dleaffaces);
- sin_dleaffaces = NULL;
- //leaf brushes
- sin_numleafbrushes = 0;
- FreeMemory(sin_dleafbrushes);
- sin_dleafbrushes = NULL;
- //surface edges
- sin_numsurfedges = 0;
- FreeMemory(sin_dsurfedges);
- sin_dsurfedges = NULL;
- //brushes
- sin_numbrushes = 0;
- FreeMemory(sin_dbrushes);
- sin_dbrushes = NULL;
- //brushsides
- sin_numbrushsides = 0;
- FreeMemory(sin_dbrushsides);
- sin_dbrushsides = NULL;
- //areas
- sin_numareas = 0;
- FreeMemory(sin_dareas);
- sin_dareas = NULL;
- //area portals
- sin_numareaportals = 0;
- FreeMemory(sin_dareaportals);
- sin_dareaportals = NULL;
- //light info
- sin_numlightinfo = 0;
- FreeMemory(sin_lightinfo);
- sin_lightinfo = NULL;
- //
- Log_Print("freed ");
- PrintMemorySize(sin_allocatedbspmem);
- Log_Print(" of BSP memory\n");
- sin_allocatedbspmem = 0;
-} //end of the function Sin_FreeMaxBSP
-
-#define WCONVEX_EPSILON 0.5
-
-//===========================================================================
-// returns the amount the face and the winding overlap
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float Sin_FaceOnWinding(sin_dface_t *face, winding_t *winding)
-{
- int i, edgenum, side;
- float dist, area;
- sin_dplane_t plane;
- vec_t *v1, *v2;
- vec3_t normal, edgevec;
- winding_t *w;
-
- //
- w = CopyWinding(winding);
- memcpy(&plane, &sin_dplanes[face->planenum], sizeof(sin_dplane_t));
- //check on which side of the plane the face is
- if (face->side)
- {
- VectorNegate(plane.normal, plane.normal);
- plane.dist = -plane.dist;
- } //end if
- for (i = 0; i < face->numedges && w; i++)
- {
- //get the first and second vertex of the edge
- edgenum = sin_dsurfedges[face->firstedge + i];
- side = edgenum > 0;
- //if the face plane is flipped
- v1 = sin_dvertexes[sin_dedges[abs(edgenum)].v[side]].point;
- v2 = sin_dvertexes[sin_dedges[abs(edgenum)].v[!side]].point;
- //create a plane through the edge vector, orthogonal to the face plane
- //and with the normal vector pointing out of the face
- VectorSubtract(v1, v2, edgevec);
- CrossProduct(edgevec, plane.normal, normal);
- VectorNormalize(normal);
- dist = DotProduct(normal, v1);
- //
- ChopWindingInPlace(&w, normal, dist, 0.9); //CLIP_EPSILON
- } //end for
- if (w)
- {
- area = WindingArea(w);
- FreeWinding(w);
- return area;
- } //end if
- return 0;
-} //end of the function Sin_FaceOnWinding
-//===========================================================================
-// creates a winding for the given brush side on the given brush
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-winding_t *Sin_BrushSideWinding(sin_dbrush_t *brush, sin_dbrushside_t *baseside)
-{
- int i;
- sin_dplane_t *baseplane, *plane;
- sin_dbrushside_t *side;
- winding_t *w;
-
- //create a winding for the brush side with the given planenumber
- baseplane = &sin_dplanes[baseside->planenum];
- w = BaseWindingForPlane(baseplane->normal, baseplane->dist);
- for (i = 0; i < brush->numsides && w; i++)
- {
- side = &sin_dbrushsides[brush->firstside + i];
- //don't chop with the base plane
- if (side->planenum == baseside->planenum) continue;
- //also don't use planes that are almost equal
- plane = &sin_dplanes[side->planenum];
- if (DotProduct(baseplane->normal, plane->normal) > 0.999
- && fabs(baseplane->dist - plane->dist) < 0.01) continue;
- //
- plane = &sin_dplanes[side->planenum^1];
- ChopWindingInPlace(&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
- } //end for
- return w;
-} //end of the function Sin_BrushSideWinding
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int Sin_HintSkipBrush(sin_dbrush_t *brush)
-{
- int j;
- sin_dbrushside_t *brushside;
-
- for (j = 0; j < brush->numsides; j++)
- {
- brushside = &sin_dbrushsides[brush->firstside + j];
- if (brushside->texinfo > 0)
- {
- if (sin_texinfo[brushside->texinfo].flags & (SURF_SKIP|SURF_HINT))
- {
- return true;
- } //end if
- } //end if
- } //end for
- return false;
-} //end of the function Sin_HintSkipBrush
-//===========================================================================
-// fix screwed brush texture references
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean WindingIsTiny(winding_t *w);
-
-void Sin_FixTextureReferences(void)
-{
- int i, j, k, we;
- sin_dbrushside_t *brushside;
- sin_dbrush_t *brush;
- sin_dface_t *face;
- winding_t *w;
-
- memset(sin_dbrushsidetextured, false, SIN_MAX_MAP_BRUSHSIDES);
- //go over all the brushes
- for (i = 0; i < sin_numbrushes; i++)
- {
- brush = &sin_dbrushes[i];
- //hint brushes are not textured
- if (Sin_HintSkipBrush(brush)) continue;
- //go over all the sides of the brush
- for (j = 0; j < brush->numsides; j++)
- {
- brushside = &sin_dbrushsides[brush->firstside + j];
- //
- w = Sin_BrushSideWinding(brush, brushside);
- if (!w)
- {
- sin_dbrushsidetextured[brush->firstside + j] = true;
- continue;
- } //end if
- else
- {
- //RemoveEqualPoints(w, 0.2);
- if (WindingIsTiny(w))
- {
- FreeWinding(w);
- sin_dbrushsidetextured[brush->firstside + j] = true;
- continue;
- } //end if
- else
- {
- we = WindingError(w);
- if (we == WE_NOTENOUGHPOINTS
- || we == WE_SMALLAREA
- || we == WE_POINTBOGUSRANGE
-// || we == WE_NONCONVEX
- )
- {
- FreeWinding(w);
- sin_dbrushsidetextured[brush->firstside + j] = true;
- continue;
- } //end if
- } //end else
- } //end else
- if (WindingArea(w) < 20)
- {
- sin_dbrushsidetextured[brush->firstside + j] = true;
- } //end if
- //find a face for texturing this brush
- for (k = 0; k < sin_numfaces; k++)
- {
- face = &sin_dfaces[k];
- //if the face is in the same plane as the brush side
- if ((face->planenum&~1) != (brushside->planenum&~1)) continue;
- //if the face is partly or totally on the brush side
- if (Sin_FaceOnWinding(face, w))
- {
- brushside->texinfo = face->texinfo;
- sin_dbrushsidetextured[brush->firstside + j] = true;
- break;
- } //end if
- } //end for
- FreeWinding(w);
- } //end for
- } //end for
-} //end of the function Sin_FixTextureReferences*/
-
-/*
-===============
-CompressVis
-
-===============
-*/
-int Sin_CompressVis (byte *vis, byte *dest)
-{
- int j;
- int rep;
- int visrow;
- byte *dest_p;
-
- dest_p = dest;
-// visrow = (r_numvisleafs + 7)>>3;
- visrow = (sin_dvis->numclusters + 7)>>3;
-
- for (j=0 ; j<visrow ; j++)
- {
- *dest_p++ = vis[j];
- if (vis[j])
- continue;
-
- rep = 1;
- for ( j++; j<visrow ; j++)
- if (vis[j] || rep == 255)
- break;
- else
- rep++;
- *dest_p++ = rep;
- j--;
- }
-
- return dest_p - dest;
-} //end of the function Sin_CompressVis
-
-
-/*
-===================
-DecompressVis
-===================
-*/
-void Sin_DecompressVis (byte *in, byte *decompressed)
-{
- int c;
- byte *out;
- int row;
-
-// row = (r_numvisleafs+7)>>3;
- row = (sin_dvis->numclusters+7)>>3;
- out = decompressed;
-
- do
- {
- if (*in)
- {
- *out++ = *in++;
- continue;
- }
-
- c = in[1];
- if (!c)
- Error ("DecompressVis: 0 repeat");
- in += 2;
- while (c)
- {
- *out++ = 0;
- c--;
- }
- } while (out - decompressed < row);
-} //end of the function Sin_DecompressVis
-
-//=============================================================================
-
-/*
-=============
-Sin_SwapBSPFile
-
-Byte swaps all data in a bsp file.
-=============
-*/
-void Sin_SwapBSPFile (qboolean todisk)
-{
- int i, j;
- sin_dmodel_t *d;
-
-
-// models
- for (i=0 ; i<sin_nummodels ; i++)
- {
- d = &sin_dmodels[i];
-
- d->firstface = LittleLong (d->firstface);
- d->numfaces = LittleLong (d->numfaces);
- d->headnode = LittleLong (d->headnode);
-
- for (j=0 ; j<3 ; j++)
- {
- d->mins[j] = LittleFloat(d->mins[j]);
- d->maxs[j] = LittleFloat(d->maxs[j]);
- d->origin[j] = LittleFloat(d->origin[j]);
- }
- }
-
-//
-// vertexes
-//
- for (i=0 ; i<sin_numvertexes ; i++)
- {
- for (j=0 ; j<3 ; j++)
- sin_dvertexes[i].point[j] = LittleFloat (sin_dvertexes[i].point[j]);
- }
-
-//
-// planes
-//
- for (i=0 ; i<sin_numplanes ; i++)
- {
- for (j=0 ; j<3 ; j++)
- sin_dplanes[i].normal[j] = LittleFloat (sin_dplanes[i].normal[j]);
- sin_dplanes[i].dist = LittleFloat (sin_dplanes[i].dist);
- sin_dplanes[i].type = LittleLong (sin_dplanes[i].type);
- }
-
-//
-// sin_texinfos
-//
- for (i = 0; i < sin_numtexinfo; i++)
- {
- for (j=0 ; j<8 ; j++)
- sin_texinfo[i].vecs[0][j] = LittleFloat (sin_texinfo[i].vecs[0][j]);
-#ifdef SIN
- sin_texinfo[i].trans_mag = LittleFloat( sin_texinfo[i].trans_mag );
- sin_texinfo[i].trans_angle = LittleLong( sin_texinfo[i].trans_angle );
- sin_texinfo[i].animtime = LittleFloat( sin_texinfo[i].animtime );
- sin_texinfo[i].nonlit = LittleFloat( sin_texinfo[i].nonlit );
- sin_texinfo[i].translucence = LittleFloat( sin_texinfo[i].translucence );
- sin_texinfo[i].friction = LittleFloat( sin_texinfo[i].friction );
- sin_texinfo[i].restitution = LittleFloat( sin_texinfo[i].restitution );
- sin_texinfo[i].flags = LittleUnsigned (sin_texinfo[i].flags);
-#else
- sin_texinfo[i].value = LittleLong (sin_texinfo[i].value);
- sin_texinfo[i].flags = LittleLong (sin_texinfo[i].flags);
-#endif
- sin_texinfo[i].nexttexinfo = LittleLong (sin_texinfo[i].nexttexinfo);
- }
-
-#ifdef SIN
-//
-// lightinfos
-//
- for (i = 0; i < sin_numlightinfo; i++)
- {
- for (j=0 ; j<3 ; j++)
- {
- sin_lightinfo[i].color[j] = LittleFloat (sin_lightinfo[i].color[j]);
- }
- sin_lightinfo[i].value = LittleLong (sin_lightinfo[i].value);
- sin_lightinfo[i].direct = LittleFloat( sin_lightinfo[i].direct );
- sin_lightinfo[i].directangle = LittleFloat( sin_lightinfo[i].directangle );
- sin_lightinfo[i].directstyle = LittleFloat( sin_lightinfo[i].directstyle );
- }
-#endif
-
-//
-// faces
-//
- for (i=0 ; i<sin_numfaces ; i++)
- {
- sin_dfaces[i].texinfo = LittleShort (sin_dfaces[i].texinfo);
-#ifdef SIN
- sin_dfaces[i].lightinfo = LittleLong (sin_dfaces[i].lightinfo);
- sin_dfaces[i].planenum = LittleUnsignedShort (sin_dfaces[i].planenum);
-#else
- sin_dfaces[i].planenum = LittleShort (sin_dfaces[i].planenum);
-#endif
- sin_dfaces[i].side = LittleShort (sin_dfaces[i].side);
- sin_dfaces[i].lightofs = LittleLong (sin_dfaces[i].lightofs);
- sin_dfaces[i].firstedge = LittleLong (sin_dfaces[i].firstedge);
- sin_dfaces[i].numedges = LittleShort (sin_dfaces[i].numedges);
- }
-
-//
-// nodes
-//
- for (i=0 ; i<sin_numnodes ; i++)
- {
- sin_dnodes[i].planenum = LittleLong (sin_dnodes[i].planenum);
- for (j=0 ; j<3 ; j++)
- {
- sin_dnodes[i].mins[j] = LittleShort (sin_dnodes[i].mins[j]);
- sin_dnodes[i].maxs[j] = LittleShort (sin_dnodes[i].maxs[j]);
- }
- sin_dnodes[i].children[0] = LittleLong (sin_dnodes[i].children[0]);
- sin_dnodes[i].children[1] = LittleLong (sin_dnodes[i].children[1]);
-#ifdef SIN
- sin_dnodes[i].firstface = LittleUnsignedShort (sin_dnodes[i].firstface);
- sin_dnodes[i].numfaces = LittleUnsignedShort (sin_dnodes[i].numfaces);
-#else
- sin_dnodes[i].firstface = LittleShort (sin_dnodes[i].firstface);
- sin_dnodes[i].numfaces = LittleShort (sin_dnodes[i].numfaces);
-#endif
- }
-
-//
-// leafs
-//
- for (i=0 ; i<sin_numleafs ; i++)
- {
- sin_dleafs[i].contents = LittleLong (sin_dleafs[i].contents);
- sin_dleafs[i].cluster = LittleShort (sin_dleafs[i].cluster);
- sin_dleafs[i].area = LittleShort (sin_dleafs[i].area);
- for (j=0 ; j<3 ; j++)
- {
- sin_dleafs[i].mins[j] = LittleShort (sin_dleafs[i].mins[j]);
- sin_dleafs[i].maxs[j] = LittleShort (sin_dleafs[i].maxs[j]);
- }
-#ifdef SIN
- sin_dleafs[i].firstleafface = LittleUnsignedShort (sin_dleafs[i].firstleafface);
- sin_dleafs[i].numleaffaces = LittleUnsignedShort (sin_dleafs[i].numleaffaces);
- sin_dleafs[i].firstleafbrush = LittleUnsignedShort (sin_dleafs[i].firstleafbrush);
- sin_dleafs[i].numleafbrushes = LittleUnsignedShort (sin_dleafs[i].numleafbrushes);
-#else
- sin_dleafs[i].firstleafface = LittleShort (sin_dleafs[i].firstleafface);
- sin_dleafs[i].numleaffaces = LittleShort (sin_dleafs[i].numleaffaces);
- sin_dleafs[i].firstleafbrush = LittleShort (sin_dleafs[i].firstleafbrush);
- sin_dleafs[i].numleafbrushes = LittleShort (sin_dleafs[i].numleafbrushes);
-#endif
- }
-
-//
-// leaffaces
-//
- for (i=0 ; i<sin_numleaffaces ; i++)
- sin_dleaffaces[i] = LittleShort (sin_dleaffaces[i]);
-
-//
-// leafbrushes
-//
- for (i=0 ; i<sin_numleafbrushes ; i++)
- sin_dleafbrushes[i] = LittleShort (sin_dleafbrushes[i]);
-
-//
-// surfedges
-//
- for (i=0 ; i<sin_numsurfedges ; i++)
- sin_dsurfedges[i] = LittleLong (sin_dsurfedges[i]);
-
-//
-// edges
-//
- for (i=0 ; i<sin_numedges ; i++)
- {
-#ifdef SIN
- sin_dedges[i].v[0] = LittleUnsignedShort (sin_dedges[i].v[0]);
- sin_dedges[i].v[1] = LittleUnsignedShort (sin_dedges[i].v[1]);
-#else
- sin_dedges[i].v[0] = LittleShort (sin_dedges[i].v[0]);
- sin_dedges[i].v[1] = LittleShort (sin_dedges[i].v[1]);
-#endif
- }
-
-//
-// brushes
-//
- for (i=0 ; i<sin_numbrushes ; i++)
- {
- sin_dbrushes[i].firstside = LittleLong (sin_dbrushes[i].firstside);
- sin_dbrushes[i].numsides = LittleLong (sin_dbrushes[i].numsides);
- sin_dbrushes[i].contents = LittleLong (sin_dbrushes[i].contents);
- }
-
-//
-// areas
-//
- for (i=0 ; i<sin_numareas ; i++)
- {
- sin_dareas[i].numareaportals = LittleLong (sin_dareas[i].numareaportals);
- sin_dareas[i].firstareaportal = LittleLong (sin_dareas[i].firstareaportal);
- }
-
-//
-// areasportals
-//
- for (i=0 ; i<sin_numareaportals ; i++)
- {
- sin_dareaportals[i].portalnum = LittleLong (sin_dareaportals[i].portalnum);
- sin_dareaportals[i].otherarea = LittleLong (sin_dareaportals[i].otherarea);
- }
-
-//
-// brushsides
-//
- for (i=0 ; i<sin_numbrushsides ; i++)
- {
-#ifdef SIN
- sin_dbrushsides[i].planenum = LittleUnsignedShort (sin_dbrushsides[i].planenum);
-#else
- sin_dbrushsides[i].planenum = LittleShort (sin_dbrushsides[i].planenum);
-#endif
- sin_dbrushsides[i].texinfo = LittleShort (sin_dbrushsides[i].texinfo);
-#ifdef SIN
- sin_dbrushsides[i].lightinfo = LittleLong (sin_dbrushsides[i].lightinfo);
-#endif
- }
-
-//
-// visibility
-//
- if (todisk)
- j = sin_dvis->numclusters;
- else
- j = LittleLong(sin_dvis->numclusters);
- sin_dvis->numclusters = LittleLong (sin_dvis->numclusters);
- for (i=0 ; i<j ; i++)
- {
- sin_dvis->bitofs[i][0] = LittleLong (sin_dvis->bitofs[i][0]);
- sin_dvis->bitofs[i][1] = LittleLong (sin_dvis->bitofs[i][1]);
- }
-} //end of the function Sin_SwapBSPFile
-
-
-sin_dheader_t *header;
-#ifdef SIN
-int Sin_CopyLump (int lump, void *dest, int size, int maxsize)
-{
- int length, ofs;
-
- length = header->lumps[lump].filelen;
- ofs = header->lumps[lump].fileofs;
-
- if (length % size)
- Error ("Sin_LoadBSPFile: odd lump size");
-
- if ((length/size) > maxsize)
- Error ("Sin_LoadBSPFile: exceeded max size for lump %d size %d > maxsize %d\n", lump, (length/size), maxsize );
-
- memcpy (dest, (byte *)header + ofs, length);
-
- return length / size;
-}
-#else
-int Sin_CopyLump (int lump, void *dest, int size)
-{
- int length, ofs;
-
- length = header->lumps[lump].filelen;
- ofs = header->lumps[lump].fileofs;
-
- if (length % size)
- Error ("Sin_LoadBSPFile: odd lump size");
-
- memcpy (dest, (byte *)header + ofs, length);
-
- return length / size;
-}
-#endif
-
-/*
-=============
-Sin_LoadBSPFile
-=============
-*/
-void Sin_LoadBSPFile(char *filename, int offset, int length)
-{
- int i;
-
-//
-// load the file header
-//
- LoadFile (filename, (void **)&header, offset, length);
-
-// swap the header
- for (i=0 ; i< sizeof(sin_dheader_t)/4 ; i++)
- ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
-
- if (header->ident != SIN_BSPHEADER && header->ident != SINGAME_BSPHEADER)
- Error ("%s is not a IBSP file", filename);
- if (header->version != SIN_BSPVERSION && header->version != SINGAME_BSPVERSION)
- Error ("%s is version %i, not %i", filename, header->version, SIN_BSPVERSION);
-
-#ifdef SIN
- sin_nummodels = Sin_CopyLump (SIN_LUMP_MODELS, sin_dmodels, sizeof(sin_dmodel_t), SIN_MAX_MAP_MODELS);
- sin_numvertexes = Sin_CopyLump (SIN_LUMP_VERTEXES, sin_dvertexes, sizeof(sin_dvertex_t), SIN_MAX_MAP_VERTS);
- sin_numplanes = Sin_CopyLump (SIN_LUMP_PLANES, sin_dplanes, sizeof(sin_dplane_t), SIN_MAX_MAP_PLANES);
- sin_numleafs = Sin_CopyLump (SIN_LUMP_LEAFS, sin_dleafs, sizeof(sin_dleaf_t), SIN_MAX_MAP_LEAFS);
- sin_numnodes = Sin_CopyLump (SIN_LUMP_NODES, sin_dnodes, sizeof(sin_dnode_t), SIN_MAX_MAP_NODES);
- sin_numtexinfo = Sin_CopyLump (SIN_LUMP_TEXINFO, sin_texinfo, sizeof(sin_texinfo_t), SIN_MAX_MAP_TEXINFO);
- sin_numfaces = Sin_CopyLump (SIN_LUMP_FACES, sin_dfaces, sizeof(sin_dface_t), SIN_MAX_MAP_FACES);
- sin_numleaffaces = Sin_CopyLump (SIN_LUMP_LEAFFACES, sin_dleaffaces, sizeof(sin_dleaffaces[0]), SIN_MAX_MAP_LEAFFACES);
- sin_numleafbrushes = Sin_CopyLump (SIN_LUMP_LEAFBRUSHES, sin_dleafbrushes, sizeof(sin_dleafbrushes[0]), SIN_MAX_MAP_LEAFBRUSHES);
- sin_numsurfedges = Sin_CopyLump (SIN_LUMP_SURFEDGES, sin_dsurfedges, sizeof(sin_dsurfedges[0]), SIN_MAX_MAP_SURFEDGES);
- sin_numedges = Sin_CopyLump (SIN_LUMP_EDGES, sin_dedges, sizeof(sin_dedge_t), SIN_MAX_MAP_EDGES);
- sin_numbrushes = Sin_CopyLump (SIN_LUMP_BRUSHES, sin_dbrushes, sizeof(sin_dbrush_t), SIN_MAX_MAP_BRUSHES);
- sin_numbrushsides = Sin_CopyLump (SIN_LUMP_BRUSHSIDES, sin_dbrushsides, sizeof(sin_dbrushside_t), SIN_MAX_MAP_BRUSHSIDES);
- sin_numareas = Sin_CopyLump (SIN_LUMP_AREAS, sin_dareas, sizeof(sin_darea_t), SIN_MAX_MAP_AREAS);
- sin_numareaportals = Sin_CopyLump (SIN_LUMP_AREAPORTALS, sin_dareaportals, sizeof(sin_dareaportal_t), SIN_MAX_MAP_AREAPORTALS);
- sin_numlightinfo = Sin_CopyLump (SIN_LUMP_LIGHTINFO, sin_lightinfo, sizeof(sin_lightvalue_t), SIN_MAX_MAP_LIGHTINFO);
-
- sin_visdatasize = Sin_CopyLump (SIN_LUMP_VISIBILITY, sin_dvisdata, 1, SIN_MAX_MAP_VISIBILITY);
- sin_lightdatasize = Sin_CopyLump (SIN_LUMP_LIGHTING, sin_dlightdata, 1, SIN_MAX_MAP_LIGHTING);
- sin_entdatasize = Sin_CopyLump (SIN_LUMP_ENTITIES, sin_dentdata, 1, SIN_MAX_MAP_ENTSTRING);
-
- Sin_CopyLump (SIN_LUMP_POP, sin_dpop, 1, sizeof(sin_dpop));
-#else
- sin_nummodels = Sin_CopyLump (SIN_LUMP_MODELS, sin_dmodels, sizeof(sin_dmodel_t));
- sin_numvertexes = Sin_CopyLump (SIN_LUMP_VERTEXES, sin_dvertexes, sizeof(sin_dvertex_t));
- sin_numplanes = Sin_CopyLump (SIN_LUMP_PLANES, sin_dplanes, sizeof(sin_dplane_t));
- sin_numleafs = Sin_CopyLump (SIN_LUMP_LEAFS, sin_dleafs, sizeof(sin_dleaf_t));
- sin_numnodes = Sin_CopyLump (SIN_LUMP_NODES, sin_dnodes, sizeof(sin_dnode_t));
- sin_numtexinfo = Sin_CopyLump (SIN_LUMP_TEXINFO, sin_texinfo, sizeof(sin_texinfo_t));
- sin_numfaces = Sin_CopyLump (SIN_LUMP_FACES, sin_dfaces, sizeof(sin_dface_t));
- sin_numleaffaces = Sin_CopyLump (SIN_LUMP_LEAFFACES, sin_dleaffaces, sizeof(sin_dleaffaces[0]));
- sin_numleafbrushes = Sin_CopyLump (SIN_LUMP_LEAFBRUSHES, sin_dleafbrushes, sizeof(sin_dleafbrushes[0]));
- sin_numsurfedges = Sin_CopyLump (SIN_LUMP_SURFEDGES, sin_dsurfedges, sizeof(sin_dsurfedges[0]));
- sin_numedges = Sin_CopyLump (SIN_LUMP_EDGES, sin_dedges, sizeof(sin_dedge_t));
- sin_numbrushes = Sin_CopyLump (SIN_LUMP_BRUSHES, sin_dbrushes, sizeof(sin_dbrush_t));
- sin_numbrushsides = Sin_CopyLump (SIN_LUMP_BRUSHSIDES, sin_dbrushsides, sizeof(sin_dbrushside_t));
- sin_numareas = Sin_CopyLump (SIN_LUMP_AREAS, sin_dareas, sizeof(sin_darea_t));
- sin_numareaportals = Sin_CopyLump (SIN_LUMP_AREAPORTALS, sin_dareaportals, sizeof(sin_dareaportal_t));
-
- sin_visdatasize = Sin_CopyLump (SIN_LUMP_VISIBILITY, sin_dvisdata, 1);
- sin_lightdatasize = Sin_CopyLump (SIN_LUMP_LIGHTING, sin_dlightdata, 1);
- sin_entdatasize = Sin_CopyLump (SIN_LUMP_ENTITIES, sin_dentdata, 1);
-
- Sin_CopyLump (SIN_LUMP_POP, sin_dpop, 1);
-#endif
-
- FreeMemory(header); // everything has been copied out
-
-//
-// swap everything
-//
- Sin_SwapBSPFile (false);
-} //end of the function Sin_LoadBSPFile
-
-/*
-=============
-Sin_LoadBSPFilesTexinfo
-
-Only loads the sin_texinfo lump, so qdata can scan for textures
-=============
-*/
-void Sin_LoadBSPFileTexinfo (char *filename)
-{
- int i;
- FILE *f;
- int length, ofs;
-
- header = GetMemory(sizeof(sin_dheader_t));
-
- f = fopen (filename, "rb");
- fread (header, sizeof(sin_dheader_t), 1, f);
-
-// swap the header
- for (i=0 ; i< sizeof(sin_dheader_t)/4 ; i++)
- ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
-
- if (header->ident != SIN_BSPHEADER && header->ident != SINGAME_BSPHEADER)
- Error ("%s is not a IBSP file", filename);
- if (header->version != SIN_BSPVERSION && header->version != SINGAME_BSPVERSION)
- Error ("%s is version %i, not %i", filename, header->version, SIN_BSPVERSION);
-
-
- length = header->lumps[SIN_LUMP_TEXINFO].filelen;
- ofs = header->lumps[SIN_LUMP_TEXINFO].fileofs;
-
- fseek (f, ofs, SEEK_SET);
- fread (sin_texinfo, length, 1, f);
- fclose (f);
-
- sin_numtexinfo = length / sizeof(sin_texinfo_t);
-
- FreeMemory(header); // everything has been copied out
-
- Sin_SwapBSPFile (false);
-} //end of the function Sin_LoadBSPFilesTexinfo
-
-
-//============================================================================
-
-FILE *wadfile;
-sin_dheader_t outheader;
-
-#ifdef SIN
-void Sin_AddLump (int lumpnum, void *data, int len, int size, int maxsize)
-{
- sin_lump_t *lump;
- int totallength;
-
- totallength = len*size;
-
- if (len > maxsize)
- Error ("Sin_WriteBSPFile: exceeded max size for lump %d size %d > maxsize %d\n", lumpnum, len, maxsize );
-
- lump = &header->lumps[lumpnum];
-
- lump->fileofs = LittleLong( ftell(wadfile) );
- lump->filelen = LittleLong(totallength);
- SafeWrite (wadfile, data, (totallength+3)&~3);
-}
-#else
-void Sin_AddLump (int lumpnum, void *data, int len)
-{
- sin_lump_t *lump;
-
- lump = &header->lumps[lumpnum];
-
- lump->fileofs = LittleLong( ftell(wadfile) );
- lump->filelen = LittleLong(len);
- SafeWrite (wadfile, data, (len+3)&~3);
-}
-#endif
-/*
-=============
-Sin_WriteBSPFile
-
-Swaps the bsp file in place, so it should not be referenced again
-=============
-*/
-void Sin_WriteBSPFile (char *filename)
-{
- header = &outheader;
- memset (header, 0, sizeof(sin_dheader_t));
-
- Sin_SwapBSPFile (true);
-
- header->ident = LittleLong (SIN_BSPHEADER);
- header->version = LittleLong (SIN_BSPVERSION);
-
- wadfile = SafeOpenWrite (filename);
- SafeWrite (wadfile, header, sizeof(sin_dheader_t)); // overwritten later
-
-#ifdef SIN
- Sin_AddLump (SIN_LUMP_PLANES, sin_dplanes, sin_numplanes, sizeof(sin_dplane_t), SIN_MAX_MAP_PLANES);
- Sin_AddLump (SIN_LUMP_LEAFS, sin_dleafs, sin_numleafs, sizeof(sin_dleaf_t), SIN_MAX_MAP_LEAFS);
- Sin_AddLump (SIN_LUMP_VERTEXES, sin_dvertexes, sin_numvertexes, sizeof(sin_dvertex_t), SIN_MAX_MAP_VERTS);
- Sin_AddLump (SIN_LUMP_NODES, sin_dnodes, sin_numnodes, sizeof(sin_dnode_t), SIN_MAX_MAP_NODES);
- Sin_AddLump (SIN_LUMP_TEXINFO, sin_texinfo, sin_numtexinfo, sizeof(sin_texinfo_t), SIN_MAX_MAP_TEXINFO);
- Sin_AddLump (SIN_LUMP_FACES, sin_dfaces, sin_numfaces, sizeof(sin_dface_t), SIN_MAX_MAP_FACES);
- Sin_AddLump (SIN_LUMP_BRUSHES, sin_dbrushes, sin_numbrushes, sizeof(sin_dbrush_t), SIN_MAX_MAP_BRUSHES);
- Sin_AddLump (SIN_LUMP_BRUSHSIDES, sin_dbrushsides, sin_numbrushsides, sizeof(sin_dbrushside_t), SIN_MAX_MAP_BRUSHSIDES);
- Sin_AddLump (SIN_LUMP_LEAFFACES, sin_dleaffaces, sin_numleaffaces, sizeof(sin_dleaffaces[0]), SIN_MAX_MAP_LEAFFACES);
- Sin_AddLump (SIN_LUMP_LEAFBRUSHES, sin_dleafbrushes, sin_numleafbrushes, sizeof(sin_dleafbrushes[0]), SIN_MAX_MAP_LEAFBRUSHES);
- Sin_AddLump (SIN_LUMP_SURFEDGES, sin_dsurfedges, sin_numsurfedges, sizeof(sin_dsurfedges[0]), SIN_MAX_MAP_SURFEDGES);
- Sin_AddLump (SIN_LUMP_EDGES, sin_dedges, sin_numedges, sizeof(sin_dedge_t), SIN_MAX_MAP_EDGES);
- Sin_AddLump (SIN_LUMP_MODELS, sin_dmodels, sin_nummodels, sizeof(sin_dmodel_t), SIN_MAX_MAP_MODELS);
- Sin_AddLump (SIN_LUMP_AREAS, sin_dareas, sin_numareas, sizeof(sin_darea_t), SIN_MAX_MAP_AREAS);
- Sin_AddLump (SIN_LUMP_AREAPORTALS, sin_dareaportals, sin_numareaportals, sizeof(sin_dareaportal_t), SIN_MAX_MAP_AREAPORTALS);
- Sin_AddLump (SIN_LUMP_LIGHTINFO, sin_lightinfo, sin_numlightinfo, sizeof(sin_lightvalue_t), SIN_MAX_MAP_LIGHTINFO);
-
- Sin_AddLump (SIN_LUMP_LIGHTING, sin_dlightdata, sin_lightdatasize, 1, SIN_MAX_MAP_LIGHTING);
- Sin_AddLump (SIN_LUMP_VISIBILITY, sin_dvisdata, sin_visdatasize, 1, SIN_MAX_MAP_VISIBILITY);
- Sin_AddLump (SIN_LUMP_ENTITIES, sin_dentdata, sin_entdatasize, 1, SIN_MAX_MAP_ENTSTRING);
- Sin_AddLump (SIN_LUMP_POP, sin_dpop, sizeof(sin_dpop), 1, sizeof(sin_dpop));
-#else
- Sin_AddLump (SIN_LUMP_PLANES, sin_dplanes, sin_numplanes*sizeof(sin_dplane_t));
- Sin_AddLump (SIN_LUMP_LEAFS, sin_dleafs, sin_numleafs*sizeof(sin_dleaf_t));
- Sin_AddLump (SIN_LUMP_VERTEXES, sin_dvertexes, sin_numvertexes*sizeof(sin_dvertex_t));
- Sin_AddLump (SIN_LUMP_NODES, sin_dnodes, sin_numnodes*sizeof(sin_dnode_t));
- Sin_AddLump (SIN_LUMP_TEXINFO, sin_texinfo, sin_numtexinfo*sizeof(sin_texinfo_t));
- Sin_AddLump (SIN_LUMP_FACES, sin_dfaces, sin_numfaces*sizeof(sin_dface_t));
- Sin_AddLump (SIN_LUMP_BRUSHES, sin_dbrushes, sin_numbrushes*sizeof(sin_dbrush_t));
- Sin_AddLump (SIN_LUMP_BRUSHSIDES, sin_dbrushsides, sin_numbrushsides*sizeof(sin_dbrushside_t));
- Sin_AddLump (SIN_LUMP_LEAFFACES, sin_dleaffaces, sin_numleaffaces*sizeof(sin_dleaffaces[0]));
- Sin_AddLump (SIN_LUMP_LEAFBRUSHES, sin_dleafbrushes, sin_numleafbrushes*sizeof(sin_dleafbrushes[0]));
- Sin_AddLump (SIN_LUMP_SURFEDGES, sin_dsurfedges, sin_numsurfedges*sizeof(sin_dsurfedges[0]));
- Sin_AddLump (SIN_LUMP_EDGES, sin_dedges, sin_numedges*sizeof(sin_dedge_t));
- Sin_AddLump (SIN_LUMP_MODELS, sin_dmodels, sin_nummodels*sizeof(sin_dmodel_t));
- Sin_AddLump (SIN_LUMP_AREAS, sin_dareas, sin_numareas*sizeof(sin_darea_t));
- Sin_AddLump (SIN_LUMP_AREAPORTALS, sin_dareaportals, sin_numareaportals*sizeof(sin_dareaportal_t));
-
- Sin_AddLump (SIN_LUMP_LIGHTING, sin_dlightdata, sin_lightdatasize);
- Sin_AddLump (SIN_LUMP_VISIBILITY, sin_dvisdata, sin_visdatasize);
- Sin_AddLump (SIN_LUMP_ENTITIES, sin_dentdata, sin_entdatasize);
- Sin_AddLump (SIN_LUMP_POP, sin_dpop, sizeof(sin_dpop));
-#endif
-
- fseek (wadfile, 0, SEEK_SET);
- SafeWrite (wadfile, header, sizeof(sin_dheader_t));
- fclose (wadfile);
-}
-
-//============================================================================
-
-
-//============================================
-
-/*
-================
-ParseEntities
-
-Parses the sin_dentdata string into entities
-================
-*/
-void Sin_ParseEntities (void)
-{
- script_t *script;
-
- num_entities = 0;
- script = LoadScriptMemory(sin_dentdata, sin_entdatasize, "*sin bsp file");
- SetScriptFlags(script, SCFL_NOSTRINGWHITESPACES |
- SCFL_NOSTRINGESCAPECHARS);
-
- while(ParseEntity(script))
- {
- } //end while
-
- FreeScript(script);
-} //end of the function Sin_ParseEntities
-
-
-/*
-================
-UnparseEntities
-
-Generates the sin_dentdata string from all the entities
-================
-*/
-void Sin_UnparseEntities (void)
-{
- char *buf, *end;
- epair_t *ep;
- char line[2048];
- int i;
- char key[1024], value[1024];
-
- buf = sin_dentdata;
- end = buf;
- *end = 0;
-
- for (i=0 ; i<num_entities ; i++)
- {
- ep = entities[i].epairs;
- if (!ep)
- continue; // ent got removed
-
- strcat (end,"{\n");
- end += 2;
-
- for (ep = entities[i].epairs ; ep ; ep=ep->next)
- {
- strcpy (key, ep->key);
- StripTrailing (key);
- strcpy (value, ep->value);
- StripTrailing (value);
-
- sprintf (line, "\"%s\" \"%s\"\n", key, value);
- strcat (end, line);
- end += strlen(line);
- }
- strcat (end,"}\n");
- end += 2;
-
- if (end > buf + SIN_MAX_MAP_ENTSTRING)
- Error ("Entity text too long");
- }
- sin_entdatasize = end - buf + 1;
-} //end of the function Sin_UnparseEntities
-
-#ifdef SIN
-void FreeValueKeys(entity_t *ent)
-{
- epair_t *ep,*next;
-
- for (ep=ent->epairs ; ep ; ep=next)
- {
- next = ep->next;
- FreeMemory(ep->value);
- FreeMemory(ep->key);
- FreeMemory(ep);
- }
- ent->epairs = NULL;
-}
-#endif
-
-/*
-=============
-Sin_PrintBSPFileSizes
-
-Dumps info about current file
-=============
-*/
-void Sin_PrintBSPFileSizes (void)
-{
- if (!num_entities)
- Sin_ParseEntities ();
-
- Log_Print("%6i models %7i\n"
- ,sin_nummodels, (int)(sin_nummodels*sizeof(sin_dmodel_t)));
- Log_Print("%6i brushes %7i\n"
- ,sin_numbrushes, (int)(sin_numbrushes*sizeof(sin_dbrush_t)));
- Log_Print("%6i brushsides %7i\n"
- ,sin_numbrushsides, (int)(sin_numbrushsides*sizeof(sin_dbrushside_t)));
- Log_Print("%6i planes %7i\n"
- ,sin_numplanes, (int)(sin_numplanes*sizeof(sin_dplane_t)));
- Log_Print("%6i texinfo %7i\n"
- ,sin_numtexinfo, (int)(sin_numtexinfo*sizeof(sin_texinfo_t)));
-#ifdef SIN
- Log_Print("%6i lightinfo %7i\n"
- ,sin_numlightinfo, (int)(sin_numlightinfo*sizeof(sin_lightvalue_t)));
-#endif
- Log_Print("%6i entdata %7i\n", num_entities, sin_entdatasize);
-
- Log_Print("\n");
-
- Log_Print("%6i vertexes %7i\n"
- ,sin_numvertexes, (int)(sin_numvertexes*sizeof(sin_dvertex_t)));
- Log_Print("%6i nodes %7i\n"
- ,sin_numnodes, (int)(sin_numnodes*sizeof(sin_dnode_t)));
- Log_Print("%6i faces %7i\n"
- ,sin_numfaces, (int)(sin_numfaces*sizeof(sin_dface_t)));
- Log_Print("%6i leafs %7i\n"
- ,sin_numleafs, (int)(sin_numleafs*sizeof(sin_dleaf_t)));
- Log_Print("%6i leaffaces %7i\n"
- ,sin_numleaffaces, (int)(sin_numleaffaces*sizeof(sin_dleaffaces[0])));
- Log_Print("%6i leafbrushes %7i\n"
- ,sin_numleafbrushes, (int)(sin_numleafbrushes*sizeof(sin_dleafbrushes[0])));
- Log_Print("%6i surfedges %7i\n"
- ,sin_numsurfedges, (int)(sin_numsurfedges*sizeof(sin_dsurfedges[0])));
- Log_Print("%6i edges %7i\n"
- ,sin_numedges, (int)(sin_numedges*sizeof(sin_dedge_t)));
- Log_Print(" lightdata %7i\n", sin_lightdatasize);
- Log_Print(" visdata %7i\n", sin_visdatasize);
-}
+/*
+===========================================================================
+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 "l_cmd.h"
+#include "l_math.h"
+#include "l_mem.h"
+#include "l_log.h"
+#include "l_poly.h"
+#include "../botlib/l_script.h"
+#include "l_bsp_ent.h"
+#include "l_bsp_sin.h"
+
+void GetLeafNums (void);
+
+//=============================================================================
+
+int sin_nummodels;
+sin_dmodel_t *sin_dmodels;//[SIN_MAX_MAP_MODELS];
+
+int sin_visdatasize;
+byte *sin_dvisdata;//[SIN_MAX_MAP_VISIBILITY];
+sin_dvis_t *sin_dvis;// = (sin_dvis_t *)sin_sin_dvisdata;
+
+int sin_lightdatasize;
+byte *sin_dlightdata;//[SIN_MAX_MAP_LIGHTING];
+
+int sin_entdatasize;
+char *sin_dentdata;//[SIN_MAX_MAP_ENTSTRING];
+
+int sin_numleafs;
+sin_dleaf_t *sin_dleafs;//[SIN_MAX_MAP_LEAFS];
+
+int sin_numplanes;
+sin_dplane_t *sin_dplanes;//[SIN_MAX_MAP_PLANES];
+
+int sin_numvertexes;
+sin_dvertex_t *sin_dvertexes;//[SIN_MAX_MAP_VERTS];
+
+int sin_numnodes;
+sin_dnode_t *sin_dnodes;//[SIN_MAX_MAP_NODES];
+
+int sin_numtexinfo;
+sin_texinfo_t *sin_texinfo;//[SIN_MAX_MAP_sin_texinfo];
+
+int sin_numfaces;
+sin_dface_t *sin_dfaces;//[SIN_MAX_MAP_FACES];
+
+int sin_numedges;
+sin_dedge_t *sin_dedges;//[SIN_MAX_MAP_EDGES];
+
+int sin_numleaffaces;
+unsigned short *sin_dleaffaces;//[SIN_MAX_MAP_LEAFFACES];
+
+int sin_numleafbrushes;
+unsigned short *sin_dleafbrushes;//[SIN_MAX_MAP_LEAFBRUSHES];
+
+int sin_numsurfedges;
+int *sin_dsurfedges;//[SIN_MAX_MAP_SURFEDGES];
+
+int sin_numbrushes;
+sin_dbrush_t *sin_dbrushes;//[SIN_MAX_MAP_BRUSHES];
+
+int sin_numbrushsides;
+sin_dbrushside_t *sin_dbrushsides;//[SIN_MAX_MAP_BRUSHSIDES];
+
+int sin_numareas;
+sin_darea_t *sin_dareas;//[SIN_MAX_MAP_AREAS];
+
+int sin_numareaportals;
+sin_dareaportal_t *sin_dareaportals;//[SIN_MAX_MAP_AREAPORTALS];
+
+int sin_numlightinfo;
+sin_lightvalue_t *sin_lightinfo;//[SIN_MAX_MAP_LIGHTINFO];
+
+byte sin_dpop[256];
+
+char sin_dbrushsidetextured[SIN_MAX_MAP_BRUSHSIDES];
+
+int sin_bspallocated = false;
+int sin_allocatedbspmem = 0;
+
+void Sin_AllocMaxBSP(void)
+{
+ //models
+ sin_nummodels = 0;
+ sin_dmodels = (sin_dmodel_t *) GetClearedMemory(SIN_MAX_MAP_MODELS * sizeof(sin_dmodel_t));
+ sin_allocatedbspmem += SIN_MAX_MAP_MODELS * sizeof(sin_dmodel_t);
+ //vis data
+ sin_visdatasize = 0;
+ sin_dvisdata = (byte *) GetClearedMemory(SIN_MAX_MAP_VISIBILITY * sizeof(byte));
+ sin_dvis = (sin_dvis_t *) sin_dvisdata;
+ sin_allocatedbspmem += SIN_MAX_MAP_VISIBILITY * sizeof(byte);
+ //light data
+ sin_lightdatasize = 0;
+ sin_dlightdata = (byte *) GetClearedMemory(SIN_MAX_MAP_LIGHTING * sizeof(byte));
+ sin_allocatedbspmem += SIN_MAX_MAP_LIGHTING * sizeof(byte);
+ //entity data
+ sin_entdatasize = 0;
+ sin_dentdata = (char *) GetClearedMemory(SIN_MAX_MAP_ENTSTRING * sizeof(char));
+ sin_allocatedbspmem += SIN_MAX_MAP_ENTSTRING * sizeof(char);
+ //leafs
+ sin_numleafs = 0;
+ sin_dleafs = (sin_dleaf_t *) GetClearedMemory(SIN_MAX_MAP_LEAFS * sizeof(sin_dleaf_t));
+ sin_allocatedbspmem += SIN_MAX_MAP_LEAFS * sizeof(sin_dleaf_t);
+ //planes
+ sin_numplanes = 0;
+ sin_dplanes = (sin_dplane_t *) GetClearedMemory(SIN_MAX_MAP_PLANES * sizeof(sin_dplane_t));
+ sin_allocatedbspmem += SIN_MAX_MAP_PLANES * sizeof(sin_dplane_t);
+ //vertexes
+ sin_numvertexes = 0;
+ sin_dvertexes = (sin_dvertex_t *) GetClearedMemory(SIN_MAX_MAP_VERTS * sizeof(sin_dvertex_t));
+ sin_allocatedbspmem += SIN_MAX_MAP_VERTS * sizeof(sin_dvertex_t);
+ //nodes
+ sin_numnodes = 0;
+ sin_dnodes = (sin_dnode_t *) GetClearedMemory(SIN_MAX_MAP_NODES * sizeof(sin_dnode_t));
+ sin_allocatedbspmem += SIN_MAX_MAP_NODES * sizeof(sin_dnode_t);
+ //texture info
+ sin_numtexinfo = 0;
+ sin_texinfo = (sin_texinfo_t *) GetClearedMemory(SIN_MAX_MAP_TEXINFO * sizeof(sin_texinfo_t));
+ sin_allocatedbspmem += SIN_MAX_MAP_TEXINFO * sizeof(sin_texinfo_t);
+ //faces
+ sin_numfaces = 0;
+ sin_dfaces = (sin_dface_t *) GetClearedMemory(SIN_MAX_MAP_FACES * sizeof(sin_dface_t));
+ sin_allocatedbspmem += SIN_MAX_MAP_FACES * sizeof(sin_dface_t);
+ //edges
+ sin_numedges = 0;
+ sin_dedges = (sin_dedge_t *) GetClearedMemory(SIN_MAX_MAP_EDGES * sizeof(sin_dedge_t));
+ sin_allocatedbspmem += SIN_MAX_MAP_EDGES * sizeof(sin_dedge_t);
+ //leaf faces
+ sin_numleaffaces = 0;
+ sin_dleaffaces = (unsigned short *) GetClearedMemory(SIN_MAX_MAP_LEAFFACES * sizeof(unsigned short));
+ sin_allocatedbspmem += SIN_MAX_MAP_LEAFFACES * sizeof(unsigned short);
+ //leaf brushes
+ sin_numleafbrushes = 0;
+ sin_dleafbrushes = (unsigned short *) GetClearedMemory(SIN_MAX_MAP_LEAFBRUSHES * sizeof(unsigned short));
+ sin_allocatedbspmem += SIN_MAX_MAP_LEAFBRUSHES * sizeof(unsigned short);
+ //surface edges
+ sin_numsurfedges = 0;
+ sin_dsurfedges = (int *) GetClearedMemory(SIN_MAX_MAP_SURFEDGES * sizeof(int));
+ sin_allocatedbspmem += SIN_MAX_MAP_SURFEDGES * sizeof(int);
+ //brushes
+ sin_numbrushes = 0;
+ sin_dbrushes = (sin_dbrush_t *) GetClearedMemory(SIN_MAX_MAP_BRUSHES * sizeof(sin_dbrush_t));
+ sin_allocatedbspmem += SIN_MAX_MAP_BRUSHES * sizeof(sin_dbrush_t);
+ //brushsides
+ sin_numbrushsides = 0;
+ sin_dbrushsides = (sin_dbrushside_t *) GetClearedMemory(SIN_MAX_MAP_BRUSHSIDES * sizeof(sin_dbrushside_t));
+ sin_allocatedbspmem += SIN_MAX_MAP_BRUSHSIDES * sizeof(sin_dbrushside_t);
+ //areas
+ sin_numareas = 0;
+ sin_dareas = (sin_darea_t *) GetClearedMemory(SIN_MAX_MAP_AREAS * sizeof(sin_darea_t));
+ sin_allocatedbspmem += SIN_MAX_MAP_AREAS * sizeof(sin_darea_t);
+ //area portals
+ sin_numareaportals = 0;
+ sin_dareaportals = (sin_dareaportal_t *) GetClearedMemory(SIN_MAX_MAP_AREAPORTALS * sizeof(sin_dareaportal_t));
+ sin_allocatedbspmem += SIN_MAX_MAP_AREAPORTALS * sizeof(sin_dareaportal_t);
+ //light info
+ sin_numlightinfo = 0;
+ sin_lightinfo = (sin_lightvalue_t *) GetClearedMemory(SIN_MAX_MAP_LIGHTINFO * sizeof(sin_lightvalue_t));
+ sin_allocatedbspmem += SIN_MAX_MAP_LIGHTINFO * sizeof(sin_lightvalue_t);
+ //print allocated memory
+ Log_Print("allocated ");
+ PrintMemorySize(sin_allocatedbspmem);
+ Log_Print(" of BSP memory\n");
+} //end of the function Sin_AllocMaxBSP
+
+void Sin_FreeMaxBSP(void)
+{
+ //models
+ sin_nummodels = 0;
+ FreeMemory(sin_dmodels);
+ sin_dmodels = NULL;
+ //vis data
+ sin_visdatasize = 0;
+ FreeMemory(sin_dvisdata);
+ sin_dvisdata = NULL;
+ sin_dvis = NULL;
+ //light data
+ sin_lightdatasize = 0;
+ FreeMemory(sin_dlightdata);
+ sin_dlightdata = NULL;
+ //entity data
+ sin_entdatasize = 0;
+ FreeMemory(sin_dentdata);
+ sin_dentdata = NULL;
+ //leafs
+ sin_numleafs = 0;
+ FreeMemory(sin_dleafs);
+ sin_dleafs = NULL;
+ //planes
+ sin_numplanes = 0;
+ FreeMemory(sin_dplanes);
+ sin_dplanes = NULL;
+ //vertexes
+ sin_numvertexes = 0;
+ FreeMemory(sin_dvertexes);
+ sin_dvertexes = NULL;
+ //nodes
+ sin_numnodes = 0;
+ FreeMemory(sin_dnodes);
+ sin_dnodes = NULL;
+ //texture info
+ sin_numtexinfo = 0;
+ FreeMemory(sin_texinfo);
+ sin_texinfo = NULL;
+ //faces
+ sin_numfaces = 0;
+ FreeMemory(sin_dfaces);
+ sin_dfaces = NULL;
+ //edges
+ sin_numedges = 0;
+ FreeMemory(sin_dedges);
+ sin_dedges = NULL;
+ //leaf faces
+ sin_numleaffaces = 0;
+ FreeMemory(sin_dleaffaces);
+ sin_dleaffaces = NULL;
+ //leaf brushes
+ sin_numleafbrushes = 0;
+ FreeMemory(sin_dleafbrushes);
+ sin_dleafbrushes = NULL;
+ //surface edges
+ sin_numsurfedges = 0;
+ FreeMemory(sin_dsurfedges);
+ sin_dsurfedges = NULL;
+ //brushes
+ sin_numbrushes = 0;
+ FreeMemory(sin_dbrushes);
+ sin_dbrushes = NULL;
+ //brushsides
+ sin_numbrushsides = 0;
+ FreeMemory(sin_dbrushsides);
+ sin_dbrushsides = NULL;
+ //areas
+ sin_numareas = 0;
+ FreeMemory(sin_dareas);
+ sin_dareas = NULL;
+ //area portals
+ sin_numareaportals = 0;
+ FreeMemory(sin_dareaportals);
+ sin_dareaportals = NULL;
+ //light info
+ sin_numlightinfo = 0;
+ FreeMemory(sin_lightinfo);
+ sin_lightinfo = NULL;
+ //
+ Log_Print("freed ");
+ PrintMemorySize(sin_allocatedbspmem);
+ Log_Print(" of BSP memory\n");
+ sin_allocatedbspmem = 0;
+} //end of the function Sin_FreeMaxBSP
+
+#define WCONVEX_EPSILON 0.5
+
+//===========================================================================
+// returns the amount the face and the winding overlap
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+float Sin_FaceOnWinding(sin_dface_t *face, winding_t *winding)
+{
+ int i, edgenum, side;
+ float dist, area;
+ sin_dplane_t plane;
+ vec_t *v1, *v2;
+ vec3_t normal, edgevec;
+ winding_t *w;
+
+ //
+ w = CopyWinding(winding);
+ memcpy(&plane, &sin_dplanes[face->planenum], sizeof(sin_dplane_t));
+ //check on which side of the plane the face is
+ if (face->side)
+ {
+ VectorNegate(plane.normal, plane.normal);
+ plane.dist = -plane.dist;
+ } //end if
+ for (i = 0; i < face->numedges && w; i++)
+ {
+ //get the first and second vertex of the edge
+ edgenum = sin_dsurfedges[face->firstedge + i];
+ side = edgenum > 0;
+ //if the face plane is flipped
+ v1 = sin_dvertexes[sin_dedges[abs(edgenum)].v[side]].point;
+ v2 = sin_dvertexes[sin_dedges[abs(edgenum)].v[!side]].point;
+ //create a plane through the edge vector, orthogonal to the face plane
+ //and with the normal vector pointing out of the face
+ VectorSubtract(v1, v2, edgevec);
+ CrossProduct(edgevec, plane.normal, normal);
+ VectorNormalize(normal);
+ dist = DotProduct(normal, v1);
+ //
+ ChopWindingInPlace(&w, normal, dist, 0.9); //CLIP_EPSILON
+ } //end for
+ if (w)
+ {
+ area = WindingArea(w);
+ FreeWinding(w);
+ return area;
+ } //end if
+ return 0;
+} //end of the function Sin_FaceOnWinding
+//===========================================================================
+// creates a winding for the given brush side on the given brush
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+winding_t *Sin_BrushSideWinding(sin_dbrush_t *brush, sin_dbrushside_t *baseside)
+{
+ int i;
+ sin_dplane_t *baseplane, *plane;
+ sin_dbrushside_t *side;
+ winding_t *w;
+
+ //create a winding for the brush side with the given planenumber
+ baseplane = &sin_dplanes[baseside->planenum];
+ w = BaseWindingForPlane(baseplane->normal, baseplane->dist);
+ for (i = 0; i < brush->numsides && w; i++)
+ {
+ side = &sin_dbrushsides[brush->firstside + i];
+ //don't chop with the base plane
+ if (side->planenum == baseside->planenum) continue;
+ //also don't use planes that are almost equal
+ plane = &sin_dplanes[side->planenum];
+ if (DotProduct(baseplane->normal, plane->normal) > 0.999
+ && fabs(baseplane->dist - plane->dist) < 0.01) continue;
+ //
+ plane = &sin_dplanes[side->planenum^1];
+ ChopWindingInPlace(&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
+ } //end for
+ return w;
+} //end of the function Sin_BrushSideWinding
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int Sin_HintSkipBrush(sin_dbrush_t *brush)
+{
+ int j;
+ sin_dbrushside_t *brushside;
+
+ for (j = 0; j < brush->numsides; j++)
+ {
+ brushside = &sin_dbrushsides[brush->firstside + j];
+ if (brushside->texinfo > 0)
+ {
+ if (sin_texinfo[brushside->texinfo].flags & (SURF_SKIP|SURF_HINT))
+ {
+ return true;
+ } //end if
+ } //end if
+ } //end for
+ return false;
+} //end of the function Sin_HintSkipBrush
+//===========================================================================
+// fix screwed brush texture references
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+qboolean WindingIsTiny(winding_t *w);
+
+void Sin_FixTextureReferences(void)
+{
+ int i, j, k, we;
+ sin_dbrushside_t *brushside;
+ sin_dbrush_t *brush;
+ sin_dface_t *face;
+ winding_t *w;
+
+ memset(sin_dbrushsidetextured, false, SIN_MAX_MAP_BRUSHSIDES);
+ //go over all the brushes
+ for (i = 0; i < sin_numbrushes; i++)
+ {
+ brush = &sin_dbrushes[i];
+ //hint brushes are not textured
+ if (Sin_HintSkipBrush(brush)) continue;
+ //go over all the sides of the brush
+ for (j = 0; j < brush->numsides; j++)
+ {
+ brushside = &sin_dbrushsides[brush->firstside + j];
+ //
+ w = Sin_BrushSideWinding(brush, brushside);
+ if (!w)
+ {
+ sin_dbrushsidetextured[brush->firstside + j] = true;
+ continue;
+ } //end if
+ else
+ {
+ //RemoveEqualPoints(w, 0.2);
+ if (WindingIsTiny(w))
+ {
+ FreeWinding(w);
+ sin_dbrushsidetextured[brush->firstside + j] = true;
+ continue;
+ } //end if
+ else
+ {
+ we = WindingError(w);
+ if (we == WE_NOTENOUGHPOINTS
+ || we == WE_SMALLAREA
+ || we == WE_POINTBOGUSRANGE
+// || we == WE_NONCONVEX
+ )
+ {
+ FreeWinding(w);
+ sin_dbrushsidetextured[brush->firstside + j] = true;
+ continue;
+ } //end if
+ } //end else
+ } //end else
+ if (WindingArea(w) < 20)
+ {
+ sin_dbrushsidetextured[brush->firstside + j] = true;
+ } //end if
+ //find a face for texturing this brush
+ for (k = 0; k < sin_numfaces; k++)
+ {
+ face = &sin_dfaces[k];
+ //if the face is in the same plane as the brush side
+ if ((face->planenum&~1) != (brushside->planenum&~1)) continue;
+ //if the face is partly or totally on the brush side
+ if (Sin_FaceOnWinding(face, w))
+ {
+ brushside->texinfo = face->texinfo;
+ sin_dbrushsidetextured[brush->firstside + j] = true;
+ break;
+ } //end if
+ } //end for
+ FreeWinding(w);
+ } //end for
+ } //end for
+} //end of the function Sin_FixTextureReferences*/
+
+/*
+===============
+CompressVis
+
+===============
+*/
+int Sin_CompressVis (byte *vis, byte *dest)
+{
+ int j;
+ int rep;
+ int visrow;
+ byte *dest_p;
+
+ dest_p = dest;
+// visrow = (r_numvisleafs + 7)>>3;
+ visrow = (sin_dvis->numclusters + 7)>>3;
+
+ for (j=0 ; j<visrow ; j++)
+ {
+ *dest_p++ = vis[j];
+ if (vis[j])
+ continue;
+
+ rep = 1;
+ for ( j++; j<visrow ; j++)
+ if (vis[j] || rep == 255)
+ break;
+ else
+ rep++;
+ *dest_p++ = rep;
+ j--;
+ }
+
+ return dest_p - dest;
+} //end of the function Sin_CompressVis
+
+
+/*
+===================
+DecompressVis
+===================
+*/
+void Sin_DecompressVis (byte *in, byte *decompressed)
+{
+ int c;
+ byte *out;
+ int row;
+
+// row = (r_numvisleafs+7)>>3;
+ row = (sin_dvis->numclusters+7)>>3;
+ out = decompressed;
+
+ do
+ {
+ if (*in)
+ {
+ *out++ = *in++;
+ continue;
+ }
+
+ c = in[1];
+ if (!c)
+ Error ("DecompressVis: 0 repeat");
+ in += 2;
+ while (c)
+ {
+ *out++ = 0;
+ c--;
+ }
+ } while (out - decompressed < row);
+} //end of the function Sin_DecompressVis
+
+//=============================================================================
+
+/*
+=============
+Sin_SwapBSPFile
+
+Byte swaps all data in a bsp file.
+=============
+*/
+void Sin_SwapBSPFile (qboolean todisk)
+{
+ int i, j;
+ sin_dmodel_t *d;
+
+
+// models
+ for (i=0 ; i<sin_nummodels ; i++)
+ {
+ d = &sin_dmodels[i];
+
+ d->firstface = LittleLong (d->firstface);
+ d->numfaces = LittleLong (d->numfaces);
+ d->headnode = LittleLong (d->headnode);
+
+ for (j=0 ; j<3 ; j++)
+ {
+ d->mins[j] = LittleFloat(d->mins[j]);
+ d->maxs[j] = LittleFloat(d->maxs[j]);
+ d->origin[j] = LittleFloat(d->origin[j]);
+ }
+ }
+
+//
+// vertexes
+//
+ for (i=0 ; i<sin_numvertexes ; i++)
+ {
+ for (j=0 ; j<3 ; j++)
+ sin_dvertexes[i].point[j] = LittleFloat (sin_dvertexes[i].point[j]);
+ }
+
+//
+// planes
+//
+ for (i=0 ; i<sin_numplanes ; i++)
+ {
+ for (j=0 ; j<3 ; j++)
+ sin_dplanes[i].normal[j] = LittleFloat (sin_dplanes[i].normal[j]);
+ sin_dplanes[i].dist = LittleFloat (sin_dplanes[i].dist);
+ sin_dplanes[i].type = LittleLong (sin_dplanes[i].type);
+ }
+
+//
+// sin_texinfos
+//
+ for (i = 0; i < sin_numtexinfo; i++)
+ {
+ for (j=0 ; j<8 ; j++)
+ sin_texinfo[i].vecs[0][j] = LittleFloat (sin_texinfo[i].vecs[0][j]);
+#ifdef SIN
+ sin_texinfo[i].trans_mag = LittleFloat( sin_texinfo[i].trans_mag );
+ sin_texinfo[i].trans_angle = LittleLong( sin_texinfo[i].trans_angle );
+ sin_texinfo[i].animtime = LittleFloat( sin_texinfo[i].animtime );
+ sin_texinfo[i].nonlit = LittleFloat( sin_texinfo[i].nonlit );
+ sin_texinfo[i].translucence = LittleFloat( sin_texinfo[i].translucence );
+ sin_texinfo[i].friction = LittleFloat( sin_texinfo[i].friction );
+ sin_texinfo[i].restitution = LittleFloat( sin_texinfo[i].restitution );
+ sin_texinfo[i].flags = LittleUnsigned (sin_texinfo[i].flags);
+#else
+ sin_texinfo[i].value = LittleLong (sin_texinfo[i].value);
+ sin_texinfo[i].flags = LittleLong (sin_texinfo[i].flags);
+#endif
+ sin_texinfo[i].nexttexinfo = LittleLong (sin_texinfo[i].nexttexinfo);
+ }
+
+#ifdef SIN
+//
+// lightinfos
+//
+ for (i = 0; i < sin_numlightinfo; i++)
+ {
+ for (j=0 ; j<3 ; j++)
+ {
+ sin_lightinfo[i].color[j] = LittleFloat (sin_lightinfo[i].color[j]);
+ }
+ sin_lightinfo[i].value = LittleLong (sin_lightinfo[i].value);
+ sin_lightinfo[i].direct = LittleFloat( sin_lightinfo[i].direct );
+ sin_lightinfo[i].directangle = LittleFloat( sin_lightinfo[i].directangle );
+ sin_lightinfo[i].directstyle = LittleFloat( sin_lightinfo[i].directstyle );
+ }
+#endif
+
+//
+// faces
+//
+ for (i=0 ; i<sin_numfaces ; i++)
+ {
+ sin_dfaces[i].texinfo = LittleShort (sin_dfaces[i].texinfo);
+#ifdef SIN
+ sin_dfaces[i].lightinfo = LittleLong (sin_dfaces[i].lightinfo);
+ sin_dfaces[i].planenum = LittleUnsignedShort (sin_dfaces[i].planenum);
+#else
+ sin_dfaces[i].planenum = LittleShort (sin_dfaces[i].planenum);
+#endif
+ sin_dfaces[i].side = LittleShort (sin_dfaces[i].side);
+ sin_dfaces[i].lightofs = LittleLong (sin_dfaces[i].lightofs);
+ sin_dfaces[i].firstedge = LittleLong (sin_dfaces[i].firstedge);
+ sin_dfaces[i].numedges = LittleShort (sin_dfaces[i].numedges);
+ }
+
+//
+// nodes
+//
+ for (i=0 ; i<sin_numnodes ; i++)
+ {
+ sin_dnodes[i].planenum = LittleLong (sin_dnodes[i].planenum);
+ for (j=0 ; j<3 ; j++)
+ {
+ sin_dnodes[i].mins[j] = LittleShort (sin_dnodes[i].mins[j]);
+ sin_dnodes[i].maxs[j] = LittleShort (sin_dnodes[i].maxs[j]);
+ }
+ sin_dnodes[i].children[0] = LittleLong (sin_dnodes[i].children[0]);
+ sin_dnodes[i].children[1] = LittleLong (sin_dnodes[i].children[1]);
+#ifdef SIN
+ sin_dnodes[i].firstface = LittleUnsignedShort (sin_dnodes[i].firstface);
+ sin_dnodes[i].numfaces = LittleUnsignedShort (sin_dnodes[i].numfaces);
+#else
+ sin_dnodes[i].firstface = LittleShort (sin_dnodes[i].firstface);
+ sin_dnodes[i].numfaces = LittleShort (sin_dnodes[i].numfaces);
+#endif
+ }
+
+//
+// leafs
+//
+ for (i=0 ; i<sin_numleafs ; i++)
+ {
+ sin_dleafs[i].contents = LittleLong (sin_dleafs[i].contents);
+ sin_dleafs[i].cluster = LittleShort (sin_dleafs[i].cluster);
+ sin_dleafs[i].area = LittleShort (sin_dleafs[i].area);
+ for (j=0 ; j<3 ; j++)
+ {
+ sin_dleafs[i].mins[j] = LittleShort (sin_dleafs[i].mins[j]);
+ sin_dleafs[i].maxs[j] = LittleShort (sin_dleafs[i].maxs[j]);
+ }
+#ifdef SIN
+ sin_dleafs[i].firstleafface = LittleUnsignedShort (sin_dleafs[i].firstleafface);
+ sin_dleafs[i].numleaffaces = LittleUnsignedShort (sin_dleafs[i].numleaffaces);
+ sin_dleafs[i].firstleafbrush = LittleUnsignedShort (sin_dleafs[i].firstleafbrush);
+ sin_dleafs[i].numleafbrushes = LittleUnsignedShort (sin_dleafs[i].numleafbrushes);
+#else
+ sin_dleafs[i].firstleafface = LittleShort (sin_dleafs[i].firstleafface);
+ sin_dleafs[i].numleaffaces = LittleShort (sin_dleafs[i].numleaffaces);
+ sin_dleafs[i].firstleafbrush = LittleShort (sin_dleafs[i].firstleafbrush);
+ sin_dleafs[i].numleafbrushes = LittleShort (sin_dleafs[i].numleafbrushes);
+#endif
+ }
+
+//
+// leaffaces
+//
+ for (i=0 ; i<sin_numleaffaces ; i++)
+ sin_dleaffaces[i] = LittleShort (sin_dleaffaces[i]);
+
+//
+// leafbrushes
+//
+ for (i=0 ; i<sin_numleafbrushes ; i++)
+ sin_dleafbrushes[i] = LittleShort (sin_dleafbrushes[i]);
+
+//
+// surfedges
+//
+ for (i=0 ; i<sin_numsurfedges ; i++)
+ sin_dsurfedges[i] = LittleLong (sin_dsurfedges[i]);
+
+//
+// edges
+//
+ for (i=0 ; i<sin_numedges ; i++)
+ {
+#ifdef SIN
+ sin_dedges[i].v[0] = LittleUnsignedShort (sin_dedges[i].v[0]);
+ sin_dedges[i].v[1] = LittleUnsignedShort (sin_dedges[i].v[1]);
+#else
+ sin_dedges[i].v[0] = LittleShort (sin_dedges[i].v[0]);
+ sin_dedges[i].v[1] = LittleShort (sin_dedges[i].v[1]);
+#endif
+ }
+
+//
+// brushes
+//
+ for (i=0 ; i<sin_numbrushes ; i++)
+ {
+ sin_dbrushes[i].firstside = LittleLong (sin_dbrushes[i].firstside);
+ sin_dbrushes[i].numsides = LittleLong (sin_dbrushes[i].numsides);
+ sin_dbrushes[i].contents = LittleLong (sin_dbrushes[i].contents);
+ }
+
+//
+// areas
+//
+ for (i=0 ; i<sin_numareas ; i++)
+ {
+ sin_dareas[i].numareaportals = LittleLong (sin_dareas[i].numareaportals);
+ sin_dareas[i].firstareaportal = LittleLong (sin_dareas[i].firstareaportal);
+ }
+
+//
+// areasportals
+//
+ for (i=0 ; i<sin_numareaportals ; i++)
+ {
+ sin_dareaportals[i].portalnum = LittleLong (sin_dareaportals[i].portalnum);
+ sin_dareaportals[i].otherarea = LittleLong (sin_dareaportals[i].otherarea);
+ }
+
+//
+// brushsides
+//
+ for (i=0 ; i<sin_numbrushsides ; i++)
+ {
+#ifdef SIN
+ sin_dbrushsides[i].planenum = LittleUnsignedShort (sin_dbrushsides[i].planenum);
+#else
+ sin_dbrushsides[i].planenum = LittleShort (sin_dbrushsides[i].planenum);
+#endif
+ sin_dbrushsides[i].texinfo = LittleShort (sin_dbrushsides[i].texinfo);
+#ifdef SIN
+ sin_dbrushsides[i].lightinfo = LittleLong (sin_dbrushsides[i].lightinfo);
+#endif
+ }
+
+//
+// visibility
+//
+ if (todisk)
+ j = sin_dvis->numclusters;
+ else
+ j = LittleLong(sin_dvis->numclusters);
+ sin_dvis->numclusters = LittleLong (sin_dvis->numclusters);
+ for (i=0 ; i<j ; i++)
+ {
+ sin_dvis->bitofs[i][0] = LittleLong (sin_dvis->bitofs[i][0]);
+ sin_dvis->bitofs[i][1] = LittleLong (sin_dvis->bitofs[i][1]);
+ }
+} //end of the function Sin_SwapBSPFile
+
+
+sin_dheader_t *header;
+#ifdef SIN
+int Sin_CopyLump (int lump, void *dest, int size, int maxsize)
+{
+ int length, ofs;
+
+ length = header->lumps[lump].filelen;
+ ofs = header->lumps[lump].fileofs;
+
+ if (length % size)
+ Error ("Sin_LoadBSPFile: odd lump size");
+
+ if ((length/size) > maxsize)
+ Error ("Sin_LoadBSPFile: exceeded max size for lump %d size %d > maxsize %d\n", lump, (length/size), maxsize );
+
+ memcpy (dest, (byte *)header + ofs, length);
+
+ return length / size;
+}
+#else
+int Sin_CopyLump (int lump, void *dest, int size)
+{
+ int length, ofs;
+
+ length = header->lumps[lump].filelen;
+ ofs = header->lumps[lump].fileofs;
+
+ if (length % size)
+ Error ("Sin_LoadBSPFile: odd lump size");
+
+ memcpy (dest, (byte *)header + ofs, length);
+
+ return length / size;
+}
+#endif
+
+/*
+=============
+Sin_LoadBSPFile
+=============
+*/
+void Sin_LoadBSPFile(char *filename, int offset, int length)
+{
+ int i;
+
+//
+// load the file header
+//
+ LoadFile (filename, (void **)&header, offset, length);
+
+// swap the header
+ for (i=0 ; i< sizeof(sin_dheader_t)/4 ; i++)
+ ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
+
+ if (header->ident != SIN_BSPHEADER && header->ident != SINGAME_BSPHEADER)
+ Error ("%s is not a IBSP file", filename);
+ if (header->version != SIN_BSPVERSION && header->version != SINGAME_BSPVERSION)
+ Error ("%s is version %i, not %i", filename, header->version, SIN_BSPVERSION);
+
+#ifdef SIN
+ sin_nummodels = Sin_CopyLump (SIN_LUMP_MODELS, sin_dmodels, sizeof(sin_dmodel_t), SIN_MAX_MAP_MODELS);
+ sin_numvertexes = Sin_CopyLump (SIN_LUMP_VERTEXES, sin_dvertexes, sizeof(sin_dvertex_t), SIN_MAX_MAP_VERTS);
+ sin_numplanes = Sin_CopyLump (SIN_LUMP_PLANES, sin_dplanes, sizeof(sin_dplane_t), SIN_MAX_MAP_PLANES);
+ sin_numleafs = Sin_CopyLump (SIN_LUMP_LEAFS, sin_dleafs, sizeof(sin_dleaf_t), SIN_MAX_MAP_LEAFS);
+ sin_numnodes = Sin_CopyLump (SIN_LUMP_NODES, sin_dnodes, sizeof(sin_dnode_t), SIN_MAX_MAP_NODES);
+ sin_numtexinfo = Sin_CopyLump (SIN_LUMP_TEXINFO, sin_texinfo, sizeof(sin_texinfo_t), SIN_MAX_MAP_TEXINFO);
+ sin_numfaces = Sin_CopyLump (SIN_LUMP_FACES, sin_dfaces, sizeof(sin_dface_t), SIN_MAX_MAP_FACES);
+ sin_numleaffaces = Sin_CopyLump (SIN_LUMP_LEAFFACES, sin_dleaffaces, sizeof(sin_dleaffaces[0]), SIN_MAX_MAP_LEAFFACES);
+ sin_numleafbrushes = Sin_CopyLump (SIN_LUMP_LEAFBRUSHES, sin_dleafbrushes, sizeof(sin_dleafbrushes[0]), SIN_MAX_MAP_LEAFBRUSHES);
+ sin_numsurfedges = Sin_CopyLump (SIN_LUMP_SURFEDGES, sin_dsurfedges, sizeof(sin_dsurfedges[0]), SIN_MAX_MAP_SURFEDGES);
+ sin_numedges = Sin_CopyLump (SIN_LUMP_EDGES, sin_dedges, sizeof(sin_dedge_t), SIN_MAX_MAP_EDGES);
+ sin_numbrushes = Sin_CopyLump (SIN_LUMP_BRUSHES, sin_dbrushes, sizeof(sin_dbrush_t), SIN_MAX_MAP_BRUSHES);
+ sin_numbrushsides = Sin_CopyLump (SIN_LUMP_BRUSHSIDES, sin_dbrushsides, sizeof(sin_dbrushside_t), SIN_MAX_MAP_BRUSHSIDES);
+ sin_numareas = Sin_CopyLump (SIN_LUMP_AREAS, sin_dareas, sizeof(sin_darea_t), SIN_MAX_MAP_AREAS);
+ sin_numareaportals = Sin_CopyLump (SIN_LUMP_AREAPORTALS, sin_dareaportals, sizeof(sin_dareaportal_t), SIN_MAX_MAP_AREAPORTALS);
+ sin_numlightinfo = Sin_CopyLump (SIN_LUMP_LIGHTINFO, sin_lightinfo, sizeof(sin_lightvalue_t), SIN_MAX_MAP_LIGHTINFO);
+
+ sin_visdatasize = Sin_CopyLump (SIN_LUMP_VISIBILITY, sin_dvisdata, 1, SIN_MAX_MAP_VISIBILITY);
+ sin_lightdatasize = Sin_CopyLump (SIN_LUMP_LIGHTING, sin_dlightdata, 1, SIN_MAX_MAP_LIGHTING);
+ sin_entdatasize = Sin_CopyLump (SIN_LUMP_ENTITIES, sin_dentdata, 1, SIN_MAX_MAP_ENTSTRING);
+
+ Sin_CopyLump (SIN_LUMP_POP, sin_dpop, 1, sizeof(sin_dpop));
+#else
+ sin_nummodels = Sin_CopyLump (SIN_LUMP_MODELS, sin_dmodels, sizeof(sin_dmodel_t));
+ sin_numvertexes = Sin_CopyLump (SIN_LUMP_VERTEXES, sin_dvertexes, sizeof(sin_dvertex_t));
+ sin_numplanes = Sin_CopyLump (SIN_LUMP_PLANES, sin_dplanes, sizeof(sin_dplane_t));
+ sin_numleafs = Sin_CopyLump (SIN_LUMP_LEAFS, sin_dleafs, sizeof(sin_dleaf_t));
+ sin_numnodes = Sin_CopyLump (SIN_LUMP_NODES, sin_dnodes, sizeof(sin_dnode_t));
+ sin_numtexinfo = Sin_CopyLump (SIN_LUMP_TEXINFO, sin_texinfo, sizeof(sin_texinfo_t));
+ sin_numfaces = Sin_CopyLump (SIN_LUMP_FACES, sin_dfaces, sizeof(sin_dface_t));
+ sin_numleaffaces = Sin_CopyLump (SIN_LUMP_LEAFFACES, sin_dleaffaces, sizeof(sin_dleaffaces[0]));
+ sin_numleafbrushes = Sin_CopyLump (SIN_LUMP_LEAFBRUSHES, sin_dleafbrushes, sizeof(sin_dleafbrushes[0]));
+ sin_numsurfedges = Sin_CopyLump (SIN_LUMP_SURFEDGES, sin_dsurfedges, sizeof(sin_dsurfedges[0]));
+ sin_numedges = Sin_CopyLump (SIN_LUMP_EDGES, sin_dedges, sizeof(sin_dedge_t));
+ sin_numbrushes = Sin_CopyLump (SIN_LUMP_BRUSHES, sin_dbrushes, sizeof(sin_dbrush_t));
+ sin_numbrushsides = Sin_CopyLump (SIN_LUMP_BRUSHSIDES, sin_dbrushsides, sizeof(sin_dbrushside_t));
+ sin_numareas = Sin_CopyLump (SIN_LUMP_AREAS, sin_dareas, sizeof(sin_darea_t));
+ sin_numareaportals = Sin_CopyLump (SIN_LUMP_AREAPORTALS, sin_dareaportals, sizeof(sin_dareaportal_t));
+
+ sin_visdatasize = Sin_CopyLump (SIN_LUMP_VISIBILITY, sin_dvisdata, 1);
+ sin_lightdatasize = Sin_CopyLump (SIN_LUMP_LIGHTING, sin_dlightdata, 1);
+ sin_entdatasize = Sin_CopyLump (SIN_LUMP_ENTITIES, sin_dentdata, 1);
+
+ Sin_CopyLump (SIN_LUMP_POP, sin_dpop, 1);
+#endif
+
+ FreeMemory(header); // everything has been copied out
+
+//
+// swap everything
+//
+ Sin_SwapBSPFile (false);
+} //end of the function Sin_LoadBSPFile
+
+/*
+=============
+Sin_LoadBSPFilesTexinfo
+
+Only loads the sin_texinfo lump, so qdata can scan for textures
+=============
+*/
+void Sin_LoadBSPFileTexinfo (char *filename)
+{
+ int i;
+ FILE *f;
+ int length, ofs;
+
+ header = GetMemory(sizeof(sin_dheader_t));
+
+ f = fopen (filename, "rb");
+ fread (header, sizeof(sin_dheader_t), 1, f);
+
+// swap the header
+ for (i=0 ; i< sizeof(sin_dheader_t)/4 ; i++)
+ ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
+
+ if (header->ident != SIN_BSPHEADER && header->ident != SINGAME_BSPHEADER)
+ Error ("%s is not a IBSP file", filename);
+ if (header->version != SIN_BSPVERSION && header->version != SINGAME_BSPVERSION)
+ Error ("%s is version %i, not %i", filename, header->version, SIN_BSPVERSION);
+
+
+ length = header->lumps[SIN_LUMP_TEXINFO].filelen;
+ ofs = header->lumps[SIN_LUMP_TEXINFO].fileofs;
+
+ fseek (f, ofs, SEEK_SET);
+ fread (sin_texinfo, length, 1, f);
+ fclose (f);
+
+ sin_numtexinfo = length / sizeof(sin_texinfo_t);
+
+ FreeMemory(header); // everything has been copied out
+
+ Sin_SwapBSPFile (false);
+} //end of the function Sin_LoadBSPFilesTexinfo
+
+
+//============================================================================
+
+FILE *wadfile;
+sin_dheader_t outheader;
+
+#ifdef SIN
+void Sin_AddLump (int lumpnum, void *data, int len, int size, int maxsize)
+{
+ sin_lump_t *lump;
+ int totallength;
+
+ totallength = len*size;
+
+ if (len > maxsize)
+ Error ("Sin_WriteBSPFile: exceeded max size for lump %d size %d > maxsize %d\n", lumpnum, len, maxsize );
+
+ lump = &header->lumps[lumpnum];
+
+ lump->fileofs = LittleLong( ftell(wadfile) );
+ lump->filelen = LittleLong(totallength);
+ SafeWrite (wadfile, data, (totallength+3)&~3);
+}
+#else
+void Sin_AddLump (int lumpnum, void *data, int len)
+{
+ sin_lump_t *lump;
+
+ lump = &header->lumps[lumpnum];
+
+ lump->fileofs = LittleLong( ftell(wadfile) );
+ lump->filelen = LittleLong(len);
+ SafeWrite (wadfile, data, (len+3)&~3);
+}
+#endif
+/*
+=============
+Sin_WriteBSPFile
+
+Swaps the bsp file in place, so it should not be referenced again
+=============
+*/
+void Sin_WriteBSPFile (char *filename)
+{
+ header = &outheader;
+ memset (header, 0, sizeof(sin_dheader_t));
+
+ Sin_SwapBSPFile (true);
+
+ header->ident = LittleLong (SIN_BSPHEADER);
+ header->version = LittleLong (SIN_BSPVERSION);
+
+ wadfile = SafeOpenWrite (filename);
+ SafeWrite (wadfile, header, sizeof(sin_dheader_t)); // overwritten later
+
+#ifdef SIN
+ Sin_AddLump (SIN_LUMP_PLANES, sin_dplanes, sin_numplanes, sizeof(sin_dplane_t), SIN_MAX_MAP_PLANES);
+ Sin_AddLump (SIN_LUMP_LEAFS, sin_dleafs, sin_numleafs, sizeof(sin_dleaf_t), SIN_MAX_MAP_LEAFS);
+ Sin_AddLump (SIN_LUMP_VERTEXES, sin_dvertexes, sin_numvertexes, sizeof(sin_dvertex_t), SIN_MAX_MAP_VERTS);
+ Sin_AddLump (SIN_LUMP_NODES, sin_dnodes, sin_numnodes, sizeof(sin_dnode_t), SIN_MAX_MAP_NODES);
+ Sin_AddLump (SIN_LUMP_TEXINFO, sin_texinfo, sin_numtexinfo, sizeof(sin_texinfo_t), SIN_MAX_MAP_TEXINFO);
+ Sin_AddLump (SIN_LUMP_FACES, sin_dfaces, sin_numfaces, sizeof(sin_dface_t), SIN_MAX_MAP_FACES);
+ Sin_AddLump (SIN_LUMP_BRUSHES, sin_dbrushes, sin_numbrushes, sizeof(sin_dbrush_t), SIN_MAX_MAP_BRUSHES);
+ Sin_AddLump (SIN_LUMP_BRUSHSIDES, sin_dbrushsides, sin_numbrushsides, sizeof(sin_dbrushside_t), SIN_MAX_MAP_BRUSHSIDES);
+ Sin_AddLump (SIN_LUMP_LEAFFACES, sin_dleaffaces, sin_numleaffaces, sizeof(sin_dleaffaces[0]), SIN_MAX_MAP_LEAFFACES);
+ Sin_AddLump (SIN_LUMP_LEAFBRUSHES, sin_dleafbrushes, sin_numleafbrushes, sizeof(sin_dleafbrushes[0]), SIN_MAX_MAP_LEAFBRUSHES);
+ Sin_AddLump (SIN_LUMP_SURFEDGES, sin_dsurfedges, sin_numsurfedges, sizeof(sin_dsurfedges[0]), SIN_MAX_MAP_SURFEDGES);
+ Sin_AddLump (SIN_LUMP_EDGES, sin_dedges, sin_numedges, sizeof(sin_dedge_t), SIN_MAX_MAP_EDGES);
+ Sin_AddLump (SIN_LUMP_MODELS, sin_dmodels, sin_nummodels, sizeof(sin_dmodel_t), SIN_MAX_MAP_MODELS);
+ Sin_AddLump (SIN_LUMP_AREAS, sin_dareas, sin_numareas, sizeof(sin_darea_t), SIN_MAX_MAP_AREAS);
+ Sin_AddLump (SIN_LUMP_AREAPORTALS, sin_dareaportals, sin_numareaportals, sizeof(sin_dareaportal_t), SIN_MAX_MAP_AREAPORTALS);
+ Sin_AddLump (SIN_LUMP_LIGHTINFO, sin_lightinfo, sin_numlightinfo, sizeof(sin_lightvalue_t), SIN_MAX_MAP_LIGHTINFO);
+
+ Sin_AddLump (SIN_LUMP_LIGHTING, sin_dlightdata, sin_lightdatasize, 1, SIN_MAX_MAP_LIGHTING);
+ Sin_AddLump (SIN_LUMP_VISIBILITY, sin_dvisdata, sin_visdatasize, 1, SIN_MAX_MAP_VISIBILITY);
+ Sin_AddLump (SIN_LUMP_ENTITIES, sin_dentdata, sin_entdatasize, 1, SIN_MAX_MAP_ENTSTRING);
+ Sin_AddLump (SIN_LUMP_POP, sin_dpop, sizeof(sin_dpop), 1, sizeof(sin_dpop));
+#else
+ Sin_AddLump (SIN_LUMP_PLANES, sin_dplanes, sin_numplanes*sizeof(sin_dplane_t));
+ Sin_AddLump (SIN_LUMP_LEAFS, sin_dleafs, sin_numleafs*sizeof(sin_dleaf_t));
+ Sin_AddLump (SIN_LUMP_VERTEXES, sin_dvertexes, sin_numvertexes*sizeof(sin_dvertex_t));
+ Sin_AddLump (SIN_LUMP_NODES, sin_dnodes, sin_numnodes*sizeof(sin_dnode_t));
+ Sin_AddLump (SIN_LUMP_TEXINFO, sin_texinfo, sin_numtexinfo*sizeof(sin_texinfo_t));
+ Sin_AddLump (SIN_LUMP_FACES, sin_dfaces, sin_numfaces*sizeof(sin_dface_t));
+ Sin_AddLump (SIN_LUMP_BRUSHES, sin_dbrushes, sin_numbrushes*sizeof(sin_dbrush_t));
+ Sin_AddLump (SIN_LUMP_BRUSHSIDES, sin_dbrushsides, sin_numbrushsides*sizeof(sin_dbrushside_t));
+ Sin_AddLump (SIN_LUMP_LEAFFACES, sin_dleaffaces, sin_numleaffaces*sizeof(sin_dleaffaces[0]));
+ Sin_AddLump (SIN_LUMP_LEAFBRUSHES, sin_dleafbrushes, sin_numleafbrushes*sizeof(sin_dleafbrushes[0]));
+ Sin_AddLump (SIN_LUMP_SURFEDGES, sin_dsurfedges, sin_numsurfedges*sizeof(sin_dsurfedges[0]));
+ Sin_AddLump (SIN_LUMP_EDGES, sin_dedges, sin_numedges*sizeof(sin_dedge_t));
+ Sin_AddLump (SIN_LUMP_MODELS, sin_dmodels, sin_nummodels*sizeof(sin_dmodel_t));
+ Sin_AddLump (SIN_LUMP_AREAS, sin_dareas, sin_numareas*sizeof(sin_darea_t));
+ Sin_AddLump (SIN_LUMP_AREAPORTALS, sin_dareaportals, sin_numareaportals*sizeof(sin_dareaportal_t));
+
+ Sin_AddLump (SIN_LUMP_LIGHTING, sin_dlightdata, sin_lightdatasize);
+ Sin_AddLump (SIN_LUMP_VISIBILITY, sin_dvisdata, sin_visdatasize);
+ Sin_AddLump (SIN_LUMP_ENTITIES, sin_dentdata, sin_entdatasize);
+ Sin_AddLump (SIN_LUMP_POP, sin_dpop, sizeof(sin_dpop));
+#endif
+
+ fseek (wadfile, 0, SEEK_SET);
+ SafeWrite (wadfile, header, sizeof(sin_dheader_t));
+ fclose (wadfile);
+}
+
+//============================================================================
+
+
+//============================================
+
+/*
+================
+ParseEntities
+
+Parses the sin_dentdata string into entities
+================
+*/
+void Sin_ParseEntities (void)
+{
+ script_t *script;
+
+ num_entities = 0;
+ script = LoadScriptMemory(sin_dentdata, sin_entdatasize, "*sin bsp file");
+ SetScriptFlags(script, SCFL_NOSTRINGWHITESPACES |
+ SCFL_NOSTRINGESCAPECHARS);
+
+ while(ParseEntity(script))
+ {
+ } //end while
+
+ FreeScript(script);
+} //end of the function Sin_ParseEntities
+
+
+/*
+================
+UnparseEntities
+
+Generates the sin_dentdata string from all the entities
+================
+*/
+void Sin_UnparseEntities (void)
+{
+ char *buf, *end;
+ epair_t *ep;
+ char line[2048];
+ int i;
+ char key[1024], value[1024];
+
+ buf = sin_dentdata;
+ end = buf;
+ *end = 0;
+
+ for (i=0 ; i<num_entities ; i++)
+ {
+ ep = entities[i].epairs;
+ if (!ep)
+ continue; // ent got removed
+
+ strcat (end,"{\n");
+ end += 2;
+
+ for (ep = entities[i].epairs ; ep ; ep=ep->next)
+ {
+ strcpy (key, ep->key);
+ StripTrailing (key);
+ strcpy (value, ep->value);
+ StripTrailing (value);
+
+ sprintf (line, "\"%s\" \"%s\"\n", key, value);
+ strcat (end, line);
+ end += strlen(line);
+ }
+ strcat (end,"}\n");
+ end += 2;
+
+ if (end > buf + SIN_MAX_MAP_ENTSTRING)
+ Error ("Entity text too long");
+ }
+ sin_entdatasize = end - buf + 1;
+} //end of the function Sin_UnparseEntities
+
+#ifdef SIN
+void FreeValueKeys(entity_t *ent)
+{
+ epair_t *ep,*next;
+
+ for (ep=ent->epairs ; ep ; ep=next)
+ {
+ next = ep->next;
+ FreeMemory(ep->value);
+ FreeMemory(ep->key);
+ FreeMemory(ep);
+ }
+ ent->epairs = NULL;
+}
+#endif
+
+/*
+=============
+Sin_PrintBSPFileSizes
+
+Dumps info about current file
+=============
+*/
+void Sin_PrintBSPFileSizes (void)
+{
+ if (!num_entities)
+ Sin_ParseEntities ();
+
+ Log_Print("%6i models %7i\n"
+ ,sin_nummodels, (int)(sin_nummodels*sizeof(sin_dmodel_t)));
+ Log_Print("%6i brushes %7i\n"
+ ,sin_numbrushes, (int)(sin_numbrushes*sizeof(sin_dbrush_t)));
+ Log_Print("%6i brushsides %7i\n"
+ ,sin_numbrushsides, (int)(sin_numbrushsides*sizeof(sin_dbrushside_t)));
+ Log_Print("%6i planes %7i\n"
+ ,sin_numplanes, (int)(sin_numplanes*sizeof(sin_dplane_t)));
+ Log_Print("%6i texinfo %7i\n"
+ ,sin_numtexinfo, (int)(sin_numtexinfo*sizeof(sin_texinfo_t)));
+#ifdef SIN
+ Log_Print("%6i lightinfo %7i\n"
+ ,sin_numlightinfo, (int)(sin_numlightinfo*sizeof(sin_lightvalue_t)));
+#endif
+ Log_Print("%6i entdata %7i\n", num_entities, sin_entdatasize);
+
+ Log_Print("\n");
+
+ Log_Print("%6i vertexes %7i\n"
+ ,sin_numvertexes, (int)(sin_numvertexes*sizeof(sin_dvertex_t)));
+ Log_Print("%6i nodes %7i\n"
+ ,sin_numnodes, (int)(sin_numnodes*sizeof(sin_dnode_t)));
+ Log_Print("%6i faces %7i\n"
+ ,sin_numfaces, (int)(sin_numfaces*sizeof(sin_dface_t)));
+ Log_Print("%6i leafs %7i\n"
+ ,sin_numleafs, (int)(sin_numleafs*sizeof(sin_dleaf_t)));
+ Log_Print("%6i leaffaces %7i\n"
+ ,sin_numleaffaces, (int)(sin_numleaffaces*sizeof(sin_dleaffaces[0])));
+ Log_Print("%6i leafbrushes %7i\n"
+ ,sin_numleafbrushes, (int)(sin_numleafbrushes*sizeof(sin_dleafbrushes[0])));
+ Log_Print("%6i surfedges %7i\n"
+ ,sin_numsurfedges, (int)(sin_numsurfedges*sizeof(sin_dsurfedges[0])));
+ Log_Print("%6i edges %7i\n"
+ ,sin_numedges, (int)(sin_numedges*sizeof(sin_dedge_t)));
+ Log_Print(" lightdata %7i\n", sin_lightdatasize);
+ Log_Print(" visdata %7i\n", sin_visdatasize);
+}
diff --git a/code/bspc/l_bsp_sin.h b/code/bspc/l_bsp_sin.h
index 93cb69f..862674b 100755
--- a/code/bspc/l_bsp_sin.h
+++ b/code/bspc/l_bsp_sin.h
@@ -1,106 +1,106 @@
-/*
-===========================================================================
-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 "sinfiles.h"
-
-#define SINGAME_BSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'R') //RBSP
-#define SINGAME_BSPVERSION 1
-
-#define SIN_BSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I') //IBSP
-#define SIN_BSPVERSION 41
-
-
-extern int sin_nummodels;
-extern sin_dmodel_t *sin_dmodels;//[MAX_MAP_MODELS];
-
-extern int sin_visdatasize;
-extern byte *sin_dvisdata;//[MAX_MAP_VISIBILITY];
-extern sin_dvis_t *sin_dvis;// = (dvis_t *)sin_sin_dvisdata;
-
-extern int sin_lightdatasize;
-extern byte *sin_dlightdata;//[MAX_MAP_LIGHTING];
-
-extern int sin_entdatasize;
-extern char *sin_dentdata;//[MAX_MAP_ENTSTRING];
-
-extern int sin_numleafs;
-extern sin_dleaf_t *sin_dleafs;//[MAX_MAP_LEAFS];
-
-extern int sin_numplanes;
-extern sin_dplane_t *sin_dplanes;//[MAX_MAP_PLANES];
-
-extern int sin_numvertexes;
-extern sin_dvertex_t *sin_dvertexes;//[MAX_MAP_VERTS];
-
-extern int sin_numnodes;
-extern sin_dnode_t *sin_dnodes;//[MAX_MAP_NODES];
-
-extern int sin_numtexinfo;
-extern sin_texinfo_t *sin_texinfo;//[MAX_MAP_sin_texinfo];
-
-extern int sin_numfaces;
-extern sin_dface_t *sin_dfaces;//[MAX_MAP_FACES];
-
-extern int sin_numedges;
-extern sin_dedge_t *sin_dedges;//[MAX_MAP_EDGES];
-
-extern int sin_numleaffaces;
-extern unsigned short *sin_dleaffaces;//[MAX_MAP_LEAFFACES];
-
-extern int sin_numleafbrushes;
-extern unsigned short *sin_dleafbrushes;//[MAX_MAP_LEAFBRUSHES];
-
-extern int sin_numsurfedges;
-extern int *sin_dsurfedges;//[MAX_MAP_SURFEDGES];
-
-extern int sin_numbrushes;
-extern sin_dbrush_t *sin_dbrushes;//[MAX_MAP_BRUSHES];
-
-extern int sin_numbrushsides;
-extern sin_dbrushside_t *sin_dbrushsides;//[MAX_MAP_BRUSHSIDES];
-
-extern int sin_numareas;
-extern sin_darea_t *sin_dareas;//[MAX_MAP_AREAS];
-
-extern int sin_numareaportals;
-extern sin_dareaportal_t *sin_dareaportals;//[MAX_MAP_AREAPORTALS];
-
-extern int sin_numlightinfo;
-extern sin_lightvalue_t *sin_lightinfo;//[MAX_MAP_LIGHTINFO];
-
-extern byte sin_dpop[256];
-
-extern char sin_dbrushsidetextured[SIN_MAX_MAP_BRUSHSIDES];
-
-void Sin_AllocMaxBSP(void);
-void Sin_FreeMaxBSP(void);
-
-void Sin_DecompressVis(byte *in, byte *decompressed);
-int Sin_CompressVis(byte *vis, byte *dest);
-
-void Sin_LoadBSPFile (char *filename, int offset, int length);
-void Sin_LoadBSPFileTexinfo (char *filename); // just for qdata
-void Sin_WriteBSPFile (char *filename);
-void Sin_PrintBSPFileSizes (void);
-void Sin_ParseEntities(void);
-void Sin_UnparseEntities(void);
-
+/*
+===========================================================================
+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 "sinfiles.h"
+
+#define SINGAME_BSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'R') //RBSP
+#define SINGAME_BSPVERSION 1
+
+#define SIN_BSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I') //IBSP
+#define SIN_BSPVERSION 41
+
+
+extern int sin_nummodels;
+extern sin_dmodel_t *sin_dmodels;//[MAX_MAP_MODELS];
+
+extern int sin_visdatasize;
+extern byte *sin_dvisdata;//[MAX_MAP_VISIBILITY];
+extern sin_dvis_t *sin_dvis;// = (dvis_t *)sin_sin_dvisdata;
+
+extern int sin_lightdatasize;
+extern byte *sin_dlightdata;//[MAX_MAP_LIGHTING];
+
+extern int sin_entdatasize;
+extern char *sin_dentdata;//[MAX_MAP_ENTSTRING];
+
+extern int sin_numleafs;
+extern sin_dleaf_t *sin_dleafs;//[MAX_MAP_LEAFS];
+
+extern int sin_numplanes;
+extern sin_dplane_t *sin_dplanes;//[MAX_MAP_PLANES];
+
+extern int sin_numvertexes;
+extern sin_dvertex_t *sin_dvertexes;//[MAX_MAP_VERTS];
+
+extern int sin_numnodes;
+extern sin_dnode_t *sin_dnodes;//[MAX_MAP_NODES];
+
+extern int sin_numtexinfo;
+extern sin_texinfo_t *sin_texinfo;//[MAX_MAP_sin_texinfo];
+
+extern int sin_numfaces;
+extern sin_dface_t *sin_dfaces;//[MAX_MAP_FACES];
+
+extern int sin_numedges;
+extern sin_dedge_t *sin_dedges;//[MAX_MAP_EDGES];
+
+extern int sin_numleaffaces;
+extern unsigned short *sin_dleaffaces;//[MAX_MAP_LEAFFACES];
+
+extern int sin_numleafbrushes;
+extern unsigned short *sin_dleafbrushes;//[MAX_MAP_LEAFBRUSHES];
+
+extern int sin_numsurfedges;
+extern int *sin_dsurfedges;//[MAX_MAP_SURFEDGES];
+
+extern int sin_numbrushes;
+extern sin_dbrush_t *sin_dbrushes;//[MAX_MAP_BRUSHES];
+
+extern int sin_numbrushsides;
+extern sin_dbrushside_t *sin_dbrushsides;//[MAX_MAP_BRUSHSIDES];
+
+extern int sin_numareas;
+extern sin_darea_t *sin_dareas;//[MAX_MAP_AREAS];
+
+extern int sin_numareaportals;
+extern sin_dareaportal_t *sin_dareaportals;//[MAX_MAP_AREAPORTALS];
+
+extern int sin_numlightinfo;
+extern sin_lightvalue_t *sin_lightinfo;//[MAX_MAP_LIGHTINFO];
+
+extern byte sin_dpop[256];
+
+extern char sin_dbrushsidetextured[SIN_MAX_MAP_BRUSHSIDES];
+
+void Sin_AllocMaxBSP(void);
+void Sin_FreeMaxBSP(void);
+
+void Sin_DecompressVis(byte *in, byte *decompressed);
+int Sin_CompressVis(byte *vis, byte *dest);
+
+void Sin_LoadBSPFile (char *filename, int offset, int length);
+void Sin_LoadBSPFileTexinfo (char *filename); // just for qdata
+void Sin_WriteBSPFile (char *filename);
+void Sin_PrintBSPFileSizes (void);
+void Sin_ParseEntities(void);
+void Sin_UnparseEntities(void);
+
diff --git a/code/bspc/l_cmd.c b/code/bspc/l_cmd.c
index 35fef7b..e35104b 100755
--- a/code/bspc/l_cmd.c
+++ b/code/bspc/l_cmd.c
@@ -1,1230 +1,1230 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-
-// cmdlib.c
-
-#include "l_cmd.h"
-#include "l_log.h"
-#include "l_mem.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#ifndef SIN
-#define SIN
-#endif //SIN
-
-#if defined(WIN32) || defined(_WIN32)
-#include <direct.h>
-#else
-#include <unistd.h>
-#endif
-
-#ifdef NeXT
-#include <libc.h>
-#endif
-
-#define BASEDIRNAME "quake2"
-#define PATHSEPERATOR '/'
-
-// set these before calling CheckParm
-int myargc;
-char **myargv;
-
-char com_token[1024];
-qboolean com_eof;
-
-qboolean archive;
-char archivedir[1024];
-
-
-/*
-===================
-ExpandWildcards
-
-Mimic unix command line expansion
-===================
-*/
-#define MAX_EX_ARGC 1024
-int ex_argc;
-char *ex_argv[MAX_EX_ARGC];
-#ifdef _WIN32
-#include "io.h"
-void ExpandWildcards (int *argc, char ***argv)
-{
- struct _finddata_t fileinfo;
- int handle;
- int i;
- char filename[1024];
- char filebase[1024];
- char *path;
-
- ex_argc = 0;
- for (i=0 ; i<*argc ; i++)
- {
- path = (*argv)[i];
- if ( path[0] == '-'
- || ( !strstr(path, "*") && !strstr(path, "?") ) )
- {
- ex_argv[ex_argc++] = path;
- continue;
- }
-
- handle = _findfirst (path, &fileinfo);
- if (handle == -1)
- return;
-
- ExtractFilePath (path, filebase);
-
- do
- {
- sprintf (filename, "%s%s", filebase, fileinfo.name);
- ex_argv[ex_argc++] = copystring (filename);
- } while (_findnext( handle, &fileinfo ) != -1);
-
- _findclose (handle);
- }
-
- *argc = ex_argc;
- *argv = ex_argv;
-}
-#else
-void ExpandWildcards (int *argc, char ***argv)
-{
-}
-#endif
-
-#ifdef WINBSPC
-
-#include <windows.h>
-
-HWND program_hwnd;
-
-void SetProgramHandle(HWND hwnd)
-{
- program_hwnd = hwnd;
-} //end of the function SetProgramHandle
-
-/*
-=================
-Error
-
-For abnormal program terminations in windowed apps
-=================
-*/
-void Error (char *error, ...)
-{
- va_list argptr;
- char text[1024];
- char text2[1024];
- int err;
-
- err = GetLastError ();
-
- va_start(argptr, error);
- vsprintf(text, error, argptr);
- va_end(argptr);
-
- sprintf(text2, "%s\nGetLastError() = %i", text, err);
- MessageBox(program_hwnd, text2, "Error", 0 /* MB_OK */ );
-
- Log_Write(text);
- Log_Close();
-
- exit(1);
-} //end of the function Error
-
-void Warning(char *szFormat, ...)
-{
- char szBuffer[256];
- va_list argptr;
-
- va_start (argptr, szFormat);
- vsprintf(szBuffer, szFormat, argptr);
- va_end (argptr);
-
- MessageBox(program_hwnd, szBuffer, "Warning", MB_OK);
-
- Log_Write(szBuffer);
-} //end of the function Warning
-
-
-#else
-/*
-=================
-Error
-
-For abnormal program terminations in console apps
-=================
-*/
-void Error (char *error, ...)
-{
- va_list argptr;
- char text[1024];
-
- va_start(argptr, error);
- vsprintf(text, error, argptr);
- va_end(argptr);
- printf("ERROR: %s\n", text);
-
- Log_Write(text);
- Log_Close();
-
- exit (1);
-} //end of the function Error
-
-void Warning(char *warning, ...)
-{
- va_list argptr;
- char text[1024];
-
- va_start(argptr, warning);
- vsprintf(text, warning, argptr);
- va_end(argptr);
- printf("WARNING: %s\n", text);
-
- Log_Write(text);
-} //end of the function Warning
-
-#endif
-
-//only printf if in verbose mode
-qboolean verbose = true;
-
-void qprintf(char *format, ...)
-{
- va_list argptr;
-#ifdef WINBSPC
- char buf[2048];
-#endif //WINBSPC
-
- if (!verbose)
- return;
-
- va_start(argptr,format);
-#ifdef WINBSPC
- vsprintf(buf, format, argptr);
- WinBSPCPrint(buf);
-#else
- vprintf(format, argptr);
-#endif //WINBSPC
- va_end(argptr);
-} //end of the function qprintf
-
-void Com_Error(int level, char *error, ...)
-{
- va_list argptr;
- char text[1024];
-
- va_start(argptr, error);
- vsprintf(text, error, argptr);
- va_end(argptr);
- Error(text);
-} //end of the funcion Com_Error
-
-void Com_Printf( const char *fmt, ... )
-{
- va_list argptr;
- char text[1024];
-
- va_start(argptr, fmt);
- vsprintf(text, fmt, argptr);
- va_end(argptr);
- Log_Print(text);
-} //end of the funcion Com_Printf
-
-/*
-
-qdir will hold the path up to the quake directory, including the slash
-
- f:\quake\
- /raid/quake/
-
-gamedir will hold qdir + the game directory (id1, id2, etc)
-
- */
-
-char qdir[1024];
-char gamedir[1024];
-
-void SetQdirFromPath (char *path)
-{
- char temp[1024];
- char *c;
- int len;
-
- if (!(path[0] == '/' || path[0] == '\\' || path[1] == ':'))
- { // path is partial
- Q_getwd (temp);
- strcat (temp, path);
- path = temp;
- }
-
- // search for "quake2" in path
-
- len = strlen(BASEDIRNAME);
- for (c=path+strlen(path)-1 ; c != path ; c--)
- if (!Q_strncasecmp (c, BASEDIRNAME, len))
- {
- strncpy (qdir, path, c+len+1-path);
- qprintf ("qdir: %s\n", qdir);
- c += len+1;
- while (*c)
- {
- if (*c == '/' || *c == '\\')
- {
- strncpy (gamedir, path, c+1-path);
- qprintf ("gamedir: %s\n", gamedir);
- return;
- }
- c++;
- }
- Error ("No gamedir in %s", path);
- return;
- }
- Error ("SetQdirFromPath: no '%s' in %s", BASEDIRNAME, path);
-}
-
-char *ExpandArg (char *path)
-{
- static char full[1024];
-
- if (path[0] != '/' && path[0] != '\\' && path[1] != ':')
- {
- Q_getwd (full);
- strcat (full, path);
- }
- else
- strcpy (full, path);
- return full;
-}
-
-char *ExpandPath (char *path)
-{
- static char full[1024];
- if (!qdir)
- Error ("ExpandPath called without qdir set");
- if (path[0] == '/' || path[0] == '\\' || path[1] == ':')
- return path;
- sprintf (full, "%s%s", qdir, path);
- return full;
-}
-
-char *ExpandPathAndArchive (char *path)
-{
- char *expanded;
- char archivename[1024];
-
- expanded = ExpandPath (path);
-
- if (archive)
- {
- sprintf (archivename, "%s/%s", archivedir, path);
- QCopyFile (expanded, archivename);
- }
- return expanded;
-}
-
-
-char *copystring(char *s)
-{
- char *b;
- b = GetMemory(strlen(s)+1);
- strcpy (b, s);
- return b;
-}
-
-
-
-/*
-================
-I_FloatTime
-================
-*/
-double I_FloatTime (void)
-{
- time_t t;
-
- time (&t);
-
- return t;
-#if 0
-// more precise, less portable
- struct timeval tp;
- struct timezone tzp;
- static int secbase;
-
- gettimeofday(&tp, &tzp);
-
- if (!secbase)
- {
- secbase = tp.tv_sec;
- return tp.tv_usec/1000000.0;
- }
-
- return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0;
-#endif
-}
-
-void Q_getwd (char *out)
-{
-#if defined(WIN32) || defined(_WIN32)
- getcwd (out, 256);
- strcat (out, "\\");
-#else
- getwd(out);
- strcat(out, "/");
-#endif
-}
-
-
-void Q_mkdir (char *path)
-{
-#ifdef WIN32
- if (_mkdir (path) != -1)
- return;
-#else
- if (mkdir (path, 0777) != -1)
- return;
-#endif
- if (errno != EEXIST)
- Error ("mkdir %s: %s",path, strerror(errno));
-}
-
-/*
-============
-FileTime
-
-returns -1 if not present
-============
-*/
-int FileTime (char *path)
-{
- struct stat buf;
-
- if (stat (path,&buf) == -1)
- return -1;
-
- return buf.st_mtime;
-}
-
-
-
-/*
-==============
-COM_Parse
-
-Parse a token out of a string
-==============
-*/
-char *COM_Parse (char *data)
-{
- int c;
- int len;
-
- len = 0;
- com_token[0] = 0;
-
- if (!data)
- return NULL;
-
-// skip whitespace
-skipwhite:
- while ( (c = *data) <= ' ')
- {
- if (c == 0)
- {
- com_eof = true;
- return NULL; // end of file;
- }
- data++;
- }
-
-// skip // comments
- if (c=='/' && data[1] == '/')
- {
- while (*data && *data != '\n')
- data++;
- goto skipwhite;
- }
-
-
-// handle quoted strings specially
- if (c == '\"')
- {
- data++;
- do
- {
- c = *data++;
- if (c=='\"')
- {
- com_token[len] = 0;
- return data;
- }
- com_token[len] = c;
- len++;
- } while (1);
- }
-
-// parse single characters
- if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
- {
- com_token[len] = c;
- len++;
- com_token[len] = 0;
- return data+1;
- }
-
-// parse a regular word
- do
- {
- com_token[len] = c;
- data++;
- len++;
- c = *data;
- if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
- break;
- } while (c>32);
-
- com_token[len] = 0;
- return data;
-}
-
-
-int Q_strncasecmp (char *s1, char *s2, int n)
-{
- int c1, c2;
-
- do
- {
- c1 = *s1++;
- c2 = *s2++;
-
- if (!n--)
- return 0; // strings are equal until end point
-
- if (c1 != c2)
- {
- if (c1 >= 'a' && c1 <= 'z')
- c1 -= ('a' - 'A');
- if (c2 >= 'a' && c2 <= 'z')
- c2 -= ('a' - 'A');
- if (c1 != c2)
- return -1; // strings not equal
- }
- } while (c1);
-
- return 0; // strings are equal
-}
-
-int Q_strcasecmp (char *s1, char *s2)
-{
- return Q_strncasecmp (s1, s2, 99999);
-}
-
-int Q_stricmp (char *s1, char *s2)
-{
- return Q_strncasecmp (s1, s2, 99999);
-}
-
-void Q_strncpyz( char *dest, const char *src, int destsize ) {
- strncpy( dest, src, destsize-1 );
- dest[destsize-1] = 0;
-}
-
-char *strupr (char *start)
-{
- char *in;
- in = start;
- while (*in)
- {
- *in = toupper(*in);
- in++;
- }
- return start;
-}
-
-char *strlower (char *start)
-{
- char *in;
- in = start;
- while (*in)
- {
- *in = tolower(*in);
- in++;
- }
- return start;
-}
-
-
-/*
-=============================================================================
-
- MISC FUNCTIONS
-
-=============================================================================
-*/
-
-
-/*
-=================
-CheckParm
-
-Checks for the given parameter in the program's command line arguments
-Returns the argument number (1 to argc-1) or 0 if not present
-=================
-*/
-int CheckParm (char *check)
-{
- int i;
-
- for (i = 1;i<myargc;i++)
- {
- if ( !Q_strcasecmp(check, myargv[i]) )
- return i;
- }
-
- return 0;
-}
-
-
-
-/*
-================
-Q_filelength
-================
-*/
-int Q_filelength (FILE *f)
-{
- int pos;
- int end;
-
- pos = ftell (f);
- fseek (f, 0, SEEK_END);
- end = ftell (f);
- fseek (f, pos, SEEK_SET);
-
- return end;
-}
-
-
-FILE *SafeOpenWrite (char *filename)
-{
- FILE *f;
-
- f = fopen(filename, "wb");
-
- if (!f)
- Error ("Error opening %s: %s",filename,strerror(errno));
-
- return f;
-}
-
-FILE *SafeOpenRead (char *filename)
-{
- FILE *f;
-
- f = fopen(filename, "rb");
-
- if (!f)
- Error ("Error opening %s: %s",filename,strerror(errno));
-
- return f;
-}
-
-
-void SafeRead (FILE *f, void *buffer, int count)
-{
- if ( fread (buffer, 1, count, f) != (size_t)count)
- Error ("File read failure");
-}
-
-
-void SafeWrite (FILE *f, void *buffer, int count)
-{
- if (fwrite (buffer, 1, count, f) != (size_t)count)
- Error ("File write failure");
-}
-
-
-/*
-==============
-FileExists
-==============
-*/
-qboolean FileExists (char *filename)
-{
- FILE *f;
-
- f = fopen (filename, "r");
- if (!f)
- return false;
- fclose (f);
- return true;
-}
-
-/*
-==============
-LoadFile
-==============
-*/
-int LoadFile (char *filename, void **bufferptr, int offset, int length)
-{
- FILE *f;
- void *buffer;
-
- f = SafeOpenRead(filename);
- fseek(f, offset, SEEK_SET);
- if (!length) length = Q_filelength(f);
- buffer = GetMemory(length+1);
- ((char *)buffer)[length] = 0;
- SafeRead(f, buffer, length);
- fclose(f);
-
- *bufferptr = buffer;
- return length;
-}
-
-
-/*
-==============
-TryLoadFile
-
-Allows failure
-==============
-*/
-int TryLoadFile (char *filename, void **bufferptr)
-{
- FILE *f;
- int length;
- void *buffer;
-
- *bufferptr = NULL;
-
- f = fopen (filename, "rb");
- if (!f)
- return -1;
- length = Q_filelength (f);
- buffer = GetMemory(length+1);
- ((char *)buffer)[length] = 0;
- SafeRead (f, buffer, length);
- fclose (f);
-
- *bufferptr = buffer;
- return length;
-}
-
-
-/*
-==============
-SaveFile
-==============
-*/
-void SaveFile (char *filename, void *buffer, int count)
-{
- FILE *f;
-
- f = SafeOpenWrite (filename);
- SafeWrite (f, buffer, count);
- fclose (f);
-}
-
-
-
-void DefaultExtension (char *path, char *extension)
-{
- char *src;
-//
-// if path doesnt have a .EXT, append extension
-// (extension should include the .)
-//
- src = path + strlen(path) - 1;
-
- while (*src != PATHSEPERATOR && src != path)
- {
- if (*src == '.')
- return; // it has an extension
- src--;
- }
-
- strcat (path, extension);
-}
-
-
-void DefaultPath (char *path, char *basepath)
-{
- char temp[128];
-
- if (path[0] == PATHSEPERATOR)
- return; // absolute path location
- strcpy (temp,path);
- strcpy (path,basepath);
- strcat (path,temp);
-}
-
-
-void StripFilename (char *path)
-{
- int length;
-
- length = strlen(path)-1;
- while (length > 0 && path[length] != PATHSEPERATOR)
- length--;
- path[length] = 0;
-}
-
-void StripExtension (char *path)
-{
- int length;
-
- length = strlen(path)-1;
- while (length > 0 && path[length] != '.')
- {
- length--;
- if (path[length] == '/')
- return; // no extension
- }
- if (length)
- path[length] = 0;
-}
-
-
-/*
-====================
-Extract file parts
-====================
-*/
-// FIXME: should include the slash, otherwise
-// backing to an empty path will be wrong when appending a slash
-void ExtractFilePath (char *path, char *dest)
-{
- char *src;
-
- src = path + strlen(path) - 1;
-
-//
-// back up until a \ or the start
-//
- while (src != path && *(src-1) != '\\' && *(src-1) != '/')
- src--;
-
- memcpy (dest, path, src-path);
- dest[src-path] = 0;
-}
-
-void ExtractFileBase (char *path, char *dest)
-{
- char *src;
-
- src = path + strlen(path) - 1;
-
-//
-// back up until a \ or the start
-//
- while (src != path && *(src-1) != '\\' && *(src-1) != '/')
- src--;
-
- while (*src && *src != '.')
- {
- *dest++ = *src++;
- }
- *dest = 0;
-}
-
-void ExtractFileExtension (char *path, char *dest)
-{
- char *src;
-
- src = path + strlen(path) - 1;
-
-//
-// back up until a . or the start
-//
- while (src != path && *(src-1) != '.')
- src--;
- if (src == path)
- {
- *dest = 0; // no extension
- return;
- }
-
- strcpy (dest,src);
-}
-
-
-/*
-==============
-ParseNum / ParseHex
-==============
-*/
-int ParseHex (char *hex)
-{
- char *str;
- int num;
-
- num = 0;
- str = hex;
-
- while (*str)
- {
- num <<= 4;
- if (*str >= '0' && *str <= '9')
- num += *str-'0';
- else if (*str >= 'a' && *str <= 'f')
- num += 10 + *str-'a';
- else if (*str >= 'A' && *str <= 'F')
- num += 10 + *str-'A';
- else
- Error ("Bad hex number: %s",hex);
- str++;
- }
-
- return num;
-}
-
-
-int ParseNum (char *str)
-{
- if (str[0] == '$')
- return ParseHex (str+1);
- if (str[0] == '0' && str[1] == 'x')
- return ParseHex (str+2);
- return atol (str);
-}
-
-
-
-/*
-============================================================================
-
- BYTE ORDER FUNCTIONS
-
-============================================================================
-*/
-
-#ifdef _SGI_SOURCE
-#define __BIG_ENDIAN__
-#endif
-
-#ifdef __BIG_ENDIAN__
-
-short LittleShort (short l)
-{
- byte b1,b2;
-
- b1 = l&255;
- b2 = (l>>8)&255;
-
- return (b1<<8) + b2;
-}
-
-short BigShort (short l)
-{
- return l;
-}
-
-
-int LittleLong (int l)
-{
- byte b1,b2,b3,b4;
-
- b1 = l&255;
- b2 = (l>>8)&255;
- b3 = (l>>16)&255;
- b4 = (l>>24)&255;
-
- return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
-}
-
-int BigLong (int l)
-{
- return l;
-}
-
-
-float LittleFloat (float l)
-{
- union {byte b[4]; float f;} in, out;
-
- in.f = l;
- out.b[0] = in.b[3];
- out.b[1] = in.b[2];
- out.b[2] = in.b[1];
- out.b[3] = in.b[0];
-
- return out.f;
-}
-
-float BigFloat (float l)
-{
- return l;
-}
-
-#ifdef SIN
-unsigned short LittleUnsignedShort (unsigned short l)
-{
- byte b1,b2;
-
- b1 = l&255;
- b2 = (l>>8)&255;
-
- return (b1<<8) + b2;
-}
-
-unsigned short BigUnsignedShort (unsigned short l)
-{
- return l;
-}
-
-unsigned LittleUnsigned (unsigned l)
-{
- byte b1,b2,b3,b4;
-
- b1 = l&255;
- b2 = (l>>8)&255;
- b3 = (l>>16)&255;
- b4 = (l>>24)&255;
-
- return ((unsigned)b1<<24) + ((unsigned)b2<<16) + ((unsigned)b3<<8) + b4;
-}
-
-unsigned BigUnsigned (unsigned l)
-{
- return l;
-}
-#endif
-
-
-#else
-
-
-short BigShort (short l)
-{
- byte b1,b2;
-
- b1 = l&255;
- b2 = (l>>8)&255;
-
- return (b1<<8) + b2;
-}
-
-short LittleShort (short l)
-{
- return l;
-}
-
-
-int BigLong (int l)
-{
- byte b1,b2,b3,b4;
-
- b1 = l&255;
- b2 = (l>>8)&255;
- b3 = (l>>16)&255;
- b4 = (l>>24)&255;
-
- return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
-}
-
-int LittleLong (int l)
-{
- return l;
-}
-
-float BigFloat (float l)
-{
- union {byte b[4]; float f;} in, out;
-
- in.f = l;
- out.b[0] = in.b[3];
- out.b[1] = in.b[2];
- out.b[2] = in.b[1];
- out.b[3] = in.b[0];
-
- return out.f;
-}
-
-float LittleFloat (float l)
-{
- return l;
-}
-
-#ifdef SIN
-unsigned short BigUnsignedShort (unsigned short l)
-{
- byte b1,b2;
-
- b1 = l&255;
- b2 = (l>>8)&255;
-
- return (b1<<8) + b2;
-}
-
-unsigned short LittleUnsignedShort (unsigned short l)
-{
- return l;
-}
-
-
-unsigned BigUnsigned (unsigned l)
-{
- byte b1,b2,b3,b4;
-
- b1 = l&255;
- b2 = (l>>8)&255;
- b3 = (l>>16)&255;
- b4 = (l>>24)&255;
-
- return ((unsigned)b1<<24) + ((unsigned)b2<<16) + ((unsigned)b3<<8) + b4;
-}
-
-unsigned LittleUnsigned (unsigned l)
-{
- return l;
-}
-#endif
-
-
-#endif
-
-
-//=======================================================
-
-
-// FIXME: byte swap?
-
-// this is a 16 bit, non-reflected CRC using the polynomial 0x1021
-// and the initial and final xor values shown below... in other words, the
-// CCITT standard CRC used by XMODEM
-
-#define CRC_INIT_VALUE 0xffff
-#define CRC_XOR_VALUE 0x0000
-
-static unsigned short crctable[256] =
-{
- 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
- 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
- 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
- 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
- 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
- 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
- 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
- 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
- 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
- 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
- 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
- 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
- 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
- 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
- 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
- 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
- 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
- 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
- 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
- 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
- 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
- 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
- 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
- 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
- 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
- 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
- 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
- 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
- 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
- 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
- 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
- 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
-};
-
-void CRC_Init(unsigned short *crcvalue)
-{
- *crcvalue = CRC_INIT_VALUE;
-}
-
-void CRC_ProcessByte(unsigned short *crcvalue, byte data)
-{
- *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];
-}
-
-unsigned short CRC_Value(unsigned short crcvalue)
-{
- return crcvalue ^ CRC_XOR_VALUE;
-}
-//=============================================================================
-
-/*
-============
-CreatePath
-============
-*/
-void CreatePath (char *path)
-{
- char *ofs, c;
-
- if (path[1] == ':')
- path += 2;
-
- for (ofs = path+1 ; *ofs ; ofs++)
- {
- c = *ofs;
- if (c == '/' || c == '\\')
- { // create the directory
- *ofs = 0;
- Q_mkdir (path);
- *ofs = c;
- }
- }
-}
-
-
-/*
-============
-QCopyFile
-
- Used to archive source files
-============
-*/
-void QCopyFile (char *from, char *to)
-{
- void *buffer;
- int length;
-
- length = LoadFile (from, &buffer, 0, 0);
- CreatePath (to);
- SaveFile (to, buffer, length);
- FreeMemory(buffer);
-}
-
-void FS_FreeFile(void *buf)
-{
- FreeMemory(buf);
-} //end of the function FS_FreeFile
-
-int FS_ReadFileAndCache(const char *qpath, void **buffer)
-{
- return LoadFile((char *) qpath, buffer, 0, 0);
-} //end of the function FS_ReadFileAndCache
-
-int FS_FOpenFileRead( const char *filename, FILE **file, qboolean uniqueFILE )
-{
- *file = fopen(filename, "rb");
- return (*file != NULL);
-} //end of the function FS_FOpenFileRead
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+// cmdlib.c
+
+#include "l_cmd.h"
+#include "l_log.h"
+#include "l_mem.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifndef SIN
+#define SIN
+#endif //SIN
+
+#if defined(WIN32) || defined(_WIN32)
+#include <direct.h>
+#else
+#include <unistd.h>
+#endif
+
+#ifdef NeXT
+#include <libc.h>
+#endif
+
+#define BASEDIRNAME "quake2"
+#define PATHSEPERATOR '/'
+
+// set these before calling CheckParm
+int myargc;
+char **myargv;
+
+char com_token[1024];
+qboolean com_eof;
+
+qboolean archive;
+char archivedir[1024];
+
+
+/*
+===================
+ExpandWildcards
+
+Mimic unix command line expansion
+===================
+*/
+#define MAX_EX_ARGC 1024
+int ex_argc;
+char *ex_argv[MAX_EX_ARGC];
+#ifdef _WIN32
+#include "io.h"
+void ExpandWildcards (int *argc, char ***argv)
+{
+ struct _finddata_t fileinfo;
+ int handle;
+ int i;
+ char filename[1024];
+ char filebase[1024];
+ char *path;
+
+ ex_argc = 0;
+ for (i=0 ; i<*argc ; i++)
+ {
+ path = (*argv)[i];
+ if ( path[0] == '-'
+ || ( !strstr(path, "*") && !strstr(path, "?") ) )
+ {
+ ex_argv[ex_argc++] = path;
+ continue;
+ }
+
+ handle = _findfirst (path, &fileinfo);
+ if (handle == -1)
+ return;
+
+ ExtractFilePath (path, filebase);
+
+ do
+ {
+ sprintf (filename, "%s%s", filebase, fileinfo.name);
+ ex_argv[ex_argc++] = copystring (filename);
+ } while (_findnext( handle, &fileinfo ) != -1);
+
+ _findclose (handle);
+ }
+
+ *argc = ex_argc;
+ *argv = ex_argv;
+}
+#else
+void ExpandWildcards (int *argc, char ***argv)
+{
+}
+#endif
+
+#ifdef WINBSPC
+
+#include <windows.h>
+
+HWND program_hwnd;
+
+void SetProgramHandle(HWND hwnd)
+{
+ program_hwnd = hwnd;
+} //end of the function SetProgramHandle
+
+/*
+=================
+Error
+
+For abnormal program terminations in windowed apps
+=================
+*/
+void Error (char *error, ...)
+{
+ va_list argptr;
+ char text[1024];
+ char text2[1024];
+ int err;
+
+ err = GetLastError ();
+
+ va_start(argptr, error);
+ vsprintf(text, error, argptr);
+ va_end(argptr);
+
+ sprintf(text2, "%s\nGetLastError() = %i", text, err);
+ MessageBox(program_hwnd, text2, "Error", 0 /* MB_OK */ );
+
+ Log_Write(text);
+ Log_Close();
+
+ exit(1);
+} //end of the function Error
+
+void Warning(char *szFormat, ...)
+{
+ char szBuffer[256];
+ va_list argptr;
+
+ va_start (argptr, szFormat);
+ vsprintf(szBuffer, szFormat, argptr);
+ va_end (argptr);
+
+ MessageBox(program_hwnd, szBuffer, "Warning", MB_OK);
+
+ Log_Write(szBuffer);
+} //end of the function Warning
+
+
+#else
+/*
+=================
+Error
+
+For abnormal program terminations in console apps
+=================
+*/
+void Error (char *error, ...)
+{
+ va_list argptr;
+ char text[1024];
+
+ va_start(argptr, error);
+ vsprintf(text, error, argptr);
+ va_end(argptr);
+ printf("ERROR: %s\n", text);
+
+ Log_Write(text);
+ Log_Close();
+
+ exit (1);
+} //end of the function Error
+
+void Warning(char *warning, ...)
+{
+ va_list argptr;
+ char text[1024];
+
+ va_start(argptr, warning);
+ vsprintf(text, warning, argptr);
+ va_end(argptr);
+ printf("WARNING: %s\n", text);
+
+ Log_Write(text);
+} //end of the function Warning
+
+#endif
+
+//only printf if in verbose mode
+qboolean verbose = true;
+
+void qprintf(char *format, ...)
+{
+ va_list argptr;
+#ifdef WINBSPC
+ char buf[2048];
+#endif //WINBSPC
+
+ if (!verbose)
+ return;
+
+ va_start(argptr,format);
+#ifdef WINBSPC
+ vsprintf(buf, format, argptr);
+ WinBSPCPrint(buf);
+#else
+ vprintf(format, argptr);
+#endif //WINBSPC
+ va_end(argptr);
+} //end of the function qprintf
+
+void Com_Error(int level, char *error, ...)
+{
+ va_list argptr;
+ char text[1024];
+
+ va_start(argptr, error);
+ vsprintf(text, error, argptr);
+ va_end(argptr);
+ Error(text);
+} //end of the funcion Com_Error
+
+void Com_Printf( const char *fmt, ... )
+{
+ va_list argptr;
+ char text[1024];
+
+ va_start(argptr, fmt);
+ vsprintf(text, fmt, argptr);
+ va_end(argptr);
+ Log_Print(text);
+} //end of the funcion Com_Printf
+
+/*
+
+qdir will hold the path up to the quake directory, including the slash
+
+ f:\quake\
+ /raid/quake/
+
+gamedir will hold qdir + the game directory (id1, id2, etc)
+
+ */
+
+char qdir[1024];
+char gamedir[1024];
+
+void SetQdirFromPath (char *path)
+{
+ char temp[1024];
+ char *c;
+ int len;
+
+ if (!(path[0] == '/' || path[0] == '\\' || path[1] == ':'))
+ { // path is partial
+ Q_getwd (temp);
+ strcat (temp, path);
+ path = temp;
+ }
+
+ // search for "quake2" in path
+
+ len = strlen(BASEDIRNAME);
+ for (c=path+strlen(path)-1 ; c != path ; c--)
+ if (!Q_strncasecmp (c, BASEDIRNAME, len))
+ {
+ strncpy (qdir, path, c+len+1-path);
+ qprintf ("qdir: %s\n", qdir);
+ c += len+1;
+ while (*c)
+ {
+ if (*c == '/' || *c == '\\')
+ {
+ strncpy (gamedir, path, c+1-path);
+ qprintf ("gamedir: %s\n", gamedir);
+ return;
+ }
+ c++;
+ }
+ Error ("No gamedir in %s", path);
+ return;
+ }
+ Error ("SetQdirFromPath: no '%s' in %s", BASEDIRNAME, path);
+}
+
+char *ExpandArg (char *path)
+{
+ static char full[1024];
+
+ if (path[0] != '/' && path[0] != '\\' && path[1] != ':')
+ {
+ Q_getwd (full);
+ strcat (full, path);
+ }
+ else
+ strcpy (full, path);
+ return full;
+}
+
+char *ExpandPath (char *path)
+{
+ static char full[1024];
+ if (!qdir)
+ Error ("ExpandPath called without qdir set");
+ if (path[0] == '/' || path[0] == '\\' || path[1] == ':')
+ return path;
+ sprintf (full, "%s%s", qdir, path);
+ return full;
+}
+
+char *ExpandPathAndArchive (char *path)
+{
+ char *expanded;
+ char archivename[1024];
+
+ expanded = ExpandPath (path);
+
+ if (archive)
+ {
+ sprintf (archivename, "%s/%s", archivedir, path);
+ QCopyFile (expanded, archivename);
+ }
+ return expanded;
+}
+
+
+char *copystring(char *s)
+{
+ char *b;
+ b = GetMemory(strlen(s)+1);
+ strcpy (b, s);
+ return b;
+}
+
+
+
+/*
+================
+I_FloatTime
+================
+*/
+double I_FloatTime (void)
+{
+ time_t t;
+
+ time (&t);
+
+ return t;
+#if 0
+// more precise, less portable
+ struct timeval tp;
+ struct timezone tzp;
+ static int secbase;
+
+ gettimeofday(&tp, &tzp);
+
+ if (!secbase)
+ {
+ secbase = tp.tv_sec;
+ return tp.tv_usec/1000000.0;
+ }
+
+ return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0;
+#endif
+}
+
+void Q_getwd (char *out)
+{
+#if defined(WIN32) || defined(_WIN32)
+ getcwd (out, 256);
+ strcat (out, "\\");
+#else
+ getwd(out);
+ strcat(out, "/");
+#endif
+}
+
+
+void Q_mkdir (char *path)
+{
+#ifdef WIN32
+ if (_mkdir (path) != -1)
+ return;
+#else
+ if (mkdir (path, 0777) != -1)
+ return;
+#endif
+ if (errno != EEXIST)
+ Error ("mkdir %s: %s",path, strerror(errno));
+}
+
+/*
+============
+FileTime
+
+returns -1 if not present
+============
+*/
+int FileTime (char *path)
+{
+ struct stat buf;
+
+ if (stat (path,&buf) == -1)
+ return -1;
+
+ return buf.st_mtime;
+}
+
+
+
+/*
+==============
+COM_Parse
+
+Parse a token out of a string
+==============
+*/
+char *COM_Parse (char *data)
+{
+ int c;
+ int len;
+
+ len = 0;
+ com_token[0] = 0;
+
+ if (!data)
+ return NULL;
+
+// skip whitespace
+skipwhite:
+ while ( (c = *data) <= ' ')
+ {
+ if (c == 0)
+ {
+ com_eof = true;
+ return NULL; // end of file;
+ }
+ data++;
+ }
+
+// skip // comments
+ if (c=='/' && data[1] == '/')
+ {
+ while (*data && *data != '\n')
+ data++;
+ goto skipwhite;
+ }
+
+
+// handle quoted strings specially
+ if (c == '\"')
+ {
+ data++;
+ do
+ {
+ c = *data++;
+ if (c=='\"')
+ {
+ com_token[len] = 0;
+ return data;
+ }
+ com_token[len] = c;
+ len++;
+ } while (1);
+ }
+
+// parse single characters
+ if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
+ {
+ com_token[len] = c;
+ len++;
+ com_token[len] = 0;
+ return data+1;
+ }
+
+// parse a regular word
+ do
+ {
+ com_token[len] = c;
+ data++;
+ len++;
+ c = *data;
+ if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
+ break;
+ } while (c>32);
+
+ com_token[len] = 0;
+ return data;
+}
+
+
+int Q_strncasecmp (char *s1, char *s2, int n)
+{
+ int c1, c2;
+
+ do
+ {
+ c1 = *s1++;
+ c2 = *s2++;
+
+ if (!n--)
+ return 0; // strings are equal until end point
+
+ if (c1 != c2)
+ {
+ if (c1 >= 'a' && c1 <= 'z')
+ c1 -= ('a' - 'A');
+ if (c2 >= 'a' && c2 <= 'z')
+ c2 -= ('a' - 'A');
+ if (c1 != c2)
+ return -1; // strings not equal
+ }
+ } while (c1);
+
+ return 0; // strings are equal
+}
+
+int Q_strcasecmp (char *s1, char *s2)
+{
+ return Q_strncasecmp (s1, s2, 99999);
+}
+
+int Q_stricmp (char *s1, char *s2)
+{
+ return Q_strncasecmp (s1, s2, 99999);
+}
+
+void Q_strncpyz( char *dest, const char *src, int destsize ) {
+ strncpy( dest, src, destsize-1 );
+ dest[destsize-1] = 0;
+}
+
+char *strupr (char *start)
+{
+ char *in;
+ in = start;
+ while (*in)
+ {
+ *in = toupper(*in);
+ in++;
+ }
+ return start;
+}
+
+char *strlower (char *start)
+{
+ char *in;
+ in = start;
+ while (*in)
+ {
+ *in = tolower(*in);
+ in++;
+ }
+ return start;
+}
+
+
+/*
+=============================================================================
+
+ MISC FUNCTIONS
+
+=============================================================================
+*/
+
+
+/*
+=================
+CheckParm
+
+Checks for the given parameter in the program's command line arguments
+Returns the argument number (1 to argc-1) or 0 if not present
+=================
+*/
+int CheckParm (char *check)
+{
+ int i;
+
+ for (i = 1;i<myargc;i++)
+ {
+ if ( !Q_strcasecmp(check, myargv[i]) )
+ return i;
+ }
+
+ return 0;
+}
+
+
+
+/*
+================
+Q_filelength
+================
+*/
+int Q_filelength (FILE *f)
+{
+ int pos;
+ int end;
+
+ pos = ftell (f);
+ fseek (f, 0, SEEK_END);
+ end = ftell (f);
+ fseek (f, pos, SEEK_SET);
+
+ return end;
+}
+
+
+FILE *SafeOpenWrite (char *filename)
+{
+ FILE *f;
+
+ f = fopen(filename, "wb");
+
+ if (!f)
+ Error ("Error opening %s: %s",filename,strerror(errno));
+
+ return f;
+}
+
+FILE *SafeOpenRead (char *filename)
+{
+ FILE *f;
+
+ f = fopen(filename, "rb");
+
+ if (!f)
+ Error ("Error opening %s: %s",filename,strerror(errno));
+
+ return f;
+}
+
+
+void SafeRead (FILE *f, void *buffer, int count)
+{
+ if ( fread (buffer, 1, count, f) != (size_t)count)
+ Error ("File read failure");
+}
+
+
+void SafeWrite (FILE *f, void *buffer, int count)
+{
+ if (fwrite (buffer, 1, count, f) != (size_t)count)
+ Error ("File write failure");
+}
+
+
+/*
+==============
+FileExists
+==============
+*/
+qboolean FileExists (char *filename)
+{
+ FILE *f;
+
+ f = fopen (filename, "r");
+ if (!f)
+ return false;
+ fclose (f);
+ return true;
+}
+
+/*
+==============
+LoadFile
+==============
+*/
+int LoadFile (char *filename, void **bufferptr, int offset, int length)
+{
+ FILE *f;
+ void *buffer;
+
+ f = SafeOpenRead(filename);
+ fseek(f, offset, SEEK_SET);
+ if (!length) length = Q_filelength(f);
+ buffer = GetMemory(length+1);
+ ((char *)buffer)[length] = 0;
+ SafeRead(f, buffer, length);
+ fclose(f);
+
+ *bufferptr = buffer;
+ return length;
+}
+
+
+/*
+==============
+TryLoadFile
+
+Allows failure
+==============
+*/
+int TryLoadFile (char *filename, void **bufferptr)
+{
+ FILE *f;
+ int length;
+ void *buffer;
+
+ *bufferptr = NULL;
+
+ f = fopen (filename, "rb");
+ if (!f)
+ return -1;
+ length = Q_filelength (f);
+ buffer = GetMemory(length+1);
+ ((char *)buffer)[length] = 0;
+ SafeRead (f, buffer, length);
+ fclose (f);
+
+ *bufferptr = buffer;
+ return length;
+}
+
+
+/*
+==============
+SaveFile
+==============
+*/
+void SaveFile (char *filename, void *buffer, int count)
+{
+ FILE *f;
+
+ f = SafeOpenWrite (filename);
+ SafeWrite (f, buffer, count);
+ fclose (f);
+}
+
+
+
+void DefaultExtension (char *path, char *extension)
+{
+ char *src;
+//
+// if path doesnt have a .EXT, append extension
+// (extension should include the .)
+//
+ src = path + strlen(path) - 1;
+
+ while (*src != PATHSEPERATOR && src != path)
+ {
+ if (*src == '.')
+ return; // it has an extension
+ src--;
+ }
+
+ strcat (path, extension);
+}
+
+
+void DefaultPath (char *path, char *basepath)
+{
+ char temp[128];
+
+ if (path[0] == PATHSEPERATOR)
+ return; // absolute path location
+ strcpy (temp,path);
+ strcpy (path,basepath);
+ strcat (path,temp);
+}
+
+
+void StripFilename (char *path)
+{
+ int length;
+
+ length = strlen(path)-1;
+ while (length > 0 && path[length] != PATHSEPERATOR)
+ length--;
+ path[length] = 0;
+}
+
+void StripExtension (char *path)
+{
+ int length;
+
+ length = strlen(path)-1;
+ while (length > 0 && path[length] != '.')
+ {
+ length--;
+ if (path[length] == '/')
+ return; // no extension
+ }
+ if (length)
+ path[length] = 0;
+}
+
+
+/*
+====================
+Extract file parts
+====================
+*/
+// FIXME: should include the slash, otherwise
+// backing to an empty path will be wrong when appending a slash
+void ExtractFilePath (char *path, char *dest)
+{
+ char *src;
+
+ src = path + strlen(path) - 1;
+
+//
+// back up until a \ or the start
+//
+ while (src != path && *(src-1) != '\\' && *(src-1) != '/')
+ src--;
+
+ memcpy (dest, path, src-path);
+ dest[src-path] = 0;
+}
+
+void ExtractFileBase (char *path, char *dest)
+{
+ char *src;
+
+ src = path + strlen(path) - 1;
+
+//
+// back up until a \ or the start
+//
+ while (src != path && *(src-1) != '\\' && *(src-1) != '/')
+ src--;
+
+ while (*src && *src != '.')
+ {
+ *dest++ = *src++;
+ }
+ *dest = 0;
+}
+
+void ExtractFileExtension (char *path, char *dest)
+{
+ char *src;
+
+ src = path + strlen(path) - 1;
+
+//
+// back up until a . or the start
+//
+ while (src != path && *(src-1) != '.')
+ src--;
+ if (src == path)
+ {
+ *dest = 0; // no extension
+ return;
+ }
+
+ strcpy (dest,src);
+}
+
+
+/*
+==============
+ParseNum / ParseHex
+==============
+*/
+int ParseHex (char *hex)
+{
+ char *str;
+ int num;
+
+ num = 0;
+ str = hex;
+
+ while (*str)
+ {
+ num <<= 4;
+ if (*str >= '0' && *str <= '9')
+ num += *str-'0';
+ else if (*str >= 'a' && *str <= 'f')
+ num += 10 + *str-'a';
+ else if (*str >= 'A' && *str <= 'F')
+ num += 10 + *str-'A';
+ else
+ Error ("Bad hex number: %s",hex);
+ str++;
+ }
+
+ return num;
+}
+
+
+int ParseNum (char *str)
+{
+ if (str[0] == '$')
+ return ParseHex (str+1);
+ if (str[0] == '0' && str[1] == 'x')
+ return ParseHex (str+2);
+ return atol (str);
+}
+
+
+
+/*
+============================================================================
+
+ BYTE ORDER FUNCTIONS
+
+============================================================================
+*/
+
+#ifdef _SGI_SOURCE
+#define __BIG_ENDIAN__
+#endif
+
+#ifdef __BIG_ENDIAN__
+
+short LittleShort (short l)
+{
+ byte b1,b2;
+
+ b1 = l&255;
+ b2 = (l>>8)&255;
+
+ return (b1<<8) + b2;
+}
+
+short BigShort (short l)
+{
+ return l;
+}
+
+
+int LittleLong (int l)
+{
+ byte b1,b2,b3,b4;
+
+ b1 = l&255;
+ b2 = (l>>8)&255;
+ b3 = (l>>16)&255;
+ b4 = (l>>24)&255;
+
+ return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
+}
+
+int BigLong (int l)
+{
+ return l;
+}
+
+
+float LittleFloat (float l)
+{
+ union {byte b[4]; float f;} in, out;
+
+ in.f = l;
+ out.b[0] = in.b[3];
+ out.b[1] = in.b[2];
+ out.b[2] = in.b[1];
+ out.b[3] = in.b[0];
+
+ return out.f;
+}
+
+float BigFloat (float l)
+{
+ return l;
+}
+
+#ifdef SIN
+unsigned short LittleUnsignedShort (unsigned short l)
+{
+ byte b1,b2;
+
+ b1 = l&255;
+ b2 = (l>>8)&255;
+
+ return (b1<<8) + b2;
+}
+
+unsigned short BigUnsignedShort (unsigned short l)
+{
+ return l;
+}
+
+unsigned LittleUnsigned (unsigned l)
+{
+ byte b1,b2,b3,b4;
+
+ b1 = l&255;
+ b2 = (l>>8)&255;
+ b3 = (l>>16)&255;
+ b4 = (l>>24)&255;
+
+ return ((unsigned)b1<<24) + ((unsigned)b2<<16) + ((unsigned)b3<<8) + b4;
+}
+
+unsigned BigUnsigned (unsigned l)
+{
+ return l;
+}
+#endif
+
+
+#else
+
+
+short BigShort (short l)
+{
+ byte b1,b2;
+
+ b1 = l&255;
+ b2 = (l>>8)&255;
+
+ return (b1<<8) + b2;
+}
+
+short LittleShort (short l)
+{
+ return l;
+}
+
+
+int BigLong (int l)
+{
+ byte b1,b2,b3,b4;
+
+ b1 = l&255;
+ b2 = (l>>8)&255;
+ b3 = (l>>16)&255;
+ b4 = (l>>24)&255;
+
+ return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
+}
+
+int LittleLong (int l)
+{
+ return l;
+}
+
+float BigFloat (float l)
+{
+ union {byte b[4]; float f;} in, out;
+
+ in.f = l;
+ out.b[0] = in.b[3];
+ out.b[1] = in.b[2];
+ out.b[2] = in.b[1];
+ out.b[3] = in.b[0];
+
+ return out.f;
+}
+
+float LittleFloat (float l)
+{
+ return l;
+}
+
+#ifdef SIN
+unsigned short BigUnsignedShort (unsigned short l)
+{
+ byte b1,b2;
+
+ b1 = l&255;
+ b2 = (l>>8)&255;
+
+ return (b1<<8) + b2;
+}
+
+unsigned short LittleUnsignedShort (unsigned short l)
+{
+ return l;
+}
+
+
+unsigned BigUnsigned (unsigned l)
+{
+ byte b1,b2,b3,b4;
+
+ b1 = l&255;
+ b2 = (l>>8)&255;
+ b3 = (l>>16)&255;
+ b4 = (l>>24)&255;
+
+ return ((unsigned)b1<<24) + ((unsigned)b2<<16) + ((unsigned)b3<<8) + b4;
+}
+
+unsigned LittleUnsigned (unsigned l)
+{
+ return l;
+}
+#endif
+
+
+#endif
+
+
+//=======================================================
+
+
+// FIXME: byte swap?
+
+// this is a 16 bit, non-reflected CRC using the polynomial 0x1021
+// and the initial and final xor values shown below... in other words, the
+// CCITT standard CRC used by XMODEM
+
+#define CRC_INIT_VALUE 0xffff
+#define CRC_XOR_VALUE 0x0000
+
+static unsigned short crctable[256] =
+{
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+ 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+ 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+ 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+ 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+ 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+ 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+ 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+ 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+ 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+ 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+ 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+ 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+ 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+ 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+ 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+ 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+ 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+ 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+ 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+ 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+ 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+ 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+};
+
+void CRC_Init(unsigned short *crcvalue)
+{
+ *crcvalue = CRC_INIT_VALUE;
+}
+
+void CRC_ProcessByte(unsigned short *crcvalue, byte data)
+{
+ *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];
+}
+
+unsigned short CRC_Value(unsigned short crcvalue)
+{
+ return crcvalue ^ CRC_XOR_VALUE;
+}
+//=============================================================================
+
+/*
+============
+CreatePath
+============
+*/
+void CreatePath (char *path)
+{
+ char *ofs, c;
+
+ if (path[1] == ':')
+ path += 2;
+
+ for (ofs = path+1 ; *ofs ; ofs++)
+ {
+ c = *ofs;
+ if (c == '/' || c == '\\')
+ { // create the directory
+ *ofs = 0;
+ Q_mkdir (path);
+ *ofs = c;
+ }
+ }
+}
+
+
+/*
+============
+QCopyFile
+
+ Used to archive source files
+============
+*/
+void QCopyFile (char *from, char *to)
+{
+ void *buffer;
+ int length;
+
+ length = LoadFile (from, &buffer, 0, 0);
+ CreatePath (to);
+ SaveFile (to, buffer, length);
+ FreeMemory(buffer);
+}
+
+void FS_FreeFile(void *buf)
+{
+ FreeMemory(buf);
+} //end of the function FS_FreeFile
+
+int FS_ReadFileAndCache(const char *qpath, void **buffer)
+{
+ return LoadFile((char *) qpath, buffer, 0, 0);
+} //end of the function FS_ReadFileAndCache
+
+int FS_FOpenFileRead( const char *filename, FILE **file, qboolean uniqueFILE )
+{
+ *file = fopen(filename, "rb");
+ return (*file != NULL);
+} //end of the function FS_FOpenFileRead
diff --git a/code/bspc/l_cmd.h b/code/bspc/l_cmd.h
index b5497b4..613cafa 100755
--- a/code/bspc/l_cmd.h
+++ b/code/bspc/l_cmd.h
@@ -1,157 +1,157 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-// cmdlib.h
-
-#ifndef SIN
-#define SIN
-#endif //SIN
-
-#ifndef __CMDLIB__
-#define __CMDLIB__
-
-#ifdef _WIN32
-#pragma warning(disable : 4244) // MIPS
-#pragma warning(disable : 4136) // X86
-#pragma warning(disable : 4051) // ALPHA
-
-#pragma warning(disable : 4018) // signed/unsigned mismatch
-#pragma warning(disable : 4305) // truncate from double to float
-#endif
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <ctype.h>
-#include <time.h>
-#include <stdarg.h>
-
-#ifndef __BYTEBOOL__
-#define __BYTEBOOL__
-typedef enum {false, true} qboolean;
-typedef unsigned char byte;
-#endif
-
-// the dec offsetof macro doesnt work very well...
-#define myoffsetof(type,identifier) ((size_t)&((type *)0)->identifier)
-
-
-// set these before calling CheckParm
-extern int myargc;
-extern char **myargv;
-
-char *strupr (char *in);
-char *strlower (char *in);
-int Q_strncasecmp (char *s1, char *s2, int n);
-int Q_strcasecmp (char *s1, char *s2);
-void Q_getwd (char *out);
-
-int Q_filelength (FILE *f);
-int FileTime (char *path);
-
-void Q_mkdir (char *path);
-
-extern char qdir[1024];
-extern char gamedir[1024];
-void SetQdirFromPath (char *path);
-char *ExpandArg (char *path); // from cmd line
-char *ExpandPath (char *path); // from scripts
-char *ExpandPathAndArchive (char *path);
-
-
-double I_FloatTime (void);
-
-void Error(char *error, ...);
-void Warning(char *warning, ...);
-
-int CheckParm (char *check);
-
-FILE *SafeOpenWrite (char *filename);
-FILE *SafeOpenRead (char *filename);
-void SafeRead (FILE *f, void *buffer, int count);
-void SafeWrite (FILE *f, void *buffer, int count);
-
-int LoadFile (char *filename, void **bufferptr, int offset, int length);
-int TryLoadFile (char *filename, void **bufferptr);
-void SaveFile (char *filename, void *buffer, int count);
-qboolean FileExists (char *filename);
-
-void DefaultExtension (char *path, char *extension);
-void DefaultPath (char *path, char *basepath);
-void StripFilename (char *path);
-void StripExtension (char *path);
-
-void ExtractFilePath (char *path, char *dest);
-void ExtractFileBase (char *path, char *dest);
-void ExtractFileExtension (char *path, char *dest);
-
-int ParseNum (char *str);
-
-short BigShort (short l);
-short LittleShort (short l);
-int BigLong (int l);
-int LittleLong (int l);
-float BigFloat (float l);
-float LittleFloat (float l);
-
-#ifdef SIN
-unsigned short BigUnsignedShort (unsigned short l);
-unsigned short LittleUnsignedShort (unsigned short l);
-unsigned BigUnsigned (unsigned l);
-unsigned LittleUnsigned (unsigned l);
-#endif
-
-
-char *COM_Parse (char *data);
-
-extern char com_token[1024];
-extern qboolean com_eof;
-
-char *copystring(char *s);
-
-
-void CRC_Init(unsigned short *crcvalue);
-void CRC_ProcessByte(unsigned short *crcvalue, byte data);
-unsigned short CRC_Value(unsigned short crcvalue);
-
-void CreatePath (char *path);
-void QCopyFile (char *from, char *to);
-
-extern qboolean archive;
-extern char archivedir[1024];
-
-
-extern qboolean verbose;
-void qprintf (char *format, ...);
-
-void ExpandWildcards (int *argc, char ***argv);
-
-
-// for compression routines
-typedef struct
-{
- byte *data;
- int count;
-} cblock_t;
-
-#endif
-
+/*
+===========================================================================
+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
+===========================================================================
+*/
+// cmdlib.h
+
+#ifndef SIN
+#define SIN
+#endif //SIN
+
+#ifndef __CMDLIB__
+#define __CMDLIB__
+
+#ifdef _WIN32
+#pragma warning(disable : 4244) // MIPS
+#pragma warning(disable : 4136) // X86
+#pragma warning(disable : 4051) // ALPHA
+
+#pragma warning(disable : 4018) // signed/unsigned mismatch
+#pragma warning(disable : 4305) // truncate from double to float
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <stdarg.h>
+
+#ifndef __BYTEBOOL__
+#define __BYTEBOOL__
+typedef enum {false, true} qboolean;
+typedef unsigned char byte;
+#endif
+
+// the dec offsetof macro doesnt work very well...
+#define myoffsetof(type,identifier) ((size_t)&((type *)0)->identifier)
+
+
+// set these before calling CheckParm
+extern int myargc;
+extern char **myargv;
+
+char *strupr (char *in);
+char *strlower (char *in);
+int Q_strncasecmp (char *s1, char *s2, int n);
+int Q_strcasecmp (char *s1, char *s2);
+void Q_getwd (char *out);
+
+int Q_filelength (FILE *f);
+int FileTime (char *path);
+
+void Q_mkdir (char *path);
+
+extern char qdir[1024];
+extern char gamedir[1024];
+void SetQdirFromPath (char *path);
+char *ExpandArg (char *path); // from cmd line
+char *ExpandPath (char *path); // from scripts
+char *ExpandPathAndArchive (char *path);
+
+
+double I_FloatTime (void);
+
+void Error(char *error, ...);
+void Warning(char *warning, ...);
+
+int CheckParm (char *check);
+
+FILE *SafeOpenWrite (char *filename);
+FILE *SafeOpenRead (char *filename);
+void SafeRead (FILE *f, void *buffer, int count);
+void SafeWrite (FILE *f, void *buffer, int count);
+
+int LoadFile (char *filename, void **bufferptr, int offset, int length);
+int TryLoadFile (char *filename, void **bufferptr);
+void SaveFile (char *filename, void *buffer, int count);
+qboolean FileExists (char *filename);
+
+void DefaultExtension (char *path, char *extension);
+void DefaultPath (char *path, char *basepath);
+void StripFilename (char *path);
+void StripExtension (char *path);
+
+void ExtractFilePath (char *path, char *dest);
+void ExtractFileBase (char *path, char *dest);
+void ExtractFileExtension (char *path, char *dest);
+
+int ParseNum (char *str);
+
+short BigShort (short l);
+short LittleShort (short l);
+int BigLong (int l);
+int LittleLong (int l);
+float BigFloat (float l);
+float LittleFloat (float l);
+
+#ifdef SIN
+unsigned short BigUnsignedShort (unsigned short l);
+unsigned short LittleUnsignedShort (unsigned short l);
+unsigned BigUnsigned (unsigned l);
+unsigned LittleUnsigned (unsigned l);
+#endif
+
+
+char *COM_Parse (char *data);
+
+extern char com_token[1024];
+extern qboolean com_eof;
+
+char *copystring(char *s);
+
+
+void CRC_Init(unsigned short *crcvalue);
+void CRC_ProcessByte(unsigned short *crcvalue, byte data);
+unsigned short CRC_Value(unsigned short crcvalue);
+
+void CreatePath (char *path);
+void QCopyFile (char *from, char *to);
+
+extern qboolean archive;
+extern char archivedir[1024];
+
+
+extern qboolean verbose;
+void qprintf (char *format, ...);
+
+void ExpandWildcards (int *argc, char ***argv);
+
+
+// for compression routines
+typedef struct
+{
+ byte *data;
+ int count;
+} cblock_t;
+
+#endif
+
diff --git a/code/bspc/l_log.c b/code/bspc/l_log.c
index b685ed3..6a69c2b 100755
--- a/code/bspc/l_log.c
+++ b/code/bspc/l_log.c
@@ -1,215 +1,215 @@
-/*
-===========================================================================
-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 <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "qbsp.h"
-
-#define MAX_LOGFILENAMESIZE 1024
-
-typedef struct logfile_s
-{
- char filename[MAX_LOGFILENAMESIZE];
- FILE *fp;
- int numwrites;
-} logfile_t;
-
-logfile_t logfile;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Log_Open(char *filename)
-{
- if (!filename || !strlen(filename))
- {
- printf("openlog <filename>\n");
- return;
- } //end if
- if (logfile.fp)
- {
- printf("log file %s is already opened\n", logfile.filename);
- return;
- } //end if
- logfile.fp = fopen(filename, "wb");
- if (!logfile.fp)
- {
- printf("can't open the log file %s\n", filename);
- return;
- } //end if
- strncpy(logfile.filename, filename, MAX_LOGFILENAMESIZE);
- printf("Opened log %s\n", logfile.filename);
-} //end of the function Log_Create
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Log_Close(void)
-{
- if (!logfile.fp)
- {
- printf("no log file to close\n");
- return;
- } //end if
- if (fclose(logfile.fp))
- {
- printf("can't close log file %s\n", logfile.filename);
- return;
- } //end if
- logfile.fp = NULL;
- printf("Closed log %s\n", logfile.filename);
-} //end of the function Log_Close
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Log_Shutdown(void)
-{
- if (logfile.fp) Log_Close();
-} //end of the function Log_Shutdown
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Log_UnifyEndOfLine(char *buf)
-{
- int i;
-
- for (i = 0; buf[i]; i++)
- {
- if (buf[i] == '\n')
- {
- if (i <= 0 || buf[i-1] != '\r')
- {
- memmove(&buf[i+1], &buf[i], strlen(&buf[i])+1);
- buf[i] = '\r';
- i++;
- } //end if
- } //end if
- } //end for
-} //end of the function Log_UnifyEndOfLine
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Log_Print(char *fmt, ...)
-{
- va_list ap;
- char buf[2048];
-
- va_start(ap, fmt);
- vsprintf(buf, fmt, ap);
- va_end(ap);
-
- if (verbose)
- {
-#ifdef WINBSPC
- WinBSPCPrint(buf);
-#else
- printf("%s", buf);
-#endif //WINBSPS
- } //end if
-
- if (logfile.fp)
- {
- Log_UnifyEndOfLine(buf);
- fprintf(logfile.fp, "%s", buf);
- fflush(logfile.fp);
- } //end if
-} //end of the function Log_Print
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Log_Write(char *fmt, ...)
-{
- va_list ap;
- char buf[2048];
-
- if (!logfile.fp) return;
- va_start(ap, fmt);
- vsprintf(buf, fmt, ap);
- va_end(ap);
- Log_UnifyEndOfLine(buf);
- fprintf(logfile.fp, "%s", buf);
- fflush(logfile.fp);
-} //end of the function Log_Write
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Log_WriteTimeStamped(char *fmt, ...)
-{
- va_list ap;
-
- if (!logfile.fp) return;
-/* fprintf(logfile.fp, "%d %02d:%02d:%02d:%02d ",
- logfile.numwrites,
- (int) (botlibglobals.time / 60 / 60),
- (int) (botlibglobals.time / 60),
- (int) (botlibglobals.time),
- (int) ((int) (botlibglobals.time * 100)) -
- ((int) botlibglobals.time) * 100);*/
- va_start(ap, fmt);
- vfprintf(logfile.fp, fmt, ap);
- va_end(ap);
- logfile.numwrites++;
- fflush(logfile.fp);
-} //end of the function Log_Write
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-FILE *Log_FileStruct(void)
-{
- return logfile.fp;
-} //end of the function Log_FileStruct
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Log_Flush(void)
-{
- if (logfile.fp) fflush(logfile.fp);
-} //end of the function Log_Flush
-
+/*
+===========================================================================
+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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "qbsp.h"
+
+#define MAX_LOGFILENAMESIZE 1024
+
+typedef struct logfile_s
+{
+ char filename[MAX_LOGFILENAMESIZE];
+ FILE *fp;
+ int numwrites;
+} logfile_t;
+
+logfile_t logfile;
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Log_Open(char *filename)
+{
+ if (!filename || !strlen(filename))
+ {
+ printf("openlog <filename>\n");
+ return;
+ } //end if
+ if (logfile.fp)
+ {
+ printf("log file %s is already opened\n", logfile.filename);
+ return;
+ } //end if
+ logfile.fp = fopen(filename, "wb");
+ if (!logfile.fp)
+ {
+ printf("can't open the log file %s\n", filename);
+ return;
+ } //end if
+ strncpy(logfile.filename, filename, MAX_LOGFILENAMESIZE);
+ printf("Opened log %s\n", logfile.filename);
+} //end of the function Log_Create
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Log_Close(void)
+{
+ if (!logfile.fp)
+ {
+ printf("no log file to close\n");
+ return;
+ } //end if
+ if (fclose(logfile.fp))
+ {
+ printf("can't close log file %s\n", logfile.filename);
+ return;
+ } //end if
+ logfile.fp = NULL;
+ printf("Closed log %s\n", logfile.filename);
+} //end of the function Log_Close
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Log_Shutdown(void)
+{
+ if (logfile.fp) Log_Close();
+} //end of the function Log_Shutdown
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Log_UnifyEndOfLine(char *buf)
+{
+ int i;
+
+ for (i = 0; buf[i]; i++)
+ {
+ if (buf[i] == '\n')
+ {
+ if (i <= 0 || buf[i-1] != '\r')
+ {
+ memmove(&buf[i+1], &buf[i], strlen(&buf[i])+1);
+ buf[i] = '\r';
+ i++;
+ } //end if
+ } //end if
+ } //end for
+} //end of the function Log_UnifyEndOfLine
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Log_Print(char *fmt, ...)
+{
+ va_list ap;
+ char buf[2048];
+
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ if (verbose)
+ {
+#ifdef WINBSPC
+ WinBSPCPrint(buf);
+#else
+ printf("%s", buf);
+#endif //WINBSPS
+ } //end if
+
+ if (logfile.fp)
+ {
+ Log_UnifyEndOfLine(buf);
+ fprintf(logfile.fp, "%s", buf);
+ fflush(logfile.fp);
+ } //end if
+} //end of the function Log_Print
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Log_Write(char *fmt, ...)
+{
+ va_list ap;
+ char buf[2048];
+
+ if (!logfile.fp) return;
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+ Log_UnifyEndOfLine(buf);
+ fprintf(logfile.fp, "%s", buf);
+ fflush(logfile.fp);
+} //end of the function Log_Write
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Log_WriteTimeStamped(char *fmt, ...)
+{
+ va_list ap;
+
+ if (!logfile.fp) return;
+/* fprintf(logfile.fp, "%d %02d:%02d:%02d:%02d ",
+ logfile.numwrites,
+ (int) (botlibglobals.time / 60 / 60),
+ (int) (botlibglobals.time / 60),
+ (int) (botlibglobals.time),
+ (int) ((int) (botlibglobals.time * 100)) -
+ ((int) botlibglobals.time) * 100);*/
+ va_start(ap, fmt);
+ vfprintf(logfile.fp, fmt, ap);
+ va_end(ap);
+ logfile.numwrites++;
+ fflush(logfile.fp);
+} //end of the function Log_Write
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+FILE *Log_FileStruct(void)
+{
+ return logfile.fp;
+} //end of the function Log_FileStruct
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Log_Flush(void)
+{
+ if (logfile.fp) fflush(logfile.fp);
+} //end of the function Log_Flush
+
diff --git a/code/bspc/l_log.h b/code/bspc/l_log.h
index eff7bf6..b9f1be4 100755
--- a/code/bspc/l_log.h
+++ b/code/bspc/l_log.h
@@ -1,42 +1,42 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-
-//open a log file
-void Log_Open(char *filename);
-//close the current log file
-void Log_Close(void);
-//close log file if present
-void Log_Shutdown(void);
-//print on stdout and write to the current opened log file
-void Log_Print(char *fmt, ...);
-//write to the current opened log file
-void Log_Write(char *fmt, ...);
-//write to the current opened log file with a time stamp
-void Log_WriteTimeStamped(char *fmt, ...);
-//returns the log file structure
-FILE *Log_FileStruct(void);
-//flush log file
-void Log_Flush(void);
-
-#ifdef WINBSPC
-void WinBSPCPrint(char *str);
-#endif //WINBSPC
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+//open a log file
+void Log_Open(char *filename);
+//close the current log file
+void Log_Close(void);
+//close log file if present
+void Log_Shutdown(void);
+//print on stdout and write to the current opened log file
+void Log_Print(char *fmt, ...);
+//write to the current opened log file
+void Log_Write(char *fmt, ...);
+//write to the current opened log file with a time stamp
+void Log_WriteTimeStamped(char *fmt, ...);
+//returns the log file structure
+FILE *Log_FileStruct(void);
+//flush log file
+void Log_Flush(void);
+
+#ifdef WINBSPC
+void WinBSPCPrint(char *str);
+#endif //WINBSPC
diff --git a/code/bspc/l_math.c b/code/bspc/l_math.c
index caf3419..8d26a05 100755
--- a/code/bspc/l_math.c
+++ b/code/bspc/l_math.c
@@ -1,289 +1,289 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-// mathlib.c -- math primitives
-
-#include "l_cmd.h"
-#include "l_math.h"
-
-vec3_t vec3_origin = {0,0,0};
-
-void AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
-{
- float angle;
- static float sr, sp, sy, cr, cp, cy;
- // static to help MS compiler fp bugs
-
- angle = angles[YAW] * (M_PI*2 / 360);
- sy = sin(angle);
- cy = cos(angle);
- angle = angles[PITCH] * (M_PI*2 / 360);
- sp = sin(angle);
- cp = cos(angle);
- angle = angles[ROLL] * (M_PI*2 / 360);
- sr = sin(angle);
- cr = cos(angle);
-
- if (forward)
- {
- forward[0] = cp*cy;
- forward[1] = cp*sy;
- forward[2] = -sp;
- }
- if (right)
- {
- right[0] = (-1*sr*sp*cy+-1*cr*-sy);
- right[1] = (-1*sr*sp*sy+-1*cr*cy);
- right[2] = -1*sr*cp;
- }
- if (up)
- {
- up[0] = (cr*sp*cy+-sr*-sy);
- up[1] = (cr*sp*sy+-sr*cy);
- up[2] = cr*cp;
- }
-}
-
-/*
-=================
-RadiusFromBounds
-=================
-*/
-float RadiusFromBounds( const vec3_t mins, const vec3_t maxs ) {
- int i;
- vec3_t corner;
- float a, b;
-
- for (i=0 ; i<3 ; i++) {
- a = fabs( mins[i] );
- b = fabs( maxs[i] );
- corner[i] = a > b ? a : b;
- }
-
- return VectorLength (corner);
-}
-
-/*
-================
-R_ConcatRotations
-================
-*/
-void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3])
-{
- out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
- in1[0][2] * in2[2][0];
- out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
- in1[0][2] * in2[2][1];
- out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
- in1[0][2] * in2[2][2];
- out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
- in1[1][2] * in2[2][0];
- out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
- in1[1][2] * in2[2][1];
- out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
- in1[1][2] * in2[2][2];
- out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
- in1[2][2] * in2[2][0];
- out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
- in1[2][2] * in2[2][1];
- out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
- in1[2][2] * in2[2][2];
-}
-
-void AxisClear( vec3_t axis[3] ) {
- axis[0][0] = 1;
- axis[0][1] = 0;
- axis[0][2] = 0;
- axis[1][0] = 0;
- axis[1][1] = 1;
- axis[1][2] = 0;
- axis[2][0] = 0;
- axis[2][1] = 0;
- axis[2][2] = 1;
-}
-
-float VectorLengthSquared(vec3_t v) {
- return DotProduct(v, v);
-}
-
-double VectorLength(vec3_t v)
-{
- int i;
- double length;
-
- length = 0;
- for (i=0 ; i< 3 ; i++)
- length += v[i]*v[i];
- length = sqrt (length); // FIXME
-
- return length;
-}
-
-qboolean VectorCompare (vec3_t v1, vec3_t v2)
-{
- int i;
-
- for (i=0 ; i<3 ; i++)
- if (fabs(v1[i]-v2[i]) > EQUAL_EPSILON)
- return false;
-
- return true;
-}
-
-vec_t Q_rint (vec_t in)
-{
- return floor(in + 0.5);
-}
-
-void CrossProduct (const vec3_t v1, const vec3_t v2, vec3_t cross)
-{
- cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
- cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
- cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
-}
-
-void _VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc)
-{
- vc[0] = va[0] + scale*vb[0];
- vc[1] = va[1] + scale*vb[1];
- vc[2] = va[2] + scale*vb[2];
-}
-
-vec_t _DotProduct (vec3_t v1, vec3_t v2)
-{
- return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
-}
-
-void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out)
-{
- out[0] = va[0]-vb[0];
- out[1] = va[1]-vb[1];
- out[2] = va[2]-vb[2];
-}
-
-void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out)
-{
- out[0] = va[0]+vb[0];
- out[1] = va[1]+vb[1];
- out[2] = va[2]+vb[2];
-}
-
-void _VectorCopy (vec3_t in, vec3_t out)
-{
- out[0] = in[0];
- out[1] = in[1];
- out[2] = in[2];
-}
-
-void _VectorScale (vec3_t v, vec_t scale, vec3_t out)
-{
- out[0] = v[0] * scale;
- out[1] = v[1] * scale;
- out[2] = v[2] * scale;
-}
-
-vec_t VectorNormalize(vec3_t inout)
-{
- vec_t length, ilength;
-
- length = sqrt (inout[0]*inout[0] + inout[1]*inout[1] + inout[2]*inout[2]);
- if (length == 0)
- {
- VectorClear (inout);
- return 0;
- }
-
- ilength = 1.0/length;
- inout[0] = inout[0]*ilength;
- inout[1] = inout[1]*ilength;
- inout[2] = inout[2]*ilength;
-
- return length;
-}
-
-vec_t VectorNormalize2(const vec3_t in, vec3_t out)
-{
- vec_t length, ilength;
-
- length = sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]);
- if (length == 0)
- {
- VectorClear (out);
- return 0;
- }
-
- ilength = 1.0/length;
- out[0] = in[0]*ilength;
- out[1] = in[1]*ilength;
- out[2] = in[2]*ilength;
-
- return length;
-}
-
-vec_t ColorNormalize (vec3_t in, vec3_t out)
-{
- float max, scale;
-
- max = in[0];
- if (in[1] > max)
- max = in[1];
- if (in[2] > max)
- max = in[2];
-
- if (max == 0)
- return 0;
-
- scale = 1.0 / max;
-
- VectorScale (in, scale, out);
-
- return max;
-}
-
-
-
-void VectorInverse (vec3_t v)
-{
- v[0] = -v[0];
- v[1] = -v[1];
- v[2] = -v[2];
-}
-
-void ClearBounds(vec3_t mins, vec3_t maxs)
-{
- mins[0] = mins[1] = mins[2] = 99999;
- maxs[0] = maxs[1] = maxs[2] = -99999;
-}
-
-void AddPointToBounds(const vec3_t v, vec3_t mins, vec3_t maxs)
-{
- int i;
- vec_t val;
-
- for (i=0 ; i<3 ; i++)
- {
- val = v[i];
- if (val < mins[i])
- mins[i] = val;
- if (val > maxs[i])
- maxs[i] = val;
- }
-}
+/*
+===========================================================================
+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
+===========================================================================
+*/
+// mathlib.c -- math primitives
+
+#include "l_cmd.h"
+#include "l_math.h"
+
+vec3_t vec3_origin = {0,0,0};
+
+void AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
+{
+ float angle;
+ static float sr, sp, sy, cr, cp, cy;
+ // static to help MS compiler fp bugs
+
+ angle = angles[YAW] * (M_PI*2 / 360);
+ sy = sin(angle);
+ cy = cos(angle);
+ angle = angles[PITCH] * (M_PI*2 / 360);
+ sp = sin(angle);
+ cp = cos(angle);
+ angle = angles[ROLL] * (M_PI*2 / 360);
+ sr = sin(angle);
+ cr = cos(angle);
+
+ if (forward)
+ {
+ forward[0] = cp*cy;
+ forward[1] = cp*sy;
+ forward[2] = -sp;
+ }
+ if (right)
+ {
+ right[0] = (-1*sr*sp*cy+-1*cr*-sy);
+ right[1] = (-1*sr*sp*sy+-1*cr*cy);
+ right[2] = -1*sr*cp;
+ }
+ if (up)
+ {
+ up[0] = (cr*sp*cy+-sr*-sy);
+ up[1] = (cr*sp*sy+-sr*cy);
+ up[2] = cr*cp;
+ }
+}
+
+/*
+=================
+RadiusFromBounds
+=================
+*/
+float RadiusFromBounds( const vec3_t mins, const vec3_t maxs ) {
+ int i;
+ vec3_t corner;
+ float a, b;
+
+ for (i=0 ; i<3 ; i++) {
+ a = fabs( mins[i] );
+ b = fabs( maxs[i] );
+ corner[i] = a > b ? a : b;
+ }
+
+ return VectorLength (corner);
+}
+
+/*
+================
+R_ConcatRotations
+================
+*/
+void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3])
+{
+ out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
+ in1[0][2] * in2[2][0];
+ out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
+ in1[0][2] * in2[2][1];
+ out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
+ in1[0][2] * in2[2][2];
+ out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
+ in1[1][2] * in2[2][0];
+ out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
+ in1[1][2] * in2[2][1];
+ out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
+ in1[1][2] * in2[2][2];
+ out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
+ in1[2][2] * in2[2][0];
+ out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
+ in1[2][2] * in2[2][1];
+ out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
+ in1[2][2] * in2[2][2];
+}
+
+void AxisClear( vec3_t axis[3] ) {
+ axis[0][0] = 1;
+ axis[0][1] = 0;
+ axis[0][2] = 0;
+ axis[1][0] = 0;
+ axis[1][1] = 1;
+ axis[1][2] = 0;
+ axis[2][0] = 0;
+ axis[2][1] = 0;
+ axis[2][2] = 1;
+}
+
+float VectorLengthSquared(vec3_t v) {
+ return DotProduct(v, v);
+}
+
+double VectorLength(vec3_t v)
+{
+ int i;
+ double length;
+
+ length = 0;
+ for (i=0 ; i< 3 ; i++)
+ length += v[i]*v[i];
+ length = sqrt (length); // FIXME
+
+ return length;
+}
+
+qboolean VectorCompare (vec3_t v1, vec3_t v2)
+{
+ int i;
+
+ for (i=0 ; i<3 ; i++)
+ if (fabs(v1[i]-v2[i]) > EQUAL_EPSILON)
+ return false;
+
+ return true;
+}
+
+vec_t Q_rint (vec_t in)
+{
+ return floor(in + 0.5);
+}
+
+void CrossProduct (const vec3_t v1, const vec3_t v2, vec3_t cross)
+{
+ cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
+ cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
+ cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
+}
+
+void _VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc)
+{
+ vc[0] = va[0] + scale*vb[0];
+ vc[1] = va[1] + scale*vb[1];
+ vc[2] = va[2] + scale*vb[2];
+}
+
+vec_t _DotProduct (vec3_t v1, vec3_t v2)
+{
+ return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
+}
+
+void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out)
+{
+ out[0] = va[0]-vb[0];
+ out[1] = va[1]-vb[1];
+ out[2] = va[2]-vb[2];
+}
+
+void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out)
+{
+ out[0] = va[0]+vb[0];
+ out[1] = va[1]+vb[1];
+ out[2] = va[2]+vb[2];
+}
+
+void _VectorCopy (vec3_t in, vec3_t out)
+{
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+}
+
+void _VectorScale (vec3_t v, vec_t scale, vec3_t out)
+{
+ out[0] = v[0] * scale;
+ out[1] = v[1] * scale;
+ out[2] = v[2] * scale;
+}
+
+vec_t VectorNormalize(vec3_t inout)
+{
+ vec_t length, ilength;
+
+ length = sqrt (inout[0]*inout[0] + inout[1]*inout[1] + inout[2]*inout[2]);
+ if (length == 0)
+ {
+ VectorClear (inout);
+ return 0;
+ }
+
+ ilength = 1.0/length;
+ inout[0] = inout[0]*ilength;
+ inout[1] = inout[1]*ilength;
+ inout[2] = inout[2]*ilength;
+
+ return length;
+}
+
+vec_t VectorNormalize2(const vec3_t in, vec3_t out)
+{
+ vec_t length, ilength;
+
+ length = sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]);
+ if (length == 0)
+ {
+ VectorClear (out);
+ return 0;
+ }
+
+ ilength = 1.0/length;
+ out[0] = in[0]*ilength;
+ out[1] = in[1]*ilength;
+ out[2] = in[2]*ilength;
+
+ return length;
+}
+
+vec_t ColorNormalize (vec3_t in, vec3_t out)
+{
+ float max, scale;
+
+ max = in[0];
+ if (in[1] > max)
+ max = in[1];
+ if (in[2] > max)
+ max = in[2];
+
+ if (max == 0)
+ return 0;
+
+ scale = 1.0 / max;
+
+ VectorScale (in, scale, out);
+
+ return max;
+}
+
+
+
+void VectorInverse (vec3_t v)
+{
+ v[0] = -v[0];
+ v[1] = -v[1];
+ v[2] = -v[2];
+}
+
+void ClearBounds(vec3_t mins, vec3_t maxs)
+{
+ mins[0] = mins[1] = mins[2] = 99999;
+ maxs[0] = maxs[1] = maxs[2] = -99999;
+}
+
+void AddPointToBounds(const vec3_t v, vec3_t mins, vec3_t maxs)
+{
+ int i;
+ vec_t val;
+
+ for (i=0 ; i<3 ; i++)
+ {
+ val = v[i];
+ if (val < mins[i])
+ mins[i] = val;
+ if (val > maxs[i])
+ maxs[i] = val;
+ }
+}
diff --git a/code/bspc/l_math.h b/code/bspc/l_math.h
index 1df7b61..4cd4a6c 100755
--- a/code/bspc/l_math.h
+++ b/code/bspc/l_math.h
@@ -1,93 +1,93 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-#ifndef __MATHLIB__
-#define __MATHLIB__
-
-// mathlib.h
-
-#include <math.h>
-
-#ifdef DOUBLEVEC_T
-typedef double vec_t;
-#else
-typedef float vec_t;
-#endif
-typedef vec_t vec3_t[3];
-typedef vec_t vec4_t[4];
-
-#define SIDE_FRONT 0
-#define SIDE_ON 2
-#define SIDE_BACK 1
-#define SIDE_CROSS -2
-
-#define PITCH 0
-#define YAW 1
-#define ROLL 2
-
-#define Q_PI 3.14159265358979323846
-
-#define DEG2RAD( a ) ( a * M_PI ) / 180.0F
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h
-#endif
-
-extern vec3_t vec3_origin;
-
-#define EQUAL_EPSILON 0.001
-
-qboolean VectorCompare (vec3_t v1, vec3_t v2);
-
-#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
-#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];}
-#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];}
-#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];}
-#define Vector4Copy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];}
-#define VectorScale(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s))
-#define VectorClear(x) {x[0] = x[1] = x[2] = 0;}
-#define VectorNegate(x, y) {y[0]=-x[0];y[1]=-x[1];y[2]=-x[2];}
-#define VectorMA(v, s, b, o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s))
-
-vec_t Q_rint (vec_t in);
-vec_t _DotProduct (vec3_t v1, vec3_t v2);
-void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out);
-void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out);
-void _VectorCopy (vec3_t in, vec3_t out);
-void _VectorScale (vec3_t v, vec_t scale, vec3_t out);
-void _VectorMA(vec3_t va, double scale, vec3_t vb, vec3_t vc);
-
-double VectorLength(vec3_t v);
-void CrossProduct(const vec3_t v1, const vec3_t v2, vec3_t cross);
-vec_t VectorNormalize(vec3_t inout);
-vec_t ColorNormalize(vec3_t in, vec3_t out);
-vec_t VectorNormalize2(const vec3_t v, vec3_t out);
-void VectorInverse (vec3_t v);
-
-void ClearBounds (vec3_t mins, vec3_t maxs);
-void AddPointToBounds (const vec3_t v, vec3_t mins, vec3_t maxs);
-
-void AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
-void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]);
-void RotatePoint(vec3_t point, float matrix[3][3]);
-void CreateRotationMatrix(vec3_t angles, float matrix[3][3]);
-
-#endif
+/*
+===========================================================================
+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
+===========================================================================
+*/
+#ifndef __MATHLIB__
+#define __MATHLIB__
+
+// mathlib.h
+
+#include <math.h>
+
+#ifdef DOUBLEVEC_T
+typedef double vec_t;
+#else
+typedef float vec_t;
+#endif
+typedef vec_t vec3_t[3];
+typedef vec_t vec4_t[4];
+
+#define SIDE_FRONT 0
+#define SIDE_ON 2
+#define SIDE_BACK 1
+#define SIDE_CROSS -2
+
+#define PITCH 0
+#define YAW 1
+#define ROLL 2
+
+#define Q_PI 3.14159265358979323846
+
+#define DEG2RAD( a ) ( a * M_PI ) / 180.0F
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h
+#endif
+
+extern vec3_t vec3_origin;
+
+#define EQUAL_EPSILON 0.001
+
+qboolean VectorCompare (vec3_t v1, vec3_t v2);
+
+#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
+#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];}
+#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];}
+#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];}
+#define Vector4Copy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];}
+#define VectorScale(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s))
+#define VectorClear(x) {x[0] = x[1] = x[2] = 0;}
+#define VectorNegate(x, y) {y[0]=-x[0];y[1]=-x[1];y[2]=-x[2];}
+#define VectorMA(v, s, b, o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s))
+
+vec_t Q_rint (vec_t in);
+vec_t _DotProduct (vec3_t v1, vec3_t v2);
+void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out);
+void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out);
+void _VectorCopy (vec3_t in, vec3_t out);
+void _VectorScale (vec3_t v, vec_t scale, vec3_t out);
+void _VectorMA(vec3_t va, double scale, vec3_t vb, vec3_t vc);
+
+double VectorLength(vec3_t v);
+void CrossProduct(const vec3_t v1, const vec3_t v2, vec3_t cross);
+vec_t VectorNormalize(vec3_t inout);
+vec_t ColorNormalize(vec3_t in, vec3_t out);
+vec_t VectorNormalize2(const vec3_t v, vec3_t out);
+void VectorInverse (vec3_t v);
+
+void ClearBounds (vec3_t mins, vec3_t maxs);
+void AddPointToBounds (const vec3_t v, vec3_t mins, vec3_t maxs);
+
+void AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
+void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]);
+void RotatePoint(vec3_t point, float matrix[3][3]);
+void CreateRotationMatrix(vec3_t angles, float matrix[3][3]);
+
+#endif
diff --git a/code/bspc/l_mem.c b/code/bspc/l_mem.c
index 831543e..31e02b2 100755
--- a/code/bspc/l_mem.c
+++ b/code/bspc/l_mem.c
@@ -1,441 +1,441 @@
-/*
-===========================================================================
-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 "l_log.h"
-
-int allocedmemory;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void PrintMemorySize(unsigned long size)
-{
- unsigned long number1, number2, number3;
- number1 = size >> 20;
- number2 = (size & 0xFFFFF) >> 10;
- number3 = (size & 0x3FF);
- if (number1) Log_Print("%ld MB", number1);
- if (number1 && number2) Log_Print(" and ");
- if (number2) Log_Print("%ld KB", number2);
- if (number2 && number3) Log_Print(" and ");
- if (number3) Log_Print("%ld bytes", number3);
-} //end of the function PrintFileSize
-
-#ifndef MEMDEBUG
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int MemorySize(void *ptr)
-{
-#if defined(WIN32) || defined(_WIN32)
- #ifdef __WATCOMC__
- //Intel 32 bits memory addressing, 16 bytes aligned
- return (_msize(ptr) + 15) >> 4 << 4;
- #else
- return _msize(ptr);
- #endif
-#else
- return 0;
-#endif
-} //end of the function MemorySize
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void *GetClearedMemory(int size)
-{
- void *ptr;
-
- ptr = (void *) malloc(size);
- if (!ptr) Error("out of memory");
- memset(ptr, 0, size);
- allocedmemory += MemorySize(ptr);
- return ptr;
-} //end of the function GetClearedMemory
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void *GetMemory(unsigned long size)
-{
- void *ptr;
- ptr = malloc(size);
- if (!ptr) Error("out of memory");
- allocedmemory += MemorySize(ptr);
- return ptr;
-} //end of the function GetMemory
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void FreeMemory(void *ptr)
-{
- allocedmemory -= MemorySize(ptr);
- free(ptr);
-} //end of the function FreeMemory
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TotalAllocatedMemory(void)
-{
- return allocedmemory;
-} //end of the function TotalAllocatedMemory
-
-#else
-
-#define MEM_ID 0x12345678l
-
-int totalmemorysize;
-int numblocks;
-
-typedef struct memoryblock_s
-{
- unsigned long int id;
- void *ptr;
- int size;
-#ifdef MEMDEBUG
- char *label;
- char *file;
- int line;
-#endif //MEMDEBUG
- struct memoryblock_s *prev, *next;
-} memoryblock_t;
-
-memoryblock_t *memory;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void LinkMemoryBlock(memoryblock_t *block)
-{
- block->prev = NULL;
- block->next = memory;
- if (memory) memory->prev = block;
- memory = block;
-} //end of the function LinkMemoryBlock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void UnlinkMemoryBlock(memoryblock_t *block)
-{
- if (block->prev) block->prev->next = block->next;
- else memory = block->next;
- if (block->next) block->next->prev = block->prev;
-} //end of the function UnlinkMemoryBlock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#ifdef MEMDEBUG
-void *GetMemoryDebug(unsigned long size, char *label, char *file, int line)
-#else
-void *GetMemory(unsigned long size)
-#endif //MEMDEBUG
-{
- void *ptr;
- memoryblock_t *block;
-
- ptr = malloc(size + sizeof(memoryblock_t));
- block = (memoryblock_t *) ptr;
- block->id = MEM_ID;
- block->ptr = (char *) ptr + sizeof(memoryblock_t);
- block->size = size + sizeof(memoryblock_t);
-#ifdef MEMDEBUG
- block->label = label;
- block->file = file;
- block->line = line;
-#endif //MEMDEBUG
- LinkMemoryBlock(block);
- totalmemorysize += block->size;
- numblocks++;
- return block->ptr;
-} //end of the function GetMemoryDebug
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#ifdef MEMDEBUG
-void *GetClearedMemoryDebug(unsigned long size, char *label, char *file, int line)
-#else
-void *GetClearedMemory(unsigned long size)
-#endif //MEMDEBUG
-{
- void *ptr;
-#ifdef MEMDEBUG
- ptr = GetMemoryDebug(size, label, file, line);
-#else
- ptr = GetMemory(size);
-#endif //MEMDEBUG
- memset(ptr, 0, size);
- return ptr;
-} //end of the function GetClearedMemoryLabelled
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void *GetClearedHunkMemory(unsigned long size)
-{
- return GetClearedMemory(size);
-} //end of the function GetClearedHunkMemory
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void *GetHunkMemory(unsigned long size)
-{
- return GetMemory(size);
-} //end of the function GetHunkMemory
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-memoryblock_t *BlockFromPointer(void *ptr, char *str)
-{
- memoryblock_t *block;
-
- if (!ptr)
- {
-#ifdef MEMDEBUG
- //char *crash = (char *) NULL;
- //crash[0] = 1;
- Error("%s: NULL pointer\n", str);
-#endif MEMDEBUG
- return NULL;
- } //end if
- block = (memoryblock_t *) ((char *) ptr - sizeof(memoryblock_t));
- if (block->id != MEM_ID)
- {
- Error("%s: invalid memory block\n", str);
- } //end if
- if (block->ptr != ptr)
- {
-
- Error("%s: memory block pointer invalid\n", str);
- } //end if
- return block;
-} //end of the function BlockFromPointer
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void FreeMemory(void *ptr)
-{
- memoryblock_t *block;
-
- block = BlockFromPointer(ptr, "FreeMemory");
- if (!block) return;
- UnlinkMemoryBlock(block);
- totalmemorysize -= block->size;
- numblocks--;
- //
- free(block);
-} //end of the function FreeMemory
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int MemoryByteSize(void *ptr)
-{
- memoryblock_t *block;
-
- block = BlockFromPointer(ptr, "MemoryByteSize");
- if (!block) return 0;
- return block->size;
-} //end of the function MemoryByteSize
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int MemorySize(void *ptr)
-{
- return MemoryByteSize(ptr);
-} //end of the function MemorySize
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void PrintUsedMemorySize(void)
-{
- printf("total botlib memory: %d KB\n", totalmemorysize >> 10);
- printf("total memory blocks: %d\n", numblocks);
-} //end of the function PrintUsedMemorySize
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void PrintMemoryLabels(void)
-{
- memoryblock_t *block;
- int i;
-
- PrintUsedMemorySize();
- i = 0;
- for (block = memory; block; block = block->next)
- {
-#ifdef MEMDEBUG
- Log_Write("%6d, %p, %8d: %24s line %6d: %s", i, block->ptr, block->size, block->file, block->line, block->label);
-#endif //MEMDEBUG
- i++;
- } //end for
-} //end of the function PrintMemoryLabels
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void DumpMemory(void)
-{
- memoryblock_t *block;
-
- for (block = memory; block; block = memory)
- {
- FreeMemory(block->ptr);
- } //end for
- totalmemorysize = 0;
-} //end of the function DumpMemory
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TotalAllocatedMemory(void)
-{
- return totalmemorysize;
-} //end of the function TotalAllocatedMemory
-#endif
-
-//===========================================================================
-// Q3 Hunk and Z_ memory management
-//===========================================================================
-
-typedef struct memhunk_s
-{
- void *ptr;
- struct memhunk_s *next;
-} memhunk_t;
-
-memhunk_t *memhunk_high;
-memhunk_t *memhunk_low;
-int memhunk_high_size = 16 * 1024 * 1024;
-int memhunk_low_size = 0;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Hunk_ClearHigh(void)
-{
- memhunk_t *h, *nexth;
-
- for (h = memhunk_high; h; h = nexth)
- {
- nexth = h->next;
- FreeMemory(h);
- } //end for
- memhunk_high = NULL;
- memhunk_high_size = 16 * 1024 * 1024;
-} //end of the function Hunk_ClearHigh
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void *Hunk_Alloc(int size)
-{
- memhunk_t *h;
-
- if (!size) return (void *) memhunk_high_size;
- //
- h = GetClearedMemory(size + sizeof(memhunk_t));
- h->ptr = (char *) h + sizeof(memhunk_t);
- h->next = memhunk_high;
- memhunk_high = h;
- memhunk_high_size -= size;
- return h->ptr;
-} //end of the function Hunk_Alloc
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void *Z_Malloc(int size)
-{
- return GetClearedMemory(size);
-} //end of the function Z_Malloc
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Z_Free (void *ptr)
-{
- FreeMemory(ptr);
-} //end of the function Z_Free
+/*
+===========================================================================
+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 "l_log.h"
+
+int allocedmemory;
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void PrintMemorySize(unsigned long size)
+{
+ unsigned long number1, number2, number3;
+ number1 = size >> 20;
+ number2 = (size & 0xFFFFF) >> 10;
+ number3 = (size & 0x3FF);
+ if (number1) Log_Print("%ld MB", number1);
+ if (number1 && number2) Log_Print(" and ");
+ if (number2) Log_Print("%ld KB", number2);
+ if (number2 && number3) Log_Print(" and ");
+ if (number3) Log_Print("%ld bytes", number3);
+} //end of the function PrintFileSize
+
+#ifndef MEMDEBUG
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int MemorySize(void *ptr)
+{
+#if defined(WIN32) || defined(_WIN32)
+ #ifdef __WATCOMC__
+ //Intel 32 bits memory addressing, 16 bytes aligned
+ return (_msize(ptr) + 15) >> 4 << 4;
+ #else
+ return _msize(ptr);
+ #endif
+#else
+ return 0;
+#endif
+} //end of the function MemorySize
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void *GetClearedMemory(int size)
+{
+ void *ptr;
+
+ ptr = (void *) malloc(size);
+ if (!ptr) Error("out of memory");
+ memset(ptr, 0, size);
+ allocedmemory += MemorySize(ptr);
+ return ptr;
+} //end of the function GetClearedMemory
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void *GetMemory(unsigned long size)
+{
+ void *ptr;
+ ptr = malloc(size);
+ if (!ptr) Error("out of memory");
+ allocedmemory += MemorySize(ptr);
+ return ptr;
+} //end of the function GetMemory
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void FreeMemory(void *ptr)
+{
+ allocedmemory -= MemorySize(ptr);
+ free(ptr);
+} //end of the function FreeMemory
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TotalAllocatedMemory(void)
+{
+ return allocedmemory;
+} //end of the function TotalAllocatedMemory
+
+#else
+
+#define MEM_ID 0x12345678l
+
+int totalmemorysize;
+int numblocks;
+
+typedef struct memoryblock_s
+{
+ unsigned long int id;
+ void *ptr;
+ int size;
+#ifdef MEMDEBUG
+ char *label;
+ char *file;
+ int line;
+#endif //MEMDEBUG
+ struct memoryblock_s *prev, *next;
+} memoryblock_t;
+
+memoryblock_t *memory;
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void LinkMemoryBlock(memoryblock_t *block)
+{
+ block->prev = NULL;
+ block->next = memory;
+ if (memory) memory->prev = block;
+ memory = block;
+} //end of the function LinkMemoryBlock
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void UnlinkMemoryBlock(memoryblock_t *block)
+{
+ if (block->prev) block->prev->next = block->next;
+ else memory = block->next;
+ if (block->next) block->next->prev = block->prev;
+} //end of the function UnlinkMemoryBlock
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+#ifdef MEMDEBUG
+void *GetMemoryDebug(unsigned long size, char *label, char *file, int line)
+#else
+void *GetMemory(unsigned long size)
+#endif //MEMDEBUG
+{
+ void *ptr;
+ memoryblock_t *block;
+
+ ptr = malloc(size + sizeof(memoryblock_t));
+ block = (memoryblock_t *) ptr;
+ block->id = MEM_ID;
+ block->ptr = (char *) ptr + sizeof(memoryblock_t);
+ block->size = size + sizeof(memoryblock_t);
+#ifdef MEMDEBUG
+ block->label = label;
+ block->file = file;
+ block->line = line;
+#endif //MEMDEBUG
+ LinkMemoryBlock(block);
+ totalmemorysize += block->size;
+ numblocks++;
+ return block->ptr;
+} //end of the function GetMemoryDebug
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+#ifdef MEMDEBUG
+void *GetClearedMemoryDebug(unsigned long size, char *label, char *file, int line)
+#else
+void *GetClearedMemory(unsigned long size)
+#endif //MEMDEBUG
+{
+ void *ptr;
+#ifdef MEMDEBUG
+ ptr = GetMemoryDebug(size, label, file, line);
+#else
+ ptr = GetMemory(size);
+#endif //MEMDEBUG
+ memset(ptr, 0, size);
+ return ptr;
+} //end of the function GetClearedMemoryLabelled
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void *GetClearedHunkMemory(unsigned long size)
+{
+ return GetClearedMemory(size);
+} //end of the function GetClearedHunkMemory
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void *GetHunkMemory(unsigned long size)
+{
+ return GetMemory(size);
+} //end of the function GetHunkMemory
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+memoryblock_t *BlockFromPointer(void *ptr, char *str)
+{
+ memoryblock_t *block;
+
+ if (!ptr)
+ {
+#ifdef MEMDEBUG
+ //char *crash = (char *) NULL;
+ //crash[0] = 1;
+ Error("%s: NULL pointer\n", str);
+#endif MEMDEBUG
+ return NULL;
+ } //end if
+ block = (memoryblock_t *) ((char *) ptr - sizeof(memoryblock_t));
+ if (block->id != MEM_ID)
+ {
+ Error("%s: invalid memory block\n", str);
+ } //end if
+ if (block->ptr != ptr)
+ {
+
+ Error("%s: memory block pointer invalid\n", str);
+ } //end if
+ return block;
+} //end of the function BlockFromPointer
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void FreeMemory(void *ptr)
+{
+ memoryblock_t *block;
+
+ block = BlockFromPointer(ptr, "FreeMemory");
+ if (!block) return;
+ UnlinkMemoryBlock(block);
+ totalmemorysize -= block->size;
+ numblocks--;
+ //
+ free(block);
+} //end of the function FreeMemory
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int MemoryByteSize(void *ptr)
+{
+ memoryblock_t *block;
+
+ block = BlockFromPointer(ptr, "MemoryByteSize");
+ if (!block) return 0;
+ return block->size;
+} //end of the function MemoryByteSize
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int MemorySize(void *ptr)
+{
+ return MemoryByteSize(ptr);
+} //end of the function MemorySize
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void PrintUsedMemorySize(void)
+{
+ printf("total botlib memory: %d KB\n", totalmemorysize >> 10);
+ printf("total memory blocks: %d\n", numblocks);
+} //end of the function PrintUsedMemorySize
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void PrintMemoryLabels(void)
+{
+ memoryblock_t *block;
+ int i;
+
+ PrintUsedMemorySize();
+ i = 0;
+ for (block = memory; block; block = block->next)
+ {
+#ifdef MEMDEBUG
+ Log_Write("%6d, %p, %8d: %24s line %6d: %s", i, block->ptr, block->size, block->file, block->line, block->label);
+#endif //MEMDEBUG
+ i++;
+ } //end for
+} //end of the function PrintMemoryLabels
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void DumpMemory(void)
+{
+ memoryblock_t *block;
+
+ for (block = memory; block; block = memory)
+ {
+ FreeMemory(block->ptr);
+ } //end for
+ totalmemorysize = 0;
+} //end of the function DumpMemory
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TotalAllocatedMemory(void)
+{
+ return totalmemorysize;
+} //end of the function TotalAllocatedMemory
+#endif
+
+//===========================================================================
+// Q3 Hunk and Z_ memory management
+//===========================================================================
+
+typedef struct memhunk_s
+{
+ void *ptr;
+ struct memhunk_s *next;
+} memhunk_t;
+
+memhunk_t *memhunk_high;
+memhunk_t *memhunk_low;
+int memhunk_high_size = 16 * 1024 * 1024;
+int memhunk_low_size = 0;
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Hunk_ClearHigh(void)
+{
+ memhunk_t *h, *nexth;
+
+ for (h = memhunk_high; h; h = nexth)
+ {
+ nexth = h->next;
+ FreeMemory(h);
+ } //end for
+ memhunk_high = NULL;
+ memhunk_high_size = 16 * 1024 * 1024;
+} //end of the function Hunk_ClearHigh
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void *Hunk_Alloc(int size)
+{
+ memhunk_t *h;
+
+ if (!size) return (void *) memhunk_high_size;
+ //
+ h = GetClearedMemory(size + sizeof(memhunk_t));
+ h->ptr = (char *) h + sizeof(memhunk_t);
+ h->next = memhunk_high;
+ memhunk_high = h;
+ memhunk_high_size -= size;
+ return h->ptr;
+} //end of the function Hunk_Alloc
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void *Z_Malloc(int size)
+{
+ return GetClearedMemory(size);
+} //end of the function Z_Malloc
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Z_Free (void *ptr)
+{
+ FreeMemory(ptr);
+} //end of the function Z_Free
diff --git a/code/bspc/l_mem.h b/code/bspc/l_mem.h
index d517743..ba3b0d3 100755
--- a/code/bspc/l_mem.h
+++ b/code/bspc/l_mem.h
@@ -1,51 +1,51 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-
-
-//=============================================================================
-
-// memory.h
-//#define MEMDEBUG
-#undef MEMDEBUG
-
-#ifndef MEMDEBUG
-
-void *GetClearedMemory(int size);
-void *GetMemory(unsigned long size);
-
-#else
-
-#define GetMemory(size) GetMemoryDebug(size, #size, __FILE__, __LINE__);
-#define GetClearedMemory(size) GetClearedMemoryDebug(size, #size, __FILE__, __LINE__);
-//allocate a memory block of the given size
-void *GetMemoryDebug(unsigned long size, char *label, char *file, int line);
-//allocate a memory block of the given size and clear it
-void *GetClearedMemoryDebug(unsigned long size, char *label, char *file, int line);
-//
-void PrintMemoryLabels(void);
-#endif //MEMDEBUG
-
-void FreeMemory(void *ptr);
-int MemorySize(void *ptr);
-void PrintMemorySize(unsigned long size);
-int TotalAllocatedMemory(void);
-
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+
+//=============================================================================
+
+// memory.h
+//#define MEMDEBUG
+#undef MEMDEBUG
+
+#ifndef MEMDEBUG
+
+void *GetClearedMemory(int size);
+void *GetMemory(unsigned long size);
+
+#else
+
+#define GetMemory(size) GetMemoryDebug(size, #size, __FILE__, __LINE__);
+#define GetClearedMemory(size) GetClearedMemoryDebug(size, #size, __FILE__, __LINE__);
+//allocate a memory block of the given size
+void *GetMemoryDebug(unsigned long size, char *label, char *file, int line);
+//allocate a memory block of the given size and clear it
+void *GetClearedMemoryDebug(unsigned long size, char *label, char *file, int line);
+//
+void PrintMemoryLabels(void);
+#endif //MEMDEBUG
+
+void FreeMemory(void *ptr);
+int MemorySize(void *ptr);
+void PrintMemorySize(unsigned long size);
+int TotalAllocatedMemory(void);
+
diff --git a/code/bspc/l_poly.c b/code/bspc/l_poly.c
index fea2bef..7627d20 100755
--- a/code/bspc/l_poly.c
+++ b/code/bspc/l_poly.c
@@ -1,1411 +1,1411 @@
-/*
-===========================================================================
-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 <malloc.h>
-#include "l_cmd.h"
-#include "l_math.h"
-#include "l_poly.h"
-#include "l_log.h"
-#include "l_mem.h"
-
-#define BOGUS_RANGE 65535
-
-extern int numthreads;
-
-// counters are only bumped when running single threaded,
-// because they are an awefull coherence problem
-int c_active_windings;
-int c_peak_windings;
-int c_winding_allocs;
-int c_winding_points;
-int c_windingmemory;
-int c_peak_windingmemory;
-
-char windingerror[1024];
-
-void pw(winding_t *w)
-{
- int i;
- for (i=0 ; i<w->numpoints ; i++)
- printf ("(%5.3f, %5.3f, %5.3f)\n",w->p[i][0], w->p[i][1],w->p[i][2]);
-}
-
-
-void ResetWindings(void)
-{
- c_active_windings = 0;
- c_peak_windings = 0;
- c_winding_allocs = 0;
- c_winding_points = 0;
- c_windingmemory = 0;
- c_peak_windingmemory = 0;
-
- strcpy(windingerror, "");
-} //end of the function ResetWindings
-/*
-=============
-AllocWinding
-=============
-*/
-winding_t *AllocWinding (int points)
-{
- winding_t *w;
- int s;
-
- s = sizeof(vec_t)*3*points + sizeof(int);
- w = GetMemory(s);
- memset(w, 0, s);
-
- if (numthreads == 1)
- {
- c_winding_allocs++;
- c_winding_points += points;
- c_active_windings++;
- if (c_active_windings > c_peak_windings)
- c_peak_windings = c_active_windings;
- c_windingmemory += MemorySize(w);
- if (c_windingmemory > c_peak_windingmemory)
- c_peak_windingmemory = c_windingmemory;
- } //end if
- return w;
-} //end of the function AllocWinding
-
-void FreeWinding (winding_t *w)
-{
- if (*(unsigned *)w == 0xdeaddead)
- Error ("FreeWinding: freed a freed winding");
-
- if (numthreads == 1)
- {
- c_active_windings--;
- c_windingmemory -= MemorySize(w);
- } //end if
-
- *(unsigned *)w = 0xdeaddead;
-
- FreeMemory(w);
-} //end of the function FreeWinding
-
-int WindingMemory(void)
-{
- return c_windingmemory;
-} //end of the function WindingMemory
-
-int WindingPeakMemory(void)
-{
- return c_peak_windingmemory;
-} //end of the function WindingPeakMemory
-
-int ActiveWindings(void)
-{
- return c_active_windings;
-} //end of the function ActiveWindings
-/*
-============
-RemoveColinearPoints
-============
-*/
-int c_removed;
-
-void RemoveColinearPoints (winding_t *w)
-{
- int i, j, k;
- vec3_t v1, v2;
- int nump;
- vec3_t p[MAX_POINTS_ON_WINDING];
-
- nump = 0;
- for (i=0 ; i<w->numpoints ; i++)
- {
- j = (i+1)%w->numpoints;
- k = (i+w->numpoints-1)%w->numpoints;
- VectorSubtract (w->p[j], w->p[i], v1);
- VectorSubtract (w->p[i], w->p[k], v2);
- VectorNormalize(v1);
- VectorNormalize(v2);
- if (DotProduct(v1, v2) < 0.999)
- {
- if (nump >= MAX_POINTS_ON_WINDING)
- Error("RemoveColinearPoints: MAX_POINTS_ON_WINDING");
- VectorCopy (w->p[i], p[nump]);
- nump++;
- }
- }
-
- if (nump == w->numpoints)
- return;
-
- if (numthreads == 1)
- c_removed += w->numpoints - nump;
- w->numpoints = nump;
- memcpy (w->p, p, nump*sizeof(p[0]));
-}
-
-/*
-============
-WindingPlane
-============
-*/
-void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist)
-{
- vec3_t v1, v2;
- int i;
-
- //find two vectors each longer than 0.5 units
- for (i = 0; i < w->numpoints; i++)
- {
- VectorSubtract(w->p[(i+1) % w->numpoints], w->p[i], v1);
- VectorSubtract(w->p[(i+2) % w->numpoints], w->p[i], v2);
- if (VectorLength(v1) > 0.5 && VectorLength(v2) > 0.5) break;
- } //end for
- CrossProduct(v2, v1, normal);
- VectorNormalize(normal);
- *dist = DotProduct(w->p[0], normal);
-} //end of the function WindingPlane
-
-/*
-=============
-WindingArea
-=============
-*/
-vec_t WindingArea (winding_t *w)
-{
- int i;
- vec3_t d1, d2, cross;
- vec_t total;
-
- total = 0;
- for (i=2 ; i<w->numpoints ; i++)
- {
- VectorSubtract (w->p[i-1], w->p[0], d1);
- VectorSubtract (w->p[i], w->p[0], d2);
- CrossProduct (d1, d2, cross);
- total += 0.5 * VectorLength ( cross );
- }
- return total;
-}
-
-void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs)
-{
- vec_t v;
- int i,j;
-
- mins[0] = mins[1] = mins[2] = 99999;
- maxs[0] = maxs[1] = maxs[2] = -99999;
-
- for (i=0 ; i<w->numpoints ; i++)
- {
- for (j=0 ; j<3 ; j++)
- {
- v = w->p[i][j];
- if (v < mins[j])
- mins[j] = v;
- if (v > maxs[j])
- maxs[j] = v;
- }
- }
-}
-
-/*
-=============
-WindingCenter
-=============
-*/
-void WindingCenter (winding_t *w, vec3_t center)
-{
- int i;
- float scale;
-
- VectorCopy (vec3_origin, center);
- for (i=0 ; i<w->numpoints ; i++)
- VectorAdd (w->p[i], center, center);
-
- scale = 1.0/w->numpoints;
- VectorScale (center, scale, center);
-}
-
-/*
-=================
-BaseWindingForPlane
-=================
-*/
-winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist)
-{
- int i, x;
- vec_t max, v;
- vec3_t org, vright, vup;
- winding_t *w;
-
-// find the major axis
-
- max = -BOGUS_RANGE;
- x = -1;
- for (i=0 ; i<3; i++)
- {
- v = fabs(normal[i]);
- if (v > max)
- {
- x = i;
- max = v;
- }
- }
- if (x==-1)
- Error ("BaseWindingForPlane: no axis found");
-
- VectorCopy (vec3_origin, vup);
- switch (x)
- {
- case 0:
- case 1:
- vup[2] = 1;
- break;
- case 2:
- vup[0] = 1;
- break;
- }
-
- v = DotProduct (vup, normal);
- VectorMA (vup, -v, normal, vup);
- VectorNormalize (vup);
-
- VectorScale (normal, dist, org);
-
- CrossProduct (vup, normal, vright);
-
- VectorScale (vup, BOGUS_RANGE, vup);
- VectorScale (vright, BOGUS_RANGE, vright);
-
-// project a really big axis aligned box onto the plane
- w = AllocWinding (4);
-
- VectorSubtract (org, vright, w->p[0]);
- VectorAdd (w->p[0], vup, w->p[0]);
-
- VectorAdd (org, vright, w->p[1]);
- VectorAdd (w->p[1], vup, w->p[1]);
-
- VectorAdd (org, vright, w->p[2]);
- VectorSubtract (w->p[2], vup, w->p[2]);
-
- VectorSubtract (org, vright, w->p[3]);
- VectorSubtract (w->p[3], vup, w->p[3]);
-
- w->numpoints = 4;
-
- return w;
-}
-
-/*
-==================
-CopyWinding
-==================
-*/
-winding_t *CopyWinding (winding_t *w)
-{
- int size;
- winding_t *c;
-
- c = AllocWinding (w->numpoints);
- size = (int)((winding_t *)0)->p[w->numpoints];
- memcpy (c, w, size);
- return c;
-}
-
-/*
-==================
-ReverseWinding
-==================
-*/
-winding_t *ReverseWinding (winding_t *w)
-{
- int i;
- winding_t *c;
-
- c = AllocWinding (w->numpoints);
- for (i=0 ; i<w->numpoints ; i++)
- {
- VectorCopy (w->p[w->numpoints-1-i], c->p[i]);
- }
- c->numpoints = w->numpoints;
- return c;
-}
-
-
-/*
-=============
-ClipWindingEpsilon
-=============
-*/
-void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist,
- vec_t epsilon, winding_t **front, winding_t **back)
-{
- vec_t dists[MAX_POINTS_ON_WINDING+4];
- int sides[MAX_POINTS_ON_WINDING+4];
- int counts[3];
- //MrElusive: DOH can't use statics when unsing multithreading!!!
- vec_t dot; // VC 4.2 optimizer bug if not static
- int i, j;
- vec_t *p1, *p2;
- vec3_t mid;
- winding_t *f, *b;
- int maxpts;
-
- counts[0] = counts[1] = counts[2] = 0;
-
-// determine sides for each point
- for (i=0 ; i<in->numpoints ; i++)
- {
- dot = DotProduct (in->p[i], normal);
- dot -= dist;
- dists[i] = dot;
- if (dot > epsilon)
- sides[i] = SIDE_FRONT;
- else if (dot < -epsilon)
- sides[i] = SIDE_BACK;
- else
- {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- *front = *back = NULL;
-
- if (!counts[0])
- {
- *back = CopyWinding (in);
- return;
- }
- if (!counts[1])
- {
- *front = CopyWinding (in);
- return;
- }
-
- maxpts = in->numpoints+4; // cant use counts[0]+2 because
- // of fp grouping errors
-
- *front = f = AllocWinding (maxpts);
- *back = b = AllocWinding (maxpts);
-
- for (i=0 ; i<in->numpoints ; i++)
- {
- p1 = in->p[i];
-
- if (sides[i] == SIDE_ON)
- {
- VectorCopy (p1, f->p[f->numpoints]);
- f->numpoints++;
- VectorCopy (p1, b->p[b->numpoints]);
- b->numpoints++;
- continue;
- }
-
- if (sides[i] == SIDE_FRONT)
- {
- VectorCopy (p1, f->p[f->numpoints]);
- f->numpoints++;
- }
- if (sides[i] == SIDE_BACK)
- {
- VectorCopy (p1, b->p[b->numpoints]);
- b->numpoints++;
- }
-
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- // generate a split point
- p2 = in->p[(i+1)%in->numpoints];
-
- dot = dists[i] / (dists[i]-dists[i+1]);
- for (j=0 ; j<3 ; j++)
- { // avoid round off error when possible
- if (normal[j] == 1)
- mid[j] = dist;
- else if (normal[j] == -1)
- mid[j] = -dist;
- else
- mid[j] = p1[j] + dot*(p2[j]-p1[j]);
- }
-
- VectorCopy (mid, f->p[f->numpoints]);
- f->numpoints++;
- VectorCopy (mid, b->p[b->numpoints]);
- b->numpoints++;
- }
-
- if (f->numpoints > maxpts || b->numpoints > maxpts)
- Error ("ClipWinding: points exceeded estimate");
- if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)
- Error ("ClipWinding: MAX_POINTS_ON_WINDING");
-}
-
-
-/*
-=============
-ChopWindingInPlace
-=============
-*/
-void ChopWindingInPlace (winding_t **inout, vec3_t normal, vec_t dist, vec_t epsilon)
-{
- winding_t *in;
- vec_t dists[MAX_POINTS_ON_WINDING+4];
- int sides[MAX_POINTS_ON_WINDING+4];
- int counts[3];
- //MrElusive: DOH can't use statics when unsing multithreading!!!
- vec_t dot; // VC 4.2 optimizer bug if not static
- int i, j;
- vec_t *p1, *p2;
- vec3_t mid;
- winding_t *f;
- int maxpts;
-
- in = *inout;
- counts[0] = counts[1] = counts[2] = 0;
-
-// determine sides for each point
- for (i=0 ; i<in->numpoints ; i++)
- {
- dot = DotProduct (in->p[i], normal);
- dot -= dist;
- dists[i] = dot;
- if (dot > epsilon)
- sides[i] = SIDE_FRONT;
- else if (dot < -epsilon)
- sides[i] = SIDE_BACK;
- else
- {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- if (!counts[0])
- {
- FreeWinding (in);
- *inout = NULL;
- return;
- }
- if (!counts[1])
- return; // inout stays the same
-
- maxpts = in->numpoints+4; // cant use counts[0]+2 because
- // of fp grouping errors
-
- f = AllocWinding (maxpts);
-
- for (i=0 ; i<in->numpoints ; i++)
- {
- p1 = in->p[i];
-
- if (sides[i] == SIDE_ON)
- {
- VectorCopy (p1, f->p[f->numpoints]);
- f->numpoints++;
- continue;
- }
-
- if (sides[i] == SIDE_FRONT)
- {
- VectorCopy (p1, f->p[f->numpoints]);
- f->numpoints++;
- }
-
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- // generate a split point
- p2 = in->p[(i+1)%in->numpoints];
-
- dot = dists[i] / (dists[i]-dists[i+1]);
- for (j=0 ; j<3 ; j++)
- { // avoid round off error when possible
- if (normal[j] == 1)
- mid[j] = dist;
- else if (normal[j] == -1)
- mid[j] = -dist;
- else
- mid[j] = p1[j] + dot*(p2[j]-p1[j]);
- }
-
- VectorCopy (mid, f->p[f->numpoints]);
- f->numpoints++;
- }
-
- if (f->numpoints > maxpts)
- Error ("ClipWinding: points exceeded estimate");
- if (f->numpoints > MAX_POINTS_ON_WINDING)
- Error ("ClipWinding: MAX_POINTS_ON_WINDING");
-
- FreeWinding (in);
- *inout = f;
-}
-
-
-/*
-=================
-ChopWinding
-
-Returns the fragment of in that is on the front side
-of the cliping plane. The original is freed.
-=================
-*/
-winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist)
-{
- winding_t *f, *b;
-
- ClipWindingEpsilon (in, normal, dist, ON_EPSILON, &f, &b);
- FreeWinding (in);
- if (b)
- FreeWinding (b);
- return f;
-}
-
-
-/*
-=================
-CheckWinding
-
-=================
-*/
-void CheckWinding (winding_t *w)
-{
- int i, j;
- vec_t *p1, *p2;
- vec_t d, edgedist;
- vec3_t dir, edgenormal, facenormal;
- vec_t area;
- vec_t facedist;
-
- if (w->numpoints < 3)
- Error ("CheckWinding: %i points",w->numpoints);
-
- area = WindingArea(w);
- if (area < 1)
- Error ("CheckWinding: %f area", area);
-
- WindingPlane (w, facenormal, &facedist);
-
- for (i=0 ; i<w->numpoints ; i++)
- {
- p1 = w->p[i];
-
- for (j=0 ; j<3 ; j++)
- if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE)
- Error ("CheckWinding: BUGUS_RANGE: %f",p1[j]);
-
- j = i+1 == w->numpoints ? 0 : i+1;
-
- // check the point is on the face plane
- d = DotProduct (p1, facenormal) - facedist;
- if (d < -ON_EPSILON || d > ON_EPSILON)
- Error ("CheckWinding: point off plane");
-
- // check the edge isnt degenerate
- p2 = w->p[j];
- VectorSubtract (p2, p1, dir);
-
- if (VectorLength (dir) < ON_EPSILON)
- Error ("CheckWinding: degenerate edge");
-
- CrossProduct (facenormal, dir, edgenormal);
- VectorNormalize (edgenormal);
- edgedist = DotProduct (p1, edgenormal);
- edgedist += ON_EPSILON;
-
- // all other points must be on front side
- for (j=0 ; j<w->numpoints ; j++)
- {
- if (j == i)
- continue;
- d = DotProduct (w->p[j], edgenormal);
- if (d > edgedist)
- Error ("CheckWinding: non-convex");
- }
- }
-}
-
-
-/*
-============
-WindingOnPlaneSide
-============
-*/
-int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist)
-{
- qboolean front, back;
- int i;
- vec_t d;
-
- front = false;
- back = false;
- for (i=0 ; i<w->numpoints ; i++)
- {
- d = DotProduct (w->p[i], normal) - dist;
- if (d < -ON_EPSILON)
- {
- if (front)
- return SIDE_CROSS;
- back = true;
- continue;
- }
- if (d > ON_EPSILON)
- {
- if (back)
- return SIDE_CROSS;
- front = true;
- continue;
- }
- }
-
- if (back)
- return SIDE_BACK;
- if (front)
- return SIDE_FRONT;
- return SIDE_ON;
-}
-
-//#ifdef ME
- #define CONTINUOUS_EPSILON 0.005
-//#else
-// #define CONTINUOUS_EPSILON 0.001
-//#endif
-
-/*
-=============
-TryMergeWinding
-
-If two polygons share a common edge and the edges that meet at the
-common points are both inside the other polygons, merge them
-
-Returns NULL if the faces couldn't be merged, or the new face.
-The originals will NOT be freed.
-=============
-*/
-
-winding_t *TryMergeWinding (winding_t *f1, winding_t *f2, vec3_t planenormal)
-{
- vec_t *p1, *p2, *p3, *p4, *back;
- winding_t *newf;
- int i, j, k, l;
- vec3_t normal, delta;
- vec_t dot;
- qboolean keep1, keep2;
-
-
- //
- // find a common edge
- //
- p1 = p2 = NULL; // stop compiler warning
- j = 0; //
-
- for (i = 0; i < f1->numpoints; i++)
- {
- p1 = f1->p[i];
- p2 = f1->p[(i+1) % f1->numpoints];
- for (j = 0; j < f2->numpoints; j++)
- {
- p3 = f2->p[j];
- p4 = f2->p[(j+1) % f2->numpoints];
- for (k = 0; k < 3; k++)
- {
- if (fabs(p1[k] - p4[k]) > 0.1)//EQUAL_EPSILON) //ME
- break;
- if (fabs(p2[k] - p3[k]) > 0.1)//EQUAL_EPSILON) //ME
- break;
- } //end for
- if (k==3)
- break;
- } //end for
- if (j < f2->numpoints)
- break;
- } //end for
-
- if (i == f1->numpoints)
- return NULL; // no matching edges
-
- //
- // check slope of connected lines
- // if the slopes are colinear, the point can be removed
- //
- back = f1->p[(i+f1->numpoints-1)%f1->numpoints];
- VectorSubtract (p1, back, delta);
- CrossProduct (planenormal, delta, normal);
- VectorNormalize (normal);
-
- back = f2->p[(j+2)%f2->numpoints];
- VectorSubtract (back, p1, delta);
- dot = DotProduct (delta, normal);
- if (dot > CONTINUOUS_EPSILON)
- return NULL; // not a convex polygon
- keep1 = (qboolean)(dot < -CONTINUOUS_EPSILON);
-
- back = f1->p[(i+2)%f1->numpoints];
- VectorSubtract (back, p2, delta);
- CrossProduct (planenormal, delta, normal);
- VectorNormalize (normal);
-
- back = f2->p[(j+f2->numpoints-1)%f2->numpoints];
- VectorSubtract (back, p2, delta);
- dot = DotProduct (delta, normal);
- if (dot > CONTINUOUS_EPSILON)
- return NULL; // not a convex polygon
- keep2 = (qboolean)(dot < -CONTINUOUS_EPSILON);
-
- //
- // build the new polygon
- //
- newf = AllocWinding (f1->numpoints + f2->numpoints);
-
- // copy first polygon
- for (k=(i+1)%f1->numpoints ; k != i ; k=(k+1)%f1->numpoints)
- {
- if (k==(i+1)%f1->numpoints && !keep2)
- continue;
-
- VectorCopy (f1->p[k], newf->p[newf->numpoints]);
- newf->numpoints++;
- }
-
- // copy second polygon
- for (l= (j+1)%f2->numpoints ; l != j ; l=(l+1)%f2->numpoints)
- {
- if (l==(j+1)%f2->numpoints && !keep1)
- continue;
- VectorCopy (f2->p[l], newf->p[newf->numpoints]);
- newf->numpoints++;
- }
-
- return newf;
-}
-
-//#ifdef ME
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-winding_t *MergeWindings(winding_t *w1, winding_t *w2, vec3_t planenormal)
-{
- winding_t *neww;
- float dist;
- int i, j, n, found, insertafter;
- int sides[MAX_POINTS_ON_WINDING+4];
- vec3_t newp[MAX_POINTS_ON_WINDING+4];
- int numpoints;
- vec3_t edgevec, sepnormal, v;
-
- RemoveEqualPoints(w1, 0.2);
- numpoints = w1->numpoints;
- memcpy(newp, w1->p, w1->numpoints * sizeof(vec3_t));
- //
- for (i = 0; i < w2->numpoints; i++)
- {
- VectorCopy(w2->p[i], v);
- for (j = 0; j < numpoints; j++)
- {
- VectorSubtract(newp[(j+1)%numpoints],
- newp[(j)%numpoints], edgevec);
- CrossProduct(edgevec, planenormal, sepnormal);
- VectorNormalize(sepnormal);
- if (VectorLength(sepnormal) < 0.9)
- {
- //remove the point from the new winding
- for (n = j; n < numpoints-1; n++)
- {
- VectorCopy(newp[n+1], newp[n]);
- sides[n] = sides[n+1];
- } //end for
- numpoints--;
- j--;
- Log_Print("MergeWindings: degenerate edge on winding %f %f %f\n", sepnormal[0],
- sepnormal[1],
- sepnormal[2]);
- continue;
- } //end if
- dist = DotProduct(newp[(j)%numpoints], sepnormal);
- if (DotProduct(v, sepnormal) - dist < -0.1) sides[j] = SIDE_BACK;
- else sides[j] = SIDE_FRONT;
- } //end for
- //remove all unnecesary points
- for (j = 0; j < numpoints;)
- {
- if (sides[j] == SIDE_BACK
- && sides[(j+1)%numpoints] == SIDE_BACK)
- {
- //remove the point from the new winding
- for (n = (j+1)%numpoints; n < numpoints-1; n++)
- {
- VectorCopy(newp[n+1], newp[n]);
- sides[n] = sides[n+1];
- } //end for
- numpoints--;
- } //end if
- else
- {
- j++;
- } //end else
- } //end for
- //
- found = false;
- for (j = 0; j < numpoints; j++)
- {
- if (sides[j] == SIDE_FRONT
- && sides[(j+1)%numpoints] == SIDE_BACK)
- {
- if (found) Log_Print("Warning: MergeWindings: front to back found twice\n");
- found = true;
- } //end if
- } //end for
- //
- for (j = 0; j < numpoints; j++)
- {
- if (sides[j] == SIDE_FRONT
- && sides[(j+1)%numpoints] == SIDE_BACK)
- {
- insertafter = (j+1)%numpoints;
- //insert the new point after j+1
- for (n = numpoints-1; n > insertafter; n--)
- {
- VectorCopy(newp[n], newp[n+1]);
- } //end for
- numpoints++;
- VectorCopy(v, newp[(insertafter+1)%numpoints]);
- break;
- } //end if
- } //end for
- } //end for
- neww = AllocWinding(numpoints);
- neww->numpoints = numpoints;
- memcpy(neww->p, newp, numpoints * sizeof(vec3_t));
- RemoveColinearPoints(neww);
- return neww;
-} //end of the function MergeWindings
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-char *WindingErrorString(void)
-{
- return windingerror;
-} //end of the function WindingErrorString
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int WindingError(winding_t *w)
-{
- int i, j;
- vec_t *p1, *p2;
- vec_t d, edgedist;
- vec3_t dir, edgenormal, facenormal;
- vec_t area;
- vec_t facedist;
-
- if (w->numpoints < 3)
- {
- sprintf(windingerror, "winding %i points", w->numpoints);
- return WE_NOTENOUGHPOINTS;
- } //end if
-
- area = WindingArea(w);
- if (area < 1)
- {
- sprintf(windingerror, "winding %f area", area);
- return WE_SMALLAREA;
- } //end if
-
- WindingPlane (w, facenormal, &facedist);
-
- for (i=0 ; i<w->numpoints ; i++)
- {
- p1 = w->p[i];
-
- for (j=0 ; j<3 ; j++)
- {
- if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE)
- {
- sprintf(windingerror, "winding point %d BUGUS_RANGE \'%f %f %f\'", j, p1[0], p1[1], p1[2]);
- return WE_POINTBOGUSRANGE;
- } //end if
- } //end for
-
- j = i+1 == w->numpoints ? 0 : i+1;
-
- // check the point is on the face plane
- d = DotProduct (p1, facenormal) - facedist;
- if (d < -ON_EPSILON || d > ON_EPSILON)
- {
- sprintf(windingerror, "winding point %d off plane", i);
- return WE_POINTOFFPLANE;
- } //end if
-
- // check the edge isnt degenerate
- p2 = w->p[j];
- VectorSubtract (p2, p1, dir);
-
- if (VectorLength (dir) < ON_EPSILON)
- {
- sprintf(windingerror, "winding degenerate edge %d-%d", i, j);
- return WE_DEGENERATEEDGE;
- } //end if
-
- CrossProduct (facenormal, dir, edgenormal);
- VectorNormalize (edgenormal);
- edgedist = DotProduct (p1, edgenormal);
- edgedist += ON_EPSILON;
-
- // all other points must be on front side
- for (j=0 ; j<w->numpoints ; j++)
- {
- if (j == i)
- continue;
- d = DotProduct (w->p[j], edgenormal);
- if (d > edgedist)
- {
- sprintf(windingerror, "winding non-convex");
- return WE_NONCONVEX;
- } //end if
- } //end for
- } //end for
- return WE_NONE;
-} //end of the function WindingError
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void RemoveEqualPoints(winding_t *w, float epsilon)
-{
- int i, nump;
- vec3_t v;
- vec3_t p[MAX_POINTS_ON_WINDING];
-
- VectorCopy(w->p[0], p[0]);
- nump = 1;
- for (i = 1; i < w->numpoints; i++)
- {
- VectorSubtract(w->p[i], p[nump-1], v);
- if (VectorLength(v) > epsilon)
- {
- if (nump >= MAX_POINTS_ON_WINDING)
- Error("RemoveColinearPoints: MAX_POINTS_ON_WINDING");
- VectorCopy (w->p[i], p[nump]);
- nump++;
- } //end if
- } //end for
-
- if (nump == w->numpoints)
- return;
-
- w->numpoints = nump;
- memcpy(w->p, p, nump * sizeof(p[0]));
-} //end of the function RemoveEqualPoints
-//===========================================================================
-// adds the given point to a winding at the given spot
-// (for instance when spot is zero then the point is added at position zero)
-// the original winding is NOT freed
-//
-// Parameter: -
-// Returns: the new winding with the added point
-// Changes Globals: -
-//===========================================================================
-winding_t *AddWindingPoint(winding_t *w, vec3_t point, int spot)
-{
- int i, j;
- winding_t *neww;
-
- if (spot > w->numpoints)
- {
- Error("AddWindingPoint: num > w->numpoints");
- } //end if
- if (spot < 0)
- {
- Error("AddWindingPoint: num < 0");
- } //end if
- neww = AllocWinding(w->numpoints + 1);
- neww->numpoints = w->numpoints + 1;
- for (i = 0, j = 0; i < neww->numpoints; i++)
- {
- if (i == spot)
- {
- VectorCopy(point, neww->p[i]);
- } //end if
- else
- {
- VectorCopy(w->p[j], neww->p[i]);
- j++;
- } //end else
- } //end for
- return neww;
-} //end of the function AddWindingPoint
-//===========================================================================
-// the position where the new point should be added in the winding is
-// stored in *spot
-//
-// Parameter: -
-// Returns: true if the point is on the winding
-// Changes Globals: -
-//===========================================================================
-#define MELT_ON_EPSILON 0.2
-
-int PointOnWinding(winding_t *w, vec3_t normal, float dist, vec3_t point, int *spot)
-{
- int i, j;
- vec3_t v1, v2;
- vec3_t edgenormal, edgevec;
- float edgedist, dot;
-
- *spot = 0;
- //the point must be on the winding plane
- dot = DotProduct(point, normal) - dist;
- if (dot < -MELT_ON_EPSILON || dot > MELT_ON_EPSILON) return false;
- //
- for (i = 0; i < w->numpoints; i++)
- {
- j = (i+1) % w->numpoints;
- //get a plane orthogonal to the winding plane through the edge
- VectorSubtract(w->p[j], w->p[i], edgevec);
- CrossProduct(normal, edgevec, edgenormal);
- VectorNormalize(edgenormal);
- edgedist = DotProduct(edgenormal, w->p[i]);
- //point must be not too far from the plane
- dot = DotProduct(point, edgenormal) - edgedist;
- if (dot < -MELT_ON_EPSILON || dot > MELT_ON_EPSILON) continue;
- //vector from first point of winding to the point to test
- VectorSubtract(point, w->p[i], v1);
- //vector from second point of winding to the point to test
- VectorSubtract(point, w->p[j], v2);
- //if the length of the vector is not larger than 0.5 units then
- //the point is assumend to be the same as one of the winding points
- if (VectorNormalize(v1) < 0.5) return false;
- if (VectorNormalize(v2) < 0.5) return false;
- //point must be between the two winding points
- //(the two vectors must be directed towards each other, and on the
- //same straight line)
- if (DotProduct(v1, v2) < -0.99)
- {
- *spot = i + 1;
- return true;
- } //end if
- } //end for
- return false;
-} //end of the function PointOnWinding
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int FindPlaneSeperatingWindings(winding_t *w1, winding_t *w2, vec3_t dir,
- vec3_t normal, float *dist)
-{
- int i, i2, j, j2, n;
- int sides1[3], sides2[3];
- float dist1, dist2, dot, diff;
- vec3_t normal1, normal2;
- vec3_t v1, v2;
-
- for (i = 0; i < w1->numpoints; i++)
- {
- i2 = (i+1) % w1->numpoints;
- //
- VectorSubtract(w1->p[i2], w1->p[i], v1);
- if (VectorLength(v1) < 0.1)
- {
- //Log_Write("FindPlaneSeperatingWindings: winding1 with degenerate edge\r\n");
- continue;
- } //end if
- CrossProduct(v1, dir, normal1);
- VectorNormalize(normal1);
- dist1 = DotProduct(normal1, w1->p[i]);
- //
- for (j = 0; j < w2->numpoints; j++)
- {
- j2 = (j+1) % w2->numpoints;
- //
- VectorSubtract(w2->p[j2], w2->p[j], v2);
- if (VectorLength(v2) < 0.1)
- {
- //Log_Write("FindPlaneSeperatingWindings: winding2 with degenerate edge\r\n");
- continue;
- } //end if
- CrossProduct(v2, dir, normal2);
- VectorNormalize(normal2);
- dist2 = DotProduct(normal2, w2->p[j]);
- //
- diff = dist1 - dist2;
- if (diff < -0.1 || diff > 0.1)
- {
- dist2 = -dist2;
- VectorNegate(normal2, normal2);
- diff = dist1 - dist2;
- if (diff < -0.1 || diff > 0.1) continue;
- } //end if
- //check if the normal vectors are equal
- for (n = 0; n < 3; n++)
- {
- diff = normal1[n] - normal2[n];
- if (diff < -0.0001 || diff > 0.0001) break;
- } //end for
- if (n != 3) continue;
- //check on which side of the seperating plane the points of
- //the first winding are
- sides1[0] = sides1[1] = sides1[2] = 0;
- for (n = 0; n < w1->numpoints; n++)
- {
- dot = DotProduct(w1->p[n], normal1) - dist1;
- if (dot > 0.1) sides1[0]++;
- else if (dot < -0.1) sides1[1]++;
- else sides1[2]++;
- } //end for
- //check on which side of the seperating plane the points of
- //the second winding are
- sides2[0] = sides2[1] = sides2[2] = 0;
- for (n = 0; n < w2->numpoints; n++)
- {
- //used normal1 and dist1 (they are equal to normal2 and dist2)
- dot = DotProduct(w2->p[n], normal1) - dist1;
- if (dot > 0.1) sides2[0]++;
- else if (dot < -0.1) sides2[1]++;
- else sides2[2]++;
- } //end for
- //if the first winding has points at both sides
- if (sides1[0] && sides1[1])
- {
- Log_Write("FindPlaneSeperatingWindings: winding1 non-convex\r\n");
- continue;
- } //end if
- //if the second winding has points at both sides
- if (sides2[0] && sides2[1])
- {
- Log_Write("FindPlaneSeperatingWindings: winding2 non-convex\r\n");
- continue;
- } //end if
- //
- if ((!sides1[0] && !sides1[1]) || (!sides2[0] && !sides2[1]))
- {
- //don't use one of the winding planes as the seperating plane
- continue;
- } //end if
- //the windings must be at different sides of the seperating plane
- if ((!sides1[0] && !sides2[1]) || (!sides1[1] && !sides2[0]))
- {
- VectorCopy(normal1, normal);
- *dist = dist1;
- return true;
- } //end if
- } //end for
- } //end for
- return false;
-} //end of the function FindPlaneSeperatingWindings
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#define WCONVEX_EPSILON 0.2
-
-int WindingsNonConvex(winding_t *w1, winding_t *w2,
- vec3_t normal1, vec3_t normal2,
- float dist1, float dist2)
-{
- int i;
-
- if (!w1 || !w2) return false;
-
- //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(normal2, w1->p[i]) - dist2 > WCONVEX_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(normal1, w2->p[i]) - dist1 > WCONVEX_EPSILON) return true;
- } //end for
-
- return false;
-} //end of the function WindingsNonConvex
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-/*
-#define VERTEX_EPSILON 0.5
-
-qboolean EqualVertexes(vec3_t v1, vec3_t v2)
-{
- float diff;
-
- diff = v1[0] - v2[0];
- if (diff > -VERTEX_EPSILON && diff < VERTEX_EPSILON)
- {
- diff = v1[1] - v2[1];
- if (diff > -VERTEX_EPSILON && diff < VERTEX_EPSILON)
- {
- diff = v1[2] - v2[2];
- if (diff > -VERTEX_EPSILON && diff < VERTEX_EPSILON)
- {
- return true;
- } //end if
- } //end if
- } //end if
- return false;
-} //end of the function EqualVertexes
-
-#define CONTINUOUS_EPSILON 0.001
-
-winding_t *AAS_MergeWindings(winding_t *w1, winding_t *w2, vec3_t windingnormal)
-{
- int n, i, k;
- vec3_t normal, delta;
- winding_t *winding, *neww;
- float dist, dot;
- int p1, p2;
- int points[2][64];
- int numpoints[2] = {0, 0};
- int newnumpoints;
- int keep[2];
-
- if (!FindPlaneSeperatingWindings(w1, w2, windingnormal, normal, &dist)) return NULL;
-
- //for both windings
- for (n = 0; n < 2; n++)
- {
- if (n == 0) winding = w1;
- else winding = w2;
- //get the points of the winding which are on the seperating plane
- for (i = 0; i < winding->numpoints; i++)
- {
- dot = DotProduct(winding->p[i], normal) - dist;
- if (dot > -ON_EPSILON && dot < ON_EPSILON)
- {
- //don't allow more than 64 points on the seperating plane
- if (numpoints[n] >= 64) Error("AAS_MergeWindings: more than 64 points on seperating plane\n");
- points[n][numpoints[n]++] = i;
- } //end if
- } //end for
- //there must be at least two points of each winding on the seperating plane
- if (numpoints[n] < 2) return NULL;
- } //end for
-
- //if the first point of winding1 (which is on the seperating plane) is unequal
- //to the last point of winding2 (which is on the seperating plane)
- if (!EqualVertexes(w1->p[points[0][0]], w2->p[points[1][numpoints[1]-1]]))
- {
- return NULL;
- } //end if
- //if the last point of winding1 (which is on the seperating plane) is unequal
- //to the first point of winding2 (which is on the seperating plane)
- if (!EqualVertexes(w1->p[points[0][numpoints[0]-1]], w2->p[points[1][0]]))
- {
- return NULL;
- } //end if
- //
- // check slope of connected lines
- // if the slopes are colinear, the point can be removed
- //
- //first point of winding1 which is on the seperating plane
- p1 = points[0][0];
- //point before p1
- p2 = (p1 + w1->numpoints - 1) % w1->numpoints;
- VectorSubtract(w1->p[p1], w1->p[p2], delta);
- CrossProduct(windingnormal, delta, normal);
- VectorNormalize(normal, normal);
-
- //last point of winding2 which is on the seperating plane
- p1 = points[1][numpoints[1]-1];
- //point after p1
- p2 = (p1 + 1) % w2->numpoints;
- VectorSubtract(w2->p[p2], w2->p[p1], delta);
- dot = DotProduct(delta, normal);
- if (dot > CONTINUOUS_EPSILON) return NULL; //merging would create a non-convex polygon
- keep[0] = (qboolean)(dot < -CONTINUOUS_EPSILON);
-
- //first point of winding2 which is on the seperating plane
- p1 = points[1][0];
- //point before p1
- p2 = (p1 + w2->numpoints - 1) % w2->numpoints;
- VectorSubtract(w2->p[p1], w2->p[p2], delta);
- CrossProduct(windingnormal, delta, normal);
- VectorNormalize(normal, normal);
-
- //last point of winding1 which is on the seperating plane
- p1 = points[0][numpoints[0]-1];
- //point after p1
- p2 = (p1 + 1) % w1->numpoints;
- VectorSubtract(w1->p[p2], w1->p[p1], delta);
- dot = DotProduct(delta, normal);
- if (dot > CONTINUOUS_EPSILON) return NULL; //merging would create a non-convex polygon
- keep[1] = (qboolean)(dot < -CONTINUOUS_EPSILON);
-
- //number of points on the new winding
- newnumpoints = w1->numpoints - numpoints[0] + w2->numpoints - numpoints[1] + 2;
- //allocate the winding
- neww = AllocWinding(newnumpoints);
- neww->numpoints = newnumpoints;
- //copy all the points
- k = 0;
- //for both windings
- for (n = 0; n < 2; n++)
- {
- if (n == 0) winding = w1;
- else winding = w2;
- //copy the points of the winding starting with the last point on the
- //seperating plane and ending before the first point on the seperating plane
- for (i = points[n][numpoints[n]-1]; i != points[n][0]; i = (i+1)%winding->numpoints)
- {
- if (k >= newnumpoints)
- {
- Log_Print("numpoints[0] = %d\n", numpoints[0]);
- Log_Print("numpoints[1] = %d\n", numpoints[1]);
- Error("AAS_MergeWindings: k = %d >= newnumpoints = %d\n", k, newnumpoints);
- } //end if
- VectorCopy(winding->p[i], neww->p[k]);
- k++;
- } //end for
- } //end for
- RemoveEqualPoints(neww);
- if (!WindingIsOk(neww, 1))
- {
- Log_Print("AAS_MergeWindings: winding not ok after merging\n");
- FreeWinding(neww);
- return NULL;
- } //end if
- return neww;
-} //end of the function AAS_MergeWindings*/
-//#endif //ME
+/*
+===========================================================================
+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 <malloc.h>
+#include "l_cmd.h"
+#include "l_math.h"
+#include "l_poly.h"
+#include "l_log.h"
+#include "l_mem.h"
+
+#define BOGUS_RANGE 65535
+
+extern int numthreads;
+
+// counters are only bumped when running single threaded,
+// because they are an awefull coherence problem
+int c_active_windings;
+int c_peak_windings;
+int c_winding_allocs;
+int c_winding_points;
+int c_windingmemory;
+int c_peak_windingmemory;
+
+char windingerror[1024];
+
+void pw(winding_t *w)
+{
+ int i;
+ for (i=0 ; i<w->numpoints ; i++)
+ printf ("(%5.3f, %5.3f, %5.3f)\n",w->p[i][0], w->p[i][1],w->p[i][2]);
+}
+
+
+void ResetWindings(void)
+{
+ c_active_windings = 0;
+ c_peak_windings = 0;
+ c_winding_allocs = 0;
+ c_winding_points = 0;
+ c_windingmemory = 0;
+ c_peak_windingmemory = 0;
+
+ strcpy(windingerror, "");
+} //end of the function ResetWindings
+/*
+=============
+AllocWinding
+=============
+*/
+winding_t *AllocWinding (int points)
+{
+ winding_t *w;
+ int s;
+
+ s = sizeof(vec_t)*3*points + sizeof(int);
+ w = GetMemory(s);
+ memset(w, 0, s);
+
+ if (numthreads == 1)
+ {
+ c_winding_allocs++;
+ c_winding_points += points;
+ c_active_windings++;
+ if (c_active_windings > c_peak_windings)
+ c_peak_windings = c_active_windings;
+ c_windingmemory += MemorySize(w);
+ if (c_windingmemory > c_peak_windingmemory)
+ c_peak_windingmemory = c_windingmemory;
+ } //end if
+ return w;
+} //end of the function AllocWinding
+
+void FreeWinding (winding_t *w)
+{
+ if (*(unsigned *)w == 0xdeaddead)
+ Error ("FreeWinding: freed a freed winding");
+
+ if (numthreads == 1)
+ {
+ c_active_windings--;
+ c_windingmemory -= MemorySize(w);
+ } //end if
+
+ *(unsigned *)w = 0xdeaddead;
+
+ FreeMemory(w);
+} //end of the function FreeWinding
+
+int WindingMemory(void)
+{
+ return c_windingmemory;
+} //end of the function WindingMemory
+
+int WindingPeakMemory(void)
+{
+ return c_peak_windingmemory;
+} //end of the function WindingPeakMemory
+
+int ActiveWindings(void)
+{
+ return c_active_windings;
+} //end of the function ActiveWindings
+/*
+============
+RemoveColinearPoints
+============
+*/
+int c_removed;
+
+void RemoveColinearPoints (winding_t *w)
+{
+ int i, j, k;
+ vec3_t v1, v2;
+ int nump;
+ vec3_t p[MAX_POINTS_ON_WINDING];
+
+ nump = 0;
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ j = (i+1)%w->numpoints;
+ k = (i+w->numpoints-1)%w->numpoints;
+ VectorSubtract (w->p[j], w->p[i], v1);
+ VectorSubtract (w->p[i], w->p[k], v2);
+ VectorNormalize(v1);
+ VectorNormalize(v2);
+ if (DotProduct(v1, v2) < 0.999)
+ {
+ if (nump >= MAX_POINTS_ON_WINDING)
+ Error("RemoveColinearPoints: MAX_POINTS_ON_WINDING");
+ VectorCopy (w->p[i], p[nump]);
+ nump++;
+ }
+ }
+
+ if (nump == w->numpoints)
+ return;
+
+ if (numthreads == 1)
+ c_removed += w->numpoints - nump;
+ w->numpoints = nump;
+ memcpy (w->p, p, nump*sizeof(p[0]));
+}
+
+/*
+============
+WindingPlane
+============
+*/
+void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist)
+{
+ vec3_t v1, v2;
+ int i;
+
+ //find two vectors each longer than 0.5 units
+ for (i = 0; i < w->numpoints; i++)
+ {
+ VectorSubtract(w->p[(i+1) % w->numpoints], w->p[i], v1);
+ VectorSubtract(w->p[(i+2) % w->numpoints], w->p[i], v2);
+ if (VectorLength(v1) > 0.5 && VectorLength(v2) > 0.5) break;
+ } //end for
+ CrossProduct(v2, v1, normal);
+ VectorNormalize(normal);
+ *dist = DotProduct(w->p[0], normal);
+} //end of the function WindingPlane
+
+/*
+=============
+WindingArea
+=============
+*/
+vec_t WindingArea (winding_t *w)
+{
+ int i;
+ vec3_t d1, d2, cross;
+ vec_t total;
+
+ total = 0;
+ for (i=2 ; i<w->numpoints ; i++)
+ {
+ VectorSubtract (w->p[i-1], w->p[0], d1);
+ VectorSubtract (w->p[i], w->p[0], d2);
+ CrossProduct (d1, d2, cross);
+ total += 0.5 * VectorLength ( cross );
+ }
+ return total;
+}
+
+void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs)
+{
+ vec_t v;
+ int i,j;
+
+ mins[0] = mins[1] = mins[2] = 99999;
+ maxs[0] = maxs[1] = maxs[2] = -99999;
+
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ for (j=0 ; j<3 ; j++)
+ {
+ v = w->p[i][j];
+ if (v < mins[j])
+ mins[j] = v;
+ if (v > maxs[j])
+ maxs[j] = v;
+ }
+ }
+}
+
+/*
+=============
+WindingCenter
+=============
+*/
+void WindingCenter (winding_t *w, vec3_t center)
+{
+ int i;
+ float scale;
+
+ VectorCopy (vec3_origin, center);
+ for (i=0 ; i<w->numpoints ; i++)
+ VectorAdd (w->p[i], center, center);
+
+ scale = 1.0/w->numpoints;
+ VectorScale (center, scale, center);
+}
+
+/*
+=================
+BaseWindingForPlane
+=================
+*/
+winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist)
+{
+ int i, x;
+ vec_t max, v;
+ vec3_t org, vright, vup;
+ winding_t *w;
+
+// find the major axis
+
+ max = -BOGUS_RANGE;
+ x = -1;
+ for (i=0 ; i<3; i++)
+ {
+ v = fabs(normal[i]);
+ if (v > max)
+ {
+ x = i;
+ max = v;
+ }
+ }
+ if (x==-1)
+ Error ("BaseWindingForPlane: no axis found");
+
+ VectorCopy (vec3_origin, vup);
+ switch (x)
+ {
+ case 0:
+ case 1:
+ vup[2] = 1;
+ break;
+ case 2:
+ vup[0] = 1;
+ break;
+ }
+
+ v = DotProduct (vup, normal);
+ VectorMA (vup, -v, normal, vup);
+ VectorNormalize (vup);
+
+ VectorScale (normal, dist, org);
+
+ CrossProduct (vup, normal, vright);
+
+ VectorScale (vup, BOGUS_RANGE, vup);
+ VectorScale (vright, BOGUS_RANGE, vright);
+
+// project a really big axis aligned box onto the plane
+ w = AllocWinding (4);
+
+ VectorSubtract (org, vright, w->p[0]);
+ VectorAdd (w->p[0], vup, w->p[0]);
+
+ VectorAdd (org, vright, w->p[1]);
+ VectorAdd (w->p[1], vup, w->p[1]);
+
+ VectorAdd (org, vright, w->p[2]);
+ VectorSubtract (w->p[2], vup, w->p[2]);
+
+ VectorSubtract (org, vright, w->p[3]);
+ VectorSubtract (w->p[3], vup, w->p[3]);
+
+ w->numpoints = 4;
+
+ return w;
+}
+
+/*
+==================
+CopyWinding
+==================
+*/
+winding_t *CopyWinding (winding_t *w)
+{
+ int size;
+ winding_t *c;
+
+ c = AllocWinding (w->numpoints);
+ size = (int)((winding_t *)0)->p[w->numpoints];
+ memcpy (c, w, size);
+ return c;
+}
+
+/*
+==================
+ReverseWinding
+==================
+*/
+winding_t *ReverseWinding (winding_t *w)
+{
+ int i;
+ winding_t *c;
+
+ c = AllocWinding (w->numpoints);
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ VectorCopy (w->p[w->numpoints-1-i], c->p[i]);
+ }
+ c->numpoints = w->numpoints;
+ return c;
+}
+
+
+/*
+=============
+ClipWindingEpsilon
+=============
+*/
+void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist,
+ vec_t epsilon, winding_t **front, winding_t **back)
+{
+ vec_t dists[MAX_POINTS_ON_WINDING+4];
+ int sides[MAX_POINTS_ON_WINDING+4];
+ int counts[3];
+ //MrElusive: DOH can't use statics when unsing multithreading!!!
+ vec_t dot; // VC 4.2 optimizer bug if not static
+ int i, j;
+ vec_t *p1, *p2;
+ vec3_t mid;
+ winding_t *f, *b;
+ int maxpts;
+
+ counts[0] = counts[1] = counts[2] = 0;
+
+// determine sides for each point
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ dot = DotProduct (in->p[i], normal);
+ dot -= dist;
+ dists[i] = dot;
+ if (dot > epsilon)
+ sides[i] = SIDE_FRONT;
+ else if (dot < -epsilon)
+ sides[i] = SIDE_BACK;
+ else
+ {
+ sides[i] = SIDE_ON;
+ }
+ counts[sides[i]]++;
+ }
+ sides[i] = sides[0];
+ dists[i] = dists[0];
+
+ *front = *back = NULL;
+
+ if (!counts[0])
+ {
+ *back = CopyWinding (in);
+ return;
+ }
+ if (!counts[1])
+ {
+ *front = CopyWinding (in);
+ return;
+ }
+
+ maxpts = in->numpoints+4; // cant use counts[0]+2 because
+ // of fp grouping errors
+
+ *front = f = AllocWinding (maxpts);
+ *back = b = AllocWinding (maxpts);
+
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ p1 = in->p[i];
+
+ if (sides[i] == SIDE_ON)
+ {
+ VectorCopy (p1, f->p[f->numpoints]);
+ f->numpoints++;
+ VectorCopy (p1, b->p[b->numpoints]);
+ b->numpoints++;
+ continue;
+ }
+
+ if (sides[i] == SIDE_FRONT)
+ {
+ VectorCopy (p1, f->p[f->numpoints]);
+ f->numpoints++;
+ }
+ if (sides[i] == SIDE_BACK)
+ {
+ VectorCopy (p1, b->p[b->numpoints]);
+ b->numpoints++;
+ }
+
+ if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
+ continue;
+
+ // generate a split point
+ p2 = in->p[(i+1)%in->numpoints];
+
+ dot = dists[i] / (dists[i]-dists[i+1]);
+ for (j=0 ; j<3 ; j++)
+ { // avoid round off error when possible
+ if (normal[j] == 1)
+ mid[j] = dist;
+ else if (normal[j] == -1)
+ mid[j] = -dist;
+ else
+ mid[j] = p1[j] + dot*(p2[j]-p1[j]);
+ }
+
+ VectorCopy (mid, f->p[f->numpoints]);
+ f->numpoints++;
+ VectorCopy (mid, b->p[b->numpoints]);
+ b->numpoints++;
+ }
+
+ if (f->numpoints > maxpts || b->numpoints > maxpts)
+ Error ("ClipWinding: points exceeded estimate");
+ if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)
+ Error ("ClipWinding: MAX_POINTS_ON_WINDING");
+}
+
+
+/*
+=============
+ChopWindingInPlace
+=============
+*/
+void ChopWindingInPlace (winding_t **inout, vec3_t normal, vec_t dist, vec_t epsilon)
+{
+ winding_t *in;
+ vec_t dists[MAX_POINTS_ON_WINDING+4];
+ int sides[MAX_POINTS_ON_WINDING+4];
+ int counts[3];
+ //MrElusive: DOH can't use statics when unsing multithreading!!!
+ vec_t dot; // VC 4.2 optimizer bug if not static
+ int i, j;
+ vec_t *p1, *p2;
+ vec3_t mid;
+ winding_t *f;
+ int maxpts;
+
+ in = *inout;
+ counts[0] = counts[1] = counts[2] = 0;
+
+// determine sides for each point
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ dot = DotProduct (in->p[i], normal);
+ dot -= dist;
+ dists[i] = dot;
+ if (dot > epsilon)
+ sides[i] = SIDE_FRONT;
+ else if (dot < -epsilon)
+ sides[i] = SIDE_BACK;
+ else
+ {
+ sides[i] = SIDE_ON;
+ }
+ counts[sides[i]]++;
+ }
+ sides[i] = sides[0];
+ dists[i] = dists[0];
+
+ if (!counts[0])
+ {
+ FreeWinding (in);
+ *inout = NULL;
+ return;
+ }
+ if (!counts[1])
+ return; // inout stays the same
+
+ maxpts = in->numpoints+4; // cant use counts[0]+2 because
+ // of fp grouping errors
+
+ f = AllocWinding (maxpts);
+
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ p1 = in->p[i];
+
+ if (sides[i] == SIDE_ON)
+ {
+ VectorCopy (p1, f->p[f->numpoints]);
+ f->numpoints++;
+ continue;
+ }
+
+ if (sides[i] == SIDE_FRONT)
+ {
+ VectorCopy (p1, f->p[f->numpoints]);
+ f->numpoints++;
+ }
+
+ if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
+ continue;
+
+ // generate a split point
+ p2 = in->p[(i+1)%in->numpoints];
+
+ dot = dists[i] / (dists[i]-dists[i+1]);
+ for (j=0 ; j<3 ; j++)
+ { // avoid round off error when possible
+ if (normal[j] == 1)
+ mid[j] = dist;
+ else if (normal[j] == -1)
+ mid[j] = -dist;
+ else
+ mid[j] = p1[j] + dot*(p2[j]-p1[j]);
+ }
+
+ VectorCopy (mid, f->p[f->numpoints]);
+ f->numpoints++;
+ }
+
+ if (f->numpoints > maxpts)
+ Error ("ClipWinding: points exceeded estimate");
+ if (f->numpoints > MAX_POINTS_ON_WINDING)
+ Error ("ClipWinding: MAX_POINTS_ON_WINDING");
+
+ FreeWinding (in);
+ *inout = f;
+}
+
+
+/*
+=================
+ChopWinding
+
+Returns the fragment of in that is on the front side
+of the cliping plane. The original is freed.
+=================
+*/
+winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist)
+{
+ winding_t *f, *b;
+
+ ClipWindingEpsilon (in, normal, dist, ON_EPSILON, &f, &b);
+ FreeWinding (in);
+ if (b)
+ FreeWinding (b);
+ return f;
+}
+
+
+/*
+=================
+CheckWinding
+
+=================
+*/
+void CheckWinding (winding_t *w)
+{
+ int i, j;
+ vec_t *p1, *p2;
+ vec_t d, edgedist;
+ vec3_t dir, edgenormal, facenormal;
+ vec_t area;
+ vec_t facedist;
+
+ if (w->numpoints < 3)
+ Error ("CheckWinding: %i points",w->numpoints);
+
+ area = WindingArea(w);
+ if (area < 1)
+ Error ("CheckWinding: %f area", area);
+
+ WindingPlane (w, facenormal, &facedist);
+
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ p1 = w->p[i];
+
+ for (j=0 ; j<3 ; j++)
+ if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE)
+ Error ("CheckWinding: BUGUS_RANGE: %f",p1[j]);
+
+ j = i+1 == w->numpoints ? 0 : i+1;
+
+ // check the point is on the face plane
+ d = DotProduct (p1, facenormal) - facedist;
+ if (d < -ON_EPSILON || d > ON_EPSILON)
+ Error ("CheckWinding: point off plane");
+
+ // check the edge isnt degenerate
+ p2 = w->p[j];
+ VectorSubtract (p2, p1, dir);
+
+ if (VectorLength (dir) < ON_EPSILON)
+ Error ("CheckWinding: degenerate edge");
+
+ CrossProduct (facenormal, dir, edgenormal);
+ VectorNormalize (edgenormal);
+ edgedist = DotProduct (p1, edgenormal);
+ edgedist += ON_EPSILON;
+
+ // all other points must be on front side
+ for (j=0 ; j<w->numpoints ; j++)
+ {
+ if (j == i)
+ continue;
+ d = DotProduct (w->p[j], edgenormal);
+ if (d > edgedist)
+ Error ("CheckWinding: non-convex");
+ }
+ }
+}
+
+
+/*
+============
+WindingOnPlaneSide
+============
+*/
+int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist)
+{
+ qboolean front, back;
+ int i;
+ vec_t d;
+
+ front = false;
+ back = false;
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ d = DotProduct (w->p[i], normal) - dist;
+ if (d < -ON_EPSILON)
+ {
+ if (front)
+ return SIDE_CROSS;
+ back = true;
+ continue;
+ }
+ if (d > ON_EPSILON)
+ {
+ if (back)
+ return SIDE_CROSS;
+ front = true;
+ continue;
+ }
+ }
+
+ if (back)
+ return SIDE_BACK;
+ if (front)
+ return SIDE_FRONT;
+ return SIDE_ON;
+}
+
+//#ifdef ME
+ #define CONTINUOUS_EPSILON 0.005
+//#else
+// #define CONTINUOUS_EPSILON 0.001
+//#endif
+
+/*
+=============
+TryMergeWinding
+
+If two polygons share a common edge and the edges that meet at the
+common points are both inside the other polygons, merge them
+
+Returns NULL if the faces couldn't be merged, or the new face.
+The originals will NOT be freed.
+=============
+*/
+
+winding_t *TryMergeWinding (winding_t *f1, winding_t *f2, vec3_t planenormal)
+{
+ vec_t *p1, *p2, *p3, *p4, *back;
+ winding_t *newf;
+ int i, j, k, l;
+ vec3_t normal, delta;
+ vec_t dot;
+ qboolean keep1, keep2;
+
+
+ //
+ // find a common edge
+ //
+ p1 = p2 = NULL; // stop compiler warning
+ j = 0; //
+
+ for (i = 0; i < f1->numpoints; i++)
+ {
+ p1 = f1->p[i];
+ p2 = f1->p[(i+1) % f1->numpoints];
+ for (j = 0; j < f2->numpoints; j++)
+ {
+ p3 = f2->p[j];
+ p4 = f2->p[(j+1) % f2->numpoints];
+ for (k = 0; k < 3; k++)
+ {
+ if (fabs(p1[k] - p4[k]) > 0.1)//EQUAL_EPSILON) //ME
+ break;
+ if (fabs(p2[k] - p3[k]) > 0.1)//EQUAL_EPSILON) //ME
+ break;
+ } //end for
+ if (k==3)
+ break;
+ } //end for
+ if (j < f2->numpoints)
+ break;
+ } //end for
+
+ if (i == f1->numpoints)
+ return NULL; // no matching edges
+
+ //
+ // check slope of connected lines
+ // if the slopes are colinear, the point can be removed
+ //
+ back = f1->p[(i+f1->numpoints-1)%f1->numpoints];
+ VectorSubtract (p1, back, delta);
+ CrossProduct (planenormal, delta, normal);
+ VectorNormalize (normal);
+
+ back = f2->p[(j+2)%f2->numpoints];
+ VectorSubtract (back, p1, delta);
+ dot = DotProduct (delta, normal);
+ if (dot > CONTINUOUS_EPSILON)
+ return NULL; // not a convex polygon
+ keep1 = (qboolean)(dot < -CONTINUOUS_EPSILON);
+
+ back = f1->p[(i+2)%f1->numpoints];
+ VectorSubtract (back, p2, delta);
+ CrossProduct (planenormal, delta, normal);
+ VectorNormalize (normal);
+
+ back = f2->p[(j+f2->numpoints-1)%f2->numpoints];
+ VectorSubtract (back, p2, delta);
+ dot = DotProduct (delta, normal);
+ if (dot > CONTINUOUS_EPSILON)
+ return NULL; // not a convex polygon
+ keep2 = (qboolean)(dot < -CONTINUOUS_EPSILON);
+
+ //
+ // build the new polygon
+ //
+ newf = AllocWinding (f1->numpoints + f2->numpoints);
+
+ // copy first polygon
+ for (k=(i+1)%f1->numpoints ; k != i ; k=(k+1)%f1->numpoints)
+ {
+ if (k==(i+1)%f1->numpoints && !keep2)
+ continue;
+
+ VectorCopy (f1->p[k], newf->p[newf->numpoints]);
+ newf->numpoints++;
+ }
+
+ // copy second polygon
+ for (l= (j+1)%f2->numpoints ; l != j ; l=(l+1)%f2->numpoints)
+ {
+ if (l==(j+1)%f2->numpoints && !keep1)
+ continue;
+ VectorCopy (f2->p[l], newf->p[newf->numpoints]);
+ newf->numpoints++;
+ }
+
+ return newf;
+}
+
+//#ifdef ME
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+winding_t *MergeWindings(winding_t *w1, winding_t *w2, vec3_t planenormal)
+{
+ winding_t *neww;
+ float dist;
+ int i, j, n, found, insertafter;
+ int sides[MAX_POINTS_ON_WINDING+4];
+ vec3_t newp[MAX_POINTS_ON_WINDING+4];
+ int numpoints;
+ vec3_t edgevec, sepnormal, v;
+
+ RemoveEqualPoints(w1, 0.2);
+ numpoints = w1->numpoints;
+ memcpy(newp, w1->p, w1->numpoints * sizeof(vec3_t));
+ //
+ for (i = 0; i < w2->numpoints; i++)
+ {
+ VectorCopy(w2->p[i], v);
+ for (j = 0; j < numpoints; j++)
+ {
+ VectorSubtract(newp[(j+1)%numpoints],
+ newp[(j)%numpoints], edgevec);
+ CrossProduct(edgevec, planenormal, sepnormal);
+ VectorNormalize(sepnormal);
+ if (VectorLength(sepnormal) < 0.9)
+ {
+ //remove the point from the new winding
+ for (n = j; n < numpoints-1; n++)
+ {
+ VectorCopy(newp[n+1], newp[n]);
+ sides[n] = sides[n+1];
+ } //end for
+ numpoints--;
+ j--;
+ Log_Print("MergeWindings: degenerate edge on winding %f %f %f\n", sepnormal[0],
+ sepnormal[1],
+ sepnormal[2]);
+ continue;
+ } //end if
+ dist = DotProduct(newp[(j)%numpoints], sepnormal);
+ if (DotProduct(v, sepnormal) - dist < -0.1) sides[j] = SIDE_BACK;
+ else sides[j] = SIDE_FRONT;
+ } //end for
+ //remove all unnecesary points
+ for (j = 0; j < numpoints;)
+ {
+ if (sides[j] == SIDE_BACK
+ && sides[(j+1)%numpoints] == SIDE_BACK)
+ {
+ //remove the point from the new winding
+ for (n = (j+1)%numpoints; n < numpoints-1; n++)
+ {
+ VectorCopy(newp[n+1], newp[n]);
+ sides[n] = sides[n+1];
+ } //end for
+ numpoints--;
+ } //end if
+ else
+ {
+ j++;
+ } //end else
+ } //end for
+ //
+ found = false;
+ for (j = 0; j < numpoints; j++)
+ {
+ if (sides[j] == SIDE_FRONT
+ && sides[(j+1)%numpoints] == SIDE_BACK)
+ {
+ if (found) Log_Print("Warning: MergeWindings: front to back found twice\n");
+ found = true;
+ } //end if
+ } //end for
+ //
+ for (j = 0; j < numpoints; j++)
+ {
+ if (sides[j] == SIDE_FRONT
+ && sides[(j+1)%numpoints] == SIDE_BACK)
+ {
+ insertafter = (j+1)%numpoints;
+ //insert the new point after j+1
+ for (n = numpoints-1; n > insertafter; n--)
+ {
+ VectorCopy(newp[n], newp[n+1]);
+ } //end for
+ numpoints++;
+ VectorCopy(v, newp[(insertafter+1)%numpoints]);
+ break;
+ } //end if
+ } //end for
+ } //end for
+ neww = AllocWinding(numpoints);
+ neww->numpoints = numpoints;
+ memcpy(neww->p, newp, numpoints * sizeof(vec3_t));
+ RemoveColinearPoints(neww);
+ return neww;
+} //end of the function MergeWindings
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+char *WindingErrorString(void)
+{
+ return windingerror;
+} //end of the function WindingErrorString
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int WindingError(winding_t *w)
+{
+ int i, j;
+ vec_t *p1, *p2;
+ vec_t d, edgedist;
+ vec3_t dir, edgenormal, facenormal;
+ vec_t area;
+ vec_t facedist;
+
+ if (w->numpoints < 3)
+ {
+ sprintf(windingerror, "winding %i points", w->numpoints);
+ return WE_NOTENOUGHPOINTS;
+ } //end if
+
+ area = WindingArea(w);
+ if (area < 1)
+ {
+ sprintf(windingerror, "winding %f area", area);
+ return WE_SMALLAREA;
+ } //end if
+
+ WindingPlane (w, facenormal, &facedist);
+
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ p1 = w->p[i];
+
+ for (j=0 ; j<3 ; j++)
+ {
+ if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE)
+ {
+ sprintf(windingerror, "winding point %d BUGUS_RANGE \'%f %f %f\'", j, p1[0], p1[1], p1[2]);
+ return WE_POINTBOGUSRANGE;
+ } //end if
+ } //end for
+
+ j = i+1 == w->numpoints ? 0 : i+1;
+
+ // check the point is on the face plane
+ d = DotProduct (p1, facenormal) - facedist;
+ if (d < -ON_EPSILON || d > ON_EPSILON)
+ {
+ sprintf(windingerror, "winding point %d off plane", i);
+ return WE_POINTOFFPLANE;
+ } //end if
+
+ // check the edge isnt degenerate
+ p2 = w->p[j];
+ VectorSubtract (p2, p1, dir);
+
+ if (VectorLength (dir) < ON_EPSILON)
+ {
+ sprintf(windingerror, "winding degenerate edge %d-%d", i, j);
+ return WE_DEGENERATEEDGE;
+ } //end if
+
+ CrossProduct (facenormal, dir, edgenormal);
+ VectorNormalize (edgenormal);
+ edgedist = DotProduct (p1, edgenormal);
+ edgedist += ON_EPSILON;
+
+ // all other points must be on front side
+ for (j=0 ; j<w->numpoints ; j++)
+ {
+ if (j == i)
+ continue;
+ d = DotProduct (w->p[j], edgenormal);
+ if (d > edgedist)
+ {
+ sprintf(windingerror, "winding non-convex");
+ return WE_NONCONVEX;
+ } //end if
+ } //end for
+ } //end for
+ return WE_NONE;
+} //end of the function WindingError
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void RemoveEqualPoints(winding_t *w, float epsilon)
+{
+ int i, nump;
+ vec3_t v;
+ vec3_t p[MAX_POINTS_ON_WINDING];
+
+ VectorCopy(w->p[0], p[0]);
+ nump = 1;
+ for (i = 1; i < w->numpoints; i++)
+ {
+ VectorSubtract(w->p[i], p[nump-1], v);
+ if (VectorLength(v) > epsilon)
+ {
+ if (nump >= MAX_POINTS_ON_WINDING)
+ Error("RemoveColinearPoints: MAX_POINTS_ON_WINDING");
+ VectorCopy (w->p[i], p[nump]);
+ nump++;
+ } //end if
+ } //end for
+
+ if (nump == w->numpoints)
+ return;
+
+ w->numpoints = nump;
+ memcpy(w->p, p, nump * sizeof(p[0]));
+} //end of the function RemoveEqualPoints
+//===========================================================================
+// adds the given point to a winding at the given spot
+// (for instance when spot is zero then the point is added at position zero)
+// the original winding is NOT freed
+//
+// Parameter: -
+// Returns: the new winding with the added point
+// Changes Globals: -
+//===========================================================================
+winding_t *AddWindingPoint(winding_t *w, vec3_t point, int spot)
+{
+ int i, j;
+ winding_t *neww;
+
+ if (spot > w->numpoints)
+ {
+ Error("AddWindingPoint: num > w->numpoints");
+ } //end if
+ if (spot < 0)
+ {
+ Error("AddWindingPoint: num < 0");
+ } //end if
+ neww = AllocWinding(w->numpoints + 1);
+ neww->numpoints = w->numpoints + 1;
+ for (i = 0, j = 0; i < neww->numpoints; i++)
+ {
+ if (i == spot)
+ {
+ VectorCopy(point, neww->p[i]);
+ } //end if
+ else
+ {
+ VectorCopy(w->p[j], neww->p[i]);
+ j++;
+ } //end else
+ } //end for
+ return neww;
+} //end of the function AddWindingPoint
+//===========================================================================
+// the position where the new point should be added in the winding is
+// stored in *spot
+//
+// Parameter: -
+// Returns: true if the point is on the winding
+// Changes Globals: -
+//===========================================================================
+#define MELT_ON_EPSILON 0.2
+
+int PointOnWinding(winding_t *w, vec3_t normal, float dist, vec3_t point, int *spot)
+{
+ int i, j;
+ vec3_t v1, v2;
+ vec3_t edgenormal, edgevec;
+ float edgedist, dot;
+
+ *spot = 0;
+ //the point must be on the winding plane
+ dot = DotProduct(point, normal) - dist;
+ if (dot < -MELT_ON_EPSILON || dot > MELT_ON_EPSILON) return false;
+ //
+ for (i = 0; i < w->numpoints; i++)
+ {
+ j = (i+1) % w->numpoints;
+ //get a plane orthogonal to the winding plane through the edge
+ VectorSubtract(w->p[j], w->p[i], edgevec);
+ CrossProduct(normal, edgevec, edgenormal);
+ VectorNormalize(edgenormal);
+ edgedist = DotProduct(edgenormal, w->p[i]);
+ //point must be not too far from the plane
+ dot = DotProduct(point, edgenormal) - edgedist;
+ if (dot < -MELT_ON_EPSILON || dot > MELT_ON_EPSILON) continue;
+ //vector from first point of winding to the point to test
+ VectorSubtract(point, w->p[i], v1);
+ //vector from second point of winding to the point to test
+ VectorSubtract(point, w->p[j], v2);
+ //if the length of the vector is not larger than 0.5 units then
+ //the point is assumend to be the same as one of the winding points
+ if (VectorNormalize(v1) < 0.5) return false;
+ if (VectorNormalize(v2) < 0.5) return false;
+ //point must be between the two winding points
+ //(the two vectors must be directed towards each other, and on the
+ //same straight line)
+ if (DotProduct(v1, v2) < -0.99)
+ {
+ *spot = i + 1;
+ return true;
+ } //end if
+ } //end for
+ return false;
+} //end of the function PointOnWinding
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int FindPlaneSeperatingWindings(winding_t *w1, winding_t *w2, vec3_t dir,
+ vec3_t normal, float *dist)
+{
+ int i, i2, j, j2, n;
+ int sides1[3], sides2[3];
+ float dist1, dist2, dot, diff;
+ vec3_t normal1, normal2;
+ vec3_t v1, v2;
+
+ for (i = 0; i < w1->numpoints; i++)
+ {
+ i2 = (i+1) % w1->numpoints;
+ //
+ VectorSubtract(w1->p[i2], w1->p[i], v1);
+ if (VectorLength(v1) < 0.1)
+ {
+ //Log_Write("FindPlaneSeperatingWindings: winding1 with degenerate edge\r\n");
+ continue;
+ } //end if
+ CrossProduct(v1, dir, normal1);
+ VectorNormalize(normal1);
+ dist1 = DotProduct(normal1, w1->p[i]);
+ //
+ for (j = 0; j < w2->numpoints; j++)
+ {
+ j2 = (j+1) % w2->numpoints;
+ //
+ VectorSubtract(w2->p[j2], w2->p[j], v2);
+ if (VectorLength(v2) < 0.1)
+ {
+ //Log_Write("FindPlaneSeperatingWindings: winding2 with degenerate edge\r\n");
+ continue;
+ } //end if
+ CrossProduct(v2, dir, normal2);
+ VectorNormalize(normal2);
+ dist2 = DotProduct(normal2, w2->p[j]);
+ //
+ diff = dist1 - dist2;
+ if (diff < -0.1 || diff > 0.1)
+ {
+ dist2 = -dist2;
+ VectorNegate(normal2, normal2);
+ diff = dist1 - dist2;
+ if (diff < -0.1 || diff > 0.1) continue;
+ } //end if
+ //check if the normal vectors are equal
+ for (n = 0; n < 3; n++)
+ {
+ diff = normal1[n] - normal2[n];
+ if (diff < -0.0001 || diff > 0.0001) break;
+ } //end for
+ if (n != 3) continue;
+ //check on which side of the seperating plane the points of
+ //the first winding are
+ sides1[0] = sides1[1] = sides1[2] = 0;
+ for (n = 0; n < w1->numpoints; n++)
+ {
+ dot = DotProduct(w1->p[n], normal1) - dist1;
+ if (dot > 0.1) sides1[0]++;
+ else if (dot < -0.1) sides1[1]++;
+ else sides1[2]++;
+ } //end for
+ //check on which side of the seperating plane the points of
+ //the second winding are
+ sides2[0] = sides2[1] = sides2[2] = 0;
+ for (n = 0; n < w2->numpoints; n++)
+ {
+ //used normal1 and dist1 (they are equal to normal2 and dist2)
+ dot = DotProduct(w2->p[n], normal1) - dist1;
+ if (dot > 0.1) sides2[0]++;
+ else if (dot < -0.1) sides2[1]++;
+ else sides2[2]++;
+ } //end for
+ //if the first winding has points at both sides
+ if (sides1[0] && sides1[1])
+ {
+ Log_Write("FindPlaneSeperatingWindings: winding1 non-convex\r\n");
+ continue;
+ } //end if
+ //if the second winding has points at both sides
+ if (sides2[0] && sides2[1])
+ {
+ Log_Write("FindPlaneSeperatingWindings: winding2 non-convex\r\n");
+ continue;
+ } //end if
+ //
+ if ((!sides1[0] && !sides1[1]) || (!sides2[0] && !sides2[1]))
+ {
+ //don't use one of the winding planes as the seperating plane
+ continue;
+ } //end if
+ //the windings must be at different sides of the seperating plane
+ if ((!sides1[0] && !sides2[1]) || (!sides1[1] && !sides2[0]))
+ {
+ VectorCopy(normal1, normal);
+ *dist = dist1;
+ return true;
+ } //end if
+ } //end for
+ } //end for
+ return false;
+} //end of the function FindPlaneSeperatingWindings
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+#define WCONVEX_EPSILON 0.2
+
+int WindingsNonConvex(winding_t *w1, winding_t *w2,
+ vec3_t normal1, vec3_t normal2,
+ float dist1, float dist2)
+{
+ int i;
+
+ if (!w1 || !w2) return false;
+
+ //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(normal2, w1->p[i]) - dist2 > WCONVEX_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(normal1, w2->p[i]) - dist1 > WCONVEX_EPSILON) return true;
+ } //end for
+
+ return false;
+} //end of the function WindingsNonConvex
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+/*
+#define VERTEX_EPSILON 0.5
+
+qboolean EqualVertexes(vec3_t v1, vec3_t v2)
+{
+ float diff;
+
+ diff = v1[0] - v2[0];
+ if (diff > -VERTEX_EPSILON && diff < VERTEX_EPSILON)
+ {
+ diff = v1[1] - v2[1];
+ if (diff > -VERTEX_EPSILON && diff < VERTEX_EPSILON)
+ {
+ diff = v1[2] - v2[2];
+ if (diff > -VERTEX_EPSILON && diff < VERTEX_EPSILON)
+ {
+ return true;
+ } //end if
+ } //end if
+ } //end if
+ return false;
+} //end of the function EqualVertexes
+
+#define CONTINUOUS_EPSILON 0.001
+
+winding_t *AAS_MergeWindings(winding_t *w1, winding_t *w2, vec3_t windingnormal)
+{
+ int n, i, k;
+ vec3_t normal, delta;
+ winding_t *winding, *neww;
+ float dist, dot;
+ int p1, p2;
+ int points[2][64];
+ int numpoints[2] = {0, 0};
+ int newnumpoints;
+ int keep[2];
+
+ if (!FindPlaneSeperatingWindings(w1, w2, windingnormal, normal, &dist)) return NULL;
+
+ //for both windings
+ for (n = 0; n < 2; n++)
+ {
+ if (n == 0) winding = w1;
+ else winding = w2;
+ //get the points of the winding which are on the seperating plane
+ for (i = 0; i < winding->numpoints; i++)
+ {
+ dot = DotProduct(winding->p[i], normal) - dist;
+ if (dot > -ON_EPSILON && dot < ON_EPSILON)
+ {
+ //don't allow more than 64 points on the seperating plane
+ if (numpoints[n] >= 64) Error("AAS_MergeWindings: more than 64 points on seperating plane\n");
+ points[n][numpoints[n]++] = i;
+ } //end if
+ } //end for
+ //there must be at least two points of each winding on the seperating plane
+ if (numpoints[n] < 2) return NULL;
+ } //end for
+
+ //if the first point of winding1 (which is on the seperating plane) is unequal
+ //to the last point of winding2 (which is on the seperating plane)
+ if (!EqualVertexes(w1->p[points[0][0]], w2->p[points[1][numpoints[1]-1]]))
+ {
+ return NULL;
+ } //end if
+ //if the last point of winding1 (which is on the seperating plane) is unequal
+ //to the first point of winding2 (which is on the seperating plane)
+ if (!EqualVertexes(w1->p[points[0][numpoints[0]-1]], w2->p[points[1][0]]))
+ {
+ return NULL;
+ } //end if
+ //
+ // check slope of connected lines
+ // if the slopes are colinear, the point can be removed
+ //
+ //first point of winding1 which is on the seperating plane
+ p1 = points[0][0];
+ //point before p1
+ p2 = (p1 + w1->numpoints - 1) % w1->numpoints;
+ VectorSubtract(w1->p[p1], w1->p[p2], delta);
+ CrossProduct(windingnormal, delta, normal);
+ VectorNormalize(normal, normal);
+
+ //last point of winding2 which is on the seperating plane
+ p1 = points[1][numpoints[1]-1];
+ //point after p1
+ p2 = (p1 + 1) % w2->numpoints;
+ VectorSubtract(w2->p[p2], w2->p[p1], delta);
+ dot = DotProduct(delta, normal);
+ if (dot > CONTINUOUS_EPSILON) return NULL; //merging would create a non-convex polygon
+ keep[0] = (qboolean)(dot < -CONTINUOUS_EPSILON);
+
+ //first point of winding2 which is on the seperating plane
+ p1 = points[1][0];
+ //point before p1
+ p2 = (p1 + w2->numpoints - 1) % w2->numpoints;
+ VectorSubtract(w2->p[p1], w2->p[p2], delta);
+ CrossProduct(windingnormal, delta, normal);
+ VectorNormalize(normal, normal);
+
+ //last point of winding1 which is on the seperating plane
+ p1 = points[0][numpoints[0]-1];
+ //point after p1
+ p2 = (p1 + 1) % w1->numpoints;
+ VectorSubtract(w1->p[p2], w1->p[p1], delta);
+ dot = DotProduct(delta, normal);
+ if (dot > CONTINUOUS_EPSILON) return NULL; //merging would create a non-convex polygon
+ keep[1] = (qboolean)(dot < -CONTINUOUS_EPSILON);
+
+ //number of points on the new winding
+ newnumpoints = w1->numpoints - numpoints[0] + w2->numpoints - numpoints[1] + 2;
+ //allocate the winding
+ neww = AllocWinding(newnumpoints);
+ neww->numpoints = newnumpoints;
+ //copy all the points
+ k = 0;
+ //for both windings
+ for (n = 0; n < 2; n++)
+ {
+ if (n == 0) winding = w1;
+ else winding = w2;
+ //copy the points of the winding starting with the last point on the
+ //seperating plane and ending before the first point on the seperating plane
+ for (i = points[n][numpoints[n]-1]; i != points[n][0]; i = (i+1)%winding->numpoints)
+ {
+ if (k >= newnumpoints)
+ {
+ Log_Print("numpoints[0] = %d\n", numpoints[0]);
+ Log_Print("numpoints[1] = %d\n", numpoints[1]);
+ Error("AAS_MergeWindings: k = %d >= newnumpoints = %d\n", k, newnumpoints);
+ } //end if
+ VectorCopy(winding->p[i], neww->p[k]);
+ k++;
+ } //end for
+ } //end for
+ RemoveEqualPoints(neww);
+ if (!WindingIsOk(neww, 1))
+ {
+ Log_Print("AAS_MergeWindings: winding not ok after merging\n");
+ FreeWinding(neww);
+ return NULL;
+ } //end if
+ return neww;
+} //end of the function AAS_MergeWindings*/
+//#endif //ME
diff --git a/code/bspc/l_poly.h b/code/bspc/l_poly.h
index a14b834..f3191eb 100755
--- a/code/bspc/l_poly.h
+++ b/code/bspc/l_poly.h
@@ -1,120 +1,120 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-
-//a winding gives the bounding points of a convex polygon
-typedef struct
-{
- int numpoints;
- vec3_t p[4]; //variable sized
-} winding_t;
-
-#define MAX_POINTS_ON_WINDING 96
-
-//you can define on_epsilon in the makefile as tighter
-#ifndef ON_EPSILON
-#define ON_EPSILON 0.1
-#endif
-//winding errors
-#define WE_NONE 0
-#define WE_NOTENOUGHPOINTS 1
-#define WE_SMALLAREA 2
-#define WE_POINTBOGUSRANGE 3
-#define WE_POINTOFFPLANE 4
-#define WE_DEGENERATEEDGE 5
-#define WE_NONCONVEX 6
-
-//allocates a winding
-winding_t *AllocWinding (int points);
-//returns the area of the winding
-vec_t WindingArea (winding_t *w);
-//gives the center of the winding
-void WindingCenter (winding_t *w, vec3_t center);
-//clips the given winding to the given plane and gives the front
-//and back part of the clipped winding
-void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist,
- vec_t epsilon, winding_t **front, winding_t **back);
-//returns the fragment of the given winding that is on the front
-//side of the cliping plane. The original is freed.
-winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist);
-//returns a copy of the given winding
-winding_t *CopyWinding (winding_t *w);
-//returns the reversed winding of the given one
-winding_t *ReverseWinding (winding_t *w);
-//returns a base winding for the given plane
-winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist);
-//checks the winding for errors
-void CheckWinding (winding_t *w);
-//returns the plane normal and dist the winding is in
-void WindingPlane(winding_t *w, vec3_t normal, vec_t *dist);
-//removes colinear points from the winding
-void RemoveColinearPoints(winding_t *w);
-//returns on which side of the plane the winding is situated
-int WindingOnPlaneSide(winding_t *w, vec3_t normal, vec_t dist);
-//frees the winding
-void FreeWinding(winding_t *w);
-//gets the bounds of the winding
-void WindingBounds(winding_t *w, vec3_t mins, vec3_t maxs);
-//chops the winding with the given plane, the original winding is freed if clipped
-void ChopWindingInPlace (winding_t **w, vec3_t normal, vec_t dist, vec_t epsilon);
-//prints the winding points on STDOUT
-void pw(winding_t *w);
-//try to merge the two windings which are in the given plane
-//the original windings are undisturbed
-//the merged winding is returned when merging was possible
-//NULL is returned otherwise
-winding_t *TryMergeWinding (winding_t *f1, winding_t *f2, vec3_t planenormal);
-//brute force winding merging... creates a convex winding out of
-//the two whatsoever
-winding_t *MergeWindings(winding_t *w1, winding_t *w2, vec3_t planenormal);
-
-//#ifdef ME
-void ResetWindings(void);
-//returns the amount of winding memory
-int WindingMemory(void);
-int WindingPeakMemory(void);
-int ActiveWindings(void);
-//returns the winding error string
-char *WindingErrorString(void);
-//returns one of the WE_ flags when the winding has errors
-int WindingError(winding_t *w);
-//removes equal points from the winding
-void RemoveEqualPoints(winding_t *w, float epsilon);
-//returns a winding with a point added at the given spot to the
-//given winding, original winding is NOT freed
-winding_t *AddWindingPoint(winding_t *w, vec3_t point, int spot);
-//returns true if the point is on one of the winding 'edges'
-//when the point is on one of the edged the number of the first
-//point of the edge is stored in 'spot'
-int PointOnWinding(winding_t *w, vec3_t normal, float dist, vec3_t point, int *spot);
-//find a plane seperating the two windings
-//true is returned when the windings area adjacent
-//the seperating plane normal and distance area stored in 'normal' and 'dist'
-//this plane will contain both the piece of common edge of the two windings
-//and the vector 'dir'
-int FindPlaneSeperatingWindings(winding_t *w1, winding_t *w2, vec3_t dir,
- vec3_t normal, float *dist);
-//
-int WindingsNonConvex(winding_t *w1, winding_t *w2,
- vec3_t normal1, vec3_t normal2,
- float dist1, float dist2);
-//#endif //ME
-
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+//a winding gives the bounding points of a convex polygon
+typedef struct
+{
+ int numpoints;
+ vec3_t p[4]; //variable sized
+} winding_t;
+
+#define MAX_POINTS_ON_WINDING 96
+
+//you can define on_epsilon in the makefile as tighter
+#ifndef ON_EPSILON
+#define ON_EPSILON 0.1
+#endif
+//winding errors
+#define WE_NONE 0
+#define WE_NOTENOUGHPOINTS 1
+#define WE_SMALLAREA 2
+#define WE_POINTBOGUSRANGE 3
+#define WE_POINTOFFPLANE 4
+#define WE_DEGENERATEEDGE 5
+#define WE_NONCONVEX 6
+
+//allocates a winding
+winding_t *AllocWinding (int points);
+//returns the area of the winding
+vec_t WindingArea (winding_t *w);
+//gives the center of the winding
+void WindingCenter (winding_t *w, vec3_t center);
+//clips the given winding to the given plane and gives the front
+//and back part of the clipped winding
+void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist,
+ vec_t epsilon, winding_t **front, winding_t **back);
+//returns the fragment of the given winding that is on the front
+//side of the cliping plane. The original is freed.
+winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist);
+//returns a copy of the given winding
+winding_t *CopyWinding (winding_t *w);
+//returns the reversed winding of the given one
+winding_t *ReverseWinding (winding_t *w);
+//returns a base winding for the given plane
+winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist);
+//checks the winding for errors
+void CheckWinding (winding_t *w);
+//returns the plane normal and dist the winding is in
+void WindingPlane(winding_t *w, vec3_t normal, vec_t *dist);
+//removes colinear points from the winding
+void RemoveColinearPoints(winding_t *w);
+//returns on which side of the plane the winding is situated
+int WindingOnPlaneSide(winding_t *w, vec3_t normal, vec_t dist);
+//frees the winding
+void FreeWinding(winding_t *w);
+//gets the bounds of the winding
+void WindingBounds(winding_t *w, vec3_t mins, vec3_t maxs);
+//chops the winding with the given plane, the original winding is freed if clipped
+void ChopWindingInPlace (winding_t **w, vec3_t normal, vec_t dist, vec_t epsilon);
+//prints the winding points on STDOUT
+void pw(winding_t *w);
+//try to merge the two windings which are in the given plane
+//the original windings are undisturbed
+//the merged winding is returned when merging was possible
+//NULL is returned otherwise
+winding_t *TryMergeWinding (winding_t *f1, winding_t *f2, vec3_t planenormal);
+//brute force winding merging... creates a convex winding out of
+//the two whatsoever
+winding_t *MergeWindings(winding_t *w1, winding_t *w2, vec3_t planenormal);
+
+//#ifdef ME
+void ResetWindings(void);
+//returns the amount of winding memory
+int WindingMemory(void);
+int WindingPeakMemory(void);
+int ActiveWindings(void);
+//returns the winding error string
+char *WindingErrorString(void);
+//returns one of the WE_ flags when the winding has errors
+int WindingError(winding_t *w);
+//removes equal points from the winding
+void RemoveEqualPoints(winding_t *w, float epsilon);
+//returns a winding with a point added at the given spot to the
+//given winding, original winding is NOT freed
+winding_t *AddWindingPoint(winding_t *w, vec3_t point, int spot);
+//returns true if the point is on one of the winding 'edges'
+//when the point is on one of the edged the number of the first
+//point of the edge is stored in 'spot'
+int PointOnWinding(winding_t *w, vec3_t normal, float dist, vec3_t point, int *spot);
+//find a plane seperating the two windings
+//true is returned when the windings area adjacent
+//the seperating plane normal and distance area stored in 'normal' and 'dist'
+//this plane will contain both the piece of common edge of the two windings
+//and the vector 'dir'
+int FindPlaneSeperatingWindings(winding_t *w1, winding_t *w2, vec3_t dir,
+ vec3_t normal, float *dist);
+//
+int WindingsNonConvex(winding_t *w1, winding_t *w2,
+ vec3_t normal1, vec3_t normal2,
+ float dist1, float dist2);
+//#endif //ME
+
diff --git a/code/bspc/l_qfiles.c b/code/bspc/l_qfiles.c
index 32cb6de..e2e8d10 100755
--- a/code/bspc/l_qfiles.c
+++ b/code/bspc/l_qfiles.c
@@ -1,663 +1,663 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-
-#if defined(WIN32)|defined(_WIN32)
-#include <windows.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#else
-#include <glob.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#endif
-
-#include "qbsp.h"
-
-//file extensions with their type
-typedef struct qfile_exttype_s
-{
- char *extension;
- int type;
-} qfile_exttyp_t;
-
-qfile_exttyp_t quakefiletypes[] =
-{
- {QFILEEXT_UNKNOWN, QFILETYPE_UNKNOWN},
- {QFILEEXT_PAK, QFILETYPE_PAK},
- {QFILEEXT_PK3, QFILETYPE_PK3},
- {QFILEEXT_SIN, QFILETYPE_PAK},
- {QFILEEXT_BSP, QFILETYPE_BSP},
- {QFILEEXT_MAP, QFILETYPE_MAP},
- {QFILEEXT_MDL, QFILETYPE_MDL},
- {QFILEEXT_MD2, QFILETYPE_MD2},
- {QFILEEXT_MD3, QFILETYPE_MD3},
- {QFILEEXT_WAL, QFILETYPE_WAL},
- {QFILEEXT_WAV, QFILETYPE_WAV},
- {QFILEEXT_AAS, QFILETYPE_AAS},
- {NULL, 0}
-};
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int QuakeFileExtensionType(char *extension)
-{
- int i;
-
- for (i = 0; quakefiletypes[i].extension; i++)
- {
- if (!stricmp(extension, quakefiletypes[i].extension))
- {
- return quakefiletypes[i].type;
- } //end if
- } //end for
- return QFILETYPE_UNKNOWN;
-} //end of the function QuakeFileExtensionType
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-char *QuakeFileTypeExtension(int type)
-{
- int i;
-
- for (i = 0; quakefiletypes[i].extension; i++)
- {
- if (quakefiletypes[i].type == type)
- {
- return quakefiletypes[i].extension;
- } //end if
- } //end for
- return QFILEEXT_UNKNOWN;
-} //end of the function QuakeFileExtension
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int QuakeFileType(char *filename)
-{
- char ext[_MAX_PATH] = ".";
-
- ExtractFileExtension(filename, ext+1);
- return QuakeFileExtensionType(ext);
-} //end of the function QuakeFileTypeFromFileName
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-char *StringContains(char *str1, char *str2, int casesensitive)
-{
- int len, i, j;
-
- len = strlen(str1) - strlen(str2);
- for (i = 0; i <= len; i++, str1++)
- {
- for (j = 0; str2[j]; j++)
- {
- if (casesensitive)
- {
- if (str1[j] != str2[j]) break;
- } //end if
- else
- {
- if (toupper(str1[j]) != toupper(str2[j])) break;
- } //end else
- } //end for
- if (!str2[j]) return str1;
- } //end for
- return NULL;
-} //end of the function StringContains
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int FileFilter(char *filter, char *filename, int casesensitive)
-{
- char buf[1024];
- char *ptr;
- int i, found;
-
- while(*filter)
- {
- if (*filter == '*')
- {
- filter++;
- for (i = 0; *filter; i++)
- {
- if (*filter == '*' || *filter == '?') break;
- buf[i] = *filter;
- filter++;
- } //end for
- buf[i] = '\0';
- if (strlen(buf))
- {
- ptr = StringContains(filename, buf, casesensitive);
- if (!ptr) return false;
- filename = ptr + strlen(buf);
- } //end if
- } //end if
- else if (*filter == '?')
- {
- filter++;
- filename++;
- } //end else if
- else if (*filter == '[' && *(filter+1) == '[')
- {
- filter++;
- } //end if
- else if (*filter == '[')
- {
- filter++;
- found = false;
- while(*filter && !found)
- {
- if (*filter == ']' && *(filter+1) != ']') break;
- if (*(filter+1) == '-' && *(filter+2) && (*(filter+2) != ']' || *(filter+3) == ']'))
- {
- if (casesensitive)
- {
- if (*filename >= *filter && *filename <= *(filter+2)) found = true;
- } //end if
- else
- {
- if (toupper(*filename) >= toupper(*filter) &&
- toupper(*filename) <= toupper(*(filter+2))) found = true;
- } //end else
- filter += 3;
- } //end if
- else
- {
- if (casesensitive)
- {
- if (*filter == *filename) found = true;
- } //end if
- else
- {
- if (toupper(*filter) == toupper(*filename)) found = true;
- } //end else
- filter++;
- } //end else
- } //end while
- if (!found) return false;
- while(*filter)
- {
- if (*filter == ']' && *(filter+1) != ']') break;
- filter++;
- } //end while
- filter++;
- filename++;
- } //end else if
- else
- {
- if (casesensitive)
- {
- if (*filter != *filename) return false;
- } //end if
- else
- {
- if (toupper(*filter) != toupper(*filename)) return false;
- } //end else
- filter++;
- filename++;
- } //end else
- } //end while
- return true;
-} //end of the function FileFilter
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-quakefile_t *FindQuakeFilesInZip(char *zipfile, char *filter)
-{
- unzFile uf;
- int err;
- unz_global_info gi;
- char filename_inzip[MAX_PATH];
- unz_file_info file_info;
- int i;
- quakefile_t *qfiles, *lastqf, *qf;
-
- uf = unzOpen(zipfile);
- err = unzGetGlobalInfo(uf, &gi);
-
- if (err != UNZ_OK) return NULL;
-
- unzGoToFirstFile(uf);
-
- qfiles = NULL;
- lastqf = NULL;
- for (i = 0; i < gi.number_entry; i++)
- {
- err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL,0,NULL,0);
- if (err != UNZ_OK) break;
-
- ConvertPath(filename_inzip);
- if (FileFilter(filter, filename_inzip, false))
- {
- qf = malloc(sizeof(quakefile_t));
- if (!qf) Error("out of memory");
- memset(qf, 0, sizeof(quakefile_t));
- strcpy(qf->pakfile, zipfile);
- strcpy(qf->filename, zipfile);
- strcpy(qf->origname, filename_inzip);
- qf->zipfile = true;
- //memcpy( &buildBuffer[i].zipfileinfo, (unz_s*)uf, sizeof(unz_s));
- memcpy(&qf->zipinfo, (unz_s*)uf, sizeof(unz_s));
- qf->offset = 0;
- qf->length = file_info.uncompressed_size;
- qf->type = QuakeFileType(filename_inzip);
- //add the file ot the list
- qf->next = NULL;
- if (lastqf) lastqf->next = qf;
- else qfiles = qf;
- lastqf = qf;
- } //end if
- unzGoToNextFile(uf);
- } //end for
-
- unzClose(uf);
-
- return qfiles;
-} //end of the function FindQuakeFilesInZip
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-quakefile_t *FindQuakeFilesInPak(char *pakfile, char *filter)
-{
- FILE *fp;
- dpackheader_t packheader;
- dsinpackfile_t *packfiles;
- dpackfile_t *idpackfiles;
- quakefile_t *qfiles, *lastqf, *qf;
- int numpackdirs, i;
-
- qfiles = NULL;
- lastqf = NULL;
- //open the pak file
- fp = fopen(pakfile, "rb");
- if (!fp)
- {
- Warning("can't open pak file %s", pakfile);
- return NULL;
- } //end if
- //read pak header, check for valid pak id and seek to the dir entries
- if ((fread(&packheader, 1, sizeof(dpackheader_t), fp) != sizeof(dpackheader_t))
- || (packheader.ident != IDPAKHEADER && packheader.ident != SINPAKHEADER)
- || (fseek(fp, LittleLong(packheader.dirofs), SEEK_SET))
- )
- {
- fclose(fp);
- Warning("invalid pak file %s", pakfile);
- return NULL;
- } //end if
- //if it is a pak file from id software
- if (packheader.ident == IDPAKHEADER)
- {
- //number of dir entries in the pak file
- numpackdirs = LittleLong(packheader.dirlen) / sizeof(dpackfile_t);
- idpackfiles = (dpackfile_t *) malloc(numpackdirs * sizeof(dpackfile_t));
- if (!idpackfiles) Error("out of memory");
- //read the dir entry
- if (fread(idpackfiles, sizeof(dpackfile_t), numpackdirs, fp) != numpackdirs)
- {
- fclose(fp);
- free(idpackfiles);
- Warning("can't read the Quake pak file dir entries from %s", pakfile);
- return NULL;
- } //end if
- fclose(fp);
- //convert to sin pack files
- packfiles = (dsinpackfile_t *) malloc(numpackdirs * sizeof(dsinpackfile_t));
- if (!packfiles) Error("out of memory");
- for (i = 0; i < numpackdirs; i++)
- {
- strcpy(packfiles[i].name, idpackfiles[i].name);
- packfiles[i].filepos = LittleLong(idpackfiles[i].filepos);
- packfiles[i].filelen = LittleLong(idpackfiles[i].filelen);
- } //end for
- free(idpackfiles);
- } //end if
- else //its a Sin pack file
- {
- //number of dir entries in the pak file
- numpackdirs = LittleLong(packheader.dirlen) / sizeof(dsinpackfile_t);
- packfiles = (dsinpackfile_t *) malloc(numpackdirs * sizeof(dsinpackfile_t));
- if (!packfiles) Error("out of memory");
- //read the dir entry
- if (fread(packfiles, sizeof(dsinpackfile_t), numpackdirs, fp) != numpackdirs)
- {
- fclose(fp);
- free(packfiles);
- Warning("can't read the Sin pak file dir entries from %s", pakfile);
- return NULL;
- } //end if
- fclose(fp);
- for (i = 0; i < numpackdirs; i++)
- {
- packfiles[i].filepos = LittleLong(packfiles[i].filepos);
- packfiles[i].filelen = LittleLong(packfiles[i].filelen);
- } //end for
- } //end else
- //
- for (i = 0; i < numpackdirs; i++)
- {
- ConvertPath(packfiles[i].name);
- if (FileFilter(filter, packfiles[i].name, false))
- {
- qf = malloc(sizeof(quakefile_t));
- if (!qf) Error("out of memory");
- memset(qf, 0, sizeof(quakefile_t));
- strcpy(qf->pakfile, pakfile);
- strcpy(qf->filename, pakfile);
- strcpy(qf->origname, packfiles[i].name);
- qf->zipfile = false;
- qf->offset = packfiles[i].filepos;
- qf->length = packfiles[i].filelen;
- qf->type = QuakeFileType(packfiles[i].name);
- //add the file ot the list
- qf->next = NULL;
- if (lastqf) lastqf->next = qf;
- else qfiles = qf;
- lastqf = qf;
- } //end if
- } //end for
- free(packfiles);
- return qfiles;
-} //end of the function FindQuakeFilesInPak
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-quakefile_t *FindQuakeFilesWithPakFilter(char *pakfilter, char *filter)
-{
-#if defined(WIN32)|defined(_WIN32)
- WIN32_FIND_DATA filedata;
- HWND handle;
- struct _stat statbuf;
-#else
- glob_t globbuf;
- struct stat statbuf;
- int j;
-#endif
- quakefile_t *qfiles, *lastqf, *qf;
- char pakfile[_MAX_PATH], filename[_MAX_PATH], *str;
- int done;
-
- qfiles = NULL;
- lastqf = NULL;
- if (pakfilter && strlen(pakfilter))
- {
-#if defined(WIN32)|defined(_WIN32)
- handle = FindFirstFile(pakfilter, &filedata);
- done = (handle == INVALID_HANDLE_VALUE);
- while(!done)
- {
- _splitpath(pakfilter, pakfile, NULL, NULL, NULL);
- _splitpath(pakfilter, NULL, &pakfile[strlen(pakfile)], NULL, NULL);
- AppendPathSeperator(pakfile, _MAX_PATH);
- strcat(pakfile, filedata.cFileName);
- _stat(pakfile, &statbuf);
-#else
- glob(pakfilter, 0, NULL, &globbuf);
- for (j = 0; j < globbuf.gl_pathc; j++)
- {
- strcpy(pakfile, globbuf.gl_pathv[j]);
- stat(pakfile, &statbuf);
-#endif
- //if the file with .pak or .pk3 is a folder
- if (statbuf.st_mode & S_IFDIR)
- {
- strcpy(filename, pakfilter);
- AppendPathSeperator(filename, _MAX_PATH);
- strcat(filename, filter);
- qf = FindQuakeFilesWithPakFilter(NULL, filename);
- if (lastqf) lastqf->next = qf;
- else qfiles = qf;
- lastqf = qf;
- while(lastqf->next) lastqf = lastqf->next;
- } //end if
- else
- {
-#if defined(WIN32)|defined(_WIN32)
- str = StringContains(pakfile, ".pk3", false);
-#else
- str = StringContains(pakfile, ".pk3", true);
-#endif
- if (str && str == pakfile + strlen(pakfile) - strlen(".pk3"))
- {
- qf = FindQuakeFilesInZip(pakfile, filter);
- } //end if
- else
- {
- qf = FindQuakeFilesInPak(pakfile, filter);
- } //end else
- //
- if (qf)
- {
- if (lastqf) lastqf->next = qf;
- else qfiles = qf;
- lastqf = qf;
- while(lastqf->next) lastqf = lastqf->next;
- } //end if
- } //end else
- //
-#if defined(WIN32)|defined(_WIN32)
- //find the next file
- done = !FindNextFile(handle, &filedata);
- } //end while
-#else
- } //end for
- globfree(&globbuf);
-#endif
- } //end if
- else
- {
-#if defined(WIN32)|defined(_WIN32)
- handle = FindFirstFile(filter, &filedata);
- done = (handle == INVALID_HANDLE_VALUE);
- while(!done)
- {
- _splitpath(filter, filename, NULL, NULL, NULL);
- _splitpath(filter, NULL, &filename[strlen(filename)], NULL, NULL);
- AppendPathSeperator(filename, _MAX_PATH);
- strcat(filename, filedata.cFileName);
-#else
- glob(filter, 0, NULL, &globbuf);
- for (j = 0; j < globbuf.gl_pathc; j++)
- {
- strcpy(filename, globbuf.gl_pathv[j]);
-#endif
- //
- qf = malloc(sizeof(quakefile_t));
- if (!qf) Error("out of memory");
- memset(qf, 0, sizeof(quakefile_t));
- strcpy(qf->pakfile, "");
- strcpy(qf->filename, filename);
- strcpy(qf->origname, filename);
- qf->offset = 0;
- qf->length = 0;
- qf->type = QuakeFileType(filename);
- //add the file ot the list
- qf->next = NULL;
- if (lastqf) lastqf->next = qf;
- else qfiles = qf;
- lastqf = qf;
-#if defined(WIN32)|defined(_WIN32)
- //find the next file
- done = !FindNextFile(handle, &filedata);
- } //end while
-#else
- } //end for
- globfree(&globbuf);
-#endif
- } //end else
- return qfiles;
-} //end of the function FindQuakeFilesWithPakFilter
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-quakefile_t *FindQuakeFiles(char *filter)
-{
- char *str;
- char newfilter[_MAX_PATH];
- char pakfilter[_MAX_PATH];
- char filefilter[_MAX_PATH];
-
- strcpy(newfilter, filter);
- ConvertPath(newfilter);
- strcpy(pakfilter, newfilter);
-
- str = StringContains(pakfilter, ".pak", false);
- if (!str) str = StringContains(pakfilter, ".pk3", false);
-
- if (str)
- {
- str += strlen(".pak");
- if (*str)
- {
- *str++ = '\0';
- while(*str == '\\' || *str == '/') str++;
- strcpy(filefilter, str);
- return FindQuakeFilesWithPakFilter(pakfilter, filefilter);
- } //end if
- } //end else
- return FindQuakeFilesWithPakFilter(NULL, newfilter);
-} //end of the function FindQuakeFiles
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int LoadQuakeFile(quakefile_t *qf, void **bufferptr)
-{
- FILE *fp;
- void *buffer;
- int length;
- unzFile zf;
-
- if (qf->zipfile)
- {
- //open the zip file
- zf = unzOpen(qf->pakfile);
- //set the file pointer
- qf->zipinfo.file = ((unz_s *) zf)->file;
- //open the Quake file in the zip file
- unzOpenCurrentFile(&qf->zipinfo);
- //allocate memory for the buffer
- length = qf->length;
- buffer = GetMemory(length+1);
- //read the Quake file from the zip file
- length = unzReadCurrentFile(&qf->zipinfo, buffer, length);
- //close the Quake file in the zip file
- unzCloseCurrentFile(&qf->zipinfo);
- //close the zip file
- unzClose(zf);
-
- *bufferptr = buffer;
- return length;
- } //end if
- else
- {
- fp = SafeOpenRead(qf->filename);
- if (qf->offset) fseek(fp, qf->offset, SEEK_SET);
- length = qf->length;
- if (!length) length = Q_filelength(fp);
- buffer = GetMemory(length+1);
- ((char *)buffer)[length] = 0;
- SafeRead(fp, buffer, length);
- fclose(fp);
-
- *bufferptr = buffer;
- return length;
- } //end else
-} //end of the function LoadQuakeFile
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int ReadQuakeFile(quakefile_t *qf, void *buffer, int offset, int length)
-{
- FILE *fp;
- int read;
- unzFile zf;
- char tmpbuf[1024];
-
- if (qf->zipfile)
- {
- //open the zip file
- zf = unzOpen(qf->pakfile);
- //set the file pointer
- qf->zipinfo.file = ((unz_s *) zf)->file;
- //open the Quake file in the zip file
- unzOpenCurrentFile(&qf->zipinfo);
- //
- while(offset > 0)
- {
- read = offset;
- if (read > sizeof(tmpbuf)) read = sizeof(tmpbuf);
- unzReadCurrentFile(&qf->zipinfo, tmpbuf, read);
- offset -= read;
- } //end while
- //read the Quake file from the zip file
- length = unzReadCurrentFile(&qf->zipinfo, buffer, length);
- //close the Quake file in the zip file
- unzCloseCurrentFile(&qf->zipinfo);
- //close the zip file
- unzClose(zf);
-
- return length;
- } //end if
- else
- {
- fp = SafeOpenRead(qf->filename);
- if (qf->offset) fseek(fp, qf->offset, SEEK_SET);
- if (offset) fseek(fp, offset, SEEK_CUR);
- SafeRead(fp, buffer, length);
- fclose(fp);
-
- return length;
- } //end else
-} //end of the function ReadQuakeFile
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+#if defined(WIN32)|defined(_WIN32)
+#include <windows.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#else
+#include <glob.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+#include "qbsp.h"
+
+//file extensions with their type
+typedef struct qfile_exttype_s
+{
+ char *extension;
+ int type;
+} qfile_exttyp_t;
+
+qfile_exttyp_t quakefiletypes[] =
+{
+ {QFILEEXT_UNKNOWN, QFILETYPE_UNKNOWN},
+ {QFILEEXT_PAK, QFILETYPE_PAK},
+ {QFILEEXT_PK3, QFILETYPE_PK3},
+ {QFILEEXT_SIN, QFILETYPE_PAK},
+ {QFILEEXT_BSP, QFILETYPE_BSP},
+ {QFILEEXT_MAP, QFILETYPE_MAP},
+ {QFILEEXT_MDL, QFILETYPE_MDL},
+ {QFILEEXT_MD2, QFILETYPE_MD2},
+ {QFILEEXT_MD3, QFILETYPE_MD3},
+ {QFILEEXT_WAL, QFILETYPE_WAL},
+ {QFILEEXT_WAV, QFILETYPE_WAV},
+ {QFILEEXT_AAS, QFILETYPE_AAS},
+ {NULL, 0}
+};
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int QuakeFileExtensionType(char *extension)
+{
+ int i;
+
+ for (i = 0; quakefiletypes[i].extension; i++)
+ {
+ if (!stricmp(extension, quakefiletypes[i].extension))
+ {
+ return quakefiletypes[i].type;
+ } //end if
+ } //end for
+ return QFILETYPE_UNKNOWN;
+} //end of the function QuakeFileExtensionType
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+char *QuakeFileTypeExtension(int type)
+{
+ int i;
+
+ for (i = 0; quakefiletypes[i].extension; i++)
+ {
+ if (quakefiletypes[i].type == type)
+ {
+ return quakefiletypes[i].extension;
+ } //end if
+ } //end for
+ return QFILEEXT_UNKNOWN;
+} //end of the function QuakeFileExtension
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int QuakeFileType(char *filename)
+{
+ char ext[_MAX_PATH] = ".";
+
+ ExtractFileExtension(filename, ext+1);
+ return QuakeFileExtensionType(ext);
+} //end of the function QuakeFileTypeFromFileName
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+char *StringContains(char *str1, char *str2, int casesensitive)
+{
+ int len, i, j;
+
+ len = strlen(str1) - strlen(str2);
+ for (i = 0; i <= len; i++, str1++)
+ {
+ for (j = 0; str2[j]; j++)
+ {
+ if (casesensitive)
+ {
+ if (str1[j] != str2[j]) break;
+ } //end if
+ else
+ {
+ if (toupper(str1[j]) != toupper(str2[j])) break;
+ } //end else
+ } //end for
+ if (!str2[j]) return str1;
+ } //end for
+ return NULL;
+} //end of the function StringContains
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int FileFilter(char *filter, char *filename, int casesensitive)
+{
+ char buf[1024];
+ char *ptr;
+ int i, found;
+
+ while(*filter)
+ {
+ if (*filter == '*')
+ {
+ filter++;
+ for (i = 0; *filter; i++)
+ {
+ if (*filter == '*' || *filter == '?') break;
+ buf[i] = *filter;
+ filter++;
+ } //end for
+ buf[i] = '\0';
+ if (strlen(buf))
+ {
+ ptr = StringContains(filename, buf, casesensitive);
+ if (!ptr) return false;
+ filename = ptr + strlen(buf);
+ } //end if
+ } //end if
+ else if (*filter == '?')
+ {
+ filter++;
+ filename++;
+ } //end else if
+ else if (*filter == '[' && *(filter+1) == '[')
+ {
+ filter++;
+ } //end if
+ else if (*filter == '[')
+ {
+ filter++;
+ found = false;
+ while(*filter && !found)
+ {
+ if (*filter == ']' && *(filter+1) != ']') break;
+ if (*(filter+1) == '-' && *(filter+2) && (*(filter+2) != ']' || *(filter+3) == ']'))
+ {
+ if (casesensitive)
+ {
+ if (*filename >= *filter && *filename <= *(filter+2)) found = true;
+ } //end if
+ else
+ {
+ if (toupper(*filename) >= toupper(*filter) &&
+ toupper(*filename) <= toupper(*(filter+2))) found = true;
+ } //end else
+ filter += 3;
+ } //end if
+ else
+ {
+ if (casesensitive)
+ {
+ if (*filter == *filename) found = true;
+ } //end if
+ else
+ {
+ if (toupper(*filter) == toupper(*filename)) found = true;
+ } //end else
+ filter++;
+ } //end else
+ } //end while
+ if (!found) return false;
+ while(*filter)
+ {
+ if (*filter == ']' && *(filter+1) != ']') break;
+ filter++;
+ } //end while
+ filter++;
+ filename++;
+ } //end else if
+ else
+ {
+ if (casesensitive)
+ {
+ if (*filter != *filename) return false;
+ } //end if
+ else
+ {
+ if (toupper(*filter) != toupper(*filename)) return false;
+ } //end else
+ filter++;
+ filename++;
+ } //end else
+ } //end while
+ return true;
+} //end of the function FileFilter
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+quakefile_t *FindQuakeFilesInZip(char *zipfile, char *filter)
+{
+ unzFile uf;
+ int err;
+ unz_global_info gi;
+ char filename_inzip[MAX_PATH];
+ unz_file_info file_info;
+ int i;
+ quakefile_t *qfiles, *lastqf, *qf;
+
+ uf = unzOpen(zipfile);
+ err = unzGetGlobalInfo(uf, &gi);
+
+ if (err != UNZ_OK) return NULL;
+
+ unzGoToFirstFile(uf);
+
+ qfiles = NULL;
+ lastqf = NULL;
+ for (i = 0; i < gi.number_entry; i++)
+ {
+ err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL,0,NULL,0);
+ if (err != UNZ_OK) break;
+
+ ConvertPath(filename_inzip);
+ if (FileFilter(filter, filename_inzip, false))
+ {
+ qf = malloc(sizeof(quakefile_t));
+ if (!qf) Error("out of memory");
+ memset(qf, 0, sizeof(quakefile_t));
+ strcpy(qf->pakfile, zipfile);
+ strcpy(qf->filename, zipfile);
+ strcpy(qf->origname, filename_inzip);
+ qf->zipfile = true;
+ //memcpy( &buildBuffer[i].zipfileinfo, (unz_s*)uf, sizeof(unz_s));
+ memcpy(&qf->zipinfo, (unz_s*)uf, sizeof(unz_s));
+ qf->offset = 0;
+ qf->length = file_info.uncompressed_size;
+ qf->type = QuakeFileType(filename_inzip);
+ //add the file ot the list
+ qf->next = NULL;
+ if (lastqf) lastqf->next = qf;
+ else qfiles = qf;
+ lastqf = qf;
+ } //end if
+ unzGoToNextFile(uf);
+ } //end for
+
+ unzClose(uf);
+
+ return qfiles;
+} //end of the function FindQuakeFilesInZip
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+quakefile_t *FindQuakeFilesInPak(char *pakfile, char *filter)
+{
+ FILE *fp;
+ dpackheader_t packheader;
+ dsinpackfile_t *packfiles;
+ dpackfile_t *idpackfiles;
+ quakefile_t *qfiles, *lastqf, *qf;
+ int numpackdirs, i;
+
+ qfiles = NULL;
+ lastqf = NULL;
+ //open the pak file
+ fp = fopen(pakfile, "rb");
+ if (!fp)
+ {
+ Warning("can't open pak file %s", pakfile);
+ return NULL;
+ } //end if
+ //read pak header, check for valid pak id and seek to the dir entries
+ if ((fread(&packheader, 1, sizeof(dpackheader_t), fp) != sizeof(dpackheader_t))
+ || (packheader.ident != IDPAKHEADER && packheader.ident != SINPAKHEADER)
+ || (fseek(fp, LittleLong(packheader.dirofs), SEEK_SET))
+ )
+ {
+ fclose(fp);
+ Warning("invalid pak file %s", pakfile);
+ return NULL;
+ } //end if
+ //if it is a pak file from id software
+ if (packheader.ident == IDPAKHEADER)
+ {
+ //number of dir entries in the pak file
+ numpackdirs = LittleLong(packheader.dirlen) / sizeof(dpackfile_t);
+ idpackfiles = (dpackfile_t *) malloc(numpackdirs * sizeof(dpackfile_t));
+ if (!idpackfiles) Error("out of memory");
+ //read the dir entry
+ if (fread(idpackfiles, sizeof(dpackfile_t), numpackdirs, fp) != numpackdirs)
+ {
+ fclose(fp);
+ free(idpackfiles);
+ Warning("can't read the Quake pak file dir entries from %s", pakfile);
+ return NULL;
+ } //end if
+ fclose(fp);
+ //convert to sin pack files
+ packfiles = (dsinpackfile_t *) malloc(numpackdirs * sizeof(dsinpackfile_t));
+ if (!packfiles) Error("out of memory");
+ for (i = 0; i < numpackdirs; i++)
+ {
+ strcpy(packfiles[i].name, idpackfiles[i].name);
+ packfiles[i].filepos = LittleLong(idpackfiles[i].filepos);
+ packfiles[i].filelen = LittleLong(idpackfiles[i].filelen);
+ } //end for
+ free(idpackfiles);
+ } //end if
+ else //its a Sin pack file
+ {
+ //number of dir entries in the pak file
+ numpackdirs = LittleLong(packheader.dirlen) / sizeof(dsinpackfile_t);
+ packfiles = (dsinpackfile_t *) malloc(numpackdirs * sizeof(dsinpackfile_t));
+ if (!packfiles) Error("out of memory");
+ //read the dir entry
+ if (fread(packfiles, sizeof(dsinpackfile_t), numpackdirs, fp) != numpackdirs)
+ {
+ fclose(fp);
+ free(packfiles);
+ Warning("can't read the Sin pak file dir entries from %s", pakfile);
+ return NULL;
+ } //end if
+ fclose(fp);
+ for (i = 0; i < numpackdirs; i++)
+ {
+ packfiles[i].filepos = LittleLong(packfiles[i].filepos);
+ packfiles[i].filelen = LittleLong(packfiles[i].filelen);
+ } //end for
+ } //end else
+ //
+ for (i = 0; i < numpackdirs; i++)
+ {
+ ConvertPath(packfiles[i].name);
+ if (FileFilter(filter, packfiles[i].name, false))
+ {
+ qf = malloc(sizeof(quakefile_t));
+ if (!qf) Error("out of memory");
+ memset(qf, 0, sizeof(quakefile_t));
+ strcpy(qf->pakfile, pakfile);
+ strcpy(qf->filename, pakfile);
+ strcpy(qf->origname, packfiles[i].name);
+ qf->zipfile = false;
+ qf->offset = packfiles[i].filepos;
+ qf->length = packfiles[i].filelen;
+ qf->type = QuakeFileType(packfiles[i].name);
+ //add the file ot the list
+ qf->next = NULL;
+ if (lastqf) lastqf->next = qf;
+ else qfiles = qf;
+ lastqf = qf;
+ } //end if
+ } //end for
+ free(packfiles);
+ return qfiles;
+} //end of the function FindQuakeFilesInPak
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+quakefile_t *FindQuakeFilesWithPakFilter(char *pakfilter, char *filter)
+{
+#if defined(WIN32)|defined(_WIN32)
+ WIN32_FIND_DATA filedata;
+ HWND handle;
+ struct _stat statbuf;
+#else
+ glob_t globbuf;
+ struct stat statbuf;
+ int j;
+#endif
+ quakefile_t *qfiles, *lastqf, *qf;
+ char pakfile[_MAX_PATH], filename[_MAX_PATH], *str;
+ int done;
+
+ qfiles = NULL;
+ lastqf = NULL;
+ if (pakfilter && strlen(pakfilter))
+ {
+#if defined(WIN32)|defined(_WIN32)
+ handle = FindFirstFile(pakfilter, &filedata);
+ done = (handle == INVALID_HANDLE_VALUE);
+ while(!done)
+ {
+ _splitpath(pakfilter, pakfile, NULL, NULL, NULL);
+ _splitpath(pakfilter, NULL, &pakfile[strlen(pakfile)], NULL, NULL);
+ AppendPathSeperator(pakfile, _MAX_PATH);
+ strcat(pakfile, filedata.cFileName);
+ _stat(pakfile, &statbuf);
+#else
+ glob(pakfilter, 0, NULL, &globbuf);
+ for (j = 0; j < globbuf.gl_pathc; j++)
+ {
+ strcpy(pakfile, globbuf.gl_pathv[j]);
+ stat(pakfile, &statbuf);
+#endif
+ //if the file with .pak or .pk3 is a folder
+ if (statbuf.st_mode & S_IFDIR)
+ {
+ strcpy(filename, pakfilter);
+ AppendPathSeperator(filename, _MAX_PATH);
+ strcat(filename, filter);
+ qf = FindQuakeFilesWithPakFilter(NULL, filename);
+ if (lastqf) lastqf->next = qf;
+ else qfiles = qf;
+ lastqf = qf;
+ while(lastqf->next) lastqf = lastqf->next;
+ } //end if
+ else
+ {
+#if defined(WIN32)|defined(_WIN32)
+ str = StringContains(pakfile, ".pk3", false);
+#else
+ str = StringContains(pakfile, ".pk3", true);
+#endif
+ if (str && str == pakfile + strlen(pakfile) - strlen(".pk3"))
+ {
+ qf = FindQuakeFilesInZip(pakfile, filter);
+ } //end if
+ else
+ {
+ qf = FindQuakeFilesInPak(pakfile, filter);
+ } //end else
+ //
+ if (qf)
+ {
+ if (lastqf) lastqf->next = qf;
+ else qfiles = qf;
+ lastqf = qf;
+ while(lastqf->next) lastqf = lastqf->next;
+ } //end if
+ } //end else
+ //
+#if defined(WIN32)|defined(_WIN32)
+ //find the next file
+ done = !FindNextFile(handle, &filedata);
+ } //end while
+#else
+ } //end for
+ globfree(&globbuf);
+#endif
+ } //end if
+ else
+ {
+#if defined(WIN32)|defined(_WIN32)
+ handle = FindFirstFile(filter, &filedata);
+ done = (handle == INVALID_HANDLE_VALUE);
+ while(!done)
+ {
+ _splitpath(filter, filename, NULL, NULL, NULL);
+ _splitpath(filter, NULL, &filename[strlen(filename)], NULL, NULL);
+ AppendPathSeperator(filename, _MAX_PATH);
+ strcat(filename, filedata.cFileName);
+#else
+ glob(filter, 0, NULL, &globbuf);
+ for (j = 0; j < globbuf.gl_pathc; j++)
+ {
+ strcpy(filename, globbuf.gl_pathv[j]);
+#endif
+ //
+ qf = malloc(sizeof(quakefile_t));
+ if (!qf) Error("out of memory");
+ memset(qf, 0, sizeof(quakefile_t));
+ strcpy(qf->pakfile, "");
+ strcpy(qf->filename, filename);
+ strcpy(qf->origname, filename);
+ qf->offset = 0;
+ qf->length = 0;
+ qf->type = QuakeFileType(filename);
+ //add the file ot the list
+ qf->next = NULL;
+ if (lastqf) lastqf->next = qf;
+ else qfiles = qf;
+ lastqf = qf;
+#if defined(WIN32)|defined(_WIN32)
+ //find the next file
+ done = !FindNextFile(handle, &filedata);
+ } //end while
+#else
+ } //end for
+ globfree(&globbuf);
+#endif
+ } //end else
+ return qfiles;
+} //end of the function FindQuakeFilesWithPakFilter
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+quakefile_t *FindQuakeFiles(char *filter)
+{
+ char *str;
+ char newfilter[_MAX_PATH];
+ char pakfilter[_MAX_PATH];
+ char filefilter[_MAX_PATH];
+
+ strcpy(newfilter, filter);
+ ConvertPath(newfilter);
+ strcpy(pakfilter, newfilter);
+
+ str = StringContains(pakfilter, ".pak", false);
+ if (!str) str = StringContains(pakfilter, ".pk3", false);
+
+ if (str)
+ {
+ str += strlen(".pak");
+ if (*str)
+ {
+ *str++ = '\0';
+ while(*str == '\\' || *str == '/') str++;
+ strcpy(filefilter, str);
+ return FindQuakeFilesWithPakFilter(pakfilter, filefilter);
+ } //end if
+ } //end else
+ return FindQuakeFilesWithPakFilter(NULL, newfilter);
+} //end of the function FindQuakeFiles
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int LoadQuakeFile(quakefile_t *qf, void **bufferptr)
+{
+ FILE *fp;
+ void *buffer;
+ int length;
+ unzFile zf;
+
+ if (qf->zipfile)
+ {
+ //open the zip file
+ zf = unzOpen(qf->pakfile);
+ //set the file pointer
+ qf->zipinfo.file = ((unz_s *) zf)->file;
+ //open the Quake file in the zip file
+ unzOpenCurrentFile(&qf->zipinfo);
+ //allocate memory for the buffer
+ length = qf->length;
+ buffer = GetMemory(length+1);
+ //read the Quake file from the zip file
+ length = unzReadCurrentFile(&qf->zipinfo, buffer, length);
+ //close the Quake file in the zip file
+ unzCloseCurrentFile(&qf->zipinfo);
+ //close the zip file
+ unzClose(zf);
+
+ *bufferptr = buffer;
+ return length;
+ } //end if
+ else
+ {
+ fp = SafeOpenRead(qf->filename);
+ if (qf->offset) fseek(fp, qf->offset, SEEK_SET);
+ length = qf->length;
+ if (!length) length = Q_filelength(fp);
+ buffer = GetMemory(length+1);
+ ((char *)buffer)[length] = 0;
+ SafeRead(fp, buffer, length);
+ fclose(fp);
+
+ *bufferptr = buffer;
+ return length;
+ } //end else
+} //end of the function LoadQuakeFile
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int ReadQuakeFile(quakefile_t *qf, void *buffer, int offset, int length)
+{
+ FILE *fp;
+ int read;
+ unzFile zf;
+ char tmpbuf[1024];
+
+ if (qf->zipfile)
+ {
+ //open the zip file
+ zf = unzOpen(qf->pakfile);
+ //set the file pointer
+ qf->zipinfo.file = ((unz_s *) zf)->file;
+ //open the Quake file in the zip file
+ unzOpenCurrentFile(&qf->zipinfo);
+ //
+ while(offset > 0)
+ {
+ read = offset;
+ if (read > sizeof(tmpbuf)) read = sizeof(tmpbuf);
+ unzReadCurrentFile(&qf->zipinfo, tmpbuf, read);
+ offset -= read;
+ } //end while
+ //read the Quake file from the zip file
+ length = unzReadCurrentFile(&qf->zipinfo, buffer, length);
+ //close the Quake file in the zip file
+ unzCloseCurrentFile(&qf->zipinfo);
+ //close the zip file
+ unzClose(zf);
+
+ return length;
+ } //end if
+ else
+ {
+ fp = SafeOpenRead(qf->filename);
+ if (qf->offset) fseek(fp, qf->offset, SEEK_SET);
+ if (offset) fseek(fp, offset, SEEK_CUR);
+ SafeRead(fp, buffer, length);
+ fclose(fp);
+
+ return length;
+ } //end else
+} //end of the function ReadQuakeFile
diff --git a/code/bspc/l_qfiles.h b/code/bspc/l_qfiles.h
index 308c608..0f79e7f 100755
--- a/code/bspc/l_qfiles.h
+++ b/code/bspc/l_qfiles.h
@@ -1,91 +1,91 @@
-/*
-===========================================================================
-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 "../qcommon/unzip.h"
-
-#define QFILETYPE_UNKNOWN 0x8000
-#define QFILETYPE_PAK 0x0001
-#define QFILETYPE_PK3 0x0002
-#define QFILETYPE_BSP 0x0004
-#define QFILETYPE_MAP 0x0008
-#define QFILETYPE_MDL 0x0010
-#define QFILETYPE_MD2 0x0020
-#define QFILETYPE_MD3 0x0040
-#define QFILETYPE_WAL 0x0080
-#define QFILETYPE_WAV 0x0100
-#define QFILETYPE_AAS 0x4000
-
-#define QFILEEXT_UNKNOWN ""
-#define QFILEEXT_PAK ".PAK"
-#define QFILEEXT_PK3 ".PK3"
-#define QFILEEXT_SIN ".SIN"
-#define QFILEEXT_BSP ".BSP"
-#define QFILEEXT_MAP ".MAP"
-#define QFILEEXT_MDL ".MDL"
-#define QFILEEXT_MD2 ".MD2"
-#define QFILEEXT_MD3 ".MD3"
-#define QFILEEXT_WAL ".WAL"
-#define QFILEEXT_WAV ".WAV"
-#define QFILEEXT_AAS ".AAS"
-
-//maximum path length
-#ifndef _MAX_PATH
- #define _MAX_PATH 1024
-#endif
-
-//for Sin packs
-#define MAX_PAK_FILENAME_LENGTH 120
-#define SINPAKHEADER (('K'<<24)+('A'<<16)+('P'<<8)+'S')
-
-typedef struct
-{
- char name[MAX_PAK_FILENAME_LENGTH];
- int filepos, filelen;
-} dsinpackfile_t;
-
-typedef struct quakefile_s
-{
- char pakfile[_MAX_PATH];
- char filename[_MAX_PATH];
- char origname[_MAX_PATH];
- int zipfile;
- int type;
- int offset;
- int length;
- unz_s zipinfo;
- struct quakefile_s *next;
-} quakefile_t;
-
-//returns the file extension for the given type
-char *QuakeFileTypeExtension(int type);
-//returns the file type for the given extension
-int QuakeFileExtensionType(char *extension);
-//return the Quake file type for the given file
-int QuakeFileType(char *filename);
-//returns true if the filename complies to the filter
-int FileFilter(char *filter, char *filename, int casesensitive);
-//find Quake files using the given filter
-quakefile_t *FindQuakeFiles(char *filter);
-//load the given Quake file, returns the length of the file
-int LoadQuakeFile(quakefile_t *qf, void **bufferptr);
-//read part of a Quake file into the buffer
-int ReadQuakeFile(quakefile_t *qf, void *buffer, int offset, int length);
+/*
+===========================================================================
+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 "../qcommon/unzip.h"
+
+#define QFILETYPE_UNKNOWN 0x8000
+#define QFILETYPE_PAK 0x0001
+#define QFILETYPE_PK3 0x0002
+#define QFILETYPE_BSP 0x0004
+#define QFILETYPE_MAP 0x0008
+#define QFILETYPE_MDL 0x0010
+#define QFILETYPE_MD2 0x0020
+#define QFILETYPE_MD3 0x0040
+#define QFILETYPE_WAL 0x0080
+#define QFILETYPE_WAV 0x0100
+#define QFILETYPE_AAS 0x4000
+
+#define QFILEEXT_UNKNOWN ""
+#define QFILEEXT_PAK ".PAK"
+#define QFILEEXT_PK3 ".PK3"
+#define QFILEEXT_SIN ".SIN"
+#define QFILEEXT_BSP ".BSP"
+#define QFILEEXT_MAP ".MAP"
+#define QFILEEXT_MDL ".MDL"
+#define QFILEEXT_MD2 ".MD2"
+#define QFILEEXT_MD3 ".MD3"
+#define QFILEEXT_WAL ".WAL"
+#define QFILEEXT_WAV ".WAV"
+#define QFILEEXT_AAS ".AAS"
+
+//maximum path length
+#ifndef _MAX_PATH
+ #define _MAX_PATH 1024
+#endif
+
+//for Sin packs
+#define MAX_PAK_FILENAME_LENGTH 120
+#define SINPAKHEADER (('K'<<24)+('A'<<16)+('P'<<8)+'S')
+
+typedef struct
+{
+ char name[MAX_PAK_FILENAME_LENGTH];
+ int filepos, filelen;
+} dsinpackfile_t;
+
+typedef struct quakefile_s
+{
+ char pakfile[_MAX_PATH];
+ char filename[_MAX_PATH];
+ char origname[_MAX_PATH];
+ int zipfile;
+ int type;
+ int offset;
+ int length;
+ unz_s zipinfo;
+ struct quakefile_s *next;
+} quakefile_t;
+
+//returns the file extension for the given type
+char *QuakeFileTypeExtension(int type);
+//returns the file type for the given extension
+int QuakeFileExtensionType(char *extension);
+//return the Quake file type for the given file
+int QuakeFileType(char *filename);
+//returns true if the filename complies to the filter
+int FileFilter(char *filter, char *filename, int casesensitive);
+//find Quake files using the given filter
+quakefile_t *FindQuakeFiles(char *filter);
+//load the given Quake file, returns the length of the file
+int LoadQuakeFile(quakefile_t *qf, void **bufferptr);
+//read part of a Quake file into the buffer
+int ReadQuakeFile(quakefile_t *qf, void *buffer, int offset, int length);
diff --git a/code/bspc/l_threads.c b/code/bspc/l_threads.c
index bc4b998..94e641a 100755
--- a/code/bspc/l_threads.c
+++ b/code/bspc/l_threads.c
@@ -1,1510 +1,1510 @@
-/*
-===========================================================================
-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 "l_cmd.h"
-#include "l_threads.h"
-#include "l_log.h"
-#include "l_mem.h"
-
-#define MAX_THREADS 64
-
-//#define THREAD_DEBUG
-
-int dispatch;
-int workcount;
-int oldf;
-qboolean pacifier;
-qboolean threaded;
-void (*workfunction) (int);
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int GetThreadWork(void)
-{
- int r;
- int f;
-
- ThreadLock();
-
- if (dispatch == workcount)
- {
- ThreadUnlock ();
- return -1;
- }
-
- f = 10*dispatch / workcount;
- if (f != oldf)
- {
- oldf = f;
- if (pacifier)
- printf ("%i...", f);
- } //end if
-
- r = dispatch;
- dispatch++;
- ThreadUnlock ();
-
- return r;
-} //end of the function GetThreadWork
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadWorkerFunction(int threadnum)
-{
- int work;
-
- while(1)
- {
- work = GetThreadWork ();
- if (work == -1)
- break;
-//printf ("thread %i, work %i\n", threadnum, work);
- workfunction(work);
- } //end while
-} //end of the function ThreadWorkerFunction
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, void(*func)(int))
-{
- if (numthreads == -1)
- ThreadSetDefault ();
- workfunction = func;
- RunThreadsOn (workcnt, showpacifier, ThreadWorkerFunction);
-} //end of the function RunThreadsOnIndividual
-
-
-//===================================================================
-//
-// WIN32
-//
-//===================================================================
-
-#if defined(WIN32) || defined(_WIN32)
-
-#define USED
-
-#include <windows.h>
-
-typedef struct thread_s
-{
- HANDLE handle;
- int threadid;
- int id;
- struct thread_s *next;
-} thread_t;
-
-thread_t *firstthread;
-thread_t *lastthread;
-int currentnumthreads;
-int currentthreadid;
-
-int numthreads = 1;
-CRITICAL_SECTION crit;
-HANDLE semaphore;
-static int enter;
-static int numwaitingthreads = 0;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadSetDefault(void)
-{
- SYSTEM_INFO info;
-
- if (numthreads == -1) // not set manually
- {
- GetSystemInfo (&info);
- numthreads = info.dwNumberOfProcessors;
- if (numthreads < 1 || numthreads > 32)
- numthreads = 1;
- } //end if
- qprintf ("%i threads\n", numthreads);
-} //end of the function ThreadSetDefault
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadLock(void)
-{
- if (!threaded)
- {
- Error("ThreadLock: !threaded");
- return;
- } //end if
- EnterCriticalSection(&crit);
- if (enter)
- Error("Recursive ThreadLock\n");
- enter = 1;
-} //end of the function ThreadLock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadUnlock (void)
-{
- if (!threaded)
- {
- Error("ThreadUnlock: !threaded");
- return;
- } //end if
- if (!enter)
- Error("ThreadUnlock without lock\n");
- enter = 0;
- LeaveCriticalSection(&crit);
-} //end of the function ThreadUnlock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadSetupLock(void)
-{
- Log_Print("Win32 multi-threading\n");
- InitializeCriticalSection(&crit);
- threaded = true; //Stupid me... forgot this!!!
- currentnumthreads = 0;
- currentthreadid = 0;
-} //end of the function ThreadInitLock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadShutdownLock(void)
-{
- DeleteCriticalSection(&crit);
- threaded = false; //Stupid me... forgot this!!!
-} //end of the function ThreadShutdownLock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadSetupSemaphore(void)
-{
- semaphore = CreateSemaphore(NULL, 0, 99999999, "bspc");
-} //end of the function ThreadSetupSemaphore
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadShutdownSemaphore(void)
-{
-} //end of the function ThreadShutdownSemaphore
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadSemaphoreWait(void)
-{
- WaitForSingleObject(semaphore, INFINITE);
-} //end of the function ThreadSemaphoreWait
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadSemaphoreIncrease(int count)
-{
- ReleaseSemaphore(semaphore, count, NULL);
-} //end of the function ThreadSemaphoreIncrease
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void RunThreadsOn(int workcnt, qboolean showpacifier, void(*func)(int))
-{
- int threadid[MAX_THREADS];
- HANDLE threadhandle[MAX_THREADS];
- int i;
- int start, end;
-
- Log_Print("Win32 multi-threading\n");
- start = I_FloatTime ();
- dispatch = 0;
- workcount = workcnt;
- oldf = -1;
- pacifier = showpacifier;
- threaded = true;
-
- if (numthreads == -1)
- ThreadSetDefault ();
-
- if (numthreads < 1 || numthreads > MAX_THREADS) numthreads = 1;
- //
- // run threads in parallel
- //
- InitializeCriticalSection (&crit);
-
- numwaitingthreads = 0;
-
- if (numthreads == 1)
- { // use same thread
- func (0);
- } //end if
- else
- {
-// printf("starting %d threads\n", numthreads);
- for (i = 0; i < numthreads; i++)
- {
- threadhandle[i] = CreateThread(
- NULL, // LPSECURITY_ATTRIBUTES lpsa,
- 0, // DWORD cbStack,
- (LPTHREAD_START_ROUTINE)func, // LPTHREAD_START_ROUTINE lpStartAddr,
- (LPVOID)i, // LPVOID lpvThreadParm,
- 0, // DWORD fdwCreate,
- &threadid[i]);
-// printf("started thread %d\n", i);
- } //end for
-
- for (i = 0; i < numthreads; i++)
- WaitForSingleObject (threadhandle[i], INFINITE);
- } //end else
- DeleteCriticalSection (&crit);
-
- threaded = false;
- end = I_FloatTime ();
- if (pacifier) printf (" (%i)\n", end-start);
-} //end of the function RunThreadsOn
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AddThread(void (*func)(int))
-{
- thread_t *thread;
-
- if (numthreads == 1)
- {
- if (currentnumthreads >= numthreads) return;
- currentnumthreads++;
- func(-1);
- currentnumthreads--;
- } //end if
- else
- {
- ThreadLock();
- if (currentnumthreads >= numthreads)
- {
- ThreadUnlock();
- return;
- } //end if
- //allocate new thread
- thread = GetMemory(sizeof(thread_t));
- if (!thread) Error("can't allocate memory for thread\n");
-
- //
- thread->threadid = currentthreadid;
- thread->handle = CreateThread(
- NULL, // LPSECURITY_ATTRIBUTES lpsa,
- 0, // DWORD cbStack,
- (LPTHREAD_START_ROUTINE)func, // LPTHREAD_START_ROUTINE lpStartAddr,
- (LPVOID) thread->threadid, // LPVOID lpvThreadParm,
- 0, // DWORD fdwCreate,
- &thread->id);
-
- //add the thread to the end of the list
- thread->next = NULL;
- if (lastthread) lastthread->next = thread;
- else firstthread = thread;
- lastthread = thread;
- //
-#ifdef THREAD_DEBUG
- qprintf("added thread with id %d\n", thread->threadid);
-#endif //THREAD_DEBUG
- //
- currentnumthreads++;
- currentthreadid++;
- //
- ThreadUnlock();
- } //end else
-} //end of the function AddThread
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void RemoveThread(int threadid)
-{
- thread_t *thread, *last;
-
- //if a single thread
- if (threadid == -1) return;
- //
- ThreadLock();
- last = NULL;
- for (thread = firstthread; thread; thread = thread->next)
- {
- if (thread->threadid == threadid)
- {
- if (last) last->next = thread->next;
- else firstthread = thread->next;
- if (!thread->next) lastthread = last;
- //
- FreeMemory(thread);
- currentnumthreads--;
-#ifdef THREAD_DEBUG
- qprintf("removed thread with id %d\n", threadid);
-#endif //THREAD_DEBUG
- break;
- } //end if
- last = thread;
- } //end if
- if (!thread) Error("couldn't find thread with id %d", threadid);
- ThreadUnlock();
-} //end of the function RemoveThread
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void WaitForAllThreadsFinished(void)
-{
- HANDLE handle;
-
- ThreadLock();
- while(firstthread)
- {
- handle = firstthread->handle;
- ThreadUnlock();
-
- WaitForSingleObject(handle, INFINITE);
-
- ThreadLock();
- } //end while
- ThreadUnlock();
-} //end of the function WaitForAllThreadsFinished
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int GetNumThreads(void)
-{
- return currentnumthreads;
-} //end of the function GetNumThreads
-
-#endif
-
-
-//===================================================================
-//
-// OSF1
-//
-//===================================================================
-
-#if defined(__osf__)
-
-#define USED
-
-#include <pthread.h>
-
-typedef struct thread_s
-{
- pthread_t thread;
- int threadid;
- int id;
- struct thread_s *next;
-} thread_t;
-
-thread_t *firstthread;
-thread_t *lastthread;
-int currentnumthreads;
-int currentthreadid;
-
-int numthreads = 1;
-pthread_mutex_t my_mutex;
-pthread_attr_t attrib;
-static int enter;
-static int numwaitingthreads = 0;
-
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadSetDefault(void)
-{
- if (numthreads == -1) // not set manually
- {
- numthreads = 1;
- } //end if
- qprintf("%i threads\n", numthreads);
-} //end of the function ThreadSetDefault
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadLock(void)
-{
- if (!threaded)
- {
- Error("ThreadLock: !threaded");
- return;
- } //end if
- if (my_mutex)
- {
- pthread_mutex_lock(my_mutex);
- } //end if
- if (enter)
- Error("Recursive ThreadLock\n");
- enter = 1;
-} //end of the function ThreadLock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadUnlock(void)
-{
- if (!threaded)
- {
- Error("ThreadUnlock: !threaded");
- return;
- } //end if
- if (!enter)
- Error("ThreadUnlock without lock\n");
- enter = 0;
- if (my_mutex)
- {
- pthread_mutex_unlock(my_mutex);
- } //end if
-} //end of the function ThreadUnlock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadSetupLock(void)
-{
- pthread_mutexattr_t mattrib;
-
- Log_Print("pthread multi-threading\n");
-
- if (!my_mutex)
- {
- my_mutex = GetMemory(sizeof(*my_mutex));
- if (pthread_mutexattr_create (&mattrib) == -1)
- Error ("pthread_mutex_attr_create failed");
- if (pthread_mutexattr_setkind_np (&mattrib, MUTEX_FAST_NP) == -1)
- Error ("pthread_mutexattr_setkind_np failed");
- if (pthread_mutex_init (my_mutex, mattrib) == -1)
- Error ("pthread_mutex_init failed");
- }
-
- if (pthread_attr_create (&attrib) == -1)
- Error ("pthread_attr_create failed");
- if (pthread_attr_setstacksize (&attrib, 0x100000) == -1)
- Error ("pthread_attr_setstacksize failed");
-
- threaded = true;
- currentnumthreads = 0;
- currentthreadid = 0;
-} //end of the function ThreadInitLock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadShutdownLock(void)
-{
- threaded = false;
-} //end of the function ThreadShutdownLock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void RunThreadsOn(int workcnt, qboolean showpacifier, void(*func)(int))
-{
- int i;
- pthread_t work_threads[MAX_THREADS];
- pthread_addr_t status;
- pthread_attr_t attrib;
- pthread_mutexattr_t mattrib;
- int start, end;
-
- Log_Print("pthread multi-threading\n");
-
- start = I_FloatTime ();
- dispatch = 0;
- workcount = workcnt;
- oldf = -1;
- pacifier = showpacifier;
- threaded = true;
-
- if (numthreads < 1 || numthreads > MAX_THREADS) numthreads = 1;
-
- if (pacifier)
- setbuf (stdout, NULL);
-
- if (!my_mutex)
- {
- my_mutex = GetMemory(sizeof(*my_mutex));
- if (pthread_mutexattr_create (&mattrib) == -1)
- Error ("pthread_mutex_attr_create failed");
- if (pthread_mutexattr_setkind_np (&mattrib, MUTEX_FAST_NP) == -1)
- Error ("pthread_mutexattr_setkind_np failed");
- if (pthread_mutex_init (my_mutex, mattrib) == -1)
- Error ("pthread_mutex_init failed");
- }
-
- if (pthread_attr_create (&attrib) == -1)
- Error ("pthread_attr_create failed");
- if (pthread_attr_setstacksize (&attrib, 0x100000) == -1)
- Error ("pthread_attr_setstacksize failed");
-
- for (i=0 ; i<numthreads ; i++)
- {
- if (pthread_create(&work_threads[i], attrib
- , (pthread_startroutine_t)func, (pthread_addr_t)i) == -1)
- Error ("pthread_create failed");
- }
-
- for (i=0 ; i<numthreads ; i++)
- {
- if (pthread_join (work_threads[i], &status) == -1)
- Error ("pthread_join failed");
- }
-
- threaded = false;
-
- end = I_FloatTime ();
- if (pacifier)
- printf (" (%i)\n", end-start);
-} //end of the function RunThreadsOn
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AddThread(void (*func)(int))
-{
- thread_t *thread;
-
- if (numthreads == 1)
- {
- if (currentnumthreads >= numthreads) return;
- currentnumthreads++;
- func(-1);
- currentnumthreads--;
- } //end if
- else
- {
- ThreadLock();
- if (currentnumthreads >= numthreads)
- {
- ThreadUnlock();
- return;
- } //end if
- //allocate new thread
- thread = GetMemory(sizeof(thread_t));
- if (!thread) Error("can't allocate memory for thread\n");
- //
- thread->threadid = currentthreadid;
-
- if (pthread_create(&thread->thread, attrib, (pthread_startroutine_t)func, (pthread_addr_t)thread->threadid) == -1)
- Error ("pthread_create failed");
-
- //add the thread to the end of the list
- thread->next = NULL;
- if (lastthread) lastthread->next = thread;
- else firstthread = thread;
- lastthread = thread;
- //
-#ifdef THREAD_DEBUG
- qprintf("added thread with id %d\n", thread->threadid);
-#endif //THREAD_DEBUG
- //
- currentnumthreads++;
- currentthreadid++;
- //
- ThreadUnlock();
- } //end else
-} //end of the function AddThread
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void RemoveThread(int threadid)
-{
- thread_t *thread, *last;
-
- //if a single thread
- if (threadid == -1) return;
- //
- ThreadLock();
- last = NULL;
- for (thread = firstthread; thread; thread = thread->next)
- {
- if (thread->threadid == threadid)
- {
- if (last) last->next = thread->next;
- else firstthread = thread->next;
- if (!thread->next) lastthread = last;
- //
- FreeMemory(thread);
- currentnumthreads--;
-#ifdef THREAD_DEBUG
- qprintf("removed thread with id %d\n", threadid);
-#endif //THREAD_DEBUG
- break;
- } //end if
- last = thread;
- } //end if
- if (!thread) Error("couldn't find thread with id %d", threadid);
- ThreadUnlock();
-} //end of the function RemoveThread
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void WaitForAllThreadsFinished(void)
-{
- pthread_t *thread;
- pthread_addr_t status;
-
- ThreadLock();
- while(firstthread)
- {
- thread = &firstthread->thread;
- ThreadUnlock();
-
- if (pthread_join(*thread, &status) == -1)
- Error("pthread_join failed");
-
- ThreadLock();
- } //end while
- ThreadUnlock();
-} //end of the function WaitForAllThreadsFinished
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int GetNumThreads(void)
-{
- return currentnumthreads;
-} //end of the function GetNumThreads
-
-#endif
-
-//===================================================================
-//
-// LINUX
-//
-//===================================================================
-
-#if defined(LINUX)
-
-#define USED
-
-#include <pthread.h>
-#include <semaphore.h>
-
-typedef struct thread_s
-{
- pthread_t thread;
- int threadid;
- int id;
- struct thread_s *next;
-} thread_t;
-
-thread_t *firstthread;
-thread_t *lastthread;
-int currentnumthreads;
-int currentthreadid;
-
-int numthreads = 1;
-pthread_mutex_t my_mutex = PTHREAD_MUTEX_INITIALIZER;
-pthread_attr_t attrib;
-sem_t semaphore;
-static int enter;
-static int numwaitingthreads = 0;
-
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadSetDefault(void)
-{
- if (numthreads == -1) // not set manually
- {
- numthreads = 1;
- } //end if
- qprintf("%i threads\n", numthreads);
-} //end of the function ThreadSetDefault
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadLock(void)
-{
- if (!threaded)
- {
- Error("ThreadLock: !threaded");
- return;
- } //end if
- pthread_mutex_lock(&my_mutex);
- if (enter)
- Error("Recursive ThreadLock\n");
- enter = 1;
-} //end of the function ThreadLock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadUnlock(void)
-{
- if (!threaded)
- {
- Error("ThreadUnlock: !threaded");
- return;
- } //end if
- if (!enter)
- Error("ThreadUnlock without lock\n");
- enter = 0;
- pthread_mutex_unlock(&my_mutex);
-} //end of the function ThreadUnlock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadSetupLock(void)
-{
- pthread_mutexattr_t mattrib;
-
- Log_Print("pthread multi-threading\n");
-
- threaded = true;
- currentnumthreads = 0;
- currentthreadid = 0;
-} //end of the function ThreadInitLock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadShutdownLock(void)
-{
- threaded = false;
-} //end of the function ThreadShutdownLock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadSetupSemaphore(void)
-{
- sem_init(&semaphore, 0, 0);
-} //end of the function ThreadSetupSemaphore
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadShutdownSemaphore(void)
-{
- sem_destroy(&semaphore);
-} //end of the function ThreadShutdownSemaphore
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadSemaphoreWait(void)
-{
- sem_wait(&semaphore);
-} //end of the function ThreadSemaphoreWait
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadSemaphoreIncrease(int count)
-{
- int i;
-
- for (i = 0; i < count; i++)
- {
- sem_post(&semaphore);
- } //end for
-} //end of the function ThreadSemaphoreIncrease
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void RunThreadsOn(int workcnt, qboolean showpacifier, void(*func)(int))
-{
- int i;
- pthread_t work_threads[MAX_THREADS];
- void *pthread_return;
- pthread_attr_t attrib;
- pthread_mutexattr_t mattrib;
- int start, end;
-
- Log_Print("pthread multi-threading\n");
-
- start = I_FloatTime ();
- dispatch = 0;
- workcount = workcnt;
- oldf = -1;
- pacifier = showpacifier;
- threaded = true;
-
- if (numthreads < 1 || numthreads > MAX_THREADS) numthreads = 1;
-
- if (pacifier)
- setbuf (stdout, NULL);
-
- for (i=0 ; i<numthreads ; i++)
- {
- if (pthread_create(&work_threads[i], NULL, (void *)func, (void *)i) == -1)
- Error ("pthread_create failed");
- }
-
- for (i=0 ; i<numthreads ; i++)
- {
- if (pthread_join(work_threads[i], &pthread_return) == -1)
- Error ("pthread_join failed");
- }
-
- threaded = false;
-
- end = I_FloatTime ();
- if (pacifier)
- printf (" (%i)\n", end-start);
-} //end of the function RunThreadsOn
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AddThread(void (*func)(int))
-{
- thread_t *thread;
-
- if (numthreads == 1)
- {
- if (currentnumthreads >= numthreads) return;
- currentnumthreads++;
- func(-1);
- currentnumthreads--;
- } //end if
- else
- {
- ThreadLock();
- if (currentnumthreads >= numthreads)
- {
- ThreadUnlock();
- return;
- } //end if
- //allocate new thread
- thread = GetMemory(sizeof(thread_t));
- if (!thread) Error("can't allocate memory for thread\n");
- //
- thread->threadid = currentthreadid;
-
- if (pthread_create(&thread->thread, NULL, (void *)func, (void *)thread->threadid) == -1)
- Error ("pthread_create failed");
-
- //add the thread to the end of the list
- thread->next = NULL;
- if (lastthread) lastthread->next = thread;
- else firstthread = thread;
- lastthread = thread;
- //
-#ifdef THREAD_DEBUG
- qprintf("added thread with id %d\n", thread->threadid);
-#endif //THREAD_DEBUG
- //
- currentnumthreads++;
- currentthreadid++;
- //
- ThreadUnlock();
- } //end else
-} //end of the function AddThread
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void RemoveThread(int threadid)
-{
- thread_t *thread, *last;
-
- //if a single thread
- if (threadid == -1) return;
- //
- ThreadLock();
- last = NULL;
- for (thread = firstthread; thread; thread = thread->next)
- {
- if (thread->threadid == threadid)
- {
- if (last) last->next = thread->next;
- else firstthread = thread->next;
- if (!thread->next) lastthread = last;
- //
- FreeMemory(thread);
- currentnumthreads--;
-#ifdef THREAD_DEBUG
- qprintf("removed thread with id %d\n", threadid);
-#endif //THREAD_DEBUG
- break;
- } //end if
- last = thread;
- } //end if
- if (!thread) Error("couldn't find thread with id %d", threadid);
- ThreadUnlock();
-} //end of the function RemoveThread
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void WaitForAllThreadsFinished(void)
-{
- pthread_t *thread;
- void *pthread_return;
-
- ThreadLock();
- while(firstthread)
- {
- thread = &firstthread->thread;
- ThreadUnlock();
-
- if (pthread_join(*thread, &pthread_return) == -1)
- Error("pthread_join failed");
-
- ThreadLock();
- } //end while
- ThreadUnlock();
-} //end of the function WaitForAllThreadsFinished
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int GetNumThreads(void)
-{
- return currentnumthreads;
-} //end of the function GetNumThreads
-
-#endif //LINUX
-
-
-//===================================================================
-//
-// IRIX
-//
-//===================================================================
-
-#ifdef _MIPS_ISA
-
-#define USED
-
-#include <task.h>
-#include <abi_mutex.h>
-#include <sys/types.h>
-#include <sys/prctl.h>
-
-typedef struct thread_s
-{
- int threadid;
- int id;
- struct thread_s *next;
-} thread_t;
-
-thread_t *firstthread;
-thread_t *lastthread;
-int currentnumthreads;
-int currentthreadid;
-
-int numthreads = 1;
-static int enter;
-static int numwaitingthreads = 0;
-
-abilock_t lck;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadSetDefault (void)
-{
- if (numthreads == -1)
- numthreads = prctl(PR_MAXPPROCS);
- printf ("%i threads\n", numthreads);
-//@@
- usconfig (CONF_INITUSERS, numthreads);
-} //end of the function ThreadSetDefault
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadLock (void)
-{
- spin_lock (&lck);
-} //end of the function ThreadLock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadUnlock (void)
-{
- release_lock(&lck);
-} //end of the function ThreadUnlock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadSetupLock(void)
-{
- init_lock (&lck);
-
- Log_Print("IRIX multi-threading\n");
-
- threaded = true;
- currentnumthreads = 0;
- currentthreadid = 0;
-} //end of the function ThreadInitLock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadShutdownLock(void)
-{
- threaded = false;
-} //end of the function ThreadShutdownLock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
-{
- int i;
- int pid[MAX_THREADS];
- int start, end;
-
- start = I_FloatTime ();
- dispatch = 0;
- workcount = workcnt;
- oldf = -1;
- pacifier = showpacifier;
- threaded = true;
-
- if (numthreads < 1 || numthreads > MAX_THREADS) numthreads = 1;
-
- if (pacifier)
- setbuf (stdout, NULL);
-
- init_lock (&lck);
-
- for (i=0 ; i<numthreads-1 ; i++)
- {
- pid[i] = sprocsp ( (void (*)(void *, size_t))func, PR_SALL, (void *)i
- , NULL, 0x100000);
-// pid[i] = sprocsp ( (void (*)(void *, size_t))func, PR_SALL, (void *)i
-// , NULL, 0x80000);
- if (pid[i] == -1)
- {
- perror ("sproc");
- Error ("sproc failed");
- }
- }
-
- func(i);
-
- for (i=0 ; i<numthreads-1 ; i++)
- wait (NULL);
-
- threaded = false;
-
- end = I_FloatTime ();
- if (pacifier)
- printf (" (%i)\n", end-start);
-} //end of the function RunThreadsOn
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AddThread(void (*func)(int))
-{
- thread_t *thread;
-
- if (numthreads == 1)
- {
- if (currentnumthreads >= numthreads) return;
- currentnumthreads++;
- func(-1);
- currentnumthreads--;
- } //end if
- else
- {
- ThreadLock();
- if (currentnumthreads >= numthreads)
- {
- ThreadUnlock();
- return;
- } //end if
- //allocate new thread
- thread = GetMemory(sizeof(thread_t));
- if (!thread) Error("can't allocate memory for thread\n");
- //
- thread->threadid = currentthreadid;
-
- thread->id = sprocsp ( (void (*)(void *, size_t))func, PR_SALL, (void *)thread->threadid, NULL, 0x100000);
- if (thread->id == -1)
- {
- perror ("sproc");
- Error ("sproc failed");
- }
-
- //add the thread to the end of the list
- thread->next = NULL;
- if (lastthread) lastthread->next = thread;
- else firstthread = thread;
- lastthread = thread;
- //
-#ifdef THREAD_DEBUG
- qprintf("added thread with id %d\n", thread->threadid);
-#endif //THREAD_DEBUG
- //
- currentnumthreads++;
- currentthreadid++;
- //
- ThreadUnlock();
- } //end else
-} //end of the function AddThread
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void RemoveThread(int threadid)
-{
- thread_t *thread, *last;
-
- //if a single thread
- if (threadid == -1) return;
- //
- ThreadLock();
- last = NULL;
- for (thread = firstthread; thread; thread = thread->next)
- {
- if (thread->threadid == threadid)
- {
- if (last) last->next = thread->next;
- else firstthread = thread->next;
- if (!thread->next) lastthread = last;
- //
- FreeMemory(thread);
- currentnumthreads--;
-#ifdef THREAD_DEBUG
- qprintf("removed thread with id %d\n", threadid);
-#endif //THREAD_DEBUG
- break;
- } //end if
- last = thread;
- } //end if
- if (!thread) Error("couldn't find thread with id %d", threadid);
- ThreadUnlock();
-} //end of the function RemoveThread
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void WaitForAllThreadsFinished(void)
-{
- ThreadLock();
- while(firstthread)
- {
- ThreadUnlock();
-
- //wait (NULL);
-
- ThreadLock();
- } //end while
- ThreadUnlock();
-} //end of the function WaitForAllThreadsFinished
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int GetNumThreads(void)
-{
- return currentnumthreads;
-} //end of the function GetNumThreads
-
-#endif //_MIPS_ISA
-
-
-//=======================================================================
-//
-// SINGLE THREAD
-//
-//=======================================================================
-
-#ifndef USED
-
-int numthreads = 1;
-int currentnumthreads = 0;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadSetDefault(void)
-{
- numthreads = 1;
-} //end of the function ThreadSetDefault
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadLock(void)
-{
-} //end of the function ThreadLock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadUnlock(void)
-{
-} //end of the function ThreadUnlock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadSetupLock(void)
-{
- Log_Print("no multi-threading\n");
-} //end of the function ThreadInitLock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadShutdownLock(void)
-{
-} //end of the function ThreadShutdownLock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadSetupSemaphore(void)
-{
-} //end of the function ThreadSetupSemaphore
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadShutdownSemaphore(void)
-{
-} //end of the function ThreadShutdownSemaphore
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadSemaphoreWait(void)
-{
-} //end of the function ThreadSemaphoreWait
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ThreadSemaphoreIncrease(int count)
-{
-} //end of the function ThreadSemaphoreIncrease
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void RunThreadsOn(int workcnt, qboolean showpacifier, void(*func)(int))
-{
- int start, end;
-
- Log_Print("no multi-threading\n");
- dispatch = 0;
- workcount = workcnt;
- oldf = -1;
- pacifier = showpacifier;
- start = I_FloatTime ();
-#ifdef NeXT
- if (pacifier)
- setbuf (stdout, NULL);
-#endif
- func(0);
-
- end = I_FloatTime ();
- if (pacifier)
- printf (" (%i)\n", end-start);
-} //end of the function RunThreadsOn
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AddThread(void (*func)(int))
-{
- if (currentnumthreads >= numthreads) return;
- currentnumthreads++;
- func(-1);
- currentnumthreads--;
-} //end of the function AddThread
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void RemoveThread(int threadid)
-{
-} //end of the function RemoveThread
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void WaitForAllThreadsFinished(void)
-{
-} //end of the function WaitForAllThreadsFinished
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int GetNumThreads(void)
-{
- return currentnumthreads;
-} //end of the function GetNumThreads
-
-#endif //USED
+/*
+===========================================================================
+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 "l_cmd.h"
+#include "l_threads.h"
+#include "l_log.h"
+#include "l_mem.h"
+
+#define MAX_THREADS 64
+
+//#define THREAD_DEBUG
+
+int dispatch;
+int workcount;
+int oldf;
+qboolean pacifier;
+qboolean threaded;
+void (*workfunction) (int);
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int GetThreadWork(void)
+{
+ int r;
+ int f;
+
+ ThreadLock();
+
+ if (dispatch == workcount)
+ {
+ ThreadUnlock ();
+ return -1;
+ }
+
+ f = 10*dispatch / workcount;
+ if (f != oldf)
+ {
+ oldf = f;
+ if (pacifier)
+ printf ("%i...", f);
+ } //end if
+
+ r = dispatch;
+ dispatch++;
+ ThreadUnlock ();
+
+ return r;
+} //end of the function GetThreadWork
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadWorkerFunction(int threadnum)
+{
+ int work;
+
+ while(1)
+ {
+ work = GetThreadWork ();
+ if (work == -1)
+ break;
+//printf ("thread %i, work %i\n", threadnum, work);
+ workfunction(work);
+ } //end while
+} //end of the function ThreadWorkerFunction
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, void(*func)(int))
+{
+ if (numthreads == -1)
+ ThreadSetDefault ();
+ workfunction = func;
+ RunThreadsOn (workcnt, showpacifier, ThreadWorkerFunction);
+} //end of the function RunThreadsOnIndividual
+
+
+//===================================================================
+//
+// WIN32
+//
+//===================================================================
+
+#if defined(WIN32) || defined(_WIN32)
+
+#define USED
+
+#include <windows.h>
+
+typedef struct thread_s
+{
+ HANDLE handle;
+ int threadid;
+ int id;
+ struct thread_s *next;
+} thread_t;
+
+thread_t *firstthread;
+thread_t *lastthread;
+int currentnumthreads;
+int currentthreadid;
+
+int numthreads = 1;
+CRITICAL_SECTION crit;
+HANDLE semaphore;
+static int enter;
+static int numwaitingthreads = 0;
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadSetDefault(void)
+{
+ SYSTEM_INFO info;
+
+ if (numthreads == -1) // not set manually
+ {
+ GetSystemInfo (&info);
+ numthreads = info.dwNumberOfProcessors;
+ if (numthreads < 1 || numthreads > 32)
+ numthreads = 1;
+ } //end if
+ qprintf ("%i threads\n", numthreads);
+} //end of the function ThreadSetDefault
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadLock(void)
+{
+ if (!threaded)
+ {
+ Error("ThreadLock: !threaded");
+ return;
+ } //end if
+ EnterCriticalSection(&crit);
+ if (enter)
+ Error("Recursive ThreadLock\n");
+ enter = 1;
+} //end of the function ThreadLock
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadUnlock (void)
+{
+ if (!threaded)
+ {
+ Error("ThreadUnlock: !threaded");
+ return;
+ } //end if
+ if (!enter)
+ Error("ThreadUnlock without lock\n");
+ enter = 0;
+ LeaveCriticalSection(&crit);
+} //end of the function ThreadUnlock
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadSetupLock(void)
+{
+ Log_Print("Win32 multi-threading\n");
+ InitializeCriticalSection(&crit);
+ threaded = true; //Stupid me... forgot this!!!
+ currentnumthreads = 0;
+ currentthreadid = 0;
+} //end of the function ThreadInitLock
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadShutdownLock(void)
+{
+ DeleteCriticalSection(&crit);
+ threaded = false; //Stupid me... forgot this!!!
+} //end of the function ThreadShutdownLock
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadSetupSemaphore(void)
+{
+ semaphore = CreateSemaphore(NULL, 0, 99999999, "bspc");
+} //end of the function ThreadSetupSemaphore
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadShutdownSemaphore(void)
+{
+} //end of the function ThreadShutdownSemaphore
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadSemaphoreWait(void)
+{
+ WaitForSingleObject(semaphore, INFINITE);
+} //end of the function ThreadSemaphoreWait
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadSemaphoreIncrease(int count)
+{
+ ReleaseSemaphore(semaphore, count, NULL);
+} //end of the function ThreadSemaphoreIncrease
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void RunThreadsOn(int workcnt, qboolean showpacifier, void(*func)(int))
+{
+ int threadid[MAX_THREADS];
+ HANDLE threadhandle[MAX_THREADS];
+ int i;
+ int start, end;
+
+ Log_Print("Win32 multi-threading\n");
+ start = I_FloatTime ();
+ dispatch = 0;
+ workcount = workcnt;
+ oldf = -1;
+ pacifier = showpacifier;
+ threaded = true;
+
+ if (numthreads == -1)
+ ThreadSetDefault ();
+
+ if (numthreads < 1 || numthreads > MAX_THREADS) numthreads = 1;
+ //
+ // run threads in parallel
+ //
+ InitializeCriticalSection (&crit);
+
+ numwaitingthreads = 0;
+
+ if (numthreads == 1)
+ { // use same thread
+ func (0);
+ } //end if
+ else
+ {
+// printf("starting %d threads\n", numthreads);
+ for (i = 0; i < numthreads; i++)
+ {
+ threadhandle[i] = CreateThread(
+ NULL, // LPSECURITY_ATTRIBUTES lpsa,
+ 0, // DWORD cbStack,
+ (LPTHREAD_START_ROUTINE)func, // LPTHREAD_START_ROUTINE lpStartAddr,
+ (LPVOID)i, // LPVOID lpvThreadParm,
+ 0, // DWORD fdwCreate,
+ &threadid[i]);
+// printf("started thread %d\n", i);
+ } //end for
+
+ for (i = 0; i < numthreads; i++)
+ WaitForSingleObject (threadhandle[i], INFINITE);
+ } //end else
+ DeleteCriticalSection (&crit);
+
+ threaded = false;
+ end = I_FloatTime ();
+ if (pacifier) printf (" (%i)\n", end-start);
+} //end of the function RunThreadsOn
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AddThread(void (*func)(int))
+{
+ thread_t *thread;
+
+ if (numthreads == 1)
+ {
+ if (currentnumthreads >= numthreads) return;
+ currentnumthreads++;
+ func(-1);
+ currentnumthreads--;
+ } //end if
+ else
+ {
+ ThreadLock();
+ if (currentnumthreads >= numthreads)
+ {
+ ThreadUnlock();
+ return;
+ } //end if
+ //allocate new thread
+ thread = GetMemory(sizeof(thread_t));
+ if (!thread) Error("can't allocate memory for thread\n");
+
+ //
+ thread->threadid = currentthreadid;
+ thread->handle = CreateThread(
+ NULL, // LPSECURITY_ATTRIBUTES lpsa,
+ 0, // DWORD cbStack,
+ (LPTHREAD_START_ROUTINE)func, // LPTHREAD_START_ROUTINE lpStartAddr,
+ (LPVOID) thread->threadid, // LPVOID lpvThreadParm,
+ 0, // DWORD fdwCreate,
+ &thread->id);
+
+ //add the thread to the end of the list
+ thread->next = NULL;
+ if (lastthread) lastthread->next = thread;
+ else firstthread = thread;
+ lastthread = thread;
+ //
+#ifdef THREAD_DEBUG
+ qprintf("added thread with id %d\n", thread->threadid);
+#endif //THREAD_DEBUG
+ //
+ currentnumthreads++;
+ currentthreadid++;
+ //
+ ThreadUnlock();
+ } //end else
+} //end of the function AddThread
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void RemoveThread(int threadid)
+{
+ thread_t *thread, *last;
+
+ //if a single thread
+ if (threadid == -1) return;
+ //
+ ThreadLock();
+ last = NULL;
+ for (thread = firstthread; thread; thread = thread->next)
+ {
+ if (thread->threadid == threadid)
+ {
+ if (last) last->next = thread->next;
+ else firstthread = thread->next;
+ if (!thread->next) lastthread = last;
+ //
+ FreeMemory(thread);
+ currentnumthreads--;
+#ifdef THREAD_DEBUG
+ qprintf("removed thread with id %d\n", threadid);
+#endif //THREAD_DEBUG
+ break;
+ } //end if
+ last = thread;
+ } //end if
+ if (!thread) Error("couldn't find thread with id %d", threadid);
+ ThreadUnlock();
+} //end of the function RemoveThread
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void WaitForAllThreadsFinished(void)
+{
+ HANDLE handle;
+
+ ThreadLock();
+ while(firstthread)
+ {
+ handle = firstthread->handle;
+ ThreadUnlock();
+
+ WaitForSingleObject(handle, INFINITE);
+
+ ThreadLock();
+ } //end while
+ ThreadUnlock();
+} //end of the function WaitForAllThreadsFinished
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int GetNumThreads(void)
+{
+ return currentnumthreads;
+} //end of the function GetNumThreads
+
+#endif
+
+
+//===================================================================
+//
+// OSF1
+//
+//===================================================================
+
+#if defined(__osf__)
+
+#define USED
+
+#include <pthread.h>
+
+typedef struct thread_s
+{
+ pthread_t thread;
+ int threadid;
+ int id;
+ struct thread_s *next;
+} thread_t;
+
+thread_t *firstthread;
+thread_t *lastthread;
+int currentnumthreads;
+int currentthreadid;
+
+int numthreads = 1;
+pthread_mutex_t my_mutex;
+pthread_attr_t attrib;
+static int enter;
+static int numwaitingthreads = 0;
+
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadSetDefault(void)
+{
+ if (numthreads == -1) // not set manually
+ {
+ numthreads = 1;
+ } //end if
+ qprintf("%i threads\n", numthreads);
+} //end of the function ThreadSetDefault
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadLock(void)
+{
+ if (!threaded)
+ {
+ Error("ThreadLock: !threaded");
+ return;
+ } //end if
+ if (my_mutex)
+ {
+ pthread_mutex_lock(my_mutex);
+ } //end if
+ if (enter)
+ Error("Recursive ThreadLock\n");
+ enter = 1;
+} //end of the function ThreadLock
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadUnlock(void)
+{
+ if (!threaded)
+ {
+ Error("ThreadUnlock: !threaded");
+ return;
+ } //end if
+ if (!enter)
+ Error("ThreadUnlock without lock\n");
+ enter = 0;
+ if (my_mutex)
+ {
+ pthread_mutex_unlock(my_mutex);
+ } //end if
+} //end of the function ThreadUnlock
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadSetupLock(void)
+{
+ pthread_mutexattr_t mattrib;
+
+ Log_Print("pthread multi-threading\n");
+
+ if (!my_mutex)
+ {
+ my_mutex = GetMemory(sizeof(*my_mutex));
+ if (pthread_mutexattr_create (&mattrib) == -1)
+ Error ("pthread_mutex_attr_create failed");
+ if (pthread_mutexattr_setkind_np (&mattrib, MUTEX_FAST_NP) == -1)
+ Error ("pthread_mutexattr_setkind_np failed");
+ if (pthread_mutex_init (my_mutex, mattrib) == -1)
+ Error ("pthread_mutex_init failed");
+ }
+
+ if (pthread_attr_create (&attrib) == -1)
+ Error ("pthread_attr_create failed");
+ if (pthread_attr_setstacksize (&attrib, 0x100000) == -1)
+ Error ("pthread_attr_setstacksize failed");
+
+ threaded = true;
+ currentnumthreads = 0;
+ currentthreadid = 0;
+} //end of the function ThreadInitLock
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadShutdownLock(void)
+{
+ threaded = false;
+} //end of the function ThreadShutdownLock
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void RunThreadsOn(int workcnt, qboolean showpacifier, void(*func)(int))
+{
+ int i;
+ pthread_t work_threads[MAX_THREADS];
+ pthread_addr_t status;
+ pthread_attr_t attrib;
+ pthread_mutexattr_t mattrib;
+ int start, end;
+
+ Log_Print("pthread multi-threading\n");
+
+ start = I_FloatTime ();
+ dispatch = 0;
+ workcount = workcnt;
+ oldf = -1;
+ pacifier = showpacifier;
+ threaded = true;
+
+ if (numthreads < 1 || numthreads > MAX_THREADS) numthreads = 1;
+
+ if (pacifier)
+ setbuf (stdout, NULL);
+
+ if (!my_mutex)
+ {
+ my_mutex = GetMemory(sizeof(*my_mutex));
+ if (pthread_mutexattr_create (&mattrib) == -1)
+ Error ("pthread_mutex_attr_create failed");
+ if (pthread_mutexattr_setkind_np (&mattrib, MUTEX_FAST_NP) == -1)
+ Error ("pthread_mutexattr_setkind_np failed");
+ if (pthread_mutex_init (my_mutex, mattrib) == -1)
+ Error ("pthread_mutex_init failed");
+ }
+
+ if (pthread_attr_create (&attrib) == -1)
+ Error ("pthread_attr_create failed");
+ if (pthread_attr_setstacksize (&attrib, 0x100000) == -1)
+ Error ("pthread_attr_setstacksize failed");
+
+ for (i=0 ; i<numthreads ; i++)
+ {
+ if (pthread_create(&work_threads[i], attrib
+ , (pthread_startroutine_t)func, (pthread_addr_t)i) == -1)
+ Error ("pthread_create failed");
+ }
+
+ for (i=0 ; i<numthreads ; i++)
+ {
+ if (pthread_join (work_threads[i], &status) == -1)
+ Error ("pthread_join failed");
+ }
+
+ threaded = false;
+
+ end = I_FloatTime ();
+ if (pacifier)
+ printf (" (%i)\n", end-start);
+} //end of the function RunThreadsOn
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AddThread(void (*func)(int))
+{
+ thread_t *thread;
+
+ if (numthreads == 1)
+ {
+ if (currentnumthreads >= numthreads) return;
+ currentnumthreads++;
+ func(-1);
+ currentnumthreads--;
+ } //end if
+ else
+ {
+ ThreadLock();
+ if (currentnumthreads >= numthreads)
+ {
+ ThreadUnlock();
+ return;
+ } //end if
+ //allocate new thread
+ thread = GetMemory(sizeof(thread_t));
+ if (!thread) Error("can't allocate memory for thread\n");
+ //
+ thread->threadid = currentthreadid;
+
+ if (pthread_create(&thread->thread, attrib, (pthread_startroutine_t)func, (pthread_addr_t)thread->threadid) == -1)
+ Error ("pthread_create failed");
+
+ //add the thread to the end of the list
+ thread->next = NULL;
+ if (lastthread) lastthread->next = thread;
+ else firstthread = thread;
+ lastthread = thread;
+ //
+#ifdef THREAD_DEBUG
+ qprintf("added thread with id %d\n", thread->threadid);
+#endif //THREAD_DEBUG
+ //
+ currentnumthreads++;
+ currentthreadid++;
+ //
+ ThreadUnlock();
+ } //end else
+} //end of the function AddThread
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void RemoveThread(int threadid)
+{
+ thread_t *thread, *last;
+
+ //if a single thread
+ if (threadid == -1) return;
+ //
+ ThreadLock();
+ last = NULL;
+ for (thread = firstthread; thread; thread = thread->next)
+ {
+ if (thread->threadid == threadid)
+ {
+ if (last) last->next = thread->next;
+ else firstthread = thread->next;
+ if (!thread->next) lastthread = last;
+ //
+ FreeMemory(thread);
+ currentnumthreads--;
+#ifdef THREAD_DEBUG
+ qprintf("removed thread with id %d\n", threadid);
+#endif //THREAD_DEBUG
+ break;
+ } //end if
+ last = thread;
+ } //end if
+ if (!thread) Error("couldn't find thread with id %d", threadid);
+ ThreadUnlock();
+} //end of the function RemoveThread
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void WaitForAllThreadsFinished(void)
+{
+ pthread_t *thread;
+ pthread_addr_t status;
+
+ ThreadLock();
+ while(firstthread)
+ {
+ thread = &firstthread->thread;
+ ThreadUnlock();
+
+ if (pthread_join(*thread, &status) == -1)
+ Error("pthread_join failed");
+
+ ThreadLock();
+ } //end while
+ ThreadUnlock();
+} //end of the function WaitForAllThreadsFinished
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int GetNumThreads(void)
+{
+ return currentnumthreads;
+} //end of the function GetNumThreads
+
+#endif
+
+//===================================================================
+//
+// LINUX
+//
+//===================================================================
+
+#if defined(LINUX)
+
+#define USED
+
+#include <pthread.h>
+#include <semaphore.h>
+
+typedef struct thread_s
+{
+ pthread_t thread;
+ int threadid;
+ int id;
+ struct thread_s *next;
+} thread_t;
+
+thread_t *firstthread;
+thread_t *lastthread;
+int currentnumthreads;
+int currentthreadid;
+
+int numthreads = 1;
+pthread_mutex_t my_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_attr_t attrib;
+sem_t semaphore;
+static int enter;
+static int numwaitingthreads = 0;
+
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadSetDefault(void)
+{
+ if (numthreads == -1) // not set manually
+ {
+ numthreads = 1;
+ } //end if
+ qprintf("%i threads\n", numthreads);
+} //end of the function ThreadSetDefault
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadLock(void)
+{
+ if (!threaded)
+ {
+ Error("ThreadLock: !threaded");
+ return;
+ } //end if
+ pthread_mutex_lock(&my_mutex);
+ if (enter)
+ Error("Recursive ThreadLock\n");
+ enter = 1;
+} //end of the function ThreadLock
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadUnlock(void)
+{
+ if (!threaded)
+ {
+ Error("ThreadUnlock: !threaded");
+ return;
+ } //end if
+ if (!enter)
+ Error("ThreadUnlock without lock\n");
+ enter = 0;
+ pthread_mutex_unlock(&my_mutex);
+} //end of the function ThreadUnlock
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadSetupLock(void)
+{
+ pthread_mutexattr_t mattrib;
+
+ Log_Print("pthread multi-threading\n");
+
+ threaded = true;
+ currentnumthreads = 0;
+ currentthreadid = 0;
+} //end of the function ThreadInitLock
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadShutdownLock(void)
+{
+ threaded = false;
+} //end of the function ThreadShutdownLock
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadSetupSemaphore(void)
+{
+ sem_init(&semaphore, 0, 0);
+} //end of the function ThreadSetupSemaphore
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadShutdownSemaphore(void)
+{
+ sem_destroy(&semaphore);
+} //end of the function ThreadShutdownSemaphore
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadSemaphoreWait(void)
+{
+ sem_wait(&semaphore);
+} //end of the function ThreadSemaphoreWait
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadSemaphoreIncrease(int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ {
+ sem_post(&semaphore);
+ } //end for
+} //end of the function ThreadSemaphoreIncrease
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void RunThreadsOn(int workcnt, qboolean showpacifier, void(*func)(int))
+{
+ int i;
+ pthread_t work_threads[MAX_THREADS];
+ void *pthread_return;
+ pthread_attr_t attrib;
+ pthread_mutexattr_t mattrib;
+ int start, end;
+
+ Log_Print("pthread multi-threading\n");
+
+ start = I_FloatTime ();
+ dispatch = 0;
+ workcount = workcnt;
+ oldf = -1;
+ pacifier = showpacifier;
+ threaded = true;
+
+ if (numthreads < 1 || numthreads > MAX_THREADS) numthreads = 1;
+
+ if (pacifier)
+ setbuf (stdout, NULL);
+
+ for (i=0 ; i<numthreads ; i++)
+ {
+ if (pthread_create(&work_threads[i], NULL, (void *)func, (void *)i) == -1)
+ Error ("pthread_create failed");
+ }
+
+ for (i=0 ; i<numthreads ; i++)
+ {
+ if (pthread_join(work_threads[i], &pthread_return) == -1)
+ Error ("pthread_join failed");
+ }
+
+ threaded = false;
+
+ end = I_FloatTime ();
+ if (pacifier)
+ printf (" (%i)\n", end-start);
+} //end of the function RunThreadsOn
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AddThread(void (*func)(int))
+{
+ thread_t *thread;
+
+ if (numthreads == 1)
+ {
+ if (currentnumthreads >= numthreads) return;
+ currentnumthreads++;
+ func(-1);
+ currentnumthreads--;
+ } //end if
+ else
+ {
+ ThreadLock();
+ if (currentnumthreads >= numthreads)
+ {
+ ThreadUnlock();
+ return;
+ } //end if
+ //allocate new thread
+ thread = GetMemory(sizeof(thread_t));
+ if (!thread) Error("can't allocate memory for thread\n");
+ //
+ thread->threadid = currentthreadid;
+
+ if (pthread_create(&thread->thread, NULL, (void *)func, (void *)thread->threadid) == -1)
+ Error ("pthread_create failed");
+
+ //add the thread to the end of the list
+ thread->next = NULL;
+ if (lastthread) lastthread->next = thread;
+ else firstthread = thread;
+ lastthread = thread;
+ //
+#ifdef THREAD_DEBUG
+ qprintf("added thread with id %d\n", thread->threadid);
+#endif //THREAD_DEBUG
+ //
+ currentnumthreads++;
+ currentthreadid++;
+ //
+ ThreadUnlock();
+ } //end else
+} //end of the function AddThread
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void RemoveThread(int threadid)
+{
+ thread_t *thread, *last;
+
+ //if a single thread
+ if (threadid == -1) return;
+ //
+ ThreadLock();
+ last = NULL;
+ for (thread = firstthread; thread; thread = thread->next)
+ {
+ if (thread->threadid == threadid)
+ {
+ if (last) last->next = thread->next;
+ else firstthread = thread->next;
+ if (!thread->next) lastthread = last;
+ //
+ FreeMemory(thread);
+ currentnumthreads--;
+#ifdef THREAD_DEBUG
+ qprintf("removed thread with id %d\n", threadid);
+#endif //THREAD_DEBUG
+ break;
+ } //end if
+ last = thread;
+ } //end if
+ if (!thread) Error("couldn't find thread with id %d", threadid);
+ ThreadUnlock();
+} //end of the function RemoveThread
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void WaitForAllThreadsFinished(void)
+{
+ pthread_t *thread;
+ void *pthread_return;
+
+ ThreadLock();
+ while(firstthread)
+ {
+ thread = &firstthread->thread;
+ ThreadUnlock();
+
+ if (pthread_join(*thread, &pthread_return) == -1)
+ Error("pthread_join failed");
+
+ ThreadLock();
+ } //end while
+ ThreadUnlock();
+} //end of the function WaitForAllThreadsFinished
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int GetNumThreads(void)
+{
+ return currentnumthreads;
+} //end of the function GetNumThreads
+
+#endif //LINUX
+
+
+//===================================================================
+//
+// IRIX
+//
+//===================================================================
+
+#ifdef _MIPS_ISA
+
+#define USED
+
+#include <task.h>
+#include <abi_mutex.h>
+#include <sys/types.h>
+#include <sys/prctl.h>
+
+typedef struct thread_s
+{
+ int threadid;
+ int id;
+ struct thread_s *next;
+} thread_t;
+
+thread_t *firstthread;
+thread_t *lastthread;
+int currentnumthreads;
+int currentthreadid;
+
+int numthreads = 1;
+static int enter;
+static int numwaitingthreads = 0;
+
+abilock_t lck;
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadSetDefault (void)
+{
+ if (numthreads == -1)
+ numthreads = prctl(PR_MAXPPROCS);
+ printf ("%i threads\n", numthreads);
+//@@
+ usconfig (CONF_INITUSERS, numthreads);
+} //end of the function ThreadSetDefault
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadLock (void)
+{
+ spin_lock (&lck);
+} //end of the function ThreadLock
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadUnlock (void)
+{
+ release_lock(&lck);
+} //end of the function ThreadUnlock
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadSetupLock(void)
+{
+ init_lock (&lck);
+
+ Log_Print("IRIX multi-threading\n");
+
+ threaded = true;
+ currentnumthreads = 0;
+ currentthreadid = 0;
+} //end of the function ThreadInitLock
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadShutdownLock(void)
+{
+ threaded = false;
+} //end of the function ThreadShutdownLock
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
+{
+ int i;
+ int pid[MAX_THREADS];
+ int start, end;
+
+ start = I_FloatTime ();
+ dispatch = 0;
+ workcount = workcnt;
+ oldf = -1;
+ pacifier = showpacifier;
+ threaded = true;
+
+ if (numthreads < 1 || numthreads > MAX_THREADS) numthreads = 1;
+
+ if (pacifier)
+ setbuf (stdout, NULL);
+
+ init_lock (&lck);
+
+ for (i=0 ; i<numthreads-1 ; i++)
+ {
+ pid[i] = sprocsp ( (void (*)(void *, size_t))func, PR_SALL, (void *)i
+ , NULL, 0x100000);
+// pid[i] = sprocsp ( (void (*)(void *, size_t))func, PR_SALL, (void *)i
+// , NULL, 0x80000);
+ if (pid[i] == -1)
+ {
+ perror ("sproc");
+ Error ("sproc failed");
+ }
+ }
+
+ func(i);
+
+ for (i=0 ; i<numthreads-1 ; i++)
+ wait (NULL);
+
+ threaded = false;
+
+ end = I_FloatTime ();
+ if (pacifier)
+ printf (" (%i)\n", end-start);
+} //end of the function RunThreadsOn
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AddThread(void (*func)(int))
+{
+ thread_t *thread;
+
+ if (numthreads == 1)
+ {
+ if (currentnumthreads >= numthreads) return;
+ currentnumthreads++;
+ func(-1);
+ currentnumthreads--;
+ } //end if
+ else
+ {
+ ThreadLock();
+ if (currentnumthreads >= numthreads)
+ {
+ ThreadUnlock();
+ return;
+ } //end if
+ //allocate new thread
+ thread = GetMemory(sizeof(thread_t));
+ if (!thread) Error("can't allocate memory for thread\n");
+ //
+ thread->threadid = currentthreadid;
+
+ thread->id = sprocsp ( (void (*)(void *, size_t))func, PR_SALL, (void *)thread->threadid, NULL, 0x100000);
+ if (thread->id == -1)
+ {
+ perror ("sproc");
+ Error ("sproc failed");
+ }
+
+ //add the thread to the end of the list
+ thread->next = NULL;
+ if (lastthread) lastthread->next = thread;
+ else firstthread = thread;
+ lastthread = thread;
+ //
+#ifdef THREAD_DEBUG
+ qprintf("added thread with id %d\n", thread->threadid);
+#endif //THREAD_DEBUG
+ //
+ currentnumthreads++;
+ currentthreadid++;
+ //
+ ThreadUnlock();
+ } //end else
+} //end of the function AddThread
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void RemoveThread(int threadid)
+{
+ thread_t *thread, *last;
+
+ //if a single thread
+ if (threadid == -1) return;
+ //
+ ThreadLock();
+ last = NULL;
+ for (thread = firstthread; thread; thread = thread->next)
+ {
+ if (thread->threadid == threadid)
+ {
+ if (last) last->next = thread->next;
+ else firstthread = thread->next;
+ if (!thread->next) lastthread = last;
+ //
+ FreeMemory(thread);
+ currentnumthreads--;
+#ifdef THREAD_DEBUG
+ qprintf("removed thread with id %d\n", threadid);
+#endif //THREAD_DEBUG
+ break;
+ } //end if
+ last = thread;
+ } //end if
+ if (!thread) Error("couldn't find thread with id %d", threadid);
+ ThreadUnlock();
+} //end of the function RemoveThread
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void WaitForAllThreadsFinished(void)
+{
+ ThreadLock();
+ while(firstthread)
+ {
+ ThreadUnlock();
+
+ //wait (NULL);
+
+ ThreadLock();
+ } //end while
+ ThreadUnlock();
+} //end of the function WaitForAllThreadsFinished
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int GetNumThreads(void)
+{
+ return currentnumthreads;
+} //end of the function GetNumThreads
+
+#endif //_MIPS_ISA
+
+
+//=======================================================================
+//
+// SINGLE THREAD
+//
+//=======================================================================
+
+#ifndef USED
+
+int numthreads = 1;
+int currentnumthreads = 0;
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadSetDefault(void)
+{
+ numthreads = 1;
+} //end of the function ThreadSetDefault
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadLock(void)
+{
+} //end of the function ThreadLock
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadUnlock(void)
+{
+} //end of the function ThreadUnlock
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadSetupLock(void)
+{
+ Log_Print("no multi-threading\n");
+} //end of the function ThreadInitLock
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadShutdownLock(void)
+{
+} //end of the function ThreadShutdownLock
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadSetupSemaphore(void)
+{
+} //end of the function ThreadSetupSemaphore
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadShutdownSemaphore(void)
+{
+} //end of the function ThreadShutdownSemaphore
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadSemaphoreWait(void)
+{
+} //end of the function ThreadSemaphoreWait
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ThreadSemaphoreIncrease(int count)
+{
+} //end of the function ThreadSemaphoreIncrease
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void RunThreadsOn(int workcnt, qboolean showpacifier, void(*func)(int))
+{
+ int start, end;
+
+ Log_Print("no multi-threading\n");
+ dispatch = 0;
+ workcount = workcnt;
+ oldf = -1;
+ pacifier = showpacifier;
+ start = I_FloatTime ();
+#ifdef NeXT
+ if (pacifier)
+ setbuf (stdout, NULL);
+#endif
+ func(0);
+
+ end = I_FloatTime ();
+ if (pacifier)
+ printf (" (%i)\n", end-start);
+} //end of the function RunThreadsOn
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AddThread(void (*func)(int))
+{
+ if (currentnumthreads >= numthreads) return;
+ currentnumthreads++;
+ func(-1);
+ currentnumthreads--;
+} //end of the function AddThread
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void RemoveThread(int threadid)
+{
+} //end of the function RemoveThread
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void WaitForAllThreadsFinished(void)
+{
+} //end of the function WaitForAllThreadsFinished
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int GetNumThreads(void)
+{
+ return currentnumthreads;
+} //end of the function GetNumThreads
+
+#endif //USED
diff --git a/code/bspc/l_threads.h b/code/bspc/l_threads.h
index 2c6d8df..fe4df17 100755
--- a/code/bspc/l_threads.h
+++ b/code/bspc/l_threads.h
@@ -1,45 +1,45 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-
-extern int numthreads;
-
-void ThreadSetDefault (void);
-int GetThreadWork (void);
-void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, void(*func)(int));
-void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int));
-
-//mutex
-void ThreadSetupLock(void);
-void ThreadShutdownLock(void);
-void ThreadLock (void);
-void ThreadUnlock (void);
-//semaphore
-void ThreadSetupSemaphore(void);
-void ThreadShutdownSemaphore(void);
-void ThreadSemaphoreWait(void);
-void ThreadSemaphoreIncrease(int count);
-//add/remove threads
-void AddThread(void (*func)(int));
-void RemoveThread(int threadid);
-void WaitForAllThreadsFinished(void);
-int GetNumThreads(void);
-
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+extern int numthreads;
+
+void ThreadSetDefault (void);
+int GetThreadWork (void);
+void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, void(*func)(int));
+void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int));
+
+//mutex
+void ThreadSetupLock(void);
+void ThreadShutdownLock(void);
+void ThreadLock (void);
+void ThreadUnlock (void);
+//semaphore
+void ThreadSetupSemaphore(void);
+void ThreadShutdownSemaphore(void);
+void ThreadSemaphoreWait(void);
+void ThreadSemaphoreIncrease(int count);
+//add/remove threads
+void AddThread(void (*func)(int));
+void RemoveThread(int threadid);
+void WaitForAllThreadsFinished(void);
+int GetNumThreads(void);
+
diff --git a/code/bspc/l_utils.c b/code/bspc/l_utils.c
index f9d6d5f..8b229aa 100755
--- a/code/bspc/l_utils.c
+++ b/code/bspc/l_utils.c
@@ -1,259 +1,259 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-
-//#ifndef BOTLIB
-//#define BOTLIB
-//#endif //BOTLIB
-
-#ifdef BOTLIB
-#include "q_shared.h"
-#include "qfiles.h"
-#include "botlib.h"
-#include "l_log.h"
-#include "l_libvar.h"
-#include "l_memory.h"
-//#include "l_utils.h"
-#include "be_interface.h"
-#else //BOTLIB
-#include "qbsp.h"
-#include "l_mem.h"
-#endif //BOTLIB
-
-#ifdef BOTLIB
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-void Vector2Angles(vec3_t value1, vec3_t angles)
-{
- float forward;
- float yaw, pitch;
-
- if (value1[1] == 0 && value1[0] == 0)
- {
- yaw = 0;
- if (value1[2] > 0) pitch = 90;
- else pitch = 270;
- } //end if
- else
- {
- yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
- if (yaw < 0) yaw += 360;
-
- forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
- pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
- if (pitch < 0) pitch += 360;
- } //end else
-
- angles[PITCH] = -pitch;
- angles[YAW] = yaw;
- angles[ROLL] = 0;
-} //end of the function Vector2Angles
-#endif //BOTLIB
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ConvertPath(char *path)
-{
- while(*path)
- {
- if (*path == '/' || *path == '\\') *path = PATHSEPERATOR_CHAR;
- path++;
- } //end while
-} //end of the function ConvertPath
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AppendPathSeperator(char *path, int length)
-{
- int pathlen = strlen(path);
-
- if (strlen(path) && length-pathlen > 1 && path[pathlen-1] != '/' && path[pathlen-1] != '\\')
- {
- path[pathlen] = PATHSEPERATOR_CHAR;
- path[pathlen+1] = '\0';
- } //end if
-} //end of the function AppenPathSeperator
-
-#if 0
-//===========================================================================
-// returns pointer to file handle
-// sets offset to and length of 'filename' in the pak file
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean FindFileInPak(char *pakfile, char *filename, foundfile_t *file)
-{
- FILE *fp;
- dpackheader_t packheader;
- dpackfile_t *packfiles;
- int numdirs, i;
- char path[MAX_PATH];
-
- //open the pak file
- fp = fopen(pakfile, "rb");
- if (!fp)
- {
- return false;
- } //end if
- //read pak header, check for valid pak id and seek to the dir entries
- if ((fread(&packheader, 1, sizeof(dpackheader_t), fp) != sizeof(dpackheader_t))
- || (packheader.ident != IDPAKHEADER)
- || (fseek(fp, LittleLong(packheader.dirofs), SEEK_SET))
- )
- {
- fclose(fp);
- return false;
- } //end if
- //number of dir entries in the pak file
- numdirs = LittleLong(packheader.dirlen) / sizeof(dpackfile_t);
- packfiles = (dpackfile_t *) GetMemory(numdirs * sizeof(dpackfile_t));
- //read the dir entry
- if (fread(packfiles, sizeof(dpackfile_t), numdirs, fp) != numdirs)
- {
- fclose(fp);
- FreeMemory(packfiles);
- return false;
- } //end if
- fclose(fp);
- //
- strcpy(path, filename);
- ConvertPath(path);
- //find the dir entry in the pak file
- for (i = 0; i < numdirs; i++)
- {
- //convert the dir entry name
- ConvertPath(packfiles[i].name);
- //compare the dir entry name with the filename
- if (Q_strcasecmp(packfiles[i].name, path) == 0)
- {
- strcpy(file->filename, pakfile);
- file->offset = LittleLong(packfiles[i].filepos);
- file->length = LittleLong(packfiles[i].filelen);
- FreeMemory(packfiles);
- return true;
- } //end if
- } //end for
- FreeMemory(packfiles);
- return false;
-} //end of the function FindFileInPak
-//===========================================================================
-// find a Quake2 file
-// returns full path in 'filename'
-// sets offset and length of the file
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean FindQuakeFile2(char *basedir, char *gamedir, char *filename, foundfile_t *file)
-{
- int dir, i;
- //NOTE: 3 is necessary (LCC bug???)
- char gamedirs[3][MAX_PATH] = {"","",""};
- char filedir[MAX_PATH] = "";
-
- //
- if (gamedir) strncpy(gamedirs[0], gamedir, MAX_PATH);
- strncpy(gamedirs[1], "baseq2", MAX_PATH);
- //
- //find the file in the two game directories
- for (dir = 0; dir < 2; dir++)
- {
- //check if the file is in a directory
- filedir[0] = 0;
- if (basedir && strlen(basedir))
- {
- strncpy(filedir, basedir, MAX_PATH);
- AppendPathSeperator(filedir, MAX_PATH);
- } //end if
- if (strlen(gamedirs[dir]))
- {
- strncat(filedir, gamedirs[dir], MAX_PATH - strlen(filedir));
- AppendPathSeperator(filedir, MAX_PATH);
- } //end if
- strncat(filedir, filename, MAX_PATH - strlen(filedir));
- ConvertPath(filedir);
- Log_Write("accessing %s", filedir);
- if (!access(filedir, 0x04))
- {
- strcpy(file->filename, filedir);
- file->length = 0;
- file->offset = 0;
- return true;
- } //end if
- //check if the file is in a pak?.pak
- for (i = 0; i < 10; i++)
- {
- filedir[0] = 0;
- if (basedir && strlen(basedir))
- {
- strncpy(filedir, basedir, MAX_PATH);
- AppendPathSeperator(filedir, MAX_PATH);
- } //end if
- if (strlen(gamedirs[dir]))
- {
- strncat(filedir, gamedirs[dir], MAX_PATH - strlen(filedir));
- AppendPathSeperator(filedir, MAX_PATH);
- } //end if
- sprintf(&filedir[strlen(filedir)], "pak%d.pak\0", i);
- if (!access(filedir, 0x04))
- {
- Log_Write("searching %s in %s", filename, filedir);
- if (FindFileInPak(filedir, filename, file)) return true;
- } //end if
- } //end for
- } //end for
- file->offset = 0;
- file->length = 0;
- return false;
-} //end of the function FindQuakeFile2
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#ifdef BOTLIB
-qboolean FindQuakeFile(char *filename, foundfile_t *file)
-{
- return FindQuakeFile2(LibVarGetString("basedir"),
- LibVarGetString("gamedir"), filename, file);
-} //end of the function FindQuakeFile
-#else //BOTLIB
-qboolean FindQuakeFile(char *basedir, char *gamedir, char *filename, foundfile_t *file)
-{
- return FindQuakeFile2(basedir, gamedir, filename, file);
-} //end of the function FindQuakeFile
-#endif //BOTLIB
-
-#endif
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+//#ifndef BOTLIB
+//#define BOTLIB
+//#endif //BOTLIB
+
+#ifdef BOTLIB
+#include "q_shared.h"
+#include "qfiles.h"
+#include "botlib.h"
+#include "l_log.h"
+#include "l_libvar.h"
+#include "l_memory.h"
+//#include "l_utils.h"
+#include "be_interface.h"
+#else //BOTLIB
+#include "qbsp.h"
+#include "l_mem.h"
+#endif //BOTLIB
+
+#ifdef BOTLIB
+//========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//========================================================================
+void Vector2Angles(vec3_t value1, vec3_t angles)
+{
+ float forward;
+ float yaw, pitch;
+
+ if (value1[1] == 0 && value1[0] == 0)
+ {
+ yaw = 0;
+ if (value1[2] > 0) pitch = 90;
+ else pitch = 270;
+ } //end if
+ else
+ {
+ yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
+ if (yaw < 0) yaw += 360;
+
+ forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
+ pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
+ if (pitch < 0) pitch += 360;
+ } //end else
+
+ angles[PITCH] = -pitch;
+ angles[YAW] = yaw;
+ angles[ROLL] = 0;
+} //end of the function Vector2Angles
+#endif //BOTLIB
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ConvertPath(char *path)
+{
+ while(*path)
+ {
+ if (*path == '/' || *path == '\\') *path = PATHSEPERATOR_CHAR;
+ path++;
+ } //end while
+} //end of the function ConvertPath
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AppendPathSeperator(char *path, int length)
+{
+ int pathlen = strlen(path);
+
+ if (strlen(path) && length-pathlen > 1 && path[pathlen-1] != '/' && path[pathlen-1] != '\\')
+ {
+ path[pathlen] = PATHSEPERATOR_CHAR;
+ path[pathlen+1] = '\0';
+ } //end if
+} //end of the function AppenPathSeperator
+
+#if 0
+//===========================================================================
+// returns pointer to file handle
+// sets offset to and length of 'filename' in the pak file
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+qboolean FindFileInPak(char *pakfile, char *filename, foundfile_t *file)
+{
+ FILE *fp;
+ dpackheader_t packheader;
+ dpackfile_t *packfiles;
+ int numdirs, i;
+ char path[MAX_PATH];
+
+ //open the pak file
+ fp = fopen(pakfile, "rb");
+ if (!fp)
+ {
+ return false;
+ } //end if
+ //read pak header, check for valid pak id and seek to the dir entries
+ if ((fread(&packheader, 1, sizeof(dpackheader_t), fp) != sizeof(dpackheader_t))
+ || (packheader.ident != IDPAKHEADER)
+ || (fseek(fp, LittleLong(packheader.dirofs), SEEK_SET))
+ )
+ {
+ fclose(fp);
+ return false;
+ } //end if
+ //number of dir entries in the pak file
+ numdirs = LittleLong(packheader.dirlen) / sizeof(dpackfile_t);
+ packfiles = (dpackfile_t *) GetMemory(numdirs * sizeof(dpackfile_t));
+ //read the dir entry
+ if (fread(packfiles, sizeof(dpackfile_t), numdirs, fp) != numdirs)
+ {
+ fclose(fp);
+ FreeMemory(packfiles);
+ return false;
+ } //end if
+ fclose(fp);
+ //
+ strcpy(path, filename);
+ ConvertPath(path);
+ //find the dir entry in the pak file
+ for (i = 0; i < numdirs; i++)
+ {
+ //convert the dir entry name
+ ConvertPath(packfiles[i].name);
+ //compare the dir entry name with the filename
+ if (Q_strcasecmp(packfiles[i].name, path) == 0)
+ {
+ strcpy(file->filename, pakfile);
+ file->offset = LittleLong(packfiles[i].filepos);
+ file->length = LittleLong(packfiles[i].filelen);
+ FreeMemory(packfiles);
+ return true;
+ } //end if
+ } //end for
+ FreeMemory(packfiles);
+ return false;
+} //end of the function FindFileInPak
+//===========================================================================
+// find a Quake2 file
+// returns full path in 'filename'
+// sets offset and length of the file
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+qboolean FindQuakeFile2(char *basedir, char *gamedir, char *filename, foundfile_t *file)
+{
+ int dir, i;
+ //NOTE: 3 is necessary (LCC bug???)
+ char gamedirs[3][MAX_PATH] = {"","",""};
+ char filedir[MAX_PATH] = "";
+
+ //
+ if (gamedir) strncpy(gamedirs[0], gamedir, MAX_PATH);
+ strncpy(gamedirs[1], "baseq2", MAX_PATH);
+ //
+ //find the file in the two game directories
+ for (dir = 0; dir < 2; dir++)
+ {
+ //check if the file is in a directory
+ filedir[0] = 0;
+ if (basedir && strlen(basedir))
+ {
+ strncpy(filedir, basedir, MAX_PATH);
+ AppendPathSeperator(filedir, MAX_PATH);
+ } //end if
+ if (strlen(gamedirs[dir]))
+ {
+ strncat(filedir, gamedirs[dir], MAX_PATH - strlen(filedir));
+ AppendPathSeperator(filedir, MAX_PATH);
+ } //end if
+ strncat(filedir, filename, MAX_PATH - strlen(filedir));
+ ConvertPath(filedir);
+ Log_Write("accessing %s", filedir);
+ if (!access(filedir, 0x04))
+ {
+ strcpy(file->filename, filedir);
+ file->length = 0;
+ file->offset = 0;
+ return true;
+ } //end if
+ //check if the file is in a pak?.pak
+ for (i = 0; i < 10; i++)
+ {
+ filedir[0] = 0;
+ if (basedir && strlen(basedir))
+ {
+ strncpy(filedir, basedir, MAX_PATH);
+ AppendPathSeperator(filedir, MAX_PATH);
+ } //end if
+ if (strlen(gamedirs[dir]))
+ {
+ strncat(filedir, gamedirs[dir], MAX_PATH - strlen(filedir));
+ AppendPathSeperator(filedir, MAX_PATH);
+ } //end if
+ sprintf(&filedir[strlen(filedir)], "pak%d.pak\0", i);
+ if (!access(filedir, 0x04))
+ {
+ Log_Write("searching %s in %s", filename, filedir);
+ if (FindFileInPak(filedir, filename, file)) return true;
+ } //end if
+ } //end for
+ } //end for
+ file->offset = 0;
+ file->length = 0;
+ return false;
+} //end of the function FindQuakeFile2
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+#ifdef BOTLIB
+qboolean FindQuakeFile(char *filename, foundfile_t *file)
+{
+ return FindQuakeFile2(LibVarGetString("basedir"),
+ LibVarGetString("gamedir"), filename, file);
+} //end of the function FindQuakeFile
+#else //BOTLIB
+qboolean FindQuakeFile(char *basedir, char *gamedir, char *filename, foundfile_t *file)
+{
+ return FindQuakeFile2(basedir, gamedir, filename, file);
+} //end of the function FindQuakeFile
+#endif //BOTLIB
+
+#endif
diff --git a/code/bspc/l_utils.h b/code/bspc/l_utils.h
index 2ef9161..ebd8dbb 100755
--- a/code/bspc/l_utils.h
+++ b/code/bspc/l_utils.h
@@ -1,79 +1,79 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-
-#ifndef MAX_PATH
- #define MAX_PATH 64
-#endif
-
-#ifndef PATH_SEPERATORSTR
- #if defined(WIN32)|defined(_WIN32)|defined(__NT__)|defined(__WINDOWS__)|defined(__WINDOWS_386__)
- #define PATHSEPERATOR_STR "\\"
- #else
- #define PATHSEPERATOR_STR "/"
- #endif
-#endif
-#ifndef PATH_SEPERATORCHAR
- #if defined(WIN32)|defined(_WIN32)|defined(__NT__)|defined(__WINDOWS__)|defined(__WINDOWS_386__)
- #define PATHSEPERATOR_CHAR '\\'
- #else
- #define PATHSEPERATOR_CHAR '/'
- #endif
-#endif
-
-//random in the range [0, 1]
-#define random() ((rand () & 0x7fff) / ((float)0x7fff))
-//random in the range [-1, 1]
-#define crandom() (2.0 * (random() - 0.5))
-//min and max
-#define Maximum(x,y) (x > y ? x : y)
-#define Minimum(x,y) (x < y ? x : y)
-//absolute value
-#define FloatAbs(x) (*(float *) &((* (int *) &(x)) & 0x7FFFFFFF))
-#define IntAbs(x) (~(x))
-//coordinates
-#define _X 0
-#define _Y 1
-#define _Z 2
-
-typedef struct foundfile_s
-{
- int offset;
- int length;
- char filename[MAX_PATH]; //screw LCC, array must be at end of struct
-} foundfile_t;
-
-void Vector2Angles(vec3_t value1, vec3_t angles);
-//set the correct path seperators
-void ConvertPath(char *path);
-//append a path seperator to the given path not exceeding the length
-void AppendPathSeperator(char *path, int length);
-//find a file in a pak file
-qboolean FindFileInPak(char *pakfile, char *filename, foundfile_t *file);
-//find a quake file
-#ifdef BOTLIB
-qboolean FindQuakeFile(char *filename, foundfile_t *file);
-#else //BOTLIB
-qboolean FindQuakeFile(char *basedir, char *gamedir, char *filename, foundfile_t *file);
-#endif //BOTLIB
-
-
-
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+#ifndef MAX_PATH
+ #define MAX_PATH 64
+#endif
+
+#ifndef PATH_SEPERATORSTR
+ #if defined(WIN32)|defined(_WIN32)|defined(__NT__)|defined(__WINDOWS__)|defined(__WINDOWS_386__)
+ #define PATHSEPERATOR_STR "\\"
+ #else
+ #define PATHSEPERATOR_STR "/"
+ #endif
+#endif
+#ifndef PATH_SEPERATORCHAR
+ #if defined(WIN32)|defined(_WIN32)|defined(__NT__)|defined(__WINDOWS__)|defined(__WINDOWS_386__)
+ #define PATHSEPERATOR_CHAR '\\'
+ #else
+ #define PATHSEPERATOR_CHAR '/'
+ #endif
+#endif
+
+//random in the range [0, 1]
+#define random() ((rand () & 0x7fff) / ((float)0x7fff))
+//random in the range [-1, 1]
+#define crandom() (2.0 * (random() - 0.5))
+//min and max
+#define Maximum(x,y) (x > y ? x : y)
+#define Minimum(x,y) (x < y ? x : y)
+//absolute value
+#define FloatAbs(x) (*(float *) &((* (int *) &(x)) & 0x7FFFFFFF))
+#define IntAbs(x) (~(x))
+//coordinates
+#define _X 0
+#define _Y 1
+#define _Z 2
+
+typedef struct foundfile_s
+{
+ int offset;
+ int length;
+ char filename[MAX_PATH]; //screw LCC, array must be at end of struct
+} foundfile_t;
+
+void Vector2Angles(vec3_t value1, vec3_t angles);
+//set the correct path seperators
+void ConvertPath(char *path);
+//append a path seperator to the given path not exceeding the length
+void AppendPathSeperator(char *path, int length);
+//find a file in a pak file
+qboolean FindFileInPak(char *pakfile, char *filename, foundfile_t *file);
+//find a quake file
+#ifdef BOTLIB
+qboolean FindQuakeFile(char *filename, foundfile_t *file);
+#else //BOTLIB
+qboolean FindQuakeFile(char *basedir, char *gamedir, char *filename, foundfile_t *file);
+#endif //BOTLIB
+
+
+
diff --git a/code/bspc/lcc.mak b/code/bspc/lcc.mak
index d74adce..1b99864 100755
--- a/code/bspc/lcc.mak
+++ b/code/bspc/lcc.mak
@@ -1,61 +1,61 @@
-#
-# Makefile for the BSPC tool for the Gladiator Bot
-# Intended for LCC-Win32
-#
-
-CC=lcc
-CFLAGS=-DC_ONLY -o
-OBJS= _files.obj\
- aas_areamerging.obj\
- aas_cfg.obj\
- aas_create.obj\
- aas_edgemelting.obj\
- aas_facemerging.obj\
- aas_file.obj\
- aas_gsubdiv.obj\
- aas_map.obj\
- aas_prunenodes.obj\
- aas_store.obj\
- brushbsp.obj\
- bspc.obj\
- csg.obj\
- faces.obj\
- glfile.obj\
- l_bsp_hl.obj\
- l_bsp_q1.obj\
- l_bsp_q2.obj\
- l_bsp_sin.obj\
- l_cmd.obj\
- l_log.obj\
- l_math.obj\
- l_mem.obj\
- l_poly.obj\
- l_qfiles.obj\
- l_script.obj\
- l_threads.obj\
- l_utils.obj\
- leakfile.obj\
- map.obj\
- map_hl.obj\
- map_q1.obj\
- map_q2.obj\
- map_q2_new.obj\
- map_sin.obj\
- nodraw.obj\
- portals.obj\
- prtfile.obj\
- textures.obj\
- tree.obj\
- writebsp.obj
-
-all: bspc.exe
-
-bspc.exe: $(OBJS)
- lcclnk
-
-clean:
- del *.obj bspc.exe
-
-%.obj: %.c
- $(CC) $(CFLAGS) $<
-
+#
+# Makefile for the BSPC tool for the Gladiator Bot
+# Intended for LCC-Win32
+#
+
+CC=lcc
+CFLAGS=-DC_ONLY -o
+OBJS= _files.obj\
+ aas_areamerging.obj\
+ aas_cfg.obj\
+ aas_create.obj\
+ aas_edgemelting.obj\
+ aas_facemerging.obj\
+ aas_file.obj\
+ aas_gsubdiv.obj\
+ aas_map.obj\
+ aas_prunenodes.obj\
+ aas_store.obj\
+ brushbsp.obj\
+ bspc.obj\
+ csg.obj\
+ faces.obj\
+ glfile.obj\
+ l_bsp_hl.obj\
+ l_bsp_q1.obj\
+ l_bsp_q2.obj\
+ l_bsp_sin.obj\
+ l_cmd.obj\
+ l_log.obj\
+ l_math.obj\
+ l_mem.obj\
+ l_poly.obj\
+ l_qfiles.obj\
+ l_script.obj\
+ l_threads.obj\
+ l_utils.obj\
+ leakfile.obj\
+ map.obj\
+ map_hl.obj\
+ map_q1.obj\
+ map_q2.obj\
+ map_q2_new.obj\
+ map_sin.obj\
+ nodraw.obj\
+ portals.obj\
+ prtfile.obj\
+ textures.obj\
+ tree.obj\
+ writebsp.obj
+
+all: bspc.exe
+
+bspc.exe: $(OBJS)
+ lcclnk
+
+clean:
+ del *.obj bspc.exe
+
+%.obj: %.c
+ $(CC) $(CFLAGS) $<
+
diff --git a/code/bspc/leakfile.c b/code/bspc/leakfile.c
index 7118759..924b34d 100755
--- a/code/bspc/leakfile.c
+++ b/code/bspc/leakfile.c
@@ -1,101 +1,101 @@
-/*
-===========================================================================
-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"
-
-/*
-==============================================================================
-
-LEAF FILE GENERATION
-
-Save out name.line for qe3 to read
-==============================================================================
-*/
-
-
-/*
-=============
-LeakFile
-
-Finds the shortest possible chain of portals
-that leads from the outside leaf to a specifically
-occupied leaf
-=============
-*/
-void LeakFile (tree_t *tree)
-{
- vec3_t mid;
- FILE *linefile;
- char filename[1024];
- node_t *node;
- int count;
-
- if (!tree->outside_node.occupied)
- return;
-
- qprintf ("--- LeakFile ---\n");
-
- //
- // write the points to the file
- //
- sprintf (filename, "%s.lin", source);
- qprintf ("%s\n", filename);
- linefile = fopen (filename, "w");
- if (!linefile)
- Error ("Couldn't open %s\n", filename);
-
- count = 0;
- node = &tree->outside_node;
- while (node->occupied > 1)
- {
- int next;
- portal_t *p, *nextportal;
- node_t *nextnode;
- int s;
-
- // find the best portal exit
- next = node->occupied;
- for (p=node->portals ; p ; p = p->next[!s])
- {
- s = (p->nodes[0] == node);
- if (p->nodes[s]->occupied
- && p->nodes[s]->occupied < next)
- {
- nextportal = p;
- nextnode = p->nodes[s];
- next = nextnode->occupied;
- }
- }
- node = nextnode;
- WindingCenter (nextportal->winding, mid);
- fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
- count++;
- }
- // add the occupant center
- GetVectorForKey (node->occupant, "origin", mid);
-
- fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
- qprintf ("%5i point linefile\n", count+1);
-
- fclose (linefile);
-}
-
+/*
+===========================================================================
+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"
+
+/*
+==============================================================================
+
+LEAF FILE GENERATION
+
+Save out name.line for qe3 to read
+==============================================================================
+*/
+
+
+/*
+=============
+LeakFile
+
+Finds the shortest possible chain of portals
+that leads from the outside leaf to a specifically
+occupied leaf
+=============
+*/
+void LeakFile (tree_t *tree)
+{
+ vec3_t mid;
+ FILE *linefile;
+ char filename[1024];
+ node_t *node;
+ int count;
+
+ if (!tree->outside_node.occupied)
+ return;
+
+ qprintf ("--- LeakFile ---\n");
+
+ //
+ // write the points to the file
+ //
+ sprintf (filename, "%s.lin", source);
+ qprintf ("%s\n", filename);
+ linefile = fopen (filename, "w");
+ if (!linefile)
+ Error ("Couldn't open %s\n", filename);
+
+ count = 0;
+ node = &tree->outside_node;
+ while (node->occupied > 1)
+ {
+ int next;
+ portal_t *p, *nextportal;
+ node_t *nextnode;
+ int s;
+
+ // find the best portal exit
+ next = node->occupied;
+ for (p=node->portals ; p ; p = p->next[!s])
+ {
+ s = (p->nodes[0] == node);
+ if (p->nodes[s]->occupied
+ && p->nodes[s]->occupied < next)
+ {
+ nextportal = p;
+ nextnode = p->nodes[s];
+ next = nextnode->occupied;
+ }
+ }
+ node = nextnode;
+ WindingCenter (nextportal->winding, mid);
+ fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
+ count++;
+ }
+ // add the occupant center
+ GetVectorForKey (node->occupant, "origin", mid);
+
+ fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
+ qprintf ("%5i point linefile\n", count+1);
+
+ fclose (linefile);
+}
+
diff --git a/code/bspc/linux-i386.mak b/code/bspc/linux-i386.mak
index 00a261d..dd9566d 100755
--- a/code/bspc/linux-i386.mak
+++ b/code/bspc/linux-i386.mak
@@ -1,109 +1,109 @@
-#
-# Makefile for the BSPC tool for the Gladiator Bot
-# Intended for gcc/Linux
-#
-
-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\
- tetrahedron.o\
- textures.o\
- tree.o\
- ../qcommon/unzip.o
-
-bspc$(ARCH) : $(GAME_OBJS)
- $(CC) $(CFLAGS) -o $@ $(GAME_OBJS) $(LDFLAGS)
-
-
-#############################################################################
-# MISC
-#############################################################################
-
-clean:
- -rm -f $(GAME_OBJS)
-
-depend:
- gcc -MM $(GAME_OBJS:.o=.c)
-
-
-install:
- cp bspci386 ..
-
-#
-# From "make depend"
-#
-
+#
+# Makefile for the BSPC tool for the Gladiator Bot
+# Intended for gcc/Linux
+#
+
+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\
+ tetrahedron.o\
+ textures.o\
+ tree.o\
+ ../qcommon/unzip.o
+
+bspc$(ARCH) : $(GAME_OBJS)
+ $(CC) $(CFLAGS) -o $@ $(GAME_OBJS) $(LDFLAGS)
+
+
+#############################################################################
+# MISC
+#############################################################################
+
+clean:
+ -rm -f $(GAME_OBJS)
+
+depend:
+ gcc -MM $(GAME_OBJS:.o=.c)
+
+
+install:
+ cp bspci386 ..
+
+#
+# From "make depend"
+#
+
diff --git a/code/bspc/map.c b/code/bspc/map.c
index 613c234..e156d3a 100755
--- a/code/bspc/map.c
+++ b/code/bspc/map.c
@@ -1,1267 +1,1267 @@
-/*
-===========================================================================
-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 "l_bsp_hl.h"
-#include "l_bsp_q1.h"
-#include "l_bsp_q2.h"
-#include "l_bsp_q3.h"
-#include "l_bsp_sin.h"
-#include "l_mem.h"
-#include "../botlib/aasfile.h" //aas_bbox_t
-#include "aas_store.h" //AAS_MAX_BBOXES
-#include "aas_cfg.h"
-
-#define Sign(x) (x < 0 ? 1 : 0)
-
-int nummapbrushes;
-mapbrush_t mapbrushes[MAX_MAPFILE_BRUSHES];
-
-int nummapbrushsides;
-side_t brushsides[MAX_MAPFILE_BRUSHSIDES];
-brush_texture_t side_brushtextures[MAX_MAPFILE_BRUSHSIDES];
-
-int nummapplanes;
-plane_t mapplanes[MAX_MAPFILE_PLANES];
-int mapplaneusers[MAX_MAPFILE_PLANES];
-
-#define PLANE_HASHES 1024
-plane_t *planehash[PLANE_HASHES];
-vec3_t map_mins, map_maxs;
-
-#ifdef SIN
-textureref_t side_newrefs[MAX_MAPFILE_BRUSHSIDES];
-#endif
-
-map_texinfo_t map_texinfo[MAX_MAPFILE_TEXINFO];
-int map_numtexinfo;
-int loadedmaptype; //loaded map type
-
-// undefine to make plane finding use linear sort
-#define USE_HASHING
-
-int c_boxbevels;
-int c_edgebevels;
-int c_areaportals;
-int c_clipbrushes;
-int c_squattbrushes;
-int c_writtenbrushes;
-
-/*
-=============================================================================
-
-PLANE FINDING
-
-=============================================================================
-*/
-
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int PlaneSignBits(vec3_t normal)
-{
- int i, signbits;
-
- signbits = 0;
- for (i = 2; i >= 0; i--)
- {
- signbits = (signbits << 1) + Sign(normal[i]);
- } //end for
- return signbits;
-} //end of the function PlaneSignBits
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int PlaneTypeForNormal(vec3_t normal)
-{
- vec_t ax, ay, az;
-
-// NOTE: should these have an epsilon around 1.0?
- if (normal[0] == 1.0 || normal[0] == -1.0)
- return PLANE_X;
- if (normal[1] == 1.0 || normal[1] == -1.0)
- return PLANE_Y;
- if (normal[2] == 1.0 || normal[2] == -1.0)
- 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 PlaneTypeForNormal
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-//ME NOTE: changed from 0.00001
-#define NORMAL_EPSILON 0.0001
-//ME NOTE: changed from 0.01
-#define DIST_EPSILON 0.02
-qboolean PlaneEqual(plane_t *p, vec3_t normal, vec_t dist)
-{
-#if 1
- if (
- fabs(p->normal[0] - normal[0]) < NORMAL_EPSILON
- && fabs(p->normal[1] - normal[1]) < NORMAL_EPSILON
- && fabs(p->normal[2] - normal[2]) < NORMAL_EPSILON
- && fabs(p->dist - dist) < DIST_EPSILON )
- return true;
-#else
- if (p->normal[0] == normal[0]
- && p->normal[1] == normal[1]
- && p->normal[2] == normal[2]
- && p->dist == dist)
- return true;
-#endif
- return false;
-} //end of the function PlaneEqual
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AddPlaneToHash(plane_t *p)
-{
- int hash;
-
- hash = (int)fabs(p->dist) / 8;
- hash &= (PLANE_HASHES-1);
-
- p->hash_chain = planehash[hash];
- planehash[hash] = p;
-} //end of the function AddPlaneToHash
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int CreateNewFloatPlane (vec3_t normal, vec_t dist)
-{
- plane_t *p, temp;
-
- if (VectorLength(normal) < 0.5)
- Error ("FloatPlane: bad normal");
- // create a new plane
- if (nummapplanes+2 > MAX_MAPFILE_PLANES)
- Error ("MAX_MAPFILE_PLANES");
-
- p = &mapplanes[nummapplanes];
- VectorCopy (normal, p->normal);
- p->dist = dist;
- p->type = (p+1)->type = PlaneTypeForNormal (p->normal);
- p->signbits = PlaneSignBits(p->normal);
-
- VectorSubtract (vec3_origin, normal, (p+1)->normal);
- (p+1)->dist = -dist;
- (p+1)->signbits = PlaneSignBits((p+1)->normal);
-
- nummapplanes += 2;
-
- // allways put axial planes facing positive first
- if (p->type < 3)
- {
- if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0)
- {
- // flip order
- temp = *p;
- *p = *(p+1);
- *(p+1) = temp;
-
- AddPlaneToHash (p);
- AddPlaneToHash (p+1);
- return nummapplanes - 1;
- }
- }
-
- AddPlaneToHash (p);
- AddPlaneToHash (p+1);
- return nummapplanes - 2;
-} //end of the function CreateNewFloatPlane
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void SnapVector(vec3_t normal)
-{
- int i;
-
- for (i=0 ; i<3 ; i++)
- {
- if ( fabs(normal[i] - 1) < NORMAL_EPSILON )
- {
- VectorClear (normal);
- normal[i] = 1;
- break;
- }
- if ( fabs(normal[i] - -1) < NORMAL_EPSILON )
- {
- VectorClear (normal);
- normal[i] = -1;
- break;
- }
- }
-} //end of the function SnapVector
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void SnapPlane(vec3_t normal, vec_t *dist)
-{
- SnapVector(normal);
-
- if (fabs(*dist-Q_rint(*dist)) < DIST_EPSILON)
- *dist = Q_rint(*dist);
-} //end of the function SnapPlane
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#ifndef USE_HASHING
-int FindFloatPlane(vec3_t normal, vec_t dist)
-{
- int i;
- plane_t *p;
-
- SnapPlane(normal, &dist);
- for (i = 0, p = mapplanes; i < nummapplanes; i++, p++)
- {
- if (PlaneEqual (p, normal, dist))
- {
- mapplaneusers[i]++;
- return i;
- } //end if
- } //end for
- i = CreateNewFloatPlane (normal, dist);
- mapplaneusers[i]++;
- return i;
-} //end of the function FindFloatPlane
-#else
-int FindFloatPlane (vec3_t normal, vec_t dist)
-{
- int i;
- plane_t *p;
- int hash, h;
-
- SnapPlane (normal, &dist);
- hash = (int)fabs(dist) / 8;
- hash &= (PLANE_HASHES-1);
-
- // search the border bins as well
- for (i = -1; i <= 1; i++)
- {
- h = (hash+i)&(PLANE_HASHES-1);
- for (p = planehash[h]; p; p = p->hash_chain)
- {
- if (PlaneEqual(p, normal, dist))
- {
- mapplaneusers[p-mapplanes]++;
- return p - mapplanes;
- } //end if
- } //end for
- } //end for
- i = CreateNewFloatPlane (normal, dist);
- mapplaneusers[i]++;
- return i;
-} //end of the function FindFloatPlane
-#endif
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int PlaneFromPoints (int *p0, int *p1, int *p2)
-{
- vec3_t t1, t2, normal;
- vec_t dist;
-
- VectorSubtract (p0, p1, t1);
- VectorSubtract (p2, p1, t2);
- CrossProduct (t1, t2, normal);
- VectorNormalize (normal);
-
- dist = DotProduct (p0, normal);
-
- return FindFloatPlane (normal, dist);
-} //end of the function PlaneFromPoints
-//===========================================================================
-// Adds any additional planes necessary to allow the brush to be expanded
-// against axial bounding boxes
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AddBrushBevels (mapbrush_t *b)
-{
- int axis, dir;
- int i, j, k, l, order;
- side_t sidetemp;
- brush_texture_t tdtemp;
-#ifdef SIN
- textureref_t trtemp;
-#endif
- side_t *s, *s2;
- vec3_t normal;
- float dist;
- winding_t *w, *w2;
- vec3_t vec, vec2;
- float d;
-
- //
- // add the axial planes
- //
- order = 0;
- for (axis=0 ; axis <3 ; axis++)
- {
- for (dir=-1 ; dir <= 1 ; dir+=2, order++)
- {
- // see if the plane is allready present
- for (i=0, s=b->original_sides ; i<b->numsides ; i++,s++)
- {
- if (mapplanes[s->planenum].normal[axis] == dir)
- break;
- }
-
- if (i == b->numsides)
- { // add a new side
- if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
- Error ("MAX_MAP_BRUSHSIDES");
- nummapbrushsides++;
- b->numsides++;
- VectorClear (normal);
- normal[axis] = dir;
- if (dir == 1)
- dist = b->maxs[axis];
- else
- dist = -b->mins[axis];
- s->planenum = FindFloatPlane (normal, dist);
- s->texinfo = b->original_sides[0].texinfo;
-#ifdef SIN
- s->lightinfo = b->original_sides[0].lightinfo;
-#endif
- s->contents = b->original_sides[0].contents;
- s->flags |= SFL_BEVEL;
- c_boxbevels++;
- }
-
- // if the plane is not in it canonical order, swap it
- if (i != order)
- {
- sidetemp = b->original_sides[order];
- b->original_sides[order] = b->original_sides[i];
- b->original_sides[i] = sidetemp;
-
- j = b->original_sides - brushsides;
- tdtemp = side_brushtextures[j+order];
- side_brushtextures[j+order] = side_brushtextures[j+i];
- side_brushtextures[j+i] = tdtemp;
-
-#ifdef SIN
- trtemp = side_newrefs[j+order];
- side_newrefs[j+order] = side_newrefs[j+i];
- side_newrefs[j+i] = trtemp;
-#endif
- }
- }
- }
-
- //
- // add the edge bevels
- //
- if (b->numsides == 6)
- return; // pure axial
-
- // test the non-axial plane edges
- for (i=6 ; i<b->numsides ; i++)
- {
- s = b->original_sides + i;
- w = s->winding;
- if (!w)
- continue;
- for (j=0 ; j<w->numpoints ; j++)
- {
- k = (j+1)%w->numpoints;
- VectorSubtract (w->p[j], w->p[k], vec);
- if (VectorNormalize (vec) < 0.5)
- continue;
- SnapVector (vec);
- for (k=0 ; k<3 ; k++)
- if ( vec[k] == -1 || vec[k] == 1)
- break; // axial
- if (k != 3)
- continue; // only test non-axial edges
-
- // try the six possible slanted axials from this edge
- for (axis=0 ; axis <3 ; axis++)
- {
- for (dir=-1 ; dir <= 1 ; dir+=2)
- {
- // construct a plane
- VectorClear (vec2);
- vec2[axis] = dir;
- CrossProduct (vec, vec2, normal);
- if (VectorNormalize (normal) < 0.5)
- continue;
- dist = DotProduct (w->p[j], normal);
-
- // if all the points on all the sides are
- // behind this plane, it is a proper edge bevel
- for (k=0 ; k<b->numsides ; k++)
- {
- // if this plane has allready been used, skip it
- if (PlaneEqual (&mapplanes[b->original_sides[k].planenum]
- , normal, dist) )
- break;
-
- w2 = b->original_sides[k].winding;
- if (!w2)
- continue;
- for (l=0 ; l<w2->numpoints ; l++)
- {
- d = DotProduct (w2->p[l], normal) - dist;
- if (d > 0.1)
- break; // point in front
- }
- if (l != w2->numpoints)
- break;
- }
-
- if (k != b->numsides)
- continue; // wasn't part of the outer hull
- // add this plane
- if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
- Error ("MAX_MAP_BRUSHSIDES");
- nummapbrushsides++;
- s2 = &b->original_sides[b->numsides];
- s2->planenum = FindFloatPlane (normal, dist);
- s2->texinfo = b->original_sides[0].texinfo;
-#ifdef SIN
- s2->lightinfo = b->original_sides[0].lightinfo;
-#endif
- s2->contents = b->original_sides[0].contents;
- s2->flags |= SFL_BEVEL;
- c_edgebevels++;
- b->numsides++;
- }
- }
- }
- }
-} //end of the function AddBrushBevels
-//===========================================================================
-// creates windigs for sides and mins / maxs for the brush
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean MakeBrushWindings(mapbrush_t *ob)
-{
- int i, j;
- winding_t *w;
- side_t *side;
- plane_t *plane;
-
- ClearBounds (ob->mins, ob->maxs);
-
- for (i = 0; i < ob->numsides; i++)
- {
- plane = &mapplanes[ob->original_sides[i].planenum];
- w = BaseWindingForPlane(plane->normal, plane->dist);
- for (j = 0; j <ob->numsides && w; j++)
- {
- if (i == j) continue;
- if (ob->original_sides[j].flags & SFL_BEVEL) continue;
- plane = &mapplanes[ob->original_sides[j].planenum^1];
- ChopWindingInPlace(&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
- }
-
- side = &ob->original_sides[i];
- side->winding = w;
- if (w)
- {
- side->flags |= SFL_VISIBLE;
- for (j = 0; j < w->numpoints; j++)
- AddPointToBounds (w->p[j], ob->mins, ob->maxs);
- }
- }
-
- for (i = 0; i < 3; i++)
- {
- //IDBUG: all the indexes into the mins and maxs were zero (not using i)
- if (ob->mins[i] < -MAX_MAP_BOUNDS || ob->maxs[i] > MAX_MAP_BOUNDS)
- {
- Log_Print("entity %i, brush %i: bounds out of range\n", ob->entitynum, ob->brushnum);
- ob->numsides = 0; //remove the brush
- break;
- } //end if
- if (ob->mins[i] > MAX_MAP_BOUNDS || ob->maxs[i] < -MAX_MAP_BOUNDS)
- {
- Log_Print("entity %i, brush %i: no visible sides on brush\n", ob->entitynum, ob->brushnum);
- ob->numsides = 0; //remove the brush
- break;
- } //end if
- } //end for
- return true;
-} //end of the function MakeBrushWindings
-//===========================================================================
-// FIXME: currently doesn't mark all bevels
-// NOTE: when one brush bevel is found the remaining sides of the brush
-// are bevels as well (when the brush isn't expanded for AAS :))
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void MarkBrushBevels(mapbrush_t *brush)
-{
- int i;
- int we;
- side_t *s;
-
- //check all the sides of the brush
- for (i = 0; i < brush->numsides; i++)
- {
- s = brush->original_sides + i;
- //if the side has no winding
- if (!s->winding)
- {
- Log_Write("MarkBrushBevels: brush %d no winding", brush->brushnum);
- s->flags |= SFL_BEVEL;
- } //end if
- //if the winding is tiny
- else if (WindingIsTiny(s->winding))
- {
- s->flags |= SFL_BEVEL;
- Log_Write("MarkBrushBevels: brush %d tiny winding", brush->brushnum);
- } //end else if
- //if the winding has errors
- else
- {
- we = WindingError(s->winding);
- if (we == WE_NOTENOUGHPOINTS
- || we == WE_SMALLAREA
- || we == WE_POINTBOGUSRANGE
-// || we == WE_NONCONVEX
- )
- {
- Log_Write("MarkBrushBevels: brush %d %s", brush->brushnum, WindingErrorString());
- s->flags |= SFL_BEVEL;
- } //end else if
- } //end else
- if (s->flags & SFL_BEVEL)
- {
- s->flags &= ~SFL_VISIBLE;
- //if the side has a valid plane
- if (s->planenum > 0 && s->planenum < nummapplanes)
- {
- //if it is an axial plane
- if (mapplanes[s->planenum].type < 3) c_boxbevels++;
- else c_edgebevels++;
- } //end if
- } //end if
- } //end for
-} //end of the function MarkBrushBevels
-//===========================================================================
-// returns true if the map brush already exists
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BrushExists(mapbrush_t *brush)
-{
- int i, s1, s2;
- side_t *side1, *side2;
- mapbrush_t *brush1, *brush2;
-
- for (i = 0; i < nummapbrushes; i++)
- {
- brush1 = brush;
- brush2 = &mapbrushes[i];
- //compare the brushes
- if (brush1->entitynum != brush2->entitynum) continue;
- //if (brush1->contents != brush2->contents) continue;
- if (brush1->numsides != brush2->numsides) continue;
- for (s1 = 0; s1 < brush1->numsides; s1++)
- {
- side1 = brush1->original_sides + s1;
- //
- for (s2 = 0; s2 < brush2->numsides; s2++)
- {
- side2 = brush2->original_sides + s2;
- //
- if ((side1->planenum & ~1) == (side2->planenum & ~1)
-// && side1->texinfo == side2->texinfo
-// && side1->contents == side2->contents
-// && side1->surf == side2->surf
- ) break;
- } //end if
- if (s2 >= brush2->numsides) break;
- } //end for
- if (s1 >= brush1->numsides) return true;
- } //end for
- return false;
-} //end of the function BrushExists
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean WriteMapBrush(FILE *fp, mapbrush_t *brush, vec3_t origin)
-{
- int sn, rotate, shift[2], sv, tv, planenum, p1, i, j;
- float scale[2], originshift[2], ang1, ang2, newdist;
- vec3_t vecs[2], axis[2];
- map_texinfo_t *ti;
- winding_t *w;
- side_t *s;
- plane_t *plane;
-
- if (noliquids)
- {
- if (brush->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA))
- {
- return true;
- } //end if
- } //end if
- //if the brush has no contents
- if (!brush->contents) return true;
- //print the leading {
- if (fprintf(fp, " { //brush %d\n", brush->brushnum) < 0) return false;
- //write brush sides
- for (sn = 0; sn < brush->numsides; sn++)
- {
- s = brush->original_sides + sn;
- //don't write out bevels
- if (!(s->flags & SFL_BEVEL))
- {
- //if the entity has an origin set
- if (origin[0] || origin[1] || origin[2])
- {
- newdist = mapplanes[s->planenum].dist +
- DotProduct(mapplanes[s->planenum].normal, origin);
- planenum = FindFloatPlane(mapplanes[s->planenum].normal, newdist);
- } //end if
- else
- {
- planenum = s->planenum;
- } //end else
- //always take the first plane, then flip the points if necesary
- plane = &mapplanes[planenum & ~1];
- w = BaseWindingForPlane(plane->normal, plane->dist);
- //
- for (i = 0; i < 3; i++)
- {
- for (j = 0; j < 3; j++)
- {
- if (fabs(w->p[i][j]) < 0.2) w->p[i][j] = 0;
- else if (fabs((int)w->p[i][j] - w->p[i][j]) < 0.3) w->p[i][j] = (int) w->p[i][j];
- //w->p[i][j] = (int) (w->p[i][j] + 0.2);
- } //end for
- } //end for
- //three non-colinear points to define the plane
- if (planenum & 1) p1 = 1;
- else p1 = 0;
- if (fprintf(fp," ( %5i %5i %5i ) ", (int)w->p[p1][0], (int)w->p[p1][1], (int)w->p[p1][2]) < 0) return false;
- if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[!p1][0], (int)w->p[!p1][1], (int)w->p[!p1][2]) < 0) return false;
- if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]) < 0) return false;
- //free the winding
- FreeWinding(w);
- //
- if (s->texinfo == TEXINFO_NODE)
- {
- if (brush->contents & CONTENTS_PLAYERCLIP)
- {
- //player clip
- if (loadedmaptype == MAPTYPE_SIN)
- {
- if (fprintf(fp, "generic/misc/clip 0 0 0 1 1") < 0) return false;
- } //end if
- else if (loadedmaptype == MAPTYPE_QUAKE2)
- { //FIXME: don't always use e1u1
- if (fprintf(fp, "e1u1/clip 0 0 0 1 1") < 0) return false;
- } //end else
- else if (loadedmaptype == MAPTYPE_QUAKE3)
- {
- if (fprintf(fp, "e1u1/clip 0 0 0 1 1") < 0) return false;
- } //end else if
- else
- {
- if (fprintf(fp, "clip 0 0 0 1 1") < 0) return false;
- } //end else
- } //end if
- else if (brush->contents == CONTENTS_MONSTERCLIP)
- {
- //monster clip
- if (loadedmaptype == MAPTYPE_SIN)
- {
- if (fprintf(fp, "generic/misc/monster 0 0 0 1 1") < 0) return false;
- } //end if
- else if (loadedmaptype == MAPTYPE_QUAKE2)
- {
- if (fprintf(fp, "e1u1/clip_mon 0 0 0 1 1") < 0) return false;
- } //end else
- else
- {
- if (fprintf(fp, "clip 0 0 0 1 1") < 0) return false;
- } //end else
- } //end else
- else
- {
- if (fprintf(fp, "clip 0 0 0 1 1") < 0) return false;
- Log_Write("brush->contents = %d\n", brush->contents);
- } //end else
- } //end if
- else if (loadedmaptype == MAPTYPE_SIN && s->texinfo == 0)
- {
- if (brush->contents & CONTENTS_DUMMYFENCE)
- {
- if (fprintf(fp, "generic/misc/fence 0 0 0 1 1") < 0) return false;
- } //end if
- else if (brush->contents & CONTENTS_MIST)
- {
- if (fprintf(fp, "generic/misc/volumetric_base 0 0 0 1 1") < 0) return false;
- } //end if
- else //unknown so far
- {
- if (fprintf(fp, "generic/misc/red 0 0 0 1 1") < 0) return false;
- } //end else
- } //end if
- else if (loadedmaptype == MAPTYPE_QUAKE3)
- {
- //always use the same texture
- if (fprintf(fp, "e2u3/floor1_2 0 0 0 1 1 1 0 0") < 0) return false;
- } //end else if
- else
- {
- //*
- ti = &map_texinfo[s->texinfo];
- //the scaling of the texture
- scale[0] = 1 / VectorNormalize2(ti->vecs[0], vecs[0]);
- scale[1] = 1 / VectorNormalize2(ti->vecs[1], vecs[1]);
- //
- TextureAxisFromPlane(plane, axis[0], axis[1]);
- //calculate texture shift done by entity origin
- originshift[0] = DotProduct(origin, axis[0]);
- originshift[1] = DotProduct(origin, axis[1]);
- //the texture shift without origin shift
- shift[0] = ti->vecs[0][3] - originshift[0];
- shift[1] = ti->vecs[1][3] - originshift[1];
- //
- if (axis[0][0]) sv = 0;
- else if (axis[0][1]) sv = 1;
- else sv = 2;
- if (axis[1][0]) tv = 0;
- else if (axis[1][1]) tv = 1;
- else tv = 2;
- //calculate rotation of texture
- if (vecs[0][tv] == 0) ang1 = vecs[0][sv] > 0 ? 90.0 : -90.0;
- else ang1 = atan2(vecs[0][sv], vecs[0][tv]) * 180 / Q_PI;
- if (ang1 < 0) ang1 += 360;
- if (ang1 >= 360) ang1 -= 360;
- if (axis[0][tv] == 0) ang2 = axis[0][sv] > 0 ? 90.0 : -90.0;
- else ang2 = atan2(axis[0][sv], axis[0][tv]) * 180 / Q_PI;
- if (ang2 < 0) ang2 += 360;
- if (ang2 >= 360) ang2 -= 360;
- rotate = ang2 - ang1;
- if (rotate < 0) rotate += 360;
- if (rotate >= 360) rotate -= 360;
- //write the texture info
- if (fprintf(fp, "%s %d %d %d", ti->texture, shift[0], shift[1], rotate) < 0) return false;
- if (fabs(scale[0] - ((int) scale[0])) < 0.001)
- {
- if (fprintf(fp, " %d", (int) scale[0]) < 0) return false;
- } //end if
- else
- {
- if (fprintf(fp, " %4f", scale[0]) < 0) return false;
- } //end if
- if (fabs(scale[1] - ((int) scale[1])) < 0.001)
- {
- if (fprintf(fp, " %d", (int) scale[1]) < 0) return false;
- } //end if
- else
- {
- if (fprintf(fp, " %4f", scale[1]) < 0) return false;
- } //end else
- //write the extra brush side info
- if (loadedmaptype == MAPTYPE_QUAKE2)
- {
- if (fprintf(fp, " %ld %ld %ld", s->contents, ti->flags, ti->value) < 0) return false;
- } //end if
- //*/
- } //end else
- if (fprintf(fp, "\n") < 0) return false;
- } //end if
- } //end if
- if (fprintf(fp, " }\n") < 0) return false;
- c_writtenbrushes++;
- return true;
-} //end of the function WriteMapBrush
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean WriteOriginBrush(FILE *fp, vec3_t origin)
-{
- vec3_t normal;
- float dist;
- int i, s;
- winding_t *w;
-
- if (fprintf(fp, " {\n") < 0) return false;
- //
- for (i = 0; i < 3; i++)
- {
- for (s = -1; s <= 1; s += 2)
- {
- //
- VectorClear(normal);
- normal[i] = s;
- dist = origin[i] * s + 16;
- //
- w = BaseWindingForPlane(normal, dist);
- //three non-colinear points to define the plane
- if (fprintf(fp," ( %5i %5i %5i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]) < 0) return false;
- if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]) < 0) return false;
- if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]) < 0) return false;
- //free the winding
- FreeWinding(w);
- //write origin texture:
- // CONTENTS_ORIGIN = 16777216
- // SURF_NODRAW = 128
- if (loadedmaptype == MAPTYPE_SIN)
- {
- if (fprintf(fp, "generic/misc/origin 0 0 0 1 1") < 0) return false;
- } //end if
- else if (loadedmaptype == MAPTYPE_HALFLIFE)
- {
- if (fprintf(fp, "origin 0 0 0 1 1") < 0) return false;
- } //end if
- else
- {
- if (fprintf(fp, "e1u1/origin 0 0 0 1 1") < 0) return false;
- } //end else
- //Quake2 extra brush side info
- if (loadedmaptype == MAPTYPE_QUAKE2)
- {
- //if (fprintf(fp, " 16777216 128 0") < 0) return false;
- } //end if
- if (fprintf(fp, "\n") < 0) return false;
- } //end for
- } //end for
- if (fprintf(fp, " }\n") < 0) return false;
- c_writtenbrushes++;
- return true;
-} //end of the function WriteOriginBrush
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-mapbrush_t *GetAreaPortalBrush(entity_t *mapent)
-{
- int portalnum, bn;
- mapbrush_t *brush;
-
- //the area portal number
- portalnum = mapent->areaportalnum;
- //find the area portal brush in the world brushes
- for (bn = 0; bn < nummapbrushes && portalnum; bn++)
- {
- brush = &mapbrushes[bn];
- //must be in world entity
- if (brush->entitynum == 0)
- {
- if (brush->contents & CONTENTS_AREAPORTAL)
- {
- portalnum--;
- } //end if
- } //end if
- } //end for
- if (bn < nummapbrushes)
- {
- return brush;
- } //end if
- else
- {
- Log_Print("area portal %d brush not found\n", mapent->areaportalnum);
- return NULL;
- } //end else
-} //end of the function GetAreaPortalBrush
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean WriteMapFileSafe(FILE *fp)
-{
- char key[1024], value[1024];
- int i, bn, entitybrushes;
- epair_t *ep;
- mapbrush_t *brush;
- entity_t *mapent;
- //vec3_t vec_origin = {0, 0, 0};
-
- //
- if (fprintf(fp,"//=====================================================\n"
- "//\n"
- "// map file created with BSPC "BSPC_VERSION"\n"
- "//\n"
- "// BSPC is designed to decompile material in which you own the copyright\n"
- "// or have obtained permission to decompile from the copyright owner. Unless\n"
- "// you own the copyright or have permission to decompile from the copyright\n"
- "// owner, you may be violating copyright law and be subject to payment of\n"
- "// damages and other remedies. If you are uncertain about your rights, contact\n"
- "// your legal advisor.\n"
- "//\n") < 0) return false;
- if (loadedmaptype == MAPTYPE_SIN)
- {
- if (fprintf(fp,
- "// generic/misc/red is used for unknown textures\n") < 0) return false;
- } //end if
- if (fprintf(fp,"//\n"
- "//=====================================================\n") < 0) return false;
- //write out all the entities
- for (i = 0; i < num_entities; i++)
- {
- mapent = &entities[i];
- if (!mapent->epairs)
- {
- continue;
- } //end if
- if (fprintf(fp, "{\n") < 0) return false;
- //
- if (loadedmaptype == MAPTYPE_QUAKE3)
- {
- if (!stricmp(ValueForKey(mapent, "classname"), "light"))
- {
- SetKeyValue(mapent, "light", "10000");
- } //end if
- } //end if
- //write epairs
- for (ep = mapent->epairs; ep; ep = ep->next)
- {
- strcpy(key, ep->key);
- StripTrailing (key);
- strcpy(value, ep->value);
- StripTrailing(value);
- //
- if (loadedmaptype == MAPTYPE_QUAKE2 ||
- loadedmaptype == MAPTYPE_SIN)
- {
- //don't write an origin for BSP models
- if (mapent->modelnum >= 0 && !strcmp(key, "origin")) continue;
- } //end if
- //don't write BSP model numbers
- if (mapent->modelnum >= 0 && !strcmp(key, "model") && value[0] == '*') continue;
- //
- if (fprintf(fp, " \"%s\" \"%s\"\n", key, value) < 0) return false;
- } //end for
- //
- if (ValueForKey(mapent, "origin")) GetVectorForKey(mapent, "origin", mapent->origin);
- else mapent->origin[0] = mapent->origin[1] = mapent->origin[2] = 0;
- //if this is an area portal entity
- if (!strcmp("func_areaportal", ValueForKey(mapent, "classname")))
- {
- brush = GetAreaPortalBrush(mapent);
- if (!brush) return false;
- if (!WriteMapBrush(fp, brush, mapent->origin)) return false;
- } //end if
- else
- {
- entitybrushes = false;
- //write brushes
- for (bn = 0; bn < nummapbrushes; bn++)
- {
- brush = &mapbrushes[bn];
- //if the brush is part of this entity
- if (brush->entitynum == i)
- {
- //don't write out area portal brushes in the world
- if (!((brush->contents & CONTENTS_AREAPORTAL) && brush->entitynum == 0))
- {
- /*
- if (!strcmp("func_door_rotating", ValueForKey(mapent, "classname")))
- {
- AAS_PositionFuncRotatingBrush(mapent, brush);
- if (!WriteMapBrush(fp, brush, vec_origin)) return false;
- } //end if
- else //*/
- {
- if (!WriteMapBrush(fp, brush, mapent->origin)) return false;
- } //end else
- entitybrushes = true;
- } //end if
- } //end if
- } //end for
- //if the entity had brushes
- if (entitybrushes)
- {
- //if the entity has an origin set
- if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2])
- {
- if (!WriteOriginBrush(fp, mapent->origin)) return false;
- } //end if
- } //end if
- } //end else
- if (fprintf(fp, "}\n") < 0) return false;
- } //end for
- if (fprintf(fp, "//total of %d brushes\n", c_writtenbrushes) < 0) return false;
- return true;
-} //end of the function WriteMapFileSafe
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void WriteMapFile(char *filename)
-{
- FILE *fp;
- double start_time;
-
- c_writtenbrushes = 0;
- //the time started
- start_time = I_FloatTime();
- //
- Log_Print("writing %s\n", filename);
- fp = fopen(filename, "wb");
- if (!fp)
- {
- Log_Print("can't open %s\n", filename);
- return;
- } //end if
- if (!WriteMapFileSafe(fp))
- {
- fclose(fp);
- Log_Print("error writing map file %s\n", filename);
- return;
- } //end if
- fclose(fp);
- //display creation time
- Log_Print("written %d brushes\n", c_writtenbrushes);
- Log_Print("map file written in %5.0f seconds\n", I_FloatTime() - start_time);
-} //end of the function WriteMapFile
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void PrintMapInfo(void)
-{
- Log_Print("\n");
- Log_Print("%6i brushes\n", nummapbrushes);
- Log_Print("%6i brush sides\n", nummapbrushsides);
-// Log_Print("%6i clipbrushes\n", c_clipbrushes);
-// Log_Print("%6i total sides\n", nummapbrushsides);
-// Log_Print("%6i boxbevels\n", c_boxbevels);
-// Log_Print("%6i edgebevels\n", c_edgebevels);
-// Log_Print("%6i entities\n", num_entities);
-// Log_Print("%6i planes\n", nummapplanes);
-// Log_Print("%6i areaportals\n", c_areaportals);
-// Log_Print("%6i squatt brushes\n", c_squattbrushes);
-// Log_Print("size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", map_mins[0],map_mins[1],map_mins[2],
-// map_maxs[0],map_maxs[1],map_maxs[2]);
-} //end of the function PrintMapInfo
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ResetMapLoading(void)
-{
- int i;
- epair_t *ep, *nextep;
-
- Q2_ResetMapLoading();
- Sin_ResetMapLoading();
-
- //free all map brush side windings
- for (i = 0; i < nummapbrushsides; i++)
- {
- if (brushsides[i].winding)
- {
- FreeWinding(brushsides[i].winding);
- } //end for
- } //end for
-
- //reset regular stuff
- nummapbrushes = 0;
- memset(mapbrushes, 0, MAX_MAPFILE_BRUSHES * sizeof(mapbrush_t));
- //
- nummapbrushsides = 0;
- memset(brushsides, 0, MAX_MAPFILE_BRUSHSIDES * sizeof(side_t));
- memset(side_brushtextures, 0, MAX_MAPFILE_BRUSHSIDES * sizeof(brush_texture_t));
- //
- nummapplanes = 0;
- memset(mapplanes, 0, MAX_MAPFILE_PLANES * sizeof(plane_t));
- //
- memset(planehash, 0, PLANE_HASHES * sizeof(plane_t *));
- //
- memset(map_texinfo, 0, MAX_MAPFILE_TEXINFO * sizeof(map_texinfo_t));
- map_numtexinfo = 0;
- //
- VectorClear(map_mins);
- VectorClear(map_maxs);
- //
- c_boxbevels = 0;
- c_edgebevels = 0;
- c_areaportals = 0;
- c_clipbrushes = 0;
- c_writtenbrushes = 0;
- //clear the entities
- for (i = 0; i < num_entities; i++)
- {
- for (ep = entities[i].epairs; ep; ep = nextep)
- {
- nextep = ep->next;
- FreeMemory(ep->key);
- FreeMemory(ep->value);
- FreeMemory(ep);
- } //end for
- } //end for
- num_entities = 0;
- memset(entities, 0, MAX_MAP_ENTITIES * sizeof(entity_t));
-} //end of the function ResetMapLoading
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#ifndef Q1_BSPVERSION
-#define Q1_BSPVERSION 29
-#endif
-#ifndef HL_BSPVERSION
-#define HL_BSPVERSION 30
-#endif
-
-#define Q2_BSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I') //IBSP
-#define Q2_BSPVERSION 38
-
-#define SINGAME_BSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'R') //RBSP
-#define SINGAME_BSPVERSION 1
-
-#define SIN_BSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I') //IBSP
-#define SIN_BSPVERSION 41
-
-typedef struct
-{
- int ident;
- int version;
-} idheader_t;
-
-int LoadMapFromBSP(struct quakefile_s *qf)
-{
- idheader_t idheader;
-
- if (ReadQuakeFile(qf, &idheader, 0, sizeof(idheader_t)) != sizeof(idheader_t))
- {
- return false;
- } //end if
-
- idheader.ident = LittleLong(idheader.ident);
- idheader.version = LittleLong(idheader.version);
- //Quake3 BSP file
- if (idheader.ident == Q3_BSP_IDENT && idheader.version == Q3_BSP_VERSION)
- {
- ResetMapLoading();
- Q3_LoadMapFromBSP(qf);
- Q3_FreeMaxBSP();
- } //end if
- //Quake2 BSP file
- else if (idheader.ident == Q2_BSPHEADER && idheader.version == Q2_BSPVERSION)
- {
- ResetMapLoading();
- Q2_AllocMaxBSP();
- Q2_LoadMapFromBSP(qf->filename, qf->offset, qf->length);
- Q2_FreeMaxBSP();
- } //endif
- //Sin BSP file
- else if ((idheader.ident == SIN_BSPHEADER && idheader.version == SIN_BSPVERSION) ||
- //the dorks gave the same format another ident and verions
- (idheader.ident == SINGAME_BSPHEADER && idheader.version == SINGAME_BSPVERSION))
- {
- ResetMapLoading();
- Sin_AllocMaxBSP();
- Sin_LoadMapFromBSP(qf->filename, qf->offset, qf->length);
- Sin_FreeMaxBSP();
- } //end if
- //the Quake1 bsp files don't have a ident only a version
- else if (idheader.ident == Q1_BSPVERSION)
- {
- ResetMapLoading();
- Q1_AllocMaxBSP();
- Q1_LoadMapFromBSP(qf->filename, qf->offset, qf->length);
- Q1_FreeMaxBSP();
- } //end if
- //Half-Life also only uses a version number
- else if (idheader.ident == HL_BSPVERSION)
- {
- ResetMapLoading();
- HL_AllocMaxBSP();
- HL_LoadMapFromBSP(qf->filename, qf->offset, qf->length);
- HL_FreeMaxBSP();
- } //end if
- else
- {
- Error("unknown BSP format %c%c%c%c, version %d\n",
- (idheader.ident & 0xFF),
- ((idheader.ident >> 8) & 0xFF),
- ((idheader.ident >> 16) & 0xFF),
- ((idheader.ident >> 24) & 0xFF), idheader.version);
- return false;
- } //end if
- //
- return true;
-} //end of the function LoadMapFromBSP
+/*
+===========================================================================
+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 "l_bsp_hl.h"
+#include "l_bsp_q1.h"
+#include "l_bsp_q2.h"
+#include "l_bsp_q3.h"
+#include "l_bsp_sin.h"
+#include "l_mem.h"
+#include "../botlib/aasfile.h" //aas_bbox_t
+#include "aas_store.h" //AAS_MAX_BBOXES
+#include "aas_cfg.h"
+
+#define Sign(x) (x < 0 ? 1 : 0)
+
+int nummapbrushes;
+mapbrush_t mapbrushes[MAX_MAPFILE_BRUSHES];
+
+int nummapbrushsides;
+side_t brushsides[MAX_MAPFILE_BRUSHSIDES];
+brush_texture_t side_brushtextures[MAX_MAPFILE_BRUSHSIDES];
+
+int nummapplanes;
+plane_t mapplanes[MAX_MAPFILE_PLANES];
+int mapplaneusers[MAX_MAPFILE_PLANES];
+
+#define PLANE_HASHES 1024
+plane_t *planehash[PLANE_HASHES];
+vec3_t map_mins, map_maxs;
+
+#ifdef SIN
+textureref_t side_newrefs[MAX_MAPFILE_BRUSHSIDES];
+#endif
+
+map_texinfo_t map_texinfo[MAX_MAPFILE_TEXINFO];
+int map_numtexinfo;
+int loadedmaptype; //loaded map type
+
+// undefine to make plane finding use linear sort
+#define USE_HASHING
+
+int c_boxbevels;
+int c_edgebevels;
+int c_areaportals;
+int c_clipbrushes;
+int c_squattbrushes;
+int c_writtenbrushes;
+
+/*
+=============================================================================
+
+PLANE FINDING
+
+=============================================================================
+*/
+
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int PlaneSignBits(vec3_t normal)
+{
+ int i, signbits;
+
+ signbits = 0;
+ for (i = 2; i >= 0; i--)
+ {
+ signbits = (signbits << 1) + Sign(normal[i]);
+ } //end for
+ return signbits;
+} //end of the function PlaneSignBits
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int PlaneTypeForNormal(vec3_t normal)
+{
+ vec_t ax, ay, az;
+
+// NOTE: should these have an epsilon around 1.0?
+ if (normal[0] == 1.0 || normal[0] == -1.0)
+ return PLANE_X;
+ if (normal[1] == 1.0 || normal[1] == -1.0)
+ return PLANE_Y;
+ if (normal[2] == 1.0 || normal[2] == -1.0)
+ 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 PlaneTypeForNormal
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+//ME NOTE: changed from 0.00001
+#define NORMAL_EPSILON 0.0001
+//ME NOTE: changed from 0.01
+#define DIST_EPSILON 0.02
+qboolean PlaneEqual(plane_t *p, vec3_t normal, vec_t dist)
+{
+#if 1
+ if (
+ fabs(p->normal[0] - normal[0]) < NORMAL_EPSILON
+ && fabs(p->normal[1] - normal[1]) < NORMAL_EPSILON
+ && fabs(p->normal[2] - normal[2]) < NORMAL_EPSILON
+ && fabs(p->dist - dist) < DIST_EPSILON )
+ return true;
+#else
+ if (p->normal[0] == normal[0]
+ && p->normal[1] == normal[1]
+ && p->normal[2] == normal[2]
+ && p->dist == dist)
+ return true;
+#endif
+ return false;
+} //end of the function PlaneEqual
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AddPlaneToHash(plane_t *p)
+{
+ int hash;
+
+ hash = (int)fabs(p->dist) / 8;
+ hash &= (PLANE_HASHES-1);
+
+ p->hash_chain = planehash[hash];
+ planehash[hash] = p;
+} //end of the function AddPlaneToHash
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int CreateNewFloatPlane (vec3_t normal, vec_t dist)
+{
+ plane_t *p, temp;
+
+ if (VectorLength(normal) < 0.5)
+ Error ("FloatPlane: bad normal");
+ // create a new plane
+ if (nummapplanes+2 > MAX_MAPFILE_PLANES)
+ Error ("MAX_MAPFILE_PLANES");
+
+ p = &mapplanes[nummapplanes];
+ VectorCopy (normal, p->normal);
+ p->dist = dist;
+ p->type = (p+1)->type = PlaneTypeForNormal (p->normal);
+ p->signbits = PlaneSignBits(p->normal);
+
+ VectorSubtract (vec3_origin, normal, (p+1)->normal);
+ (p+1)->dist = -dist;
+ (p+1)->signbits = PlaneSignBits((p+1)->normal);
+
+ nummapplanes += 2;
+
+ // allways put axial planes facing positive first
+ if (p->type < 3)
+ {
+ if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0)
+ {
+ // flip order
+ temp = *p;
+ *p = *(p+1);
+ *(p+1) = temp;
+
+ AddPlaneToHash (p);
+ AddPlaneToHash (p+1);
+ return nummapplanes - 1;
+ }
+ }
+
+ AddPlaneToHash (p);
+ AddPlaneToHash (p+1);
+ return nummapplanes - 2;
+} //end of the function CreateNewFloatPlane
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void SnapVector(vec3_t normal)
+{
+ int i;
+
+ for (i=0 ; i<3 ; i++)
+ {
+ if ( fabs(normal[i] - 1) < NORMAL_EPSILON )
+ {
+ VectorClear (normal);
+ normal[i] = 1;
+ break;
+ }
+ if ( fabs(normal[i] - -1) < NORMAL_EPSILON )
+ {
+ VectorClear (normal);
+ normal[i] = -1;
+ break;
+ }
+ }
+} //end of the function SnapVector
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void SnapPlane(vec3_t normal, vec_t *dist)
+{
+ SnapVector(normal);
+
+ if (fabs(*dist-Q_rint(*dist)) < DIST_EPSILON)
+ *dist = Q_rint(*dist);
+} //end of the function SnapPlane
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+#ifndef USE_HASHING
+int FindFloatPlane(vec3_t normal, vec_t dist)
+{
+ int i;
+ plane_t *p;
+
+ SnapPlane(normal, &dist);
+ for (i = 0, p = mapplanes; i < nummapplanes; i++, p++)
+ {
+ if (PlaneEqual (p, normal, dist))
+ {
+ mapplaneusers[i]++;
+ return i;
+ } //end if
+ } //end for
+ i = CreateNewFloatPlane (normal, dist);
+ mapplaneusers[i]++;
+ return i;
+} //end of the function FindFloatPlane
+#else
+int FindFloatPlane (vec3_t normal, vec_t dist)
+{
+ int i;
+ plane_t *p;
+ int hash, h;
+
+ SnapPlane (normal, &dist);
+ hash = (int)fabs(dist) / 8;
+ hash &= (PLANE_HASHES-1);
+
+ // search the border bins as well
+ for (i = -1; i <= 1; i++)
+ {
+ h = (hash+i)&(PLANE_HASHES-1);
+ for (p = planehash[h]; p; p = p->hash_chain)
+ {
+ if (PlaneEqual(p, normal, dist))
+ {
+ mapplaneusers[p-mapplanes]++;
+ return p - mapplanes;
+ } //end if
+ } //end for
+ } //end for
+ i = CreateNewFloatPlane (normal, dist);
+ mapplaneusers[i]++;
+ return i;
+} //end of the function FindFloatPlane
+#endif
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int PlaneFromPoints (int *p0, int *p1, int *p2)
+{
+ vec3_t t1, t2, normal;
+ vec_t dist;
+
+ VectorSubtract (p0, p1, t1);
+ VectorSubtract (p2, p1, t2);
+ CrossProduct (t1, t2, normal);
+ VectorNormalize (normal);
+
+ dist = DotProduct (p0, normal);
+
+ return FindFloatPlane (normal, dist);
+} //end of the function PlaneFromPoints
+//===========================================================================
+// Adds any additional planes necessary to allow the brush to be expanded
+// against axial bounding boxes
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AddBrushBevels (mapbrush_t *b)
+{
+ int axis, dir;
+ int i, j, k, l, order;
+ side_t sidetemp;
+ brush_texture_t tdtemp;
+#ifdef SIN
+ textureref_t trtemp;
+#endif
+ side_t *s, *s2;
+ vec3_t normal;
+ float dist;
+ winding_t *w, *w2;
+ vec3_t vec, vec2;
+ float d;
+
+ //
+ // add the axial planes
+ //
+ order = 0;
+ for (axis=0 ; axis <3 ; axis++)
+ {
+ for (dir=-1 ; dir <= 1 ; dir+=2, order++)
+ {
+ // see if the plane is allready present
+ for (i=0, s=b->original_sides ; i<b->numsides ; i++,s++)
+ {
+ if (mapplanes[s->planenum].normal[axis] == dir)
+ break;
+ }
+
+ if (i == b->numsides)
+ { // add a new side
+ if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
+ Error ("MAX_MAP_BRUSHSIDES");
+ nummapbrushsides++;
+ b->numsides++;
+ VectorClear (normal);
+ normal[axis] = dir;
+ if (dir == 1)
+ dist = b->maxs[axis];
+ else
+ dist = -b->mins[axis];
+ s->planenum = FindFloatPlane (normal, dist);
+ s->texinfo = b->original_sides[0].texinfo;
+#ifdef SIN
+ s->lightinfo = b->original_sides[0].lightinfo;
+#endif
+ s->contents = b->original_sides[0].contents;
+ s->flags |= SFL_BEVEL;
+ c_boxbevels++;
+ }
+
+ // if the plane is not in it canonical order, swap it
+ if (i != order)
+ {
+ sidetemp = b->original_sides[order];
+ b->original_sides[order] = b->original_sides[i];
+ b->original_sides[i] = sidetemp;
+
+ j = b->original_sides - brushsides;
+ tdtemp = side_brushtextures[j+order];
+ side_brushtextures[j+order] = side_brushtextures[j+i];
+ side_brushtextures[j+i] = tdtemp;
+
+#ifdef SIN
+ trtemp = side_newrefs[j+order];
+ side_newrefs[j+order] = side_newrefs[j+i];
+ side_newrefs[j+i] = trtemp;
+#endif
+ }
+ }
+ }
+
+ //
+ // add the edge bevels
+ //
+ if (b->numsides == 6)
+ return; // pure axial
+
+ // test the non-axial plane edges
+ for (i=6 ; i<b->numsides ; i++)
+ {
+ s = b->original_sides + i;
+ w = s->winding;
+ if (!w)
+ continue;
+ for (j=0 ; j<w->numpoints ; j++)
+ {
+ k = (j+1)%w->numpoints;
+ VectorSubtract (w->p[j], w->p[k], vec);
+ if (VectorNormalize (vec) < 0.5)
+ continue;
+ SnapVector (vec);
+ for (k=0 ; k<3 ; k++)
+ if ( vec[k] == -1 || vec[k] == 1)
+ break; // axial
+ if (k != 3)
+ continue; // only test non-axial edges
+
+ // try the six possible slanted axials from this edge
+ for (axis=0 ; axis <3 ; axis++)
+ {
+ for (dir=-1 ; dir <= 1 ; dir+=2)
+ {
+ // construct a plane
+ VectorClear (vec2);
+ vec2[axis] = dir;
+ CrossProduct (vec, vec2, normal);
+ if (VectorNormalize (normal) < 0.5)
+ continue;
+ dist = DotProduct (w->p[j], normal);
+
+ // if all the points on all the sides are
+ // behind this plane, it is a proper edge bevel
+ for (k=0 ; k<b->numsides ; k++)
+ {
+ // if this plane has allready been used, skip it
+ if (PlaneEqual (&mapplanes[b->original_sides[k].planenum]
+ , normal, dist) )
+ break;
+
+ w2 = b->original_sides[k].winding;
+ if (!w2)
+ continue;
+ for (l=0 ; l<w2->numpoints ; l++)
+ {
+ d = DotProduct (w2->p[l], normal) - dist;
+ if (d > 0.1)
+ break; // point in front
+ }
+ if (l != w2->numpoints)
+ break;
+ }
+
+ if (k != b->numsides)
+ continue; // wasn't part of the outer hull
+ // add this plane
+ if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
+ Error ("MAX_MAP_BRUSHSIDES");
+ nummapbrushsides++;
+ s2 = &b->original_sides[b->numsides];
+ s2->planenum = FindFloatPlane (normal, dist);
+ s2->texinfo = b->original_sides[0].texinfo;
+#ifdef SIN
+ s2->lightinfo = b->original_sides[0].lightinfo;
+#endif
+ s2->contents = b->original_sides[0].contents;
+ s2->flags |= SFL_BEVEL;
+ c_edgebevels++;
+ b->numsides++;
+ }
+ }
+ }
+ }
+} //end of the function AddBrushBevels
+//===========================================================================
+// creates windigs for sides and mins / maxs for the brush
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+qboolean MakeBrushWindings(mapbrush_t *ob)
+{
+ int i, j;
+ winding_t *w;
+ side_t *side;
+ plane_t *plane;
+
+ ClearBounds (ob->mins, ob->maxs);
+
+ for (i = 0; i < ob->numsides; i++)
+ {
+ plane = &mapplanes[ob->original_sides[i].planenum];
+ w = BaseWindingForPlane(plane->normal, plane->dist);
+ for (j = 0; j <ob->numsides && w; j++)
+ {
+ if (i == j) continue;
+ if (ob->original_sides[j].flags & SFL_BEVEL) continue;
+ plane = &mapplanes[ob->original_sides[j].planenum^1];
+ ChopWindingInPlace(&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
+ }
+
+ side = &ob->original_sides[i];
+ side->winding = w;
+ if (w)
+ {
+ side->flags |= SFL_VISIBLE;
+ for (j = 0; j < w->numpoints; j++)
+ AddPointToBounds (w->p[j], ob->mins, ob->maxs);
+ }
+ }
+
+ for (i = 0; i < 3; i++)
+ {
+ //IDBUG: all the indexes into the mins and maxs were zero (not using i)
+ if (ob->mins[i] < -MAX_MAP_BOUNDS || ob->maxs[i] > MAX_MAP_BOUNDS)
+ {
+ Log_Print("entity %i, brush %i: bounds out of range\n", ob->entitynum, ob->brushnum);
+ ob->numsides = 0; //remove the brush
+ break;
+ } //end if
+ if (ob->mins[i] > MAX_MAP_BOUNDS || ob->maxs[i] < -MAX_MAP_BOUNDS)
+ {
+ Log_Print("entity %i, brush %i: no visible sides on brush\n", ob->entitynum, ob->brushnum);
+ ob->numsides = 0; //remove the brush
+ break;
+ } //end if
+ } //end for
+ return true;
+} //end of the function MakeBrushWindings
+//===========================================================================
+// FIXME: currently doesn't mark all bevels
+// NOTE: when one brush bevel is found the remaining sides of the brush
+// are bevels as well (when the brush isn't expanded for AAS :))
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void MarkBrushBevels(mapbrush_t *brush)
+{
+ int i;
+ int we;
+ side_t *s;
+
+ //check all the sides of the brush
+ for (i = 0; i < brush->numsides; i++)
+ {
+ s = brush->original_sides + i;
+ //if the side has no winding
+ if (!s->winding)
+ {
+ Log_Write("MarkBrushBevels: brush %d no winding", brush->brushnum);
+ s->flags |= SFL_BEVEL;
+ } //end if
+ //if the winding is tiny
+ else if (WindingIsTiny(s->winding))
+ {
+ s->flags |= SFL_BEVEL;
+ Log_Write("MarkBrushBevels: brush %d tiny winding", brush->brushnum);
+ } //end else if
+ //if the winding has errors
+ else
+ {
+ we = WindingError(s->winding);
+ if (we == WE_NOTENOUGHPOINTS
+ || we == WE_SMALLAREA
+ || we == WE_POINTBOGUSRANGE
+// || we == WE_NONCONVEX
+ )
+ {
+ Log_Write("MarkBrushBevels: brush %d %s", brush->brushnum, WindingErrorString());
+ s->flags |= SFL_BEVEL;
+ } //end else if
+ } //end else
+ if (s->flags & SFL_BEVEL)
+ {
+ s->flags &= ~SFL_VISIBLE;
+ //if the side has a valid plane
+ if (s->planenum > 0 && s->planenum < nummapplanes)
+ {
+ //if it is an axial plane
+ if (mapplanes[s->planenum].type < 3) c_boxbevels++;
+ else c_edgebevels++;
+ } //end if
+ } //end if
+ } //end for
+} //end of the function MarkBrushBevels
+//===========================================================================
+// returns true if the map brush already exists
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int BrushExists(mapbrush_t *brush)
+{
+ int i, s1, s2;
+ side_t *side1, *side2;
+ mapbrush_t *brush1, *brush2;
+
+ for (i = 0; i < nummapbrushes; i++)
+ {
+ brush1 = brush;
+ brush2 = &mapbrushes[i];
+ //compare the brushes
+ if (brush1->entitynum != brush2->entitynum) continue;
+ //if (brush1->contents != brush2->contents) continue;
+ if (brush1->numsides != brush2->numsides) continue;
+ for (s1 = 0; s1 < brush1->numsides; s1++)
+ {
+ side1 = brush1->original_sides + s1;
+ //
+ for (s2 = 0; s2 < brush2->numsides; s2++)
+ {
+ side2 = brush2->original_sides + s2;
+ //
+ if ((side1->planenum & ~1) == (side2->planenum & ~1)
+// && side1->texinfo == side2->texinfo
+// && side1->contents == side2->contents
+// && side1->surf == side2->surf
+ ) break;
+ } //end if
+ if (s2 >= brush2->numsides) break;
+ } //end for
+ if (s1 >= brush1->numsides) return true;
+ } //end for
+ return false;
+} //end of the function BrushExists
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+qboolean WriteMapBrush(FILE *fp, mapbrush_t *brush, vec3_t origin)
+{
+ int sn, rotate, shift[2], sv, tv, planenum, p1, i, j;
+ float scale[2], originshift[2], ang1, ang2, newdist;
+ vec3_t vecs[2], axis[2];
+ map_texinfo_t *ti;
+ winding_t *w;
+ side_t *s;
+ plane_t *plane;
+
+ if (noliquids)
+ {
+ if (brush->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA))
+ {
+ return true;
+ } //end if
+ } //end if
+ //if the brush has no contents
+ if (!brush->contents) return true;
+ //print the leading {
+ if (fprintf(fp, " { //brush %d\n", brush->brushnum) < 0) return false;
+ //write brush sides
+ for (sn = 0; sn < brush->numsides; sn++)
+ {
+ s = brush->original_sides + sn;
+ //don't write out bevels
+ if (!(s->flags & SFL_BEVEL))
+ {
+ //if the entity has an origin set
+ if (origin[0] || origin[1] || origin[2])
+ {
+ newdist = mapplanes[s->planenum].dist +
+ DotProduct(mapplanes[s->planenum].normal, origin);
+ planenum = FindFloatPlane(mapplanes[s->planenum].normal, newdist);
+ } //end if
+ else
+ {
+ planenum = s->planenum;
+ } //end else
+ //always take the first plane, then flip the points if necesary
+ plane = &mapplanes[planenum & ~1];
+ w = BaseWindingForPlane(plane->normal, plane->dist);
+ //
+ for (i = 0; i < 3; i++)
+ {
+ for (j = 0; j < 3; j++)
+ {
+ if (fabs(w->p[i][j]) < 0.2) w->p[i][j] = 0;
+ else if (fabs((int)w->p[i][j] - w->p[i][j]) < 0.3) w->p[i][j] = (int) w->p[i][j];
+ //w->p[i][j] = (int) (w->p[i][j] + 0.2);
+ } //end for
+ } //end for
+ //three non-colinear points to define the plane
+ if (planenum & 1) p1 = 1;
+ else p1 = 0;
+ if (fprintf(fp," ( %5i %5i %5i ) ", (int)w->p[p1][0], (int)w->p[p1][1], (int)w->p[p1][2]) < 0) return false;
+ if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[!p1][0], (int)w->p[!p1][1], (int)w->p[!p1][2]) < 0) return false;
+ if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]) < 0) return false;
+ //free the winding
+ FreeWinding(w);
+ //
+ if (s->texinfo == TEXINFO_NODE)
+ {
+ if (brush->contents & CONTENTS_PLAYERCLIP)
+ {
+ //player clip
+ if (loadedmaptype == MAPTYPE_SIN)
+ {
+ if (fprintf(fp, "generic/misc/clip 0 0 0 1 1") < 0) return false;
+ } //end if
+ else if (loadedmaptype == MAPTYPE_QUAKE2)
+ { //FIXME: don't always use e1u1
+ if (fprintf(fp, "e1u1/clip 0 0 0 1 1") < 0) return false;
+ } //end else
+ else if (loadedmaptype == MAPTYPE_QUAKE3)
+ {
+ if (fprintf(fp, "e1u1/clip 0 0 0 1 1") < 0) return false;
+ } //end else if
+ else
+ {
+ if (fprintf(fp, "clip 0 0 0 1 1") < 0) return false;
+ } //end else
+ } //end if
+ else if (brush->contents == CONTENTS_MONSTERCLIP)
+ {
+ //monster clip
+ if (loadedmaptype == MAPTYPE_SIN)
+ {
+ if (fprintf(fp, "generic/misc/monster 0 0 0 1 1") < 0) return false;
+ } //end if
+ else if (loadedmaptype == MAPTYPE_QUAKE2)
+ {
+ if (fprintf(fp, "e1u1/clip_mon 0 0 0 1 1") < 0) return false;
+ } //end else
+ else
+ {
+ if (fprintf(fp, "clip 0 0 0 1 1") < 0) return false;
+ } //end else
+ } //end else
+ else
+ {
+ if (fprintf(fp, "clip 0 0 0 1 1") < 0) return false;
+ Log_Write("brush->contents = %d\n", brush->contents);
+ } //end else
+ } //end if
+ else if (loadedmaptype == MAPTYPE_SIN && s->texinfo == 0)
+ {
+ if (brush->contents & CONTENTS_DUMMYFENCE)
+ {
+ if (fprintf(fp, "generic/misc/fence 0 0 0 1 1") < 0) return false;
+ } //end if
+ else if (brush->contents & CONTENTS_MIST)
+ {
+ if (fprintf(fp, "generic/misc/volumetric_base 0 0 0 1 1") < 0) return false;
+ } //end if
+ else //unknown so far
+ {
+ if (fprintf(fp, "generic/misc/red 0 0 0 1 1") < 0) return false;
+ } //end else
+ } //end if
+ else if (loadedmaptype == MAPTYPE_QUAKE3)
+ {
+ //always use the same texture
+ if (fprintf(fp, "e2u3/floor1_2 0 0 0 1 1 1 0 0") < 0) return false;
+ } //end else if
+ else
+ {
+ //*
+ ti = &map_texinfo[s->texinfo];
+ //the scaling of the texture
+ scale[0] = 1 / VectorNormalize2(ti->vecs[0], vecs[0]);
+ scale[1] = 1 / VectorNormalize2(ti->vecs[1], vecs[1]);
+ //
+ TextureAxisFromPlane(plane, axis[0], axis[1]);
+ //calculate texture shift done by entity origin
+ originshift[0] = DotProduct(origin, axis[0]);
+ originshift[1] = DotProduct(origin, axis[1]);
+ //the texture shift without origin shift
+ shift[0] = ti->vecs[0][3] - originshift[0];
+ shift[1] = ti->vecs[1][3] - originshift[1];
+ //
+ if (axis[0][0]) sv = 0;
+ else if (axis[0][1]) sv = 1;
+ else sv = 2;
+ if (axis[1][0]) tv = 0;
+ else if (axis[1][1]) tv = 1;
+ else tv = 2;
+ //calculate rotation of texture
+ if (vecs[0][tv] == 0) ang1 = vecs[0][sv] > 0 ? 90.0 : -90.0;
+ else ang1 = atan2(vecs[0][sv], vecs[0][tv]) * 180 / Q_PI;
+ if (ang1 < 0) ang1 += 360;
+ if (ang1 >= 360) ang1 -= 360;
+ if (axis[0][tv] == 0) ang2 = axis[0][sv] > 0 ? 90.0 : -90.0;
+ else ang2 = atan2(axis[0][sv], axis[0][tv]) * 180 / Q_PI;
+ if (ang2 < 0) ang2 += 360;
+ if (ang2 >= 360) ang2 -= 360;
+ rotate = ang2 - ang1;
+ if (rotate < 0) rotate += 360;
+ if (rotate >= 360) rotate -= 360;
+ //write the texture info
+ if (fprintf(fp, "%s %d %d %d", ti->texture, shift[0], shift[1], rotate) < 0) return false;
+ if (fabs(scale[0] - ((int) scale[0])) < 0.001)
+ {
+ if (fprintf(fp, " %d", (int) scale[0]) < 0) return false;
+ } //end if
+ else
+ {
+ if (fprintf(fp, " %4f", scale[0]) < 0) return false;
+ } //end if
+ if (fabs(scale[1] - ((int) scale[1])) < 0.001)
+ {
+ if (fprintf(fp, " %d", (int) scale[1]) < 0) return false;
+ } //end if
+ else
+ {
+ if (fprintf(fp, " %4f", scale[1]) < 0) return false;
+ } //end else
+ //write the extra brush side info
+ if (loadedmaptype == MAPTYPE_QUAKE2)
+ {
+ if (fprintf(fp, " %ld %ld %ld", s->contents, ti->flags, ti->value) < 0) return false;
+ } //end if
+ //*/
+ } //end else
+ if (fprintf(fp, "\n") < 0) return false;
+ } //end if
+ } //end if
+ if (fprintf(fp, " }\n") < 0) return false;
+ c_writtenbrushes++;
+ return true;
+} //end of the function WriteMapBrush
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+qboolean WriteOriginBrush(FILE *fp, vec3_t origin)
+{
+ vec3_t normal;
+ float dist;
+ int i, s;
+ winding_t *w;
+
+ if (fprintf(fp, " {\n") < 0) return false;
+ //
+ for (i = 0; i < 3; i++)
+ {
+ for (s = -1; s <= 1; s += 2)
+ {
+ //
+ VectorClear(normal);
+ normal[i] = s;
+ dist = origin[i] * s + 16;
+ //
+ w = BaseWindingForPlane(normal, dist);
+ //three non-colinear points to define the plane
+ if (fprintf(fp," ( %5i %5i %5i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]) < 0) return false;
+ if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]) < 0) return false;
+ if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]) < 0) return false;
+ //free the winding
+ FreeWinding(w);
+ //write origin texture:
+ // CONTENTS_ORIGIN = 16777216
+ // SURF_NODRAW = 128
+ if (loadedmaptype == MAPTYPE_SIN)
+ {
+ if (fprintf(fp, "generic/misc/origin 0 0 0 1 1") < 0) return false;
+ } //end if
+ else if (loadedmaptype == MAPTYPE_HALFLIFE)
+ {
+ if (fprintf(fp, "origin 0 0 0 1 1") < 0) return false;
+ } //end if
+ else
+ {
+ if (fprintf(fp, "e1u1/origin 0 0 0 1 1") < 0) return false;
+ } //end else
+ //Quake2 extra brush side info
+ if (loadedmaptype == MAPTYPE_QUAKE2)
+ {
+ //if (fprintf(fp, " 16777216 128 0") < 0) return false;
+ } //end if
+ if (fprintf(fp, "\n") < 0) return false;
+ } //end for
+ } //end for
+ if (fprintf(fp, " }\n") < 0) return false;
+ c_writtenbrushes++;
+ return true;
+} //end of the function WriteOriginBrush
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+mapbrush_t *GetAreaPortalBrush(entity_t *mapent)
+{
+ int portalnum, bn;
+ mapbrush_t *brush;
+
+ //the area portal number
+ portalnum = mapent->areaportalnum;
+ //find the area portal brush in the world brushes
+ for (bn = 0; bn < nummapbrushes && portalnum; bn++)
+ {
+ brush = &mapbrushes[bn];
+ //must be in world entity
+ if (brush->entitynum == 0)
+ {
+ if (brush->contents & CONTENTS_AREAPORTAL)
+ {
+ portalnum--;
+ } //end if
+ } //end if
+ } //end for
+ if (bn < nummapbrushes)
+ {
+ return brush;
+ } //end if
+ else
+ {
+ Log_Print("area portal %d brush not found\n", mapent->areaportalnum);
+ return NULL;
+ } //end else
+} //end of the function GetAreaPortalBrush
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+qboolean WriteMapFileSafe(FILE *fp)
+{
+ char key[1024], value[1024];
+ int i, bn, entitybrushes;
+ epair_t *ep;
+ mapbrush_t *brush;
+ entity_t *mapent;
+ //vec3_t vec_origin = {0, 0, 0};
+
+ //
+ if (fprintf(fp,"//=====================================================\n"
+ "//\n"
+ "// map file created with BSPC "BSPC_VERSION"\n"
+ "//\n"
+ "// BSPC is designed to decompile material in which you own the copyright\n"
+ "// or have obtained permission to decompile from the copyright owner. Unless\n"
+ "// you own the copyright or have permission to decompile from the copyright\n"
+ "// owner, you may be violating copyright law and be subject to payment of\n"
+ "// damages and other remedies. If you are uncertain about your rights, contact\n"
+ "// your legal advisor.\n"
+ "//\n") < 0) return false;
+ if (loadedmaptype == MAPTYPE_SIN)
+ {
+ if (fprintf(fp,
+ "// generic/misc/red is used for unknown textures\n") < 0) return false;
+ } //end if
+ if (fprintf(fp,"//\n"
+ "//=====================================================\n") < 0) return false;
+ //write out all the entities
+ for (i = 0; i < num_entities; i++)
+ {
+ mapent = &entities[i];
+ if (!mapent->epairs)
+ {
+ continue;
+ } //end if
+ if (fprintf(fp, "{\n") < 0) return false;
+ //
+ if (loadedmaptype == MAPTYPE_QUAKE3)
+ {
+ if (!stricmp(ValueForKey(mapent, "classname"), "light"))
+ {
+ SetKeyValue(mapent, "light", "10000");
+ } //end if
+ } //end if
+ //write epairs
+ for (ep = mapent->epairs; ep; ep = ep->next)
+ {
+ strcpy(key, ep->key);
+ StripTrailing (key);
+ strcpy(value, ep->value);
+ StripTrailing(value);
+ //
+ if (loadedmaptype == MAPTYPE_QUAKE2 ||
+ loadedmaptype == MAPTYPE_SIN)
+ {
+ //don't write an origin for BSP models
+ if (mapent->modelnum >= 0 && !strcmp(key, "origin")) continue;
+ } //end if
+ //don't write BSP model numbers
+ if (mapent->modelnum >= 0 && !strcmp(key, "model") && value[0] == '*') continue;
+ //
+ if (fprintf(fp, " \"%s\" \"%s\"\n", key, value) < 0) return false;
+ } //end for
+ //
+ if (ValueForKey(mapent, "origin")) GetVectorForKey(mapent, "origin", mapent->origin);
+ else mapent->origin[0] = mapent->origin[1] = mapent->origin[2] = 0;
+ //if this is an area portal entity
+ if (!strcmp("func_areaportal", ValueForKey(mapent, "classname")))
+ {
+ brush = GetAreaPortalBrush(mapent);
+ if (!brush) return false;
+ if (!WriteMapBrush(fp, brush, mapent->origin)) return false;
+ } //end if
+ else
+ {
+ entitybrushes = false;
+ //write brushes
+ for (bn = 0; bn < nummapbrushes; bn++)
+ {
+ brush = &mapbrushes[bn];
+ //if the brush is part of this entity
+ if (brush->entitynum == i)
+ {
+ //don't write out area portal brushes in the world
+ if (!((brush->contents & CONTENTS_AREAPORTAL) && brush->entitynum == 0))
+ {
+ /*
+ if (!strcmp("func_door_rotating", ValueForKey(mapent, "classname")))
+ {
+ AAS_PositionFuncRotatingBrush(mapent, brush);
+ if (!WriteMapBrush(fp, brush, vec_origin)) return false;
+ } //end if
+ else //*/
+ {
+ if (!WriteMapBrush(fp, brush, mapent->origin)) return false;
+ } //end else
+ entitybrushes = true;
+ } //end if
+ } //end if
+ } //end for
+ //if the entity had brushes
+ if (entitybrushes)
+ {
+ //if the entity has an origin set
+ if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2])
+ {
+ if (!WriteOriginBrush(fp, mapent->origin)) return false;
+ } //end if
+ } //end if
+ } //end else
+ if (fprintf(fp, "}\n") < 0) return false;
+ } //end for
+ if (fprintf(fp, "//total of %d brushes\n", c_writtenbrushes) < 0) return false;
+ return true;
+} //end of the function WriteMapFileSafe
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void WriteMapFile(char *filename)
+{
+ FILE *fp;
+ double start_time;
+
+ c_writtenbrushes = 0;
+ //the time started
+ start_time = I_FloatTime();
+ //
+ Log_Print("writing %s\n", filename);
+ fp = fopen(filename, "wb");
+ if (!fp)
+ {
+ Log_Print("can't open %s\n", filename);
+ return;
+ } //end if
+ if (!WriteMapFileSafe(fp))
+ {
+ fclose(fp);
+ Log_Print("error writing map file %s\n", filename);
+ return;
+ } //end if
+ fclose(fp);
+ //display creation time
+ Log_Print("written %d brushes\n", c_writtenbrushes);
+ Log_Print("map file written in %5.0f seconds\n", I_FloatTime() - start_time);
+} //end of the function WriteMapFile
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void PrintMapInfo(void)
+{
+ Log_Print("\n");
+ Log_Print("%6i brushes\n", nummapbrushes);
+ Log_Print("%6i brush sides\n", nummapbrushsides);
+// Log_Print("%6i clipbrushes\n", c_clipbrushes);
+// Log_Print("%6i total sides\n", nummapbrushsides);
+// Log_Print("%6i boxbevels\n", c_boxbevels);
+// Log_Print("%6i edgebevels\n", c_edgebevels);
+// Log_Print("%6i entities\n", num_entities);
+// Log_Print("%6i planes\n", nummapplanes);
+// Log_Print("%6i areaportals\n", c_areaportals);
+// Log_Print("%6i squatt brushes\n", c_squattbrushes);
+// Log_Print("size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", map_mins[0],map_mins[1],map_mins[2],
+// map_maxs[0],map_maxs[1],map_maxs[2]);
+} //end of the function PrintMapInfo
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void ResetMapLoading(void)
+{
+ int i;
+ epair_t *ep, *nextep;
+
+ Q2_ResetMapLoading();
+ Sin_ResetMapLoading();
+
+ //free all map brush side windings
+ for (i = 0; i < nummapbrushsides; i++)
+ {
+ if (brushsides[i].winding)
+ {
+ FreeWinding(brushsides[i].winding);
+ } //end for
+ } //end for
+
+ //reset regular stuff
+ nummapbrushes = 0;
+ memset(mapbrushes, 0, MAX_MAPFILE_BRUSHES * sizeof(mapbrush_t));
+ //
+ nummapbrushsides = 0;
+ memset(brushsides, 0, MAX_MAPFILE_BRUSHSIDES * sizeof(side_t));
+ memset(side_brushtextures, 0, MAX_MAPFILE_BRUSHSIDES * sizeof(brush_texture_t));
+ //
+ nummapplanes = 0;
+ memset(mapplanes, 0, MAX_MAPFILE_PLANES * sizeof(plane_t));
+ //
+ memset(planehash, 0, PLANE_HASHES * sizeof(plane_t *));
+ //
+ memset(map_texinfo, 0, MAX_MAPFILE_TEXINFO * sizeof(map_texinfo_t));
+ map_numtexinfo = 0;
+ //
+ VectorClear(map_mins);
+ VectorClear(map_maxs);
+ //
+ c_boxbevels = 0;
+ c_edgebevels = 0;
+ c_areaportals = 0;
+ c_clipbrushes = 0;
+ c_writtenbrushes = 0;
+ //clear the entities
+ for (i = 0; i < num_entities; i++)
+ {
+ for (ep = entities[i].epairs; ep; ep = nextep)
+ {
+ nextep = ep->next;
+ FreeMemory(ep->key);
+ FreeMemory(ep->value);
+ FreeMemory(ep);
+ } //end for
+ } //end for
+ num_entities = 0;
+ memset(entities, 0, MAX_MAP_ENTITIES * sizeof(entity_t));
+} //end of the function ResetMapLoading
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+#ifndef Q1_BSPVERSION
+#define Q1_BSPVERSION 29
+#endif
+#ifndef HL_BSPVERSION
+#define HL_BSPVERSION 30
+#endif
+
+#define Q2_BSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I') //IBSP
+#define Q2_BSPVERSION 38
+
+#define SINGAME_BSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'R') //RBSP
+#define SINGAME_BSPVERSION 1
+
+#define SIN_BSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I') //IBSP
+#define SIN_BSPVERSION 41
+
+typedef struct
+{
+ int ident;
+ int version;
+} idheader_t;
+
+int LoadMapFromBSP(struct quakefile_s *qf)
+{
+ idheader_t idheader;
+
+ if (ReadQuakeFile(qf, &idheader, 0, sizeof(idheader_t)) != sizeof(idheader_t))
+ {
+ return false;
+ } //end if
+
+ idheader.ident = LittleLong(idheader.ident);
+ idheader.version = LittleLong(idheader.version);
+ //Quake3 BSP file
+ if (idheader.ident == Q3_BSP_IDENT && idheader.version == Q3_BSP_VERSION)
+ {
+ ResetMapLoading();
+ Q3_LoadMapFromBSP(qf);
+ Q3_FreeMaxBSP();
+ } //end if
+ //Quake2 BSP file
+ else if (idheader.ident == Q2_BSPHEADER && idheader.version == Q2_BSPVERSION)
+ {
+ ResetMapLoading();
+ Q2_AllocMaxBSP();
+ Q2_LoadMapFromBSP(qf->filename, qf->offset, qf->length);
+ Q2_FreeMaxBSP();
+ } //endif
+ //Sin BSP file
+ else if ((idheader.ident == SIN_BSPHEADER && idheader.version == SIN_BSPVERSION) ||
+ //the dorks gave the same format another ident and verions
+ (idheader.ident == SINGAME_BSPHEADER && idheader.version == SINGAME_BSPVERSION))
+ {
+ ResetMapLoading();
+ Sin_AllocMaxBSP();
+ Sin_LoadMapFromBSP(qf->filename, qf->offset, qf->length);
+ Sin_FreeMaxBSP();
+ } //end if
+ //the Quake1 bsp files don't have a ident only a version
+ else if (idheader.ident == Q1_BSPVERSION)
+ {
+ ResetMapLoading();
+ Q1_AllocMaxBSP();
+ Q1_LoadMapFromBSP(qf->filename, qf->offset, qf->length);
+ Q1_FreeMaxBSP();
+ } //end if
+ //Half-Life also only uses a version number
+ else if (idheader.ident == HL_BSPVERSION)
+ {
+ ResetMapLoading();
+ HL_AllocMaxBSP();
+ HL_LoadMapFromBSP(qf->filename, qf->offset, qf->length);
+ HL_FreeMaxBSP();
+ } //end if
+ else
+ {
+ Error("unknown BSP format %c%c%c%c, version %d\n",
+ (idheader.ident & 0xFF),
+ ((idheader.ident >> 8) & 0xFF),
+ ((idheader.ident >> 16) & 0xFF),
+ ((idheader.ident >> 24) & 0xFF), idheader.version);
+ return false;
+ } //end if
+ //
+ return true;
+} //end of the function LoadMapFromBSP
diff --git a/code/bspc/map_hl.c b/code/bspc/map_hl.c
index 7e6037b..88e4fa7 100755
--- a/code/bspc/map_hl.c
+++ b/code/bspc/map_hl.c
@@ -1,1114 +1,1114 @@
-/*
-===========================================================================
-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 "l_bsp_hl.h"
-#include "aas_map.h" //AAS_CreateMapBrushes
-
-int hl_numbrushes;
-int hl_numclipbrushes;
-
-//#define HL_PRINT
-#define HLCONTENTS
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int HL_TextureContents(char *name)
-{
- if (!Q_strncasecmp (name, "sky",3))
- return CONTENTS_SOLID;
-
- if (!Q_strncasecmp(name+1,"!lava",5))
- return CONTENTS_LAVA;
-
- if (!Q_strncasecmp(name+1,"!slime",6))
- return CONTENTS_SLIME;
-
- /*
- if (!Q_strncasecmp (name, "!cur_90",7))
- return CONTENTS_CURRENT_90;
- if (!Q_strncasecmp (name, "!cur_0",6))
- return CONTENTS_CURRENT_0;
- if (!Q_strncasecmp (name, "!cur_270",8))
- return CONTENTS_CURRENT_270;
- if (!Q_strncasecmp (name, "!cur_180",8))
- return CONTENTS_CURRENT_180;
- if (!Q_strncasecmp (name, "!cur_up",7))
- return CONTENTS_CURRENT_UP;
- if (!Q_strncasecmp (name, "!cur_dwn",8))
- return CONTENTS_CURRENT_DOWN;
- //*/
- if (name[0] == '!')
- return CONTENTS_WATER;
- /*
- if (!Q_strncasecmp (name, "origin",6))
- return CONTENTS_ORIGIN;
- if (!Q_strncasecmp (name, "clip",4))
- return CONTENTS_CLIP;
- if( !Q_strncasecmp( name, "translucent", 11 ) )
- return CONTENTS_TRANSLUCENT;
- if( name[0] == '@' )
- return CONTENTS_TRANSLUCENT;
- //*/
-
- return CONTENTS_SOLID;
-} //end of the function HL_TextureContents
-//===========================================================================
-// Generates two new brushes, leaving the original
-// unchanged
-//
-// modified for Half-Life because there are quite a lot of tiny node leaves
-// in the Half-Life bsps
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void HL_SplitBrush(bspbrush_t *brush, int planenum, int nodenum,
- bspbrush_t **front, bspbrush_t **back)
-{
- bspbrush_t *b[2];
- int i, j;
- winding_t *w, *cw[2], *midwinding;
- plane_t *plane, *plane2;
- side_t *s, *cs;
- float d, d_front, d_back;
-
- *front = *back = NULL;
- plane = &mapplanes[planenum];
-
- // check all points
- d_front = d_back = 0;
- for (i=0 ; i<brush->numsides ; i++)
- {
- w = brush->sides[i].winding;
- if (!w)
- continue;
- for (j=0 ; j<w->numpoints ; j++)
- {
- d = DotProduct (w->p[j], plane->normal) - plane->dist;
- if (d > 0 && d > d_front)
- d_front = d;
- if (d < 0 && d < d_back)
- d_back = d;
- } //end for
- } //end for
-
- if (d_front < 0.1) // PLANESIDE_EPSILON)
- { // only on back
- *back = CopyBrush (brush);
- Log_Print("HL_SplitBrush: only on back\n");
- return;
- } //end if
- if (d_back > -0.1) // PLANESIDE_EPSILON)
- { // only on front
- *front = CopyBrush (brush);
- Log_Print("HL_SplitBrush: only on front\n");
- return;
- } //end if
-
- // create a new winding from the split plane
-
- w = BaseWindingForPlane (plane->normal, plane->dist);
- for (i = 0; i < brush->numsides && w; i++)
- {
- plane2 = &mapplanes[brush->sides[i].planenum ^ 1];
- ChopWindingInPlace(&w, plane2->normal, plane2->dist, 0); // PLANESIDE_EPSILON);
- } //end for
-
- if (!w || WindingIsTiny(w))
- { // the brush isn't really split
- int side;
-
- Log_Print("HL_SplitBrush: no split winding\n");
- side = BrushMostlyOnSide (brush, plane);
- if (side == PSIDE_FRONT)
- *front = CopyBrush (brush);
- if (side == PSIDE_BACK)
- *back = CopyBrush (brush);
- return;
- }
-
- if (WindingIsHuge(w))
- {
- Log_Print("HL_SplitBrush: WARNING huge split winding\n");
- } //end of
-
- midwinding = w;
-
- // split it for real
-
- for (i = 0; i < 2; i++)
- {
- b[i] = AllocBrush (brush->numsides+1);
- b[i]->original = brush->original;
- } //end for
-
- // split all the current windings
-
- for (i=0 ; i<brush->numsides ; i++)
- {
- s = &brush->sides[i];
- w = s->winding;
- if (!w)
- continue;
- ClipWindingEpsilon (w, plane->normal, plane->dist,
- 0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]);
- for (j=0 ; j<2 ; j++)
- {
- if (!cw[j])
- continue;
-#if 0
- if (WindingIsTiny (cw[j]))
- {
- FreeWinding (cw[j]);
- continue;
- }
-#endif
- cs = &b[j]->sides[b[j]->numsides];
- b[j]->numsides++;
- *cs = *s;
-// cs->planenum = s->planenum;
-// cs->texinfo = s->texinfo;
-// cs->visible = s->visible;
-// cs->original = s->original;
- cs->winding = cw[j];
- cs->flags &= ~SFL_TESTED;
- } //end for
- } //end for
-
-
- // see if we have valid polygons on both sides
-
- for (i=0 ; i<2 ; i++)
- {
- BoundBrush (b[i]);
- for (j=0 ; j<3 ; j++)
- {
- if (b[i]->mins[j] < -4096 || b[i]->maxs[j] > 4096)
- {
- Log_Print("HL_SplitBrush: bogus brush after clip\n");
- break;
- } //end if
- } //end for
-
- if (b[i]->numsides < 3 || j < 3)
- {
- FreeBrush (b[i]);
- b[i] = NULL;
- Log_Print("HL_SplitBrush: numsides < 3\n");
- } //end if
- } //end for
-
- if ( !(b[0] && b[1]) )
- {
- if (!b[0] && !b[1])
- Log_Print("HL_SplitBrush: split removed brush\n");
- else
- Log_Print("HL_SplitBrush: split not on both sides\n");
- if (b[0])
- {
- FreeBrush (b[0]);
- *front = CopyBrush (brush);
- } //end if
- if (b[1])
- {
- FreeBrush (b[1]);
- *back = CopyBrush (brush);
- } //end if
- return;
- } //end if
-
- // add the midwinding to both sides
- for (i = 0; i < 2; i++)
- {
- cs = &b[i]->sides[b[i]->numsides];
- b[i]->numsides++;
-
- cs->planenum = planenum^i^1;
- cs->texinfo = 0;
- //store the node number in the surf to find the texinfo later on
- cs->surf = nodenum;
- //
- cs->flags &= ~SFL_VISIBLE;
- cs->flags &= ~SFL_TESTED;
- if (i==0)
- cs->winding = CopyWinding (midwinding);
- else
- cs->winding = midwinding;
- } //end for
-
-
-{
- vec_t v1;
- int i;
-
- for (i=0 ; i<2 ; i++)
- {
- v1 = BrushVolume (b[i]);
- if (v1 < 1)
- {
- FreeBrush (b[i]);
- b[i] = NULL;
- Log_Print("HL_SplitBrush: tiny volume after clip\n");
- } //end if
- } //end for
-} //*/
-
- *front = b[0];
- *back = b[1];
-} //end of the function HL_SplitBrush
-//===========================================================================
-// returns true if the tree starting at nodenum has only solid leaves
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int HL_SolidTree_r(int nodenum)
-{
- if (nodenum < 0)
- {
- switch(hl_dleafs[(-nodenum) - 1].contents)
- {
- case HL_CONTENTS_EMPTY:
- {
- return false;
- } //end case
- case HL_CONTENTS_SOLID:
-#ifdef HLCONTENTS
- case HL_CONTENTS_CLIP:
-#endif //HLCONTENTS
- case HL_CONTENTS_SKY:
-#ifdef HLCONTENTS
- case HL_CONTENTS_TRANSLUCENT:
-#endif //HLCONTENTS
- {
- return true;
- } //end case
- case HL_CONTENTS_WATER:
- case HL_CONTENTS_SLIME:
- case HL_CONTENTS_LAVA:
-#ifdef HLCONTENTS
- //these contents should not be found in the BSP
- case HL_CONTENTS_ORIGIN:
- case HL_CONTENTS_CURRENT_0:
- case HL_CONTENTS_CURRENT_90:
- case HL_CONTENTS_CURRENT_180:
- case HL_CONTENTS_CURRENT_270:
- case HL_CONTENTS_CURRENT_UP:
- case HL_CONTENTS_CURRENT_DOWN:
-#endif //HLCONTENTS
- default:
- {
- return false;
- } //end default
- } //end switch
- return false;
- } //end if
- if (!HL_SolidTree_r(hl_dnodes[nodenum].children[0])) return false;
- if (!HL_SolidTree_r(hl_dnodes[nodenum].children[1])) return false;
- return true;
-} //end of the function HL_SolidTree_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *HL_CreateBrushes_r(bspbrush_t *brush, int nodenum)
-{
- int planenum;
- bspbrush_t *front, *back;
- hl_dleaf_t *leaf;
-
- //if it is a leaf
- if (nodenum < 0)
- {
- leaf = &hl_dleafs[(-nodenum) - 1];
- if (leaf->contents != HL_CONTENTS_EMPTY)
- {
-#ifdef HL_PRINT
- qprintf("\r%5i", ++hl_numbrushes);
-#endif //HL_PRINT
- } //end if
- switch(leaf->contents)
- {
- case HL_CONTENTS_EMPTY:
- {
- FreeBrush(brush);
- return NULL;
- } //end case
- case HL_CONTENTS_SOLID:
-#ifdef HLCONTENTS
- case HL_CONTENTS_CLIP:
-#endif //HLCONTENTS
- case HL_CONTENTS_SKY:
-#ifdef HLCONTENTS
- case HL_CONTENTS_TRANSLUCENT:
-#endif //HLCONTENTS
- {
- brush->side = CONTENTS_SOLID;
- return brush;
- } //end case
- case HL_CONTENTS_WATER:
- {
- brush->side = CONTENTS_WATER;
- return brush;
- } //end case
- case HL_CONTENTS_SLIME:
- {
- brush->side = CONTENTS_SLIME;
- return brush;
- } //end case
- case HL_CONTENTS_LAVA:
- {
- brush->side = CONTENTS_LAVA;
- return brush;
- } //end case
-#ifdef HLCONTENTS
- //these contents should not be found in the BSP
- case HL_CONTENTS_ORIGIN:
- case HL_CONTENTS_CURRENT_0:
- case HL_CONTENTS_CURRENT_90:
- case HL_CONTENTS_CURRENT_180:
- case HL_CONTENTS_CURRENT_270:
- case HL_CONTENTS_CURRENT_UP:
- case HL_CONTENTS_CURRENT_DOWN:
- {
- Error("HL_CreateBrushes_r: found contents %d in Half-Life BSP", leaf->contents);
- return NULL;
- } //end case
-#endif //HLCONTENTS
- default:
- {
- Error("HL_CreateBrushes_r: unknown contents %d in Half-Life BSP", leaf->contents);
- return NULL;
- } //end default
- } //end switch
- return NULL;
- } //end if
- //if the rest of the tree is solid
- /*if (HL_SolidTree_r(nodenum))
- {
- brush->side = CONTENTS_SOLID;
- return brush;
- } //end if*/
- //
- planenum = hl_dnodes[nodenum].planenum;
- planenum = FindFloatPlane(hl_dplanes[planenum].normal, hl_dplanes[planenum].dist);
- //split the brush with the node plane
- HL_SplitBrush(brush, planenum, nodenum, &front, &back);
- //free the original brush
- FreeBrush(brush);
- //every node must split the brush in two
- if (!front || !back)
- {
- Log_Print("HL_CreateBrushes_r: WARNING node not splitting brush\n");
- //return NULL;
- } //end if
- //create brushes recursively
- if (front) front = HL_CreateBrushes_r(front, hl_dnodes[nodenum].children[0]);
- if (back) back = HL_CreateBrushes_r(back, hl_dnodes[nodenum].children[1]);
- //link the brushes if possible and return them
- if (front)
- {
- for (brush = front; brush->next; brush = brush->next);
- brush->next = back;
- return front;
- } //end if
- else
- {
- return back;
- } //end else
-} //end of the function HL_CreateBrushes_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *HL_CreateBrushesFromBSP(int modelnum)
-{
- bspbrush_t *brushlist;
- bspbrush_t *brush;
- hl_dnode_t *headnode;
- vec3_t mins, maxs;
- int i;
-
- //
- headnode = &hl_dnodes[hl_dmodels[modelnum].headnode[0]];
- //get the mins and maxs of the world
- VectorCopy(headnode->mins, mins);
- VectorCopy(headnode->maxs, maxs);
- //enlarge these mins and maxs
- for (i = 0; i < 3; i++)
- {
- mins[i] -= 8;
- maxs[i] += 8;
- } //end for
- //NOTE: have to add the BSP tree mins and maxs to the MAP mins and maxs
- AddPointToBounds(mins, map_mins, map_maxs);
- AddPointToBounds(maxs, map_mins, map_maxs);
- //
- if (!modelnum)
- {
- Log_Print("brush size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n",
- map_mins[0], map_mins[1], map_mins[2],
- map_maxs[0], map_maxs[1], map_maxs[2]);
- } //end if
- //create one huge brush containing the whole world
- brush = BrushFromBounds(mins, maxs);
- VectorCopy(mins, brush->mins);
- VectorCopy(maxs, brush->maxs);
- //
-#ifdef HL_PRINT
- qprintf("creating Half-Life brushes\n");
- qprintf("%5d brushes", hl_numbrushes = 0);
-#endif //HL_PRINT
- //create the brushes
- brushlist = HL_CreateBrushes_r(brush, hl_dmodels[modelnum].headnode[0]);
- //
-#ifdef HL_PRINT
- qprintf("\n");
-#endif //HL_PRINT
- //now we've got a list with brushes!
- return brushlist;
-} //end of the function HL_CreateBrushesFromBSP
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *HL_MergeBrushes(bspbrush_t *brushlist, int modelnum)
-{
- int nummerges, merged;
- bspbrush_t *b1, *b2, *tail, *newbrush, *newbrushlist;
- bspbrush_t *lastb2;
-
- if (!brushlist) return NULL;
-
- if (!modelnum) qprintf("%5d brushes merged", nummerges = 0);
- do
- {
- for (tail = brushlist; tail; tail = tail->next)
- {
- if (!tail->next) break;
- } //end for
- merged = 0;
- newbrushlist = NULL;
- for (b1 = brushlist; b1; b1 = brushlist)
- {
- lastb2 = b1;
- for (b2 = b1->next; b2; b2 = b2->next)
- {
- //can't merge brushes with different contents
- if (b1->side != b2->side) newbrush = NULL;
- else newbrush = TryMergeBrushes(b1, b2);
- //if a merged brush is created
- if (newbrush)
- {
- //copy the brush contents
- newbrush->side = b1->side;
- //add the new brush to the end of the list
- tail->next = newbrush;
- //remove the second brush from the list
- lastb2->next = b2->next;
- //remove the first brush from the list
- brushlist = brushlist->next;
- //free the merged brushes
- FreeBrush(b1);
- FreeBrush(b2);
- //get a new tail brush
- for (tail = brushlist; tail; tail = tail->next)
- {
- if (!tail->next) break;
- } //end for
- merged++;
- if (!modelnum) qprintf("\r%5d", nummerges++);
- break;
- } //end if
- lastb2 = b2;
- } //end for
- //if b1 can't be merged with any of the other brushes
- if (!b2)
- {
- brushlist = brushlist->next;
- //keep b1
- b1->next = newbrushlist;
- newbrushlist = b1;
- } //end else
- } //end for
- brushlist = newbrushlist;
- } while(merged);
- if (!modelnum) qprintf("\n");
- return newbrushlist;
-} //end of the function HL_MergeBrushes
-//===========================================================================
-// returns the amount the face and the winding have overlap
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float HL_FaceOnWinding(hl_dface_t *face, winding_t *winding)
-{
- int i, edgenum, side;
- float dist, area;
- hl_dplane_t plane;
- vec_t *v1, *v2;
- vec3_t normal, edgevec;
- winding_t *w;
-
- //
- w = CopyWinding(winding);
- memcpy(&plane, &hl_dplanes[face->planenum], sizeof(hl_dplane_t));
- //check on which side of the plane the face is
- if (face->side)
- {
- VectorNegate(plane.normal, plane.normal);
- plane.dist = -plane.dist;
- } //end if
- for (i = 0; i < face->numedges && w; i++)
- {
- //get the first and second vertex of the edge
- edgenum = hl_dsurfedges[face->firstedge + i];
- side = edgenum > 0;
- //if the face plane is flipped
- v1 = hl_dvertexes[hl_dedges[abs(edgenum)].v[side]].point;
- v2 = hl_dvertexes[hl_dedges[abs(edgenum)].v[!side]].point;
- //create a plane through the edge vector, orthogonal to the face plane
- //and with the normal vector pointing out of the face
- VectorSubtract(v1, v2, edgevec);
- CrossProduct(edgevec, plane.normal, normal);
- VectorNormalize(normal);
- dist = DotProduct(normal, v1);
- //
- ChopWindingInPlace(&w, normal, dist, 0.9); //CLIP_EPSILON
- } //end for
- if (w)
- {
- area = WindingArea(w);
- FreeWinding(w);
- return area;
- } //end if
- return 0;
-} //end of the function HL_FaceOnWinding
-//===========================================================================
-// returns a list with brushes created by splitting the given brush with
-// planes that go through the face edges and are orthogonal to the face plane
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *HL_SplitBrushWithFace(bspbrush_t *brush, hl_dface_t *face)
-{
- int i, edgenum, side, planenum, splits;
- float dist;
- hl_dplane_t plane;
- vec_t *v1, *v2;
- vec3_t normal, edgevec;
- bspbrush_t *front, *back, *brushlist;
-
- memcpy(&plane, &hl_dplanes[face->planenum], sizeof(hl_dplane_t));
- //check on which side of the plane the face is
- if (face->side)
- {
- VectorNegate(plane.normal, plane.normal);
- plane.dist = -plane.dist;
- } //end if
- splits = 0;
- brushlist = NULL;
- for (i = 0; i < face->numedges; i++)
- {
- //get the first and second vertex of the edge
- edgenum = hl_dsurfedges[face->firstedge + i];
- side = edgenum > 0;
- //if the face plane is flipped
- v1 = hl_dvertexes[hl_dedges[abs(edgenum)].v[side]].point;
- v2 = hl_dvertexes[hl_dedges[abs(edgenum)].v[!side]].point;
- //create a plane through the edge vector, orthogonal to the face plane
- //and with the normal vector pointing out of the face
- VectorSubtract(v1, v2, edgevec);
- CrossProduct(edgevec, plane.normal, normal);
- VectorNormalize(normal);
- dist = DotProduct(normal, v1);
- //
- planenum = FindFloatPlane(normal, dist);
- //split the current brush
- SplitBrush(brush, planenum, &front, &back);
- //if there is a back brush just put it in the list
- if (back)
- {
- //copy the brush contents
- back->side = brush->side;
- //
- back->next = brushlist;
- brushlist = back;
- splits++;
- } //end if
- if (!front)
- {
- Log_Print("HL_SplitBrushWithFace: no new brush\n");
- FreeBrushList(brushlist);
- return NULL;
- } //end if
- //copy the brush contents
- front->side = brush->side;
- //continue splitting the front brush
- brush = front;
- } //end for
- if (!splits)
- {
- FreeBrush(front);
- return NULL;
- } //end if
- front->next = brushlist;
- brushlist = front;
- return brushlist;
-} //end of the function HL_SplitBrushWithFace
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *HL_TextureBrushes(bspbrush_t *brushlist, int modelnum)
-{
- float area, largestarea;
- int i, n, texinfonum, sn, numbrushes, ofs;
- int bestfacenum, sidenodenum;
- side_t *side;
- hl_dmiptexlump_t *miptexlump;
- hl_miptex_t *miptex;
- bspbrush_t *brush, *nextbrush, *prevbrush, *newbrushes, *brushlistend;
- vec_t defaultvec[4] = {1, 0, 0, 0};
-
- if (!modelnum) qprintf("texturing brushes\n");
- if (!modelnum) qprintf("%5d brushes", numbrushes = 0);
- //get a pointer to the last brush in the list
- for (brushlistend = brushlist; brushlistend; brushlistend = brushlistend->next)
- {
- if (!brushlistend->next) break;
- } //end for
- //there's no previous brush when at the start of the list
- prevbrush = NULL;
- //go over the brush list
- for (brush = brushlist; brush; brush = nextbrush)
- {
- nextbrush = brush->next;
- //find a texinfo for every brush side
- for (sn = 0; sn < brush->numsides; sn++)
- {
- side = &brush->sides[sn];
- //
- if (side->flags & SFL_TEXTURED) continue;
- //number of the node that created this brush side
- sidenodenum = side->surf; //see midwinding in HL_SplitBrush
- //no face found yet
- bestfacenum = -1;
- //minimum face size
- largestarea = 1;
- //if optimizing the texture placement and not going for the
- //least number of brushes
- if (!lessbrushes)
- {
- for (i = 0; i < hl_numfaces; i++)
- {
- //the face must be in the same plane as the node plane that created
- //this brush side
- if (hl_dfaces[i].planenum == hl_dnodes[sidenodenum].planenum)
- {
- //get the area the face and the brush side overlap
- area = HL_FaceOnWinding(&hl_dfaces[i], side->winding);
- //if this face overlaps the brush side winding more than previous faces
- if (area > largestarea)
- {
- //if there already was a face for texturing this brush side with
- //a different texture
- if (bestfacenum >= 0 &&
- (hl_dfaces[bestfacenum].texinfo != hl_dfaces[i].texinfo))
- {
- //split the brush to fit the texture
- newbrushes = HL_SplitBrushWithFace(brush, &hl_dfaces[i]);
- //if new brushes where created
- if (newbrushes)
- {
- //remove the current brush from the list
- if (prevbrush) prevbrush->next = brush->next;
- else brushlist = brush->next;
- if (brushlistend == brush)
- {
- brushlistend = prevbrush;
- nextbrush = newbrushes;
- } //end if
- //add the new brushes to the end of the list
- if (brushlistend) brushlistend->next = newbrushes;
- else brushlist = newbrushes;
- //free the current brush
- FreeBrush(brush);
- //don't forget about the prevbrush pointer at the bottom of
- //the outer loop
- brush = prevbrush;
- //find the end of the list
- for (brushlistend = brushlist; brushlistend; brushlistend = brushlistend->next)
- {
- if (!brushlistend->next) break;
- } //end for
- break;
- } //end if
- else
- {
- Log_Write("brush %d: no real texture split", numbrushes);
- } //end else
- } //end if
- else
- {
- //best face for texturing this brush side
- bestfacenum = i;
- } //end else
- } //end if
- } //end if
- } //end for
- //if the brush was split the original brush is removed
- //and we just continue with the next one in the list
- if (i < hl_numfaces) break;
- } //end if
- else
- {
- //find the face with the largest overlap with this brush side
- //for texturing the brush side
- for (i = 0; i < hl_numfaces; i++)
- {
- //the face must be in the same plane as the node plane that created
- //this brush side
- if (hl_dfaces[i].planenum == hl_dnodes[sidenodenum].planenum)
- {
- //get the area the face and the brush side overlap
- area = HL_FaceOnWinding(&hl_dfaces[i], side->winding);
- //if this face overlaps the brush side winding more than previous faces
- if (area > largestarea)
- {
- largestarea = area;
- bestfacenum = i;
- } //end if
- } //end if
- } //end for
- } //end else
- //if a face was found for texturing this brush side
- if (bestfacenum >= 0)
- {
- //set the MAP texinfo values
- texinfonum = hl_dfaces[bestfacenum].texinfo;
- for (n = 0; n < 4; n++)
- {
- map_texinfo[texinfonum].vecs[0][n] = hl_texinfo[texinfonum].vecs[0][n];
- map_texinfo[texinfonum].vecs[1][n] = hl_texinfo[texinfonum].vecs[1][n];
- } //end for
- //make sure the two vectors aren't of zero length otherwise use the default
- //vector to prevent a divide by zero in the map writing
- if (VectorLength(map_texinfo[texinfonum].vecs[0]) < 0.01)
- memcpy(map_texinfo[texinfonum].vecs[0], defaultvec, sizeof(defaultvec));
- if (VectorLength(map_texinfo[texinfonum].vecs[1]) < 0.01)
- memcpy(map_texinfo[texinfonum].vecs[1], defaultvec, sizeof(defaultvec));
- //
- map_texinfo[texinfonum].flags = hl_texinfo[texinfonum].flags;
- map_texinfo[texinfonum].value = 0; //HL_ and HL texinfos don't have a value
- //the mip texture
- miptexlump = (hl_dmiptexlump_t *) hl_dtexdata;
- ofs = miptexlump->dataofs[hl_texinfo[texinfonum].miptex];
- if ( ofs > hl_texdatasize ) {
- ofs = miptexlump->dataofs[0];
- }
- miptex = (hl_miptex_t *)((byte *)miptexlump + ofs );
- //get the mip texture name
- strcpy(map_texinfo[texinfonum].texture, miptex->name);
- //no animations in Quake1 and Half-Life mip textures
- map_texinfo[texinfonum].nexttexinfo = -1;
- //store the texinfo number
- side->texinfo = texinfonum;
- //
- if (texinfonum > map_numtexinfo) map_numtexinfo = texinfonum;
- //this side is textured
- side->flags |= SFL_TEXTURED;
- } //end if
- else
- {
- //no texture for this side
- side->texinfo = TEXINFO_NODE;
- //this side is textured
- side->flags |= SFL_TEXTURED;
- } //end if
- } //end for
- //
- if (!modelnum && prevbrush != brush) qprintf("\r%5d", ++numbrushes);
- //previous brush in the list
- prevbrush = brush;
- } //end for
- if (!modelnum) qprintf("\n");
- //return the new list with brushes
- return brushlist;
-} //end of the function HL_TextureBrushes
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void HL_FixContentsTextures(bspbrush_t *brushlist)
-{
- int i, texinfonum;
- bspbrush_t *brush;
-
- for (brush = brushlist; brush; brush = brush->next)
- {
- //only fix the textures of water, slime and lava brushes
- if (brush->side != CONTENTS_WATER &&
- brush->side != CONTENTS_SLIME &&
- brush->side != CONTENTS_LAVA) continue;
- //
- for (i = 0; i < brush->numsides; i++)
- {
- texinfonum = brush->sides[i].texinfo;
- if (HL_TextureContents(map_texinfo[texinfonum].texture) == brush->side) break;
- } //end for
- //if no specific contents texture was found
- if (i >= brush->numsides)
- {
- texinfonum = -1;
- for (i = 0; i < map_numtexinfo; i++)
- {
- if (HL_TextureContents(map_texinfo[i].texture) == brush->side)
- {
- texinfonum = i;
- break;
- } //end if
- } //end for
- } //end if
- //
- if (texinfonum >= 0)
- {
- //give all the brush sides this contents texture
- for (i = 0; i < brush->numsides; i++)
- {
- brush->sides[i].texinfo = texinfonum;
- } //end for
- } //end if
- else Log_Print("brush contents %d with wrong textures\n", brush->side);
- //
- } //end for
- /*
- for (brush = brushlist; brush; brush = brush->next)
- {
- //give all the brush sides this contents texture
- for (i = 0; i < brush->numsides; i++)
- {
- if (HL_TextureContents(map_texinfo[texinfonum].texture) != brush->side)
- {
- Error("brush contents %d with wrong contents textures %s\n", brush->side,
- HL_TextureContents(map_texinfo[texinfonum].texture));
- } //end if
- } //end for
- } //end for*/
-} //end of the function HL_FixContentsTextures
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void HL_BSPBrushToMapBrush(bspbrush_t *bspbrush, entity_t *mapent)
-{
- mapbrush_t *mapbrush;
- side_t *side;
- int i, besttexinfo;
-
- if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
- Error ("nummapbrushes == MAX_MAPFILE_BRUSHES");
-
- mapbrush = &mapbrushes[nummapbrushes];
- mapbrush->original_sides = &brushsides[nummapbrushsides];
- mapbrush->entitynum = mapent - entities;
- mapbrush->brushnum = nummapbrushes - mapent->firstbrush;
- mapbrush->leafnum = -1;
- mapbrush->numsides = 0;
-
- besttexinfo = TEXINFO_NODE;
- for (i = 0; i < bspbrush->numsides; i++)
- {
- if (!bspbrush->sides[i].winding) continue;
- //
- if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
- Error ("MAX_MAPFILE_BRUSHSIDES");
- side = &brushsides[nummapbrushsides];
- //the contents of the bsp brush is stored in the side variable
- side->contents = bspbrush->side;
- side->surf = 0;
- side->planenum = bspbrush->sides[i].planenum;
- side->texinfo = bspbrush->sides[i].texinfo;
- if (side->texinfo != TEXINFO_NODE)
- {
- //this brush side is textured
- side->flags |= SFL_TEXTURED;
- besttexinfo = side->texinfo;
- } //end if
- //
- nummapbrushsides++;
- mapbrush->numsides++;
- } //end for
- //
- if (besttexinfo == TEXINFO_NODE)
- {
- mapbrush->numsides = 0;
- hl_numclipbrushes++;
- return;
- } //end if
- //set the texinfo for all the brush sides without texture
- for (i = 0; i < mapbrush->numsides; i++)
- {
- if (mapbrush->original_sides[i].texinfo == TEXINFO_NODE)
- {
- mapbrush->original_sides[i].texinfo = besttexinfo;
- } //end if
- } //end for
- //contents of the brush
- mapbrush->contents = bspbrush->side;
- //
- if (create_aas)
- {
- //create the AAS brushes from this brush, add brush bevels
- AAS_CreateMapBrushes(mapbrush, mapent, true);
- return;
- } //end if
- //create windings for sides and bounds for brush
- MakeBrushWindings(mapbrush);
- //add brush bevels
- AddBrushBevels(mapbrush);
- //a new brush has been created
- nummapbrushes++;
- mapent->numbrushes++;
-} //end of the function HL_BSPBrushToMapBrush
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void HL_CreateMapBrushes(entity_t *mapent, int modelnum)
-{
- bspbrush_t *brushlist, *brush, *nextbrush;
- int i;
-
- //create brushes from the model BSP tree
- brushlist = HL_CreateBrushesFromBSP(modelnum);
- //texture the brushes and split them when necesary
- brushlist = HL_TextureBrushes(brushlist, modelnum);
- //fix the contents textures of all brushes
- HL_FixContentsTextures(brushlist);
- //
- if (!nobrushmerge)
- {
- brushlist = HL_MergeBrushes(brushlist, modelnum);
- //brushlist = HL_MergeBrushes(brushlist, modelnum);
- } //end if
- //
- if (!modelnum) qprintf("converting brushes to map brushes\n");
- if (!modelnum) qprintf("%5d brushes", i = 0);
- for (brush = brushlist; brush; brush = nextbrush)
- {
- nextbrush = brush->next;
- HL_BSPBrushToMapBrush(brush, mapent);
- brush->next = NULL;
- FreeBrush(brush);
- if (!modelnum) qprintf("\r%5d", ++i);
- } //end for
- if (!modelnum) qprintf("\n");
-} //end of the function HL_CreateMapBrushes
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void HL_ResetMapLoading(void)
-{
-} //end of the function HL_ResetMapLoading
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void HL_LoadMapFromBSP(char *filename, int offset, int length)
-{
- int i, modelnum;
- char *model, *classname;
-
- Log_Print("-- HL_LoadMapFromBSP --\n");
- //loaded map type
- loadedmaptype = MAPTYPE_HALFLIFE;
- //
- qprintf("loading map from %s at %d\n", filename, offset);
- //load the Half-Life BSP file
- HL_LoadBSPFile(filename, offset, length);
- //
- hl_numclipbrushes = 0;
- //parse the entities from the BSP
- HL_ParseEntities();
- //clear the map mins and maxs
- ClearBounds(map_mins, map_maxs);
- //
- qprintf("creating Half-Life brushes\n");
- if (lessbrushes) qprintf("creating minimum number of brushes\n");
- else qprintf("placing textures correctly\n");
- //
- for (i = 0; i < num_entities; i++)
- {
- entities[i].firstbrush = nummapbrushes;
- entities[i].numbrushes = 0;
- //
- classname = ValueForKey(&entities[i], "classname");
- if (classname && !strcmp(classname, "worldspawn"))
- {
- modelnum = 0;
- } //end if
- else
- {
- //
- model = ValueForKey(&entities[i], "model");
- if (!model || *model != '*') continue;
- model++;
- modelnum = atoi(model);
- } //end else
- //create map brushes for the entity
- HL_CreateMapBrushes(&entities[i], modelnum);
- } //end for
- //
- qprintf("%5d map brushes\n", nummapbrushes);
- qprintf("%5d clip brushes\n", hl_numclipbrushes);
-} //end of the function HL_LoadMapFromBSP
+/*
+===========================================================================
+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 "l_bsp_hl.h"
+#include "aas_map.h" //AAS_CreateMapBrushes
+
+int hl_numbrushes;
+int hl_numclipbrushes;
+
+//#define HL_PRINT
+#define HLCONTENTS
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int HL_TextureContents(char *name)
+{
+ if (!Q_strncasecmp (name, "sky",3))
+ return CONTENTS_SOLID;
+
+ if (!Q_strncasecmp(name+1,"!lava",5))
+ return CONTENTS_LAVA;
+
+ if (!Q_strncasecmp(name+1,"!slime",6))
+ return CONTENTS_SLIME;
+
+ /*
+ if (!Q_strncasecmp (name, "!cur_90",7))
+ return CONTENTS_CURRENT_90;
+ if (!Q_strncasecmp (name, "!cur_0",6))
+ return CONTENTS_CURRENT_0;
+ if (!Q_strncasecmp (name, "!cur_270",8))
+ return CONTENTS_CURRENT_270;
+ if (!Q_strncasecmp (name, "!cur_180",8))
+ return CONTENTS_CURRENT_180;
+ if (!Q_strncasecmp (name, "!cur_up",7))
+ return CONTENTS_CURRENT_UP;
+ if (!Q_strncasecmp (name, "!cur_dwn",8))
+ return CONTENTS_CURRENT_DOWN;
+ //*/
+ if (name[0] == '!')
+ return CONTENTS_WATER;
+ /*
+ if (!Q_strncasecmp (name, "origin",6))
+ return CONTENTS_ORIGIN;
+ if (!Q_strncasecmp (name, "clip",4))
+ return CONTENTS_CLIP;
+ if( !Q_strncasecmp( name, "translucent", 11 ) )
+ return CONTENTS_TRANSLUCENT;
+ if( name[0] == '@' )
+ return CONTENTS_TRANSLUCENT;
+ //*/
+
+ return CONTENTS_SOLID;
+} //end of the function HL_TextureContents
+//===========================================================================
+// Generates two new brushes, leaving the original
+// unchanged
+//
+// modified for Half-Life because there are quite a lot of tiny node leaves
+// in the Half-Life bsps
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void HL_SplitBrush(bspbrush_t *brush, int planenum, int nodenum,
+ bspbrush_t **front, bspbrush_t **back)
+{
+ bspbrush_t *b[2];
+ int i, j;
+ winding_t *w, *cw[2], *midwinding;
+ plane_t *plane, *plane2;
+ side_t *s, *cs;
+ float d, d_front, d_back;
+
+ *front = *back = NULL;
+ plane = &mapplanes[planenum];
+
+ // check all points
+ d_front = d_back = 0;
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ w = brush->sides[i].winding;
+ if (!w)
+ continue;
+ for (j=0 ; j<w->numpoints ; j++)
+ {
+ d = DotProduct (w->p[j], plane->normal) - plane->dist;
+ if (d > 0 && d > d_front)
+ d_front = d;
+ if (d < 0 && d < d_back)
+ d_back = d;
+ } //end for
+ } //end for
+
+ if (d_front < 0.1) // PLANESIDE_EPSILON)
+ { // only on back
+ *back = CopyBrush (brush);
+ Log_Print("HL_SplitBrush: only on back\n");
+ return;
+ } //end if
+ if (d_back > -0.1) // PLANESIDE_EPSILON)
+ { // only on front
+ *front = CopyBrush (brush);
+ Log_Print("HL_SplitBrush: only on front\n");
+ return;
+ } //end if
+
+ // create a new winding from the split plane
+
+ w = BaseWindingForPlane (plane->normal, plane->dist);
+ for (i = 0; i < brush->numsides && w; i++)
+ {
+ plane2 = &mapplanes[brush->sides[i].planenum ^ 1];
+ ChopWindingInPlace(&w, plane2->normal, plane2->dist, 0); // PLANESIDE_EPSILON);
+ } //end for
+
+ if (!w || WindingIsTiny(w))
+ { // the brush isn't really split
+ int side;
+
+ Log_Print("HL_SplitBrush: no split winding\n");
+ side = BrushMostlyOnSide (brush, plane);
+ if (side == PSIDE_FRONT)
+ *front = CopyBrush (brush);
+ if (side == PSIDE_BACK)
+ *back = CopyBrush (brush);
+ return;
+ }
+
+ if (WindingIsHuge(w))
+ {
+ Log_Print("HL_SplitBrush: WARNING huge split winding\n");
+ } //end of
+
+ midwinding = w;
+
+ // split it for real
+
+ for (i = 0; i < 2; i++)
+ {
+ b[i] = AllocBrush (brush->numsides+1);
+ b[i]->original = brush->original;
+ } //end for
+
+ // split all the current windings
+
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ s = &brush->sides[i];
+ w = s->winding;
+ if (!w)
+ continue;
+ ClipWindingEpsilon (w, plane->normal, plane->dist,
+ 0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]);
+ for (j=0 ; j<2 ; j++)
+ {
+ if (!cw[j])
+ continue;
+#if 0
+ if (WindingIsTiny (cw[j]))
+ {
+ FreeWinding (cw[j]);
+ continue;
+ }
+#endif
+ cs = &b[j]->sides[b[j]->numsides];
+ b[j]->numsides++;
+ *cs = *s;
+// cs->planenum = s->planenum;
+// cs->texinfo = s->texinfo;
+// cs->visible = s->visible;
+// cs->original = s->original;
+ cs->winding = cw[j];
+ cs->flags &= ~SFL_TESTED;
+ } //end for
+ } //end for
+
+
+ // see if we have valid polygons on both sides
+
+ for (i=0 ; i<2 ; i++)
+ {
+ BoundBrush (b[i]);
+ for (j=0 ; j<3 ; j++)
+ {
+ if (b[i]->mins[j] < -4096 || b[i]->maxs[j] > 4096)
+ {
+ Log_Print("HL_SplitBrush: bogus brush after clip\n");
+ break;
+ } //end if
+ } //end for
+
+ if (b[i]->numsides < 3 || j < 3)
+ {
+ FreeBrush (b[i]);
+ b[i] = NULL;
+ Log_Print("HL_SplitBrush: numsides < 3\n");
+ } //end if
+ } //end for
+
+ if ( !(b[0] && b[1]) )
+ {
+ if (!b[0] && !b[1])
+ Log_Print("HL_SplitBrush: split removed brush\n");
+ else
+ Log_Print("HL_SplitBrush: split not on both sides\n");
+ if (b[0])
+ {
+ FreeBrush (b[0]);
+ *front = CopyBrush (brush);
+ } //end if
+ if (b[1])
+ {
+ FreeBrush (b[1]);
+ *back = CopyBrush (brush);
+ } //end if
+ return;
+ } //end if
+
+ // add the midwinding to both sides
+ for (i = 0; i < 2; i++)
+ {
+ cs = &b[i]->sides[b[i]->numsides];
+ b[i]->numsides++;
+
+ cs->planenum = planenum^i^1;
+ cs->texinfo = 0;
+ //store the node number in the surf to find the texinfo later on
+ cs->surf = nodenum;
+ //
+ cs->flags &= ~SFL_VISIBLE;
+ cs->flags &= ~SFL_TESTED;
+ if (i==0)
+ cs->winding = CopyWinding (midwinding);
+ else
+ cs->winding = midwinding;
+ } //end for
+
+
+{
+ vec_t v1;
+ int i;
+
+ for (i=0 ; i<2 ; i++)
+ {
+ v1 = BrushVolume (b[i]);
+ if (v1 < 1)
+ {
+ FreeBrush (b[i]);
+ b[i] = NULL;
+ Log_Print("HL_SplitBrush: tiny volume after clip\n");
+ } //end if
+ } //end for
+} //*/
+
+ *front = b[0];
+ *back = b[1];
+} //end of the function HL_SplitBrush
+//===========================================================================
+// returns true if the tree starting at nodenum has only solid leaves
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int HL_SolidTree_r(int nodenum)
+{
+ if (nodenum < 0)
+ {
+ switch(hl_dleafs[(-nodenum) - 1].contents)
+ {
+ case HL_CONTENTS_EMPTY:
+ {
+ return false;
+ } //end case
+ case HL_CONTENTS_SOLID:
+#ifdef HLCONTENTS
+ case HL_CONTENTS_CLIP:
+#endif //HLCONTENTS
+ case HL_CONTENTS_SKY:
+#ifdef HLCONTENTS
+ case HL_CONTENTS_TRANSLUCENT:
+#endif //HLCONTENTS
+ {
+ return true;
+ } //end case
+ case HL_CONTENTS_WATER:
+ case HL_CONTENTS_SLIME:
+ case HL_CONTENTS_LAVA:
+#ifdef HLCONTENTS
+ //these contents should not be found in the BSP
+ case HL_CONTENTS_ORIGIN:
+ case HL_CONTENTS_CURRENT_0:
+ case HL_CONTENTS_CURRENT_90:
+ case HL_CONTENTS_CURRENT_180:
+ case HL_CONTENTS_CURRENT_270:
+ case HL_CONTENTS_CURRENT_UP:
+ case HL_CONTENTS_CURRENT_DOWN:
+#endif //HLCONTENTS
+ default:
+ {
+ return false;
+ } //end default
+ } //end switch
+ return false;
+ } //end if
+ if (!HL_SolidTree_r(hl_dnodes[nodenum].children[0])) return false;
+ if (!HL_SolidTree_r(hl_dnodes[nodenum].children[1])) return false;
+ return true;
+} //end of the function HL_SolidTree_r
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *HL_CreateBrushes_r(bspbrush_t *brush, int nodenum)
+{
+ int planenum;
+ bspbrush_t *front, *back;
+ hl_dleaf_t *leaf;
+
+ //if it is a leaf
+ if (nodenum < 0)
+ {
+ leaf = &hl_dleafs[(-nodenum) - 1];
+ if (leaf->contents != HL_CONTENTS_EMPTY)
+ {
+#ifdef HL_PRINT
+ qprintf("\r%5i", ++hl_numbrushes);
+#endif //HL_PRINT
+ } //end if
+ switch(leaf->contents)
+ {
+ case HL_CONTENTS_EMPTY:
+ {
+ FreeBrush(brush);
+ return NULL;
+ } //end case
+ case HL_CONTENTS_SOLID:
+#ifdef HLCONTENTS
+ case HL_CONTENTS_CLIP:
+#endif //HLCONTENTS
+ case HL_CONTENTS_SKY:
+#ifdef HLCONTENTS
+ case HL_CONTENTS_TRANSLUCENT:
+#endif //HLCONTENTS
+ {
+ brush->side = CONTENTS_SOLID;
+ return brush;
+ } //end case
+ case HL_CONTENTS_WATER:
+ {
+ brush->side = CONTENTS_WATER;
+ return brush;
+ } //end case
+ case HL_CONTENTS_SLIME:
+ {
+ brush->side = CONTENTS_SLIME;
+ return brush;
+ } //end case
+ case HL_CONTENTS_LAVA:
+ {
+ brush->side = CONTENTS_LAVA;
+ return brush;
+ } //end case
+#ifdef HLCONTENTS
+ //these contents should not be found in the BSP
+ case HL_CONTENTS_ORIGIN:
+ case HL_CONTENTS_CURRENT_0:
+ case HL_CONTENTS_CURRENT_90:
+ case HL_CONTENTS_CURRENT_180:
+ case HL_CONTENTS_CURRENT_270:
+ case HL_CONTENTS_CURRENT_UP:
+ case HL_CONTENTS_CURRENT_DOWN:
+ {
+ Error("HL_CreateBrushes_r: found contents %d in Half-Life BSP", leaf->contents);
+ return NULL;
+ } //end case
+#endif //HLCONTENTS
+ default:
+ {
+ Error("HL_CreateBrushes_r: unknown contents %d in Half-Life BSP", leaf->contents);
+ return NULL;
+ } //end default
+ } //end switch
+ return NULL;
+ } //end if
+ //if the rest of the tree is solid
+ /*if (HL_SolidTree_r(nodenum))
+ {
+ brush->side = CONTENTS_SOLID;
+ return brush;
+ } //end if*/
+ //
+ planenum = hl_dnodes[nodenum].planenum;
+ planenum = FindFloatPlane(hl_dplanes[planenum].normal, hl_dplanes[planenum].dist);
+ //split the brush with the node plane
+ HL_SplitBrush(brush, planenum, nodenum, &front, &back);
+ //free the original brush
+ FreeBrush(brush);
+ //every node must split the brush in two
+ if (!front || !back)
+ {
+ Log_Print("HL_CreateBrushes_r: WARNING node not splitting brush\n");
+ //return NULL;
+ } //end if
+ //create brushes recursively
+ if (front) front = HL_CreateBrushes_r(front, hl_dnodes[nodenum].children[0]);
+ if (back) back = HL_CreateBrushes_r(back, hl_dnodes[nodenum].children[1]);
+ //link the brushes if possible and return them
+ if (front)
+ {
+ for (brush = front; brush->next; brush = brush->next);
+ brush->next = back;
+ return front;
+ } //end if
+ else
+ {
+ return back;
+ } //end else
+} //end of the function HL_CreateBrushes_r
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *HL_CreateBrushesFromBSP(int modelnum)
+{
+ bspbrush_t *brushlist;
+ bspbrush_t *brush;
+ hl_dnode_t *headnode;
+ vec3_t mins, maxs;
+ int i;
+
+ //
+ headnode = &hl_dnodes[hl_dmodels[modelnum].headnode[0]];
+ //get the mins and maxs of the world
+ VectorCopy(headnode->mins, mins);
+ VectorCopy(headnode->maxs, maxs);
+ //enlarge these mins and maxs
+ for (i = 0; i < 3; i++)
+ {
+ mins[i] -= 8;
+ maxs[i] += 8;
+ } //end for
+ //NOTE: have to add the BSP tree mins and maxs to the MAP mins and maxs
+ AddPointToBounds(mins, map_mins, map_maxs);
+ AddPointToBounds(maxs, map_mins, map_maxs);
+ //
+ if (!modelnum)
+ {
+ Log_Print("brush size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n",
+ map_mins[0], map_mins[1], map_mins[2],
+ map_maxs[0], map_maxs[1], map_maxs[2]);
+ } //end if
+ //create one huge brush containing the whole world
+ brush = BrushFromBounds(mins, maxs);
+ VectorCopy(mins, brush->mins);
+ VectorCopy(maxs, brush->maxs);
+ //
+#ifdef HL_PRINT
+ qprintf("creating Half-Life brushes\n");
+ qprintf("%5d brushes", hl_numbrushes = 0);
+#endif //HL_PRINT
+ //create the brushes
+ brushlist = HL_CreateBrushes_r(brush, hl_dmodels[modelnum].headnode[0]);
+ //
+#ifdef HL_PRINT
+ qprintf("\n");
+#endif //HL_PRINT
+ //now we've got a list with brushes!
+ return brushlist;
+} //end of the function HL_CreateBrushesFromBSP
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *HL_MergeBrushes(bspbrush_t *brushlist, int modelnum)
+{
+ int nummerges, merged;
+ bspbrush_t *b1, *b2, *tail, *newbrush, *newbrushlist;
+ bspbrush_t *lastb2;
+
+ if (!brushlist) return NULL;
+
+ if (!modelnum) qprintf("%5d brushes merged", nummerges = 0);
+ do
+ {
+ for (tail = brushlist; tail; tail = tail->next)
+ {
+ if (!tail->next) break;
+ } //end for
+ merged = 0;
+ newbrushlist = NULL;
+ for (b1 = brushlist; b1; b1 = brushlist)
+ {
+ lastb2 = b1;
+ for (b2 = b1->next; b2; b2 = b2->next)
+ {
+ //can't merge brushes with different contents
+ if (b1->side != b2->side) newbrush = NULL;
+ else newbrush = TryMergeBrushes(b1, b2);
+ //if a merged brush is created
+ if (newbrush)
+ {
+ //copy the brush contents
+ newbrush->side = b1->side;
+ //add the new brush to the end of the list
+ tail->next = newbrush;
+ //remove the second brush from the list
+ lastb2->next = b2->next;
+ //remove the first brush from the list
+ brushlist = brushlist->next;
+ //free the merged brushes
+ FreeBrush(b1);
+ FreeBrush(b2);
+ //get a new tail brush
+ for (tail = brushlist; tail; tail = tail->next)
+ {
+ if (!tail->next) break;
+ } //end for
+ merged++;
+ if (!modelnum) qprintf("\r%5d", nummerges++);
+ break;
+ } //end if
+ lastb2 = b2;
+ } //end for
+ //if b1 can't be merged with any of the other brushes
+ if (!b2)
+ {
+ brushlist = brushlist->next;
+ //keep b1
+ b1->next = newbrushlist;
+ newbrushlist = b1;
+ } //end else
+ } //end for
+ brushlist = newbrushlist;
+ } while(merged);
+ if (!modelnum) qprintf("\n");
+ return newbrushlist;
+} //end of the function HL_MergeBrushes
+//===========================================================================
+// returns the amount the face and the winding have overlap
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+float HL_FaceOnWinding(hl_dface_t *face, winding_t *winding)
+{
+ int i, edgenum, side;
+ float dist, area;
+ hl_dplane_t plane;
+ vec_t *v1, *v2;
+ vec3_t normal, edgevec;
+ winding_t *w;
+
+ //
+ w = CopyWinding(winding);
+ memcpy(&plane, &hl_dplanes[face->planenum], sizeof(hl_dplane_t));
+ //check on which side of the plane the face is
+ if (face->side)
+ {
+ VectorNegate(plane.normal, plane.normal);
+ plane.dist = -plane.dist;
+ } //end if
+ for (i = 0; i < face->numedges && w; i++)
+ {
+ //get the first and second vertex of the edge
+ edgenum = hl_dsurfedges[face->firstedge + i];
+ side = edgenum > 0;
+ //if the face plane is flipped
+ v1 = hl_dvertexes[hl_dedges[abs(edgenum)].v[side]].point;
+ v2 = hl_dvertexes[hl_dedges[abs(edgenum)].v[!side]].point;
+ //create a plane through the edge vector, orthogonal to the face plane
+ //and with the normal vector pointing out of the face
+ VectorSubtract(v1, v2, edgevec);
+ CrossProduct(edgevec, plane.normal, normal);
+ VectorNormalize(normal);
+ dist = DotProduct(normal, v1);
+ //
+ ChopWindingInPlace(&w, normal, dist, 0.9); //CLIP_EPSILON
+ } //end for
+ if (w)
+ {
+ area = WindingArea(w);
+ FreeWinding(w);
+ return area;
+ } //end if
+ return 0;
+} //end of the function HL_FaceOnWinding
+//===========================================================================
+// returns a list with brushes created by splitting the given brush with
+// planes that go through the face edges and are orthogonal to the face plane
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *HL_SplitBrushWithFace(bspbrush_t *brush, hl_dface_t *face)
+{
+ int i, edgenum, side, planenum, splits;
+ float dist;
+ hl_dplane_t plane;
+ vec_t *v1, *v2;
+ vec3_t normal, edgevec;
+ bspbrush_t *front, *back, *brushlist;
+
+ memcpy(&plane, &hl_dplanes[face->planenum], sizeof(hl_dplane_t));
+ //check on which side of the plane the face is
+ if (face->side)
+ {
+ VectorNegate(plane.normal, plane.normal);
+ plane.dist = -plane.dist;
+ } //end if
+ splits = 0;
+ brushlist = NULL;
+ for (i = 0; i < face->numedges; i++)
+ {
+ //get the first and second vertex of the edge
+ edgenum = hl_dsurfedges[face->firstedge + i];
+ side = edgenum > 0;
+ //if the face plane is flipped
+ v1 = hl_dvertexes[hl_dedges[abs(edgenum)].v[side]].point;
+ v2 = hl_dvertexes[hl_dedges[abs(edgenum)].v[!side]].point;
+ //create a plane through the edge vector, orthogonal to the face plane
+ //and with the normal vector pointing out of the face
+ VectorSubtract(v1, v2, edgevec);
+ CrossProduct(edgevec, plane.normal, normal);
+ VectorNormalize(normal);
+ dist = DotProduct(normal, v1);
+ //
+ planenum = FindFloatPlane(normal, dist);
+ //split the current brush
+ SplitBrush(brush, planenum, &front, &back);
+ //if there is a back brush just put it in the list
+ if (back)
+ {
+ //copy the brush contents
+ back->side = brush->side;
+ //
+ back->next = brushlist;
+ brushlist = back;
+ splits++;
+ } //end if
+ if (!front)
+ {
+ Log_Print("HL_SplitBrushWithFace: no new brush\n");
+ FreeBrushList(brushlist);
+ return NULL;
+ } //end if
+ //copy the brush contents
+ front->side = brush->side;
+ //continue splitting the front brush
+ brush = front;
+ } //end for
+ if (!splits)
+ {
+ FreeBrush(front);
+ return NULL;
+ } //end if
+ front->next = brushlist;
+ brushlist = front;
+ return brushlist;
+} //end of the function HL_SplitBrushWithFace
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *HL_TextureBrushes(bspbrush_t *brushlist, int modelnum)
+{
+ float area, largestarea;
+ int i, n, texinfonum, sn, numbrushes, ofs;
+ int bestfacenum, sidenodenum;
+ side_t *side;
+ hl_dmiptexlump_t *miptexlump;
+ hl_miptex_t *miptex;
+ bspbrush_t *brush, *nextbrush, *prevbrush, *newbrushes, *brushlistend;
+ vec_t defaultvec[4] = {1, 0, 0, 0};
+
+ if (!modelnum) qprintf("texturing brushes\n");
+ if (!modelnum) qprintf("%5d brushes", numbrushes = 0);
+ //get a pointer to the last brush in the list
+ for (brushlistend = brushlist; brushlistend; brushlistend = brushlistend->next)
+ {
+ if (!brushlistend->next) break;
+ } //end for
+ //there's no previous brush when at the start of the list
+ prevbrush = NULL;
+ //go over the brush list
+ for (brush = brushlist; brush; brush = nextbrush)
+ {
+ nextbrush = brush->next;
+ //find a texinfo for every brush side
+ for (sn = 0; sn < brush->numsides; sn++)
+ {
+ side = &brush->sides[sn];
+ //
+ if (side->flags & SFL_TEXTURED) continue;
+ //number of the node that created this brush side
+ sidenodenum = side->surf; //see midwinding in HL_SplitBrush
+ //no face found yet
+ bestfacenum = -1;
+ //minimum face size
+ largestarea = 1;
+ //if optimizing the texture placement and not going for the
+ //least number of brushes
+ if (!lessbrushes)
+ {
+ for (i = 0; i < hl_numfaces; i++)
+ {
+ //the face must be in the same plane as the node plane that created
+ //this brush side
+ if (hl_dfaces[i].planenum == hl_dnodes[sidenodenum].planenum)
+ {
+ //get the area the face and the brush side overlap
+ area = HL_FaceOnWinding(&hl_dfaces[i], side->winding);
+ //if this face overlaps the brush side winding more than previous faces
+ if (area > largestarea)
+ {
+ //if there already was a face for texturing this brush side with
+ //a different texture
+ if (bestfacenum >= 0 &&
+ (hl_dfaces[bestfacenum].texinfo != hl_dfaces[i].texinfo))
+ {
+ //split the brush to fit the texture
+ newbrushes = HL_SplitBrushWithFace(brush, &hl_dfaces[i]);
+ //if new brushes where created
+ if (newbrushes)
+ {
+ //remove the current brush from the list
+ if (prevbrush) prevbrush->next = brush->next;
+ else brushlist = brush->next;
+ if (brushlistend == brush)
+ {
+ brushlistend = prevbrush;
+ nextbrush = newbrushes;
+ } //end if
+ //add the new brushes to the end of the list
+ if (brushlistend) brushlistend->next = newbrushes;
+ else brushlist = newbrushes;
+ //free the current brush
+ FreeBrush(brush);
+ //don't forget about the prevbrush pointer at the bottom of
+ //the outer loop
+ brush = prevbrush;
+ //find the end of the list
+ for (brushlistend = brushlist; brushlistend; brushlistend = brushlistend->next)
+ {
+ if (!brushlistend->next) break;
+ } //end for
+ break;
+ } //end if
+ else
+ {
+ Log_Write("brush %d: no real texture split", numbrushes);
+ } //end else
+ } //end if
+ else
+ {
+ //best face for texturing this brush side
+ bestfacenum = i;
+ } //end else
+ } //end if
+ } //end if
+ } //end for
+ //if the brush was split the original brush is removed
+ //and we just continue with the next one in the list
+ if (i < hl_numfaces) break;
+ } //end if
+ else
+ {
+ //find the face with the largest overlap with this brush side
+ //for texturing the brush side
+ for (i = 0; i < hl_numfaces; i++)
+ {
+ //the face must be in the same plane as the node plane that created
+ //this brush side
+ if (hl_dfaces[i].planenum == hl_dnodes[sidenodenum].planenum)
+ {
+ //get the area the face and the brush side overlap
+ area = HL_FaceOnWinding(&hl_dfaces[i], side->winding);
+ //if this face overlaps the brush side winding more than previous faces
+ if (area > largestarea)
+ {
+ largestarea = area;
+ bestfacenum = i;
+ } //end if
+ } //end if
+ } //end for
+ } //end else
+ //if a face was found for texturing this brush side
+ if (bestfacenum >= 0)
+ {
+ //set the MAP texinfo values
+ texinfonum = hl_dfaces[bestfacenum].texinfo;
+ for (n = 0; n < 4; n++)
+ {
+ map_texinfo[texinfonum].vecs[0][n] = hl_texinfo[texinfonum].vecs[0][n];
+ map_texinfo[texinfonum].vecs[1][n] = hl_texinfo[texinfonum].vecs[1][n];
+ } //end for
+ //make sure the two vectors aren't of zero length otherwise use the default
+ //vector to prevent a divide by zero in the map writing
+ if (VectorLength(map_texinfo[texinfonum].vecs[0]) < 0.01)
+ memcpy(map_texinfo[texinfonum].vecs[0], defaultvec, sizeof(defaultvec));
+ if (VectorLength(map_texinfo[texinfonum].vecs[1]) < 0.01)
+ memcpy(map_texinfo[texinfonum].vecs[1], defaultvec, sizeof(defaultvec));
+ //
+ map_texinfo[texinfonum].flags = hl_texinfo[texinfonum].flags;
+ map_texinfo[texinfonum].value = 0; //HL_ and HL texinfos don't have a value
+ //the mip texture
+ miptexlump = (hl_dmiptexlump_t *) hl_dtexdata;
+ ofs = miptexlump->dataofs[hl_texinfo[texinfonum].miptex];
+ if ( ofs > hl_texdatasize ) {
+ ofs = miptexlump->dataofs[0];
+ }
+ miptex = (hl_miptex_t *)((byte *)miptexlump + ofs );
+ //get the mip texture name
+ strcpy(map_texinfo[texinfonum].texture, miptex->name);
+ //no animations in Quake1 and Half-Life mip textures
+ map_texinfo[texinfonum].nexttexinfo = -1;
+ //store the texinfo number
+ side->texinfo = texinfonum;
+ //
+ if (texinfonum > map_numtexinfo) map_numtexinfo = texinfonum;
+ //this side is textured
+ side->flags |= SFL_TEXTURED;
+ } //end if
+ else
+ {
+ //no texture for this side
+ side->texinfo = TEXINFO_NODE;
+ //this side is textured
+ side->flags |= SFL_TEXTURED;
+ } //end if
+ } //end for
+ //
+ if (!modelnum && prevbrush != brush) qprintf("\r%5d", ++numbrushes);
+ //previous brush in the list
+ prevbrush = brush;
+ } //end for
+ if (!modelnum) qprintf("\n");
+ //return the new list with brushes
+ return brushlist;
+} //end of the function HL_TextureBrushes
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void HL_FixContentsTextures(bspbrush_t *brushlist)
+{
+ int i, texinfonum;
+ bspbrush_t *brush;
+
+ for (brush = brushlist; brush; brush = brush->next)
+ {
+ //only fix the textures of water, slime and lava brushes
+ if (brush->side != CONTENTS_WATER &&
+ brush->side != CONTENTS_SLIME &&
+ brush->side != CONTENTS_LAVA) continue;
+ //
+ for (i = 0; i < brush->numsides; i++)
+ {
+ texinfonum = brush->sides[i].texinfo;
+ if (HL_TextureContents(map_texinfo[texinfonum].texture) == brush->side) break;
+ } //end for
+ //if no specific contents texture was found
+ if (i >= brush->numsides)
+ {
+ texinfonum = -1;
+ for (i = 0; i < map_numtexinfo; i++)
+ {
+ if (HL_TextureContents(map_texinfo[i].texture) == brush->side)
+ {
+ texinfonum = i;
+ break;
+ } //end if
+ } //end for
+ } //end if
+ //
+ if (texinfonum >= 0)
+ {
+ //give all the brush sides this contents texture
+ for (i = 0; i < brush->numsides; i++)
+ {
+ brush->sides[i].texinfo = texinfonum;
+ } //end for
+ } //end if
+ else Log_Print("brush contents %d with wrong textures\n", brush->side);
+ //
+ } //end for
+ /*
+ for (brush = brushlist; brush; brush = brush->next)
+ {
+ //give all the brush sides this contents texture
+ for (i = 0; i < brush->numsides; i++)
+ {
+ if (HL_TextureContents(map_texinfo[texinfonum].texture) != brush->side)
+ {
+ Error("brush contents %d with wrong contents textures %s\n", brush->side,
+ HL_TextureContents(map_texinfo[texinfonum].texture));
+ } //end if
+ } //end for
+ } //end for*/
+} //end of the function HL_FixContentsTextures
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void HL_BSPBrushToMapBrush(bspbrush_t *bspbrush, entity_t *mapent)
+{
+ mapbrush_t *mapbrush;
+ side_t *side;
+ int i, besttexinfo;
+
+ if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
+ Error ("nummapbrushes == MAX_MAPFILE_BRUSHES");
+
+ mapbrush = &mapbrushes[nummapbrushes];
+ mapbrush->original_sides = &brushsides[nummapbrushsides];
+ mapbrush->entitynum = mapent - entities;
+ mapbrush->brushnum = nummapbrushes - mapent->firstbrush;
+ mapbrush->leafnum = -1;
+ mapbrush->numsides = 0;
+
+ besttexinfo = TEXINFO_NODE;
+ for (i = 0; i < bspbrush->numsides; i++)
+ {
+ if (!bspbrush->sides[i].winding) continue;
+ //
+ if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
+ Error ("MAX_MAPFILE_BRUSHSIDES");
+ side = &brushsides[nummapbrushsides];
+ //the contents of the bsp brush is stored in the side variable
+ side->contents = bspbrush->side;
+ side->surf = 0;
+ side->planenum = bspbrush->sides[i].planenum;
+ side->texinfo = bspbrush->sides[i].texinfo;
+ if (side->texinfo != TEXINFO_NODE)
+ {
+ //this brush side is textured
+ side->flags |= SFL_TEXTURED;
+ besttexinfo = side->texinfo;
+ } //end if
+ //
+ nummapbrushsides++;
+ mapbrush->numsides++;
+ } //end for
+ //
+ if (besttexinfo == TEXINFO_NODE)
+ {
+ mapbrush->numsides = 0;
+ hl_numclipbrushes++;
+ return;
+ } //end if
+ //set the texinfo for all the brush sides without texture
+ for (i = 0; i < mapbrush->numsides; i++)
+ {
+ if (mapbrush->original_sides[i].texinfo == TEXINFO_NODE)
+ {
+ mapbrush->original_sides[i].texinfo = besttexinfo;
+ } //end if
+ } //end for
+ //contents of the brush
+ mapbrush->contents = bspbrush->side;
+ //
+ if (create_aas)
+ {
+ //create the AAS brushes from this brush, add brush bevels
+ AAS_CreateMapBrushes(mapbrush, mapent, true);
+ return;
+ } //end if
+ //create windings for sides and bounds for brush
+ MakeBrushWindings(mapbrush);
+ //add brush bevels
+ AddBrushBevels(mapbrush);
+ //a new brush has been created
+ nummapbrushes++;
+ mapent->numbrushes++;
+} //end of the function HL_BSPBrushToMapBrush
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void HL_CreateMapBrushes(entity_t *mapent, int modelnum)
+{
+ bspbrush_t *brushlist, *brush, *nextbrush;
+ int i;
+
+ //create brushes from the model BSP tree
+ brushlist = HL_CreateBrushesFromBSP(modelnum);
+ //texture the brushes and split them when necesary
+ brushlist = HL_TextureBrushes(brushlist, modelnum);
+ //fix the contents textures of all brushes
+ HL_FixContentsTextures(brushlist);
+ //
+ if (!nobrushmerge)
+ {
+ brushlist = HL_MergeBrushes(brushlist, modelnum);
+ //brushlist = HL_MergeBrushes(brushlist, modelnum);
+ } //end if
+ //
+ if (!modelnum) qprintf("converting brushes to map brushes\n");
+ if (!modelnum) qprintf("%5d brushes", i = 0);
+ for (brush = brushlist; brush; brush = nextbrush)
+ {
+ nextbrush = brush->next;
+ HL_BSPBrushToMapBrush(brush, mapent);
+ brush->next = NULL;
+ FreeBrush(brush);
+ if (!modelnum) qprintf("\r%5d", ++i);
+ } //end for
+ if (!modelnum) qprintf("\n");
+} //end of the function HL_CreateMapBrushes
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void HL_ResetMapLoading(void)
+{
+} //end of the function HL_ResetMapLoading
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void HL_LoadMapFromBSP(char *filename, int offset, int length)
+{
+ int i, modelnum;
+ char *model, *classname;
+
+ Log_Print("-- HL_LoadMapFromBSP --\n");
+ //loaded map type
+ loadedmaptype = MAPTYPE_HALFLIFE;
+ //
+ qprintf("loading map from %s at %d\n", filename, offset);
+ //load the Half-Life BSP file
+ HL_LoadBSPFile(filename, offset, length);
+ //
+ hl_numclipbrushes = 0;
+ //parse the entities from the BSP
+ HL_ParseEntities();
+ //clear the map mins and maxs
+ ClearBounds(map_mins, map_maxs);
+ //
+ qprintf("creating Half-Life brushes\n");
+ if (lessbrushes) qprintf("creating minimum number of brushes\n");
+ else qprintf("placing textures correctly\n");
+ //
+ for (i = 0; i < num_entities; i++)
+ {
+ entities[i].firstbrush = nummapbrushes;
+ entities[i].numbrushes = 0;
+ //
+ classname = ValueForKey(&entities[i], "classname");
+ if (classname && !strcmp(classname, "worldspawn"))
+ {
+ modelnum = 0;
+ } //end if
+ else
+ {
+ //
+ model = ValueForKey(&entities[i], "model");
+ if (!model || *model != '*') continue;
+ model++;
+ modelnum = atoi(model);
+ } //end else
+ //create map brushes for the entity
+ HL_CreateMapBrushes(&entities[i], modelnum);
+ } //end for
+ //
+ qprintf("%5d map brushes\n", nummapbrushes);
+ qprintf("%5d clip brushes\n", hl_numclipbrushes);
+} //end of the function HL_LoadMapFromBSP
diff --git a/code/bspc/map_q1.c b/code/bspc/map_q1.c
index 772a358..fa9d117 100755
--- a/code/bspc/map_q1.c
+++ b/code/bspc/map_q1.c
@@ -1,1174 +1,1174 @@
-/*
-===========================================================================
-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 "l_bsp_q1.h"
-#include "aas_map.h" //AAS_CreateMapBrushes
-
-int q1_numbrushes;
-int q1_numclipbrushes;
-
-//#define Q1_PRINT
-
-//===========================================================================
-// water, slime and lava brush textures names always start with a *
-// followed by the type: "slime", "lava" or otherwise water
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int Q1_TextureContents(char *name)
-{
- if (!Q_strcasecmp(name, "clip")) return CONTENTS_SOLID;
- if (name[0] == '*')
- {
- if (!Q_strncasecmp(name+1,"lava",4)) return CONTENTS_LAVA;
- else if (!Q_strncasecmp(name+1,"slime",5)) return CONTENTS_SLIME;
- else return CONTENTS_WATER;
- } //end if
- else if (!Q_strncasecmp(name, "sky", 3)) return CONTENTS_SOLID;
- else return CONTENTS_SOLID;
-} //end of the function Q1_TextureContents
-//===========================================================================
-// Generates two new brushes, leaving the original
-// unchanged
-//
-// modified for Half-Life because there are quite a lot of tiny node leaves
-// in the Half-Life bsps
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q1_SplitBrush(bspbrush_t *brush, int planenum, int nodenum,
- bspbrush_t **front, bspbrush_t **back)
-{
- bspbrush_t *b[2];
- int i, j;
- winding_t *w, *cw[2], *midwinding;
- plane_t *plane, *plane2;
- side_t *s, *cs;
- float d, d_front, d_back;
-
- *front = *back = NULL;
- plane = &mapplanes[planenum];
-
- // check all points
- d_front = d_back = 0;
- for (i=0 ; i<brush->numsides ; i++)
- {
- w = brush->sides[i].winding;
- if (!w)
- continue;
- for (j=0 ; j<w->numpoints ; j++)
- {
- d = DotProduct (w->p[j], plane->normal) - plane->dist;
- if (d > 0 && d > d_front)
- d_front = d;
- if (d < 0 && d < d_back)
- d_back = d;
- } //end for
- } //end for
-
- if (d_front < 0.1) // PLANESIDE_EPSILON)
- { // only on back
- *back = CopyBrush (brush);
- Log_Print("Q1_SplitBrush: only on back\n");
- return;
- } //end if
- if (d_back > -0.1) // PLANESIDE_EPSILON)
- { // only on front
- *front = CopyBrush (brush);
- Log_Print("Q1_SplitBrush: only on front\n");
- return;
- } //end if
-
- // create a new winding from the split plane
-
- w = BaseWindingForPlane (plane->normal, plane->dist);
- for (i = 0; i < brush->numsides && w; i++)
- {
- plane2 = &mapplanes[brush->sides[i].planenum ^ 1];
- ChopWindingInPlace(&w, plane2->normal, plane2->dist, 0); // PLANESIDE_EPSILON);
- } //end for
-
- if (!w || WindingIsTiny(w))
- { // the brush isn't really split
- int side;
-
- Log_Print("Q1_SplitBrush: no split winding\n");
- side = BrushMostlyOnSide (brush, plane);
- if (side == PSIDE_FRONT)
- *front = CopyBrush (brush);
- if (side == PSIDE_BACK)
- *back = CopyBrush (brush);
- return;
- }
-
- if (WindingIsHuge(w))
- {
- Log_Print("Q1_SplitBrush: WARNING huge split winding\n");
- } //end of
-
- midwinding = w;
-
- // split it for real
-
- for (i = 0; i < 2; i++)
- {
- b[i] = AllocBrush (brush->numsides+1);
- b[i]->original = brush->original;
- } //end for
-
- // split all the current windings
-
- for (i=0 ; i<brush->numsides ; i++)
- {
- s = &brush->sides[i];
- w = s->winding;
- if (!w)
- continue;
- ClipWindingEpsilon (w, plane->normal, plane->dist,
- 0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]);
- for (j=0 ; j<2 ; j++)
- {
- if (!cw[j])
- continue;
-#if 0
- if (WindingIsTiny (cw[j]))
- {
- FreeWinding (cw[j]);
- continue;
- }
-#endif
- cs = &b[j]->sides[b[j]->numsides];
- b[j]->numsides++;
- *cs = *s;
-// cs->planenum = s->planenum;
-// cs->texinfo = s->texinfo;
-// cs->visible = s->visible;
-// cs->original = s->original;
- cs->winding = cw[j];
- cs->flags &= ~SFL_TESTED;
- } //end for
- } //end for
-
-
- // see if we have valid polygons on both sides
-
- for (i=0 ; i<2 ; i++)
- {
- BoundBrush (b[i]);
- for (j=0 ; j<3 ; j++)
- {
- if (b[i]->mins[j] < -4096 || b[i]->maxs[j] > 4096)
- {
- Log_Print("Q1_SplitBrush: bogus brush after clip\n");
- break;
- } //end if
- } //end for
-
- if (b[i]->numsides < 3 || j < 3)
- {
- FreeBrush (b[i]);
- b[i] = NULL;
- Log_Print("Q1_SplitBrush: numsides < 3\n");
- } //end if
- } //end for
-
- if ( !(b[0] && b[1]) )
- {
- if (!b[0] && !b[1])
- Log_Print("Q1_SplitBrush: split removed brush\n");
- else
- Log_Print("Q1_SplitBrush: split not on both sides\n");
- if (b[0])
- {
- FreeBrush (b[0]);
- *front = CopyBrush (brush);
- } //end if
- if (b[1])
- {
- FreeBrush (b[1]);
- *back = CopyBrush (brush);
- } //end if
- return;
- } //end if
-
- // add the midwinding to both sides
- for (i = 0; i < 2; i++)
- {
- cs = &b[i]->sides[b[i]->numsides];
- b[i]->numsides++;
-
- cs->planenum = planenum^i^1;
- cs->texinfo = 0;
- //store the node number in the surf to find the texinfo later on
- cs->surf = nodenum;
- //
- cs->flags &= ~SFL_VISIBLE;
- cs->flags &= ~SFL_TESTED;
- cs->flags &= ~SFL_TEXTURED;
- if (i==0)
- cs->winding = CopyWinding (midwinding);
- else
- cs->winding = midwinding;
- } //end for
-
-
-{
- vec_t v1;
- int i;
-
- for (i=0 ; i<2 ; i++)
- {
- v1 = BrushVolume (b[i]);
- if (v1 < 1)
- {
- FreeBrush (b[i]);
- b[i] = NULL;
- Log_Print("Q1_SplitBrush: tiny volume after clip\n");
- } //end if
- } //end for
-} //*/
-
- *front = b[0];
- *back = b[1];
-} //end of the function Q1_SplitBrush
-//===========================================================================
-// returns true if the tree starting at nodenum has only solid leaves
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int Q1_SolidTree_r(int nodenum)
-{
- if (nodenum < 0)
- {
- switch(q1_dleafs[(-nodenum) - 1].contents)
- {
- case Q1_CONTENTS_EMPTY:
- {
- return false;
- } //end case
- case Q1_CONTENTS_SOLID:
-#ifdef HLCONTENTS
- case Q1_CONTENTS_CLIP:
-#endif HLCONTENTS
- case Q1_CONTENTS_SKY:
-#ifdef HLCONTENTS
- case Q1_CONTENTS_TRANSLUCENT:
-#endif HLCONTENTS
- {
- return true;
- } //end case
- case Q1_CONTENTS_WATER:
- case Q1_CONTENTS_SLIME:
- case Q1_CONTENTS_LAVA:
-#ifdef HLCONTENTS
- //these contents should not be found in the BSP
- case Q1_CONTENTS_ORIGIN:
- case Q1_CONTENTS_CURRENT_0:
- case Q1_CONTENTS_CURRENT_90:
- case Q1_CONTENTS_CURRENT_180:
- case Q1_CONTENTS_CURRENT_270:
- case Q1_CONTENTS_CURRENT_UP:
- case Q1_CONTENTS_CURRENT_DOWN:
-#endif HLCONTENTS
- default:
- {
- return false;
- } //end default
- } //end switch
- return false;
- } //end if
- if (!Q1_SolidTree_r(q1_dnodes[nodenum].children[0])) return false;
- if (!Q1_SolidTree_r(q1_dnodes[nodenum].children[1])) return false;
- return true;
-} //end of the function Q1_SolidTree_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *Q1_CreateBrushes_r(bspbrush_t *brush, int nodenum)
-{
- int planenum;
- bspbrush_t *front, *back;
- q1_dleaf_t *leaf;
-
- //if it is a leaf
- if (nodenum < 0)
- {
- leaf = &q1_dleafs[(-nodenum) - 1];
- if (leaf->contents != Q1_CONTENTS_EMPTY)
- {
-#ifdef Q1_PRINT
- qprintf("\r%5i", ++q1_numbrushes);
-#endif //Q1_PRINT
- } //end if
- switch(leaf->contents)
- {
- case Q1_CONTENTS_EMPTY:
- {
- FreeBrush(brush);
- return NULL;
- } //end case
- case Q1_CONTENTS_SOLID:
-#ifdef HLCONTENTS
- case Q1_CONTENTS_CLIP:
-#endif HLCONTENTS
- case Q1_CONTENTS_SKY:
-#ifdef HLCONTENTS
- case Q1_CONTENTS_TRANSLUCENT:
-#endif HLCONTENTS
- {
- brush->side = CONTENTS_SOLID;
- return brush;
- } //end case
- case Q1_CONTENTS_WATER:
- {
- brush->side = CONTENTS_WATER;
- return brush;
- } //end case
- case Q1_CONTENTS_SLIME:
- {
- brush->side = CONTENTS_SLIME;
- return brush;
- } //end case
- case Q1_CONTENTS_LAVA:
- {
- brush->side = CONTENTS_LAVA;
- return brush;
- } //end case
-#ifdef HLCONTENTS
- //these contents should not be found in the BSP
- case Q1_CONTENTS_ORIGIN:
- case Q1_CONTENTS_CURRENT_0:
- case Q1_CONTENTS_CURRENT_90:
- case Q1_CONTENTS_CURRENT_180:
- case Q1_CONTENTS_CURRENT_270:
- case Q1_CONTENTS_CURRENT_UP:
- case Q1_CONTENTS_CURRENT_DOWN:
- {
- Error("Q1_CreateBrushes_r: found contents %d in Half-Life BSP", leaf->contents);
- return NULL;
- } //end case
-#endif HLCONTENTS
- default:
- {
- Error("Q1_CreateBrushes_r: unknown contents %d in Half-Life BSP", leaf->contents);
- return NULL;
- } //end default
- } //end switch
- return NULL;
- } //end if
- //if the rest of the tree is solid
- /*if (Q1_SolidTree_r(nodenum))
- {
- brush->side = CONTENTS_SOLID;
- return brush;
- } //end if*/
- //
- planenum = q1_dnodes[nodenum].planenum;
- planenum = FindFloatPlane(q1_dplanes[planenum].normal, q1_dplanes[planenum].dist);
- //split the brush with the node plane
- Q1_SplitBrush(brush, planenum, nodenum, &front, &back);
- //free the original brush
- FreeBrush(brush);
- //every node must split the brush in two
- if (!front || !back)
- {
- Log_Print("Q1_CreateBrushes_r: WARNING node not splitting brush\n");
- //return NULL;
- } //end if
- //create brushes recursively
- if (front) front = Q1_CreateBrushes_r(front, q1_dnodes[nodenum].children[0]);
- if (back) back = Q1_CreateBrushes_r(back, q1_dnodes[nodenum].children[1]);
- //link the brushes if possible and return them
- if (front)
- {
- for (brush = front; brush->next; brush = brush->next);
- brush->next = back;
- return front;
- } //end if
- else
- {
- return back;
- } //end else
-} //end of the function Q1_CreateBrushes_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *Q1_CreateBrushesFromBSP(int modelnum)
-{
- bspbrush_t *brushlist;
- bspbrush_t *brush;
- q1_dnode_t *headnode;
- vec3_t mins, maxs;
- int i;
-
- //
- headnode = &q1_dnodes[q1_dmodels[modelnum].headnode[0]];
- //get the mins and maxs of the world
- VectorCopy(headnode->mins, mins);
- VectorCopy(headnode->maxs, maxs);
- //enlarge these mins and maxs
- for (i = 0; i < 3; i++)
- {
- mins[i] -= 8;
- maxs[i] += 8;
- } //end for
- //NOTE: have to add the BSP tree mins and maxs to the MAP mins and maxs
- AddPointToBounds(mins, map_mins, map_maxs);
- AddPointToBounds(maxs, map_mins, map_maxs);
- //
- if (!modelnum)
- {
- Log_Print("brush size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n",
- map_mins[0], map_mins[1], map_mins[2],
- map_maxs[0], map_maxs[1], map_maxs[2]);
- } //end if
- //create one huge brush containing the whole world
- brush = BrushFromBounds(mins, maxs);
- VectorCopy(mins, brush->mins);
- VectorCopy(maxs, brush->maxs);
- //
-#ifdef Q1_PRINT
- qprintf("creating Quake brushes\n");
- qprintf("%5d brushes", q1_numbrushes = 0);
-#endif //Q1_PRINT
- //create the brushes
- brushlist = Q1_CreateBrushes_r(brush, q1_dmodels[modelnum].headnode[0]);
- //
-#ifdef Q1_PRINT
- qprintf("\n");
-#endif //Q1_PRINT
- //now we've got a list with brushes!
- return brushlist;
-} //end of the function Q1_CreateBrushesFromBSP
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-q1_dleaf_t *Q1_PointInLeaf(int startnode, vec3_t point)
-{
- int nodenum;
- vec_t dist;
- q1_dnode_t *node;
- q1_dplane_t *plane;
-
- nodenum = startnode;
- while (nodenum >= 0)
- {
- node = &q1_dnodes[nodenum];
- plane = &q1_dplanes[node->planenum];
- dist = DotProduct(point, plane->normal) - plane->dist;
- if (dist > 0)
- nodenum = node->children[0];
- else
- nodenum = node->children[1];
- } //end while
-
- return &q1_dleafs[-nodenum - 1];
-} //end of the function Q1_PointInLeaf
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float Q1_FaceArea(q1_dface_t *face)
-{
- int i;
- float total;
- vec_t *v;
- vec3_t d1, d2, cross;
- q1_dedge_t *edge;
-
- edge = &q1_dedges[face->firstedge];
- v = q1_dvertexes[edge->v[0]].point;
-
- total = 0;
- for (i = 1; i < face->numedges - 1; i++)
- {
- edge = &q1_dedges[face->firstedge + i];
- VectorSubtract(q1_dvertexes[edge->v[0]].point, v, d1);
- VectorSubtract(q1_dvertexes[edge->v[1]].point, v, d2);
- CrossProduct(d1, d2, cross);
- total += 0.5 * VectorLength(cross);
- } //end for
- return total;
-} //end of the function AAS_FaceArea
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q1_FacePlane(q1_dface_t *face, vec3_t normal, float *dist)
-{
- vec_t *v1, *v2, *v3;
- vec3_t vec1, vec2;
- int side, edgenum;
-
- edgenum = q1_dsurfedges[face->firstedge];
- side = edgenum < 0;
- v1 = q1_dvertexes[q1_dedges[abs(edgenum)].v[side]].point;
- v2 = q1_dvertexes[q1_dedges[abs(edgenum)].v[!side]].point;
- edgenum = q1_dsurfedges[face->firstedge+1];
- side = edgenum < 0;
- v3 = q1_dvertexes[q1_dedges[abs(edgenum)].v[!side]].point;
- //
- VectorSubtract(v2, v1, vec1);
- VectorSubtract(v3, v1, vec2);
-
- CrossProduct(vec1, vec2, normal);
- VectorNormalize(normal);
- *dist = DotProduct(v1, normal);
-} //end of the function Q1_FacePlane
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *Q1_MergeBrushes(bspbrush_t *brushlist, int modelnum)
-{
- int nummerges, merged;
- bspbrush_t *b1, *b2, *tail, *newbrush, *newbrushlist;
- bspbrush_t *lastb2;
-
- if (!brushlist) return NULL;
-
- if (!modelnum) qprintf("%5d brushes merged", nummerges = 0);
- do
- {
- for (tail = brushlist; tail; tail = tail->next)
- {
- if (!tail->next) break;
- } //end for
- merged = 0;
- newbrushlist = NULL;
- for (b1 = brushlist; b1; b1 = brushlist)
- {
- lastb2 = b1;
- for (b2 = b1->next; b2; b2 = b2->next)
- {
- //can't merge brushes with different contents
- if (b1->side != b2->side) newbrush = NULL;
- else newbrush = TryMergeBrushes(b1, b2);
- //if a merged brush is created
- if (newbrush)
- {
- //copy the brush contents
- newbrush->side = b1->side;
- //add the new brush to the end of the list
- tail->next = newbrush;
- //remove the second brush from the list
- lastb2->next = b2->next;
- //remove the first brush from the list
- brushlist = brushlist->next;
- //free the merged brushes
- FreeBrush(b1);
- FreeBrush(b2);
- //get a new tail brush
- for (tail = brushlist; tail; tail = tail->next)
- {
- if (!tail->next) break;
- } //end for
- merged++;
- if (!modelnum) qprintf("\r%5d", nummerges++);
- break;
- } //end if
- lastb2 = b2;
- } //end for
- //if b1 can't be merged with any of the other brushes
- if (!b2)
- {
- brushlist = brushlist->next;
- //keep b1
- b1->next = newbrushlist;
- newbrushlist = b1;
- } //end else
- } //end for
- brushlist = newbrushlist;
- } while(merged);
- if (!modelnum) qprintf("\n");
- return newbrushlist;
-} //end of the function Q1_MergeBrushes
-//===========================================================================
-// returns the amount the face and the winding overlap
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float Q1_FaceOnWinding(q1_dface_t *face, winding_t *winding)
-{
- int i, edgenum, side;
- float dist, area;
- q1_dplane_t plane;
- vec_t *v1, *v2;
- vec3_t normal, edgevec;
- winding_t *w;
-
- //
- w = CopyWinding(winding);
- memcpy(&plane, &q1_dplanes[face->planenum], sizeof(q1_dplane_t));
- //check on which side of the plane the face is
- if (face->side)
- {
- VectorNegate(plane.normal, plane.normal);
- plane.dist = -plane.dist;
- } //end if
- for (i = 0; i < face->numedges && w; i++)
- {
- //get the first and second vertex of the edge
- edgenum = q1_dsurfedges[face->firstedge + i];
- side = edgenum > 0;
- //if the face plane is flipped
- v1 = q1_dvertexes[q1_dedges[abs(edgenum)].v[side]].point;
- v2 = q1_dvertexes[q1_dedges[abs(edgenum)].v[!side]].point;
- //create a plane through the edge vector, orthogonal to the face plane
- //and with the normal vector pointing out of the face
- VectorSubtract(v1, v2, edgevec);
- CrossProduct(edgevec, plane.normal, normal);
- VectorNormalize(normal);
- dist = DotProduct(normal, v1);
- //
- ChopWindingInPlace(&w, normal, dist, 0.9); //CLIP_EPSILON
- } //end for
- if (w)
- {
- area = WindingArea(w);
- FreeWinding(w);
- return area;
- } //end if
- return 0;
-} //end of the function Q1_FaceOnWinding
-//===========================================================================
-// returns a list with brushes created by splitting the given brush with
-// planes that go through the face edges and are orthogonal to the face plane
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *Q1_SplitBrushWithFace(bspbrush_t *brush, q1_dface_t *face)
-{
- int i, edgenum, side, planenum, splits;
- float dist;
- q1_dplane_t plane;
- vec_t *v1, *v2;
- vec3_t normal, edgevec;
- bspbrush_t *front, *back, *brushlist;
-
- memcpy(&plane, &q1_dplanes[face->planenum], sizeof(q1_dplane_t));
- //check on which side of the plane the face is
- if (face->side)
- {
- VectorNegate(plane.normal, plane.normal);
- plane.dist = -plane.dist;
- } //end if
- splits = 0;
- brushlist = NULL;
- for (i = 0; i < face->numedges; i++)
- {
- //get the first and second vertex of the edge
- edgenum = q1_dsurfedges[face->firstedge + i];
- side = edgenum > 0;
- //if the face plane is flipped
- v1 = q1_dvertexes[q1_dedges[abs(edgenum)].v[side]].point;
- v2 = q1_dvertexes[q1_dedges[abs(edgenum)].v[!side]].point;
- //create a plane through the edge vector, orthogonal to the face plane
- //and with the normal vector pointing out of the face
- VectorSubtract(v1, v2, edgevec);
- CrossProduct(edgevec, plane.normal, normal);
- VectorNormalize(normal);
- dist = DotProduct(normal, v1);
- //
- planenum = FindFloatPlane(normal, dist);
- //split the current brush
- SplitBrush(brush, planenum, &front, &back);
- //if there is a back brush just put it in the list
- if (back)
- {
- //copy the brush contents
- back->side = brush->side;
- //
- back->next = brushlist;
- brushlist = back;
- splits++;
- } //end if
- if (!front)
- {
- Log_Print("Q1_SplitBrushWithFace: no new brush\n");
- FreeBrushList(brushlist);
- return NULL;
- } //end if
- //copy the brush contents
- front->side = brush->side;
- //continue splitting the front brush
- brush = front;
- } //end for
- if (!splits)
- {
- FreeBrush(front);
- return NULL;
- } //end if
- front->next = brushlist;
- brushlist = front;
- return brushlist;
-} //end of the function Q1_SplitBrushWithFace
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bspbrush_t *Q1_TextureBrushes(bspbrush_t *brushlist, int modelnum)
-{
- float area, largestarea;
- int i, n, texinfonum, sn, numbrushes, ofs;
- int bestfacenum, sidenodenum;
- side_t *side;
- q1_dmiptexlump_t *miptexlump;
- q1_miptex_t *miptex;
- bspbrush_t *brush, *nextbrush, *prevbrush, *newbrushes, *brushlistend;
- vec_t defaultvec[4] = {1, 0, 0, 0};
-
- if (!modelnum) qprintf("texturing brushes\n");
- if (!modelnum) qprintf("%5d brushes", numbrushes = 0);
- //get a pointer to the last brush in the list
- for (brushlistend = brushlist; brushlistend; brushlistend = brushlistend->next)
- {
- if (!brushlistend->next) break;
- } //end for
- //there's no previous brush when at the start of the list
- prevbrush = NULL;
- //go over the brush list
- for (brush = brushlist; brush; brush = nextbrush)
- {
- nextbrush = brush->next;
- //find a texinfo for every brush side
- for (sn = 0; sn < brush->numsides; sn++)
- {
- side = &brush->sides[sn];
- //
- if (side->flags & SFL_TEXTURED) continue;
- //number of the node that created this brush side
- sidenodenum = side->surf; //see midwinding in Q1_SplitBrush
- //no face found yet
- bestfacenum = -1;
- //minimum face size
- largestarea = 1;
- //if optimizing the texture placement and not going for the
- //least number of brushes
- if (!lessbrushes)
- {
- for (i = 0; i < q1_numfaces; i++)
- {
- //the face must be in the same plane as the node plane that created
- //this brush side
- if (q1_dfaces[i].planenum == q1_dnodes[sidenodenum].planenum)
- {
- //get the area the face and the brush side overlap
- area = Q1_FaceOnWinding(&q1_dfaces[i], side->winding);
- //if this face overlaps the brush side winding more than previous faces
- if (area > largestarea)
- {
- //if there already was a face for texturing this brush side with
- //a different texture
- if (bestfacenum >= 0 &&
- (q1_dfaces[bestfacenum].texinfo != q1_dfaces[i].texinfo))
- {
- //split the brush to fit the texture
- newbrushes = Q1_SplitBrushWithFace(brush, &q1_dfaces[i]);
- //if new brushes where created
- if (newbrushes)
- {
- //remove the current brush from the list
- if (prevbrush) prevbrush->next = brush->next;
- else brushlist = brush->next;
- if (brushlistend == brush)
- {
- brushlistend = prevbrush;
- nextbrush = newbrushes;
- } //end if
- //add the new brushes to the end of the list
- if (brushlistend) brushlistend->next = newbrushes;
- else brushlist = newbrushes;
- //free the current brush
- FreeBrush(brush);
- //don't forget about the prevbrush pointer at the bottom of
- //the outer loop
- brush = prevbrush;
- //find the end of the list
- for (brushlistend = brushlist; brushlistend; brushlistend = brushlistend->next)
- {
- if (!brushlistend->next) break;
- } //end for
- break;
- } //end if
- else
- {
- Log_Write("brush %d: no real texture split", numbrushes);
- } //end else
- } //end if
- else
- {
- //best face for texturing this brush side
- bestfacenum = i;
- } //end else
- } //end if
- } //end if
- } //end for
- //if the brush was split the original brush is removed
- //and we just continue with the next one in the list
- if (i < q1_numfaces) break;
- } //end if
- else
- {
- //find the face with the largest overlap with this brush side
- //for texturing the brush side
- for (i = 0; i < q1_numfaces; i++)
- {
- //the face must be in the same plane as the node plane that created
- //this brush side
- if (q1_dfaces[i].planenum == q1_dnodes[sidenodenum].planenum)
- {
- //get the area the face and the brush side overlap
- area = Q1_FaceOnWinding(&q1_dfaces[i], side->winding);
- //if this face overlaps the brush side winding more than previous faces
- if (area > largestarea)
- {
- largestarea = area;
- bestfacenum = i;
- } //end if
- } //end if
- } //end for
- } //end else
- //if a face was found for texturing this brush side
- if (bestfacenum >= 0)
- {
- //set the MAP texinfo values
- texinfonum = q1_dfaces[bestfacenum].texinfo;
- for (n = 0; n < 4; n++)
- {
- map_texinfo[texinfonum].vecs[0][n] = q1_texinfo[texinfonum].vecs[0][n];
- map_texinfo[texinfonum].vecs[1][n] = q1_texinfo[texinfonum].vecs[1][n];
- } //end for
- //make sure the two vectors aren't of zero length otherwise use the default
- //vector to prevent a divide by zero in the map writing
- if (VectorLength(map_texinfo[texinfonum].vecs[0]) < 0.01)
- memcpy(map_texinfo[texinfonum].vecs[0], defaultvec, sizeof(defaultvec));
- if (VectorLength(map_texinfo[texinfonum].vecs[1]) < 0.01)
- memcpy(map_texinfo[texinfonum].vecs[1], defaultvec, sizeof(defaultvec));
- //
- map_texinfo[texinfonum].flags = q1_texinfo[texinfonum].flags;
- map_texinfo[texinfonum].value = 0; //Q1 and HL texinfos don't have a value
- //the mip texture
- miptexlump = (q1_dmiptexlump_t *) q1_dtexdata;
- ofs = miptexlump->dataofs[q1_texinfo[texinfonum].miptex];
- if ( ofs > q1_texdatasize ) {
- ofs = miptexlump->dataofs[0];
- }
- miptex = (q1_miptex_t *)((byte *)miptexlump + ofs);
- //get the mip texture name
- strcpy(map_texinfo[texinfonum].texture, miptex->name);
- //no animations in Quake1 and Half-Life mip textures
- map_texinfo[texinfonum].nexttexinfo = -1;
- //store the texinfo number
- side->texinfo = texinfonum;
- //
- if (texinfonum > map_numtexinfo) map_numtexinfo = texinfonum;
- //this side is textured
- side->flags |= SFL_TEXTURED;
- } //end if
- else
- {
- //no texture for this side
- side->texinfo = TEXINFO_NODE;
- //this side is textured
- side->flags |= SFL_TEXTURED;
- } //end if
- } //end for
- //
- if (!modelnum && prevbrush != brush) qprintf("\r%5d", ++numbrushes);
- //previous brush in the list
- prevbrush = brush;
- } //end for
- if (!modelnum) qprintf("\n");
- //return the new list with brushes
- return brushlist;
-} //end of the function Q1_TextureBrushes
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q1_FixContentsTextures(bspbrush_t *brushlist)
-{
- int i, texinfonum;
- bspbrush_t *brush;
-
- for (brush = brushlist; brush; brush = brush->next)
- {
- //only fix the textures of water, slime and lava brushes
- if (brush->side != CONTENTS_WATER &&
- brush->side != CONTENTS_SLIME &&
- brush->side != CONTENTS_LAVA) continue;
- //
- for (i = 0; i < brush->numsides; i++)
- {
- texinfonum = brush->sides[i].texinfo;
- if (Q1_TextureContents(map_texinfo[texinfonum].texture) == brush->side) break;
- } //end for
- //if no specific contents texture was found
- if (i >= brush->numsides)
- {
- texinfonum = -1;
- for (i = 0; i < map_numtexinfo; i++)
- {
- if (Q1_TextureContents(map_texinfo[i].texture) == brush->side)
- {
- texinfonum = i;
- break;
- } //end if
- } //end for
- } //end if
- //
- if (texinfonum >= 0)
- {
- //give all the brush sides this contents texture
- for (i = 0; i < brush->numsides; i++)
- {
- brush->sides[i].texinfo = texinfonum;
- } //end for
- } //end if
- else Log_Print("brush contents %d with wrong textures\n", brush->side);
- //
- } //end for
- /*
- for (brush = brushlist; brush; brush = brush->next)
- {
- //give all the brush sides this contents texture
- for (i = 0; i < brush->numsides; i++)
- {
- if (Q1_TextureContents(map_texinfo[texinfonum].texture) != brush->side)
- {
- Error("brush contents %d with wrong contents textures %s\n", brush->side,
- Q1_TextureContents(map_texinfo[texinfonum].texture));
- } //end if
- } //end for
- } //end for*/
-} //end of the function Q1_FixContentsTextures
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q1_BSPBrushToMapBrush(bspbrush_t *bspbrush, entity_t *mapent)
-{
- mapbrush_t *mapbrush;
- side_t *side;
- int i, besttexinfo;
-
- CheckBSPBrush(bspbrush);
-
- if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
- Error ("nummapbrushes == MAX_MAPFILE_BRUSHES");
-
- mapbrush = &mapbrushes[nummapbrushes];
- mapbrush->original_sides = &brushsides[nummapbrushsides];
- mapbrush->entitynum = mapent - entities;
- mapbrush->brushnum = nummapbrushes - mapent->firstbrush;
- mapbrush->leafnum = -1;
- mapbrush->numsides = 0;
-
- besttexinfo = TEXINFO_NODE;
- for (i = 0; i < bspbrush->numsides; i++)
- {
- if (!bspbrush->sides[i].winding) continue;
- //
- if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
- Error ("MAX_MAPFILE_BRUSHSIDES");
- side = &brushsides[nummapbrushsides];
- //the contents of the bsp brush is stored in the side variable
- side->contents = bspbrush->side;
- side->surf = 0;
- side->planenum = bspbrush->sides[i].planenum;
- side->texinfo = bspbrush->sides[i].texinfo;
- if (side->texinfo != TEXINFO_NODE)
- {
- //this brush side is textured
- side->flags |= SFL_TEXTURED;
- besttexinfo = side->texinfo;
- } //end if
- //
- nummapbrushsides++;
- mapbrush->numsides++;
- } //end for
- //
- if (besttexinfo == TEXINFO_NODE)
- {
- mapbrush->numsides = 0;
- q1_numclipbrushes++;
- return;
- } //end if
- //set the texinfo for all the brush sides without texture
- for (i = 0; i < mapbrush->numsides; i++)
- {
- if (mapbrush->original_sides[i].texinfo == TEXINFO_NODE)
- {
- mapbrush->original_sides[i].texinfo = besttexinfo;
- } //end if
- } //end for
- //contents of the brush
- mapbrush->contents = bspbrush->side;
- //
- if (create_aas)
- {
- //create the AAS brushes from this brush, add brush bevels
- AAS_CreateMapBrushes(mapbrush, mapent, true);
- return;
- } //end if
- //create windings for sides and bounds for brush
- MakeBrushWindings(mapbrush);
- //add brush bevels
- AddBrushBevels(mapbrush);
- //a new brush has been created
- nummapbrushes++;
- mapent->numbrushes++;
-} //end of the function Q1_BSPBrushToMapBrush
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q1_CreateMapBrushes(entity_t *mapent, int modelnum)
-{
- bspbrush_t *brushlist, *brush, *nextbrush;
- int i;
-
- //create brushes from the model BSP tree
- brushlist = Q1_CreateBrushesFromBSP(modelnum);
- //texture the brushes and split them when necesary
- brushlist = Q1_TextureBrushes(brushlist, modelnum);
- //fix the contents textures of all brushes
- Q1_FixContentsTextures(brushlist);
- //
- if (!nobrushmerge)
- {
- brushlist = Q1_MergeBrushes(brushlist, modelnum);
- //brushlist = Q1_MergeBrushes(brushlist, modelnum);
- } //end if
- //
- if (!modelnum) qprintf("converting brushes to map brushes\n");
- if (!modelnum) qprintf("%5d brushes", i = 0);
- for (brush = brushlist; brush; brush = nextbrush)
- {
- nextbrush = brush->next;
- Q1_BSPBrushToMapBrush(brush, mapent);
- brush->next = NULL;
- FreeBrush(brush);
- if (!modelnum) qprintf("\r%5d", ++i);
- } //end for
- if (!modelnum) qprintf("\n");
-} //end of the function Q1_CreateMapBrushes
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q1_ResetMapLoading(void)
-{
-} //end of the function Q1_ResetMapLoading
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q1_LoadMapFromBSP(char *filename, int offset, int length)
-{
- int i, modelnum;
- char *model, *classname;
-
- Log_Print("-- Q1_LoadMapFromBSP --\n");
- //the loaded map type
- loadedmaptype = MAPTYPE_QUAKE1;
- //
- qprintf("loading map from %s at %d\n", filename, offset);
- //load the Half-Life BSP file
- Q1_LoadBSPFile(filename, offset, length);
- //
- q1_numclipbrushes = 0;
- //CreatePath(path);
- //Q1_CreateQ2WALFiles(path);
- //parse the entities from the BSP
- Q1_ParseEntities();
- //clear the map mins and maxs
- ClearBounds(map_mins, map_maxs);
- //
- qprintf("creating Quake1 brushes\n");
- if (lessbrushes) qprintf("creating minimum number of brushes\n");
- else qprintf("placing textures correctly\n");
- //
- for (i = 0; i < num_entities; i++)
- {
- entities[i].firstbrush = nummapbrushes;
- entities[i].numbrushes = 0;
- //
- classname = ValueForKey(&entities[i], "classname");
- if (classname && !strcmp(classname, "worldspawn"))
- {
- modelnum = 0;
- } //end if
- else
- {
- //
- model = ValueForKey(&entities[i], "model");
- if (!model || *model != '*') continue;
- model++;
- modelnum = atoi(model);
- } //end else
- //create map brushes for the entity
- Q1_CreateMapBrushes(&entities[i], modelnum);
- } //end for
- //
- qprintf("%5d map brushes\n", nummapbrushes);
- qprintf("%5d clip brushes\n", q1_numclipbrushes);
-} //end of the function Q1_LoadMapFromBSP
+/*
+===========================================================================
+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 "l_bsp_q1.h"
+#include "aas_map.h" //AAS_CreateMapBrushes
+
+int q1_numbrushes;
+int q1_numclipbrushes;
+
+//#define Q1_PRINT
+
+//===========================================================================
+// water, slime and lava brush textures names always start with a *
+// followed by the type: "slime", "lava" or otherwise water
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int Q1_TextureContents(char *name)
+{
+ if (!Q_strcasecmp(name, "clip")) return CONTENTS_SOLID;
+ if (name[0] == '*')
+ {
+ if (!Q_strncasecmp(name+1,"lava",4)) return CONTENTS_LAVA;
+ else if (!Q_strncasecmp(name+1,"slime",5)) return CONTENTS_SLIME;
+ else return CONTENTS_WATER;
+ } //end if
+ else if (!Q_strncasecmp(name, "sky", 3)) return CONTENTS_SOLID;
+ else return CONTENTS_SOLID;
+} //end of the function Q1_TextureContents
+//===========================================================================
+// Generates two new brushes, leaving the original
+// unchanged
+//
+// modified for Half-Life because there are quite a lot of tiny node leaves
+// in the Half-Life bsps
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q1_SplitBrush(bspbrush_t *brush, int planenum, int nodenum,
+ bspbrush_t **front, bspbrush_t **back)
+{
+ bspbrush_t *b[2];
+ int i, j;
+ winding_t *w, *cw[2], *midwinding;
+ plane_t *plane, *plane2;
+ side_t *s, *cs;
+ float d, d_front, d_back;
+
+ *front = *back = NULL;
+ plane = &mapplanes[planenum];
+
+ // check all points
+ d_front = d_back = 0;
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ w = brush->sides[i].winding;
+ if (!w)
+ continue;
+ for (j=0 ; j<w->numpoints ; j++)
+ {
+ d = DotProduct (w->p[j], plane->normal) - plane->dist;
+ if (d > 0 && d > d_front)
+ d_front = d;
+ if (d < 0 && d < d_back)
+ d_back = d;
+ } //end for
+ } //end for
+
+ if (d_front < 0.1) // PLANESIDE_EPSILON)
+ { // only on back
+ *back = CopyBrush (brush);
+ Log_Print("Q1_SplitBrush: only on back\n");
+ return;
+ } //end if
+ if (d_back > -0.1) // PLANESIDE_EPSILON)
+ { // only on front
+ *front = CopyBrush (brush);
+ Log_Print("Q1_SplitBrush: only on front\n");
+ return;
+ } //end if
+
+ // create a new winding from the split plane
+
+ w = BaseWindingForPlane (plane->normal, plane->dist);
+ for (i = 0; i < brush->numsides && w; i++)
+ {
+ plane2 = &mapplanes[brush->sides[i].planenum ^ 1];
+ ChopWindingInPlace(&w, plane2->normal, plane2->dist, 0); // PLANESIDE_EPSILON);
+ } //end for
+
+ if (!w || WindingIsTiny(w))
+ { // the brush isn't really split
+ int side;
+
+ Log_Print("Q1_SplitBrush: no split winding\n");
+ side = BrushMostlyOnSide (brush, plane);
+ if (side == PSIDE_FRONT)
+ *front = CopyBrush (brush);
+ if (side == PSIDE_BACK)
+ *back = CopyBrush (brush);
+ return;
+ }
+
+ if (WindingIsHuge(w))
+ {
+ Log_Print("Q1_SplitBrush: WARNING huge split winding\n");
+ } //end of
+
+ midwinding = w;
+
+ // split it for real
+
+ for (i = 0; i < 2; i++)
+ {
+ b[i] = AllocBrush (brush->numsides+1);
+ b[i]->original = brush->original;
+ } //end for
+
+ // split all the current windings
+
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ s = &brush->sides[i];
+ w = s->winding;
+ if (!w)
+ continue;
+ ClipWindingEpsilon (w, plane->normal, plane->dist,
+ 0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]);
+ for (j=0 ; j<2 ; j++)
+ {
+ if (!cw[j])
+ continue;
+#if 0
+ if (WindingIsTiny (cw[j]))
+ {
+ FreeWinding (cw[j]);
+ continue;
+ }
+#endif
+ cs = &b[j]->sides[b[j]->numsides];
+ b[j]->numsides++;
+ *cs = *s;
+// cs->planenum = s->planenum;
+// cs->texinfo = s->texinfo;
+// cs->visible = s->visible;
+// cs->original = s->original;
+ cs->winding = cw[j];
+ cs->flags &= ~SFL_TESTED;
+ } //end for
+ } //end for
+
+
+ // see if we have valid polygons on both sides
+
+ for (i=0 ; i<2 ; i++)
+ {
+ BoundBrush (b[i]);
+ for (j=0 ; j<3 ; j++)
+ {
+ if (b[i]->mins[j] < -4096 || b[i]->maxs[j] > 4096)
+ {
+ Log_Print("Q1_SplitBrush: bogus brush after clip\n");
+ break;
+ } //end if
+ } //end for
+
+ if (b[i]->numsides < 3 || j < 3)
+ {
+ FreeBrush (b[i]);
+ b[i] = NULL;
+ Log_Print("Q1_SplitBrush: numsides < 3\n");
+ } //end if
+ } //end for
+
+ if ( !(b[0] && b[1]) )
+ {
+ if (!b[0] && !b[1])
+ Log_Print("Q1_SplitBrush: split removed brush\n");
+ else
+ Log_Print("Q1_SplitBrush: split not on both sides\n");
+ if (b[0])
+ {
+ FreeBrush (b[0]);
+ *front = CopyBrush (brush);
+ } //end if
+ if (b[1])
+ {
+ FreeBrush (b[1]);
+ *back = CopyBrush (brush);
+ } //end if
+ return;
+ } //end if
+
+ // add the midwinding to both sides
+ for (i = 0; i < 2; i++)
+ {
+ cs = &b[i]->sides[b[i]->numsides];
+ b[i]->numsides++;
+
+ cs->planenum = planenum^i^1;
+ cs->texinfo = 0;
+ //store the node number in the surf to find the texinfo later on
+ cs->surf = nodenum;
+ //
+ cs->flags &= ~SFL_VISIBLE;
+ cs->flags &= ~SFL_TESTED;
+ cs->flags &= ~SFL_TEXTURED;
+ if (i==0)
+ cs->winding = CopyWinding (midwinding);
+ else
+ cs->winding = midwinding;
+ } //end for
+
+
+{
+ vec_t v1;
+ int i;
+
+ for (i=0 ; i<2 ; i++)
+ {
+ v1 = BrushVolume (b[i]);
+ if (v1 < 1)
+ {
+ FreeBrush (b[i]);
+ b[i] = NULL;
+ Log_Print("Q1_SplitBrush: tiny volume after clip\n");
+ } //end if
+ } //end for
+} //*/
+
+ *front = b[0];
+ *back = b[1];
+} //end of the function Q1_SplitBrush
+//===========================================================================
+// returns true if the tree starting at nodenum has only solid leaves
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int Q1_SolidTree_r(int nodenum)
+{
+ if (nodenum < 0)
+ {
+ switch(q1_dleafs[(-nodenum) - 1].contents)
+ {
+ case Q1_CONTENTS_EMPTY:
+ {
+ return false;
+ } //end case
+ case Q1_CONTENTS_SOLID:
+#ifdef HLCONTENTS
+ case Q1_CONTENTS_CLIP:
+#endif HLCONTENTS
+ case Q1_CONTENTS_SKY:
+#ifdef HLCONTENTS
+ case Q1_CONTENTS_TRANSLUCENT:
+#endif HLCONTENTS
+ {
+ return true;
+ } //end case
+ case Q1_CONTENTS_WATER:
+ case Q1_CONTENTS_SLIME:
+ case Q1_CONTENTS_LAVA:
+#ifdef HLCONTENTS
+ //these contents should not be found in the BSP
+ case Q1_CONTENTS_ORIGIN:
+ case Q1_CONTENTS_CURRENT_0:
+ case Q1_CONTENTS_CURRENT_90:
+ case Q1_CONTENTS_CURRENT_180:
+ case Q1_CONTENTS_CURRENT_270:
+ case Q1_CONTENTS_CURRENT_UP:
+ case Q1_CONTENTS_CURRENT_DOWN:
+#endif HLCONTENTS
+ default:
+ {
+ return false;
+ } //end default
+ } //end switch
+ return false;
+ } //end if
+ if (!Q1_SolidTree_r(q1_dnodes[nodenum].children[0])) return false;
+ if (!Q1_SolidTree_r(q1_dnodes[nodenum].children[1])) return false;
+ return true;
+} //end of the function Q1_SolidTree_r
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *Q1_CreateBrushes_r(bspbrush_t *brush, int nodenum)
+{
+ int planenum;
+ bspbrush_t *front, *back;
+ q1_dleaf_t *leaf;
+
+ //if it is a leaf
+ if (nodenum < 0)
+ {
+ leaf = &q1_dleafs[(-nodenum) - 1];
+ if (leaf->contents != Q1_CONTENTS_EMPTY)
+ {
+#ifdef Q1_PRINT
+ qprintf("\r%5i", ++q1_numbrushes);
+#endif //Q1_PRINT
+ } //end if
+ switch(leaf->contents)
+ {
+ case Q1_CONTENTS_EMPTY:
+ {
+ FreeBrush(brush);
+ return NULL;
+ } //end case
+ case Q1_CONTENTS_SOLID:
+#ifdef HLCONTENTS
+ case Q1_CONTENTS_CLIP:
+#endif HLCONTENTS
+ case Q1_CONTENTS_SKY:
+#ifdef HLCONTENTS
+ case Q1_CONTENTS_TRANSLUCENT:
+#endif HLCONTENTS
+ {
+ brush->side = CONTENTS_SOLID;
+ return brush;
+ } //end case
+ case Q1_CONTENTS_WATER:
+ {
+ brush->side = CONTENTS_WATER;
+ return brush;
+ } //end case
+ case Q1_CONTENTS_SLIME:
+ {
+ brush->side = CONTENTS_SLIME;
+ return brush;
+ } //end case
+ case Q1_CONTENTS_LAVA:
+ {
+ brush->side = CONTENTS_LAVA;
+ return brush;
+ } //end case
+#ifdef HLCONTENTS
+ //these contents should not be found in the BSP
+ case Q1_CONTENTS_ORIGIN:
+ case Q1_CONTENTS_CURRENT_0:
+ case Q1_CONTENTS_CURRENT_90:
+ case Q1_CONTENTS_CURRENT_180:
+ case Q1_CONTENTS_CURRENT_270:
+ case Q1_CONTENTS_CURRENT_UP:
+ case Q1_CONTENTS_CURRENT_DOWN:
+ {
+ Error("Q1_CreateBrushes_r: found contents %d in Half-Life BSP", leaf->contents);
+ return NULL;
+ } //end case
+#endif HLCONTENTS
+ default:
+ {
+ Error("Q1_CreateBrushes_r: unknown contents %d in Half-Life BSP", leaf->contents);
+ return NULL;
+ } //end default
+ } //end switch
+ return NULL;
+ } //end if
+ //if the rest of the tree is solid
+ /*if (Q1_SolidTree_r(nodenum))
+ {
+ brush->side = CONTENTS_SOLID;
+ return brush;
+ } //end if*/
+ //
+ planenum = q1_dnodes[nodenum].planenum;
+ planenum = FindFloatPlane(q1_dplanes[planenum].normal, q1_dplanes[planenum].dist);
+ //split the brush with the node plane
+ Q1_SplitBrush(brush, planenum, nodenum, &front, &back);
+ //free the original brush
+ FreeBrush(brush);
+ //every node must split the brush in two
+ if (!front || !back)
+ {
+ Log_Print("Q1_CreateBrushes_r: WARNING node not splitting brush\n");
+ //return NULL;
+ } //end if
+ //create brushes recursively
+ if (front) front = Q1_CreateBrushes_r(front, q1_dnodes[nodenum].children[0]);
+ if (back) back = Q1_CreateBrushes_r(back, q1_dnodes[nodenum].children[1]);
+ //link the brushes if possible and return them
+ if (front)
+ {
+ for (brush = front; brush->next; brush = brush->next);
+ brush->next = back;
+ return front;
+ } //end if
+ else
+ {
+ return back;
+ } //end else
+} //end of the function Q1_CreateBrushes_r
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *Q1_CreateBrushesFromBSP(int modelnum)
+{
+ bspbrush_t *brushlist;
+ bspbrush_t *brush;
+ q1_dnode_t *headnode;
+ vec3_t mins, maxs;
+ int i;
+
+ //
+ headnode = &q1_dnodes[q1_dmodels[modelnum].headnode[0]];
+ //get the mins and maxs of the world
+ VectorCopy(headnode->mins, mins);
+ VectorCopy(headnode->maxs, maxs);
+ //enlarge these mins and maxs
+ for (i = 0; i < 3; i++)
+ {
+ mins[i] -= 8;
+ maxs[i] += 8;
+ } //end for
+ //NOTE: have to add the BSP tree mins and maxs to the MAP mins and maxs
+ AddPointToBounds(mins, map_mins, map_maxs);
+ AddPointToBounds(maxs, map_mins, map_maxs);
+ //
+ if (!modelnum)
+ {
+ Log_Print("brush size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n",
+ map_mins[0], map_mins[1], map_mins[2],
+ map_maxs[0], map_maxs[1], map_maxs[2]);
+ } //end if
+ //create one huge brush containing the whole world
+ brush = BrushFromBounds(mins, maxs);
+ VectorCopy(mins, brush->mins);
+ VectorCopy(maxs, brush->maxs);
+ //
+#ifdef Q1_PRINT
+ qprintf("creating Quake brushes\n");
+ qprintf("%5d brushes", q1_numbrushes = 0);
+#endif //Q1_PRINT
+ //create the brushes
+ brushlist = Q1_CreateBrushes_r(brush, q1_dmodels[modelnum].headnode[0]);
+ //
+#ifdef Q1_PRINT
+ qprintf("\n");
+#endif //Q1_PRINT
+ //now we've got a list with brushes!
+ return brushlist;
+} //end of the function Q1_CreateBrushesFromBSP
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+q1_dleaf_t *Q1_PointInLeaf(int startnode, vec3_t point)
+{
+ int nodenum;
+ vec_t dist;
+ q1_dnode_t *node;
+ q1_dplane_t *plane;
+
+ nodenum = startnode;
+ while (nodenum >= 0)
+ {
+ node = &q1_dnodes[nodenum];
+ plane = &q1_dplanes[node->planenum];
+ dist = DotProduct(point, plane->normal) - plane->dist;
+ if (dist > 0)
+ nodenum = node->children[0];
+ else
+ nodenum = node->children[1];
+ } //end while
+
+ return &q1_dleafs[-nodenum - 1];
+} //end of the function Q1_PointInLeaf
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+float Q1_FaceArea(q1_dface_t *face)
+{
+ int i;
+ float total;
+ vec_t *v;
+ vec3_t d1, d2, cross;
+ q1_dedge_t *edge;
+
+ edge = &q1_dedges[face->firstedge];
+ v = q1_dvertexes[edge->v[0]].point;
+
+ total = 0;
+ for (i = 1; i < face->numedges - 1; i++)
+ {
+ edge = &q1_dedges[face->firstedge + i];
+ VectorSubtract(q1_dvertexes[edge->v[0]].point, v, d1);
+ VectorSubtract(q1_dvertexes[edge->v[1]].point, v, d2);
+ CrossProduct(d1, d2, cross);
+ total += 0.5 * VectorLength(cross);
+ } //end for
+ return total;
+} //end of the function AAS_FaceArea
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q1_FacePlane(q1_dface_t *face, vec3_t normal, float *dist)
+{
+ vec_t *v1, *v2, *v3;
+ vec3_t vec1, vec2;
+ int side, edgenum;
+
+ edgenum = q1_dsurfedges[face->firstedge];
+ side = edgenum < 0;
+ v1 = q1_dvertexes[q1_dedges[abs(edgenum)].v[side]].point;
+ v2 = q1_dvertexes[q1_dedges[abs(edgenum)].v[!side]].point;
+ edgenum = q1_dsurfedges[face->firstedge+1];
+ side = edgenum < 0;
+ v3 = q1_dvertexes[q1_dedges[abs(edgenum)].v[!side]].point;
+ //
+ VectorSubtract(v2, v1, vec1);
+ VectorSubtract(v3, v1, vec2);
+
+ CrossProduct(vec1, vec2, normal);
+ VectorNormalize(normal);
+ *dist = DotProduct(v1, normal);
+} //end of the function Q1_FacePlane
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *Q1_MergeBrushes(bspbrush_t *brushlist, int modelnum)
+{
+ int nummerges, merged;
+ bspbrush_t *b1, *b2, *tail, *newbrush, *newbrushlist;
+ bspbrush_t *lastb2;
+
+ if (!brushlist) return NULL;
+
+ if (!modelnum) qprintf("%5d brushes merged", nummerges = 0);
+ do
+ {
+ for (tail = brushlist; tail; tail = tail->next)
+ {
+ if (!tail->next) break;
+ } //end for
+ merged = 0;
+ newbrushlist = NULL;
+ for (b1 = brushlist; b1; b1 = brushlist)
+ {
+ lastb2 = b1;
+ for (b2 = b1->next; b2; b2 = b2->next)
+ {
+ //can't merge brushes with different contents
+ if (b1->side != b2->side) newbrush = NULL;
+ else newbrush = TryMergeBrushes(b1, b2);
+ //if a merged brush is created
+ if (newbrush)
+ {
+ //copy the brush contents
+ newbrush->side = b1->side;
+ //add the new brush to the end of the list
+ tail->next = newbrush;
+ //remove the second brush from the list
+ lastb2->next = b2->next;
+ //remove the first brush from the list
+ brushlist = brushlist->next;
+ //free the merged brushes
+ FreeBrush(b1);
+ FreeBrush(b2);
+ //get a new tail brush
+ for (tail = brushlist; tail; tail = tail->next)
+ {
+ if (!tail->next) break;
+ } //end for
+ merged++;
+ if (!modelnum) qprintf("\r%5d", nummerges++);
+ break;
+ } //end if
+ lastb2 = b2;
+ } //end for
+ //if b1 can't be merged with any of the other brushes
+ if (!b2)
+ {
+ brushlist = brushlist->next;
+ //keep b1
+ b1->next = newbrushlist;
+ newbrushlist = b1;
+ } //end else
+ } //end for
+ brushlist = newbrushlist;
+ } while(merged);
+ if (!modelnum) qprintf("\n");
+ return newbrushlist;
+} //end of the function Q1_MergeBrushes
+//===========================================================================
+// returns the amount the face and the winding overlap
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+float Q1_FaceOnWinding(q1_dface_t *face, winding_t *winding)
+{
+ int i, edgenum, side;
+ float dist, area;
+ q1_dplane_t plane;
+ vec_t *v1, *v2;
+ vec3_t normal, edgevec;
+ winding_t *w;
+
+ //
+ w = CopyWinding(winding);
+ memcpy(&plane, &q1_dplanes[face->planenum], sizeof(q1_dplane_t));
+ //check on which side of the plane the face is
+ if (face->side)
+ {
+ VectorNegate(plane.normal, plane.normal);
+ plane.dist = -plane.dist;
+ } //end if
+ for (i = 0; i < face->numedges && w; i++)
+ {
+ //get the first and second vertex of the edge
+ edgenum = q1_dsurfedges[face->firstedge + i];
+ side = edgenum > 0;
+ //if the face plane is flipped
+ v1 = q1_dvertexes[q1_dedges[abs(edgenum)].v[side]].point;
+ v2 = q1_dvertexes[q1_dedges[abs(edgenum)].v[!side]].point;
+ //create a plane through the edge vector, orthogonal to the face plane
+ //and with the normal vector pointing out of the face
+ VectorSubtract(v1, v2, edgevec);
+ CrossProduct(edgevec, plane.normal, normal);
+ VectorNormalize(normal);
+ dist = DotProduct(normal, v1);
+ //
+ ChopWindingInPlace(&w, normal, dist, 0.9); //CLIP_EPSILON
+ } //end for
+ if (w)
+ {
+ area = WindingArea(w);
+ FreeWinding(w);
+ return area;
+ } //end if
+ return 0;
+} //end of the function Q1_FaceOnWinding
+//===========================================================================
+// returns a list with brushes created by splitting the given brush with
+// planes that go through the face edges and are orthogonal to the face plane
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *Q1_SplitBrushWithFace(bspbrush_t *brush, q1_dface_t *face)
+{
+ int i, edgenum, side, planenum, splits;
+ float dist;
+ q1_dplane_t plane;
+ vec_t *v1, *v2;
+ vec3_t normal, edgevec;
+ bspbrush_t *front, *back, *brushlist;
+
+ memcpy(&plane, &q1_dplanes[face->planenum], sizeof(q1_dplane_t));
+ //check on which side of the plane the face is
+ if (face->side)
+ {
+ VectorNegate(plane.normal, plane.normal);
+ plane.dist = -plane.dist;
+ } //end if
+ splits = 0;
+ brushlist = NULL;
+ for (i = 0; i < face->numedges; i++)
+ {
+ //get the first and second vertex of the edge
+ edgenum = q1_dsurfedges[face->firstedge + i];
+ side = edgenum > 0;
+ //if the face plane is flipped
+ v1 = q1_dvertexes[q1_dedges[abs(edgenum)].v[side]].point;
+ v2 = q1_dvertexes[q1_dedges[abs(edgenum)].v[!side]].point;
+ //create a plane through the edge vector, orthogonal to the face plane
+ //and with the normal vector pointing out of the face
+ VectorSubtract(v1, v2, edgevec);
+ CrossProduct(edgevec, plane.normal, normal);
+ VectorNormalize(normal);
+ dist = DotProduct(normal, v1);
+ //
+ planenum = FindFloatPlane(normal, dist);
+ //split the current brush
+ SplitBrush(brush, planenum, &front, &back);
+ //if there is a back brush just put it in the list
+ if (back)
+ {
+ //copy the brush contents
+ back->side = brush->side;
+ //
+ back->next = brushlist;
+ brushlist = back;
+ splits++;
+ } //end if
+ if (!front)
+ {
+ Log_Print("Q1_SplitBrushWithFace: no new brush\n");
+ FreeBrushList(brushlist);
+ return NULL;
+ } //end if
+ //copy the brush contents
+ front->side = brush->side;
+ //continue splitting the front brush
+ brush = front;
+ } //end for
+ if (!splits)
+ {
+ FreeBrush(front);
+ return NULL;
+ } //end if
+ front->next = brushlist;
+ brushlist = front;
+ return brushlist;
+} //end of the function Q1_SplitBrushWithFace
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+bspbrush_t *Q1_TextureBrushes(bspbrush_t *brushlist, int modelnum)
+{
+ float area, largestarea;
+ int i, n, texinfonum, sn, numbrushes, ofs;
+ int bestfacenum, sidenodenum;
+ side_t *side;
+ q1_dmiptexlump_t *miptexlump;
+ q1_miptex_t *miptex;
+ bspbrush_t *brush, *nextbrush, *prevbrush, *newbrushes, *brushlistend;
+ vec_t defaultvec[4] = {1, 0, 0, 0};
+
+ if (!modelnum) qprintf("texturing brushes\n");
+ if (!modelnum) qprintf("%5d brushes", numbrushes = 0);
+ //get a pointer to the last brush in the list
+ for (brushlistend = brushlist; brushlistend; brushlistend = brushlistend->next)
+ {
+ if (!brushlistend->next) break;
+ } //end for
+ //there's no previous brush when at the start of the list
+ prevbrush = NULL;
+ //go over the brush list
+ for (brush = brushlist; brush; brush = nextbrush)
+ {
+ nextbrush = brush->next;
+ //find a texinfo for every brush side
+ for (sn = 0; sn < brush->numsides; sn++)
+ {
+ side = &brush->sides[sn];
+ //
+ if (side->flags & SFL_TEXTURED) continue;
+ //number of the node that created this brush side
+ sidenodenum = side->surf; //see midwinding in Q1_SplitBrush
+ //no face found yet
+ bestfacenum = -1;
+ //minimum face size
+ largestarea = 1;
+ //if optimizing the texture placement and not going for the
+ //least number of brushes
+ if (!lessbrushes)
+ {
+ for (i = 0; i < q1_numfaces; i++)
+ {
+ //the face must be in the same plane as the node plane that created
+ //this brush side
+ if (q1_dfaces[i].planenum == q1_dnodes[sidenodenum].planenum)
+ {
+ //get the area the face and the brush side overlap
+ area = Q1_FaceOnWinding(&q1_dfaces[i], side->winding);
+ //if this face overlaps the brush side winding more than previous faces
+ if (area > largestarea)
+ {
+ //if there already was a face for texturing this brush side with
+ //a different texture
+ if (bestfacenum >= 0 &&
+ (q1_dfaces[bestfacenum].texinfo != q1_dfaces[i].texinfo))
+ {
+ //split the brush to fit the texture
+ newbrushes = Q1_SplitBrushWithFace(brush, &q1_dfaces[i]);
+ //if new brushes where created
+ if (newbrushes)
+ {
+ //remove the current brush from the list
+ if (prevbrush) prevbrush->next = brush->next;
+ else brushlist = brush->next;
+ if (brushlistend == brush)
+ {
+ brushlistend = prevbrush;
+ nextbrush = newbrushes;
+ } //end if
+ //add the new brushes to the end of the list
+ if (brushlistend) brushlistend->next = newbrushes;
+ else brushlist = newbrushes;
+ //free the current brush
+ FreeBrush(brush);
+ //don't forget about the prevbrush pointer at the bottom of
+ //the outer loop
+ brush = prevbrush;
+ //find the end of the list
+ for (brushlistend = brushlist; brushlistend; brushlistend = brushlistend->next)
+ {
+ if (!brushlistend->next) break;
+ } //end for
+ break;
+ } //end if
+ else
+ {
+ Log_Write("brush %d: no real texture split", numbrushes);
+ } //end else
+ } //end if
+ else
+ {
+ //best face for texturing this brush side
+ bestfacenum = i;
+ } //end else
+ } //end if
+ } //end if
+ } //end for
+ //if the brush was split the original brush is removed
+ //and we just continue with the next one in the list
+ if (i < q1_numfaces) break;
+ } //end if
+ else
+ {
+ //find the face with the largest overlap with this brush side
+ //for texturing the brush side
+ for (i = 0; i < q1_numfaces; i++)
+ {
+ //the face must be in the same plane as the node plane that created
+ //this brush side
+ if (q1_dfaces[i].planenum == q1_dnodes[sidenodenum].planenum)
+ {
+ //get the area the face and the brush side overlap
+ area = Q1_FaceOnWinding(&q1_dfaces[i], side->winding);
+ //if this face overlaps the brush side winding more than previous faces
+ if (area > largestarea)
+ {
+ largestarea = area;
+ bestfacenum = i;
+ } //end if
+ } //end if
+ } //end for
+ } //end else
+ //if a face was found for texturing this brush side
+ if (bestfacenum >= 0)
+ {
+ //set the MAP texinfo values
+ texinfonum = q1_dfaces[bestfacenum].texinfo;
+ for (n = 0; n < 4; n++)
+ {
+ map_texinfo[texinfonum].vecs[0][n] = q1_texinfo[texinfonum].vecs[0][n];
+ map_texinfo[texinfonum].vecs[1][n] = q1_texinfo[texinfonum].vecs[1][n];
+ } //end for
+ //make sure the two vectors aren't of zero length otherwise use the default
+ //vector to prevent a divide by zero in the map writing
+ if (VectorLength(map_texinfo[texinfonum].vecs[0]) < 0.01)
+ memcpy(map_texinfo[texinfonum].vecs[0], defaultvec, sizeof(defaultvec));
+ if (VectorLength(map_texinfo[texinfonum].vecs[1]) < 0.01)
+ memcpy(map_texinfo[texinfonum].vecs[1], defaultvec, sizeof(defaultvec));
+ //
+ map_texinfo[texinfonum].flags = q1_texinfo[texinfonum].flags;
+ map_texinfo[texinfonum].value = 0; //Q1 and HL texinfos don't have a value
+ //the mip texture
+ miptexlump = (q1_dmiptexlump_t *) q1_dtexdata;
+ ofs = miptexlump->dataofs[q1_texinfo[texinfonum].miptex];
+ if ( ofs > q1_texdatasize ) {
+ ofs = miptexlump->dataofs[0];
+ }
+ miptex = (q1_miptex_t *)((byte *)miptexlump + ofs);
+ //get the mip texture name
+ strcpy(map_texinfo[texinfonum].texture, miptex->name);
+ //no animations in Quake1 and Half-Life mip textures
+ map_texinfo[texinfonum].nexttexinfo = -1;
+ //store the texinfo number
+ side->texinfo = texinfonum;
+ //
+ if (texinfonum > map_numtexinfo) map_numtexinfo = texinfonum;
+ //this side is textured
+ side->flags |= SFL_TEXTURED;
+ } //end if
+ else
+ {
+ //no texture for this side
+ side->texinfo = TEXINFO_NODE;
+ //this side is textured
+ side->flags |= SFL_TEXTURED;
+ } //end if
+ } //end for
+ //
+ if (!modelnum && prevbrush != brush) qprintf("\r%5d", ++numbrushes);
+ //previous brush in the list
+ prevbrush = brush;
+ } //end for
+ if (!modelnum) qprintf("\n");
+ //return the new list with brushes
+ return brushlist;
+} //end of the function Q1_TextureBrushes
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q1_FixContentsTextures(bspbrush_t *brushlist)
+{
+ int i, texinfonum;
+ bspbrush_t *brush;
+
+ for (brush = brushlist; brush; brush = brush->next)
+ {
+ //only fix the textures of water, slime and lava brushes
+ if (brush->side != CONTENTS_WATER &&
+ brush->side != CONTENTS_SLIME &&
+ brush->side != CONTENTS_LAVA) continue;
+ //
+ for (i = 0; i < brush->numsides; i++)
+ {
+ texinfonum = brush->sides[i].texinfo;
+ if (Q1_TextureContents(map_texinfo[texinfonum].texture) == brush->side) break;
+ } //end for
+ //if no specific contents texture was found
+ if (i >= brush->numsides)
+ {
+ texinfonum = -1;
+ for (i = 0; i < map_numtexinfo; i++)
+ {
+ if (Q1_TextureContents(map_texinfo[i].texture) == brush->side)
+ {
+ texinfonum = i;
+ break;
+ } //end if
+ } //end for
+ } //end if
+ //
+ if (texinfonum >= 0)
+ {
+ //give all the brush sides this contents texture
+ for (i = 0; i < brush->numsides; i++)
+ {
+ brush->sides[i].texinfo = texinfonum;
+ } //end for
+ } //end if
+ else Log_Print("brush contents %d with wrong textures\n", brush->side);
+ //
+ } //end for
+ /*
+ for (brush = brushlist; brush; brush = brush->next)
+ {
+ //give all the brush sides this contents texture
+ for (i = 0; i < brush->numsides; i++)
+ {
+ if (Q1_TextureContents(map_texinfo[texinfonum].texture) != brush->side)
+ {
+ Error("brush contents %d with wrong contents textures %s\n", brush->side,
+ Q1_TextureContents(map_texinfo[texinfonum].texture));
+ } //end if
+ } //end for
+ } //end for*/
+} //end of the function Q1_FixContentsTextures
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q1_BSPBrushToMapBrush(bspbrush_t *bspbrush, entity_t *mapent)
+{
+ mapbrush_t *mapbrush;
+ side_t *side;
+ int i, besttexinfo;
+
+ CheckBSPBrush(bspbrush);
+
+ if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
+ Error ("nummapbrushes == MAX_MAPFILE_BRUSHES");
+
+ mapbrush = &mapbrushes[nummapbrushes];
+ mapbrush->original_sides = &brushsides[nummapbrushsides];
+ mapbrush->entitynum = mapent - entities;
+ mapbrush->brushnum = nummapbrushes - mapent->firstbrush;
+ mapbrush->leafnum = -1;
+ mapbrush->numsides = 0;
+
+ besttexinfo = TEXINFO_NODE;
+ for (i = 0; i < bspbrush->numsides; i++)
+ {
+ if (!bspbrush->sides[i].winding) continue;
+ //
+ if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
+ Error ("MAX_MAPFILE_BRUSHSIDES");
+ side = &brushsides[nummapbrushsides];
+ //the contents of the bsp brush is stored in the side variable
+ side->contents = bspbrush->side;
+ side->surf = 0;
+ side->planenum = bspbrush->sides[i].planenum;
+ side->texinfo = bspbrush->sides[i].texinfo;
+ if (side->texinfo != TEXINFO_NODE)
+ {
+ //this brush side is textured
+ side->flags |= SFL_TEXTURED;
+ besttexinfo = side->texinfo;
+ } //end if
+ //
+ nummapbrushsides++;
+ mapbrush->numsides++;
+ } //end for
+ //
+ if (besttexinfo == TEXINFO_NODE)
+ {
+ mapbrush->numsides = 0;
+ q1_numclipbrushes++;
+ return;
+ } //end if
+ //set the texinfo for all the brush sides without texture
+ for (i = 0; i < mapbrush->numsides; i++)
+ {
+ if (mapbrush->original_sides[i].texinfo == TEXINFO_NODE)
+ {
+ mapbrush->original_sides[i].texinfo = besttexinfo;
+ } //end if
+ } //end for
+ //contents of the brush
+ mapbrush->contents = bspbrush->side;
+ //
+ if (create_aas)
+ {
+ //create the AAS brushes from this brush, add brush bevels
+ AAS_CreateMapBrushes(mapbrush, mapent, true);
+ return;
+ } //end if
+ //create windings for sides and bounds for brush
+ MakeBrushWindings(mapbrush);
+ //add brush bevels
+ AddBrushBevels(mapbrush);
+ //a new brush has been created
+ nummapbrushes++;
+ mapent->numbrushes++;
+} //end of the function Q1_BSPBrushToMapBrush
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q1_CreateMapBrushes(entity_t *mapent, int modelnum)
+{
+ bspbrush_t *brushlist, *brush, *nextbrush;
+ int i;
+
+ //create brushes from the model BSP tree
+ brushlist = Q1_CreateBrushesFromBSP(modelnum);
+ //texture the brushes and split them when necesary
+ brushlist = Q1_TextureBrushes(brushlist, modelnum);
+ //fix the contents textures of all brushes
+ Q1_FixContentsTextures(brushlist);
+ //
+ if (!nobrushmerge)
+ {
+ brushlist = Q1_MergeBrushes(brushlist, modelnum);
+ //brushlist = Q1_MergeBrushes(brushlist, modelnum);
+ } //end if
+ //
+ if (!modelnum) qprintf("converting brushes to map brushes\n");
+ if (!modelnum) qprintf("%5d brushes", i = 0);
+ for (brush = brushlist; brush; brush = nextbrush)
+ {
+ nextbrush = brush->next;
+ Q1_BSPBrushToMapBrush(brush, mapent);
+ brush->next = NULL;
+ FreeBrush(brush);
+ if (!modelnum) qprintf("\r%5d", ++i);
+ } //end for
+ if (!modelnum) qprintf("\n");
+} //end of the function Q1_CreateMapBrushes
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q1_ResetMapLoading(void)
+{
+} //end of the function Q1_ResetMapLoading
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q1_LoadMapFromBSP(char *filename, int offset, int length)
+{
+ int i, modelnum;
+ char *model, *classname;
+
+ Log_Print("-- Q1_LoadMapFromBSP --\n");
+ //the loaded map type
+ loadedmaptype = MAPTYPE_QUAKE1;
+ //
+ qprintf("loading map from %s at %d\n", filename, offset);
+ //load the Half-Life BSP file
+ Q1_LoadBSPFile(filename, offset, length);
+ //
+ q1_numclipbrushes = 0;
+ //CreatePath(path);
+ //Q1_CreateQ2WALFiles(path);
+ //parse the entities from the BSP
+ Q1_ParseEntities();
+ //clear the map mins and maxs
+ ClearBounds(map_mins, map_maxs);
+ //
+ qprintf("creating Quake1 brushes\n");
+ if (lessbrushes) qprintf("creating minimum number of brushes\n");
+ else qprintf("placing textures correctly\n");
+ //
+ for (i = 0; i < num_entities; i++)
+ {
+ entities[i].firstbrush = nummapbrushes;
+ entities[i].numbrushes = 0;
+ //
+ classname = ValueForKey(&entities[i], "classname");
+ if (classname && !strcmp(classname, "worldspawn"))
+ {
+ modelnum = 0;
+ } //end if
+ else
+ {
+ //
+ model = ValueForKey(&entities[i], "model");
+ if (!model || *model != '*') continue;
+ model++;
+ modelnum = atoi(model);
+ } //end else
+ //create map brushes for the entity
+ Q1_CreateMapBrushes(&entities[i], modelnum);
+ } //end for
+ //
+ qprintf("%5d map brushes\n", nummapbrushes);
+ qprintf("%5d clip brushes\n", q1_numclipbrushes);
+} //end of the function Q1_LoadMapFromBSP
diff --git a/code/bspc/map_q2.c b/code/bspc/map_q2.c
index 0f15216..a91e78a 100755
--- a/code/bspc/map_q2.c
+++ b/code/bspc/map_q2.c
@@ -1,1162 +1,1162 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-
-//===========================================================================
-// ANSI, Area Navigational System Interface
-// AAS, Area Awareness System
-//===========================================================================
-
-#include "qbsp.h"
-#include "l_mem.h"
-#include "../botlib/aasfile.h" //aas_bbox_t
-#include "aas_store.h" //AAS_MAX_BBOXES
-#include "aas_cfg.h"
-#include "aas_map.h" //AAS_CreateMapBrushes
-#include "l_bsp_q2.h"
-
-
-#ifdef ME
-
-#define NODESTACKSIZE 1024
-
-int nodestack[NODESTACKSIZE];
-int *nodestackptr;
-int nodestacksize = 0;
-int brushmodelnumbers[MAX_MAPFILE_BRUSHES];
-int dbrushleafnums[MAX_MAPFILE_BRUSHES];
-int dplanes2mapplanes[MAX_MAPFILE_PLANES];
-
-#endif //ME
-
-//====================================================================
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q2_CreateMapTexinfo(void)
-{
- int i;
-
- for (i = 0; i < numtexinfo; i++)
- {
- memcpy(map_texinfo[i].vecs, texinfo[i].vecs, sizeof(float) * 2 * 4);
- map_texinfo[i].flags = texinfo[i].flags;
- map_texinfo[i].value = texinfo[i].value;
- strcpy(map_texinfo[i].texture, texinfo[i].texture);
- map_texinfo[i].nexttexinfo = 0;
- } //end for
-} //end of the function Q2_CreateMapTexinfo
-
-/*
-===========
-Q2_BrushContents
-===========
-*/
-int Q2_BrushContents (mapbrush_t *b)
-{
- int contents;
- side_t *s;
- int i;
- int trans;
-
- s = &b->original_sides[0];
- contents = s->contents;
- trans = texinfo[s->texinfo].flags;
- for (i = 1; i < b->numsides; i++, s++)
- {
- s = &b->original_sides[i];
- trans |= texinfo[s->texinfo].flags;
- if (s->contents != contents)
- {
- Log_Print("Entity %i, Brush %i: mixed face contents\n"
- , b->entitynum, b->brushnum);
- Log_Print("texture name = %s\n", texinfo[s->texinfo].texture);
- break;
- }
- }
-
- // if any side is translucent, mark the contents
- // and change solid to window
- if ( trans & (SURF_TRANS33|SURF_TRANS66) )
- {
- contents |= CONTENTS_Q2TRANSLUCENT;
- if (contents & CONTENTS_SOLID)
- {
- contents &= ~CONTENTS_SOLID;
- contents |= CONTENTS_WINDOW;
- }
- }
-
- return contents;
-}
-
-#ifdef ME
-
-#define BBOX_NORMAL_EPSILON 0.0001
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void MakeAreaPortalBrush(mapbrush_t *brush)
-{
- int sn;
- side_t *s;
-
- brush->contents = CONTENTS_AREAPORTAL;
-
- for (sn = 0; sn < brush->numsides; sn++)
- {
- s = brush->original_sides + sn;
- //make sure the surfaces are not hint or skip
- s->surf &= ~(SURF_HINT|SURF_SKIP);
- //
- s->texinfo = 0;
- s->contents = CONTENTS_AREAPORTAL;
- } //end for
-} //end of the function MakeAreaPortalBrush
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void DPlanes2MapPlanes(void)
-{
- int i;
-
- for (i = 0; i < numplanes; i++)
- {
- dplanes2mapplanes[i] = FindFloatPlane(dplanes[i].normal, dplanes[i].dist);
- } //end for
-} //end of the function DPlanes2MapPlanes
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void MarkVisibleBrushSides(mapbrush_t *brush)
-{
- int n, i, planenum;
- side_t *side;
- dface_t *face;
- //
- for (n = 0; n < brush->numsides; n++)
- {
- side = brush->original_sides + n;
- //if this side is a bevel or the leaf number of the brush is unknown
- if ((side->flags & SFL_BEVEL) || brush->leafnum < 0)
- {
- //this side is a valid splitter
- side->flags |= SFL_VISIBLE;
- continue;
- } //end if
- //assum this side will not be used as a splitter
- side->flags &= ~SFL_VISIBLE;
- //check if the side plane is used by a visible face
- for (i = 0; i < numfaces; i++)
- {
- face = &dfaces[i];
- planenum = dplanes2mapplanes[face->planenum];
- if ((planenum & ~1) == (side->planenum & ~1))
- {
- //this side is a valid splitter
- side->flags |= SFL_VISIBLE;
- } //end if
- } //end for
- } //end for
-} //end of the function MarkVisibleBrushSides
-
-#endif //ME
-
-/*
-=================
-Q2_ParseBrush
-=================
-*/
-void Q2_ParseBrush (script_t *script, entity_t *mapent)
-{
- mapbrush_t *b;
- int i, j, k;
- int mt;
- side_t *side, *s2;
- int planenum;
- brush_texture_t td;
- int planepts[3][3];
- token_t token;
-
- if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
- Error ("nummapbrushes == MAX_MAPFILE_BRUSHES");
-
- b = &mapbrushes[nummapbrushes];
- b->original_sides = &brushsides[nummapbrushsides];
- b->entitynum = num_entities-1;
- b->brushnum = nummapbrushes - mapent->firstbrush;
- b->leafnum = -1;
-
- do
- {
- if (!PS_ReadToken(script, &token))
- break;
- if (!strcmp(token.string, "}") )
- break;
-
- //IDBUG: mixed use of MAX_MAPFILE_? and MAX_MAP_? this could
- // lead to out of bound indexing of the arrays
- if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
- Error ("MAX_MAPFILE_BRUSHSIDES");
- side = &brushsides[nummapbrushsides];
-
- //read the three point plane definition
- for (i = 0; i < 3; i++)
- {
- if (i != 0) PS_ExpectTokenString(script, "(");
- for (j = 0; j < 3; j++)
- {
- PS_ExpectAnyToken(script, &token);
- planepts[i][j] = atof(token.string);
- } //end for
- PS_ExpectTokenString(script, ")");
- } //end for
-
- //
- //read the texturedef
- //
- PS_ExpectAnyToken(script, &token);
- strcpy(td.name, token.string);
-
- PS_ExpectAnyToken(script, &token);
- td.shift[0] = atol(token.string);
- PS_ExpectAnyToken(script, &token);
- td.shift[1] = atol(token.string);
- PS_ExpectAnyToken(script, &token);
- td.rotate = atol(token.string);
- PS_ExpectAnyToken(script, &token);
- td.scale[0] = atof(token.string);
- PS_ExpectAnyToken(script, &token);
- td.scale[1] = atof(token.string);
-
- //find default flags and values
- mt = FindMiptex (td.name);
- td.flags = textureref[mt].flags;
- td.value = textureref[mt].value;
- side->contents = textureref[mt].contents;
- side->surf = td.flags = textureref[mt].flags;
-
- //check if there's a number available
- if (PS_CheckTokenType(script, TT_NUMBER, 0, &token))
- {
- side->contents = token.intvalue;
- PS_ExpectTokenType(script, TT_NUMBER, 0, &token);
- side->surf = td.flags = token.intvalue;
- PS_ExpectTokenType(script, TT_NUMBER, 0, &token);
- td.value = token.intvalue;
- }
-
- // translucent objects are automatically classified as detail
- if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
- side->contents |= CONTENTS_DETAIL;
- if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
- side->contents |= CONTENTS_DETAIL;
- if (fulldetail)
- side->contents &= ~CONTENTS_DETAIL;
- if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1)
- | CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST) ) )
- side->contents |= CONTENTS_SOLID;
-
- // hints and skips are never detail, and have no content
- if (side->surf & (SURF_HINT|SURF_SKIP) )
- {
- side->contents = 0;
- side->surf &= ~CONTENTS_DETAIL;
- }
-
-#ifdef ME
- //for creating AAS... this side is textured
- side->flags |= SFL_TEXTURED;
-#endif //ME
- //
- // find the plane number
- //
- planenum = PlaneFromPoints (planepts[0], planepts[1], planepts[2]);
- if (planenum == -1)
- {
- Log_Print("Entity %i, Brush %i: plane with no normal\n"
- , b->entitynum, b->brushnum);
- continue;
- }
-
- //
- // see if the plane has been used already
- //
- for (k=0 ; k<b->numsides ; k++)
- {
- s2 = b->original_sides + k;
- if (s2->planenum == planenum)
- {
- Log_Print("Entity %i, Brush %i: duplicate plane\n"
- , b->entitynum, b->brushnum);
- break;
- }
- if ( s2->planenum == (planenum^1) )
- {
- Log_Print("Entity %i, Brush %i: mirrored plane\n"
- , b->entitynum, b->brushnum);
- break;
- }
- }
- if (k != b->numsides)
- continue; // duplicated
-
- //
- // keep this side
- //
-
- side = b->original_sides + b->numsides;
- side->planenum = planenum;
- side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum],
- &td, vec3_origin);
-
- // save the td off in case there is an origin brush and we
- // have to recalculate the texinfo
- side_brushtextures[nummapbrushsides] = td;
-
- nummapbrushsides++;
- b->numsides++;
- } while (1);
-
- // get the content for the entire brush
- b->contents = Q2_BrushContents (b);
-
-#ifdef ME
- if (BrushExists(b))
- {
- c_squattbrushes++;
- b->numsides = 0;
- return;
- } //end if
-
- if (create_aas)
- {
- //create AAS brushes, and add brush bevels
- AAS_CreateMapBrushes(b, mapent, true);
- //NOTE: if we return here then duplicate plane errors occur for the non world entities
- return;
- } //end if
-#endif //ME
-
- // allow detail brushes to be removed
- if (nodetail && (b->contents & CONTENTS_DETAIL) )
- {
- b->numsides = 0;
- return;
- }
-
- // allow water brushes to be removed
- if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) )
- {
- b->numsides = 0;
- return;
- }
-
- // create windings for sides and bounds for brush
- MakeBrushWindings (b);
-
- // brushes that will not be visible at all will never be
- // used as bsp splitters
- if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
- {
- c_clipbrushes++;
- for (i=0 ; i<b->numsides ; i++)
- b->original_sides[i].texinfo = TEXINFO_NODE;
- }
-
- //
- // origin brushes are removed, but they set
- // the rotation origin for the rest of the brushes
- // in the entity. After the entire entity is parsed,
- // the planenums and texinfos will be adjusted for
- // the origin brush
- //
- if (b->contents & CONTENTS_ORIGIN)
- {
- char string[32];
- vec3_t origin;
-
- if (num_entities == 1)
- {
- Error ("Entity %i, Brush %i: origin brushes not allowed in world"
- , b->entitynum, b->brushnum);
- return;
- }
-
- VectorAdd (b->mins, b->maxs, origin);
- VectorScale (origin, 0.5, origin);
-
- sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
- SetKeyValue (&entities[b->entitynum], "origin", string);
-
- VectorCopy (origin, entities[b->entitynum].origin);
-
- // don't keep this brush
- b->numsides = 0;
-
- return;
- }
-
- AddBrushBevels(b);
-
- nummapbrushes++;
- mapent->numbrushes++;
-}
-
-/*
-================
-Q2_MoveBrushesToWorld
-
-Takes all of the brushes from the current entity and
-adds them to the world's brush list.
-
-Used by func_group and func_areaportal
-================
-*/
-void Q2_MoveBrushesToWorld (entity_t *mapent)
-{
- int newbrushes;
- int worldbrushes;
- mapbrush_t *temp;
- int i;
-
- // this is pretty gross, because the brushes are expected to be
- // in linear order for each entity
-
- newbrushes = mapent->numbrushes;
- worldbrushes = entities[0].numbrushes;
-
- temp = GetMemory(newbrushes*sizeof(mapbrush_t));
- memcpy (temp, mapbrushes + mapent->firstbrush, newbrushes*sizeof(mapbrush_t));
-
-#if 0 // let them keep their original brush numbers
- for (i=0 ; i<newbrushes ; i++)
- temp[i].entitynum = 0;
-#endif
-
- // make space to move the brushes (overlapped copy)
- memmove (mapbrushes + worldbrushes + newbrushes,
- mapbrushes + worldbrushes,
- sizeof(mapbrush_t) * (nummapbrushes - worldbrushes - newbrushes) );
-
- // copy the new brushes down
- memcpy (mapbrushes + worldbrushes, temp, sizeof(mapbrush_t) * newbrushes);
-
- // fix up indexes
- entities[0].numbrushes += newbrushes;
- for (i=1 ; i<num_entities ; i++)
- entities[i].firstbrush += newbrushes;
- FreeMemory(temp);
-
- mapent->numbrushes = 0;
-}
-
-/*
-================
-Q2_ParseMapEntity
-================
-*/
-qboolean Q2_ParseMapEntity(script_t *script)
-{
- entity_t *mapent;
- epair_t *e;
- side_t *s;
- int i, j;
- int startbrush, startsides;
- vec_t newdist;
- mapbrush_t *b;
- token_t token;
-
- if (!PS_ReadToken(script, &token)) return false;
-
- if (strcmp(token.string, "{") )
- Error ("ParseEntity: { not found");
-
- if (num_entities == MAX_MAP_ENTITIES)
- Error ("num_entities == MAX_MAP_ENTITIES");
-
- startbrush = nummapbrushes;
- startsides = nummapbrushsides;
-
- mapent = &entities[num_entities];
- num_entities++;
- memset (mapent, 0, sizeof(*mapent));
- mapent->firstbrush = nummapbrushes;
- mapent->numbrushes = 0;
-// mapent->portalareas[0] = -1;
-// mapent->portalareas[1] = -1;
-
- do
- {
- if (!PS_ReadToken(script, &token))
- {
- Error("ParseEntity: EOF without closing brace");
- } //end if
- if (!strcmp(token.string, "}")) break;
- if (!strcmp(token.string, "{"))
- {
- Q2_ParseBrush(script, mapent);
- } //end if
- else
- {
- PS_UnreadLastToken(script);
- e = ParseEpair(script);
- e->next = mapent->epairs;
- mapent->epairs = e;
- } //end else
- } while(1);
-
- GetVectorForKey(mapent, "origin", mapent->origin);
-
- //
- // if there was an origin brush, offset all of the planes and texinfo
- //
- if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2])
- {
- for (i=0 ; i<mapent->numbrushes ; i++)
- {
- b = &mapbrushes[mapent->firstbrush + i];
- for (j=0 ; j<b->numsides ; j++)
- {
- s = &b->original_sides[j];
- newdist = mapplanes[s->planenum].dist -
- DotProduct (mapplanes[s->planenum].normal, mapent->origin);
- s->planenum = FindFloatPlane (mapplanes[s->planenum].normal, newdist);
- s->texinfo = TexinfoForBrushTexture (&mapplanes[s->planenum],
- &side_brushtextures[s-brushsides], mapent->origin);
- }
- MakeBrushWindings (b);
- }
- }
-
- // group entities are just for editor convenience
- // toss all brushes into the world entity
- if (!strcmp ("func_group", ValueForKey (mapent, "classname")))
- {
- Q2_MoveBrushesToWorld (mapent);
- mapent->numbrushes = 0;
- return true;
- }
-
- // areaportal entities move their brushes, but don't eliminate
- // the entity
- if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname")))
- {
- char str[128];
-
- if (mapent->numbrushes != 1)
- Error ("Entity %i: func_areaportal can only be a single brush", num_entities-1);
-
- b = &mapbrushes[nummapbrushes-1];
- b->contents = CONTENTS_AREAPORTAL;
- c_areaportals++;
- mapent->areaportalnum = c_areaportals;
- // set the portal number as "style"
- sprintf (str, "%i", c_areaportals);
- SetKeyValue (mapent, "style", str);
- Q2_MoveBrushesToWorld (mapent);
- return true;
- }
-
- return true;
-}
-
-//===================================================================
-
-/*
-================
-LoadMapFile
-================
-*/
-void Q2_LoadMapFile(char *filename)
-{
- int i;
- script_t *script;
-
- Log_Print("-- Q2_LoadMapFile --\n");
-#ifdef ME
- //loaded map type
- loadedmaptype = MAPTYPE_QUAKE2;
- //reset the map loading
- ResetMapLoading();
-#endif //ME
-
- script = LoadScriptFile(filename);
- if (!script)
- {
- Log_Print("couldn't open %s\n", filename);
- return;
- } //end if
- //white spaces and escape characters inside a string are not allowed
- SetScriptFlags(script, SCFL_NOSTRINGWHITESPACES |
- SCFL_NOSTRINGESCAPECHARS |
- SCFL_PRIMITIVE);
-
- nummapbrushsides = 0;
- num_entities = 0;
-
- while (Q2_ParseMapEntity(script))
- {
- }
-
- ClearBounds (map_mins, map_maxs);
- for (i=0 ; i<entities[0].numbrushes ; i++)
- {
- if (mapbrushes[i].mins[0] > 4096)
- continue; // no valid points
- AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs);
- AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs);
- } //end for
-
- PrintMapInfo();
-
- //free the script
- FreeScript(script);
-// TestExpandBrushes ();
- //
- Q2_CreateMapTexinfo();
-} //end of the function Q2_LoadMapFile
-
-#ifdef ME //Begin MAP loading from BSP file
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q2_SetLeafBrushesModelNumbers(int leafnum, int modelnum)
-{
- int i, brushnum;
- dleaf_t *leaf;
-
- leaf = &dleafs[leafnum];
- for (i = 0; i < leaf->numleafbrushes; i++)
- {
- brushnum = dleafbrushes[leaf->firstleafbrush + i];
- brushmodelnumbers[brushnum] = modelnum;
- dbrushleafnums[brushnum] = leafnum;
- } //end for
-} //end of the function Q2_SetLeafBrushesModelNumbers
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q2_InitNodeStack(void)
-{
- nodestackptr = nodestack;
- nodestacksize = 0;
-} //end of the function Q2_InitNodeStack
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q2_PushNodeStack(int num)
-{
- *nodestackptr = num;
- nodestackptr++;
- nodestacksize++;
- //
- if (nodestackptr >= &nodestack[NODESTACKSIZE])
- {
- Error("Q2_PushNodeStack: stack overflow\n");
- } //end if
-} //end of the function Q2_PushNodeStack
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int Q2_PopNodeStack(void)
-{
- //if the stack is empty
- if (nodestackptr <= nodestack) return -1;
- //decrease stack pointer
- nodestackptr--;
- nodestacksize--;
- //return the top value from the stack
- return *nodestackptr;
-} //end of the function Q2_PopNodeStack
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q2_SetBrushModelNumbers(entity_t *mapent)
-{
- int n, pn;
- int leafnum;
-
- //
- Q2_InitNodeStack();
- //head node (root) of the bsp tree
- n = dmodels[mapent->modelnum].headnode;
- pn = 0;
-
- do
- {
- //if we are in a leaf (negative node number)
- if (n < 0)
- {
- //number of the leaf
- leafnum = (-n) - 1;
- //set the brush numbers
- Q2_SetLeafBrushesModelNumbers(leafnum, mapent->modelnum);
- //walk back into the tree to find a second child to continue with
- for (pn = Q2_PopNodeStack(); pn >= 0; n = pn, pn = Q2_PopNodeStack())
- {
- //if we took the first child at the parent node
- if (dnodes[pn].children[0] == n) break;
- } //end for
- //if the stack wasn't empty (if not processed whole tree)
- if (pn >= 0)
- {
- //push the parent node again
- Q2_PushNodeStack(pn);
- //we proceed with the second child of the parent node
- n = dnodes[pn].children[1];
- } //end if
- } //end if
- else
- {
- //push the current node onto the stack
- Q2_PushNodeStack(n);
- //walk forward into the tree to the first child
- n = dnodes[n].children[0];
- } //end else
- } while(pn >= 0);
-} //end of the function Q2_SetBrushModelNumbers
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q2_BSPBrushToMapBrush(dbrush_t *bspbrush, entity_t *mapent)
-{
- mapbrush_t *b;
- int i, k, n;
- side_t *side, *s2;
- int planenum;
- dbrushside_t *bspbrushside;
- dplane_t *bspplane;
-
- if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
- Error ("nummapbrushes >= MAX_MAPFILE_BRUSHES");
-
- b = &mapbrushes[nummapbrushes];
- b->original_sides = &brushsides[nummapbrushsides];
- b->entitynum = mapent-entities;
- b->brushnum = nummapbrushes - mapent->firstbrush;
- b->leafnum = dbrushleafnums[bspbrush - dbrushes];
-
- for (n = 0; n < bspbrush->numsides; n++)
- {
- //pointer to the bsp brush side
- bspbrushside = &dbrushsides[bspbrush->firstside + n];
-
- if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
- {
- Error ("MAX_MAPFILE_BRUSHSIDES");
- } //end if
- //pointer to the map brush side
- side = &brushsides[nummapbrushsides];
- //if the BSP brush side is textured
- if (brushsidetextured[bspbrush->firstside + n]) side->flags |= SFL_TEXTURED;
- else side->flags &= ~SFL_TEXTURED;
- //ME: can get side contents and surf directly from BSP file
- side->contents = bspbrush->contents;
- //if the texinfo is TEXINFO_NODE
- if (bspbrushside->texinfo < 0) side->surf = 0;
- else side->surf = texinfo[bspbrushside->texinfo].flags;
-
- // translucent objects are automatically classified as detail
- if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
- side->contents |= CONTENTS_DETAIL;
- if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
- side->contents |= CONTENTS_DETAIL;
- if (fulldetail)
- side->contents &= ~CONTENTS_DETAIL;
- if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1)
- | CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST) ) )
- side->contents |= CONTENTS_SOLID;
-
- // hints and skips are never detail, and have no content
- if (side->surf & (SURF_HINT|SURF_SKIP) )
- {
- side->contents = 0;
- side->surf &= ~CONTENTS_DETAIL;
- }
-
- //ME: get a plane for this side
- bspplane = &dplanes[bspbrushside->planenum];
- planenum = FindFloatPlane(bspplane->normal, bspplane->dist);
- //
- // see if the plane has been used already
- //
- //ME: this really shouldn't happen!!!
- //ME: otherwise the bsp file is corrupted??
- //ME: still it seems to happen, maybe Johny Boy's
- //ME: brush bevel adding is crappy ?
- for (k = 0; k < b->numsides; k++)
- {
- s2 = b->original_sides + k;
-// if (DotProduct (mapplanes[s2->planenum].normal, mapplanes[planenum].normal) > 0.999
-// && fabs(mapplanes[s2->planenum].dist - mapplanes[planenum].dist) < 0.01 )
-
- if (s2->planenum == planenum)
- {
- Log_Print("Entity %i, Brush %i: duplicate plane\n"
- , b->entitynum, b->brushnum);
- break;
- }
- if ( s2->planenum == (planenum^1) )
- {
- Log_Print("Entity %i, Brush %i: mirrored plane\n"
- , b->entitynum, b->brushnum);
- break;
- }
- }
- if (k != b->numsides)
- continue; // duplicated
-
- //
- // keep this side
- //
- //ME: reset pointer to side, why? hell I dunno (pointer is set above already)
- side = b->original_sides + b->numsides;
- //ME: store the plane number
- side->planenum = planenum;
- //ME: texinfo is already stored when bsp is loaded
- //NOTE: check for TEXINFO_NODE, otherwise crash in Q2_BrushContents
- if (bspbrushside->texinfo < 0) side->texinfo = 0;
- else side->texinfo = bspbrushside->texinfo;
-
- // save the td off in case there is an origin brush and we
- // have to recalculate the texinfo
- // ME: don't need to recalculate because it's already done
- // (for non-world entities) in the BSP file
-// side_brushtextures[nummapbrushsides] = td;
-
- nummapbrushsides++;
- b->numsides++;
- } //end for
-
- // get the content for the entire brush
- b->contents = bspbrush->contents;
- Q2_BrushContents(b);
-
- if (BrushExists(b))
- {
- c_squattbrushes++;
- b->numsides = 0;
- return;
- } //end if
-
- //if we're creating AAS
- if (create_aas)
- {
- //create the AAS brushes from this brush, don't add brush bevels
- AAS_CreateMapBrushes(b, mapent, false);
- return;
- } //end if
-
- // allow detail brushes to be removed
- if (nodetail && (b->contents & CONTENTS_DETAIL) )
- {
- b->numsides = 0;
- return;
- } //end if
-
- // allow water brushes to be removed
- if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) )
- {
- b->numsides = 0;
- return;
- } //end if
-
- // create windings for sides and bounds for brush
- MakeBrushWindings(b);
-
- //mark brushes without winding or with a tiny window as bevels
- MarkBrushBevels(b);
-
- // brushes that will not be visible at all will never be
- // used as bsp splitters
- if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
- {
- c_clipbrushes++;
- for (i = 0; i < b->numsides; i++)
- b->original_sides[i].texinfo = TEXINFO_NODE;
- } //end for
-
- //
- // origin brushes are removed, but they set
- // the rotation origin for the rest of the brushes
- // in the entity. After the entire entity is parsed,
- // the planenums and texinfos will be adjusted for
- // the origin brush
- //
- //ME: not needed because the entities in the BSP file already
- // have an origin set
-// if (b->contents & CONTENTS_ORIGIN)
-// {
-// char string[32];
-// vec3_t origin;
-//
-// if (num_entities == 1)
-// {
-// Error ("Entity %i, Brush %i: origin brushes not allowed in world"
-// , b->entitynum, b->brushnum);
-// return;
-// }
-//
-// VectorAdd (b->mins, b->maxs, origin);
-// VectorScale (origin, 0.5, origin);
-//
-// sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
-// SetKeyValue (&entities[b->entitynum], "origin", string);
-//
-// VectorCopy (origin, entities[b->entitynum].origin);
-//
-// // don't keep this brush
-// b->numsides = 0;
-//
-// return;
-// }
-
- //ME: the bsp brushes already have bevels, so we won't try to
- // add them again (especially since Johny Boy's bevel adding might
- // be crappy)
-// AddBrushBevels(b);
-
- nummapbrushes++;
- mapent->numbrushes++;
-} //end of the function Q2_BSPBrushToMapBrush
-//===========================================================================
-//===========================================================================
-void Q2_ParseBSPBrushes(entity_t *mapent)
-{
- int i;
-
- //give all the brushes that belong to this entity the number of the
- //BSP model used by this entity
- Q2_SetBrushModelNumbers(mapent);
- //now parse all the brushes with the correct mapent->modelnum
- for (i = 0; i < numbrushes; i++)
- {
- if (brushmodelnumbers[i] == mapent->modelnum)
- {
- Q2_BSPBrushToMapBrush(&dbrushes[i], mapent);
- } //end if
- } //end for
-} //end of the function Q2_ParseBSPBrushes
-//===========================================================================
-//===========================================================================
-qboolean Q2_ParseBSPEntity(int entnum)
-{
- entity_t *mapent;
- char *model;
- int startbrush, startsides;
-
- startbrush = nummapbrushes;
- startsides = nummapbrushsides;
-
- mapent = &entities[entnum];//num_entities];
- mapent->firstbrush = nummapbrushes;
- mapent->numbrushes = 0;
- mapent->modelnum = -1; //-1 = no model
-
- model = ValueForKey(mapent, "model");
- if (model && strlen(model))
- {
- if (*model != '*')
- {
- Error("Q2_ParseBSPEntity: model number without leading *");
- } //end if
- //get the model number of this entity (skip the leading *)
- mapent->modelnum = atoi(&model[1]);
- } //end if
-
- GetVectorForKey(mapent, "origin", mapent->origin);
-
- //if this is the world entity it has model number zero
- //the world entity has no model key
- if (!strcmp("worldspawn", ValueForKey(mapent, "classname")))
- {
- mapent->modelnum = 0;
- } //end if
- //if the map entity has a BSP model (a modelnum of -1 is used for
- //entities that aren't using a BSP model)
- if (mapent->modelnum >= 0)
- {
- //parse the bsp brushes
- Q2_ParseBSPBrushes(mapent);
- } //end if
- //
- //the origin of the entity is already taken into account
- //
- //func_group entities can't be in the bsp file
- //
- //check out the func_areaportal entities
- if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname")))
- {
- c_areaportals++;
- mapent->areaportalnum = c_areaportals;
- return true;
- } //end if
- return true;
-} //end of the function Q2_ParseBSPEntity
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q2_LoadMapFromBSP(char *filename, int offset, int length)
-{
- int i;
-
- Log_Print("-- Q2_LoadMapFromBSP --\n");
- //loaded map type
- loadedmaptype = MAPTYPE_QUAKE2;
-
- Log_Print("Loading map from %s...\n", filename);
- //load the bsp file
- Q2_LoadBSPFile(filename, offset, length);
-
- //create an index from bsp planes to map planes
- //DPlanes2MapPlanes();
- //clear brush model numbers
- for (i = 0; i < MAX_MAPFILE_BRUSHES; i++)
- brushmodelnumbers[i] = -1;
-
- nummapbrushsides = 0;
- num_entities = 0;
-
- Q2_ParseEntities();
- //
- for (i = 0; i < num_entities; i++)
- {
- Q2_ParseBSPEntity(i);
- } //end for
-
- //get the map mins and maxs from the world model
- ClearBounds(map_mins, map_maxs);
- for (i = 0; i < entities[0].numbrushes; i++)
- {
- if (mapbrushes[i].mins[0] > 4096)
- continue; //no valid points
- AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs);
- AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs);
- } //end for
-
- PrintMapInfo();
- //
- Q2_CreateMapTexinfo();
-} //end of the function Q2_LoadMapFromBSP
-
-void Q2_ResetMapLoading(void)
-{
- //reset for map loading from bsp
- memset(nodestack, 0, NODESTACKSIZE * sizeof(int));
- nodestackptr = NULL;
- nodestacksize = 0;
- memset(brushmodelnumbers, 0, MAX_MAPFILE_BRUSHES * sizeof(int));
-} //end of the function Q2_ResetMapLoading
-
-//End MAP loading from BSP file
-#endif //ME
-
-//====================================================================
-
-/*
-================
-TestExpandBrushes
-
-Expands all the brush planes and saves a new map out
-================
-*/
-void TestExpandBrushes (void)
-{
- FILE *f;
- side_t *s;
- int i, j, bn;
- winding_t *w;
- char *name = "expanded.map";
- mapbrush_t *brush;
- vec_t dist;
-
- Log_Print("writing %s\n", name);
- f = fopen (name, "wb");
- if (!f)
- Error ("Can't write %s\n", name);
-
- fprintf (f, "{\n\"classname\" \"worldspawn\"\n");
-
- for (bn=0 ; bn<nummapbrushes ; bn++)
- {
- brush = &mapbrushes[bn];
- fprintf (f, "{\n");
- for (i=0 ; i<brush->numsides ; i++)
- {
- s = brush->original_sides + i;
- dist = mapplanes[s->planenum].dist;
- for (j=0 ; j<3 ; j++)
- dist += fabs( 16 * mapplanes[s->planenum].normal[j] );
-
- w = BaseWindingForPlane (mapplanes[s->planenum].normal, dist);
-
- fprintf (f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]);
- fprintf (f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]);
- fprintf (f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]);
-
- fprintf (f, "%s 0 0 0 1 1\n", texinfo[s->texinfo].texture);
- FreeWinding (w);
- }
- fprintf (f, "}\n");
- }
- fprintf (f, "}\n");
-
- fclose (f);
-
- Error ("can't proceed after expanding brushes");
-} //end of the function TestExpandBrushes
-
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+//===========================================================================
+// ANSI, Area Navigational System Interface
+// AAS, Area Awareness System
+//===========================================================================
+
+#include "qbsp.h"
+#include "l_mem.h"
+#include "../botlib/aasfile.h" //aas_bbox_t
+#include "aas_store.h" //AAS_MAX_BBOXES
+#include "aas_cfg.h"
+#include "aas_map.h" //AAS_CreateMapBrushes
+#include "l_bsp_q2.h"
+
+
+#ifdef ME
+
+#define NODESTACKSIZE 1024
+
+int nodestack[NODESTACKSIZE];
+int *nodestackptr;
+int nodestacksize = 0;
+int brushmodelnumbers[MAX_MAPFILE_BRUSHES];
+int dbrushleafnums[MAX_MAPFILE_BRUSHES];
+int dplanes2mapplanes[MAX_MAPFILE_PLANES];
+
+#endif //ME
+
+//====================================================================
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q2_CreateMapTexinfo(void)
+{
+ int i;
+
+ for (i = 0; i < numtexinfo; i++)
+ {
+ memcpy(map_texinfo[i].vecs, texinfo[i].vecs, sizeof(float) * 2 * 4);
+ map_texinfo[i].flags = texinfo[i].flags;
+ map_texinfo[i].value = texinfo[i].value;
+ strcpy(map_texinfo[i].texture, texinfo[i].texture);
+ map_texinfo[i].nexttexinfo = 0;
+ } //end for
+} //end of the function Q2_CreateMapTexinfo
+
+/*
+===========
+Q2_BrushContents
+===========
+*/
+int Q2_BrushContents (mapbrush_t *b)
+{
+ int contents;
+ side_t *s;
+ int i;
+ int trans;
+
+ s = &b->original_sides[0];
+ contents = s->contents;
+ trans = texinfo[s->texinfo].flags;
+ for (i = 1; i < b->numsides; i++, s++)
+ {
+ s = &b->original_sides[i];
+ trans |= texinfo[s->texinfo].flags;
+ if (s->contents != contents)
+ {
+ Log_Print("Entity %i, Brush %i: mixed face contents\n"
+ , b->entitynum, b->brushnum);
+ Log_Print("texture name = %s\n", texinfo[s->texinfo].texture);
+ break;
+ }
+ }
+
+ // if any side is translucent, mark the contents
+ // and change solid to window
+ if ( trans & (SURF_TRANS33|SURF_TRANS66) )
+ {
+ contents |= CONTENTS_Q2TRANSLUCENT;
+ if (contents & CONTENTS_SOLID)
+ {
+ contents &= ~CONTENTS_SOLID;
+ contents |= CONTENTS_WINDOW;
+ }
+ }
+
+ return contents;
+}
+
+#ifdef ME
+
+#define BBOX_NORMAL_EPSILON 0.0001
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void MakeAreaPortalBrush(mapbrush_t *brush)
+{
+ int sn;
+ side_t *s;
+
+ brush->contents = CONTENTS_AREAPORTAL;
+
+ for (sn = 0; sn < brush->numsides; sn++)
+ {
+ s = brush->original_sides + sn;
+ //make sure the surfaces are not hint or skip
+ s->surf &= ~(SURF_HINT|SURF_SKIP);
+ //
+ s->texinfo = 0;
+ s->contents = CONTENTS_AREAPORTAL;
+ } //end for
+} //end of the function MakeAreaPortalBrush
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void DPlanes2MapPlanes(void)
+{
+ int i;
+
+ for (i = 0; i < numplanes; i++)
+ {
+ dplanes2mapplanes[i] = FindFloatPlane(dplanes[i].normal, dplanes[i].dist);
+ } //end for
+} //end of the function DPlanes2MapPlanes
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void MarkVisibleBrushSides(mapbrush_t *brush)
+{
+ int n, i, planenum;
+ side_t *side;
+ dface_t *face;
+ //
+ for (n = 0; n < brush->numsides; n++)
+ {
+ side = brush->original_sides + n;
+ //if this side is a bevel or the leaf number of the brush is unknown
+ if ((side->flags & SFL_BEVEL) || brush->leafnum < 0)
+ {
+ //this side is a valid splitter
+ side->flags |= SFL_VISIBLE;
+ continue;
+ } //end if
+ //assum this side will not be used as a splitter
+ side->flags &= ~SFL_VISIBLE;
+ //check if the side plane is used by a visible face
+ for (i = 0; i < numfaces; i++)
+ {
+ face = &dfaces[i];
+ planenum = dplanes2mapplanes[face->planenum];
+ if ((planenum & ~1) == (side->planenum & ~1))
+ {
+ //this side is a valid splitter
+ side->flags |= SFL_VISIBLE;
+ } //end if
+ } //end for
+ } //end for
+} //end of the function MarkVisibleBrushSides
+
+#endif //ME
+
+/*
+=================
+Q2_ParseBrush
+=================
+*/
+void Q2_ParseBrush (script_t *script, entity_t *mapent)
+{
+ mapbrush_t *b;
+ int i, j, k;
+ int mt;
+ side_t *side, *s2;
+ int planenum;
+ brush_texture_t td;
+ int planepts[3][3];
+ token_t token;
+
+ if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
+ Error ("nummapbrushes == MAX_MAPFILE_BRUSHES");
+
+ b = &mapbrushes[nummapbrushes];
+ b->original_sides = &brushsides[nummapbrushsides];
+ b->entitynum = num_entities-1;
+ b->brushnum = nummapbrushes - mapent->firstbrush;
+ b->leafnum = -1;
+
+ do
+ {
+ if (!PS_ReadToken(script, &token))
+ break;
+ if (!strcmp(token.string, "}") )
+ break;
+
+ //IDBUG: mixed use of MAX_MAPFILE_? and MAX_MAP_? this could
+ // lead to out of bound indexing of the arrays
+ if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
+ Error ("MAX_MAPFILE_BRUSHSIDES");
+ side = &brushsides[nummapbrushsides];
+
+ //read the three point plane definition
+ for (i = 0; i < 3; i++)
+ {
+ if (i != 0) PS_ExpectTokenString(script, "(");
+ for (j = 0; j < 3; j++)
+ {
+ PS_ExpectAnyToken(script, &token);
+ planepts[i][j] = atof(token.string);
+ } //end for
+ PS_ExpectTokenString(script, ")");
+ } //end for
+
+ //
+ //read the texturedef
+ //
+ PS_ExpectAnyToken(script, &token);
+ strcpy(td.name, token.string);
+
+ PS_ExpectAnyToken(script, &token);
+ td.shift[0] = atol(token.string);
+ PS_ExpectAnyToken(script, &token);
+ td.shift[1] = atol(token.string);
+ PS_ExpectAnyToken(script, &token);
+ td.rotate = atol(token.string);
+ PS_ExpectAnyToken(script, &token);
+ td.scale[0] = atof(token.string);
+ PS_ExpectAnyToken(script, &token);
+ td.scale[1] = atof(token.string);
+
+ //find default flags and values
+ mt = FindMiptex (td.name);
+ td.flags = textureref[mt].flags;
+ td.value = textureref[mt].value;
+ side->contents = textureref[mt].contents;
+ side->surf = td.flags = textureref[mt].flags;
+
+ //check if there's a number available
+ if (PS_CheckTokenType(script, TT_NUMBER, 0, &token))
+ {
+ side->contents = token.intvalue;
+ PS_ExpectTokenType(script, TT_NUMBER, 0, &token);
+ side->surf = td.flags = token.intvalue;
+ PS_ExpectTokenType(script, TT_NUMBER, 0, &token);
+ td.value = token.intvalue;
+ }
+
+ // translucent objects are automatically classified as detail
+ if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
+ side->contents |= CONTENTS_DETAIL;
+ if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
+ side->contents |= CONTENTS_DETAIL;
+ if (fulldetail)
+ side->contents &= ~CONTENTS_DETAIL;
+ if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1)
+ | CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST) ) )
+ side->contents |= CONTENTS_SOLID;
+
+ // hints and skips are never detail, and have no content
+ if (side->surf & (SURF_HINT|SURF_SKIP) )
+ {
+ side->contents = 0;
+ side->surf &= ~CONTENTS_DETAIL;
+ }
+
+#ifdef ME
+ //for creating AAS... this side is textured
+ side->flags |= SFL_TEXTURED;
+#endif //ME
+ //
+ // find the plane number
+ //
+ planenum = PlaneFromPoints (planepts[0], planepts[1], planepts[2]);
+ if (planenum == -1)
+ {
+ Log_Print("Entity %i, Brush %i: plane with no normal\n"
+ , b->entitynum, b->brushnum);
+ continue;
+ }
+
+ //
+ // see if the plane has been used already
+ //
+ for (k=0 ; k<b->numsides ; k++)
+ {
+ s2 = b->original_sides + k;
+ if (s2->planenum == planenum)
+ {
+ Log_Print("Entity %i, Brush %i: duplicate plane\n"
+ , b->entitynum, b->brushnum);
+ break;
+ }
+ if ( s2->planenum == (planenum^1) )
+ {
+ Log_Print("Entity %i, Brush %i: mirrored plane\n"
+ , b->entitynum, b->brushnum);
+ break;
+ }
+ }
+ if (k != b->numsides)
+ continue; // duplicated
+
+ //
+ // keep this side
+ //
+
+ side = b->original_sides + b->numsides;
+ side->planenum = planenum;
+ side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum],
+ &td, vec3_origin);
+
+ // save the td off in case there is an origin brush and we
+ // have to recalculate the texinfo
+ side_brushtextures[nummapbrushsides] = td;
+
+ nummapbrushsides++;
+ b->numsides++;
+ } while (1);
+
+ // get the content for the entire brush
+ b->contents = Q2_BrushContents (b);
+
+#ifdef ME
+ if (BrushExists(b))
+ {
+ c_squattbrushes++;
+ b->numsides = 0;
+ return;
+ } //end if
+
+ if (create_aas)
+ {
+ //create AAS brushes, and add brush bevels
+ AAS_CreateMapBrushes(b, mapent, true);
+ //NOTE: if we return here then duplicate plane errors occur for the non world entities
+ return;
+ } //end if
+#endif //ME
+
+ // allow detail brushes to be removed
+ if (nodetail && (b->contents & CONTENTS_DETAIL) )
+ {
+ b->numsides = 0;
+ return;
+ }
+
+ // allow water brushes to be removed
+ if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) )
+ {
+ b->numsides = 0;
+ return;
+ }
+
+ // create windings for sides and bounds for brush
+ MakeBrushWindings (b);
+
+ // brushes that will not be visible at all will never be
+ // used as bsp splitters
+ if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
+ {
+ c_clipbrushes++;
+ for (i=0 ; i<b->numsides ; i++)
+ b->original_sides[i].texinfo = TEXINFO_NODE;
+ }
+
+ //
+ // origin brushes are removed, but they set
+ // the rotation origin for the rest of the brushes
+ // in the entity. After the entire entity is parsed,
+ // the planenums and texinfos will be adjusted for
+ // the origin brush
+ //
+ if (b->contents & CONTENTS_ORIGIN)
+ {
+ char string[32];
+ vec3_t origin;
+
+ if (num_entities == 1)
+ {
+ Error ("Entity %i, Brush %i: origin brushes not allowed in world"
+ , b->entitynum, b->brushnum);
+ return;
+ }
+
+ VectorAdd (b->mins, b->maxs, origin);
+ VectorScale (origin, 0.5, origin);
+
+ sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
+ SetKeyValue (&entities[b->entitynum], "origin", string);
+
+ VectorCopy (origin, entities[b->entitynum].origin);
+
+ // don't keep this brush
+ b->numsides = 0;
+
+ return;
+ }
+
+ AddBrushBevels(b);
+
+ nummapbrushes++;
+ mapent->numbrushes++;
+}
+
+/*
+================
+Q2_MoveBrushesToWorld
+
+Takes all of the brushes from the current entity and
+adds them to the world's brush list.
+
+Used by func_group and func_areaportal
+================
+*/
+void Q2_MoveBrushesToWorld (entity_t *mapent)
+{
+ int newbrushes;
+ int worldbrushes;
+ mapbrush_t *temp;
+ int i;
+
+ // this is pretty gross, because the brushes are expected to be
+ // in linear order for each entity
+
+ newbrushes = mapent->numbrushes;
+ worldbrushes = entities[0].numbrushes;
+
+ temp = GetMemory(newbrushes*sizeof(mapbrush_t));
+ memcpy (temp, mapbrushes + mapent->firstbrush, newbrushes*sizeof(mapbrush_t));
+
+#if 0 // let them keep their original brush numbers
+ for (i=0 ; i<newbrushes ; i++)
+ temp[i].entitynum = 0;
+#endif
+
+ // make space to move the brushes (overlapped copy)
+ memmove (mapbrushes + worldbrushes + newbrushes,
+ mapbrushes + worldbrushes,
+ sizeof(mapbrush_t) * (nummapbrushes - worldbrushes - newbrushes) );
+
+ // copy the new brushes down
+ memcpy (mapbrushes + worldbrushes, temp, sizeof(mapbrush_t) * newbrushes);
+
+ // fix up indexes
+ entities[0].numbrushes += newbrushes;
+ for (i=1 ; i<num_entities ; i++)
+ entities[i].firstbrush += newbrushes;
+ FreeMemory(temp);
+
+ mapent->numbrushes = 0;
+}
+
+/*
+================
+Q2_ParseMapEntity
+================
+*/
+qboolean Q2_ParseMapEntity(script_t *script)
+{
+ entity_t *mapent;
+ epair_t *e;
+ side_t *s;
+ int i, j;
+ int startbrush, startsides;
+ vec_t newdist;
+ mapbrush_t *b;
+ token_t token;
+
+ if (!PS_ReadToken(script, &token)) return false;
+
+ if (strcmp(token.string, "{") )
+ Error ("ParseEntity: { not found");
+
+ if (num_entities == MAX_MAP_ENTITIES)
+ Error ("num_entities == MAX_MAP_ENTITIES");
+
+ startbrush = nummapbrushes;
+ startsides = nummapbrushsides;
+
+ mapent = &entities[num_entities];
+ num_entities++;
+ memset (mapent, 0, sizeof(*mapent));
+ mapent->firstbrush = nummapbrushes;
+ mapent->numbrushes = 0;
+// mapent->portalareas[0] = -1;
+// mapent->portalareas[1] = -1;
+
+ do
+ {
+ if (!PS_ReadToken(script, &token))
+ {
+ Error("ParseEntity: EOF without closing brace");
+ } //end if
+ if (!strcmp(token.string, "}")) break;
+ if (!strcmp(token.string, "{"))
+ {
+ Q2_ParseBrush(script, mapent);
+ } //end if
+ else
+ {
+ PS_UnreadLastToken(script);
+ e = ParseEpair(script);
+ e->next = mapent->epairs;
+ mapent->epairs = e;
+ } //end else
+ } while(1);
+
+ GetVectorForKey(mapent, "origin", mapent->origin);
+
+ //
+ // if there was an origin brush, offset all of the planes and texinfo
+ //
+ if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2])
+ {
+ for (i=0 ; i<mapent->numbrushes ; i++)
+ {
+ b = &mapbrushes[mapent->firstbrush + i];
+ for (j=0 ; j<b->numsides ; j++)
+ {
+ s = &b->original_sides[j];
+ newdist = mapplanes[s->planenum].dist -
+ DotProduct (mapplanes[s->planenum].normal, mapent->origin);
+ s->planenum = FindFloatPlane (mapplanes[s->planenum].normal, newdist);
+ s->texinfo = TexinfoForBrushTexture (&mapplanes[s->planenum],
+ &side_brushtextures[s-brushsides], mapent->origin);
+ }
+ MakeBrushWindings (b);
+ }
+ }
+
+ // group entities are just for editor convenience
+ // toss all brushes into the world entity
+ if (!strcmp ("func_group", ValueForKey (mapent, "classname")))
+ {
+ Q2_MoveBrushesToWorld (mapent);
+ mapent->numbrushes = 0;
+ return true;
+ }
+
+ // areaportal entities move their brushes, but don't eliminate
+ // the entity
+ if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname")))
+ {
+ char str[128];
+
+ if (mapent->numbrushes != 1)
+ Error ("Entity %i: func_areaportal can only be a single brush", num_entities-1);
+
+ b = &mapbrushes[nummapbrushes-1];
+ b->contents = CONTENTS_AREAPORTAL;
+ c_areaportals++;
+ mapent->areaportalnum = c_areaportals;
+ // set the portal number as "style"
+ sprintf (str, "%i", c_areaportals);
+ SetKeyValue (mapent, "style", str);
+ Q2_MoveBrushesToWorld (mapent);
+ return true;
+ }
+
+ return true;
+}
+
+//===================================================================
+
+/*
+================
+LoadMapFile
+================
+*/
+void Q2_LoadMapFile(char *filename)
+{
+ int i;
+ script_t *script;
+
+ Log_Print("-- Q2_LoadMapFile --\n");
+#ifdef ME
+ //loaded map type
+ loadedmaptype = MAPTYPE_QUAKE2;
+ //reset the map loading
+ ResetMapLoading();
+#endif //ME
+
+ script = LoadScriptFile(filename);
+ if (!script)
+ {
+ Log_Print("couldn't open %s\n", filename);
+ return;
+ } //end if
+ //white spaces and escape characters inside a string are not allowed
+ SetScriptFlags(script, SCFL_NOSTRINGWHITESPACES |
+ SCFL_NOSTRINGESCAPECHARS |
+ SCFL_PRIMITIVE);
+
+ nummapbrushsides = 0;
+ num_entities = 0;
+
+ while (Q2_ParseMapEntity(script))
+ {
+ }
+
+ ClearBounds (map_mins, map_maxs);
+ for (i=0 ; i<entities[0].numbrushes ; i++)
+ {
+ if (mapbrushes[i].mins[0] > 4096)
+ continue; // no valid points
+ AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs);
+ AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs);
+ } //end for
+
+ PrintMapInfo();
+
+ //free the script
+ FreeScript(script);
+// TestExpandBrushes ();
+ //
+ Q2_CreateMapTexinfo();
+} //end of the function Q2_LoadMapFile
+
+#ifdef ME //Begin MAP loading from BSP file
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q2_SetLeafBrushesModelNumbers(int leafnum, int modelnum)
+{
+ int i, brushnum;
+ dleaf_t *leaf;
+
+ leaf = &dleafs[leafnum];
+ for (i = 0; i < leaf->numleafbrushes; i++)
+ {
+ brushnum = dleafbrushes[leaf->firstleafbrush + i];
+ brushmodelnumbers[brushnum] = modelnum;
+ dbrushleafnums[brushnum] = leafnum;
+ } //end for
+} //end of the function Q2_SetLeafBrushesModelNumbers
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q2_InitNodeStack(void)
+{
+ nodestackptr = nodestack;
+ nodestacksize = 0;
+} //end of the function Q2_InitNodeStack
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q2_PushNodeStack(int num)
+{
+ *nodestackptr = num;
+ nodestackptr++;
+ nodestacksize++;
+ //
+ if (nodestackptr >= &nodestack[NODESTACKSIZE])
+ {
+ Error("Q2_PushNodeStack: stack overflow\n");
+ } //end if
+} //end of the function Q2_PushNodeStack
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int Q2_PopNodeStack(void)
+{
+ //if the stack is empty
+ if (nodestackptr <= nodestack) return -1;
+ //decrease stack pointer
+ nodestackptr--;
+ nodestacksize--;
+ //return the top value from the stack
+ return *nodestackptr;
+} //end of the function Q2_PopNodeStack
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q2_SetBrushModelNumbers(entity_t *mapent)
+{
+ int n, pn;
+ int leafnum;
+
+ //
+ Q2_InitNodeStack();
+ //head node (root) of the bsp tree
+ n = dmodels[mapent->modelnum].headnode;
+ pn = 0;
+
+ do
+ {
+ //if we are in a leaf (negative node number)
+ if (n < 0)
+ {
+ //number of the leaf
+ leafnum = (-n) - 1;
+ //set the brush numbers
+ Q2_SetLeafBrushesModelNumbers(leafnum, mapent->modelnum);
+ //walk back into the tree to find a second child to continue with
+ for (pn = Q2_PopNodeStack(); pn >= 0; n = pn, pn = Q2_PopNodeStack())
+ {
+ //if we took the first child at the parent node
+ if (dnodes[pn].children[0] == n) break;
+ } //end for
+ //if the stack wasn't empty (if not processed whole tree)
+ if (pn >= 0)
+ {
+ //push the parent node again
+ Q2_PushNodeStack(pn);
+ //we proceed with the second child of the parent node
+ n = dnodes[pn].children[1];
+ } //end if
+ } //end if
+ else
+ {
+ //push the current node onto the stack
+ Q2_PushNodeStack(n);
+ //walk forward into the tree to the first child
+ n = dnodes[n].children[0];
+ } //end else
+ } while(pn >= 0);
+} //end of the function Q2_SetBrushModelNumbers
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q2_BSPBrushToMapBrush(dbrush_t *bspbrush, entity_t *mapent)
+{
+ mapbrush_t *b;
+ int i, k, n;
+ side_t *side, *s2;
+ int planenum;
+ dbrushside_t *bspbrushside;
+ dplane_t *bspplane;
+
+ if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
+ Error ("nummapbrushes >= MAX_MAPFILE_BRUSHES");
+
+ b = &mapbrushes[nummapbrushes];
+ b->original_sides = &brushsides[nummapbrushsides];
+ b->entitynum = mapent-entities;
+ b->brushnum = nummapbrushes - mapent->firstbrush;
+ b->leafnum = dbrushleafnums[bspbrush - dbrushes];
+
+ for (n = 0; n < bspbrush->numsides; n++)
+ {
+ //pointer to the bsp brush side
+ bspbrushside = &dbrushsides[bspbrush->firstside + n];
+
+ if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
+ {
+ Error ("MAX_MAPFILE_BRUSHSIDES");
+ } //end if
+ //pointer to the map brush side
+ side = &brushsides[nummapbrushsides];
+ //if the BSP brush side is textured
+ if (brushsidetextured[bspbrush->firstside + n]) side->flags |= SFL_TEXTURED;
+ else side->flags &= ~SFL_TEXTURED;
+ //ME: can get side contents and surf directly from BSP file
+ side->contents = bspbrush->contents;
+ //if the texinfo is TEXINFO_NODE
+ if (bspbrushside->texinfo < 0) side->surf = 0;
+ else side->surf = texinfo[bspbrushside->texinfo].flags;
+
+ // translucent objects are automatically classified as detail
+ if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
+ side->contents |= CONTENTS_DETAIL;
+ if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
+ side->contents |= CONTENTS_DETAIL;
+ if (fulldetail)
+ side->contents &= ~CONTENTS_DETAIL;
+ if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1)
+ | CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST) ) )
+ side->contents |= CONTENTS_SOLID;
+
+ // hints and skips are never detail, and have no content
+ if (side->surf & (SURF_HINT|SURF_SKIP) )
+ {
+ side->contents = 0;
+ side->surf &= ~CONTENTS_DETAIL;
+ }
+
+ //ME: get a plane for this side
+ bspplane = &dplanes[bspbrushside->planenum];
+ planenum = FindFloatPlane(bspplane->normal, bspplane->dist);
+ //
+ // see if the plane has been used already
+ //
+ //ME: this really shouldn't happen!!!
+ //ME: otherwise the bsp file is corrupted??
+ //ME: still it seems to happen, maybe Johny Boy's
+ //ME: brush bevel adding is crappy ?
+ for (k = 0; k < b->numsides; k++)
+ {
+ s2 = b->original_sides + k;
+// if (DotProduct (mapplanes[s2->planenum].normal, mapplanes[planenum].normal) > 0.999
+// && fabs(mapplanes[s2->planenum].dist - mapplanes[planenum].dist) < 0.01 )
+
+ if (s2->planenum == planenum)
+ {
+ Log_Print("Entity %i, Brush %i: duplicate plane\n"
+ , b->entitynum, b->brushnum);
+ break;
+ }
+ if ( s2->planenum == (planenum^1) )
+ {
+ Log_Print("Entity %i, Brush %i: mirrored plane\n"
+ , b->entitynum, b->brushnum);
+ break;
+ }
+ }
+ if (k != b->numsides)
+ continue; // duplicated
+
+ //
+ // keep this side
+ //
+ //ME: reset pointer to side, why? hell I dunno (pointer is set above already)
+ side = b->original_sides + b->numsides;
+ //ME: store the plane number
+ side->planenum = planenum;
+ //ME: texinfo is already stored when bsp is loaded
+ //NOTE: check for TEXINFO_NODE, otherwise crash in Q2_BrushContents
+ if (bspbrushside->texinfo < 0) side->texinfo = 0;
+ else side->texinfo = bspbrushside->texinfo;
+
+ // save the td off in case there is an origin brush and we
+ // have to recalculate the texinfo
+ // ME: don't need to recalculate because it's already done
+ // (for non-world entities) in the BSP file
+// side_brushtextures[nummapbrushsides] = td;
+
+ nummapbrushsides++;
+ b->numsides++;
+ } //end for
+
+ // get the content for the entire brush
+ b->contents = bspbrush->contents;
+ Q2_BrushContents(b);
+
+ if (BrushExists(b))
+ {
+ c_squattbrushes++;
+ b->numsides = 0;
+ return;
+ } //end if
+
+ //if we're creating AAS
+ if (create_aas)
+ {
+ //create the AAS brushes from this brush, don't add brush bevels
+ AAS_CreateMapBrushes(b, mapent, false);
+ return;
+ } //end if
+
+ // allow detail brushes to be removed
+ if (nodetail && (b->contents & CONTENTS_DETAIL) )
+ {
+ b->numsides = 0;
+ return;
+ } //end if
+
+ // allow water brushes to be removed
+ if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) )
+ {
+ b->numsides = 0;
+ return;
+ } //end if
+
+ // create windings for sides and bounds for brush
+ MakeBrushWindings(b);
+
+ //mark brushes without winding or with a tiny window as bevels
+ MarkBrushBevels(b);
+
+ // brushes that will not be visible at all will never be
+ // used as bsp splitters
+ if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
+ {
+ c_clipbrushes++;
+ for (i = 0; i < b->numsides; i++)
+ b->original_sides[i].texinfo = TEXINFO_NODE;
+ } //end for
+
+ //
+ // origin brushes are removed, but they set
+ // the rotation origin for the rest of the brushes
+ // in the entity. After the entire entity is parsed,
+ // the planenums and texinfos will be adjusted for
+ // the origin brush
+ //
+ //ME: not needed because the entities in the BSP file already
+ // have an origin set
+// if (b->contents & CONTENTS_ORIGIN)
+// {
+// char string[32];
+// vec3_t origin;
+//
+// if (num_entities == 1)
+// {
+// Error ("Entity %i, Brush %i: origin brushes not allowed in world"
+// , b->entitynum, b->brushnum);
+// return;
+// }
+//
+// VectorAdd (b->mins, b->maxs, origin);
+// VectorScale (origin, 0.5, origin);
+//
+// sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
+// SetKeyValue (&entities[b->entitynum], "origin", string);
+//
+// VectorCopy (origin, entities[b->entitynum].origin);
+//
+// // don't keep this brush
+// b->numsides = 0;
+//
+// return;
+// }
+
+ //ME: the bsp brushes already have bevels, so we won't try to
+ // add them again (especially since Johny Boy's bevel adding might
+ // be crappy)
+// AddBrushBevels(b);
+
+ nummapbrushes++;
+ mapent->numbrushes++;
+} //end of the function Q2_BSPBrushToMapBrush
+//===========================================================================
+//===========================================================================
+void Q2_ParseBSPBrushes(entity_t *mapent)
+{
+ int i;
+
+ //give all the brushes that belong to this entity the number of the
+ //BSP model used by this entity
+ Q2_SetBrushModelNumbers(mapent);
+ //now parse all the brushes with the correct mapent->modelnum
+ for (i = 0; i < numbrushes; i++)
+ {
+ if (brushmodelnumbers[i] == mapent->modelnum)
+ {
+ Q2_BSPBrushToMapBrush(&dbrushes[i], mapent);
+ } //end if
+ } //end for
+} //end of the function Q2_ParseBSPBrushes
+//===========================================================================
+//===========================================================================
+qboolean Q2_ParseBSPEntity(int entnum)
+{
+ entity_t *mapent;
+ char *model;
+ int startbrush, startsides;
+
+ startbrush = nummapbrushes;
+ startsides = nummapbrushsides;
+
+ mapent = &entities[entnum];//num_entities];
+ mapent->firstbrush = nummapbrushes;
+ mapent->numbrushes = 0;
+ mapent->modelnum = -1; //-1 = no model
+
+ model = ValueForKey(mapent, "model");
+ if (model && strlen(model))
+ {
+ if (*model != '*')
+ {
+ Error("Q2_ParseBSPEntity: model number without leading *");
+ } //end if
+ //get the model number of this entity (skip the leading *)
+ mapent->modelnum = atoi(&model[1]);
+ } //end if
+
+ GetVectorForKey(mapent, "origin", mapent->origin);
+
+ //if this is the world entity it has model number zero
+ //the world entity has no model key
+ if (!strcmp("worldspawn", ValueForKey(mapent, "classname")))
+ {
+ mapent->modelnum = 0;
+ } //end if
+ //if the map entity has a BSP model (a modelnum of -1 is used for
+ //entities that aren't using a BSP model)
+ if (mapent->modelnum >= 0)
+ {
+ //parse the bsp brushes
+ Q2_ParseBSPBrushes(mapent);
+ } //end if
+ //
+ //the origin of the entity is already taken into account
+ //
+ //func_group entities can't be in the bsp file
+ //
+ //check out the func_areaportal entities
+ if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname")))
+ {
+ c_areaportals++;
+ mapent->areaportalnum = c_areaportals;
+ return true;
+ } //end if
+ return true;
+} //end of the function Q2_ParseBSPEntity
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q2_LoadMapFromBSP(char *filename, int offset, int length)
+{
+ int i;
+
+ Log_Print("-- Q2_LoadMapFromBSP --\n");
+ //loaded map type
+ loadedmaptype = MAPTYPE_QUAKE2;
+
+ Log_Print("Loading map from %s...\n", filename);
+ //load the bsp file
+ Q2_LoadBSPFile(filename, offset, length);
+
+ //create an index from bsp planes to map planes
+ //DPlanes2MapPlanes();
+ //clear brush model numbers
+ for (i = 0; i < MAX_MAPFILE_BRUSHES; i++)
+ brushmodelnumbers[i] = -1;
+
+ nummapbrushsides = 0;
+ num_entities = 0;
+
+ Q2_ParseEntities();
+ //
+ for (i = 0; i < num_entities; i++)
+ {
+ Q2_ParseBSPEntity(i);
+ } //end for
+
+ //get the map mins and maxs from the world model
+ ClearBounds(map_mins, map_maxs);
+ for (i = 0; i < entities[0].numbrushes; i++)
+ {
+ if (mapbrushes[i].mins[0] > 4096)
+ continue; //no valid points
+ AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs);
+ AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs);
+ } //end for
+
+ PrintMapInfo();
+ //
+ Q2_CreateMapTexinfo();
+} //end of the function Q2_LoadMapFromBSP
+
+void Q2_ResetMapLoading(void)
+{
+ //reset for map loading from bsp
+ memset(nodestack, 0, NODESTACKSIZE * sizeof(int));
+ nodestackptr = NULL;
+ nodestacksize = 0;
+ memset(brushmodelnumbers, 0, MAX_MAPFILE_BRUSHES * sizeof(int));
+} //end of the function Q2_ResetMapLoading
+
+//End MAP loading from BSP file
+#endif //ME
+
+//====================================================================
+
+/*
+================
+TestExpandBrushes
+
+Expands all the brush planes and saves a new map out
+================
+*/
+void TestExpandBrushes (void)
+{
+ FILE *f;
+ side_t *s;
+ int i, j, bn;
+ winding_t *w;
+ char *name = "expanded.map";
+ mapbrush_t *brush;
+ vec_t dist;
+
+ Log_Print("writing %s\n", name);
+ f = fopen (name, "wb");
+ if (!f)
+ Error ("Can't write %s\n", name);
+
+ fprintf (f, "{\n\"classname\" \"worldspawn\"\n");
+
+ for (bn=0 ; bn<nummapbrushes ; bn++)
+ {
+ brush = &mapbrushes[bn];
+ fprintf (f, "{\n");
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ s = brush->original_sides + i;
+ dist = mapplanes[s->planenum].dist;
+ for (j=0 ; j<3 ; j++)
+ dist += fabs( 16 * mapplanes[s->planenum].normal[j] );
+
+ w = BaseWindingForPlane (mapplanes[s->planenum].normal, dist);
+
+ fprintf (f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]);
+ fprintf (f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]);
+ fprintf (f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]);
+
+ fprintf (f, "%s 0 0 0 1 1\n", texinfo[s->texinfo].texture);
+ FreeWinding (w);
+ }
+ fprintf (f, "}\n");
+ }
+ fprintf (f, "}\n");
+
+ fclose (f);
+
+ Error ("can't proceed after expanding brushes");
+} //end of the function TestExpandBrushes
+
diff --git a/code/bspc/map_q3.c b/code/bspc/map_q3.c
index 750b304..375100c 100755
--- a/code/bspc/map_q3.c
+++ b/code/bspc/map_q3.c
@@ -1,681 +1,681 @@
-/*
-===========================================================================
-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 "l_mem.h"
-#include "../botlib/aasfile.h" //aas_bbox_t
-#include "aas_store.h" //AAS_MAX_BBOXES
-#include "aas_cfg.h"
-#include "aas_map.h" //AAS_CreateMapBrushes
-#include "l_bsp_q3.h"
-#include "../qcommon/cm_patch.h"
-#include "../game/surfaceflags.h"
-
-#define NODESTACKSIZE 1024
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void PrintContents(int contents);
-
-int Q3_BrushContents(mapbrush_t *b)
-{
- int contents, i, mixed, hint;
- side_t *s;
-
- s = &b->original_sides[0];
- contents = s->contents;
- //
- mixed = false;
- hint = false;
- for (i = 1; i < b->numsides; i++)
- {
- s = &b->original_sides[i];
- if (s->contents != contents) mixed = true;
- if (s->surf & (SURF_HINT|SURF_SKIP)) hint = true;
- contents |= s->contents;
- } //end for
- //
- if (hint)
- {
- if (contents)
- {
- Log_Write("WARNING: hint brush with contents: ");
- PrintContents(contents);
- Log_Write("\r\n");
- //
- Log_Write("brush contents is: ");
- PrintContents(b->contents);
- Log_Write("\r\n");
- } //end if
- return 0;
- } //end if
- //Log_Write("brush %d contents ", nummapbrushes);
- //PrintContents(contents);
- //Log_Write("\r\n");
- //remove ladder and fog contents
- contents &= ~(CONTENTS_LADDER|CONTENTS_FOG);
- //
- if (mixed)
- {
- Log_Write("Entity %i, Brush %i: mixed face contents "
- , b->entitynum, b->brushnum);
- PrintContents(contents);
- Log_Write("\r\n");
- //
- Log_Write("brush contents is: ");
- PrintContents(b->contents);
- Log_Write("\r\n");
- //
- if (contents & CONTENTS_DONOTENTER) return CONTENTS_DONOTENTER;//Log_Print("mixed contents with donotenter\n");
- /*
- Log_Print("contents:"); PrintContents(contents);
- Log_Print("\ncontents:"); PrintContents(s->contents);
- Log_Print("\n");
- Log_Print("texture name = %s\n", texinfo[s->texinfo].texture);
- */
- //if liquid brush
- if (contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER))
- {
- return (contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER));
- } //end if
- if (contents & CONTENTS_PLAYERCLIP) return (contents & CONTENTS_PLAYERCLIP);
- return (contents & CONTENTS_SOLID);
- } //end if
- /*
- if (contents & CONTENTS_AREAPORTAL)
- {
- static int num;
- Log_Write("Entity %i, Brush %i: area portal %d\r\n", b->entitynum, b->brushnum, num++);
- } //end if*/
- if (contents == (contents & CONTENTS_STRUCTURAL))
- {
- //Log_Print("brush %i is only structural\n", b->brushnum);
- contents = 0;
- } //end if
- if (contents & CONTENTS_DONOTENTER)
- {
- Log_Print("brush %i is a donotenter brush, c = %X\n", b->brushnum, contents);
- } //end if
- return contents;
-} //end of the function Q3_BrushContents
-#define BBOX_NORMAL_EPSILON 0.0001
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q3_DPlanes2MapPlanes(void)
-{
- int i;
-
- for (i = 0; i < q3_numplanes; i++)
- {
- dplanes2mapplanes[i] = FindFloatPlane(q3_dplanes[i].normal, q3_dplanes[i].dist);
- } //end for
-} //end of the function Q3_DPlanes2MapPlanes
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q3_BSPBrushToMapBrush(q3_dbrush_t *bspbrush, entity_t *mapent)
-{
- mapbrush_t *b;
- int i, k, n;
- side_t *side, *s2;
- int planenum;
- q3_dbrushside_t *bspbrushside;
- q3_dplane_t *bspplane;
-
- if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
- Error ("nummapbrushes >= MAX_MAPFILE_BRUSHES");
-
- b = &mapbrushes[nummapbrushes];
- b->original_sides = &brushsides[nummapbrushsides];
- b->entitynum = mapent-entities;
- b->brushnum = nummapbrushes - mapent->firstbrush;
- b->leafnum = dbrushleafnums[bspbrush - q3_dbrushes];
-
- for (n = 0; n < bspbrush->numSides; n++)
- {
- //pointer to the bsp brush side
- bspbrushside = &q3_dbrushsides[bspbrush->firstSide + n];
-
- if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
- {
- Error ("MAX_MAPFILE_BRUSHSIDES");
- } //end if
- //pointer to the map brush side
- side = &brushsides[nummapbrushsides];
- //if the BSP brush side is textured
- if (q3_dbrushsidetextured[bspbrush->firstSide + n]) side->flags |= SFL_TEXTURED|SFL_VISIBLE;
- else side->flags &= ~SFL_TEXTURED;
- //NOTE: all Quake3 sides are assumed textured
- //side->flags |= SFL_TEXTURED|SFL_VISIBLE;
- //
- if (bspbrushside->shaderNum < 0)
- {
- side->contents = 0;
- side->surf = 0;
- } //end if
- else
- {
- side->contents = q3_dshaders[bspbrushside->shaderNum].contentFlags;
- side->surf = q3_dshaders[bspbrushside->shaderNum].surfaceFlags;
- if (strstr(q3_dshaders[bspbrushside->shaderNum].shader, "common/hint"))
- {
- //Log_Print("found hint side\n");
- side->surf |= SURF_HINT;
- } //end if
- } //end else
- //
- if (side->surf & SURF_NODRAW)
- {
- side->flags |= SFL_TEXTURED|SFL_VISIBLE;
- } //end if
- /*
- if (side->contents & (CONTENTS_TRANSLUCENT|CONTENTS_STRUCTURAL))
- {
- side->flags |= SFL_TEXTURED|SFL_VISIBLE;
- } //end if*/
-
- // hints and skips are never detail, and have no content
- if (side->surf & (SURF_HINT|SURF_SKIP) )
- {
- side->contents = 0;
- //Log_Print("found hint brush side\n");
- }
- /*
- if ((side->surf & SURF_NODRAW) && (side->surf & SURF_NOIMPACT))
- {
- side->contents = 0;
- side->surf &= ~CONTENTS_DETAIL;
- Log_Print("probably found hint brush in a BSP without hints being used\n");
- } //end if*/
-
- //ME: get a plane for this side
- bspplane = &q3_dplanes[bspbrushside->planeNum];
- planenum = FindFloatPlane(bspplane->normal, bspplane->dist);
- //
- // see if the plane has been used already
- //
- //ME: this really shouldn't happen!!!
- //ME: otherwise the bsp file is corrupted??
- //ME: still it seems to happen, maybe Johny Boy's
- //ME: brush bevel adding is crappy ?
- for (k = 0; k < b->numsides; k++)
- {
- s2 = b->original_sides + k;
-// if (DotProduct (mapplanes[s2->planenum].normal, mapplanes[planenum].normal) > 0.999
-// && fabs(mapplanes[s2->planenum].dist - mapplanes[planenum].dist) < 0.01 )
-
- if (s2->planenum == planenum)
- {
- Log_Print("Entity %i, Brush %i: duplicate plane\n"
- , b->entitynum, b->brushnum);
- break;
- }
- if ( s2->planenum == (planenum^1) )
- {
- Log_Print("Entity %i, Brush %i: mirrored plane\n"
- , b->entitynum, b->brushnum);
- break;
- }
- }
- if (k != b->numsides)
- continue; // duplicated
-
- //
- // keep this side
- //
- //ME: reset pointer to side, why? hell I dunno (pointer is set above already)
- side = b->original_sides + b->numsides;
- //ME: store the plane number
- side->planenum = planenum;
- //ME: texinfo is already stored when bsp is loaded
- //NOTE: check for TEXINFO_NODE, otherwise crash in Q3_BrushContents
- //if (bspbrushside->texinfo < 0) side->texinfo = 0;
- //else side->texinfo = bspbrushside->texinfo;
-
- // save the td off in case there is an origin brush and we
- // have to recalculate the texinfo
- // ME: don't need to recalculate because it's already done
- // (for non-world entities) in the BSP file
-// side_brushtextures[nummapbrushsides] = td;
-
- nummapbrushsides++;
- b->numsides++;
- } //end for
-
- // get the content for the entire brush
- b->contents = q3_dshaders[bspbrush->shaderNum].contentFlags;
- b->contents &= ~(CONTENTS_LADDER|CONTENTS_FOG|CONTENTS_STRUCTURAL);
-// b->contents = Q3_BrushContents(b);
- //
-
- if (BrushExists(b))
- {
- c_squattbrushes++;
- b->numsides = 0;
- return;
- } //end if
-
- //if we're creating AAS
- if (create_aas)
- {
- //create the AAS brushes from this brush, don't add brush bevels
- AAS_CreateMapBrushes(b, mapent, false);
- return;
- } //end if
-
- // allow detail brushes to be removed
- if (nodetail && (b->contents & CONTENTS_DETAIL) )
- {
- b->numsides = 0;
- return;
- } //end if
-
- // allow water brushes to be removed
- if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) )
- {
- b->numsides = 0;
- return;
- } //end if
-
- // create windings for sides and bounds for brush
- MakeBrushWindings(b);
-
- //mark brushes without winding or with a tiny window as bevels
- MarkBrushBevels(b);
-
- // brushes that will not be visible at all will never be
- // used as bsp splitters
- if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
- {
- c_clipbrushes++;
- for (i = 0; i < b->numsides; i++)
- b->original_sides[i].texinfo = TEXINFO_NODE;
- } //end for
-
- //
- // origin brushes are removed, but they set
- // the rotation origin for the rest of the brushes
- // in the entity. After the entire entity is parsed,
- // the planenums and texinfos will be adjusted for
- // the origin brush
- //
- //ME: not needed because the entities in the BSP file already
- // have an origin set
-// if (b->contents & CONTENTS_ORIGIN)
-// {
-// char string[32];
-// vec3_t origin;
-//
-// if (num_entities == 1)
-// {
-// Error ("Entity %i, Brush %i: origin brushes not allowed in world"
-// , b->entitynum, b->brushnum);
-// return;
-// }
-//
-// VectorAdd (b->mins, b->maxs, origin);
-// VectorScale (origin, 0.5, origin);
-//
-// sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
-// SetKeyValue (&entities[b->entitynum], "origin", string);
-//
-// VectorCopy (origin, entities[b->entitynum].origin);
-//
-// // don't keep this brush
-// b->numsides = 0;
-//
-// return;
-// }
-
- //ME: the bsp brushes already have bevels, so we won't try to
- // add them again (especially since Johny Boy's bevel adding might
- // be crappy)
-// AddBrushBevels(b);
-
- nummapbrushes++;
- mapent->numbrushes++;
-} //end of the function Q3_BSPBrushToMapBrush
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q3_ParseBSPBrushes(entity_t *mapent)
-{
- int i;
-
- for (i = 0; i < q3_dmodels[mapent->modelnum].numBrushes; i++)
- {
- Q3_BSPBrushToMapBrush(&q3_dbrushes[q3_dmodels[mapent->modelnum].firstBrush + i], mapent);
- } //end for
-} //end of the function Q3_ParseBSPBrushes
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean Q3_ParseBSPEntity(int entnum)
-{
- entity_t *mapent;
- char *model;
- int startbrush, startsides;
-
- startbrush = nummapbrushes;
- startsides = nummapbrushsides;
-
- mapent = &entities[entnum];//num_entities];
- mapent->firstbrush = nummapbrushes;
- mapent->numbrushes = 0;
- mapent->modelnum = -1; //-1 = no BSP model
-
- model = ValueForKey(mapent, "model");
- if (model && strlen(model))
- {
- if (*model == '*')
- {
- //get the model number of this entity (skip the leading *)
- mapent->modelnum = atoi(&model[1]);
- } //end if
- } //end if
-
- GetVectorForKey(mapent, "origin", mapent->origin);
-
- //if this is the world entity it has model number zero
- //the world entity has no model key
- if (!strcmp("worldspawn", ValueForKey(mapent, "classname")))
- {
- mapent->modelnum = 0;
- } //end if
- //if the map entity has a BSP model (a modelnum of -1 is used for
- //entities that aren't using a BSP model)
- if (mapent->modelnum >= 0)
- {
- //parse the bsp brushes
- Q3_ParseBSPBrushes(mapent);
- } //end if
- //
- //the origin of the entity is already taken into account
- //
- //func_group entities can't be in the bsp file
- //
- //check out the func_areaportal entities
- if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname")))
- {
- c_areaportals++;
- mapent->areaportalnum = c_areaportals;
- return true;
- } //end if
- return true;
-} //end of the function Q3_ParseBSPEntity
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#define MAX_PATCH_VERTS 1024
-
-void AAS_CreateCurveBrushes(void)
-{
- int i, j, n, planenum, numcurvebrushes = 0;
- q3_dsurface_t *surface;
- q3_drawVert_t *dv_p;
- vec3_t points[MAX_PATCH_VERTS];
- int width, height, c;
- patchCollide_t *pc;
- facet_t *facet;
- mapbrush_t *brush;
- side_t *side;
- entity_t *mapent;
- winding_t *winding;
-
- qprintf("nummapbrushsides = %d\n", nummapbrushsides);
- mapent = &entities[0];
- for (i = 0; i < q3_numDrawSurfaces; i++)
- {
- surface = &q3_drawSurfaces[i];
- if ( ! surface->patchWidth ) continue;
- // if the curve is not solid
- if (!(q3_dshaders[surface->shaderNum].contentFlags & (CONTENTS_SOLID|CONTENTS_PLAYERCLIP)))
- {
- //Log_Print("skipped non-solid curve\n");
- continue;
- } //end if
- // if this curve should not be used for AAS
- if ( q3_dshaders[surface->shaderNum].contentFlags & CONTENTS_NOBOTCLIP ) {
- continue;
- }
- //
- width = surface->patchWidth;
- height = surface->patchHeight;
- c = width * height;
- if (c > MAX_PATCH_VERTS)
- {
- Error("ParseMesh: MAX_PATCH_VERTS");
- } //end if
-
- dv_p = q3_drawVerts + surface->firstVert;
- for ( j = 0 ; j < c ; j++, dv_p++ )
- {
- points[j][0] = dv_p->xyz[0];
- points[j][1] = dv_p->xyz[1];
- points[j][2] = dv_p->xyz[2];
- } //end for
- // create the internal facet structure
- pc = CM_GeneratePatchCollide(width, height, points);
- //
- for (j = 0; j < pc->numFacets; j++)
- {
- facet = &pc->facets[j];
- //
- brush = &mapbrushes[nummapbrushes];
- brush->original_sides = &brushsides[nummapbrushsides];
- brush->entitynum = 0;
- brush->brushnum = nummapbrushes - mapent->firstbrush;
- //
- brush->numsides = facet->numBorders + 2;
- nummapbrushsides += brush->numsides;
- brush->contents = CONTENTS_SOLID;
- //
- //qprintf("\r%6d curve brushes", nummapbrushsides);//++numcurvebrushes);
- qprintf("\r%6d curve brushes", ++numcurvebrushes);
- //
- planenum = FindFloatPlane(pc->planes[facet->surfacePlane].plane, pc->planes[facet->surfacePlane].plane[3]);
- //
- side = &brush->original_sides[0];
- side->planenum = planenum;
- side->contents = CONTENTS_SOLID;
- side->flags |= SFL_TEXTURED|SFL_VISIBLE|SFL_CURVE;
- side->surf = 0;
- //
- side = &brush->original_sides[1];
- if (create_aas)
- {
- //the plane is expanded later so it's not a problem that
- //these first two opposite sides are coplanar
- side->planenum = planenum ^ 1;
- } //end if
- else
- {
- side->planenum = FindFloatPlane(mapplanes[planenum^1].normal, mapplanes[planenum^1].dist + 1);
- side->flags |= SFL_TEXTURED|SFL_VISIBLE;
- } //end else
- side->contents = CONTENTS_SOLID;
- side->flags |= SFL_CURVE;
- side->surf = 0;
- //
- winding = BaseWindingForPlane(mapplanes[side->planenum].normal, mapplanes[side->planenum].dist);
- for (n = 0; n < facet->numBorders; n++)
- {
- //never use the surface plane as a border
- if (facet->borderPlanes[n] == facet->surfacePlane) continue;
- //
- side = &brush->original_sides[2 + n];
- side->planenum = FindFloatPlane(pc->planes[facet->borderPlanes[n]].plane, pc->planes[facet->borderPlanes[n]].plane[3]);
- if (facet->borderInward[n]) side->planenum ^= 1;
- side->contents = CONTENTS_SOLID;
- side->flags |= SFL_TEXTURED|SFL_CURVE;
- side->surf = 0;
- //chop the winding in place
- if (winding) ChopWindingInPlace(&winding, mapplanes[side->planenum^1].normal, mapplanes[side->planenum^1].dist, 0.1); //CLIP_EPSILON);
- } //end for
- //VectorCopy(pc->bounds[0], brush->mins);
- //VectorCopy(pc->bounds[1], brush->maxs);
- if (!winding)
- {
- Log_Print("WARNING: AAS_CreateCurveBrushes: no winding\n");
- brush->numsides = 0;
- continue;
- } //end if
- brush->original_sides[0].winding = winding;
- WindingBounds(winding, brush->mins, brush->maxs);
- for (n = 0; n < 3; n++)
- {
- //IDBUG: all the indexes into the mins and maxs were zero (not using i)
- if (brush->mins[n] < -MAX_MAP_BOUNDS || brush->maxs[n] > MAX_MAP_BOUNDS)
- {
- Log_Print("entity %i, brush %i: bounds out of range\n", brush->entitynum, brush->brushnum);
- Log_Print("brush->mins[%d] = %f, brush->maxs[%d] = %f\n", n, brush->mins[n], n, brush->maxs[n]);
- brush->numsides = 0; //remove the brush
- break;
- } //end if
- if (brush->mins[n] > MAX_MAP_BOUNDS || brush->maxs[n] < -MAX_MAP_BOUNDS)
- {
- Log_Print("entity %i, brush %i: no visible sides on brush\n", brush->entitynum, brush->brushnum);
- Log_Print("brush->mins[%d] = %f, brush->maxs[%d] = %f\n", n, brush->mins[n], n, brush->maxs[n]);
- brush->numsides = 0; //remove the brush
- break;
- } //end if
- } //end for
- if (create_aas)
- {
- //NOTE: brush bevels now already added
- //AddBrushBevels(brush);
- AAS_CreateMapBrushes(brush, mapent, false);
- } //end if
- else
- {
- // create windings for sides and bounds for brush
- MakeBrushWindings(brush);
- AddBrushBevels(brush);
- nummapbrushes++;
- mapent->numbrushes++;
- } //end else
- } //end for
- } //end for
- //qprintf("\r%6d curve brushes", nummapbrushsides);//++numcurvebrushes);
- qprintf("\r%6d curve brushes\n", numcurvebrushes);
-} //end of the function AAS_CreateCurveBrushes
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ExpandMapBrush(mapbrush_t *brush, vec3_t mins, vec3_t maxs);
-
-void Q3_LoadMapFromBSP(struct quakefile_s *qf)
-{
- int i;
- vec3_t mins = {-1,-1,-1}, maxs = {1, 1, 1};
-
- Log_Print("-- Q3_LoadMapFromBSP --\n");
- //loaded map type
- loadedmaptype = MAPTYPE_QUAKE3;
-
- Log_Print("Loading map from %s...\n", qf->filename);
- //load the bsp file
- Q3_LoadBSPFile(qf);
-
- //create an index from bsp planes to map planes
- //DPlanes2MapPlanes();
- //clear brush model numbers
- for (i = 0; i < MAX_MAPFILE_BRUSHES; i++)
- brushmodelnumbers[i] = -1;
-
- nummapbrushsides = 0;
- num_entities = 0;
-
- Q3_ParseEntities();
- //
- for (i = 0; i < num_entities; i++)
- {
- Q3_ParseBSPEntity(i);
- } //end for
-
- AAS_CreateCurveBrushes();
- //get the map mins and maxs from the world model
- ClearBounds(map_mins, map_maxs);
- for (i = 0; i < entities[0].numbrushes; i++)
- {
- if (mapbrushes[i].numsides <= 0)
- continue;
- AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs);
- AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs);
- } //end for
- /*/
- for (i = 0; i < nummapbrushes; i++)
- {
- //if (!mapbrushes[i].original_sides) continue;
- //AddBrushBevels(&mapbrushes[i]);
- //AAS_ExpandMapBrush(&mapbrushes[i], mins, maxs);
- } //end for*/
- /*
- for (i = 0; i < nummapbrushsides; i++)
- {
- Log_Write("side %d flags = %d", i, brushsides[i].flags);
- } //end for
- for (i = 0; i < nummapbrushes; i++)
- {
- Log_Write("brush contents: ");
- PrintContents(mapbrushes[i].contents);
- Log_Print("\n");
- } //end for*/
-} //end of the function Q3_LoadMapFromBSP
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q3_ResetMapLoading(void)
-{
- //reset for map loading from bsp
- memset(nodestack, 0, NODESTACKSIZE * sizeof(int));
- nodestackptr = NULL;
- nodestacksize = 0;
- memset(brushmodelnumbers, 0, MAX_MAPFILE_BRUSHES * sizeof(int));
-} //end of the function Q3_ResetMapLoading
-
+/*
+===========================================================================
+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 "l_mem.h"
+#include "../botlib/aasfile.h" //aas_bbox_t
+#include "aas_store.h" //AAS_MAX_BBOXES
+#include "aas_cfg.h"
+#include "aas_map.h" //AAS_CreateMapBrushes
+#include "l_bsp_q3.h"
+#include "../qcommon/cm_patch.h"
+#include "../game/surfaceflags.h"
+
+#define NODESTACKSIZE 1024
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void PrintContents(int contents);
+
+int Q3_BrushContents(mapbrush_t *b)
+{
+ int contents, i, mixed, hint;
+ side_t *s;
+
+ s = &b->original_sides[0];
+ contents = s->contents;
+ //
+ mixed = false;
+ hint = false;
+ for (i = 1; i < b->numsides; i++)
+ {
+ s = &b->original_sides[i];
+ if (s->contents != contents) mixed = true;
+ if (s->surf & (SURF_HINT|SURF_SKIP)) hint = true;
+ contents |= s->contents;
+ } //end for
+ //
+ if (hint)
+ {
+ if (contents)
+ {
+ Log_Write("WARNING: hint brush with contents: ");
+ PrintContents(contents);
+ Log_Write("\r\n");
+ //
+ Log_Write("brush contents is: ");
+ PrintContents(b->contents);
+ Log_Write("\r\n");
+ } //end if
+ return 0;
+ } //end if
+ //Log_Write("brush %d contents ", nummapbrushes);
+ //PrintContents(contents);
+ //Log_Write("\r\n");
+ //remove ladder and fog contents
+ contents &= ~(CONTENTS_LADDER|CONTENTS_FOG);
+ //
+ if (mixed)
+ {
+ Log_Write("Entity %i, Brush %i: mixed face contents "
+ , b->entitynum, b->brushnum);
+ PrintContents(contents);
+ Log_Write("\r\n");
+ //
+ Log_Write("brush contents is: ");
+ PrintContents(b->contents);
+ Log_Write("\r\n");
+ //
+ if (contents & CONTENTS_DONOTENTER) return CONTENTS_DONOTENTER;//Log_Print("mixed contents with donotenter\n");
+ /*
+ Log_Print("contents:"); PrintContents(contents);
+ Log_Print("\ncontents:"); PrintContents(s->contents);
+ Log_Print("\n");
+ Log_Print("texture name = %s\n", texinfo[s->texinfo].texture);
+ */
+ //if liquid brush
+ if (contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER))
+ {
+ return (contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER));
+ } //end if
+ if (contents & CONTENTS_PLAYERCLIP) return (contents & CONTENTS_PLAYERCLIP);
+ return (contents & CONTENTS_SOLID);
+ } //end if
+ /*
+ if (contents & CONTENTS_AREAPORTAL)
+ {
+ static int num;
+ Log_Write("Entity %i, Brush %i: area portal %d\r\n", b->entitynum, b->brushnum, num++);
+ } //end if*/
+ if (contents == (contents & CONTENTS_STRUCTURAL))
+ {
+ //Log_Print("brush %i is only structural\n", b->brushnum);
+ contents = 0;
+ } //end if
+ if (contents & CONTENTS_DONOTENTER)
+ {
+ Log_Print("brush %i is a donotenter brush, c = %X\n", b->brushnum, contents);
+ } //end if
+ return contents;
+} //end of the function Q3_BrushContents
+#define BBOX_NORMAL_EPSILON 0.0001
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q3_DPlanes2MapPlanes(void)
+{
+ int i;
+
+ for (i = 0; i < q3_numplanes; i++)
+ {
+ dplanes2mapplanes[i] = FindFloatPlane(q3_dplanes[i].normal, q3_dplanes[i].dist);
+ } //end for
+} //end of the function Q3_DPlanes2MapPlanes
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q3_BSPBrushToMapBrush(q3_dbrush_t *bspbrush, entity_t *mapent)
+{
+ mapbrush_t *b;
+ int i, k, n;
+ side_t *side, *s2;
+ int planenum;
+ q3_dbrushside_t *bspbrushside;
+ q3_dplane_t *bspplane;
+
+ if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
+ Error ("nummapbrushes >= MAX_MAPFILE_BRUSHES");
+
+ b = &mapbrushes[nummapbrushes];
+ b->original_sides = &brushsides[nummapbrushsides];
+ b->entitynum = mapent-entities;
+ b->brushnum = nummapbrushes - mapent->firstbrush;
+ b->leafnum = dbrushleafnums[bspbrush - q3_dbrushes];
+
+ for (n = 0; n < bspbrush->numSides; n++)
+ {
+ //pointer to the bsp brush side
+ bspbrushside = &q3_dbrushsides[bspbrush->firstSide + n];
+
+ if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
+ {
+ Error ("MAX_MAPFILE_BRUSHSIDES");
+ } //end if
+ //pointer to the map brush side
+ side = &brushsides[nummapbrushsides];
+ //if the BSP brush side is textured
+ if (q3_dbrushsidetextured[bspbrush->firstSide + n]) side->flags |= SFL_TEXTURED|SFL_VISIBLE;
+ else side->flags &= ~SFL_TEXTURED;
+ //NOTE: all Quake3 sides are assumed textured
+ //side->flags |= SFL_TEXTURED|SFL_VISIBLE;
+ //
+ if (bspbrushside->shaderNum < 0)
+ {
+ side->contents = 0;
+ side->surf = 0;
+ } //end if
+ else
+ {
+ side->contents = q3_dshaders[bspbrushside->shaderNum].contentFlags;
+ side->surf = q3_dshaders[bspbrushside->shaderNum].surfaceFlags;
+ if (strstr(q3_dshaders[bspbrushside->shaderNum].shader, "common/hint"))
+ {
+ //Log_Print("found hint side\n");
+ side->surf |= SURF_HINT;
+ } //end if
+ } //end else
+ //
+ if (side->surf & SURF_NODRAW)
+ {
+ side->flags |= SFL_TEXTURED|SFL_VISIBLE;
+ } //end if
+ /*
+ if (side->contents & (CONTENTS_TRANSLUCENT|CONTENTS_STRUCTURAL))
+ {
+ side->flags |= SFL_TEXTURED|SFL_VISIBLE;
+ } //end if*/
+
+ // hints and skips are never detail, and have no content
+ if (side->surf & (SURF_HINT|SURF_SKIP) )
+ {
+ side->contents = 0;
+ //Log_Print("found hint brush side\n");
+ }
+ /*
+ if ((side->surf & SURF_NODRAW) && (side->surf & SURF_NOIMPACT))
+ {
+ side->contents = 0;
+ side->surf &= ~CONTENTS_DETAIL;
+ Log_Print("probably found hint brush in a BSP without hints being used\n");
+ } //end if*/
+
+ //ME: get a plane for this side
+ bspplane = &q3_dplanes[bspbrushside->planeNum];
+ planenum = FindFloatPlane(bspplane->normal, bspplane->dist);
+ //
+ // see if the plane has been used already
+ //
+ //ME: this really shouldn't happen!!!
+ //ME: otherwise the bsp file is corrupted??
+ //ME: still it seems to happen, maybe Johny Boy's
+ //ME: brush bevel adding is crappy ?
+ for (k = 0; k < b->numsides; k++)
+ {
+ s2 = b->original_sides + k;
+// if (DotProduct (mapplanes[s2->planenum].normal, mapplanes[planenum].normal) > 0.999
+// && fabs(mapplanes[s2->planenum].dist - mapplanes[planenum].dist) < 0.01 )
+
+ if (s2->planenum == planenum)
+ {
+ Log_Print("Entity %i, Brush %i: duplicate plane\n"
+ , b->entitynum, b->brushnum);
+ break;
+ }
+ if ( s2->planenum == (planenum^1) )
+ {
+ Log_Print("Entity %i, Brush %i: mirrored plane\n"
+ , b->entitynum, b->brushnum);
+ break;
+ }
+ }
+ if (k != b->numsides)
+ continue; // duplicated
+
+ //
+ // keep this side
+ //
+ //ME: reset pointer to side, why? hell I dunno (pointer is set above already)
+ side = b->original_sides + b->numsides;
+ //ME: store the plane number
+ side->planenum = planenum;
+ //ME: texinfo is already stored when bsp is loaded
+ //NOTE: check for TEXINFO_NODE, otherwise crash in Q3_BrushContents
+ //if (bspbrushside->texinfo < 0) side->texinfo = 0;
+ //else side->texinfo = bspbrushside->texinfo;
+
+ // save the td off in case there is an origin brush and we
+ // have to recalculate the texinfo
+ // ME: don't need to recalculate because it's already done
+ // (for non-world entities) in the BSP file
+// side_brushtextures[nummapbrushsides] = td;
+
+ nummapbrushsides++;
+ b->numsides++;
+ } //end for
+
+ // get the content for the entire brush
+ b->contents = q3_dshaders[bspbrush->shaderNum].contentFlags;
+ b->contents &= ~(CONTENTS_LADDER|CONTENTS_FOG|CONTENTS_STRUCTURAL);
+// b->contents = Q3_BrushContents(b);
+ //
+
+ if (BrushExists(b))
+ {
+ c_squattbrushes++;
+ b->numsides = 0;
+ return;
+ } //end if
+
+ //if we're creating AAS
+ if (create_aas)
+ {
+ //create the AAS brushes from this brush, don't add brush bevels
+ AAS_CreateMapBrushes(b, mapent, false);
+ return;
+ } //end if
+
+ // allow detail brushes to be removed
+ if (nodetail && (b->contents & CONTENTS_DETAIL) )
+ {
+ b->numsides = 0;
+ return;
+ } //end if
+
+ // allow water brushes to be removed
+ if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) )
+ {
+ b->numsides = 0;
+ return;
+ } //end if
+
+ // create windings for sides and bounds for brush
+ MakeBrushWindings(b);
+
+ //mark brushes without winding or with a tiny window as bevels
+ MarkBrushBevels(b);
+
+ // brushes that will not be visible at all will never be
+ // used as bsp splitters
+ if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
+ {
+ c_clipbrushes++;
+ for (i = 0; i < b->numsides; i++)
+ b->original_sides[i].texinfo = TEXINFO_NODE;
+ } //end for
+
+ //
+ // origin brushes are removed, but they set
+ // the rotation origin for the rest of the brushes
+ // in the entity. After the entire entity is parsed,
+ // the planenums and texinfos will be adjusted for
+ // the origin brush
+ //
+ //ME: not needed because the entities in the BSP file already
+ // have an origin set
+// if (b->contents & CONTENTS_ORIGIN)
+// {
+// char string[32];
+// vec3_t origin;
+//
+// if (num_entities == 1)
+// {
+// Error ("Entity %i, Brush %i: origin brushes not allowed in world"
+// , b->entitynum, b->brushnum);
+// return;
+// }
+//
+// VectorAdd (b->mins, b->maxs, origin);
+// VectorScale (origin, 0.5, origin);
+//
+// sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
+// SetKeyValue (&entities[b->entitynum], "origin", string);
+//
+// VectorCopy (origin, entities[b->entitynum].origin);
+//
+// // don't keep this brush
+// b->numsides = 0;
+//
+// return;
+// }
+
+ //ME: the bsp brushes already have bevels, so we won't try to
+ // add them again (especially since Johny Boy's bevel adding might
+ // be crappy)
+// AddBrushBevels(b);
+
+ nummapbrushes++;
+ mapent->numbrushes++;
+} //end of the function Q3_BSPBrushToMapBrush
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q3_ParseBSPBrushes(entity_t *mapent)
+{
+ int i;
+
+ for (i = 0; i < q3_dmodels[mapent->modelnum].numBrushes; i++)
+ {
+ Q3_BSPBrushToMapBrush(&q3_dbrushes[q3_dmodels[mapent->modelnum].firstBrush + i], mapent);
+ } //end for
+} //end of the function Q3_ParseBSPBrushes
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+qboolean Q3_ParseBSPEntity(int entnum)
+{
+ entity_t *mapent;
+ char *model;
+ int startbrush, startsides;
+
+ startbrush = nummapbrushes;
+ startsides = nummapbrushsides;
+
+ mapent = &entities[entnum];//num_entities];
+ mapent->firstbrush = nummapbrushes;
+ mapent->numbrushes = 0;
+ mapent->modelnum = -1; //-1 = no BSP model
+
+ model = ValueForKey(mapent, "model");
+ if (model && strlen(model))
+ {
+ if (*model == '*')
+ {
+ //get the model number of this entity (skip the leading *)
+ mapent->modelnum = atoi(&model[1]);
+ } //end if
+ } //end if
+
+ GetVectorForKey(mapent, "origin", mapent->origin);
+
+ //if this is the world entity it has model number zero
+ //the world entity has no model key
+ if (!strcmp("worldspawn", ValueForKey(mapent, "classname")))
+ {
+ mapent->modelnum = 0;
+ } //end if
+ //if the map entity has a BSP model (a modelnum of -1 is used for
+ //entities that aren't using a BSP model)
+ if (mapent->modelnum >= 0)
+ {
+ //parse the bsp brushes
+ Q3_ParseBSPBrushes(mapent);
+ } //end if
+ //
+ //the origin of the entity is already taken into account
+ //
+ //func_group entities can't be in the bsp file
+ //
+ //check out the func_areaportal entities
+ if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname")))
+ {
+ c_areaportals++;
+ mapent->areaportalnum = c_areaportals;
+ return true;
+ } //end if
+ return true;
+} //end of the function Q3_ParseBSPEntity
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+#define MAX_PATCH_VERTS 1024
+
+void AAS_CreateCurveBrushes(void)
+{
+ int i, j, n, planenum, numcurvebrushes = 0;
+ q3_dsurface_t *surface;
+ q3_drawVert_t *dv_p;
+ vec3_t points[MAX_PATCH_VERTS];
+ int width, height, c;
+ patchCollide_t *pc;
+ facet_t *facet;
+ mapbrush_t *brush;
+ side_t *side;
+ entity_t *mapent;
+ winding_t *winding;
+
+ qprintf("nummapbrushsides = %d\n", nummapbrushsides);
+ mapent = &entities[0];
+ for (i = 0; i < q3_numDrawSurfaces; i++)
+ {
+ surface = &q3_drawSurfaces[i];
+ if ( ! surface->patchWidth ) continue;
+ // if the curve is not solid
+ if (!(q3_dshaders[surface->shaderNum].contentFlags & (CONTENTS_SOLID|CONTENTS_PLAYERCLIP)))
+ {
+ //Log_Print("skipped non-solid curve\n");
+ continue;
+ } //end if
+ // if this curve should not be used for AAS
+ if ( q3_dshaders[surface->shaderNum].contentFlags & CONTENTS_NOBOTCLIP ) {
+ continue;
+ }
+ //
+ width = surface->patchWidth;
+ height = surface->patchHeight;
+ c = width * height;
+ if (c > MAX_PATCH_VERTS)
+ {
+ Error("ParseMesh: MAX_PATCH_VERTS");
+ } //end if
+
+ dv_p = q3_drawVerts + surface->firstVert;
+ for ( j = 0 ; j < c ; j++, dv_p++ )
+ {
+ points[j][0] = dv_p->xyz[0];
+ points[j][1] = dv_p->xyz[1];
+ points[j][2] = dv_p->xyz[2];
+ } //end for
+ // create the internal facet structure
+ pc = CM_GeneratePatchCollide(width, height, points);
+ //
+ for (j = 0; j < pc->numFacets; j++)
+ {
+ facet = &pc->facets[j];
+ //
+ brush = &mapbrushes[nummapbrushes];
+ brush->original_sides = &brushsides[nummapbrushsides];
+ brush->entitynum = 0;
+ brush->brushnum = nummapbrushes - mapent->firstbrush;
+ //
+ brush->numsides = facet->numBorders + 2;
+ nummapbrushsides += brush->numsides;
+ brush->contents = CONTENTS_SOLID;
+ //
+ //qprintf("\r%6d curve brushes", nummapbrushsides);//++numcurvebrushes);
+ qprintf("\r%6d curve brushes", ++numcurvebrushes);
+ //
+ planenum = FindFloatPlane(pc->planes[facet->surfacePlane].plane, pc->planes[facet->surfacePlane].plane[3]);
+ //
+ side = &brush->original_sides[0];
+ side->planenum = planenum;
+ side->contents = CONTENTS_SOLID;
+ side->flags |= SFL_TEXTURED|SFL_VISIBLE|SFL_CURVE;
+ side->surf = 0;
+ //
+ side = &brush->original_sides[1];
+ if (create_aas)
+ {
+ //the plane is expanded later so it's not a problem that
+ //these first two opposite sides are coplanar
+ side->planenum = planenum ^ 1;
+ } //end if
+ else
+ {
+ side->planenum = FindFloatPlane(mapplanes[planenum^1].normal, mapplanes[planenum^1].dist + 1);
+ side->flags |= SFL_TEXTURED|SFL_VISIBLE;
+ } //end else
+ side->contents = CONTENTS_SOLID;
+ side->flags |= SFL_CURVE;
+ side->surf = 0;
+ //
+ winding = BaseWindingForPlane(mapplanes[side->planenum].normal, mapplanes[side->planenum].dist);
+ for (n = 0; n < facet->numBorders; n++)
+ {
+ //never use the surface plane as a border
+ if (facet->borderPlanes[n] == facet->surfacePlane) continue;
+ //
+ side = &brush->original_sides[2 + n];
+ side->planenum = FindFloatPlane(pc->planes[facet->borderPlanes[n]].plane, pc->planes[facet->borderPlanes[n]].plane[3]);
+ if (facet->borderInward[n]) side->planenum ^= 1;
+ side->contents = CONTENTS_SOLID;
+ side->flags |= SFL_TEXTURED|SFL_CURVE;
+ side->surf = 0;
+ //chop the winding in place
+ if (winding) ChopWindingInPlace(&winding, mapplanes[side->planenum^1].normal, mapplanes[side->planenum^1].dist, 0.1); //CLIP_EPSILON);
+ } //end for
+ //VectorCopy(pc->bounds[0], brush->mins);
+ //VectorCopy(pc->bounds[1], brush->maxs);
+ if (!winding)
+ {
+ Log_Print("WARNING: AAS_CreateCurveBrushes: no winding\n");
+ brush->numsides = 0;
+ continue;
+ } //end if
+ brush->original_sides[0].winding = winding;
+ WindingBounds(winding, brush->mins, brush->maxs);
+ for (n = 0; n < 3; n++)
+ {
+ //IDBUG: all the indexes into the mins and maxs were zero (not using i)
+ if (brush->mins[n] < -MAX_MAP_BOUNDS || brush->maxs[n] > MAX_MAP_BOUNDS)
+ {
+ Log_Print("entity %i, brush %i: bounds out of range\n", brush->entitynum, brush->brushnum);
+ Log_Print("brush->mins[%d] = %f, brush->maxs[%d] = %f\n", n, brush->mins[n], n, brush->maxs[n]);
+ brush->numsides = 0; //remove the brush
+ break;
+ } //end if
+ if (brush->mins[n] > MAX_MAP_BOUNDS || brush->maxs[n] < -MAX_MAP_BOUNDS)
+ {
+ Log_Print("entity %i, brush %i: no visible sides on brush\n", brush->entitynum, brush->brushnum);
+ Log_Print("brush->mins[%d] = %f, brush->maxs[%d] = %f\n", n, brush->mins[n], n, brush->maxs[n]);
+ brush->numsides = 0; //remove the brush
+ break;
+ } //end if
+ } //end for
+ if (create_aas)
+ {
+ //NOTE: brush bevels now already added
+ //AddBrushBevels(brush);
+ AAS_CreateMapBrushes(brush, mapent, false);
+ } //end if
+ else
+ {
+ // create windings for sides and bounds for brush
+ MakeBrushWindings(brush);
+ AddBrushBevels(brush);
+ nummapbrushes++;
+ mapent->numbrushes++;
+ } //end else
+ } //end for
+ } //end for
+ //qprintf("\r%6d curve brushes", nummapbrushsides);//++numcurvebrushes);
+ qprintf("\r%6d curve brushes\n", numcurvebrushes);
+} //end of the function AAS_CreateCurveBrushes
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AAS_ExpandMapBrush(mapbrush_t *brush, vec3_t mins, vec3_t maxs);
+
+void Q3_LoadMapFromBSP(struct quakefile_s *qf)
+{
+ int i;
+ vec3_t mins = {-1,-1,-1}, maxs = {1, 1, 1};
+
+ Log_Print("-- Q3_LoadMapFromBSP --\n");
+ //loaded map type
+ loadedmaptype = MAPTYPE_QUAKE3;
+
+ Log_Print("Loading map from %s...\n", qf->filename);
+ //load the bsp file
+ Q3_LoadBSPFile(qf);
+
+ //create an index from bsp planes to map planes
+ //DPlanes2MapPlanes();
+ //clear brush model numbers
+ for (i = 0; i < MAX_MAPFILE_BRUSHES; i++)
+ brushmodelnumbers[i] = -1;
+
+ nummapbrushsides = 0;
+ num_entities = 0;
+
+ Q3_ParseEntities();
+ //
+ for (i = 0; i < num_entities; i++)
+ {
+ Q3_ParseBSPEntity(i);
+ } //end for
+
+ AAS_CreateCurveBrushes();
+ //get the map mins and maxs from the world model
+ ClearBounds(map_mins, map_maxs);
+ for (i = 0; i < entities[0].numbrushes; i++)
+ {
+ if (mapbrushes[i].numsides <= 0)
+ continue;
+ AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs);
+ AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs);
+ } //end for
+ /*/
+ for (i = 0; i < nummapbrushes; i++)
+ {
+ //if (!mapbrushes[i].original_sides) continue;
+ //AddBrushBevels(&mapbrushes[i]);
+ //AAS_ExpandMapBrush(&mapbrushes[i], mins, maxs);
+ } //end for*/
+ /*
+ for (i = 0; i < nummapbrushsides; i++)
+ {
+ Log_Write("side %d flags = %d", i, brushsides[i].flags);
+ } //end for
+ for (i = 0; i < nummapbrushes; i++)
+ {
+ Log_Write("brush contents: ");
+ PrintContents(mapbrushes[i].contents);
+ Log_Print("\n");
+ } //end for*/
+} //end of the function Q3_LoadMapFromBSP
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q3_ResetMapLoading(void)
+{
+ //reset for map loading from bsp
+ memset(nodestack, 0, NODESTACKSIZE * sizeof(int));
+ nodestackptr = NULL;
+ nodestacksize = 0;
+ memset(brushmodelnumbers, 0, MAX_MAPFILE_BRUSHES * sizeof(int));
+} //end of the function Q3_ResetMapLoading
+
diff --git a/code/bspc/map_sin.c b/code/bspc/map_sin.c
index 7794b8c..b6e67ff 100755
--- a/code/bspc/map_sin.c
+++ b/code/bspc/map_sin.c
@@ -1,1211 +1,1211 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-//-----------------------------------------------------------------------------
-//
-// $Logfile:: /MissionPack/code/bspc/map_sin.c $
-
-#include "qbsp.h"
-#include "l_bsp_sin.h"
-#include "aas_map.h" //AAS_CreateMapBrushes
-
-
-//====================================================================
-
-
-/*
-===========
-Sin_BrushContents
-===========
-*/
-
-int Sin_BrushContents(mapbrush_t *b)
-{
- int contents;
- side_t *s;
- int i;
-#ifdef SIN
- float trans = 0;
-#else
- int trans;
-#endif
-
- s = &b->original_sides[0];
- contents = s->contents;
-
-#ifdef SIN
- trans = sin_texinfo[s->texinfo].translucence;
-#else
- trans = texinfo[s->texinfo].flags;
-#endif
- for (i=1 ; i<b->numsides ; i++, s++)
- {
- s = &b->original_sides[i];
-#ifdef SIN
- trans += sin_texinfo[s->texinfo].translucence;
-#else
- trans |= texinfo[s->texinfo].flags;
-#endif
- if (s->contents != contents)
- {
-#ifdef SIN
- if (
- ( s->contents & CONTENTS_DETAIL && !(contents & CONTENTS_DETAIL) ) ||
- ( !(s->contents & CONTENTS_DETAIL) && contents & CONTENTS_DETAIL )
- )
- {
- s->contents |= CONTENTS_DETAIL;
- contents |= CONTENTS_DETAIL;
- continue;
- }
-#endif
- printf ("Entity %i, Brush %i: mixed face contents\n"
- , b->entitynum, b->brushnum);
- break;
- }
- }
-
-
-#ifdef SIN
- if (contents & CONTENTS_FENCE)
- {
-// contents |= CONTENTS_TRANSLUCENT;
- contents |= CONTENTS_DETAIL;
- contents |= CONTENTS_DUMMYFENCE;
- contents &= ~CONTENTS_SOLID;
- contents &= ~CONTENTS_FENCE;
- contents |= CONTENTS_WINDOW;
- }
-#endif
-
- // if any side is translucent, mark the contents
- // and change solid to window
-#ifdef SIN
- if ( trans > 0 )
-#else
- if ( trans & (SURF_TRANS33|SURF_TRANS66) )
-#endif
- {
- contents |= CONTENTS_Q2TRANSLUCENT;
- if (contents & CONTENTS_SOLID)
- {
- contents &= ~CONTENTS_SOLID;
- contents |= CONTENTS_WINDOW;
- }
- }
-
- return contents;
-} //*/
-
-
-//============================================================================
-
-
-
-/*
-=================
-ParseBrush
-=================
-* /
-void ParseBrush (entity_t *mapent)
-{
- mapbrush_t *b;
- int i,j, k;
- int mt;
- side_t *side, *s2;
- int planenum;
- brush_texture_t td;
-#ifdef SIN
- textureref_t newref;
-#endif
- int planepts[3][3];
-
- if (nummapbrushes == MAX_MAP_BRUSHES)
- Error ("nummapbrushes == MAX_MAP_BRUSHES");
-
- b = &mapbrushes[nummapbrushes];
- b->original_sides = &brushsides[nummapbrushsides];
- b->entitynum = num_entities-1;
- b->brushnum = nummapbrushes - mapent->firstbrush;
-
- do
- {
- if (!GetToken (true))
- break;
- if (!strcmp (token, "}") )
- break;
-
- if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
- Error ("MAX_MAP_BRUSHSIDES");
- side = &brushsides[nummapbrushsides];
-
- // read the three point plane definition
- for (i=0 ; i<3 ; i++)
- {
- if (i != 0)
- GetToken (true);
- if (strcmp (token, "(") )
- Error ("parsing brush");
-
- for (j=0 ; j<3 ; j++)
- {
- GetToken (false);
- planepts[i][j] = atoi(token);
- }
-
- GetToken (false);
- if (strcmp (token, ")") )
- Error ("parsing brush");
-
- }
-
-
- //
- // read the texturedef
- //
- GetToken (false);
- strcpy (td.name, token);
-
- GetToken (false);
- td.shift[0] = atoi(token);
- GetToken (false);
- td.shift[1] = atoi(token);
- GetToken (false);
-#ifdef SIN
- td.rotate = atof(token);
-#else
- td.rotate = atoi(token);
-#endif
- GetToken (false);
- td.scale[0] = atof(token);
- GetToken (false);
- td.scale[1] = atof(token);
-
- // find default flags and values
- mt = FindMiptex (td.name);
-#ifdef SIN
- // clear out the masks on newref
- memset(&newref,0,sizeof(newref));
- // copy over the name
- strcpy( newref.name, td.name );
-
- ParseSurfaceInfo( &newref );
- MergeRefs( &bsp_textureref[mt], &newref, &td.tref );
- side->contents = td.tref.contents;
- side->surf = td.tref.flags;
-#else
- td.flags = textureref[mt].flags;
- td.value = textureref[mt].value;
- side->contents = textureref[mt].contents;
- side->surf = td.flags = textureref[mt].flags;
-
- if (TokenAvailable())
- {
- GetToken (false);
- side->contents = atoi(token);
- GetToken (false);
- side->surf = td.flags = atoi(token);
- GetToken (false);
- td.value = atoi(token);
- }
-#endif
-
- // translucent objects are automatically classified as detail
-#ifdef SIN
- if ( td.tref.translucence > 0 )
-#else
- if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
-#endif
- side->contents |= CONTENTS_DETAIL;
- if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
- side->contents |= CONTENTS_DETAIL;
- if (fulldetail)
- side->contents &= ~CONTENTS_DETAIL;
- if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1)
- | CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST) ) )
- side->contents |= CONTENTS_SOLID;
-
- // hints and skips are never detail, and have no content
- if (side->surf & (SURF_HINT|SURF_SKIP) )
- {
- side->contents = 0;
-#ifndef SIN // I think this is a bug of some kind
- side->surf &= ~CONTENTS_DETAIL;
-#endif
- }
-
- //
- // find the plane number
- //
- planenum = PlaneFromPoints (planepts[0], planepts[1], planepts[2]);
- if (planenum == -1)
- {
- printf ("Entity %i, Brush %i: plane with no normal\n"
- , b->entitynum, b->brushnum);
- continue;
- }
-
- //
- // see if the plane has been used already
- //
- for (k=0 ; k<b->numsides ; k++)
- {
- s2 = b->original_sides + k;
- if (s2->planenum == planenum)
- {
- printf ("Entity %i, Brush %i: duplicate plane\n"
- , b->entitynum, b->brushnum);
- break;
- }
- if ( s2->planenum == (planenum^1) )
- {
- printf ("Entity %i, Brush %i: mirrored plane\n"
- , b->entitynum, b->brushnum);
- break;
- }
- }
- if (k != b->numsides)
- continue; // duplicated
-
- //
- // keep this side
- //
-
- side = b->original_sides + b->numsides;
- side->planenum = planenum;
-#ifdef SIN
- side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum],
- &td, vec3_origin, &newref);
- //
- // save off lightinfo
- //
- side->lightinfo = LightinfoForBrushTexture ( &td );
-#else
- side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum],
- &td, vec3_origin);
-
-#endif
-
- // save the td off in case there is an origin brush and we
- // have to recalculate the texinfo
- side_brushtextures[nummapbrushsides] = td;
-#ifdef SIN
- // save off the merged tref for animating textures
- side_newrefs[nummapbrushsides] = newref;
-#endif
-
- nummapbrushsides++;
- b->numsides++;
- } while (1);
-
- // get the content for the entire brush
- b->contents = Sin_BrushContents (b);
-
- // allow detail brushes to be removed
- if (nodetail && (b->contents & CONTENTS_DETAIL) )
- {
- b->numsides = 0;
- return;
- }
-
- // allow water brushes to be removed
- if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) )
- {
- b->numsides = 0;
- return;
- }
-
- // create windings for sides and bounds for brush
- MakeBrushWindings (b);
-
- // brushes that will not be visible at all will never be
- // used as bsp splitters
- if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
- {
- c_clipbrushes++;
- for (i=0 ; i<b->numsides ; i++)
- b->original_sides[i].texinfo = TEXINFO_NODE;
- }
-
- //
- // origin brushes are removed, but they set
- // the rotation origin for the rest of the brushes
- // in the entity. After the entire entity is parsed,
- // the planenums and texinfos will be adjusted for
- // the origin brush
- //
- if (b->contents & CONTENTS_ORIGIN)
- {
- char string[32];
- vec3_t origin;
-
- if (num_entities == 1)
- {
- Error ("Entity %i, Brush %i: origin brushes not allowed in world"
- , b->entitynum, b->brushnum);
- return;
- }
-
- VectorAdd (b->mins, b->maxs, origin);
- VectorScale (origin, 0.5, origin);
-
- sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
- SetKeyValue (&entities[b->entitynum], "origin", string);
-
- VectorCopy (origin, entities[b->entitynum].origin);
-
- // don't keep this brush
- b->numsides = 0;
-
- return;
- }
-
- AddBrushBevels (b);
-
- nummapbrushes++;
- mapent->numbrushes++;
-} //*/
-
-/*
-================
-MoveBrushesToWorld
-
-Takes all of the brushes from the current entity and
-adds them to the world's brush list.
-
-Used by func_group and func_areaportal
-================
-* /
-void MoveBrushesToWorld (entity_t *mapent)
-{
- int newbrushes;
- int worldbrushes;
- mapbrush_t *temp;
- int i;
-
- // this is pretty gross, because the brushes are expected to be
- // in linear order for each entity
-
- newbrushes = mapent->numbrushes;
- worldbrushes = entities[0].numbrushes;
-
- temp = malloc(newbrushes*sizeof(mapbrush_t));
- memcpy (temp, mapbrushes + mapent->firstbrush, newbrushes*sizeof(mapbrush_t));
-
-#if 0 // let them keep their original brush numbers
- for (i=0 ; i<newbrushes ; i++)
- temp[i].entitynum = 0;
-#endif
-
- // make space to move the brushes (overlapped copy)
- memmove (mapbrushes + worldbrushes + newbrushes,
- mapbrushes + worldbrushes,
- sizeof(mapbrush_t) * (nummapbrushes - worldbrushes - newbrushes) );
-
- // copy the new brushes down
- memcpy (mapbrushes + worldbrushes, temp, sizeof(mapbrush_t) * newbrushes);
-
- // fix up indexes
- entities[0].numbrushes += newbrushes;
- for (i=1 ; i<num_entities ; i++)
- entities[i].firstbrush += newbrushes;
- free (temp);
-
- mapent->numbrushes = 0;
-} //*/
-
-/*
-================
-ParseMapEntity
-================
-* /
-qboolean Sin_ParseMapEntity (void)
-{
- entity_t *mapent;
- epair_t *e;
- side_t *s;
- int i, j;
- int startbrush, startsides;
- vec_t newdist;
- mapbrush_t *b;
-
- if (!GetToken (true))
- return false;
-
- if (strcmp (token, "{") )
- Error ("ParseEntity: { not found");
-
- if (num_entities == MAX_MAP_ENTITIES)
- Error ("num_entities == MAX_MAP_ENTITIES");
-
- startbrush = nummapbrushes;
- startsides = nummapbrushsides;
-
- mapent = &entities[num_entities];
- num_entities++;
- memset (mapent, 0, sizeof(*mapent));
- mapent->firstbrush = nummapbrushes;
- mapent->numbrushes = 0;
-// mapent->portalareas[0] = -1;
-// mapent->portalareas[1] = -1;
-
- do
- {
- if (!GetToken (true))
- Error ("ParseEntity: EOF without closing brace");
- if (!strcmp (token, "}") )
- break;
- if (!strcmp (token, "{") )
- ParseBrush (mapent);
- else
- {
- e = ParseEpair ();
-#ifdef SIN
- //HACK HACK HACK
- // MED Gotta do this here
- if ( !stricmp(e->key, "surfacefile") )
- {
- if (!surfacefile[0])
- {
- strcpy( surfacefile, e->value );
- }
- printf ("--- ParseSurfaceFile ---\n");
- printf ("Surface script: %s\n", surfacefile);
- if (!ParseSurfaceFile(surfacefile))
- {
- Error ("Script file not found: %s\n", surfacefile);
- }
- }
-#endif
- e->next = mapent->epairs;
- mapent->epairs = e;
- }
- } while (1);
-
-#ifdef SIN
- if (!(strlen(ValueForKey(mapent, "origin"))) && ((num_entities-1) != 0))
- {
- mapbrush_t *brush;
- vec3_t origin;
- char string[32];
- vec3_t mins, maxs;
- int start, end;
- // Calculate bounds
-
- start = mapent->firstbrush;
- end = start + mapent->numbrushes;
- ClearBounds (mins, maxs);
-
- for (j=start ; j<end ; j++)
- {
- brush = &mapbrushes[j];
- if (!brush->numsides)
- continue; // not a real brush (origin brush) - shouldn't happen
- AddPointToBounds (brush->mins, mins, maxs);
- AddPointToBounds (brush->maxs, mins, maxs);
- }
-
- // Set the origin to be the centroid of the entity.
- VectorAdd ( mins, maxs, origin);
- VectorScale( origin, 0.5f, origin );
-
- sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
- SetKeyValue ( mapent, "origin", string);
-// qprintf("Setting origin to %s\n",string);
- }
-#endif
-
- GetVectorForKey (mapent, "origin", mapent->origin);
-
-#ifdef SIN
- if (
- (!strcmp ("func_areaportal", ValueForKey (mapent, "classname"))) ||
- (!strcmp ("func_group", ValueForKey (mapent, "classname"))) ||
- (!strcmp ("detail", ValueForKey (mapent, "classname")) && !entitydetails)
- )
- {
- VectorClear( mapent->origin );
- }
-#endif
-
- //
- // if there was an origin brush, offset all of the planes and texinfo
- //
- if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2])
- {
- for (i=0 ; i<mapent->numbrushes ; i++)
- {
- b = &mapbrushes[mapent->firstbrush + i];
- for (j=0 ; j<b->numsides ; j++)
- {
- s = &b->original_sides[j];
- newdist = mapplanes[s->planenum].dist -
- DotProduct (mapplanes[s->planenum].normal, mapent->origin);
- s->planenum = FindFloatPlane (mapplanes[s->planenum].normal, newdist);
-#ifdef SIN
- s->texinfo = TexinfoForBrushTexture (&mapplanes[s->planenum],
- &side_brushtextures[s-brushsides], mapent->origin, &side_newrefs[s-brushsides]);
- //
- // save off lightinfo
- //
- s->lightinfo = LightinfoForBrushTexture ( &side_brushtextures[s-brushsides] );
-#else
- s->texinfo = TexinfoForBrushTexture (&mapplanes[s->planenum],
- &side_brushtextures[s-brushsides], mapent->origin);
-#endif
- }
- MakeBrushWindings (b);
- }
- }
-
- // group entities are just for editor convenience
- // toss all brushes into the world entity
- if (!strcmp ("func_group", ValueForKey (mapent, "classname")))
- {
- MoveBrushesToWorld (mapent);
- mapent->numbrushes = 0;
- mapent->wasdetail = true;
- FreeValueKeys( mapent );
- return true;
- }
-#ifdef SIN
- // detail entities are just for editor convenience
- // toss all brushes into the world entity as detail brushes
- if (!strcmp ("detail", ValueForKey (mapent, "classname")) && !entitydetails)
- {
- for (i=0 ; i<mapent->numbrushes ; i++)
- {
- int j;
- side_t * s;
- b = &mapbrushes[mapent->firstbrush + i];
- if (nodetail)
- {
- b->numsides = 0;
- continue;
- }
- if (!fulldetail)
- {
- // set the contents for the entire brush
- b->contents |= CONTENTS_DETAIL;
- // set the contents in the sides as well
- for (j=0, s=b->original_sides ; j<b->numsides ; j++,s++)
- {
- s->contents |= CONTENTS_DETAIL;
- }
- }
- else
- {
- // set the contents for the entire brush
- b->contents |= CONTENTS_SOLID;
- // set the contents in the sides as well
- for (j=0, s=b->original_sides ; j<b->numsides ; j++,s++)
- {
- s->contents |= CONTENTS_SOLID;
- }
- }
- }
- MoveBrushesToWorld (mapent);
- mapent->wasdetail = true;
- FreeValueKeys( mapent );
- // kill off the entity
- // num_entities--;
- return true;
- }
-#endif
-
- // areaportal entities move their brushes, but don't eliminate
- // the entity
- if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname")))
- {
- char str[128];
-
- if (mapent->numbrushes != 1)
- Error ("Entity %i: func_areaportal can only be a single brush", num_entities-1);
-
- b = &mapbrushes[nummapbrushes-1];
- b->contents = CONTENTS_AREAPORTAL;
- c_areaportals++;
- mapent->areaportalnum = c_areaportals;
- // set the portal number as "style"
- sprintf (str, "%i", c_areaportals);
- SetKeyValue (mapent, "style", str);
- MoveBrushesToWorld (mapent);
- return true;
- }
-
- return true;
-} //end of the function Sin_ParseMapEntity */
-
-//===================================================================
-
-/*
-================
-LoadMapFile
-================
-* /
-void Sin_LoadMapFile (char *filename)
-{
- int i;
-#ifdef SIN
- int num_detailsides=0;
- int num_detailbrushes=0;
- int num_worldsides=0;
- int num_worldbrushes=0;
- int j,k;
-#endif
-
- qprintf ("--- LoadMapFile ---\n");
-
- LoadScriptFile (filename);
-
- nummapbrushsides = 0;
- num_entities = 0;
-
- while (ParseMapEntity ())
- {
- }
-
- ClearBounds (map_mins, map_maxs);
- for (i=0 ; i<entities[0].numbrushes ; i++)
- {
- if (mapbrushes[i].mins[0] > 4096)
- continue; // no valid points
- AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs);
- AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs);
- }
-#ifdef SIN
- for (j=0; j<num_entities; j++)
- {
- for (i=0 ; i<entities[j].numbrushes ; i++)
- {
- side_t * s;
- mapbrush_t *b;
- b = &mapbrushes[entities[j].firstbrush + i];
- if (b->numsides && b->contents & CONTENTS_DETAIL)
- num_detailbrushes++;
- else if (b->numsides)
- num_worldbrushes++;
- for (k=0, s=b->original_sides ; k<b->numsides ; k++,s++)
- {
- if (s->contents & CONTENTS_DETAIL)
- num_detailsides++;
- else
- num_worldsides++;
- }
- }
- }
-#endif
-
- qprintf ("%5i brushes\n", nummapbrushes);
- qprintf ("%5i clipbrushes\n", c_clipbrushes);
- qprintf ("%5i total sides\n", nummapbrushsides);
- qprintf ("%5i boxbevels\n", c_boxbevels);
- qprintf ("%5i edgebevels\n", c_edgebevels);
- qprintf ("%5i entities\n", num_entities);
- qprintf ("%5i planes\n", nummapplanes);
- qprintf ("%5i areaportals\n", c_areaportals);
- qprintf ("size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", map_mins[0],map_mins[1],map_mins[2],
- map_maxs[0],map_maxs[1],map_maxs[2]);
-#ifdef SIN
- qprintf ("%5i detailbrushes\n", num_detailbrushes);
- qprintf ("%5i worldbrushes\n", num_worldbrushes);
- qprintf ("%5i detailsides\n", num_detailsides);
- qprintf ("%5i worldsides\n", num_worldsides);
-#endif
-
-} //end of the function Sin_LoadMap */
-
-
-#ifdef ME //Begin MAP loading from BSP file
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Sin_CreateMapTexinfo(void)
-{
- int i;
- vec_t defaultvec[4] = {1, 0, 0, 0};
-
- memcpy(map_texinfo[0].vecs[0], defaultvec, sizeof(defaultvec));
- memcpy(map_texinfo[0].vecs[1], defaultvec, sizeof(defaultvec));
- map_texinfo[0].flags = 0;
- map_texinfo[0].value = 0;
- strcpy(map_texinfo[0].texture, "generic/misc/red"); //no texture
- map_texinfo[0].nexttexinfo = -1;
- for (i = 1; i < sin_numtexinfo; i++)
- {
- memcpy(map_texinfo[i].vecs, sin_texinfo[i].vecs, sizeof(float) * 2 * 4);
- map_texinfo[i].flags = sin_texinfo[i].flags;
- map_texinfo[i].value = 0;
- strcpy(map_texinfo[i].texture, sin_texinfo[i].texture);
- map_texinfo[i].nexttexinfo = -1;
- } //end for
-} //end of the function Sin_CreateMapTexinfo
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Sin_SetLeafBrushesModelNumbers(int leafnum, int modelnum)
-{
- int i, brushnum;
- sin_dleaf_t *leaf;
-
- leaf = &sin_dleafs[leafnum];
- for (i = 0; i < leaf->numleafbrushes; i++)
- {
- brushnum = sin_dleafbrushes[leaf->firstleafbrush + i];
- brushmodelnumbers[brushnum] = modelnum;
- dbrushleafnums[brushnum] = leafnum;
- } //end for
-} //end of the function Sin_SetLeafBrushesModelNumbers
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Sin_InitNodeStack(void)
-{
- nodestackptr = nodestack;
- nodestacksize = 0;
-} //end of the function Sin_InitNodeStack
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Sin_PushNodeStack(int num)
-{
- *nodestackptr = num;
- nodestackptr++;
- nodestacksize++;
- //
- if (nodestackptr >= &nodestack[NODESTACKSIZE])
- {
- Error("Sin_PushNodeStack: stack overflow\n");
- } //end if
-} //end of the function Sin_PushNodeStack
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int Sin_PopNodeStack(void)
-{
- //if the stack is empty
- if (nodestackptr <= nodestack) return -1;
- //decrease stack pointer
- nodestackptr--;
- nodestacksize--;
- //return the top value from the stack
- return *nodestackptr;
-} //end of the function Sin_PopNodeStack
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Sin_SetBrushModelNumbers(entity_t *mapent)
-{
- int n, pn;
- int leafnum;
-
- //
- Sin_InitNodeStack();
- //head node (root) of the bsp tree
- n = sin_dmodels[mapent->modelnum].headnode;
- pn = 0;
-
- do
- {
- //if we are in a leaf (negative node number)
- if (n < 0)
- {
- //number of the leaf
- leafnum = (-n) - 1;
- //set the brush numbers
- Sin_SetLeafBrushesModelNumbers(leafnum, mapent->modelnum);
- //walk back into the tree to find a second child to continue with
- for (pn = Sin_PopNodeStack(); pn >= 0; n = pn, pn = Sin_PopNodeStack())
- {
- //if we took the first child at the parent node
- if (sin_dnodes[pn].children[0] == n) break;
- } //end for
- //if the stack wasn't empty (if not processed whole tree)
- if (pn >= 0)
- {
- //push the parent node again
- Sin_PushNodeStack(pn);
- //we proceed with the second child of the parent node
- n = sin_dnodes[pn].children[1];
- } //end if
- } //end if
- else
- {
- //push the current node onto the stack
- Sin_PushNodeStack(n);
- //walk forward into the tree to the first child
- n = sin_dnodes[n].children[0];
- } //end else
- } while(pn >= 0);
-} //end of the function Sin_SetBrushModelNumbers
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Sin_BSPBrushToMapBrush(sin_dbrush_t *bspbrush, entity_t *mapent)
-{
- mapbrush_t *b;
- int i, k, n;
- side_t *side, *s2;
- int planenum;
- sin_dbrushside_t *bspbrushside;
- sin_dplane_t *bspplane;
-
- if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
- Error ("nummapbrushes >= MAX_MAPFILE_BRUSHES");
-
- b = &mapbrushes[nummapbrushes];
- b->original_sides = &brushsides[nummapbrushsides];
- b->entitynum = mapent-entities;
- b->brushnum = nummapbrushes - mapent->firstbrush;
- b->leafnum = dbrushleafnums[bspbrush - sin_dbrushes];
-
- for (n = 0; n < bspbrush->numsides; n++)
- {
- //pointer to the bsp brush side
- bspbrushside = &sin_dbrushsides[bspbrush->firstside + n];
-
- if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
- {
- Error ("MAX_MAPFILE_BRUSHSIDES");
- } //end if
- //pointer to the map brush side
- side = &brushsides[nummapbrushsides];
- //if the BSP brush side is textured
- if (sin_dbrushsidetextured[bspbrush->firstside + n]) side->flags |= SFL_TEXTURED;
- else side->flags &= ~SFL_TEXTURED;
- //ME: can get side contents and surf directly from BSP file
- side->contents = bspbrush->contents;
- //if the texinfo is TEXINFO_NODE
- if (bspbrushside->texinfo < 0) side->surf = 0;
- else side->surf = sin_texinfo[bspbrushside->texinfo].flags;
-
- // translucent objects are automatically classified as detail
- if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
- side->contents |= CONTENTS_DETAIL;
- if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
- side->contents |= CONTENTS_DETAIL;
- if (fulldetail)
- side->contents &= ~CONTENTS_DETAIL;
- if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1)
- | CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST) ) )
- side->contents |= CONTENTS_SOLID;
-
- // hints and skips are never detail, and have no content
- if (side->surf & (SURF_HINT|SURF_SKIP) )
- {
- side->contents = 0;
- side->surf &= ~CONTENTS_DETAIL;
- }
-
- //ME: get a plane for this side
- bspplane = &sin_dplanes[bspbrushside->planenum];
- planenum = FindFloatPlane(bspplane->normal, bspplane->dist);
- //
- // see if the plane has been used already
- //
- //ME: this really shouldn't happen!!!
- //ME: otherwise the bsp file is corrupted??
- //ME: still it seems to happen, maybe Johny Boy's
- //ME: brush bevel adding is crappy ?
- for (k = 0; k < b->numsides; k++)
- {
- s2 = b->original_sides + k;
- if (s2->planenum == planenum)
- {
- Log_Print("Entity %i, Brush %i: duplicate plane\n"
- , b->entitynum, b->brushnum);
- break;
- }
- if ( s2->planenum == (planenum^1) )
- {
- Log_Print("Entity %i, Brush %i: mirrored plane\n"
- , b->entitynum, b->brushnum);
- break;
- }
- }
- if (k != b->numsides)
- continue; // duplicated
-
- //
- // keep this side
- //
- //ME: reset pointer to side, why? hell I dunno (pointer is set above already)
- side = b->original_sides + b->numsides;
- //ME: store the plane number
- side->planenum = planenum;
- //ME: texinfo is already stored when bsp is loaded
- //NOTE: check for TEXINFO_NODE, otherwise crash in Sin_BrushContents
- if (bspbrushside->texinfo < 0) side->texinfo = 0;
- else side->texinfo = bspbrushside->texinfo;
-
- // save the td off in case there is an origin brush and we
- // have to recalculate the texinfo
- // ME: don't need to recalculate because it's already done
- // (for non-world entities) in the BSP file
-// side_brushtextures[nummapbrushsides] = td;
-
- nummapbrushsides++;
- b->numsides++;
- } //end for
-
- // get the content for the entire brush
- b->contents = bspbrush->contents;
- Sin_BrushContents(b);
-
- if (BrushExists(b))
- {
- c_squattbrushes++;
- b->numsides = 0;
- return;
- } //end if
-
- //if we're creating AAS
- if (create_aas)
- {
- //create the AAS brushes from this brush, don't add brush bevels
- AAS_CreateMapBrushes(b, mapent, false);
- return;
- } //end if
-
- // allow detail brushes to be removed
- if (nodetail && (b->contents & CONTENTS_DETAIL) )
- {
- b->numsides = 0;
- return;
- } //end if
-
- // allow water brushes to be removed
- if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) )
- {
- b->numsides = 0;
- return;
- } //end if
-
- // create windings for sides and bounds for brush
- MakeBrushWindings(b);
-
- //mark brushes without winding or with a tiny window as bevels
- MarkBrushBevels(b);
-
- // brushes that will not be visible at all will never be
- // used as bsp splitters
- if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
- {
- c_clipbrushes++;
- for (i = 0; i < b->numsides; i++)
- b->original_sides[i].texinfo = TEXINFO_NODE;
- } //end for
-
- //
- // origin brushes are removed, but they set
- // the rotation origin for the rest of the brushes
- // in the entity. After the entire entity is parsed,
- // the planenums and texinfos will be adjusted for
- // the origin brush
- //
- //ME: not needed because the entities in the BSP file already
- // have an origin set
-// if (b->contents & CONTENTS_ORIGIN)
-// {
-// char string[32];
-// vec3_t origin;
-//
-// if (num_entities == 1)
-// {
-// Error ("Entity %i, Brush %i: origin brushes not allowed in world"
-// , b->entitynum, b->brushnum);
-// return;
-// }
-//
-// VectorAdd (b->mins, b->maxs, origin);
-// VectorScale (origin, 0.5, origin);
-//
-// sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
-// SetKeyValue (&entities[b->entitynum], "origin", string);
-//
-// VectorCopy (origin, entities[b->entitynum].origin);
-//
-// // don't keep this brush
-// b->numsides = 0;
-//
-// return;
-// }
-
- //ME: the bsp brushes already have bevels, so we won't try to
- // add them again (especially since Johny Boy's bevel adding might
- // be crappy)
-// AddBrushBevels(b);
-
- nummapbrushes++;
- mapent->numbrushes++;
-} //end of the function Sin_BSPBrushToMapBrush
-//===========================================================================
-//===========================================================================
-void Sin_ParseBSPBrushes(entity_t *mapent)
-{
- int i, testnum = 0;
-
- //give all the brushes that belong to this entity the number of the
- //BSP model used by this entity
- Sin_SetBrushModelNumbers(mapent);
- //now parse all the brushes with the correct mapent->modelnum
- for (i = 0; i < sin_numbrushes; i++)
- {
- if (brushmodelnumbers[i] == mapent->modelnum)
- {
- testnum++;
- Sin_BSPBrushToMapBrush(&sin_dbrushes[i], mapent);
- } //end if
- } //end for
-} //end of the function Sin_ParseBSPBrushes
-//===========================================================================
-//===========================================================================
-qboolean Sin_ParseBSPEntity(int entnum)
-{
- entity_t *mapent;
- char *model;
- int startbrush, startsides;
-
- startbrush = nummapbrushes;
- startsides = nummapbrushsides;
-
- mapent = &entities[entnum];//num_entities];
- mapent->firstbrush = nummapbrushes;
- mapent->numbrushes = 0;
- mapent->modelnum = -1; //-1 = no model
-
- model = ValueForKey(mapent, "model");
- if (model && *model == '*')
- {
- mapent->modelnum = atoi(&model[1]);
- //Log_Print("model = %s\n", model);
- //Log_Print("mapent->modelnum = %d\n", mapent->modelnum);
- } //end if
-
- GetVectorForKey(mapent, "origin", mapent->origin);
-
- //if this is the world entity it has model number zero
- //the world entity has no model key
- if (!strcmp("worldspawn", ValueForKey(mapent, "classname")))
- {
- mapent->modelnum = 0;
- } //end if
- //if the map entity has a BSP model (a modelnum of -1 is used for
- //entities that aren't using a BSP model)
- if (mapent->modelnum >= 0)
- {
- //parse the bsp brushes
- Sin_ParseBSPBrushes(mapent);
- } //end if
- //
- //the origin of the entity is already taken into account
- //
- //func_group entities can't be in the bsp file
- //
- //check out the func_areaportal entities
- if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname")))
- {
- c_areaportals++;
- mapent->areaportalnum = c_areaportals;
- return true;
- } //end if
- return true;
-} //end of the function Sin_ParseBSPEntity
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Sin_LoadMapFromBSP(char *filename, int offset, int length)
-{
- int i;
-
- Log_Print("-- Sin_LoadMapFromBSP --\n");
- //loaded map type
- loadedmaptype = MAPTYPE_SIN;
-
- Log_Print("Loading map from %s...\n", filename);
- //load the bsp file
- Sin_LoadBSPFile(filename, offset, length);
-
- //create an index from bsp planes to map planes
- //DPlanes2MapPlanes();
- //clear brush model numbers
- for (i = 0; i < MAX_MAPFILE_BRUSHES; i++)
- brushmodelnumbers[i] = -1;
-
- nummapbrushsides = 0;
- num_entities = 0;
-
- Sin_ParseEntities();
- //
- for (i = 0; i < num_entities; i++)
- {
- Sin_ParseBSPEntity(i);
- } //end for
-
- //get the map mins and maxs from the world model
- ClearBounds(map_mins, map_maxs);
- for (i = 0; i < entities[0].numbrushes; i++)
- {
- if (mapbrushes[i].mins[0] > 4096)
- continue; //no valid points
- AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs);
- AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs);
- } //end for
- //
- Sin_CreateMapTexinfo();
-} //end of the function Sin_LoadMapFromBSP
-
-void Sin_ResetMapLoading(void)
-{
- //reset for map loading from bsp
- memset(nodestack, 0, NODESTACKSIZE * sizeof(int));
- nodestackptr = NULL;
- nodestacksize = 0;
- memset(brushmodelnumbers, 0, MAX_MAPFILE_BRUSHES * sizeof(int));
-} //end of the function Sin_ResetMapLoading
-
-//End MAP loading from BSP file
-
-#endif //ME
+/*
+===========================================================================
+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
+===========================================================================
+*/
+//-----------------------------------------------------------------------------
+//
+// $Logfile:: /MissionPack/code/bspc/map_sin.c $
+
+#include "qbsp.h"
+#include "l_bsp_sin.h"
+#include "aas_map.h" //AAS_CreateMapBrushes
+
+
+//====================================================================
+
+
+/*
+===========
+Sin_BrushContents
+===========
+*/
+
+int Sin_BrushContents(mapbrush_t *b)
+{
+ int contents;
+ side_t *s;
+ int i;
+#ifdef SIN
+ float trans = 0;
+#else
+ int trans;
+#endif
+
+ s = &b->original_sides[0];
+ contents = s->contents;
+
+#ifdef SIN
+ trans = sin_texinfo[s->texinfo].translucence;
+#else
+ trans = texinfo[s->texinfo].flags;
+#endif
+ for (i=1 ; i<b->numsides ; i++, s++)
+ {
+ s = &b->original_sides[i];
+#ifdef SIN
+ trans += sin_texinfo[s->texinfo].translucence;
+#else
+ trans |= texinfo[s->texinfo].flags;
+#endif
+ if (s->contents != contents)
+ {
+#ifdef SIN
+ if (
+ ( s->contents & CONTENTS_DETAIL && !(contents & CONTENTS_DETAIL) ) ||
+ ( !(s->contents & CONTENTS_DETAIL) && contents & CONTENTS_DETAIL )
+ )
+ {
+ s->contents |= CONTENTS_DETAIL;
+ contents |= CONTENTS_DETAIL;
+ continue;
+ }
+#endif
+ printf ("Entity %i, Brush %i: mixed face contents\n"
+ , b->entitynum, b->brushnum);
+ break;
+ }
+ }
+
+
+#ifdef SIN
+ if (contents & CONTENTS_FENCE)
+ {
+// contents |= CONTENTS_TRANSLUCENT;
+ contents |= CONTENTS_DETAIL;
+ contents |= CONTENTS_DUMMYFENCE;
+ contents &= ~CONTENTS_SOLID;
+ contents &= ~CONTENTS_FENCE;
+ contents |= CONTENTS_WINDOW;
+ }
+#endif
+
+ // if any side is translucent, mark the contents
+ // and change solid to window
+#ifdef SIN
+ if ( trans > 0 )
+#else
+ if ( trans & (SURF_TRANS33|SURF_TRANS66) )
+#endif
+ {
+ contents |= CONTENTS_Q2TRANSLUCENT;
+ if (contents & CONTENTS_SOLID)
+ {
+ contents &= ~CONTENTS_SOLID;
+ contents |= CONTENTS_WINDOW;
+ }
+ }
+
+ return contents;
+} //*/
+
+
+//============================================================================
+
+
+
+/*
+=================
+ParseBrush
+=================
+* /
+void ParseBrush (entity_t *mapent)
+{
+ mapbrush_t *b;
+ int i,j, k;
+ int mt;
+ side_t *side, *s2;
+ int planenum;
+ brush_texture_t td;
+#ifdef SIN
+ textureref_t newref;
+#endif
+ int planepts[3][3];
+
+ if (nummapbrushes == MAX_MAP_BRUSHES)
+ Error ("nummapbrushes == MAX_MAP_BRUSHES");
+
+ b = &mapbrushes[nummapbrushes];
+ b->original_sides = &brushsides[nummapbrushsides];
+ b->entitynum = num_entities-1;
+ b->brushnum = nummapbrushes - mapent->firstbrush;
+
+ do
+ {
+ if (!GetToken (true))
+ break;
+ if (!strcmp (token, "}") )
+ break;
+
+ if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
+ Error ("MAX_MAP_BRUSHSIDES");
+ side = &brushsides[nummapbrushsides];
+
+ // read the three point plane definition
+ for (i=0 ; i<3 ; i++)
+ {
+ if (i != 0)
+ GetToken (true);
+ if (strcmp (token, "(") )
+ Error ("parsing brush");
+
+ for (j=0 ; j<3 ; j++)
+ {
+ GetToken (false);
+ planepts[i][j] = atoi(token);
+ }
+
+ GetToken (false);
+ if (strcmp (token, ")") )
+ Error ("parsing brush");
+
+ }
+
+
+ //
+ // read the texturedef
+ //
+ GetToken (false);
+ strcpy (td.name, token);
+
+ GetToken (false);
+ td.shift[0] = atoi(token);
+ GetToken (false);
+ td.shift[1] = atoi(token);
+ GetToken (false);
+#ifdef SIN
+ td.rotate = atof(token);
+#else
+ td.rotate = atoi(token);
+#endif
+ GetToken (false);
+ td.scale[0] = atof(token);
+ GetToken (false);
+ td.scale[1] = atof(token);
+
+ // find default flags and values
+ mt = FindMiptex (td.name);
+#ifdef SIN
+ // clear out the masks on newref
+ memset(&newref,0,sizeof(newref));
+ // copy over the name
+ strcpy( newref.name, td.name );
+
+ ParseSurfaceInfo( &newref );
+ MergeRefs( &bsp_textureref[mt], &newref, &td.tref );
+ side->contents = td.tref.contents;
+ side->surf = td.tref.flags;
+#else
+ td.flags = textureref[mt].flags;
+ td.value = textureref[mt].value;
+ side->contents = textureref[mt].contents;
+ side->surf = td.flags = textureref[mt].flags;
+
+ if (TokenAvailable())
+ {
+ GetToken (false);
+ side->contents = atoi(token);
+ GetToken (false);
+ side->surf = td.flags = atoi(token);
+ GetToken (false);
+ td.value = atoi(token);
+ }
+#endif
+
+ // translucent objects are automatically classified as detail
+#ifdef SIN
+ if ( td.tref.translucence > 0 )
+#else
+ if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
+#endif
+ side->contents |= CONTENTS_DETAIL;
+ if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
+ side->contents |= CONTENTS_DETAIL;
+ if (fulldetail)
+ side->contents &= ~CONTENTS_DETAIL;
+ if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1)
+ | CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST) ) )
+ side->contents |= CONTENTS_SOLID;
+
+ // hints and skips are never detail, and have no content
+ if (side->surf & (SURF_HINT|SURF_SKIP) )
+ {
+ side->contents = 0;
+#ifndef SIN // I think this is a bug of some kind
+ side->surf &= ~CONTENTS_DETAIL;
+#endif
+ }
+
+ //
+ // find the plane number
+ //
+ planenum = PlaneFromPoints (planepts[0], planepts[1], planepts[2]);
+ if (planenum == -1)
+ {
+ printf ("Entity %i, Brush %i: plane with no normal\n"
+ , b->entitynum, b->brushnum);
+ continue;
+ }
+
+ //
+ // see if the plane has been used already
+ //
+ for (k=0 ; k<b->numsides ; k++)
+ {
+ s2 = b->original_sides + k;
+ if (s2->planenum == planenum)
+ {
+ printf ("Entity %i, Brush %i: duplicate plane\n"
+ , b->entitynum, b->brushnum);
+ break;
+ }
+ if ( s2->planenum == (planenum^1) )
+ {
+ printf ("Entity %i, Brush %i: mirrored plane\n"
+ , b->entitynum, b->brushnum);
+ break;
+ }
+ }
+ if (k != b->numsides)
+ continue; // duplicated
+
+ //
+ // keep this side
+ //
+
+ side = b->original_sides + b->numsides;
+ side->planenum = planenum;
+#ifdef SIN
+ side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum],
+ &td, vec3_origin, &newref);
+ //
+ // save off lightinfo
+ //
+ side->lightinfo = LightinfoForBrushTexture ( &td );
+#else
+ side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum],
+ &td, vec3_origin);
+
+#endif
+
+ // save the td off in case there is an origin brush and we
+ // have to recalculate the texinfo
+ side_brushtextures[nummapbrushsides] = td;
+#ifdef SIN
+ // save off the merged tref for animating textures
+ side_newrefs[nummapbrushsides] = newref;
+#endif
+
+ nummapbrushsides++;
+ b->numsides++;
+ } while (1);
+
+ // get the content for the entire brush
+ b->contents = Sin_BrushContents (b);
+
+ // allow detail brushes to be removed
+ if (nodetail && (b->contents & CONTENTS_DETAIL) )
+ {
+ b->numsides = 0;
+ return;
+ }
+
+ // allow water brushes to be removed
+ if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) )
+ {
+ b->numsides = 0;
+ return;
+ }
+
+ // create windings for sides and bounds for brush
+ MakeBrushWindings (b);
+
+ // brushes that will not be visible at all will never be
+ // used as bsp splitters
+ if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
+ {
+ c_clipbrushes++;
+ for (i=0 ; i<b->numsides ; i++)
+ b->original_sides[i].texinfo = TEXINFO_NODE;
+ }
+
+ //
+ // origin brushes are removed, but they set
+ // the rotation origin for the rest of the brushes
+ // in the entity. After the entire entity is parsed,
+ // the planenums and texinfos will be adjusted for
+ // the origin brush
+ //
+ if (b->contents & CONTENTS_ORIGIN)
+ {
+ char string[32];
+ vec3_t origin;
+
+ if (num_entities == 1)
+ {
+ Error ("Entity %i, Brush %i: origin brushes not allowed in world"
+ , b->entitynum, b->brushnum);
+ return;
+ }
+
+ VectorAdd (b->mins, b->maxs, origin);
+ VectorScale (origin, 0.5, origin);
+
+ sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
+ SetKeyValue (&entities[b->entitynum], "origin", string);
+
+ VectorCopy (origin, entities[b->entitynum].origin);
+
+ // don't keep this brush
+ b->numsides = 0;
+
+ return;
+ }
+
+ AddBrushBevels (b);
+
+ nummapbrushes++;
+ mapent->numbrushes++;
+} //*/
+
+/*
+================
+MoveBrushesToWorld
+
+Takes all of the brushes from the current entity and
+adds them to the world's brush list.
+
+Used by func_group and func_areaportal
+================
+* /
+void MoveBrushesToWorld (entity_t *mapent)
+{
+ int newbrushes;
+ int worldbrushes;
+ mapbrush_t *temp;
+ int i;
+
+ // this is pretty gross, because the brushes are expected to be
+ // in linear order for each entity
+
+ newbrushes = mapent->numbrushes;
+ worldbrushes = entities[0].numbrushes;
+
+ temp = malloc(newbrushes*sizeof(mapbrush_t));
+ memcpy (temp, mapbrushes + mapent->firstbrush, newbrushes*sizeof(mapbrush_t));
+
+#if 0 // let them keep their original brush numbers
+ for (i=0 ; i<newbrushes ; i++)
+ temp[i].entitynum = 0;
+#endif
+
+ // make space to move the brushes (overlapped copy)
+ memmove (mapbrushes + worldbrushes + newbrushes,
+ mapbrushes + worldbrushes,
+ sizeof(mapbrush_t) * (nummapbrushes - worldbrushes - newbrushes) );
+
+ // copy the new brushes down
+ memcpy (mapbrushes + worldbrushes, temp, sizeof(mapbrush_t) * newbrushes);
+
+ // fix up indexes
+ entities[0].numbrushes += newbrushes;
+ for (i=1 ; i<num_entities ; i++)
+ entities[i].firstbrush += newbrushes;
+ free (temp);
+
+ mapent->numbrushes = 0;
+} //*/
+
+/*
+================
+ParseMapEntity
+================
+* /
+qboolean Sin_ParseMapEntity (void)
+{
+ entity_t *mapent;
+ epair_t *e;
+ side_t *s;
+ int i, j;
+ int startbrush, startsides;
+ vec_t newdist;
+ mapbrush_t *b;
+
+ if (!GetToken (true))
+ return false;
+
+ if (strcmp (token, "{") )
+ Error ("ParseEntity: { not found");
+
+ if (num_entities == MAX_MAP_ENTITIES)
+ Error ("num_entities == MAX_MAP_ENTITIES");
+
+ startbrush = nummapbrushes;
+ startsides = nummapbrushsides;
+
+ mapent = &entities[num_entities];
+ num_entities++;
+ memset (mapent, 0, sizeof(*mapent));
+ mapent->firstbrush = nummapbrushes;
+ mapent->numbrushes = 0;
+// mapent->portalareas[0] = -1;
+// mapent->portalareas[1] = -1;
+
+ do
+ {
+ if (!GetToken (true))
+ Error ("ParseEntity: EOF without closing brace");
+ if (!strcmp (token, "}") )
+ break;
+ if (!strcmp (token, "{") )
+ ParseBrush (mapent);
+ else
+ {
+ e = ParseEpair ();
+#ifdef SIN
+ //HACK HACK HACK
+ // MED Gotta do this here
+ if ( !stricmp(e->key, "surfacefile") )
+ {
+ if (!surfacefile[0])
+ {
+ strcpy( surfacefile, e->value );
+ }
+ printf ("--- ParseSurfaceFile ---\n");
+ printf ("Surface script: %s\n", surfacefile);
+ if (!ParseSurfaceFile(surfacefile))
+ {
+ Error ("Script file not found: %s\n", surfacefile);
+ }
+ }
+#endif
+ e->next = mapent->epairs;
+ mapent->epairs = e;
+ }
+ } while (1);
+
+#ifdef SIN
+ if (!(strlen(ValueForKey(mapent, "origin"))) && ((num_entities-1) != 0))
+ {
+ mapbrush_t *brush;
+ vec3_t origin;
+ char string[32];
+ vec3_t mins, maxs;
+ int start, end;
+ // Calculate bounds
+
+ start = mapent->firstbrush;
+ end = start + mapent->numbrushes;
+ ClearBounds (mins, maxs);
+
+ for (j=start ; j<end ; j++)
+ {
+ brush = &mapbrushes[j];
+ if (!brush->numsides)
+ continue; // not a real brush (origin brush) - shouldn't happen
+ AddPointToBounds (brush->mins, mins, maxs);
+ AddPointToBounds (brush->maxs, mins, maxs);
+ }
+
+ // Set the origin to be the centroid of the entity.
+ VectorAdd ( mins, maxs, origin);
+ VectorScale( origin, 0.5f, origin );
+
+ sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
+ SetKeyValue ( mapent, "origin", string);
+// qprintf("Setting origin to %s\n",string);
+ }
+#endif
+
+ GetVectorForKey (mapent, "origin", mapent->origin);
+
+#ifdef SIN
+ if (
+ (!strcmp ("func_areaportal", ValueForKey (mapent, "classname"))) ||
+ (!strcmp ("func_group", ValueForKey (mapent, "classname"))) ||
+ (!strcmp ("detail", ValueForKey (mapent, "classname")) && !entitydetails)
+ )
+ {
+ VectorClear( mapent->origin );
+ }
+#endif
+
+ //
+ // if there was an origin brush, offset all of the planes and texinfo
+ //
+ if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2])
+ {
+ for (i=0 ; i<mapent->numbrushes ; i++)
+ {
+ b = &mapbrushes[mapent->firstbrush + i];
+ for (j=0 ; j<b->numsides ; j++)
+ {
+ s = &b->original_sides[j];
+ newdist = mapplanes[s->planenum].dist -
+ DotProduct (mapplanes[s->planenum].normal, mapent->origin);
+ s->planenum = FindFloatPlane (mapplanes[s->planenum].normal, newdist);
+#ifdef SIN
+ s->texinfo = TexinfoForBrushTexture (&mapplanes[s->planenum],
+ &side_brushtextures[s-brushsides], mapent->origin, &side_newrefs[s-brushsides]);
+ //
+ // save off lightinfo
+ //
+ s->lightinfo = LightinfoForBrushTexture ( &side_brushtextures[s-brushsides] );
+#else
+ s->texinfo = TexinfoForBrushTexture (&mapplanes[s->planenum],
+ &side_brushtextures[s-brushsides], mapent->origin);
+#endif
+ }
+ MakeBrushWindings (b);
+ }
+ }
+
+ // group entities are just for editor convenience
+ // toss all brushes into the world entity
+ if (!strcmp ("func_group", ValueForKey (mapent, "classname")))
+ {
+ MoveBrushesToWorld (mapent);
+ mapent->numbrushes = 0;
+ mapent->wasdetail = true;
+ FreeValueKeys( mapent );
+ return true;
+ }
+#ifdef SIN
+ // detail entities are just for editor convenience
+ // toss all brushes into the world entity as detail brushes
+ if (!strcmp ("detail", ValueForKey (mapent, "classname")) && !entitydetails)
+ {
+ for (i=0 ; i<mapent->numbrushes ; i++)
+ {
+ int j;
+ side_t * s;
+ b = &mapbrushes[mapent->firstbrush + i];
+ if (nodetail)
+ {
+ b->numsides = 0;
+ continue;
+ }
+ if (!fulldetail)
+ {
+ // set the contents for the entire brush
+ b->contents |= CONTENTS_DETAIL;
+ // set the contents in the sides as well
+ for (j=0, s=b->original_sides ; j<b->numsides ; j++,s++)
+ {
+ s->contents |= CONTENTS_DETAIL;
+ }
+ }
+ else
+ {
+ // set the contents for the entire brush
+ b->contents |= CONTENTS_SOLID;
+ // set the contents in the sides as well
+ for (j=0, s=b->original_sides ; j<b->numsides ; j++,s++)
+ {
+ s->contents |= CONTENTS_SOLID;
+ }
+ }
+ }
+ MoveBrushesToWorld (mapent);
+ mapent->wasdetail = true;
+ FreeValueKeys( mapent );
+ // kill off the entity
+ // num_entities--;
+ return true;
+ }
+#endif
+
+ // areaportal entities move their brushes, but don't eliminate
+ // the entity
+ if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname")))
+ {
+ char str[128];
+
+ if (mapent->numbrushes != 1)
+ Error ("Entity %i: func_areaportal can only be a single brush", num_entities-1);
+
+ b = &mapbrushes[nummapbrushes-1];
+ b->contents = CONTENTS_AREAPORTAL;
+ c_areaportals++;
+ mapent->areaportalnum = c_areaportals;
+ // set the portal number as "style"
+ sprintf (str, "%i", c_areaportals);
+ SetKeyValue (mapent, "style", str);
+ MoveBrushesToWorld (mapent);
+ return true;
+ }
+
+ return true;
+} //end of the function Sin_ParseMapEntity */
+
+//===================================================================
+
+/*
+================
+LoadMapFile
+================
+* /
+void Sin_LoadMapFile (char *filename)
+{
+ int i;
+#ifdef SIN
+ int num_detailsides=0;
+ int num_detailbrushes=0;
+ int num_worldsides=0;
+ int num_worldbrushes=0;
+ int j,k;
+#endif
+
+ qprintf ("--- LoadMapFile ---\n");
+
+ LoadScriptFile (filename);
+
+ nummapbrushsides = 0;
+ num_entities = 0;
+
+ while (ParseMapEntity ())
+ {
+ }
+
+ ClearBounds (map_mins, map_maxs);
+ for (i=0 ; i<entities[0].numbrushes ; i++)
+ {
+ if (mapbrushes[i].mins[0] > 4096)
+ continue; // no valid points
+ AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs);
+ AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs);
+ }
+#ifdef SIN
+ for (j=0; j<num_entities; j++)
+ {
+ for (i=0 ; i<entities[j].numbrushes ; i++)
+ {
+ side_t * s;
+ mapbrush_t *b;
+ b = &mapbrushes[entities[j].firstbrush + i];
+ if (b->numsides && b->contents & CONTENTS_DETAIL)
+ num_detailbrushes++;
+ else if (b->numsides)
+ num_worldbrushes++;
+ for (k=0, s=b->original_sides ; k<b->numsides ; k++,s++)
+ {
+ if (s->contents & CONTENTS_DETAIL)
+ num_detailsides++;
+ else
+ num_worldsides++;
+ }
+ }
+ }
+#endif
+
+ qprintf ("%5i brushes\n", nummapbrushes);
+ qprintf ("%5i clipbrushes\n", c_clipbrushes);
+ qprintf ("%5i total sides\n", nummapbrushsides);
+ qprintf ("%5i boxbevels\n", c_boxbevels);
+ qprintf ("%5i edgebevels\n", c_edgebevels);
+ qprintf ("%5i entities\n", num_entities);
+ qprintf ("%5i planes\n", nummapplanes);
+ qprintf ("%5i areaportals\n", c_areaportals);
+ qprintf ("size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", map_mins[0],map_mins[1],map_mins[2],
+ map_maxs[0],map_maxs[1],map_maxs[2]);
+#ifdef SIN
+ qprintf ("%5i detailbrushes\n", num_detailbrushes);
+ qprintf ("%5i worldbrushes\n", num_worldbrushes);
+ qprintf ("%5i detailsides\n", num_detailsides);
+ qprintf ("%5i worldsides\n", num_worldsides);
+#endif
+
+} //end of the function Sin_LoadMap */
+
+
+#ifdef ME //Begin MAP loading from BSP file
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Sin_CreateMapTexinfo(void)
+{
+ int i;
+ vec_t defaultvec[4] = {1, 0, 0, 0};
+
+ memcpy(map_texinfo[0].vecs[0], defaultvec, sizeof(defaultvec));
+ memcpy(map_texinfo[0].vecs[1], defaultvec, sizeof(defaultvec));
+ map_texinfo[0].flags = 0;
+ map_texinfo[0].value = 0;
+ strcpy(map_texinfo[0].texture, "generic/misc/red"); //no texture
+ map_texinfo[0].nexttexinfo = -1;
+ for (i = 1; i < sin_numtexinfo; i++)
+ {
+ memcpy(map_texinfo[i].vecs, sin_texinfo[i].vecs, sizeof(float) * 2 * 4);
+ map_texinfo[i].flags = sin_texinfo[i].flags;
+ map_texinfo[i].value = 0;
+ strcpy(map_texinfo[i].texture, sin_texinfo[i].texture);
+ map_texinfo[i].nexttexinfo = -1;
+ } //end for
+} //end of the function Sin_CreateMapTexinfo
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Sin_SetLeafBrushesModelNumbers(int leafnum, int modelnum)
+{
+ int i, brushnum;
+ sin_dleaf_t *leaf;
+
+ leaf = &sin_dleafs[leafnum];
+ for (i = 0; i < leaf->numleafbrushes; i++)
+ {
+ brushnum = sin_dleafbrushes[leaf->firstleafbrush + i];
+ brushmodelnumbers[brushnum] = modelnum;
+ dbrushleafnums[brushnum] = leafnum;
+ } //end for
+} //end of the function Sin_SetLeafBrushesModelNumbers
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Sin_InitNodeStack(void)
+{
+ nodestackptr = nodestack;
+ nodestacksize = 0;
+} //end of the function Sin_InitNodeStack
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Sin_PushNodeStack(int num)
+{
+ *nodestackptr = num;
+ nodestackptr++;
+ nodestacksize++;
+ //
+ if (nodestackptr >= &nodestack[NODESTACKSIZE])
+ {
+ Error("Sin_PushNodeStack: stack overflow\n");
+ } //end if
+} //end of the function Sin_PushNodeStack
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int Sin_PopNodeStack(void)
+{
+ //if the stack is empty
+ if (nodestackptr <= nodestack) return -1;
+ //decrease stack pointer
+ nodestackptr--;
+ nodestacksize--;
+ //return the top value from the stack
+ return *nodestackptr;
+} //end of the function Sin_PopNodeStack
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Sin_SetBrushModelNumbers(entity_t *mapent)
+{
+ int n, pn;
+ int leafnum;
+
+ //
+ Sin_InitNodeStack();
+ //head node (root) of the bsp tree
+ n = sin_dmodels[mapent->modelnum].headnode;
+ pn = 0;
+
+ do
+ {
+ //if we are in a leaf (negative node number)
+ if (n < 0)
+ {
+ //number of the leaf
+ leafnum = (-n) - 1;
+ //set the brush numbers
+ Sin_SetLeafBrushesModelNumbers(leafnum, mapent->modelnum);
+ //walk back into the tree to find a second child to continue with
+ for (pn = Sin_PopNodeStack(); pn >= 0; n = pn, pn = Sin_PopNodeStack())
+ {
+ //if we took the first child at the parent node
+ if (sin_dnodes[pn].children[0] == n) break;
+ } //end for
+ //if the stack wasn't empty (if not processed whole tree)
+ if (pn >= 0)
+ {
+ //push the parent node again
+ Sin_PushNodeStack(pn);
+ //we proceed with the second child of the parent node
+ n = sin_dnodes[pn].children[1];
+ } //end if
+ } //end if
+ else
+ {
+ //push the current node onto the stack
+ Sin_PushNodeStack(n);
+ //walk forward into the tree to the first child
+ n = sin_dnodes[n].children[0];
+ } //end else
+ } while(pn >= 0);
+} //end of the function Sin_SetBrushModelNumbers
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Sin_BSPBrushToMapBrush(sin_dbrush_t *bspbrush, entity_t *mapent)
+{
+ mapbrush_t *b;
+ int i, k, n;
+ side_t *side, *s2;
+ int planenum;
+ sin_dbrushside_t *bspbrushside;
+ sin_dplane_t *bspplane;
+
+ if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
+ Error ("nummapbrushes >= MAX_MAPFILE_BRUSHES");
+
+ b = &mapbrushes[nummapbrushes];
+ b->original_sides = &brushsides[nummapbrushsides];
+ b->entitynum = mapent-entities;
+ b->brushnum = nummapbrushes - mapent->firstbrush;
+ b->leafnum = dbrushleafnums[bspbrush - sin_dbrushes];
+
+ for (n = 0; n < bspbrush->numsides; n++)
+ {
+ //pointer to the bsp brush side
+ bspbrushside = &sin_dbrushsides[bspbrush->firstside + n];
+
+ if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
+ {
+ Error ("MAX_MAPFILE_BRUSHSIDES");
+ } //end if
+ //pointer to the map brush side
+ side = &brushsides[nummapbrushsides];
+ //if the BSP brush side is textured
+ if (sin_dbrushsidetextured[bspbrush->firstside + n]) side->flags |= SFL_TEXTURED;
+ else side->flags &= ~SFL_TEXTURED;
+ //ME: can get side contents and surf directly from BSP file
+ side->contents = bspbrush->contents;
+ //if the texinfo is TEXINFO_NODE
+ if (bspbrushside->texinfo < 0) side->surf = 0;
+ else side->surf = sin_texinfo[bspbrushside->texinfo].flags;
+
+ // translucent objects are automatically classified as detail
+ if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
+ side->contents |= CONTENTS_DETAIL;
+ if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
+ side->contents |= CONTENTS_DETAIL;
+ if (fulldetail)
+ side->contents &= ~CONTENTS_DETAIL;
+ if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1)
+ | CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST) ) )
+ side->contents |= CONTENTS_SOLID;
+
+ // hints and skips are never detail, and have no content
+ if (side->surf & (SURF_HINT|SURF_SKIP) )
+ {
+ side->contents = 0;
+ side->surf &= ~CONTENTS_DETAIL;
+ }
+
+ //ME: get a plane for this side
+ bspplane = &sin_dplanes[bspbrushside->planenum];
+ planenum = FindFloatPlane(bspplane->normal, bspplane->dist);
+ //
+ // see if the plane has been used already
+ //
+ //ME: this really shouldn't happen!!!
+ //ME: otherwise the bsp file is corrupted??
+ //ME: still it seems to happen, maybe Johny Boy's
+ //ME: brush bevel adding is crappy ?
+ for (k = 0; k < b->numsides; k++)
+ {
+ s2 = b->original_sides + k;
+ if (s2->planenum == planenum)
+ {
+ Log_Print("Entity %i, Brush %i: duplicate plane\n"
+ , b->entitynum, b->brushnum);
+ break;
+ }
+ if ( s2->planenum == (planenum^1) )
+ {
+ Log_Print("Entity %i, Brush %i: mirrored plane\n"
+ , b->entitynum, b->brushnum);
+ break;
+ }
+ }
+ if (k != b->numsides)
+ continue; // duplicated
+
+ //
+ // keep this side
+ //
+ //ME: reset pointer to side, why? hell I dunno (pointer is set above already)
+ side = b->original_sides + b->numsides;
+ //ME: store the plane number
+ side->planenum = planenum;
+ //ME: texinfo is already stored when bsp is loaded
+ //NOTE: check for TEXINFO_NODE, otherwise crash in Sin_BrushContents
+ if (bspbrushside->texinfo < 0) side->texinfo = 0;
+ else side->texinfo = bspbrushside->texinfo;
+
+ // save the td off in case there is an origin brush and we
+ // have to recalculate the texinfo
+ // ME: don't need to recalculate because it's already done
+ // (for non-world entities) in the BSP file
+// side_brushtextures[nummapbrushsides] = td;
+
+ nummapbrushsides++;
+ b->numsides++;
+ } //end for
+
+ // get the content for the entire brush
+ b->contents = bspbrush->contents;
+ Sin_BrushContents(b);
+
+ if (BrushExists(b))
+ {
+ c_squattbrushes++;
+ b->numsides = 0;
+ return;
+ } //end if
+
+ //if we're creating AAS
+ if (create_aas)
+ {
+ //create the AAS brushes from this brush, don't add brush bevels
+ AAS_CreateMapBrushes(b, mapent, false);
+ return;
+ } //end if
+
+ // allow detail brushes to be removed
+ if (nodetail && (b->contents & CONTENTS_DETAIL) )
+ {
+ b->numsides = 0;
+ return;
+ } //end if
+
+ // allow water brushes to be removed
+ if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) )
+ {
+ b->numsides = 0;
+ return;
+ } //end if
+
+ // create windings for sides and bounds for brush
+ MakeBrushWindings(b);
+
+ //mark brushes without winding or with a tiny window as bevels
+ MarkBrushBevels(b);
+
+ // brushes that will not be visible at all will never be
+ // used as bsp splitters
+ if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
+ {
+ c_clipbrushes++;
+ for (i = 0; i < b->numsides; i++)
+ b->original_sides[i].texinfo = TEXINFO_NODE;
+ } //end for
+
+ //
+ // origin brushes are removed, but they set
+ // the rotation origin for the rest of the brushes
+ // in the entity. After the entire entity is parsed,
+ // the planenums and texinfos will be adjusted for
+ // the origin brush
+ //
+ //ME: not needed because the entities in the BSP file already
+ // have an origin set
+// if (b->contents & CONTENTS_ORIGIN)
+// {
+// char string[32];
+// vec3_t origin;
+//
+// if (num_entities == 1)
+// {
+// Error ("Entity %i, Brush %i: origin brushes not allowed in world"
+// , b->entitynum, b->brushnum);
+// return;
+// }
+//
+// VectorAdd (b->mins, b->maxs, origin);
+// VectorScale (origin, 0.5, origin);
+//
+// sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
+// SetKeyValue (&entities[b->entitynum], "origin", string);
+//
+// VectorCopy (origin, entities[b->entitynum].origin);
+//
+// // don't keep this brush
+// b->numsides = 0;
+//
+// return;
+// }
+
+ //ME: the bsp brushes already have bevels, so we won't try to
+ // add them again (especially since Johny Boy's bevel adding might
+ // be crappy)
+// AddBrushBevels(b);
+
+ nummapbrushes++;
+ mapent->numbrushes++;
+} //end of the function Sin_BSPBrushToMapBrush
+//===========================================================================
+//===========================================================================
+void Sin_ParseBSPBrushes(entity_t *mapent)
+{
+ int i, testnum = 0;
+
+ //give all the brushes that belong to this entity the number of the
+ //BSP model used by this entity
+ Sin_SetBrushModelNumbers(mapent);
+ //now parse all the brushes with the correct mapent->modelnum
+ for (i = 0; i < sin_numbrushes; i++)
+ {
+ if (brushmodelnumbers[i] == mapent->modelnum)
+ {
+ testnum++;
+ Sin_BSPBrushToMapBrush(&sin_dbrushes[i], mapent);
+ } //end if
+ } //end for
+} //end of the function Sin_ParseBSPBrushes
+//===========================================================================
+//===========================================================================
+qboolean Sin_ParseBSPEntity(int entnum)
+{
+ entity_t *mapent;
+ char *model;
+ int startbrush, startsides;
+
+ startbrush = nummapbrushes;
+ startsides = nummapbrushsides;
+
+ mapent = &entities[entnum];//num_entities];
+ mapent->firstbrush = nummapbrushes;
+ mapent->numbrushes = 0;
+ mapent->modelnum = -1; //-1 = no model
+
+ model = ValueForKey(mapent, "model");
+ if (model && *model == '*')
+ {
+ mapent->modelnum = atoi(&model[1]);
+ //Log_Print("model = %s\n", model);
+ //Log_Print("mapent->modelnum = %d\n", mapent->modelnum);
+ } //end if
+
+ GetVectorForKey(mapent, "origin", mapent->origin);
+
+ //if this is the world entity it has model number zero
+ //the world entity has no model key
+ if (!strcmp("worldspawn", ValueForKey(mapent, "classname")))
+ {
+ mapent->modelnum = 0;
+ } //end if
+ //if the map entity has a BSP model (a modelnum of -1 is used for
+ //entities that aren't using a BSP model)
+ if (mapent->modelnum >= 0)
+ {
+ //parse the bsp brushes
+ Sin_ParseBSPBrushes(mapent);
+ } //end if
+ //
+ //the origin of the entity is already taken into account
+ //
+ //func_group entities can't be in the bsp file
+ //
+ //check out the func_areaportal entities
+ if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname")))
+ {
+ c_areaportals++;
+ mapent->areaportalnum = c_areaportals;
+ return true;
+ } //end if
+ return true;
+} //end of the function Sin_ParseBSPEntity
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Sin_LoadMapFromBSP(char *filename, int offset, int length)
+{
+ int i;
+
+ Log_Print("-- Sin_LoadMapFromBSP --\n");
+ //loaded map type
+ loadedmaptype = MAPTYPE_SIN;
+
+ Log_Print("Loading map from %s...\n", filename);
+ //load the bsp file
+ Sin_LoadBSPFile(filename, offset, length);
+
+ //create an index from bsp planes to map planes
+ //DPlanes2MapPlanes();
+ //clear brush model numbers
+ for (i = 0; i < MAX_MAPFILE_BRUSHES; i++)
+ brushmodelnumbers[i] = -1;
+
+ nummapbrushsides = 0;
+ num_entities = 0;
+
+ Sin_ParseEntities();
+ //
+ for (i = 0; i < num_entities; i++)
+ {
+ Sin_ParseBSPEntity(i);
+ } //end for
+
+ //get the map mins and maxs from the world model
+ ClearBounds(map_mins, map_maxs);
+ for (i = 0; i < entities[0].numbrushes; i++)
+ {
+ if (mapbrushes[i].mins[0] > 4096)
+ continue; //no valid points
+ AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs);
+ AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs);
+ } //end for
+ //
+ Sin_CreateMapTexinfo();
+} //end of the function Sin_LoadMapFromBSP
+
+void Sin_ResetMapLoading(void)
+{
+ //reset for map loading from bsp
+ memset(nodestack, 0, NODESTACKSIZE * sizeof(int));
+ nodestackptr = NULL;
+ nodestacksize = 0;
+ memset(brushmodelnumbers, 0, MAX_MAPFILE_BRUSHES * sizeof(int));
+} //end of the function Sin_ResetMapLoading
+
+//End MAP loading from BSP file
+
+#endif //ME
diff --git a/code/bspc/nodraw.c b/code/bspc/nodraw.c
index b5442dc..7503a48 100755
--- a/code/bspc/nodraw.c
+++ b/code/bspc/nodraw.c
@@ -1,47 +1,47 @@
-/*
-===========================================================================
-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"
-
-vec3_t draw_mins, draw_maxs;
-qboolean drawflag;
-
-void Draw_ClearWindow (void)
-{
-}
-
-//============================================================
-
-#define GLSERV_PORT 25001
-
-
-void GLS_BeginScene (void)
-{
-}
-
-void GLS_Winding (winding_t *w, int code)
-{
-}
-
-void GLS_EndScene (void)
-{
-}
+/*
+===========================================================================
+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"
+
+vec3_t draw_mins, draw_maxs;
+qboolean drawflag;
+
+void Draw_ClearWindow (void)
+{
+}
+
+//============================================================
+
+#define GLSERV_PORT 25001
+
+
+void GLS_BeginScene (void)
+{
+}
+
+void GLS_Winding (winding_t *w, int code)
+{
+}
+
+void GLS_EndScene (void)
+{
+}
diff --git a/code/bspc/portals.c b/code/bspc/portals.c
index 3d3389d..cde4f60 100755
--- a/code/bspc/portals.c
+++ b/code/bspc/portals.c
@@ -1,1297 +1,1297 @@
-/*
-===========================================================================
-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 "l_mem.h"
-
-int c_active_portals;
-int c_peak_portals;
-int c_boundary;
-int c_boundary_sides;
-int c_portalmemory;
-
-//portal_t *portallist = NULL;
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-portal_t *AllocPortal (void)
-{
- portal_t *p;
-
- p = GetMemory(sizeof(portal_t));
- memset (p, 0, sizeof(portal_t));
-
- if (numthreads == 1)
- {
- c_active_portals++;
- if (c_active_portals > c_peak_portals)
- {
- c_peak_portals = c_active_portals;
- } //end if
- c_portalmemory += MemorySize(p);
- } //end if
-
-// p->nextportal = portallist;
-// portallist = p;
-
- return p;
-} //end of the function AllocPortal
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void FreePortal (portal_t *p)
-{
- if (p->winding) FreeWinding(p->winding);
- if (numthreads == 1)
- {
- c_active_portals--;
- c_portalmemory -= MemorySize(p);
- } //end if
- FreeMemory(p);
-} //end of the function FreePortal
-//===========================================================================
-// Returns the single content bit of the
-// strongest visible content present
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int VisibleContents (int contents)
-{
- int i;
-
- for (i=1 ; i<=LAST_VISIBLE_CONTENTS ; i<<=1)
- if (contents & i )
- return i;
-
- return 0;
-} //end of the function VisibleContents
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int ClusterContents (node_t *node)
-{
- int c1, c2, c;
-
- if (node->planenum == PLANENUM_LEAF)
- return node->contents;
-
- c1 = ClusterContents(node->children[0]);
- c2 = ClusterContents(node->children[1]);
- c = c1|c2;
-
- // a cluster may include some solid detail areas, but
- // still be seen into
- if ( ! (c1&CONTENTS_SOLID) || ! (c2&CONTENTS_SOLID) )
- c &= ~CONTENTS_SOLID;
- return c;
-} //end of the function ClusterContents
-
-//===========================================================================
-// Returns true if the portal is empty or translucent, allowing
-// the PVS calculation to see through it.
-// The nodes on either side of the portal may actually be clusters,
-// not leaves, so all contents should be ored together
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean Portal_VisFlood (portal_t *p)
-{
- int c1, c2;
-
- if (!p->onnode)
- return false; // to global outsideleaf
-
- c1 = ClusterContents(p->nodes[0]);
- c2 = ClusterContents(p->nodes[1]);
-
- if (!VisibleContents (c1^c2))
- return true;
-
- if (c1 & (CONTENTS_Q2TRANSLUCENT|CONTENTS_DETAIL))
- c1 = 0;
- if (c2 & (CONTENTS_Q2TRANSLUCENT|CONTENTS_DETAIL))
- c2 = 0;
-
- if ( (c1|c2) & CONTENTS_SOLID )
- return false; // can't see through solid
-
- if (! (c1 ^ c2))
- return true; // identical on both sides
-
- if (!VisibleContents (c1^c2))
- return true;
- return false;
-} //end of the function Portal_VisFlood
-//===========================================================================
-// The entity flood determines which areas are
-// "outside" on the map, which are then filled in.
-// Flowing from side s to side !s
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean Portal_EntityFlood (portal_t *p, int s)
-{
- if (p->nodes[0]->planenum != PLANENUM_LEAF
- || p->nodes[1]->planenum != PLANENUM_LEAF)
- Error ("Portal_EntityFlood: not a leaf");
-
- // can never cross to a solid
- if ( (p->nodes[0]->contents & CONTENTS_SOLID)
- || (p->nodes[1]->contents & CONTENTS_SOLID) )
- return false;
-
- // can flood through everything else
- return true;
-}
-
-
-//=============================================================================
-
-int c_tinyportals;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AddPortalToNodes (portal_t *p, node_t *front, node_t *back)
-{
- if (p->nodes[0] || p->nodes[1])
- Error ("AddPortalToNode: allready included");
-
- p->nodes[0] = front;
- p->next[0] = front->portals;
- front->portals = p;
-
- p->nodes[1] = back;
- p->next[1] = back->portals;
- back->portals = p;
-} //end of the function AddPortalToNodes
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void RemovePortalFromNode (portal_t *portal, node_t *l)
-{
- portal_t **pp, *t;
-
- int s, i, n;
- portal_t *p;
- portal_t *portals[4096];
-
-// remove reference to the current portal
- pp = &l->portals;
- while (1)
- {
- t = *pp;
- if (!t)
- Error ("RemovePortalFromNode: portal not in leaf");
-
- if ( t == portal )
- break;
-
- if (t->nodes[0] == l)
- pp = &t->next[0];
- else if (t->nodes[1] == l)
- pp = &t->next[1];
- else
- Error ("RemovePortalFromNode: portal not bounding leaf");
- }
-
- if (portal->nodes[0] == l)
- {
- *pp = portal->next[0];
- portal->nodes[0] = NULL;
- } //end if
- else if (portal->nodes[1] == l)
- {
- *pp = portal->next[1];
- portal->nodes[1] = NULL;
- } //end else if
- else
- {
- Error("RemovePortalFromNode: mislinked portal");
- } //end else
-//#ifdef ME
- n = 0;
- for (p = l->portals; p; p = p->next[s])
- {
- for (i = 0; i < n; i++)
- {
- if (p == portals[i]) Error("RemovePortalFromNode: circular linked\n");
- } //end for
- if (p->nodes[0] != l && p->nodes[1] != l)
- {
- Error("RemovePortalFromNodes: portal does not belong to node\n");
- } //end if
- portals[n] = p;
- s = (p->nodes[1] == l);
-// if (++n >= 4096) Error("RemovePortalFromNode: more than 4096 portals\n");
- } //end for
-//#endif
-} //end of the function RemovePortalFromNode
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void PrintPortal (portal_t *p)
-{
- int i;
- winding_t *w;
-
- w = p->winding;
- for (i=0 ; i<w->numpoints ; i++)
- printf ("(%5.0f,%5.0f,%5.0f)\n",w->p[i][0]
- , w->p[i][1], w->p[i][2]);
-} //end of the function PrintPortal
-//===========================================================================
-// The created portals will face the global outside_node
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#define SIDESPACE 8
-
-void MakeHeadnodePortals (tree_t *tree)
-{
- vec3_t bounds[2];
- int i, j, n;
- portal_t *p, *portals[6];
- plane_t bplanes[6], *pl;
- node_t *node;
-
- node = tree->headnode;
-
-// pad with some space so there will never be null volume leaves
- for (i=0 ; i<3 ; i++)
- {
- bounds[0][i] = tree->mins[i] - SIDESPACE;
- bounds[1][i] = tree->maxs[i] + SIDESPACE;
- if ( bounds[0][i] > bounds[1][i] ) {
- Error("empty BSP tree");
- }
- }
-
- tree->outside_node.planenum = PLANENUM_LEAF;
- tree->outside_node.brushlist = NULL;
- tree->outside_node.portals = NULL;
- tree->outside_node.contents = 0;
-
- for (i=0 ; i<3 ; i++)
- for (j=0 ; j<2 ; j++)
- {
- n = j*3 + i;
-
- p = AllocPortal ();
- portals[n] = p;
-
- pl = &bplanes[n];
- memset (pl, 0, sizeof(*pl));
- if (j)
- {
- pl->normal[i] = -1;
- pl->dist = -bounds[j][i];
- }
- else
- {
- pl->normal[i] = 1;
- pl->dist = bounds[j][i];
- }
- p->plane = *pl;
- p->winding = BaseWindingForPlane (pl->normal, pl->dist);
- AddPortalToNodes (p, node, &tree->outside_node);
- }
-
-// clip the basewindings by all the other planes
- for (i=0 ; i<6 ; i++)
- {
- for (j=0 ; j<6 ; j++)
- {
- if (j == i) continue;
- ChopWindingInPlace (&portals[i]->winding, bplanes[j].normal, bplanes[j].dist, ON_EPSILON);
- } //end for
- } //end for
-} //end of the function MakeHeadNodePortals
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#define BASE_WINDING_EPSILON 0.001
-#define SPLIT_WINDING_EPSILON 0.001
-
-winding_t *BaseWindingForNode (node_t *node)
-{
- winding_t *w;
- node_t *n;
- plane_t *plane;
- vec3_t normal;
- vec_t dist;
-
- w = BaseWindingForPlane (mapplanes[node->planenum].normal
- , mapplanes[node->planenum].dist);
-
- // clip by all the parents
- for (n=node->parent ; n && w ; )
- {
- plane = &mapplanes[n->planenum];
-
- if (n->children[0] == node)
- { // take front
- ChopWindingInPlace (&w, plane->normal, plane->dist, BASE_WINDING_EPSILON);
- }
- else
- { // take back
- VectorSubtract (vec3_origin, plane->normal, normal);
- dist = -plane->dist;
- ChopWindingInPlace (&w, normal, dist, BASE_WINDING_EPSILON);
- }
- node = n;
- n = n->parent;
- }
-
- return w;
-} //end of the function BaseWindingForNode
-//===========================================================================
-// create the new portal by taking the full plane winding for the cutting
-// plane and clipping it by all of parents of this node
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean WindingIsTiny (winding_t *w);
-
-void MakeNodePortal (node_t *node)
-{
- portal_t *new_portal, *p;
- winding_t *w;
- vec3_t normal;
- float dist;
- int side;
-
- w = BaseWindingForNode (node);
-
- // clip the portal by all the other portals in the node
- for (p = node->portals; p && w; p = p->next[side])
- {
- if (p->nodes[0] == node)
- {
- side = 0;
- VectorCopy (p->plane.normal, normal);
- dist = p->plane.dist;
- } //end if
- else if (p->nodes[1] == node)
- {
- side = 1;
- VectorSubtract (vec3_origin, p->plane.normal, normal);
- dist = -p->plane.dist;
- } //end else if
- else
- {
- Error ("MakeNodePortal: mislinked portal");
- } //end else
- ChopWindingInPlace (&w, normal, dist, 0.1);
- } //end for
-
- if (!w)
- {
- return;
- } //end if
-
- if (WindingIsTiny (w))
- {
- c_tinyportals++;
- FreeWinding(w);
- return;
- } //end if
-
-#ifdef DEBUG
-/* //NOTE: don't use this winding ok check
- // all the invalid windings only have a degenerate edge
- if (WindingError(w))
- {
- Log_Print("MakeNodePortal: %s\n", WindingErrorString());
- FreeWinding(w);
- return;
- } //end if*/
-#endif //DEBUG
-
-
- new_portal = AllocPortal();
- new_portal->plane = mapplanes[node->planenum];
-
-#ifdef ME
- new_portal->planenum = node->planenum;
-#endif //ME
-
- new_portal->onnode = node;
- new_portal->winding = w;
- AddPortalToNodes (new_portal, node->children[0], node->children[1]);
-} //end of the function MakeNodePortal
-//===========================================================================
-// Move or split the portals that bound node so that the node's
-// children have portals instead of node.
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void SplitNodePortals (node_t *node)
-{
- portal_t *p, *next_portal, *new_portal;
- node_t *f, *b, *other_node;
- int side;
- plane_t *plane;
- winding_t *frontwinding, *backwinding;
-
- plane = &mapplanes[node->planenum];
- f = node->children[0];
- b = node->children[1];
-
- for (p = node->portals ; p ; p = next_portal)
- {
- if (p->nodes[0] == node) side = 0;
- else if (p->nodes[1] == node) side = 1;
- else Error ("SplitNodePortals: mislinked portal");
- next_portal = p->next[side];
-
- other_node = p->nodes[!side];
- RemovePortalFromNode (p, p->nodes[0]);
- RemovePortalFromNode (p, p->nodes[1]);
-
-//
-// cut the portal into two portals, one on each side of the cut plane
-//
- ClipWindingEpsilon (p->winding, plane->normal, plane->dist,
- SPLIT_WINDING_EPSILON, &frontwinding, &backwinding);
-
- if (frontwinding && WindingIsTiny(frontwinding))
- {
- FreeWinding (frontwinding);
- frontwinding = NULL;
- c_tinyportals++;
- } //end if
-
- if (backwinding && WindingIsTiny(backwinding))
- {
- FreeWinding (backwinding);
- backwinding = NULL;
- c_tinyportals++;
- } //end if
-
-#ifdef DEBUG
-/* //NOTE: don't use this winding ok check
- // all the invalid windings only have a degenerate edge
- if (frontwinding && WindingError(frontwinding))
- {
- Log_Print("SplitNodePortals: front %s\n", WindingErrorString());
- FreeWinding(frontwinding);
- frontwinding = NULL;
- } //end if
- if (backwinding && WindingError(backwinding))
- {
- Log_Print("SplitNodePortals: back %s\n", WindingErrorString());
- FreeWinding(backwinding);
- backwinding = NULL;
- } //end if*/
-#endif //DEBUG
-
- if (!frontwinding && !backwinding)
- { // tiny windings on both sides
- continue;
- }
-
- if (!frontwinding)
- {
- FreeWinding (backwinding);
- if (side == 0) AddPortalToNodes (p, b, other_node);
- else AddPortalToNodes (p, other_node, b);
- continue;
- }
- if (!backwinding)
- {
- FreeWinding (frontwinding);
- if (side == 0) AddPortalToNodes (p, f, other_node);
- else AddPortalToNodes (p, other_node, f);
- continue;
- }
-
- // the winding is split
- new_portal = AllocPortal();
- *new_portal = *p;
- new_portal->winding = backwinding;
- FreeWinding (p->winding);
- p->winding = frontwinding;
-
- if (side == 0)
- {
- AddPortalToNodes (p, f, other_node);
- AddPortalToNodes (new_portal, b, other_node);
- } //end if
- else
- {
- AddPortalToNodes (p, other_node, f);
- AddPortalToNodes (new_portal, other_node, b);
- } //end else
- }
-
- node->portals = NULL;
-} //end of the function SplitNodePortals
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void CalcNodeBounds (node_t *node)
-{
- portal_t *p;
- int s;
- int i;
-
- // calc mins/maxs for both leaves and nodes
- ClearBounds (node->mins, node->maxs);
- for (p = node->portals ; p ; p = p->next[s])
- {
- s = (p->nodes[1] == node);
- for (i=0 ; i<p->winding->numpoints ; i++)
- AddPointToBounds (p->winding->p[i], node->mins, node->maxs);
- }
-} //end of the function CalcNodeBounds
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int c_numportalizednodes;
-
-void MakeTreePortals_r (node_t *node)
-{
- int i;
-
-#ifdef ME
- qprintf("\r%6d", ++c_numportalizednodes);
- if (cancelconversion) return;
-#endif //ME
-
- CalcNodeBounds (node);
- if (node->mins[0] >= node->maxs[0])
- {
- Log_Print("WARNING: node without a volume\n");
- }
-
- for (i=0 ; i<3 ; i++)
- {
- if (node->mins[i] < -MAX_MAP_BOUNDS || node->maxs[i] > MAX_MAP_BOUNDS)
- {
- Log_Print("WARNING: node with unbounded volume\n");
- break;
- }
- }
- if (node->planenum == PLANENUM_LEAF)
- return;
-
- MakeNodePortal (node);
- SplitNodePortals (node);
-
- MakeTreePortals_r (node->children[0]);
- MakeTreePortals_r (node->children[1]);
-} //end of the function MakeTreePortals_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void MakeTreePortals(tree_t *tree)
-{
-
-#ifdef ME
- Log_Print("---- Node Portalization ----\n");
- c_numportalizednodes = 0;
- c_portalmemory = 0;
- qprintf("%6d nodes portalized", c_numportalizednodes);
-#endif //ME
-
- MakeHeadnodePortals(tree);
- MakeTreePortals_r(tree->headnode);
-
-#ifdef ME
- qprintf("\n");
- Log_Write("%6d nodes portalized\r\n", c_numportalizednodes);
- Log_Print("%6d tiny portals\r\n", c_tinyportals);
- Log_Print("%6d KB of portal memory\r\n", c_portalmemory >> 10);
- Log_Print("%6i KB of winding memory\r\n", WindingMemory() >> 10);
-#endif //ME
-} //end of the function MakeTreePortals
-
-/*
-=========================================================
-
-FLOOD ENTITIES
-
-=========================================================
-*/
-//#define P_NODESTACK
-
-node_t *p_firstnode;
-node_t *p_lastnode;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#ifdef P_NODESTACK
-void P_AddNodeToList(node_t *node)
-{
- node->next = p_firstnode;
- p_firstnode = node;
- if (!p_lastnode) p_lastnode = node;
-} //end of the function P_AddNodeToList
-#else //it's a node queue
-//add the node to the end of the node list
-void P_AddNodeToList(node_t *node)
-{
- node->next = NULL;
- if (p_lastnode) p_lastnode->next = node;
- else p_firstnode = node;
- p_lastnode = node;
-} //end of the function P_AddNodeToList
-#endif //P_NODESTACK
-//===========================================================================
-// get the first node from the front of the node list
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-node_t *P_NextNodeFromList(void)
-{
- node_t *node;
-
- node = p_firstnode;
- if (p_firstnode) p_firstnode = p_firstnode->next;
- if (!p_firstnode) p_lastnode = NULL;
- return node;
-} //end of the function P_NextNodeFromList
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void FloodPortals(node_t *firstnode)
-{
- node_t *node;
- portal_t *p;
- int s;
-
- firstnode->occupied = 1;
- P_AddNodeToList(firstnode);
-
- for (node = P_NextNodeFromList(); node; node = P_NextNodeFromList())
- {
- for (p = node->portals; p; p = p->next[s])
- {
- s = (p->nodes[1] == node);
- //if the node at the other side of the portal is occupied already
- if (p->nodes[!s]->occupied) continue;
- //if it isn't possible to flood through this portal
- if (!Portal_EntityFlood(p, s)) continue;
- //
- p->nodes[!s]->occupied = node->occupied + 1;
- //
- P_AddNodeToList(p->nodes[!s]);
- } //end for
- } //end for
-} //end of the function FloodPortals
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int numrec;
-
-void FloodPortals_r (node_t *node, int dist)
-{
- portal_t *p;
- int s;
-// int i;
-
- Log_Print("\r%6d", ++numrec);
-
- if (node->occupied) Error("FloodPortals_r: node already occupied\n");
- if (!node)
- {
- Error("FloodPortals_r: NULL node\n");
- } //end if*/
- node->occupied = dist;
-
- for (p = node->portals; p; p = p->next[s])
- {
- s = (p->nodes[1] == node);
- //if the node at the other side of the portal is occupied already
- if (p->nodes[!s]->occupied) continue;
- //if it isn't possible to flood through this portal
- if (!Portal_EntityFlood(p, s)) continue;
- //flood recursively through the current portal
- FloodPortals_r(p->nodes[!s], dist+1);
- } //end for
- Log_Print("\r%6d", --numrec);
-} //end of the function FloodPortals_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean PlaceOccupant (node_t *headnode, vec3_t origin, entity_t *occupant)
-{
- node_t *node;
- vec_t d;
- plane_t *plane;
-
- //find the leaf to start in
- node = headnode;
- while(node->planenum != PLANENUM_LEAF)
- {
- if (node->planenum < 0 || node->planenum > nummapplanes)
- {
- Error("PlaceOccupant: invalid node->planenum\n");
- } //end if
- plane = &mapplanes[node->planenum];
- d = DotProduct(origin, plane->normal) - plane->dist;
- if (d >= 0) node = node->children[0];
- else node = node->children[1];
- if (!node)
- {
- Error("PlaceOccupant: invalid child %d\n", d < 0);
- } //end if
- } //end while
- //don't start in solid
-// if (node->contents == CONTENTS_SOLID)
- //ME: replaced because in LeafNode in brushbsp.c
- // some nodes have contents solid with other contents
- if (node->contents & CONTENTS_SOLID) return false;
- //if the node is already occupied
- if (node->occupied) return false;
-
- //place the occupant in the first leaf
- node->occupant = occupant;
-
- numrec = 0;
-// Log_Print("%6d recurses", numrec);
-// FloodPortals_r(node, 1);
-// Log_Print("\n");
- FloodPortals(node);
-
- return true;
-} //end of the function PlaceOccupant
-//===========================================================================
-// Marks all nodes that can be reached by entites
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean FloodEntities (tree_t *tree)
-{
- int i;
- int x, y;
- vec3_t origin;
- char *cl;
- qboolean inside;
- node_t *headnode;
-
- headnode = tree->headnode;
- Log_Print("------ FloodEntities -------\n");
- inside = false;
- tree->outside_node.occupied = 0;
-
- //start at entity 1 not the world ( = 0)
- for (i = 1; i < num_entities; i++)
- {
- GetVectorForKey(&entities[i], "origin", origin);
- if (VectorCompare(origin, vec3_origin)) continue;
-
- cl = ValueForKey(&entities[i], "classname");
- origin[2] += 1; //so objects on floor are ok
-
-// Log_Print("flooding from entity %d: %s\n", i, cl);
- //nudge playerstart around if needed so clipping hulls allways
- //have a valid point
- if (!strcmp(cl, "info_player_start"))
- {
- for (x = -16; x <= 16; x += 16)
- {
- for (y = -16; y <= 16; y += 16)
- {
- origin[0] += x;
- origin[1] += y;
- if (PlaceOccupant(headnode, origin, &entities[i]))
- {
- inside = true;
- x = 999; //stop for this info_player_start
- break;
- } //end if
- origin[0] -= x;
- origin[1] -= y;
- } //end for
- } //end for
- } //end if
- else
- {
- if (PlaceOccupant(headnode, origin, &entities[i]))
- {
- inside = true;
- } //end if
- } //end else
- } //end for
-
- if (!inside)
- {
- Log_Print("WARNING: no entities inside\n");
- } //end if
- else if (tree->outside_node.occupied)
- {
- Log_Print("WARNING: entity reached from outside\n");
- } //end else if
-
- return (qboolean)(inside && !tree->outside_node.occupied);
-} //end of the function FloodEntities
-
-/*
-=========================================================
-
-FILL OUTSIDE
-
-=========================================================
-*/
-
-int c_outside;
-int c_inside;
-int c_solid;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void FillOutside_r (node_t *node)
-{
- if (node->planenum != PLANENUM_LEAF)
- {
- FillOutside_r (node->children[0]);
- FillOutside_r (node->children[1]);
- return;
- } //end if
- // anything not reachable by an entity
- // can be filled away (by setting solid contents)
- if (!node->occupied)
- {
- if (!(node->contents & CONTENTS_SOLID))
- {
- c_outside++;
- node->contents |= CONTENTS_SOLID;
- } //end if
- else
- {
- c_solid++;
- } //end else
- } //end if
- else
- {
- c_inside++;
- } //end else
-} //end of the function FillOutside_r
-//===========================================================================
-// Fill all nodes that can't be reached by entities
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void FillOutside (node_t *headnode)
-{
- c_outside = 0;
- c_inside = 0;
- c_solid = 0;
- Log_Print("------- FillOutside --------\n");
- FillOutside_r (headnode);
- Log_Print("%5i solid leaves\n", c_solid);
- Log_Print("%5i leaves filled\n", c_outside);
- Log_Print("%5i inside leaves\n", c_inside);
-} //end of the function FillOutside
-
-/*
-=========================================================
-
-FLOOD AREAS
-
-=========================================================
-*/
-
-int c_areas;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void FloodAreas_r (node_t *node)
-{
- portal_t *p;
- int s;
- bspbrush_t *b;
- entity_t *e;
-
- if (node->contents == CONTENTS_AREAPORTAL)
- {
- // this node is part of an area portal
- b = node->brushlist;
- e = &entities[b->original->entitynum];
-
- // if the current area has allready touched this
- // portal, we are done
- if (e->portalareas[0] == c_areas || e->portalareas[1] == c_areas)
- return;
-
- // note the current area as bounding the portal
- if (e->portalareas[1])
- {
- Log_Print("WARNING: areaportal entity %i touches > 2 areas\n", b->original->entitynum);
- return;
- }
- if (e->portalareas[0])
- e->portalareas[1] = c_areas;
- else
- e->portalareas[0] = c_areas;
-
- return;
- } //end if
-
- if (node->area)
- return; // allready got it
- node->area = c_areas;
-
- for (p=node->portals ; p ; p = p->next[s])
- {
- s = (p->nodes[1] == node);
-#if 0
- if (p->nodes[!s]->occupied)
- continue;
-#endif
- if (!Portal_EntityFlood (p, s))
- continue;
-
- FloodAreas_r (p->nodes[!s]);
- } //end for
-} //end of the function FloodAreas_r
-//===========================================================================
-// Just decend the tree, and for each node that hasn't had an
-// area set, flood fill out from there
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void FindAreas_r (node_t *node)
-{
- if (node->planenum != PLANENUM_LEAF)
- {
- FindAreas_r (node->children[0]);
- FindAreas_r (node->children[1]);
- return;
- }
-
- if (node->area)
- return; // allready got it
-
- if (node->contents & CONTENTS_SOLID)
- return;
-
- if (!node->occupied)
- return; // not reachable by entities
-
- // area portals are allways only flooded into, never
- // out of
- if (node->contents == CONTENTS_AREAPORTAL)
- return;
-
- c_areas++;
- FloodAreas_r (node);
-} //end of the function FindAreas_r
-//===========================================================================
-// Just decend the tree, and for each node that hasn't had an
-// area set, flood fill out from there
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void SetAreaPortalAreas_r (node_t *node)
-{
- bspbrush_t *b;
- entity_t *e;
-
- if (node->planenum != PLANENUM_LEAF)
- {
- SetAreaPortalAreas_r (node->children[0]);
- SetAreaPortalAreas_r (node->children[1]);
- return;
- } //end if
-
- if (node->contents == CONTENTS_AREAPORTAL)
- {
- if (node->area)
- return; // allready set
-
- b = node->brushlist;
- e = &entities[b->original->entitynum];
- node->area = e->portalareas[0];
- if (!e->portalareas[1])
- {
- Log_Print("WARNING: areaportal entity %i doesn't touch two areas\n", b->original->entitynum);
- return;
- } //end if
- } //end if
-} //end of the function SetAreaPortalAreas_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-/*
-void EmitAreaPortals(node_t *headnode)
-{
- int i, j;
- entity_t *e;
- dareaportal_t *dp;
-
- if (c_areas > MAX_MAP_AREAS)
- Error ("MAX_MAP_AREAS");
- numareas = c_areas+1;
- numareaportals = 1; // leave 0 as an error
-
- for (i=1 ; i<=c_areas ; i++)
- {
- dareas[i].firstareaportal = numareaportals;
- for (j=0 ; j<num_entities ; j++)
- {
- e = &entities[j];
- if (!e->areaportalnum)
- continue;
- dp = &dareaportals[numareaportals];
- if (e->portalareas[0] == i)
- {
- dp->portalnum = e->areaportalnum;
- dp->otherarea = e->portalareas[1];
- numareaportals++;
- } //end if
- else if (e->portalareas[1] == i)
- {
- dp->portalnum = e->areaportalnum;
- dp->otherarea = e->portalareas[0];
- numareaportals++;
- } //end else if
- } //end for
- dareas[i].numareaportals = numareaportals - dareas[i].firstareaportal;
- } //end for
-
- Log_Print("%5i numareas\n", numareas);
- Log_Print("%5i numareaportals\n", numareaportals);
-} //end of the function EmitAreaPortals
-*/
-//===========================================================================
-// Mark each leaf with an area, bounded by CONTENTS_AREAPORTAL
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void FloodAreas (tree_t *tree)
-{
- Log_Print("--- FloodAreas ---\n");
- FindAreas_r (tree->headnode);
- SetAreaPortalAreas_r (tree->headnode);
- Log_Print("%5i areas\n", c_areas);
-} //end of the function FloodAreas
-//===========================================================================
-// Finds a brush side to use for texturing the given portal
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void FindPortalSide (portal_t *p)
-{
- int viscontents;
- bspbrush_t *bb;
- mapbrush_t *brush;
- node_t *n;
- int i,j;
- int planenum;
- side_t *side, *bestside;
- float dot, bestdot;
- plane_t *p1, *p2;
-
- // decide which content change is strongest
- // solid > lava > water, etc
- viscontents = VisibleContents (p->nodes[0]->contents ^ p->nodes[1]->contents);
- if (!viscontents)
- return;
-
- planenum = p->onnode->planenum;
- bestside = NULL;
- bestdot = 0;
-
- for (j=0 ; j<2 ; j++)
- {
- n = p->nodes[j];
- p1 = &mapplanes[p->onnode->planenum];
- for (bb=n->brushlist ; bb ; bb=bb->next)
- {
- brush = bb->original;
- if ( !(brush->contents & viscontents) )
- continue;
- for (i=0 ; i<brush->numsides ; i++)
- {
- side = &brush->original_sides[i];
- if (side->flags & SFL_BEVEL)
- continue;
- if (side->texinfo == TEXINFO_NODE)
- continue; // non-visible
- if ((side->planenum&~1) == planenum)
- { // exact match
- bestside = &brush->original_sides[i];
- goto gotit;
- } //end if
- // see how close the match is
- p2 = &mapplanes[side->planenum&~1];
- dot = DotProduct (p1->normal, p2->normal);
- if (dot > bestdot)
- {
- bestdot = dot;
- bestside = side;
- } //end if
- } //end for
- } //end for
- } //end for
-
-gotit:
- if (!bestside)
- Log_Print("WARNING: side not found for portal\n");
-
- p->sidefound = true;
- p->side = bestside;
-} //end of the function FindPortalSide
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void MarkVisibleSides_r (node_t *node)
-{
- portal_t *p;
- int s;
-
- if (node->planenum != PLANENUM_LEAF)
- {
- MarkVisibleSides_r (node->children[0]);
- MarkVisibleSides_r (node->children[1]);
- return;
- } //end if
-
- // empty leaves are never boundary leaves
- if (!node->contents) return;
-
- // see if there is a visible face
- for (p=node->portals ; p ; p = p->next[!s])
- {
- s = (p->nodes[0] == node);
- if (!p->onnode)
- continue; // edge of world
- if (!p->sidefound)
- FindPortalSide (p);
- if (p->side)
- p->side->flags |= SFL_VISIBLE;
- } //end for
-} //end of the function MarkVisibleSides_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void MarkVisibleSides(tree_t *tree, int startbrush, int endbrush)
-{
- int i, j;
- mapbrush_t *mb;
- int numsides;
-
- Log_Print("--- MarkVisibleSides ---\n");
-
- // clear all the visible flags
- for (i=startbrush ; i<endbrush ; i++)
- {
- mb = &mapbrushes[i];
-
- numsides = mb->numsides;
- for (j=0 ; j<numsides ; j++)
- mb->original_sides[j].flags &= ~SFL_VISIBLE;
- }
-
- // set visible flags on the sides that are used by portals
- MarkVisibleSides_r (tree->headnode);
-} //end of the function MarkVisibleSides
-
+/*
+===========================================================================
+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 "l_mem.h"
+
+int c_active_portals;
+int c_peak_portals;
+int c_boundary;
+int c_boundary_sides;
+int c_portalmemory;
+
+//portal_t *portallist = NULL;
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+portal_t *AllocPortal (void)
+{
+ portal_t *p;
+
+ p = GetMemory(sizeof(portal_t));
+ memset (p, 0, sizeof(portal_t));
+
+ if (numthreads == 1)
+ {
+ c_active_portals++;
+ if (c_active_portals > c_peak_portals)
+ {
+ c_peak_portals = c_active_portals;
+ } //end if
+ c_portalmemory += MemorySize(p);
+ } //end if
+
+// p->nextportal = portallist;
+// portallist = p;
+
+ return p;
+} //end of the function AllocPortal
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void FreePortal (portal_t *p)
+{
+ if (p->winding) FreeWinding(p->winding);
+ if (numthreads == 1)
+ {
+ c_active_portals--;
+ c_portalmemory -= MemorySize(p);
+ } //end if
+ FreeMemory(p);
+} //end of the function FreePortal
+//===========================================================================
+// Returns the single content bit of the
+// strongest visible content present
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int VisibleContents (int contents)
+{
+ int i;
+
+ for (i=1 ; i<=LAST_VISIBLE_CONTENTS ; i<<=1)
+ if (contents & i )
+ return i;
+
+ return 0;
+} //end of the function VisibleContents
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int ClusterContents (node_t *node)
+{
+ int c1, c2, c;
+
+ if (node->planenum == PLANENUM_LEAF)
+ return node->contents;
+
+ c1 = ClusterContents(node->children[0]);
+ c2 = ClusterContents(node->children[1]);
+ c = c1|c2;
+
+ // a cluster may include some solid detail areas, but
+ // still be seen into
+ if ( ! (c1&CONTENTS_SOLID) || ! (c2&CONTENTS_SOLID) )
+ c &= ~CONTENTS_SOLID;
+ return c;
+} //end of the function ClusterContents
+
+//===========================================================================
+// Returns true if the portal is empty or translucent, allowing
+// the PVS calculation to see through it.
+// The nodes on either side of the portal may actually be clusters,
+// not leaves, so all contents should be ored together
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+qboolean Portal_VisFlood (portal_t *p)
+{
+ int c1, c2;
+
+ if (!p->onnode)
+ return false; // to global outsideleaf
+
+ c1 = ClusterContents(p->nodes[0]);
+ c2 = ClusterContents(p->nodes[1]);
+
+ if (!VisibleContents (c1^c2))
+ return true;
+
+ if (c1 & (CONTENTS_Q2TRANSLUCENT|CONTENTS_DETAIL))
+ c1 = 0;
+ if (c2 & (CONTENTS_Q2TRANSLUCENT|CONTENTS_DETAIL))
+ c2 = 0;
+
+ if ( (c1|c2) & CONTENTS_SOLID )
+ return false; // can't see through solid
+
+ if (! (c1 ^ c2))
+ return true; // identical on both sides
+
+ if (!VisibleContents (c1^c2))
+ return true;
+ return false;
+} //end of the function Portal_VisFlood
+//===========================================================================
+// The entity flood determines which areas are
+// "outside" on the map, which are then filled in.
+// Flowing from side s to side !s
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+qboolean Portal_EntityFlood (portal_t *p, int s)
+{
+ if (p->nodes[0]->planenum != PLANENUM_LEAF
+ || p->nodes[1]->planenum != PLANENUM_LEAF)
+ Error ("Portal_EntityFlood: not a leaf");
+
+ // can never cross to a solid
+ if ( (p->nodes[0]->contents & CONTENTS_SOLID)
+ || (p->nodes[1]->contents & CONTENTS_SOLID) )
+ return false;
+
+ // can flood through everything else
+ return true;
+}
+
+
+//=============================================================================
+
+int c_tinyportals;
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void AddPortalToNodes (portal_t *p, node_t *front, node_t *back)
+{
+ if (p->nodes[0] || p->nodes[1])
+ Error ("AddPortalToNode: allready included");
+
+ p->nodes[0] = front;
+ p->next[0] = front->portals;
+ front->portals = p;
+
+ p->nodes[1] = back;
+ p->next[1] = back->portals;
+ back->portals = p;
+} //end of the function AddPortalToNodes
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void RemovePortalFromNode (portal_t *portal, node_t *l)
+{
+ portal_t **pp, *t;
+
+ int s, i, n;
+ portal_t *p;
+ portal_t *portals[4096];
+
+// remove reference to the current portal
+ pp = &l->portals;
+ while (1)
+ {
+ t = *pp;
+ if (!t)
+ Error ("RemovePortalFromNode: portal not in leaf");
+
+ if ( t == portal )
+ break;
+
+ if (t->nodes[0] == l)
+ pp = &t->next[0];
+ else if (t->nodes[1] == l)
+ pp = &t->next[1];
+ else
+ Error ("RemovePortalFromNode: portal not bounding leaf");
+ }
+
+ if (portal->nodes[0] == l)
+ {
+ *pp = portal->next[0];
+ portal->nodes[0] = NULL;
+ } //end if
+ else if (portal->nodes[1] == l)
+ {
+ *pp = portal->next[1];
+ portal->nodes[1] = NULL;
+ } //end else if
+ else
+ {
+ Error("RemovePortalFromNode: mislinked portal");
+ } //end else
+//#ifdef ME
+ n = 0;
+ for (p = l->portals; p; p = p->next[s])
+ {
+ for (i = 0; i < n; i++)
+ {
+ if (p == portals[i]) Error("RemovePortalFromNode: circular linked\n");
+ } //end for
+ if (p->nodes[0] != l && p->nodes[1] != l)
+ {
+ Error("RemovePortalFromNodes: portal does not belong to node\n");
+ } //end if
+ portals[n] = p;
+ s = (p->nodes[1] == l);
+// if (++n >= 4096) Error("RemovePortalFromNode: more than 4096 portals\n");
+ } //end for
+//#endif
+} //end of the function RemovePortalFromNode
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void PrintPortal (portal_t *p)
+{
+ int i;
+ winding_t *w;
+
+ w = p->winding;
+ for (i=0 ; i<w->numpoints ; i++)
+ printf ("(%5.0f,%5.0f,%5.0f)\n",w->p[i][0]
+ , w->p[i][1], w->p[i][2]);
+} //end of the function PrintPortal
+//===========================================================================
+// The created portals will face the global outside_node
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+#define SIDESPACE 8
+
+void MakeHeadnodePortals (tree_t *tree)
+{
+ vec3_t bounds[2];
+ int i, j, n;
+ portal_t *p, *portals[6];
+ plane_t bplanes[6], *pl;
+ node_t *node;
+
+ node = tree->headnode;
+
+// pad with some space so there will never be null volume leaves
+ for (i=0 ; i<3 ; i++)
+ {
+ bounds[0][i] = tree->mins[i] - SIDESPACE;
+ bounds[1][i] = tree->maxs[i] + SIDESPACE;
+ if ( bounds[0][i] > bounds[1][i] ) {
+ Error("empty BSP tree");
+ }
+ }
+
+ tree->outside_node.planenum = PLANENUM_LEAF;
+ tree->outside_node.brushlist = NULL;
+ tree->outside_node.portals = NULL;
+ tree->outside_node.contents = 0;
+
+ for (i=0 ; i<3 ; i++)
+ for (j=0 ; j<2 ; j++)
+ {
+ n = j*3 + i;
+
+ p = AllocPortal ();
+ portals[n] = p;
+
+ pl = &bplanes[n];
+ memset (pl, 0, sizeof(*pl));
+ if (j)
+ {
+ pl->normal[i] = -1;
+ pl->dist = -bounds[j][i];
+ }
+ else
+ {
+ pl->normal[i] = 1;
+ pl->dist = bounds[j][i];
+ }
+ p->plane = *pl;
+ p->winding = BaseWindingForPlane (pl->normal, pl->dist);
+ AddPortalToNodes (p, node, &tree->outside_node);
+ }
+
+// clip the basewindings by all the other planes
+ for (i=0 ; i<6 ; i++)
+ {
+ for (j=0 ; j<6 ; j++)
+ {
+ if (j == i) continue;
+ ChopWindingInPlace (&portals[i]->winding, bplanes[j].normal, bplanes[j].dist, ON_EPSILON);
+ } //end for
+ } //end for
+} //end of the function MakeHeadNodePortals
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+#define BASE_WINDING_EPSILON 0.001
+#define SPLIT_WINDING_EPSILON 0.001
+
+winding_t *BaseWindingForNode (node_t *node)
+{
+ winding_t *w;
+ node_t *n;
+ plane_t *plane;
+ vec3_t normal;
+ vec_t dist;
+
+ w = BaseWindingForPlane (mapplanes[node->planenum].normal
+ , mapplanes[node->planenum].dist);
+
+ // clip by all the parents
+ for (n=node->parent ; n && w ; )
+ {
+ plane = &mapplanes[n->planenum];
+
+ if (n->children[0] == node)
+ { // take front
+ ChopWindingInPlace (&w, plane->normal, plane->dist, BASE_WINDING_EPSILON);
+ }
+ else
+ { // take back
+ VectorSubtract (vec3_origin, plane->normal, normal);
+ dist = -plane->dist;
+ ChopWindingInPlace (&w, normal, dist, BASE_WINDING_EPSILON);
+ }
+ node = n;
+ n = n->parent;
+ }
+
+ return w;
+} //end of the function BaseWindingForNode
+//===========================================================================
+// create the new portal by taking the full plane winding for the cutting
+// plane and clipping it by all of parents of this node
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+qboolean WindingIsTiny (winding_t *w);
+
+void MakeNodePortal (node_t *node)
+{
+ portal_t *new_portal, *p;
+ winding_t *w;
+ vec3_t normal;
+ float dist;
+ int side;
+
+ w = BaseWindingForNode (node);
+
+ // clip the portal by all the other portals in the node
+ for (p = node->portals; p && w; p = p->next[side])
+ {
+ if (p->nodes[0] == node)
+ {
+ side = 0;
+ VectorCopy (p->plane.normal, normal);
+ dist = p->plane.dist;
+ } //end if
+ else if (p->nodes[1] == node)
+ {
+ side = 1;
+ VectorSubtract (vec3_origin, p->plane.normal, normal);
+ dist = -p->plane.dist;
+ } //end else if
+ else
+ {
+ Error ("MakeNodePortal: mislinked portal");
+ } //end else
+ ChopWindingInPlace (&w, normal, dist, 0.1);
+ } //end for
+
+ if (!w)
+ {
+ return;
+ } //end if
+
+ if (WindingIsTiny (w))
+ {
+ c_tinyportals++;
+ FreeWinding(w);
+ return;
+ } //end if
+
+#ifdef DEBUG
+/* //NOTE: don't use this winding ok check
+ // all the invalid windings only have a degenerate edge
+ if (WindingError(w))
+ {
+ Log_Print("MakeNodePortal: %s\n", WindingErrorString());
+ FreeWinding(w);
+ return;
+ } //end if*/
+#endif //DEBUG
+
+
+ new_portal = AllocPortal();
+ new_portal->plane = mapplanes[node->planenum];
+
+#ifdef ME
+ new_portal->planenum = node->planenum;
+#endif //ME
+
+ new_portal->onnode = node;
+ new_portal->winding = w;
+ AddPortalToNodes (new_portal, node->children[0], node->children[1]);
+} //end of the function MakeNodePortal
+//===========================================================================
+// Move or split the portals that bound node so that the node's
+// children have portals instead of node.
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void SplitNodePortals (node_t *node)
+{
+ portal_t *p, *next_portal, *new_portal;
+ node_t *f, *b, *other_node;
+ int side;
+ plane_t *plane;
+ winding_t *frontwinding, *backwinding;
+
+ plane = &mapplanes[node->planenum];
+ f = node->children[0];
+ b = node->children[1];
+
+ for (p = node->portals ; p ; p = next_portal)
+ {
+ if (p->nodes[0] == node) side = 0;
+ else if (p->nodes[1] == node) side = 1;
+ else Error ("SplitNodePortals: mislinked portal");
+ next_portal = p->next[side];
+
+ other_node = p->nodes[!side];
+ RemovePortalFromNode (p, p->nodes[0]);
+ RemovePortalFromNode (p, p->nodes[1]);
+
+//
+// cut the portal into two portals, one on each side of the cut plane
+//
+ ClipWindingEpsilon (p->winding, plane->normal, plane->dist,
+ SPLIT_WINDING_EPSILON, &frontwinding, &backwinding);
+
+ if (frontwinding && WindingIsTiny(frontwinding))
+ {
+ FreeWinding (frontwinding);
+ frontwinding = NULL;
+ c_tinyportals++;
+ } //end if
+
+ if (backwinding && WindingIsTiny(backwinding))
+ {
+ FreeWinding (backwinding);
+ backwinding = NULL;
+ c_tinyportals++;
+ } //end if
+
+#ifdef DEBUG
+/* //NOTE: don't use this winding ok check
+ // all the invalid windings only have a degenerate edge
+ if (frontwinding && WindingError(frontwinding))
+ {
+ Log_Print("SplitNodePortals: front %s\n", WindingErrorString());
+ FreeWinding(frontwinding);
+ frontwinding = NULL;
+ } //end if
+ if (backwinding && WindingError(backwinding))
+ {
+ Log_Print("SplitNodePortals: back %s\n", WindingErrorString());
+ FreeWinding(backwinding);
+ backwinding = NULL;
+ } //end if*/
+#endif //DEBUG
+
+ if (!frontwinding && !backwinding)
+ { // tiny windings on both sides
+ continue;
+ }
+
+ if (!frontwinding)
+ {
+ FreeWinding (backwinding);
+ if (side == 0) AddPortalToNodes (p, b, other_node);
+ else AddPortalToNodes (p, other_node, b);
+ continue;
+ }
+ if (!backwinding)
+ {
+ FreeWinding (frontwinding);
+ if (side == 0) AddPortalToNodes (p, f, other_node);
+ else AddPortalToNodes (p, other_node, f);
+ continue;
+ }
+
+ // the winding is split
+ new_portal = AllocPortal();
+ *new_portal = *p;
+ new_portal->winding = backwinding;
+ FreeWinding (p->winding);
+ p->winding = frontwinding;
+
+ if (side == 0)
+ {
+ AddPortalToNodes (p, f, other_node);
+ AddPortalToNodes (new_portal, b, other_node);
+ } //end if
+ else
+ {
+ AddPortalToNodes (p, other_node, f);
+ AddPortalToNodes (new_portal, other_node, b);
+ } //end else
+ }
+
+ node->portals = NULL;
+} //end of the function SplitNodePortals
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void CalcNodeBounds (node_t *node)
+{
+ portal_t *p;
+ int s;
+ int i;
+
+ // calc mins/maxs for both leaves and nodes
+ ClearBounds (node->mins, node->maxs);
+ for (p = node->portals ; p ; p = p->next[s])
+ {
+ s = (p->nodes[1] == node);
+ for (i=0 ; i<p->winding->numpoints ; i++)
+ AddPointToBounds (p->winding->p[i], node->mins, node->maxs);
+ }
+} //end of the function CalcNodeBounds
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int c_numportalizednodes;
+
+void MakeTreePortals_r (node_t *node)
+{
+ int i;
+
+#ifdef ME
+ qprintf("\r%6d", ++c_numportalizednodes);
+ if (cancelconversion) return;
+#endif //ME
+
+ CalcNodeBounds (node);
+ if (node->mins[0] >= node->maxs[0])
+ {
+ Log_Print("WARNING: node without a volume\n");
+ }
+
+ for (i=0 ; i<3 ; i++)
+ {
+ if (node->mins[i] < -MAX_MAP_BOUNDS || node->maxs[i] > MAX_MAP_BOUNDS)
+ {
+ Log_Print("WARNING: node with unbounded volume\n");
+ break;
+ }
+ }
+ if (node->planenum == PLANENUM_LEAF)
+ return;
+
+ MakeNodePortal (node);
+ SplitNodePortals (node);
+
+ MakeTreePortals_r (node->children[0]);
+ MakeTreePortals_r (node->children[1]);
+} //end of the function MakeTreePortals_r
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void MakeTreePortals(tree_t *tree)
+{
+
+#ifdef ME
+ Log_Print("---- Node Portalization ----\n");
+ c_numportalizednodes = 0;
+ c_portalmemory = 0;
+ qprintf("%6d nodes portalized", c_numportalizednodes);
+#endif //ME
+
+ MakeHeadnodePortals(tree);
+ MakeTreePortals_r(tree->headnode);
+
+#ifdef ME
+ qprintf("\n");
+ Log_Write("%6d nodes portalized\r\n", c_numportalizednodes);
+ Log_Print("%6d tiny portals\r\n", c_tinyportals);
+ Log_Print("%6d KB of portal memory\r\n", c_portalmemory >> 10);
+ Log_Print("%6i KB of winding memory\r\n", WindingMemory() >> 10);
+#endif //ME
+} //end of the function MakeTreePortals
+
+/*
+=========================================================
+
+FLOOD ENTITIES
+
+=========================================================
+*/
+//#define P_NODESTACK
+
+node_t *p_firstnode;
+node_t *p_lastnode;
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+#ifdef P_NODESTACK
+void P_AddNodeToList(node_t *node)
+{
+ node->next = p_firstnode;
+ p_firstnode = node;
+ if (!p_lastnode) p_lastnode = node;
+} //end of the function P_AddNodeToList
+#else //it's a node queue
+//add the node to the end of the node list
+void P_AddNodeToList(node_t *node)
+{
+ node->next = NULL;
+ if (p_lastnode) p_lastnode->next = node;
+ else p_firstnode = node;
+ p_lastnode = node;
+} //end of the function P_AddNodeToList
+#endif //P_NODESTACK
+//===========================================================================
+// get the first node from the front of the node list
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+node_t *P_NextNodeFromList(void)
+{
+ node_t *node;
+
+ node = p_firstnode;
+ if (p_firstnode) p_firstnode = p_firstnode->next;
+ if (!p_firstnode) p_lastnode = NULL;
+ return node;
+} //end of the function P_NextNodeFromList
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void FloodPortals(node_t *firstnode)
+{
+ node_t *node;
+ portal_t *p;
+ int s;
+
+ firstnode->occupied = 1;
+ P_AddNodeToList(firstnode);
+
+ for (node = P_NextNodeFromList(); node; node = P_NextNodeFromList())
+ {
+ for (p = node->portals; p; p = p->next[s])
+ {
+ s = (p->nodes[1] == node);
+ //if the node at the other side of the portal is occupied already
+ if (p->nodes[!s]->occupied) continue;
+ //if it isn't possible to flood through this portal
+ if (!Portal_EntityFlood(p, s)) continue;
+ //
+ p->nodes[!s]->occupied = node->occupied + 1;
+ //
+ P_AddNodeToList(p->nodes[!s]);
+ } //end for
+ } //end for
+} //end of the function FloodPortals
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int numrec;
+
+void FloodPortals_r (node_t *node, int dist)
+{
+ portal_t *p;
+ int s;
+// int i;
+
+ Log_Print("\r%6d", ++numrec);
+
+ if (node->occupied) Error("FloodPortals_r: node already occupied\n");
+ if (!node)
+ {
+ Error("FloodPortals_r: NULL node\n");
+ } //end if*/
+ node->occupied = dist;
+
+ for (p = node->portals; p; p = p->next[s])
+ {
+ s = (p->nodes[1] == node);
+ //if the node at the other side of the portal is occupied already
+ if (p->nodes[!s]->occupied) continue;
+ //if it isn't possible to flood through this portal
+ if (!Portal_EntityFlood(p, s)) continue;
+ //flood recursively through the current portal
+ FloodPortals_r(p->nodes[!s], dist+1);
+ } //end for
+ Log_Print("\r%6d", --numrec);
+} //end of the function FloodPortals_r
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+qboolean PlaceOccupant (node_t *headnode, vec3_t origin, entity_t *occupant)
+{
+ node_t *node;
+ vec_t d;
+ plane_t *plane;
+
+ //find the leaf to start in
+ node = headnode;
+ while(node->planenum != PLANENUM_LEAF)
+ {
+ if (node->planenum < 0 || node->planenum > nummapplanes)
+ {
+ Error("PlaceOccupant: invalid node->planenum\n");
+ } //end if
+ plane = &mapplanes[node->planenum];
+ d = DotProduct(origin, plane->normal) - plane->dist;
+ if (d >= 0) node = node->children[0];
+ else node = node->children[1];
+ if (!node)
+ {
+ Error("PlaceOccupant: invalid child %d\n", d < 0);
+ } //end if
+ } //end while
+ //don't start in solid
+// if (node->contents == CONTENTS_SOLID)
+ //ME: replaced because in LeafNode in brushbsp.c
+ // some nodes have contents solid with other contents
+ if (node->contents & CONTENTS_SOLID) return false;
+ //if the node is already occupied
+ if (node->occupied) return false;
+
+ //place the occupant in the first leaf
+ node->occupant = occupant;
+
+ numrec = 0;
+// Log_Print("%6d recurses", numrec);
+// FloodPortals_r(node, 1);
+// Log_Print("\n");
+ FloodPortals(node);
+
+ return true;
+} //end of the function PlaceOccupant
+//===========================================================================
+// Marks all nodes that can be reached by entites
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+qboolean FloodEntities (tree_t *tree)
+{
+ int i;
+ int x, y;
+ vec3_t origin;
+ char *cl;
+ qboolean inside;
+ node_t *headnode;
+
+ headnode = tree->headnode;
+ Log_Print("------ FloodEntities -------\n");
+ inside = false;
+ tree->outside_node.occupied = 0;
+
+ //start at entity 1 not the world ( = 0)
+ for (i = 1; i < num_entities; i++)
+ {
+ GetVectorForKey(&entities[i], "origin", origin);
+ if (VectorCompare(origin, vec3_origin)) continue;
+
+ cl = ValueForKey(&entities[i], "classname");
+ origin[2] += 1; //so objects on floor are ok
+
+// Log_Print("flooding from entity %d: %s\n", i, cl);
+ //nudge playerstart around if needed so clipping hulls allways
+ //have a valid point
+ if (!strcmp(cl, "info_player_start"))
+ {
+ for (x = -16; x <= 16; x += 16)
+ {
+ for (y = -16; y <= 16; y += 16)
+ {
+ origin[0] += x;
+ origin[1] += y;
+ if (PlaceOccupant(headnode, origin, &entities[i]))
+ {
+ inside = true;
+ x = 999; //stop for this info_player_start
+ break;
+ } //end if
+ origin[0] -= x;
+ origin[1] -= y;
+ } //end for
+ } //end for
+ } //end if
+ else
+ {
+ if (PlaceOccupant(headnode, origin, &entities[i]))
+ {
+ inside = true;
+ } //end if
+ } //end else
+ } //end for
+
+ if (!inside)
+ {
+ Log_Print("WARNING: no entities inside\n");
+ } //end if
+ else if (tree->outside_node.occupied)
+ {
+ Log_Print("WARNING: entity reached from outside\n");
+ } //end else if
+
+ return (qboolean)(inside && !tree->outside_node.occupied);
+} //end of the function FloodEntities
+
+/*
+=========================================================
+
+FILL OUTSIDE
+
+=========================================================
+*/
+
+int c_outside;
+int c_inside;
+int c_solid;
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void FillOutside_r (node_t *node)
+{
+ if (node->planenum != PLANENUM_LEAF)
+ {
+ FillOutside_r (node->children[0]);
+ FillOutside_r (node->children[1]);
+ return;
+ } //end if
+ // anything not reachable by an entity
+ // can be filled away (by setting solid contents)
+ if (!node->occupied)
+ {
+ if (!(node->contents & CONTENTS_SOLID))
+ {
+ c_outside++;
+ node->contents |= CONTENTS_SOLID;
+ } //end if
+ else
+ {
+ c_solid++;
+ } //end else
+ } //end if
+ else
+ {
+ c_inside++;
+ } //end else
+} //end of the function FillOutside_r
+//===========================================================================
+// Fill all nodes that can't be reached by entities
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void FillOutside (node_t *headnode)
+{
+ c_outside = 0;
+ c_inside = 0;
+ c_solid = 0;
+ Log_Print("------- FillOutside --------\n");
+ FillOutside_r (headnode);
+ Log_Print("%5i solid leaves\n", c_solid);
+ Log_Print("%5i leaves filled\n", c_outside);
+ Log_Print("%5i inside leaves\n", c_inside);
+} //end of the function FillOutside
+
+/*
+=========================================================
+
+FLOOD AREAS
+
+=========================================================
+*/
+
+int c_areas;
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void FloodAreas_r (node_t *node)
+{
+ portal_t *p;
+ int s;
+ bspbrush_t *b;
+ entity_t *e;
+
+ if (node->contents == CONTENTS_AREAPORTAL)
+ {
+ // this node is part of an area portal
+ b = node->brushlist;
+ e = &entities[b->original->entitynum];
+
+ // if the current area has allready touched this
+ // portal, we are done
+ if (e->portalareas[0] == c_areas || e->portalareas[1] == c_areas)
+ return;
+
+ // note the current area as bounding the portal
+ if (e->portalareas[1])
+ {
+ Log_Print("WARNING: areaportal entity %i touches > 2 areas\n", b->original->entitynum);
+ return;
+ }
+ if (e->portalareas[0])
+ e->portalareas[1] = c_areas;
+ else
+ e->portalareas[0] = c_areas;
+
+ return;
+ } //end if
+
+ if (node->area)
+ return; // allready got it
+ node->area = c_areas;
+
+ for (p=node->portals ; p ; p = p->next[s])
+ {
+ s = (p->nodes[1] == node);
+#if 0
+ if (p->nodes[!s]->occupied)
+ continue;
+#endif
+ if (!Portal_EntityFlood (p, s))
+ continue;
+
+ FloodAreas_r (p->nodes[!s]);
+ } //end for
+} //end of the function FloodAreas_r
+//===========================================================================
+// Just decend the tree, and for each node that hasn't had an
+// area set, flood fill out from there
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void FindAreas_r (node_t *node)
+{
+ if (node->planenum != PLANENUM_LEAF)
+ {
+ FindAreas_r (node->children[0]);
+ FindAreas_r (node->children[1]);
+ return;
+ }
+
+ if (node->area)
+ return; // allready got it
+
+ if (node->contents & CONTENTS_SOLID)
+ return;
+
+ if (!node->occupied)
+ return; // not reachable by entities
+
+ // area portals are allways only flooded into, never
+ // out of
+ if (node->contents == CONTENTS_AREAPORTAL)
+ return;
+
+ c_areas++;
+ FloodAreas_r (node);
+} //end of the function FindAreas_r
+//===========================================================================
+// Just decend the tree, and for each node that hasn't had an
+// area set, flood fill out from there
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void SetAreaPortalAreas_r (node_t *node)
+{
+ bspbrush_t *b;
+ entity_t *e;
+
+ if (node->planenum != PLANENUM_LEAF)
+ {
+ SetAreaPortalAreas_r (node->children[0]);
+ SetAreaPortalAreas_r (node->children[1]);
+ return;
+ } //end if
+
+ if (node->contents == CONTENTS_AREAPORTAL)
+ {
+ if (node->area)
+ return; // allready set
+
+ b = node->brushlist;
+ e = &entities[b->original->entitynum];
+ node->area = e->portalareas[0];
+ if (!e->portalareas[1])
+ {
+ Log_Print("WARNING: areaportal entity %i doesn't touch two areas\n", b->original->entitynum);
+ return;
+ } //end if
+ } //end if
+} //end of the function SetAreaPortalAreas_r
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+/*
+void EmitAreaPortals(node_t *headnode)
+{
+ int i, j;
+ entity_t *e;
+ dareaportal_t *dp;
+
+ if (c_areas > MAX_MAP_AREAS)
+ Error ("MAX_MAP_AREAS");
+ numareas = c_areas+1;
+ numareaportals = 1; // leave 0 as an error
+
+ for (i=1 ; i<=c_areas ; i++)
+ {
+ dareas[i].firstareaportal = numareaportals;
+ for (j=0 ; j<num_entities ; j++)
+ {
+ e = &entities[j];
+ if (!e->areaportalnum)
+ continue;
+ dp = &dareaportals[numareaportals];
+ if (e->portalareas[0] == i)
+ {
+ dp->portalnum = e->areaportalnum;
+ dp->otherarea = e->portalareas[1];
+ numareaportals++;
+ } //end if
+ else if (e->portalareas[1] == i)
+ {
+ dp->portalnum = e->areaportalnum;
+ dp->otherarea = e->portalareas[0];
+ numareaportals++;
+ } //end else if
+ } //end for
+ dareas[i].numareaportals = numareaportals - dareas[i].firstareaportal;
+ } //end for
+
+ Log_Print("%5i numareas\n", numareas);
+ Log_Print("%5i numareaportals\n", numareaportals);
+} //end of the function EmitAreaPortals
+*/
+//===========================================================================
+// Mark each leaf with an area, bounded by CONTENTS_AREAPORTAL
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void FloodAreas (tree_t *tree)
+{
+ Log_Print("--- FloodAreas ---\n");
+ FindAreas_r (tree->headnode);
+ SetAreaPortalAreas_r (tree->headnode);
+ Log_Print("%5i areas\n", c_areas);
+} //end of the function FloodAreas
+//===========================================================================
+// Finds a brush side to use for texturing the given portal
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void FindPortalSide (portal_t *p)
+{
+ int viscontents;
+ bspbrush_t *bb;
+ mapbrush_t *brush;
+ node_t *n;
+ int i,j;
+ int planenum;
+ side_t *side, *bestside;
+ float dot, bestdot;
+ plane_t *p1, *p2;
+
+ // decide which content change is strongest
+ // solid > lava > water, etc
+ viscontents = VisibleContents (p->nodes[0]->contents ^ p->nodes[1]->contents);
+ if (!viscontents)
+ return;
+
+ planenum = p->onnode->planenum;
+ bestside = NULL;
+ bestdot = 0;
+
+ for (j=0 ; j<2 ; j++)
+ {
+ n = p->nodes[j];
+ p1 = &mapplanes[p->onnode->planenum];
+ for (bb=n->brushlist ; bb ; bb=bb->next)
+ {
+ brush = bb->original;
+ if ( !(brush->contents & viscontents) )
+ continue;
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ side = &brush->original_sides[i];
+ if (side->flags & SFL_BEVEL)
+ continue;
+ if (side->texinfo == TEXINFO_NODE)
+ continue; // non-visible
+ if ((side->planenum&~1) == planenum)
+ { // exact match
+ bestside = &brush->original_sides[i];
+ goto gotit;
+ } //end if
+ // see how close the match is
+ p2 = &mapplanes[side->planenum&~1];
+ dot = DotProduct (p1->normal, p2->normal);
+ if (dot > bestdot)
+ {
+ bestdot = dot;
+ bestside = side;
+ } //end if
+ } //end for
+ } //end for
+ } //end for
+
+gotit:
+ if (!bestside)
+ Log_Print("WARNING: side not found for portal\n");
+
+ p->sidefound = true;
+ p->side = bestside;
+} //end of the function FindPortalSide
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void MarkVisibleSides_r (node_t *node)
+{
+ portal_t *p;
+ int s;
+
+ if (node->planenum != PLANENUM_LEAF)
+ {
+ MarkVisibleSides_r (node->children[0]);
+ MarkVisibleSides_r (node->children[1]);
+ return;
+ } //end if
+
+ // empty leaves are never boundary leaves
+ if (!node->contents) return;
+
+ // see if there is a visible face
+ for (p=node->portals ; p ; p = p->next[!s])
+ {
+ s = (p->nodes[0] == node);
+ if (!p->onnode)
+ continue; // edge of world
+ if (!p->sidefound)
+ FindPortalSide (p);
+ if (p->side)
+ p->side->flags |= SFL_VISIBLE;
+ } //end for
+} //end of the function MarkVisibleSides_r
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void MarkVisibleSides(tree_t *tree, int startbrush, int endbrush)
+{
+ int i, j;
+ mapbrush_t *mb;
+ int numsides;
+
+ Log_Print("--- MarkVisibleSides ---\n");
+
+ // clear all the visible flags
+ for (i=startbrush ; i<endbrush ; i++)
+ {
+ mb = &mapbrushes[i];
+
+ numsides = mb->numsides;
+ for (j=0 ; j<numsides ; j++)
+ mb->original_sides[j].flags &= ~SFL_VISIBLE;
+ }
+
+ // set visible flags on the sides that are used by portals
+ MarkVisibleSides_r (tree->headnode);
+} //end of the function MarkVisibleSides
+
diff --git a/code/bspc/prtfile.c b/code/bspc/prtfile.c
index 69834aa..58d1206 100755
--- a/code/bspc/prtfile.c
+++ b/code/bspc/prtfile.c
@@ -1,287 +1,287 @@
-/*
-===========================================================================
-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"
-
-/*
-==============================================================================
-
-PORTAL FILE GENERATION
-
-Save out name.prt for qvis to read
-==============================================================================
-*/
-
-
-#define PORTALFILE "PRT1"
-
-FILE *pf;
-int num_visclusters; // clusters the player can be in
-int num_visportals;
-
-void WriteFloat2 (FILE *f, vec_t v)
-{
- if ( fabs(v - Q_rint(v)) < 0.001 )
- fprintf (f,"%i ",(int)Q_rint(v));
- else
- fprintf (f,"%f ",v);
-}
-
-/*
-=================
-WritePortalFile_r
-=================
-*/
-void WritePortalFile_r (node_t *node)
-{
- int i, s;
- portal_t *p;
- winding_t *w;
- vec3_t normal;
- vec_t dist;
-
- // decision node
- if (node->planenum != PLANENUM_LEAF && !node->detail_seperator)
- {
- WritePortalFile_r (node->children[0]);
- WritePortalFile_r (node->children[1]);
- return;
- }
-
- if (node->contents & CONTENTS_SOLID)
- return;
-
- for (p = node->portals ; p ; p=p->next[s])
- {
- w = p->winding;
- s = (p->nodes[1] == node);
- if (w && p->nodes[0] == node)
- {
- if (!Portal_VisFlood (p))
- continue;
- // write out to the file
-
- // sometimes planes get turned around when they are very near
- // the changeover point between different axis. interpret the
- // plane the same way vis will, and flip the side orders if needed
- // FIXME: is this still relevent?
- WindingPlane (w, normal, &dist);
- if ( DotProduct (p->plane.normal, normal) < 0.99 )
- { // backwards...
- fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[1]->cluster, p->nodes[0]->cluster);
- }
- else
- fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[0]->cluster, p->nodes[1]->cluster);
- for (i=0 ; i<w->numpoints ; i++)
- {
- fprintf (pf,"(");
- WriteFloat2 (pf, w->p[i][0]);
- WriteFloat2 (pf, w->p[i][1]);
- WriteFloat2 (pf, w->p[i][2]);
- fprintf (pf,") ");
- }
- fprintf (pf,"\n");
- }
- }
-
-}
-
-/*
-================
-FillLeafNumbers_r
-
-All of the leafs under node will have the same cluster
-================
-*/
-void FillLeafNumbers_r (node_t *node, int num)
-{
- if (node->planenum == PLANENUM_LEAF)
- {
- if (node->contents & CONTENTS_SOLID)
- node->cluster = -1;
- else
- node->cluster = num;
- return;
- }
- node->cluster = num;
- FillLeafNumbers_r (node->children[0], num);
- FillLeafNumbers_r (node->children[1], num);
-}
-
-/*
-================
-NumberLeafs_r
-================
-*/
-void NumberLeafs_r (node_t *node)
-{
- portal_t *p;
-
- if (node->planenum != PLANENUM_LEAF && !node->detail_seperator)
- { // decision node
- node->cluster = -99;
- NumberLeafs_r (node->children[0]);
- NumberLeafs_r (node->children[1]);
- return;
- }
-
- // either a leaf or a detail cluster
-
- if ( node->contents & CONTENTS_SOLID )
- { // solid block, viewpoint never inside
- node->cluster = -1;
- return;
- }
-
- FillLeafNumbers_r (node, num_visclusters);
- num_visclusters++;
-
- // count the portals
- for (p = node->portals ; p ; )
- {
- if (p->nodes[0] == node) // only write out from first leaf
- {
- if (Portal_VisFlood (p))
- num_visportals++;
- p = p->next[0];
- }
- else
- p = p->next[1];
- }
-
-}
-
-
-/*
-================
-CreateVisPortals_r
-================
-*/
-void CreateVisPortals_r (node_t *node)
-{
- // stop as soon as we get to a detail_seperator, which
- // means that everything below is in a single cluster
- if (node->planenum == PLANENUM_LEAF || node->detail_seperator )
- return;
-
- MakeNodePortal (node);
- SplitNodePortals (node);
-
- CreateVisPortals_r (node->children[0]);
- CreateVisPortals_r (node->children[1]);
-}
-
-/*
-================
-FinishVisPortals_r
-================
-*/
-void FinishVisPortals2_r (node_t *node)
-{
- if (node->planenum == PLANENUM_LEAF)
- return;
-
- MakeNodePortal (node);
- SplitNodePortals (node);
-
- FinishVisPortals2_r (node->children[0]);
- FinishVisPortals2_r (node->children[1]);
-}
-
-void FinishVisPortals_r (node_t *node)
-{
- if (node->planenum == PLANENUM_LEAF)
- return;
-
- if (node->detail_seperator)
- {
- FinishVisPortals2_r (node);
- return;
- }
-
- FinishVisPortals_r (node->children[0]);
- FinishVisPortals_r (node->children[1]);
-}
-
-
-int clusterleaf;
-void SaveClusters_r (node_t *node)
-{
- if (node->planenum == PLANENUM_LEAF)
- {
- dleafs[clusterleaf++].cluster = node->cluster;
- return;
- }
- SaveClusters_r (node->children[0]);
- SaveClusters_r (node->children[1]);
-}
-
-/*
-================
-WritePortalFile
-================
-*/
-void WritePortalFile (tree_t *tree)
-{
- char filename[1024];
- node_t *headnode;
-
- qprintf ("--- WritePortalFile ---\n");
-
- headnode = tree->headnode;
- num_visclusters = 0;
- num_visportals = 0;
-
- Tree_FreePortals_r (headnode);
-
- MakeHeadnodePortals (tree);
-
- CreateVisPortals_r (headnode);
-
-// set the cluster field in every leaf and count the total number of portals
-
- NumberLeafs_r (headnode);
-
-// write the file
- sprintf (filename, "%s.prt", source);
- printf ("writing %s\n", filename);
- pf = fopen (filename, "w");
- if (!pf)
- Error ("Error opening %s", filename);
-
- fprintf (pf, "%s\n", PORTALFILE);
- fprintf (pf, "%i\n", num_visclusters);
- fprintf (pf, "%i\n", num_visportals);
-
- qprintf ("%5i visclusters\n", num_visclusters);
- qprintf ("%5i visportals\n", num_visportals);
-
- WritePortalFile_r (headnode);
-
- fclose (pf);
-
- // we need to store the clusters out now because ordering
- // issues made us do this after writebsp...
- clusterleaf = 1;
- SaveClusters_r (headnode);
-}
-
+/*
+===========================================================================
+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"
+
+/*
+==============================================================================
+
+PORTAL FILE GENERATION
+
+Save out name.prt for qvis to read
+==============================================================================
+*/
+
+
+#define PORTALFILE "PRT1"
+
+FILE *pf;
+int num_visclusters; // clusters the player can be in
+int num_visportals;
+
+void WriteFloat2 (FILE *f, vec_t v)
+{
+ if ( fabs(v - Q_rint(v)) < 0.001 )
+ fprintf (f,"%i ",(int)Q_rint(v));
+ else
+ fprintf (f,"%f ",v);
+}
+
+/*
+=================
+WritePortalFile_r
+=================
+*/
+void WritePortalFile_r (node_t *node)
+{
+ int i, s;
+ portal_t *p;
+ winding_t *w;
+ vec3_t normal;
+ vec_t dist;
+
+ // decision node
+ if (node->planenum != PLANENUM_LEAF && !node->detail_seperator)
+ {
+ WritePortalFile_r (node->children[0]);
+ WritePortalFile_r (node->children[1]);
+ return;
+ }
+
+ if (node->contents & CONTENTS_SOLID)
+ return;
+
+ for (p = node->portals ; p ; p=p->next[s])
+ {
+ w = p->winding;
+ s = (p->nodes[1] == node);
+ if (w && p->nodes[0] == node)
+ {
+ if (!Portal_VisFlood (p))
+ continue;
+ // write out to the file
+
+ // sometimes planes get turned around when they are very near
+ // the changeover point between different axis. interpret the
+ // plane the same way vis will, and flip the side orders if needed
+ // FIXME: is this still relevent?
+ WindingPlane (w, normal, &dist);
+ if ( DotProduct (p->plane.normal, normal) < 0.99 )
+ { // backwards...
+ fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[1]->cluster, p->nodes[0]->cluster);
+ }
+ else
+ fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[0]->cluster, p->nodes[1]->cluster);
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ fprintf (pf,"(");
+ WriteFloat2 (pf, w->p[i][0]);
+ WriteFloat2 (pf, w->p[i][1]);
+ WriteFloat2 (pf, w->p[i][2]);
+ fprintf (pf,") ");
+ }
+ fprintf (pf,"\n");
+ }
+ }
+
+}
+
+/*
+================
+FillLeafNumbers_r
+
+All of the leafs under node will have the same cluster
+================
+*/
+void FillLeafNumbers_r (node_t *node, int num)
+{
+ if (node->planenum == PLANENUM_LEAF)
+ {
+ if (node->contents & CONTENTS_SOLID)
+ node->cluster = -1;
+ else
+ node->cluster = num;
+ return;
+ }
+ node->cluster = num;
+ FillLeafNumbers_r (node->children[0], num);
+ FillLeafNumbers_r (node->children[1], num);
+}
+
+/*
+================
+NumberLeafs_r
+================
+*/
+void NumberLeafs_r (node_t *node)
+{
+ portal_t *p;
+
+ if (node->planenum != PLANENUM_LEAF && !node->detail_seperator)
+ { // decision node
+ node->cluster = -99;
+ NumberLeafs_r (node->children[0]);
+ NumberLeafs_r (node->children[1]);
+ return;
+ }
+
+ // either a leaf or a detail cluster
+
+ if ( node->contents & CONTENTS_SOLID )
+ { // solid block, viewpoint never inside
+ node->cluster = -1;
+ return;
+ }
+
+ FillLeafNumbers_r (node, num_visclusters);
+ num_visclusters++;
+
+ // count the portals
+ for (p = node->portals ; p ; )
+ {
+ if (p->nodes[0] == node) // only write out from first leaf
+ {
+ if (Portal_VisFlood (p))
+ num_visportals++;
+ p = p->next[0];
+ }
+ else
+ p = p->next[1];
+ }
+
+}
+
+
+/*
+================
+CreateVisPortals_r
+================
+*/
+void CreateVisPortals_r (node_t *node)
+{
+ // stop as soon as we get to a detail_seperator, which
+ // means that everything below is in a single cluster
+ if (node->planenum == PLANENUM_LEAF || node->detail_seperator )
+ return;
+
+ MakeNodePortal (node);
+ SplitNodePortals (node);
+
+ CreateVisPortals_r (node->children[0]);
+ CreateVisPortals_r (node->children[1]);
+}
+
+/*
+================
+FinishVisPortals_r
+================
+*/
+void FinishVisPortals2_r (node_t *node)
+{
+ if (node->planenum == PLANENUM_LEAF)
+ return;
+
+ MakeNodePortal (node);
+ SplitNodePortals (node);
+
+ FinishVisPortals2_r (node->children[0]);
+ FinishVisPortals2_r (node->children[1]);
+}
+
+void FinishVisPortals_r (node_t *node)
+{
+ if (node->planenum == PLANENUM_LEAF)
+ return;
+
+ if (node->detail_seperator)
+ {
+ FinishVisPortals2_r (node);
+ return;
+ }
+
+ FinishVisPortals_r (node->children[0]);
+ FinishVisPortals_r (node->children[1]);
+}
+
+
+int clusterleaf;
+void SaveClusters_r (node_t *node)
+{
+ if (node->planenum == PLANENUM_LEAF)
+ {
+ dleafs[clusterleaf++].cluster = node->cluster;
+ return;
+ }
+ SaveClusters_r (node->children[0]);
+ SaveClusters_r (node->children[1]);
+}
+
+/*
+================
+WritePortalFile
+================
+*/
+void WritePortalFile (tree_t *tree)
+{
+ char filename[1024];
+ node_t *headnode;
+
+ qprintf ("--- WritePortalFile ---\n");
+
+ headnode = tree->headnode;
+ num_visclusters = 0;
+ num_visportals = 0;
+
+ Tree_FreePortals_r (headnode);
+
+ MakeHeadnodePortals (tree);
+
+ CreateVisPortals_r (headnode);
+
+// set the cluster field in every leaf and count the total number of portals
+
+ NumberLeafs_r (headnode);
+
+// write the file
+ sprintf (filename, "%s.prt", source);
+ printf ("writing %s\n", filename);
+ pf = fopen (filename, "w");
+ if (!pf)
+ Error ("Error opening %s", filename);
+
+ fprintf (pf, "%s\n", PORTALFILE);
+ fprintf (pf, "%i\n", num_visclusters);
+ fprintf (pf, "%i\n", num_visportals);
+
+ qprintf ("%5i visclusters\n", num_visclusters);
+ qprintf ("%5i visportals\n", num_visportals);
+
+ WritePortalFile_r (headnode);
+
+ fclose (pf);
+
+ // we need to store the clusters out now because ordering
+ // issues made us do this after writebsp...
+ clusterleaf = 1;
+ SaveClusters_r (headnode);
+}
+
diff --git a/code/bspc/q2files.h b/code/bspc/q2files.h
index 5ffea6e..317e47c 100755
--- a/code/bspc/q2files.h
+++ b/code/bspc/q2files.h
@@ -1,487 +1,487 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-
-//
-// qfiles.h: quake file formats
-// This file must be identical in the quake and utils directories
-//
-
-/*
-========================================================================
-
-The .pak files are just a linear collapse of a directory tree
-
-========================================================================
-*/
-
-#define IDPAKHEADER (('K'<<24)+('C'<<16)+('A'<<8)+'P')
-
-typedef struct
-{
- char name[56];
- int filepos, filelen;
-} dpackfile_t;
-
-typedef struct
-{
- int ident; // == IDPAKHEADER
- int dirofs;
- int dirlen;
-} dpackheader_t;
-
-#define MAX_FILES_IN_PACK 4096
-
-
-/*
-========================================================================
-
-PCX files are used for as many images as possible
-
-========================================================================
-*/
-
-typedef struct
-{
- char manufacturer;
- char version;
- char encoding;
- char bits_per_pixel;
- unsigned short xmin,ymin,xmax,ymax;
- unsigned short hres,vres;
- unsigned char palette[48];
- char reserved;
- char color_planes;
- unsigned short bytes_per_line;
- unsigned short palette_type;
- char filler[58];
- unsigned char data; // unbounded
-} pcx_t;
-
-
-/*
-========================================================================
-
-.MD2 triangle model file format
-
-========================================================================
-*/
-
-#define IDALIASHEADER (('2'<<24)+('P'<<16)+('D'<<8)+'I')
-#define ALIAS_VERSION 8
-
-#define MAX_TRIANGLES 4096
-#define MAX_VERTS 2048
-#define MAX_FRAMES 512
-#define MAX_MD2SKINS 32
-#define MAX_SKINNAME 64
-
-typedef struct
-{
- short s;
- short t;
-} dstvert_t;
-
-typedef struct
-{
- short index_xyz[3];
- short index_st[3];
-} dtriangle_t;
-
-typedef struct
-{
- byte v[3]; // scaled byte to fit in frame mins/maxs
- byte lightnormalindex;
-} dtrivertx_t;
-
-#define DTRIVERTX_V0 0
-#define DTRIVERTX_V1 1
-#define DTRIVERTX_V2 2
-#define DTRIVERTX_LNI 3
-#define DTRIVERTX_SIZE 4
-
-typedef struct
-{
- float scale[3]; // multiply byte verts by this
- float translate[3]; // then add this
- char name[16]; // frame name from grabbing
- dtrivertx_t verts[1]; // variable sized
-} daliasframe_t;
-
-
-// the glcmd format:
-// a positive integer starts a tristrip command, followed by that many
-// vertex structures.
-// a negative integer starts a trifan command, followed by -x vertexes
-// a zero indicates the end of the command list.
-// a vertex consists of a floating point s, a floating point t,
-// and an integer vertex index.
-
-
-typedef struct
-{
- int ident;
- int version;
-
- int skinwidth;
- int skinheight;
- int framesize; // byte size of each frame
-
- int num_skins;
- int num_xyz;
- int num_st; // greater than num_xyz for seams
- int num_tris;
- int num_glcmds; // dwords in strip/fan command list
- int num_frames;
-
- int ofs_skins; // each skin is a MAX_SKINNAME string
- int ofs_st; // byte offset from start for stverts
- int ofs_tris; // offset for dtriangles
- int ofs_frames; // offset for first frame
- int ofs_glcmds;
- int ofs_end; // end of file
-
-} dmdl_t;
-
-/*
-========================================================================
-
-.SP2 sprite file format
-
-========================================================================
-*/
-
-#define IDSPRITEHEADER (('2'<<24)+('S'<<16)+('D'<<8)+'I')
- // little-endian "IDS2"
-#define SPRITE_VERSION 2
-
-typedef struct
-{
- int width, height;
- int origin_x, origin_y; // raster coordinates inside pic
- char name[MAX_SKINNAME]; // name of pcx file
-} dsprframe_t;
-
-typedef struct {
- int ident;
- int version;
- int numframes;
- dsprframe_t frames[1]; // variable sized
-} dsprite_t;
-
-/*
-==============================================================================
-
- .WAL texture file format
-
-==============================================================================
-*/
-
-
-#define MIPLEVELS 4
-typedef struct miptex_s
-{
- char name[32];
- unsigned width, height;
- unsigned offsets[MIPLEVELS]; // four mip maps stored
- char animname[32]; // next frame in animation chain
- int flags;
- int contents;
- int value;
-} miptex_t;
-
-
-
-/*
-==============================================================================
-
- .BSP file format
-
-==============================================================================
-*/
-
-#define IDBSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I')
- // little-endian "IBSP"
-
-#define BSPVERSION 38
-
-
-// upper design bounds
-// leaffaces, leafbrushes, planes, and verts are still bounded by
-// 16 bit short limits
-#define MAX_MAP_MODELS 1024
-#define MAX_MAP_BRUSHES 8192
-#define MAX_MAP_ENTITIES 2048
-#define MAX_MAP_ENTSTRING 0x40000
-#define MAX_MAP_TEXINFO 8192
-
-#define MAX_MAP_AREAS 256
-#define MAX_MAP_AREAPORTALS 1024
-#define MAX_MAP_PLANES 65536
-#define MAX_MAP_NODES 65536
-#define MAX_MAP_BRUSHSIDES 65536
-#define MAX_MAP_LEAFS 65536
-#define MAX_MAP_VERTS 65536
-#define MAX_MAP_FACES 65536
-#define MAX_MAP_LEAFFACES 65536
-#define MAX_MAP_LEAFBRUSHES 65536
-#define MAX_MAP_PORTALS 65536
-#define MAX_MAP_EDGES 128000
-#define MAX_MAP_SURFEDGES 256000
-#define MAX_MAP_LIGHTING 0x320000
-#define MAX_MAP_VISIBILITY 0x280000
-
-// key / value pair sizes
-
-#define MAX_KEY 32
-#define MAX_VALUE 1024
-
-//=============================================================================
-
-typedef struct
-{
- int fileofs, filelen;
-} lump_t;
-
-#define LUMP_ENTITIES 0
-#define LUMP_PLANES 1
-#define LUMP_VERTEXES 2
-#define LUMP_VISIBILITY 3
-#define LUMP_NODES 4
-#define LUMP_TEXINFO 5
-#define LUMP_FACES 6
-#define LUMP_LIGHTING 7
-#define LUMP_LEAFS 8
-#define LUMP_LEAFFACES 9
-#define LUMP_LEAFBRUSHES 10
-#define LUMP_EDGES 11
-#define LUMP_SURFEDGES 12
-#define LUMP_MODELS 13
-#define LUMP_BRUSHES 14
-#define LUMP_BRUSHSIDES 15
-#define LUMP_POP 16
-#define LUMP_AREAS 17
-#define LUMP_AREAPORTALS 18
-#define HEADER_LUMPS 19
-
-typedef struct
-{
- int ident;
- int version;
- lump_t lumps[HEADER_LUMPS];
-} dheader_t;
-
-typedef struct
-{
- float mins[3], maxs[3];
- float origin[3]; // for sounds or lights
- int headnode;
- int firstface, numfaces; // submodels just draw faces
- // without walking the bsp tree
-} dmodel_t;
-
-
-typedef struct
-{
- float point[3];
-} dvertex_t;
-
-
-// 0-2 are axial planes
-#define PLANE_X 0
-#define PLANE_Y 1
-#define PLANE_Z 2
-
-// 3-5 are non-axial planes snapped to the nearest
-#define PLANE_ANYX 3
-#define PLANE_ANYY 4
-#define PLANE_ANYZ 5
-
-// planes (x&~1) and (x&~1)+1 are allways opposites
-
-typedef struct
-{
- float normal[3];
- float dist;
- int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
-} dplane_t;
-
-
-// contents flags are seperate bits
-// a given brush can contribute multiple content bits
-// multiple brushes can be in a single leaf
-
-// these definitions also need to be in q_shared.h!
-
-// lower bits are stronger, and will eat weaker brushes completely
-#define CONTENTS_SOLID 1 // an eye is never valid in a solid
-#define CONTENTS_WINDOW 2 // translucent, but not watery
-#define CONTENTS_AUX 4
-#define CONTENTS_LAVA 8
-#define CONTENTS_SLIME 16
-#define CONTENTS_WATER 32
-#define CONTENTS_MIST 64
-#define LAST_VISIBLE_CONTENTS 64
-
-// remaining contents are non-visible, and don't eat brushes
-
-#define CONTENTS_AREAPORTAL 0x8000
-
-#define CONTENTS_PLAYERCLIP 0x10000
-#define CONTENTS_MONSTERCLIP 0x20000
-
-// currents can be added to any other contents, and may be mixed
-#define CONTENTS_CURRENT_0 0x40000
-#define CONTENTS_CURRENT_90 0x80000
-#define CONTENTS_CURRENT_180 0x100000
-#define CONTENTS_CURRENT_270 0x200000
-#define CONTENTS_CURRENT_UP 0x400000
-#define CONTENTS_CURRENT_DOWN 0x800000
-
-#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity
-
-#define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game
-#define CONTENTS_DEADMONSTER 0x4000000
-#define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs
-//renamed because it's in conflict with the Q3A translucent contents
-#define CONTENTS_Q2TRANSLUCENT 0x10000000 // auto set if any surface has trans
-#define CONTENTS_LADDER 0x20000000
-
-
-
-#define SURF_LIGHT 0x1 // value will hold the light strength
-
-#define SURF_SLICK 0x2 // effects game physics
-
-#define SURF_SKY 0x4 // don't draw, but add to skybox
-#define SURF_WARP 0x8 // turbulent water warp
-#define SURF_TRANS33 0x10
-#define SURF_TRANS66 0x20
-#define SURF_FLOWING 0x40 // scroll towards angle
-#define SURF_NODRAW 0x80 // don't bother referencing the texture
-
-#define SURF_HINT 0x100 // make a primary bsp splitter
-#define SURF_SKIP 0x200 // completely ignore, allowing non-closed brushes
-
-
-
-typedef struct
-{
- int planenum;
- int children[2]; // negative numbers are -(leafs+1), not nodes
- short mins[3]; // for frustom culling
- short maxs[3];
- unsigned short firstface;
- unsigned short numfaces; // counting both sides
-} dnode_t;
-
-
-typedef struct texinfo_s
-{
- float vecs[2][4]; // [s/t][xyz offset]
- int flags; // miptex flags + overrides
- int value; // light emission, etc
- char texture[32]; // texture name (textures/*.wal)
- int nexttexinfo; // for animations, -1 = end of chain
-} texinfo_t;
-
-
-// note that edge 0 is never used, because negative edge nums are used for
-// counterclockwise use of the edge in a face
-typedef struct
-{
- unsigned short v[2]; // vertex numbers
-} dedge_t;
-
-#define MAXLIGHTMAPS 4
-typedef struct
-{
- unsigned short planenum;
- short side;
-
- int firstedge; // we must support > 64k edges
- short numedges;
- short texinfo;
-
-// lighting info
- byte styles[MAXLIGHTMAPS];
- int lightofs; // start of [numstyles*surfsize] samples
-} dface_t;
-
-typedef struct
-{
- int contents; // OR of all brushes (not needed?)
-
- short cluster;
- short area;
-
- short mins[3]; // for frustum culling
- short maxs[3];
-
- unsigned short firstleafface;
- unsigned short numleaffaces;
-
- unsigned short firstleafbrush;
- unsigned short numleafbrushes;
-} dleaf_t;
-
-typedef struct
-{
- unsigned short planenum; // facing out of the leaf
- short texinfo;
-} dbrushside_t;
-
-typedef struct
-{
- int firstside;
- int numsides;
- int contents;
-} dbrush_t;
-
-#define ANGLE_UP -1
-#define ANGLE_DOWN -2
-
-
-// the visibility lump consists of a header with a count, then
-// byte offsets for the PVS and PHS of each cluster, then the raw
-// compressed bit vectors
-#define DVIS_PVS 0
-#define DVIS_PHS 1
-typedef struct
-{
- int numclusters;
- int bitofs[8][2]; // bitofs[numclusters][2]
-} dvis_t;
-
-// each area has a list of portals that lead into other areas
-// when portals are closed, other areas may not be visible or
-// hearable even if the vis info says that it should be
-typedef struct
-{
- int portalnum;
- int otherarea;
-} dareaportal_t;
-
-typedef struct
-{
- int numareaportals;
- int firstareaportal;
-} darea_t;
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+//
+// qfiles.h: quake file formats
+// This file must be identical in the quake and utils directories
+//
+
+/*
+========================================================================
+
+The .pak files are just a linear collapse of a directory tree
+
+========================================================================
+*/
+
+#define IDPAKHEADER (('K'<<24)+('C'<<16)+('A'<<8)+'P')
+
+typedef struct
+{
+ char name[56];
+ int filepos, filelen;
+} dpackfile_t;
+
+typedef struct
+{
+ int ident; // == IDPAKHEADER
+ int dirofs;
+ int dirlen;
+} dpackheader_t;
+
+#define MAX_FILES_IN_PACK 4096
+
+
+/*
+========================================================================
+
+PCX files are used for as many images as possible
+
+========================================================================
+*/
+
+typedef struct
+{
+ char manufacturer;
+ char version;
+ char encoding;
+ char bits_per_pixel;
+ unsigned short xmin,ymin,xmax,ymax;
+ unsigned short hres,vres;
+ unsigned char palette[48];
+ char reserved;
+ char color_planes;
+ unsigned short bytes_per_line;
+ unsigned short palette_type;
+ char filler[58];
+ unsigned char data; // unbounded
+} pcx_t;
+
+
+/*
+========================================================================
+
+.MD2 triangle model file format
+
+========================================================================
+*/
+
+#define IDALIASHEADER (('2'<<24)+('P'<<16)+('D'<<8)+'I')
+#define ALIAS_VERSION 8
+
+#define MAX_TRIANGLES 4096
+#define MAX_VERTS 2048
+#define MAX_FRAMES 512
+#define MAX_MD2SKINS 32
+#define MAX_SKINNAME 64
+
+typedef struct
+{
+ short s;
+ short t;
+} dstvert_t;
+
+typedef struct
+{
+ short index_xyz[3];
+ short index_st[3];
+} dtriangle_t;
+
+typedef struct
+{
+ byte v[3]; // scaled byte to fit in frame mins/maxs
+ byte lightnormalindex;
+} dtrivertx_t;
+
+#define DTRIVERTX_V0 0
+#define DTRIVERTX_V1 1
+#define DTRIVERTX_V2 2
+#define DTRIVERTX_LNI 3
+#define DTRIVERTX_SIZE 4
+
+typedef struct
+{
+ float scale[3]; // multiply byte verts by this
+ float translate[3]; // then add this
+ char name[16]; // frame name from grabbing
+ dtrivertx_t verts[1]; // variable sized
+} daliasframe_t;
+
+
+// the glcmd format:
+// a positive integer starts a tristrip command, followed by that many
+// vertex structures.
+// a negative integer starts a trifan command, followed by -x vertexes
+// a zero indicates the end of the command list.
+// a vertex consists of a floating point s, a floating point t,
+// and an integer vertex index.
+
+
+typedef struct
+{
+ int ident;
+ int version;
+
+ int skinwidth;
+ int skinheight;
+ int framesize; // byte size of each frame
+
+ int num_skins;
+ int num_xyz;
+ int num_st; // greater than num_xyz for seams
+ int num_tris;
+ int num_glcmds; // dwords in strip/fan command list
+ int num_frames;
+
+ int ofs_skins; // each skin is a MAX_SKINNAME string
+ int ofs_st; // byte offset from start for stverts
+ int ofs_tris; // offset for dtriangles
+ int ofs_frames; // offset for first frame
+ int ofs_glcmds;
+ int ofs_end; // end of file
+
+} dmdl_t;
+
+/*
+========================================================================
+
+.SP2 sprite file format
+
+========================================================================
+*/
+
+#define IDSPRITEHEADER (('2'<<24)+('S'<<16)+('D'<<8)+'I')
+ // little-endian "IDS2"
+#define SPRITE_VERSION 2
+
+typedef struct
+{
+ int width, height;
+ int origin_x, origin_y; // raster coordinates inside pic
+ char name[MAX_SKINNAME]; // name of pcx file
+} dsprframe_t;
+
+typedef struct {
+ int ident;
+ int version;
+ int numframes;
+ dsprframe_t frames[1]; // variable sized
+} dsprite_t;
+
+/*
+==============================================================================
+
+ .WAL texture file format
+
+==============================================================================
+*/
+
+
+#define MIPLEVELS 4
+typedef struct miptex_s
+{
+ char name[32];
+ unsigned width, height;
+ unsigned offsets[MIPLEVELS]; // four mip maps stored
+ char animname[32]; // next frame in animation chain
+ int flags;
+ int contents;
+ int value;
+} miptex_t;
+
+
+
+/*
+==============================================================================
+
+ .BSP file format
+
+==============================================================================
+*/
+
+#define IDBSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I')
+ // little-endian "IBSP"
+
+#define BSPVERSION 38
+
+
+// upper design bounds
+// leaffaces, leafbrushes, planes, and verts are still bounded by
+// 16 bit short limits
+#define MAX_MAP_MODELS 1024
+#define MAX_MAP_BRUSHES 8192
+#define MAX_MAP_ENTITIES 2048
+#define MAX_MAP_ENTSTRING 0x40000
+#define MAX_MAP_TEXINFO 8192
+
+#define MAX_MAP_AREAS 256
+#define MAX_MAP_AREAPORTALS 1024
+#define MAX_MAP_PLANES 65536
+#define MAX_MAP_NODES 65536
+#define MAX_MAP_BRUSHSIDES 65536
+#define MAX_MAP_LEAFS 65536
+#define MAX_MAP_VERTS 65536
+#define MAX_MAP_FACES 65536
+#define MAX_MAP_LEAFFACES 65536
+#define MAX_MAP_LEAFBRUSHES 65536
+#define MAX_MAP_PORTALS 65536
+#define MAX_MAP_EDGES 128000
+#define MAX_MAP_SURFEDGES 256000
+#define MAX_MAP_LIGHTING 0x320000
+#define MAX_MAP_VISIBILITY 0x280000
+
+// key / value pair sizes
+
+#define MAX_KEY 32
+#define MAX_VALUE 1024
+
+//=============================================================================
+
+typedef struct
+{
+ int fileofs, filelen;
+} lump_t;
+
+#define LUMP_ENTITIES 0
+#define LUMP_PLANES 1
+#define LUMP_VERTEXES 2
+#define LUMP_VISIBILITY 3
+#define LUMP_NODES 4
+#define LUMP_TEXINFO 5
+#define LUMP_FACES 6
+#define LUMP_LIGHTING 7
+#define LUMP_LEAFS 8
+#define LUMP_LEAFFACES 9
+#define LUMP_LEAFBRUSHES 10
+#define LUMP_EDGES 11
+#define LUMP_SURFEDGES 12
+#define LUMP_MODELS 13
+#define LUMP_BRUSHES 14
+#define LUMP_BRUSHSIDES 15
+#define LUMP_POP 16
+#define LUMP_AREAS 17
+#define LUMP_AREAPORTALS 18
+#define HEADER_LUMPS 19
+
+typedef struct
+{
+ int ident;
+ int version;
+ lump_t lumps[HEADER_LUMPS];
+} dheader_t;
+
+typedef struct
+{
+ float mins[3], maxs[3];
+ float origin[3]; // for sounds or lights
+ int headnode;
+ int firstface, numfaces; // submodels just draw faces
+ // without walking the bsp tree
+} dmodel_t;
+
+
+typedef struct
+{
+ float point[3];
+} dvertex_t;
+
+
+// 0-2 are axial planes
+#define PLANE_X 0
+#define PLANE_Y 1
+#define PLANE_Z 2
+
+// 3-5 are non-axial planes snapped to the nearest
+#define PLANE_ANYX 3
+#define PLANE_ANYY 4
+#define PLANE_ANYZ 5
+
+// planes (x&~1) and (x&~1)+1 are allways opposites
+
+typedef struct
+{
+ float normal[3];
+ float dist;
+ int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
+} dplane_t;
+
+
+// contents flags are seperate bits
+// a given brush can contribute multiple content bits
+// multiple brushes can be in a single leaf
+
+// these definitions also need to be in q_shared.h!
+
+// lower bits are stronger, and will eat weaker brushes completely
+#define CONTENTS_SOLID 1 // an eye is never valid in a solid
+#define CONTENTS_WINDOW 2 // translucent, but not watery
+#define CONTENTS_AUX 4
+#define CONTENTS_LAVA 8
+#define CONTENTS_SLIME 16
+#define CONTENTS_WATER 32
+#define CONTENTS_MIST 64
+#define LAST_VISIBLE_CONTENTS 64
+
+// remaining contents are non-visible, and don't eat brushes
+
+#define CONTENTS_AREAPORTAL 0x8000
+
+#define CONTENTS_PLAYERCLIP 0x10000
+#define CONTENTS_MONSTERCLIP 0x20000
+
+// currents can be added to any other contents, and may be mixed
+#define CONTENTS_CURRENT_0 0x40000
+#define CONTENTS_CURRENT_90 0x80000
+#define CONTENTS_CURRENT_180 0x100000
+#define CONTENTS_CURRENT_270 0x200000
+#define CONTENTS_CURRENT_UP 0x400000
+#define CONTENTS_CURRENT_DOWN 0x800000
+
+#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity
+
+#define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game
+#define CONTENTS_DEADMONSTER 0x4000000
+#define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs
+//renamed because it's in conflict with the Q3A translucent contents
+#define CONTENTS_Q2TRANSLUCENT 0x10000000 // auto set if any surface has trans
+#define CONTENTS_LADDER 0x20000000
+
+
+
+#define SURF_LIGHT 0x1 // value will hold the light strength
+
+#define SURF_SLICK 0x2 // effects game physics
+
+#define SURF_SKY 0x4 // don't draw, but add to skybox
+#define SURF_WARP 0x8 // turbulent water warp
+#define SURF_TRANS33 0x10
+#define SURF_TRANS66 0x20
+#define SURF_FLOWING 0x40 // scroll towards angle
+#define SURF_NODRAW 0x80 // don't bother referencing the texture
+
+#define SURF_HINT 0x100 // make a primary bsp splitter
+#define SURF_SKIP 0x200 // completely ignore, allowing non-closed brushes
+
+
+
+typedef struct
+{
+ int planenum;
+ int children[2]; // negative numbers are -(leafs+1), not nodes
+ short mins[3]; // for frustom culling
+ short maxs[3];
+ unsigned short firstface;
+ unsigned short numfaces; // counting both sides
+} dnode_t;
+
+
+typedef struct texinfo_s
+{
+ float vecs[2][4]; // [s/t][xyz offset]
+ int flags; // miptex flags + overrides
+ int value; // light emission, etc
+ char texture[32]; // texture name (textures/*.wal)
+ int nexttexinfo; // for animations, -1 = end of chain
+} texinfo_t;
+
+
+// note that edge 0 is never used, because negative edge nums are used for
+// counterclockwise use of the edge in a face
+typedef struct
+{
+ unsigned short v[2]; // vertex numbers
+} dedge_t;
+
+#define MAXLIGHTMAPS 4
+typedef struct
+{
+ unsigned short planenum;
+ short side;
+
+ int firstedge; // we must support > 64k edges
+ short numedges;
+ short texinfo;
+
+// lighting info
+ byte styles[MAXLIGHTMAPS];
+ int lightofs; // start of [numstyles*surfsize] samples
+} dface_t;
+
+typedef struct
+{
+ int contents; // OR of all brushes (not needed?)
+
+ short cluster;
+ short area;
+
+ short mins[3]; // for frustum culling
+ short maxs[3];
+
+ unsigned short firstleafface;
+ unsigned short numleaffaces;
+
+ unsigned short firstleafbrush;
+ unsigned short numleafbrushes;
+} dleaf_t;
+
+typedef struct
+{
+ unsigned short planenum; // facing out of the leaf
+ short texinfo;
+} dbrushside_t;
+
+typedef struct
+{
+ int firstside;
+ int numsides;
+ int contents;
+} dbrush_t;
+
+#define ANGLE_UP -1
+#define ANGLE_DOWN -2
+
+
+// the visibility lump consists of a header with a count, then
+// byte offsets for the PVS and PHS of each cluster, then the raw
+// compressed bit vectors
+#define DVIS_PVS 0
+#define DVIS_PHS 1
+typedef struct
+{
+ int numclusters;
+ int bitofs[8][2]; // bitofs[numclusters][2]
+} dvis_t;
+
+// each area has a list of portals that lead into other areas
+// when portals are closed, other areas may not be visible or
+// hearable even if the vis info says that it should be
+typedef struct
+{
+ int portalnum;
+ int otherarea;
+} dareaportal_t;
+
+typedef struct
+{
+ int numareaportals;
+ int firstareaportal;
+} darea_t;
diff --git a/code/bspc/q3files.h b/code/bspc/q3files.h
index b251cc0..5ed267d 100755
--- a/code/bspc/q3files.h
+++ b/code/bspc/q3files.h
@@ -1,374 +1,374 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-#ifndef __QFILES_H__
-#define __QFILES_H__
-
-//
-// qfiles.h: quake file formats
-// This file must be identical in the quake and utils directories
-//
-
-// surface geometry should not exceed these limits
-#define SHADER_MAX_VERTEXES 1000
-#define SHADER_MAX_INDEXES (6*SHADER_MAX_VERTEXES)
-
-
-// the maximum size of game reletive pathnames
-#define MAX_QPATH 64
-
-
-/*
-========================================================================
-
-PCX files are used for 8 bit images
-
-========================================================================
-*
-
-typedef struct {
- char manufacturer;
- char version;
- char encoding;
- char bits_per_pixel;
- unsigned short xmin,ymin,xmax,ymax;
- unsigned short hres,vres;
- unsigned char palette[48];
- char reserved;
- char color_planes;
- unsigned short bytes_per_line;
- unsigned short palette_type;
- char filler[58];
- unsigned char data; // unbounded
-} pcx_t;
-
-
-/*
-========================================================================
-
-TGA files are used for 24/32 bit images
-
-========================================================================
-*
-
-typedef struct _TargaHeader {
- unsigned char id_length, colormap_type, image_type;
- unsigned short colormap_index, colormap_length;
- unsigned char colormap_size;
- unsigned short x_origin, y_origin, width, height;
- unsigned char pixel_size, attributes;
-} TargaHeader;
-
-
-*/
-
-/*
-========================================================================
-
-.MD3 triangle model file format
-
-========================================================================
-*/
-
-#define MD3_IDENT (('3'<<24)+('P'<<16)+('D'<<8)+'I')
-#define MD3_VERSION 15
-
-// limits
-#define MD3_MAX_LODS 4
-#define MD3_MAX_TRIANGLES 8192 // per surface
-#define MD3_MAX_VERTS 4096 // per surface
-#define MD3_MAX_SHADERS 256 // per surface
-#define MD3_MAX_FRAMES 1024 // per model
-#define MD3_MAX_SURFACES 32 // per model
-#define MD3_MAX_TAGS 16 // per frame
-
-// vertex scales
-#define MD3_XYZ_SCALE (1.0/64)
-
-typedef struct md3Frame_s {
- vec3_t bounds[2];
- vec3_t localOrigin;
- float radius;
- char name[16];
-} md3Frame_t;
-
-typedef struct md3Tag_s {
- char name[MAX_QPATH]; // tag name
- vec3_t origin;
- vec3_t axis[3];
-} md3Tag_t;
-
-/*
-** md3Surface_t
-**
-** CHUNK SIZE
-** header sizeof( md3Surface_t )
-** shaders sizeof( md3Shader_t ) * numShaders
-** triangles[0] sizeof( md3Triangle_t ) * numTriangles
-** st sizeof( md3St_t ) * numVerts
-** XyzNormals sizeof( md3XyzNormal_t ) * numVerts * numFrames
-*/
-
-typedef struct {
- int ident; //
-
- char name[MAX_QPATH]; // polyset name
-
- int flags;
- int numFrames; // all surfaces in a model should have the same
-
- int numShaders; // all surfaces in a model should have the same
- int numVerts;
-
- int numTriangles;
- int ofsTriangles;
-
- int ofsShaders; // offset from start of md3Surface_t
- int ofsSt; // texture coords are common for all frames
- int ofsXyzNormals; // numVerts * numFrames
-
- int ofsEnd; // next surface follows
-} md3Surface_t;
-
-typedef struct {
- char name[MAX_QPATH];
- int shaderIndex; // for in-game use
-} md3Shader_t;
-
-typedef struct {
- int indexes[3];
-} md3Triangle_t;
-
-typedef struct {
- float st[2];
-} md3St_t;
-
-typedef struct {
- short xyz[3];
- short normal;
-} md3XyzNormal_t;
-
-typedef struct {
- int ident;
- int version;
-
- char name[MAX_QPATH]; // model name
-
- int flags;
-
- int numFrames;
- int numTags;
- int numSurfaces;
-
- int numSkins;
-
- int ofsFrames; // offset for first frame
- int ofsTags; // numFrames * numTags
- int ofsSurfaces; // first surface, others follow
-
- int ofsEnd; // end of file
-} md3Header_t;
-
-
-
-/*
-==============================================================================
-
- .BSP file format
-
-==============================================================================
-*/
-
-
-#define Q3_BSP_IDENT (('P'<<24)+('S'<<16)+('B'<<8)+'I')
- // little-endian "IBSP"
-
-#define Q3_BSP_VERSION 46
-
-
-// there shouldn't be any problem with increasing these values at the
-// expense of more memory allocation in the utilities
-#define Q3_MAX_MAP_MODELS 0x400
-#define Q3_MAX_MAP_BRUSHES 0x8000
-#define Q3_MAX_MAP_ENTITIES 0x800
-#define Q3_MAX_MAP_ENTSTRING 0x10000
-#define Q3_MAX_MAP_SHADERS 0x400
-
-#define Q3_MAX_MAP_AREAS 0x100 // MAX_MAP_AREA_BYTES in q_shared must match!
-#define Q3_MAX_MAP_FOGS 0x100
-#define Q3_MAX_MAP_PLANES 0x10000
-#define Q3_MAX_MAP_NODES 0x10000
-#define Q3_MAX_MAP_BRUSHSIDES 0x10000
-#define Q3_MAX_MAP_LEAFS 0x10000
-#define Q3_MAX_MAP_LEAFFACES 0x10000
-#define Q3_MAX_MAP_LEAFBRUSHES 0x10000
-#define Q3_MAX_MAP_PORTALS 0x10000
-#define Q3_MAX_MAP_LIGHTING 0x400000
-#define Q3_MAX_MAP_LIGHTGRID 0x400000
-#define Q3_MAX_MAP_VISIBILITY 0x200000
-
-#define Q3_MAX_MAP_DRAW_SURFS 0x20000
-#define Q3_MAX_MAP_DRAW_VERTS 0x80000
-#define Q3_MAX_MAP_DRAW_INDEXES 0x80000
-
-
-// key / value pair sizes in the entities lump
-#define Q3_MAX_KEY 32
-#define Q3_MAX_VALUE 1024
-
-// the editor uses these predefined yaw angles to orient entities up or down
-#define ANGLE_UP -1
-#define ANGLE_DOWN -2
-
-#define LIGHTMAP_WIDTH 128
-#define LIGHTMAP_HEIGHT 128
-
-
-//=============================================================================
-
-
-typedef struct {
- int fileofs, filelen;
-} q3_lump_t;
-
-#define Q3_LUMP_ENTITIES 0
-#define Q3_LUMP_SHADERS 1
-#define Q3_LUMP_PLANES 2
-#define Q3_LUMP_NODES 3
-#define Q3_LUMP_LEAFS 4
-#define Q3_LUMP_LEAFSURFACES 5
-#define Q3_LUMP_LEAFBRUSHES 6
-#define Q3_LUMP_MODELS 7
-#define Q3_LUMP_BRUSHES 8
-#define Q3_LUMP_BRUSHSIDES 9
-#define Q3_LUMP_DRAWVERTS 10
-#define Q3_LUMP_DRAWINDEXES 11
-#define Q3_LUMP_FOGS 12
-#define Q3_LUMP_SURFACES 13
-#define Q3_LUMP_LIGHTMAPS 14
-#define Q3_LUMP_LIGHTGRID 15
-#define Q3_LUMP_VISIBILITY 16
-#define Q3_HEADER_LUMPS 17
-
-typedef struct {
- int ident;
- int version;
-
- q3_lump_t lumps[Q3_HEADER_LUMPS];
-} q3_dheader_t;
-
-typedef struct {
- float mins[3], maxs[3];
- int firstSurface, numSurfaces;
- int firstBrush, numBrushes;
-} q3_dmodel_t;
-
-typedef struct {
- char shader[MAX_QPATH];
- int surfaceFlags;
- int contentFlags;
-} q3_dshader_t;
-
-// planes (x&~1) and (x&~1)+1 are allways opposites
-
-typedef struct {
- float normal[3];
- float dist;
-} q3_dplane_t;
-
-typedef struct {
- int planeNum;
- int children[2]; // negative numbers are -(leafs+1), not nodes
- int mins[3]; // for frustom culling
- int maxs[3];
-} q3_dnode_t;
-
-typedef struct {
- int cluster; // -1 = opaque cluster (do I still store these?)
- int area;
-
- int mins[3]; // for frustum culling
- int maxs[3];
-
- int firstLeafSurface;
- int numLeafSurfaces;
-
- int firstLeafBrush;
- int numLeafBrushes;
-} q3_dleaf_t;
-
-typedef struct {
- int planeNum; // positive plane side faces out of the leaf
- int shaderNum;
-} q3_dbrushside_t;
-
-typedef struct {
- int firstSide;
- int numSides;
- int shaderNum; // the shader that determines the contents flags
-} q3_dbrush_t;
-
-typedef struct {
- char shader[MAX_QPATH];
- int brushNum;
- int visibleSide; // the brush side that ray tests need to clip against (-1 == none)
-} q3_dfog_t;
-
-typedef struct {
- vec3_t xyz;
- float st[2];
- float lightmap[2];
- vec3_t normal;
- byte color[4];
-} q3_drawVert_t;
-
-typedef enum {
- MST_BAD,
- MST_PLANAR,
- MST_PATCH,
- MST_TRIANGLE_SOUP,
- MST_FLARE
-} q3_mapSurfaceType_t;
-
-typedef struct {
- int shaderNum;
- int fogNum;
- int surfaceType;
-
- int firstVert;
- int numVerts;
-
- int firstIndex;
- int numIndexes;
-
- int lightmapNum;
- int lightmapX, lightmapY;
- int lightmapWidth, lightmapHeight;
-
- vec3_t lightmapOrigin;
- vec3_t lightmapVecs[3]; // for patches, [0] and [1] are lodbounds
-
- int patchWidth;
- int patchHeight;
-} q3_dsurface_t;
-
-
-#endif
+/*
+===========================================================================
+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
+===========================================================================
+*/
+#ifndef __QFILES_H__
+#define __QFILES_H__
+
+//
+// qfiles.h: quake file formats
+// This file must be identical in the quake and utils directories
+//
+
+// surface geometry should not exceed these limits
+#define SHADER_MAX_VERTEXES 1000
+#define SHADER_MAX_INDEXES (6*SHADER_MAX_VERTEXES)
+
+
+// the maximum size of game reletive pathnames
+#define MAX_QPATH 64
+
+
+/*
+========================================================================
+
+PCX files are used for 8 bit images
+
+========================================================================
+*
+
+typedef struct {
+ char manufacturer;
+ char version;
+ char encoding;
+ char bits_per_pixel;
+ unsigned short xmin,ymin,xmax,ymax;
+ unsigned short hres,vres;
+ unsigned char palette[48];
+ char reserved;
+ char color_planes;
+ unsigned short bytes_per_line;
+ unsigned short palette_type;
+ char filler[58];
+ unsigned char data; // unbounded
+} pcx_t;
+
+
+/*
+========================================================================
+
+TGA files are used for 24/32 bit images
+
+========================================================================
+*
+
+typedef struct _TargaHeader {
+ unsigned char id_length, colormap_type, image_type;
+ unsigned short colormap_index, colormap_length;
+ unsigned char colormap_size;
+ unsigned short x_origin, y_origin, width, height;
+ unsigned char pixel_size, attributes;
+} TargaHeader;
+
+
+*/
+
+/*
+========================================================================
+
+.MD3 triangle model file format
+
+========================================================================
+*/
+
+#define MD3_IDENT (('3'<<24)+('P'<<16)+('D'<<8)+'I')
+#define MD3_VERSION 15
+
+// limits
+#define MD3_MAX_LODS 4
+#define MD3_MAX_TRIANGLES 8192 // per surface
+#define MD3_MAX_VERTS 4096 // per surface
+#define MD3_MAX_SHADERS 256 // per surface
+#define MD3_MAX_FRAMES 1024 // per model
+#define MD3_MAX_SURFACES 32 // per model
+#define MD3_MAX_TAGS 16 // per frame
+
+// vertex scales
+#define MD3_XYZ_SCALE (1.0/64)
+
+typedef struct md3Frame_s {
+ vec3_t bounds[2];
+ vec3_t localOrigin;
+ float radius;
+ char name[16];
+} md3Frame_t;
+
+typedef struct md3Tag_s {
+ char name[MAX_QPATH]; // tag name
+ vec3_t origin;
+ vec3_t axis[3];
+} md3Tag_t;
+
+/*
+** md3Surface_t
+**
+** CHUNK SIZE
+** header sizeof( md3Surface_t )
+** shaders sizeof( md3Shader_t ) * numShaders
+** triangles[0] sizeof( md3Triangle_t ) * numTriangles
+** st sizeof( md3St_t ) * numVerts
+** XyzNormals sizeof( md3XyzNormal_t ) * numVerts * numFrames
+*/
+
+typedef struct {
+ int ident; //
+
+ char name[MAX_QPATH]; // polyset name
+
+ int flags;
+ int numFrames; // all surfaces in a model should have the same
+
+ int numShaders; // all surfaces in a model should have the same
+ int numVerts;
+
+ int numTriangles;
+ int ofsTriangles;
+
+ int ofsShaders; // offset from start of md3Surface_t
+ int ofsSt; // texture coords are common for all frames
+ int ofsXyzNormals; // numVerts * numFrames
+
+ int ofsEnd; // next surface follows
+} md3Surface_t;
+
+typedef struct {
+ char name[MAX_QPATH];
+ int shaderIndex; // for in-game use
+} md3Shader_t;
+
+typedef struct {
+ int indexes[3];
+} md3Triangle_t;
+
+typedef struct {
+ float st[2];
+} md3St_t;
+
+typedef struct {
+ short xyz[3];
+ short normal;
+} md3XyzNormal_t;
+
+typedef struct {
+ int ident;
+ int version;
+
+ char name[MAX_QPATH]; // model name
+
+ int flags;
+
+ int numFrames;
+ int numTags;
+ int numSurfaces;
+
+ int numSkins;
+
+ int ofsFrames; // offset for first frame
+ int ofsTags; // numFrames * numTags
+ int ofsSurfaces; // first surface, others follow
+
+ int ofsEnd; // end of file
+} md3Header_t;
+
+
+
+/*
+==============================================================================
+
+ .BSP file format
+
+==============================================================================
+*/
+
+
+#define Q3_BSP_IDENT (('P'<<24)+('S'<<16)+('B'<<8)+'I')
+ // little-endian "IBSP"
+
+#define Q3_BSP_VERSION 46
+
+
+// there shouldn't be any problem with increasing these values at the
+// expense of more memory allocation in the utilities
+#define Q3_MAX_MAP_MODELS 0x400
+#define Q3_MAX_MAP_BRUSHES 0x8000
+#define Q3_MAX_MAP_ENTITIES 0x800
+#define Q3_MAX_MAP_ENTSTRING 0x10000
+#define Q3_MAX_MAP_SHADERS 0x400
+
+#define Q3_MAX_MAP_AREAS 0x100 // MAX_MAP_AREA_BYTES in q_shared must match!
+#define Q3_MAX_MAP_FOGS 0x100
+#define Q3_MAX_MAP_PLANES 0x10000
+#define Q3_MAX_MAP_NODES 0x10000
+#define Q3_MAX_MAP_BRUSHSIDES 0x10000
+#define Q3_MAX_MAP_LEAFS 0x10000
+#define Q3_MAX_MAP_LEAFFACES 0x10000
+#define Q3_MAX_MAP_LEAFBRUSHES 0x10000
+#define Q3_MAX_MAP_PORTALS 0x10000
+#define Q3_MAX_MAP_LIGHTING 0x400000
+#define Q3_MAX_MAP_LIGHTGRID 0x400000
+#define Q3_MAX_MAP_VISIBILITY 0x200000
+
+#define Q3_MAX_MAP_DRAW_SURFS 0x20000
+#define Q3_MAX_MAP_DRAW_VERTS 0x80000
+#define Q3_MAX_MAP_DRAW_INDEXES 0x80000
+
+
+// key / value pair sizes in the entities lump
+#define Q3_MAX_KEY 32
+#define Q3_MAX_VALUE 1024
+
+// the editor uses these predefined yaw angles to orient entities up or down
+#define ANGLE_UP -1
+#define ANGLE_DOWN -2
+
+#define LIGHTMAP_WIDTH 128
+#define LIGHTMAP_HEIGHT 128
+
+
+//=============================================================================
+
+
+typedef struct {
+ int fileofs, filelen;
+} q3_lump_t;
+
+#define Q3_LUMP_ENTITIES 0
+#define Q3_LUMP_SHADERS 1
+#define Q3_LUMP_PLANES 2
+#define Q3_LUMP_NODES 3
+#define Q3_LUMP_LEAFS 4
+#define Q3_LUMP_LEAFSURFACES 5
+#define Q3_LUMP_LEAFBRUSHES 6
+#define Q3_LUMP_MODELS 7
+#define Q3_LUMP_BRUSHES 8
+#define Q3_LUMP_BRUSHSIDES 9
+#define Q3_LUMP_DRAWVERTS 10
+#define Q3_LUMP_DRAWINDEXES 11
+#define Q3_LUMP_FOGS 12
+#define Q3_LUMP_SURFACES 13
+#define Q3_LUMP_LIGHTMAPS 14
+#define Q3_LUMP_LIGHTGRID 15
+#define Q3_LUMP_VISIBILITY 16
+#define Q3_HEADER_LUMPS 17
+
+typedef struct {
+ int ident;
+ int version;
+
+ q3_lump_t lumps[Q3_HEADER_LUMPS];
+} q3_dheader_t;
+
+typedef struct {
+ float mins[3], maxs[3];
+ int firstSurface, numSurfaces;
+ int firstBrush, numBrushes;
+} q3_dmodel_t;
+
+typedef struct {
+ char shader[MAX_QPATH];
+ int surfaceFlags;
+ int contentFlags;
+} q3_dshader_t;
+
+// planes (x&~1) and (x&~1)+1 are allways opposites
+
+typedef struct {
+ float normal[3];
+ float dist;
+} q3_dplane_t;
+
+typedef struct {
+ int planeNum;
+ int children[2]; // negative numbers are -(leafs+1), not nodes
+ int mins[3]; // for frustom culling
+ int maxs[3];
+} q3_dnode_t;
+
+typedef struct {
+ int cluster; // -1 = opaque cluster (do I still store these?)
+ int area;
+
+ int mins[3]; // for frustum culling
+ int maxs[3];
+
+ int firstLeafSurface;
+ int numLeafSurfaces;
+
+ int firstLeafBrush;
+ int numLeafBrushes;
+} q3_dleaf_t;
+
+typedef struct {
+ int planeNum; // positive plane side faces out of the leaf
+ int shaderNum;
+} q3_dbrushside_t;
+
+typedef struct {
+ int firstSide;
+ int numSides;
+ int shaderNum; // the shader that determines the contents flags
+} q3_dbrush_t;
+
+typedef struct {
+ char shader[MAX_QPATH];
+ int brushNum;
+ int visibleSide; // the brush side that ray tests need to clip against (-1 == none)
+} q3_dfog_t;
+
+typedef struct {
+ vec3_t xyz;
+ float st[2];
+ float lightmap[2];
+ vec3_t normal;
+ byte color[4];
+} q3_drawVert_t;
+
+typedef enum {
+ MST_BAD,
+ MST_PLANAR,
+ MST_PATCH,
+ MST_TRIANGLE_SOUP,
+ MST_FLARE
+} q3_mapSurfaceType_t;
+
+typedef struct {
+ int shaderNum;
+ int fogNum;
+ int surfaceType;
+
+ int firstVert;
+ int numVerts;
+
+ int firstIndex;
+ int numIndexes;
+
+ int lightmapNum;
+ int lightmapX, lightmapY;
+ int lightmapWidth, lightmapHeight;
+
+ vec3_t lightmapOrigin;
+ vec3_t lightmapVecs[3]; // for patches, [0] and [1] are lodbounds
+
+ int patchWidth;
+ int patchHeight;
+} q3_dsurface_t;
+
+
+#endif
diff --git a/code/bspc/qbsp.h b/code/bspc/qbsp.h
index 7ebf9d4..dd57200 100755
--- a/code/bspc/qbsp.h
+++ b/code/bspc/qbsp.h
@@ -1,477 +1,477 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-
-
-#if defined(WIN32) || defined(_WIN32)
-#include <io.h>
-#endif
-#include <malloc.h>
-#include "l_cmd.h"
-#include "l_math.h"
-#include "l_poly.h"
-#include "l_threads.h"
-#include "../botlib/l_script.h"
-#include "l_bsp_ent.h"
-#include "q2files.h"
-#include "l_mem.h"
-#include "l_utils.h"
-#include "l_log.h"
-#include "l_qfiles.h"
-
-#define BSPC_VERSION "2.1h"
-
-#define ME
-#define DEBUG
-#define NODELIST
-#define SIN
-
-#define MAX_BRUSH_SIDES 128 //maximum number of sides per brush
-#define CLIP_EPSILON 0.1
-#define MAX_MAP_BOUNDS 65535
-#define BOGUS_RANGE (MAX_MAP_BOUNDS+128) //somewhere outside the map
-#define TEXINFO_NODE -1 //side is allready on a node
-#define PLANENUM_LEAF -1 //used for leaf nodes
-#define MAXEDGES 20 //maximum number of face edges
-#define MAX_NODE_BRUSHES 8 //maximum brushes in a node
-//side flags
-#define SFL_TESTED 1
-#define SFL_VISIBLE 2
-#define SFL_BEVEL 4
-#define SFL_TEXTURED 8
-#define SFL_CURVE 16
-
-//map plane
-typedef struct plane_s
-{
- vec3_t normal;
- vec_t dist;
- int type;
- int signbits;
- struct plane_s *hash_chain;
-} plane_t;
-//brush texture
-typedef struct
-{
- vec_t shift[2];
- vec_t rotate;
- vec_t scale[2];
- char name[32];
- int flags;
- int value;
-} brush_texture_t;
-//brush side
-typedef struct side_s
-{
- int planenum; // map plane this side is in
- int texinfo; // texture reference
- winding_t *winding; // winding of this side
- struct side_s *original; // bspbrush_t sides will reference the mapbrush_t sides
- int lightinfo; // for SIN only
- int contents; // from miptex
- int surf; // from miptex
- unsigned short flags; // side flags
-} side_t; //sizeof(side_t) = 36
-//map brush
-typedef struct mapbrush_s
-{
- int entitynum;
- int brushnum;
-
- int contents;
-#ifdef ME
- int expansionbbox; //bbox used for expansion of the brush
- int leafnum;
- int modelnum;
-#endif
-
- vec3_t mins, maxs;
-
- int numsides;
- side_t *original_sides;
-} mapbrush_t;
-//bsp face
-typedef struct face_s
-{
- struct face_s *next; // on node
-
- // the chain of faces off of a node can be merged or split,
- // but each face_t along the way will remain in the chain
- // until the entire tree is freed
- struct face_s *merged; // if set, this face isn't valid anymore
- struct face_s *split[2]; // if set, this face isn't valid anymore
-
- struct portal_s *portal;
- int texinfo;
-#ifdef SIN
- int lightinfo;
-#endif
- int planenum;
- int contents; // faces in different contents can't merge
- int outputnumber;
- winding_t *w;
- int numpoints;
- qboolean badstartvert; // tjunctions cannot be fixed without a midpoint vertex
- int vertexnums[MAXEDGES];
-} face_t;
-//bsp brush
-typedef struct bspbrush_s
-{
- struct bspbrush_s *next;
- vec3_t mins, maxs;
- int side, testside; // side of node during construction
- mapbrush_t *original;
- int numsides;
- side_t sides[6]; // variably sized
-} bspbrush_t; //sizeof(bspbrush_t) = 44 + numsides * sizeof(side_t)
-//bsp node
-typedef struct node_s
-{
- //both leafs and nodes
- int planenum; // -1 = leaf node
- struct node_s *parent;
- vec3_t mins, maxs; // valid after portalization
- bspbrush_t *volume; // one for each leaf/node
-
- // nodes only
- qboolean detail_seperator; // a detail brush caused the split
- side_t *side; // the side that created the node
- struct node_s *children[2];
- face_t *faces;
-
- // leafs only
- bspbrush_t *brushlist; // fragments of all brushes in this leaf
- int contents; // OR of all brush contents
- int occupied; // 1 or greater can reach entity
- entity_t *occupant; // for leak file testing
- int cluster; // for portalfile writing
- int area; // for areaportals
- struct portal_s *portals; // also on nodes during construction
-#ifdef NODELIST
- struct node_s *next; //next node in the nodelist
-#endif
-#ifdef ME
- int expansionbboxes; //OR of all bboxes used for expansion of the brushes
- int modelnum;
-#endif
-} node_t; //sizeof(node_t) = 80 bytes
-//bsp portal
-typedef struct portal_s
-{
- plane_t plane;
- node_t *onnode; // NULL = outside box
- node_t *nodes[2]; // [0] = front side of plane
- struct portal_s *next[2];
- winding_t *winding;
-
- qboolean sidefound; // false if ->side hasn't been checked
- side_t *side; // NULL = non-visible
- face_t *face[2]; // output face in bsp file
-#ifdef ME
- struct tmp_face_s *tmpface; //pointer to the tmpface created for this portal
- int planenum; //number of the map plane used by the portal
-#endif
-} portal_t;
-//bsp tree
-typedef struct
-{
- node_t *headnode;
- node_t outside_node;
- vec3_t mins, maxs;
-} tree_t;
-
-//=============================================================================
-// bspc.c
-//=============================================================================
-
-extern qboolean noprune;
-extern qboolean nodetail;
-extern qboolean fulldetail;
-extern qboolean nomerge;
-extern qboolean nosubdiv;
-extern qboolean nowater;
-extern qboolean noweld;
-extern qboolean noshare;
-extern qboolean notjunc;
-extern qboolean onlyents;
-#ifdef ME
-extern qboolean nocsg;
-extern qboolean create_aas;
-extern qboolean freetree;
-extern qboolean lessbrushes;
-extern qboolean nobrushmerge;
-extern qboolean cancelconversion;
-extern qboolean noliquids;
-extern qboolean capsule_collision;
-#endif //ME
-
-extern float subdivide_size;
-extern vec_t microvolume;
-
-extern char outbase[32];
-extern char source[1024];
-
-//=============================================================================
-// map.c
-//=============================================================================
-
-#define MAX_MAPFILE_PLANES 256000
-#define MAX_MAPFILE_BRUSHES 65535
-#define MAX_MAPFILE_BRUSHSIDES (MAX_MAPFILE_BRUSHES*8)
-#define MAX_MAPFILE_TEXINFO 8192
-
-extern int entity_num;
-
-extern plane_t mapplanes[MAX_MAPFILE_PLANES];
-extern int nummapplanes;
-extern int mapplaneusers[MAX_MAPFILE_PLANES];
-
-extern int nummapbrushes;
-extern mapbrush_t mapbrushes[MAX_MAPFILE_BRUSHES];
-
-extern vec3_t map_mins, map_maxs;
-
-extern int nummapbrushsides;
-extern side_t brushsides[MAX_MAPFILE_BRUSHSIDES];
-extern brush_texture_t side_brushtextures[MAX_MAPFILE_BRUSHSIDES];
-
-#ifdef ME
-
-typedef struct
-{
- float vecs[2][4]; // [s/t][xyz offset]
- int flags; // miptex flags + overrides
- int value;
- char texture[64]; // texture name (textures/*.wal)
- int nexttexinfo; // for animations, -1 = end of chain
-} map_texinfo_t;
-
-extern map_texinfo_t map_texinfo[MAX_MAPFILE_TEXINFO];
-extern int map_numtexinfo;
-#define NODESTACKSIZE 1024
-
-#define MAPTYPE_QUAKE1 1
-#define MAPTYPE_QUAKE2 2
-#define MAPTYPE_QUAKE3 3
-#define MAPTYPE_HALFLIFE 4
-#define MAPTYPE_SIN 5
-
-extern int nodestack[NODESTACKSIZE];
-extern int *nodestackptr;
-extern int nodestacksize;
-extern int brushmodelnumbers[MAX_MAPFILE_BRUSHES];
-extern int dbrushleafnums[MAX_MAPFILE_BRUSHES];
-extern int dplanes2mapplanes[MAX_MAPFILE_PLANES];
-
-extern int loadedmaptype;
-#endif //ME
-
-extern int c_boxbevels;
-extern int c_edgebevels;
-extern int c_areaportals;
-extern int c_clipbrushes;
-extern int c_squattbrushes;
-
-//finds a float plane for the given normal and distance
-int FindFloatPlane(vec3_t normal, vec_t dist);
-//returns the plane type for the given normal
-int PlaneTypeForNormal(vec3_t normal);
-//returns the plane defined by the three given points
-int PlaneFromPoints(int *p0, int *p1, int *p2);
-//add bevels to the map brush
-void AddBrushBevels(mapbrush_t *b);
-//makes brush side windings for the brush
-qboolean MakeBrushWindings(mapbrush_t *ob);
-//marks brush bevels of the brush as bevel
-void MarkBrushBevels(mapbrush_t *brush);
-//returns true if the map brush already exists
-int BrushExists(mapbrush_t *brush);
-//loads a map from a bsp file
-int LoadMapFromBSP(struct quakefile_s *qf);
-//resets map loading
-void ResetMapLoading(void);
-//print some map info
-void PrintMapInfo(void);
-//writes a map file (type depending on loaded map type)
-void WriteMapFile(char *filename);
-
-//=============================================================================
-// map_q2.c
-//=============================================================================
-
-void Q2_ResetMapLoading(void);
-//loads a Quake2 map file
-void Q2_LoadMapFile(char *filename);
-//loads a map from a Quake2 bsp file
-void Q2_LoadMapFromBSP(char *filename, int offset, int length);
-
-//=============================================================================
-// map_q1.c
-//=============================================================================
-
-void Q1_ResetMapLoading(void);
-//loads a Quake2 map file
-void Q1_LoadMapFile(char *filename);
-//loads a map from a Quake1 bsp file
-void Q1_LoadMapFromBSP(char *filename, int offset, int length);
-
-//=============================================================================
-// map_q3.c
-//=============================================================================
-void Q3_ResetMapLoading(void);
-//loads a map from a Quake3 bsp file
-void Q3_LoadMapFromBSP(struct quakefile_s *qf);
-
-//=============================================================================
-// map_sin.c
-//=============================================================================
-
-void Sin_ResetMapLoading(void);
-//loads a Sin map file
-void Sin_LoadMapFile(char *filename);
-//loads a map from a Sin bsp file
-void Sin_LoadMapFromBSP(char *filename, int offset, int length);
-
-//=============================================================================
-// map_hl.c
-//=============================================================================
-
-void HL_ResetMapLoading(void);
-//loads a Half-Life map file
-void HL_LoadMapFile(char *filename);
-//loads a map from a Half-Life bsp file
-void HL_LoadMapFromBSP(char *filename, int offset, int length);
-
-//=============================================================================
-// textures.c
-//=============================================================================
-
-typedef struct
-{
- char name[64];
- int flags;
- int value;
- int contents;
- char animname[64];
-} textureref_t;
-
-#define MAX_MAP_TEXTURES 1024
-
-extern textureref_t textureref[MAX_MAP_TEXTURES];
-
-int FindMiptex(char *name);
-int TexinfoForBrushTexture(plane_t *plane, brush_texture_t *bt, vec3_t origin);
-void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv);
-
-//=============================================================================
-// csg
-//=============================================================================
-
-bspbrush_t *MakeBspBrushList(int startbrush, int endbrush, vec3_t clipmins, vec3_t clipmaxs);
-bspbrush_t *ChopBrushes(bspbrush_t *head);
-bspbrush_t *InitialBrushList(bspbrush_t *list);
-bspbrush_t *OptimizedBrushList(bspbrush_t *list);
-void WriteBrushMap(char *name, bspbrush_t *list);
-void CheckBSPBrush(bspbrush_t *brush);
-void BSPBrushWindings(bspbrush_t *brush);
-bspbrush_t *TryMergeBrushes(bspbrush_t *brush1, bspbrush_t *brush2);
-tree_t *ProcessWorldBrushes(int brush_start, int brush_end);
-
-//=============================================================================
-// brushbsp
-//=============================================================================
-
-#define PSIDE_FRONT 1
-#define PSIDE_BACK 2
-#define PSIDE_BOTH (PSIDE_FRONT|PSIDE_BACK)
-#define PSIDE_FACING 4
-
-void WriteBrushList(char *name, bspbrush_t *brush, qboolean onlyvis);
-bspbrush_t *CopyBrush(bspbrush_t *brush);
-void SplitBrush(bspbrush_t *brush, int planenum, bspbrush_t **front, bspbrush_t **back);
-node_t *AllocNode(void);
-bspbrush_t *AllocBrush(int numsides);
-int CountBrushList(bspbrush_t *brushes);
-void FreeBrush(bspbrush_t *brushes);
-vec_t BrushVolume(bspbrush_t *brush);
-void BoundBrush(bspbrush_t *brush);
-void FreeBrushList(bspbrush_t *brushes);
-tree_t *BrushBSP(bspbrush_t *brushlist, vec3_t mins, vec3_t maxs);
-bspbrush_t *BrushFromBounds(vec3_t mins, vec3_t maxs);
-int BrushMostlyOnSide(bspbrush_t *brush, plane_t *plane);
-qboolean WindingIsHuge(winding_t *w);
-qboolean WindingIsTiny(winding_t *w);
-void ResetBrushBSP(void);
-
-//=============================================================================
-// portals.c
-//=============================================================================
-
-int VisibleContents (int contents);
-void MakeHeadnodePortals (tree_t *tree);
-void MakeNodePortal (node_t *node);
-void SplitNodePortals (node_t *node);
-qboolean Portal_VisFlood (portal_t *p);
-qboolean FloodEntities (tree_t *tree);
-void FillOutside (node_t *headnode);
-void FloodAreas (tree_t *tree);
-void MarkVisibleSides (tree_t *tree, int start, int end);
-void FreePortal (portal_t *p);
-void EmitAreaPortals (node_t *headnode);
-void MakeTreePortals (tree_t *tree);
-
-//=============================================================================
-// glfile.c
-//=============================================================================
-
-void OutputWinding(winding_t *w, FILE *glview);
-void WriteGLView(tree_t *tree, char *source);
-
-//=============================================================================
-// gldraw.c
-//=============================================================================
-
-extern vec3_t draw_mins, draw_maxs;
-extern qboolean drawflag;
-
-void Draw_ClearWindow (void);
-void DrawWinding (winding_t *w);
-void GLS_BeginScene (void);
-void GLS_Winding (winding_t *w, int code);
-void GLS_EndScene (void);
-
-//=============================================================================
-// leakfile.c
-//=============================================================================
-
-void LeakFile (tree_t *tree);
-
-//=============================================================================
-// tree.c
-//=============================================================================
-
-tree_t *Tree_Alloc(void);
-void Tree_Free(tree_t *tree);
-void Tree_Free_r(node_t *node);
-void Tree_Print_r(node_t *node, int depth);
-void Tree_FreePortals_r(node_t *node);
-void Tree_PruneNodes_r(node_t *node);
-void Tree_PruneNodes(node_t *node);
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+
+#if defined(WIN32) || defined(_WIN32)
+#include <io.h>
+#endif
+#include <malloc.h>
+#include "l_cmd.h"
+#include "l_math.h"
+#include "l_poly.h"
+#include "l_threads.h"
+#include "../botlib/l_script.h"
+#include "l_bsp_ent.h"
+#include "q2files.h"
+#include "l_mem.h"
+#include "l_utils.h"
+#include "l_log.h"
+#include "l_qfiles.h"
+
+#define BSPC_VERSION "2.1h"
+
+#define ME
+#define DEBUG
+#define NODELIST
+#define SIN
+
+#define MAX_BRUSH_SIDES 128 //maximum number of sides per brush
+#define CLIP_EPSILON 0.1
+#define MAX_MAP_BOUNDS 65535
+#define BOGUS_RANGE (MAX_MAP_BOUNDS+128) //somewhere outside the map
+#define TEXINFO_NODE -1 //side is allready on a node
+#define PLANENUM_LEAF -1 //used for leaf nodes
+#define MAXEDGES 20 //maximum number of face edges
+#define MAX_NODE_BRUSHES 8 //maximum brushes in a node
+//side flags
+#define SFL_TESTED 1
+#define SFL_VISIBLE 2
+#define SFL_BEVEL 4
+#define SFL_TEXTURED 8
+#define SFL_CURVE 16
+
+//map plane
+typedef struct plane_s
+{
+ vec3_t normal;
+ vec_t dist;
+ int type;
+ int signbits;
+ struct plane_s *hash_chain;
+} plane_t;
+//brush texture
+typedef struct
+{
+ vec_t shift[2];
+ vec_t rotate;
+ vec_t scale[2];
+ char name[32];
+ int flags;
+ int value;
+} brush_texture_t;
+//brush side
+typedef struct side_s
+{
+ int planenum; // map plane this side is in
+ int texinfo; // texture reference
+ winding_t *winding; // winding of this side
+ struct side_s *original; // bspbrush_t sides will reference the mapbrush_t sides
+ int lightinfo; // for SIN only
+ int contents; // from miptex
+ int surf; // from miptex
+ unsigned short flags; // side flags
+} side_t; //sizeof(side_t) = 36
+//map brush
+typedef struct mapbrush_s
+{
+ int entitynum;
+ int brushnum;
+
+ int contents;
+#ifdef ME
+ int expansionbbox; //bbox used for expansion of the brush
+ int leafnum;
+ int modelnum;
+#endif
+
+ vec3_t mins, maxs;
+
+ int numsides;
+ side_t *original_sides;
+} mapbrush_t;
+//bsp face
+typedef struct face_s
+{
+ struct face_s *next; // on node
+
+ // the chain of faces off of a node can be merged or split,
+ // but each face_t along the way will remain in the chain
+ // until the entire tree is freed
+ struct face_s *merged; // if set, this face isn't valid anymore
+ struct face_s *split[2]; // if set, this face isn't valid anymore
+
+ struct portal_s *portal;
+ int texinfo;
+#ifdef SIN
+ int lightinfo;
+#endif
+ int planenum;
+ int contents; // faces in different contents can't merge
+ int outputnumber;
+ winding_t *w;
+ int numpoints;
+ qboolean badstartvert; // tjunctions cannot be fixed without a midpoint vertex
+ int vertexnums[MAXEDGES];
+} face_t;
+//bsp brush
+typedef struct bspbrush_s
+{
+ struct bspbrush_s *next;
+ vec3_t mins, maxs;
+ int side, testside; // side of node during construction
+ mapbrush_t *original;
+ int numsides;
+ side_t sides[6]; // variably sized
+} bspbrush_t; //sizeof(bspbrush_t) = 44 + numsides * sizeof(side_t)
+//bsp node
+typedef struct node_s
+{
+ //both leafs and nodes
+ int planenum; // -1 = leaf node
+ struct node_s *parent;
+ vec3_t mins, maxs; // valid after portalization
+ bspbrush_t *volume; // one for each leaf/node
+
+ // nodes only
+ qboolean detail_seperator; // a detail brush caused the split
+ side_t *side; // the side that created the node
+ struct node_s *children[2];
+ face_t *faces;
+
+ // leafs only
+ bspbrush_t *brushlist; // fragments of all brushes in this leaf
+ int contents; // OR of all brush contents
+ int occupied; // 1 or greater can reach entity
+ entity_t *occupant; // for leak file testing
+ int cluster; // for portalfile writing
+ int area; // for areaportals
+ struct portal_s *portals; // also on nodes during construction
+#ifdef NODELIST
+ struct node_s *next; //next node in the nodelist
+#endif
+#ifdef ME
+ int expansionbboxes; //OR of all bboxes used for expansion of the brushes
+ int modelnum;
+#endif
+} node_t; //sizeof(node_t) = 80 bytes
+//bsp portal
+typedef struct portal_s
+{
+ plane_t plane;
+ node_t *onnode; // NULL = outside box
+ node_t *nodes[2]; // [0] = front side of plane
+ struct portal_s *next[2];
+ winding_t *winding;
+
+ qboolean sidefound; // false if ->side hasn't been checked
+ side_t *side; // NULL = non-visible
+ face_t *face[2]; // output face in bsp file
+#ifdef ME
+ struct tmp_face_s *tmpface; //pointer to the tmpface created for this portal
+ int planenum; //number of the map plane used by the portal
+#endif
+} portal_t;
+//bsp tree
+typedef struct
+{
+ node_t *headnode;
+ node_t outside_node;
+ vec3_t mins, maxs;
+} tree_t;
+
+//=============================================================================
+// bspc.c
+//=============================================================================
+
+extern qboolean noprune;
+extern qboolean nodetail;
+extern qboolean fulldetail;
+extern qboolean nomerge;
+extern qboolean nosubdiv;
+extern qboolean nowater;
+extern qboolean noweld;
+extern qboolean noshare;
+extern qboolean notjunc;
+extern qboolean onlyents;
+#ifdef ME
+extern qboolean nocsg;
+extern qboolean create_aas;
+extern qboolean freetree;
+extern qboolean lessbrushes;
+extern qboolean nobrushmerge;
+extern qboolean cancelconversion;
+extern qboolean noliquids;
+extern qboolean capsule_collision;
+#endif //ME
+
+extern float subdivide_size;
+extern vec_t microvolume;
+
+extern char outbase[32];
+extern char source[1024];
+
+//=============================================================================
+// map.c
+//=============================================================================
+
+#define MAX_MAPFILE_PLANES 256000
+#define MAX_MAPFILE_BRUSHES 65535
+#define MAX_MAPFILE_BRUSHSIDES (MAX_MAPFILE_BRUSHES*8)
+#define MAX_MAPFILE_TEXINFO 8192
+
+extern int entity_num;
+
+extern plane_t mapplanes[MAX_MAPFILE_PLANES];
+extern int nummapplanes;
+extern int mapplaneusers[MAX_MAPFILE_PLANES];
+
+extern int nummapbrushes;
+extern mapbrush_t mapbrushes[MAX_MAPFILE_BRUSHES];
+
+extern vec3_t map_mins, map_maxs;
+
+extern int nummapbrushsides;
+extern side_t brushsides[MAX_MAPFILE_BRUSHSIDES];
+extern brush_texture_t side_brushtextures[MAX_MAPFILE_BRUSHSIDES];
+
+#ifdef ME
+
+typedef struct
+{
+ float vecs[2][4]; // [s/t][xyz offset]
+ int flags; // miptex flags + overrides
+ int value;
+ char texture[64]; // texture name (textures/*.wal)
+ int nexttexinfo; // for animations, -1 = end of chain
+} map_texinfo_t;
+
+extern map_texinfo_t map_texinfo[MAX_MAPFILE_TEXINFO];
+extern int map_numtexinfo;
+#define NODESTACKSIZE 1024
+
+#define MAPTYPE_QUAKE1 1
+#define MAPTYPE_QUAKE2 2
+#define MAPTYPE_QUAKE3 3
+#define MAPTYPE_HALFLIFE 4
+#define MAPTYPE_SIN 5
+
+extern int nodestack[NODESTACKSIZE];
+extern int *nodestackptr;
+extern int nodestacksize;
+extern int brushmodelnumbers[MAX_MAPFILE_BRUSHES];
+extern int dbrushleafnums[MAX_MAPFILE_BRUSHES];
+extern int dplanes2mapplanes[MAX_MAPFILE_PLANES];
+
+extern int loadedmaptype;
+#endif //ME
+
+extern int c_boxbevels;
+extern int c_edgebevels;
+extern int c_areaportals;
+extern int c_clipbrushes;
+extern int c_squattbrushes;
+
+//finds a float plane for the given normal and distance
+int FindFloatPlane(vec3_t normal, vec_t dist);
+//returns the plane type for the given normal
+int PlaneTypeForNormal(vec3_t normal);
+//returns the plane defined by the three given points
+int PlaneFromPoints(int *p0, int *p1, int *p2);
+//add bevels to the map brush
+void AddBrushBevels(mapbrush_t *b);
+//makes brush side windings for the brush
+qboolean MakeBrushWindings(mapbrush_t *ob);
+//marks brush bevels of the brush as bevel
+void MarkBrushBevels(mapbrush_t *brush);
+//returns true if the map brush already exists
+int BrushExists(mapbrush_t *brush);
+//loads a map from a bsp file
+int LoadMapFromBSP(struct quakefile_s *qf);
+//resets map loading
+void ResetMapLoading(void);
+//print some map info
+void PrintMapInfo(void);
+//writes a map file (type depending on loaded map type)
+void WriteMapFile(char *filename);
+
+//=============================================================================
+// map_q2.c
+//=============================================================================
+
+void Q2_ResetMapLoading(void);
+//loads a Quake2 map file
+void Q2_LoadMapFile(char *filename);
+//loads a map from a Quake2 bsp file
+void Q2_LoadMapFromBSP(char *filename, int offset, int length);
+
+//=============================================================================
+// map_q1.c
+//=============================================================================
+
+void Q1_ResetMapLoading(void);
+//loads a Quake2 map file
+void Q1_LoadMapFile(char *filename);
+//loads a map from a Quake1 bsp file
+void Q1_LoadMapFromBSP(char *filename, int offset, int length);
+
+//=============================================================================
+// map_q3.c
+//=============================================================================
+void Q3_ResetMapLoading(void);
+//loads a map from a Quake3 bsp file
+void Q3_LoadMapFromBSP(struct quakefile_s *qf);
+
+//=============================================================================
+// map_sin.c
+//=============================================================================
+
+void Sin_ResetMapLoading(void);
+//loads a Sin map file
+void Sin_LoadMapFile(char *filename);
+//loads a map from a Sin bsp file
+void Sin_LoadMapFromBSP(char *filename, int offset, int length);
+
+//=============================================================================
+// map_hl.c
+//=============================================================================
+
+void HL_ResetMapLoading(void);
+//loads a Half-Life map file
+void HL_LoadMapFile(char *filename);
+//loads a map from a Half-Life bsp file
+void HL_LoadMapFromBSP(char *filename, int offset, int length);
+
+//=============================================================================
+// textures.c
+//=============================================================================
+
+typedef struct
+{
+ char name[64];
+ int flags;
+ int value;
+ int contents;
+ char animname[64];
+} textureref_t;
+
+#define MAX_MAP_TEXTURES 1024
+
+extern textureref_t textureref[MAX_MAP_TEXTURES];
+
+int FindMiptex(char *name);
+int TexinfoForBrushTexture(plane_t *plane, brush_texture_t *bt, vec3_t origin);
+void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv);
+
+//=============================================================================
+// csg
+//=============================================================================
+
+bspbrush_t *MakeBspBrushList(int startbrush, int endbrush, vec3_t clipmins, vec3_t clipmaxs);
+bspbrush_t *ChopBrushes(bspbrush_t *head);
+bspbrush_t *InitialBrushList(bspbrush_t *list);
+bspbrush_t *OptimizedBrushList(bspbrush_t *list);
+void WriteBrushMap(char *name, bspbrush_t *list);
+void CheckBSPBrush(bspbrush_t *brush);
+void BSPBrushWindings(bspbrush_t *brush);
+bspbrush_t *TryMergeBrushes(bspbrush_t *brush1, bspbrush_t *brush2);
+tree_t *ProcessWorldBrushes(int brush_start, int brush_end);
+
+//=============================================================================
+// brushbsp
+//=============================================================================
+
+#define PSIDE_FRONT 1
+#define PSIDE_BACK 2
+#define PSIDE_BOTH (PSIDE_FRONT|PSIDE_BACK)
+#define PSIDE_FACING 4
+
+void WriteBrushList(char *name, bspbrush_t *brush, qboolean onlyvis);
+bspbrush_t *CopyBrush(bspbrush_t *brush);
+void SplitBrush(bspbrush_t *brush, int planenum, bspbrush_t **front, bspbrush_t **back);
+node_t *AllocNode(void);
+bspbrush_t *AllocBrush(int numsides);
+int CountBrushList(bspbrush_t *brushes);
+void FreeBrush(bspbrush_t *brushes);
+vec_t BrushVolume(bspbrush_t *brush);
+void BoundBrush(bspbrush_t *brush);
+void FreeBrushList(bspbrush_t *brushes);
+tree_t *BrushBSP(bspbrush_t *brushlist, vec3_t mins, vec3_t maxs);
+bspbrush_t *BrushFromBounds(vec3_t mins, vec3_t maxs);
+int BrushMostlyOnSide(bspbrush_t *brush, plane_t *plane);
+qboolean WindingIsHuge(winding_t *w);
+qboolean WindingIsTiny(winding_t *w);
+void ResetBrushBSP(void);
+
+//=============================================================================
+// portals.c
+//=============================================================================
+
+int VisibleContents (int contents);
+void MakeHeadnodePortals (tree_t *tree);
+void MakeNodePortal (node_t *node);
+void SplitNodePortals (node_t *node);
+qboolean Portal_VisFlood (portal_t *p);
+qboolean FloodEntities (tree_t *tree);
+void FillOutside (node_t *headnode);
+void FloodAreas (tree_t *tree);
+void MarkVisibleSides (tree_t *tree, int start, int end);
+void FreePortal (portal_t *p);
+void EmitAreaPortals (node_t *headnode);
+void MakeTreePortals (tree_t *tree);
+
+//=============================================================================
+// glfile.c
+//=============================================================================
+
+void OutputWinding(winding_t *w, FILE *glview);
+void WriteGLView(tree_t *tree, char *source);
+
+//=============================================================================
+// gldraw.c
+//=============================================================================
+
+extern vec3_t draw_mins, draw_maxs;
+extern qboolean drawflag;
+
+void Draw_ClearWindow (void);
+void DrawWinding (winding_t *w);
+void GLS_BeginScene (void);
+void GLS_Winding (winding_t *w, int code);
+void GLS_EndScene (void);
+
+//=============================================================================
+// leakfile.c
+//=============================================================================
+
+void LeakFile (tree_t *tree);
+
+//=============================================================================
+// tree.c
+//=============================================================================
+
+tree_t *Tree_Alloc(void);
+void Tree_Free(tree_t *tree);
+void Tree_Free_r(node_t *node);
+void Tree_Print_r(node_t *node, int depth);
+void Tree_FreePortals_r(node_t *node);
+void Tree_PruneNodes_r(node_t *node);
+void Tree_PruneNodes(node_t *node);
diff --git a/code/bspc/qfiles.h b/code/bspc/qfiles.h
index 5ffea6e..317e47c 100755
--- a/code/bspc/qfiles.h
+++ b/code/bspc/qfiles.h
@@ -1,487 +1,487 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-
-//
-// qfiles.h: quake file formats
-// This file must be identical in the quake and utils directories
-//
-
-/*
-========================================================================
-
-The .pak files are just a linear collapse of a directory tree
-
-========================================================================
-*/
-
-#define IDPAKHEADER (('K'<<24)+('C'<<16)+('A'<<8)+'P')
-
-typedef struct
-{
- char name[56];
- int filepos, filelen;
-} dpackfile_t;
-
-typedef struct
-{
- int ident; // == IDPAKHEADER
- int dirofs;
- int dirlen;
-} dpackheader_t;
-
-#define MAX_FILES_IN_PACK 4096
-
-
-/*
-========================================================================
-
-PCX files are used for as many images as possible
-
-========================================================================
-*/
-
-typedef struct
-{
- char manufacturer;
- char version;
- char encoding;
- char bits_per_pixel;
- unsigned short xmin,ymin,xmax,ymax;
- unsigned short hres,vres;
- unsigned char palette[48];
- char reserved;
- char color_planes;
- unsigned short bytes_per_line;
- unsigned short palette_type;
- char filler[58];
- unsigned char data; // unbounded
-} pcx_t;
-
-
-/*
-========================================================================
-
-.MD2 triangle model file format
-
-========================================================================
-*/
-
-#define IDALIASHEADER (('2'<<24)+('P'<<16)+('D'<<8)+'I')
-#define ALIAS_VERSION 8
-
-#define MAX_TRIANGLES 4096
-#define MAX_VERTS 2048
-#define MAX_FRAMES 512
-#define MAX_MD2SKINS 32
-#define MAX_SKINNAME 64
-
-typedef struct
-{
- short s;
- short t;
-} dstvert_t;
-
-typedef struct
-{
- short index_xyz[3];
- short index_st[3];
-} dtriangle_t;
-
-typedef struct
-{
- byte v[3]; // scaled byte to fit in frame mins/maxs
- byte lightnormalindex;
-} dtrivertx_t;
-
-#define DTRIVERTX_V0 0
-#define DTRIVERTX_V1 1
-#define DTRIVERTX_V2 2
-#define DTRIVERTX_LNI 3
-#define DTRIVERTX_SIZE 4
-
-typedef struct
-{
- float scale[3]; // multiply byte verts by this
- float translate[3]; // then add this
- char name[16]; // frame name from grabbing
- dtrivertx_t verts[1]; // variable sized
-} daliasframe_t;
-
-
-// the glcmd format:
-// a positive integer starts a tristrip command, followed by that many
-// vertex structures.
-// a negative integer starts a trifan command, followed by -x vertexes
-// a zero indicates the end of the command list.
-// a vertex consists of a floating point s, a floating point t,
-// and an integer vertex index.
-
-
-typedef struct
-{
- int ident;
- int version;
-
- int skinwidth;
- int skinheight;
- int framesize; // byte size of each frame
-
- int num_skins;
- int num_xyz;
- int num_st; // greater than num_xyz for seams
- int num_tris;
- int num_glcmds; // dwords in strip/fan command list
- int num_frames;
-
- int ofs_skins; // each skin is a MAX_SKINNAME string
- int ofs_st; // byte offset from start for stverts
- int ofs_tris; // offset for dtriangles
- int ofs_frames; // offset for first frame
- int ofs_glcmds;
- int ofs_end; // end of file
-
-} dmdl_t;
-
-/*
-========================================================================
-
-.SP2 sprite file format
-
-========================================================================
-*/
-
-#define IDSPRITEHEADER (('2'<<24)+('S'<<16)+('D'<<8)+'I')
- // little-endian "IDS2"
-#define SPRITE_VERSION 2
-
-typedef struct
-{
- int width, height;
- int origin_x, origin_y; // raster coordinates inside pic
- char name[MAX_SKINNAME]; // name of pcx file
-} dsprframe_t;
-
-typedef struct {
- int ident;
- int version;
- int numframes;
- dsprframe_t frames[1]; // variable sized
-} dsprite_t;
-
-/*
-==============================================================================
-
- .WAL texture file format
-
-==============================================================================
-*/
-
-
-#define MIPLEVELS 4
-typedef struct miptex_s
-{
- char name[32];
- unsigned width, height;
- unsigned offsets[MIPLEVELS]; // four mip maps stored
- char animname[32]; // next frame in animation chain
- int flags;
- int contents;
- int value;
-} miptex_t;
-
-
-
-/*
-==============================================================================
-
- .BSP file format
-
-==============================================================================
-*/
-
-#define IDBSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I')
- // little-endian "IBSP"
-
-#define BSPVERSION 38
-
-
-// upper design bounds
-// leaffaces, leafbrushes, planes, and verts are still bounded by
-// 16 bit short limits
-#define MAX_MAP_MODELS 1024
-#define MAX_MAP_BRUSHES 8192
-#define MAX_MAP_ENTITIES 2048
-#define MAX_MAP_ENTSTRING 0x40000
-#define MAX_MAP_TEXINFO 8192
-
-#define MAX_MAP_AREAS 256
-#define MAX_MAP_AREAPORTALS 1024
-#define MAX_MAP_PLANES 65536
-#define MAX_MAP_NODES 65536
-#define MAX_MAP_BRUSHSIDES 65536
-#define MAX_MAP_LEAFS 65536
-#define MAX_MAP_VERTS 65536
-#define MAX_MAP_FACES 65536
-#define MAX_MAP_LEAFFACES 65536
-#define MAX_MAP_LEAFBRUSHES 65536
-#define MAX_MAP_PORTALS 65536
-#define MAX_MAP_EDGES 128000
-#define MAX_MAP_SURFEDGES 256000
-#define MAX_MAP_LIGHTING 0x320000
-#define MAX_MAP_VISIBILITY 0x280000
-
-// key / value pair sizes
-
-#define MAX_KEY 32
-#define MAX_VALUE 1024
-
-//=============================================================================
-
-typedef struct
-{
- int fileofs, filelen;
-} lump_t;
-
-#define LUMP_ENTITIES 0
-#define LUMP_PLANES 1
-#define LUMP_VERTEXES 2
-#define LUMP_VISIBILITY 3
-#define LUMP_NODES 4
-#define LUMP_TEXINFO 5
-#define LUMP_FACES 6
-#define LUMP_LIGHTING 7
-#define LUMP_LEAFS 8
-#define LUMP_LEAFFACES 9
-#define LUMP_LEAFBRUSHES 10
-#define LUMP_EDGES 11
-#define LUMP_SURFEDGES 12
-#define LUMP_MODELS 13
-#define LUMP_BRUSHES 14
-#define LUMP_BRUSHSIDES 15
-#define LUMP_POP 16
-#define LUMP_AREAS 17
-#define LUMP_AREAPORTALS 18
-#define HEADER_LUMPS 19
-
-typedef struct
-{
- int ident;
- int version;
- lump_t lumps[HEADER_LUMPS];
-} dheader_t;
-
-typedef struct
-{
- float mins[3], maxs[3];
- float origin[3]; // for sounds or lights
- int headnode;
- int firstface, numfaces; // submodels just draw faces
- // without walking the bsp tree
-} dmodel_t;
-
-
-typedef struct
-{
- float point[3];
-} dvertex_t;
-
-
-// 0-2 are axial planes
-#define PLANE_X 0
-#define PLANE_Y 1
-#define PLANE_Z 2
-
-// 3-5 are non-axial planes snapped to the nearest
-#define PLANE_ANYX 3
-#define PLANE_ANYY 4
-#define PLANE_ANYZ 5
-
-// planes (x&~1) and (x&~1)+1 are allways opposites
-
-typedef struct
-{
- float normal[3];
- float dist;
- int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
-} dplane_t;
-
-
-// contents flags are seperate bits
-// a given brush can contribute multiple content bits
-// multiple brushes can be in a single leaf
-
-// these definitions also need to be in q_shared.h!
-
-// lower bits are stronger, and will eat weaker brushes completely
-#define CONTENTS_SOLID 1 // an eye is never valid in a solid
-#define CONTENTS_WINDOW 2 // translucent, but not watery
-#define CONTENTS_AUX 4
-#define CONTENTS_LAVA 8
-#define CONTENTS_SLIME 16
-#define CONTENTS_WATER 32
-#define CONTENTS_MIST 64
-#define LAST_VISIBLE_CONTENTS 64
-
-// remaining contents are non-visible, and don't eat brushes
-
-#define CONTENTS_AREAPORTAL 0x8000
-
-#define CONTENTS_PLAYERCLIP 0x10000
-#define CONTENTS_MONSTERCLIP 0x20000
-
-// currents can be added to any other contents, and may be mixed
-#define CONTENTS_CURRENT_0 0x40000
-#define CONTENTS_CURRENT_90 0x80000
-#define CONTENTS_CURRENT_180 0x100000
-#define CONTENTS_CURRENT_270 0x200000
-#define CONTENTS_CURRENT_UP 0x400000
-#define CONTENTS_CURRENT_DOWN 0x800000
-
-#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity
-
-#define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game
-#define CONTENTS_DEADMONSTER 0x4000000
-#define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs
-//renamed because it's in conflict with the Q3A translucent contents
-#define CONTENTS_Q2TRANSLUCENT 0x10000000 // auto set if any surface has trans
-#define CONTENTS_LADDER 0x20000000
-
-
-
-#define SURF_LIGHT 0x1 // value will hold the light strength
-
-#define SURF_SLICK 0x2 // effects game physics
-
-#define SURF_SKY 0x4 // don't draw, but add to skybox
-#define SURF_WARP 0x8 // turbulent water warp
-#define SURF_TRANS33 0x10
-#define SURF_TRANS66 0x20
-#define SURF_FLOWING 0x40 // scroll towards angle
-#define SURF_NODRAW 0x80 // don't bother referencing the texture
-
-#define SURF_HINT 0x100 // make a primary bsp splitter
-#define SURF_SKIP 0x200 // completely ignore, allowing non-closed brushes
-
-
-
-typedef struct
-{
- int planenum;
- int children[2]; // negative numbers are -(leafs+1), not nodes
- short mins[3]; // for frustom culling
- short maxs[3];
- unsigned short firstface;
- unsigned short numfaces; // counting both sides
-} dnode_t;
-
-
-typedef struct texinfo_s
-{
- float vecs[2][4]; // [s/t][xyz offset]
- int flags; // miptex flags + overrides
- int value; // light emission, etc
- char texture[32]; // texture name (textures/*.wal)
- int nexttexinfo; // for animations, -1 = end of chain
-} texinfo_t;
-
-
-// note that edge 0 is never used, because negative edge nums are used for
-// counterclockwise use of the edge in a face
-typedef struct
-{
- unsigned short v[2]; // vertex numbers
-} dedge_t;
-
-#define MAXLIGHTMAPS 4
-typedef struct
-{
- unsigned short planenum;
- short side;
-
- int firstedge; // we must support > 64k edges
- short numedges;
- short texinfo;
-
-// lighting info
- byte styles[MAXLIGHTMAPS];
- int lightofs; // start of [numstyles*surfsize] samples
-} dface_t;
-
-typedef struct
-{
- int contents; // OR of all brushes (not needed?)
-
- short cluster;
- short area;
-
- short mins[3]; // for frustum culling
- short maxs[3];
-
- unsigned short firstleafface;
- unsigned short numleaffaces;
-
- unsigned short firstleafbrush;
- unsigned short numleafbrushes;
-} dleaf_t;
-
-typedef struct
-{
- unsigned short planenum; // facing out of the leaf
- short texinfo;
-} dbrushside_t;
-
-typedef struct
-{
- int firstside;
- int numsides;
- int contents;
-} dbrush_t;
-
-#define ANGLE_UP -1
-#define ANGLE_DOWN -2
-
-
-// the visibility lump consists of a header with a count, then
-// byte offsets for the PVS and PHS of each cluster, then the raw
-// compressed bit vectors
-#define DVIS_PVS 0
-#define DVIS_PHS 1
-typedef struct
-{
- int numclusters;
- int bitofs[8][2]; // bitofs[numclusters][2]
-} dvis_t;
-
-// each area has a list of portals that lead into other areas
-// when portals are closed, other areas may not be visible or
-// hearable even if the vis info says that it should be
-typedef struct
-{
- int portalnum;
- int otherarea;
-} dareaportal_t;
-
-typedef struct
-{
- int numareaportals;
- int firstareaportal;
-} darea_t;
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+//
+// qfiles.h: quake file formats
+// This file must be identical in the quake and utils directories
+//
+
+/*
+========================================================================
+
+The .pak files are just a linear collapse of a directory tree
+
+========================================================================
+*/
+
+#define IDPAKHEADER (('K'<<24)+('C'<<16)+('A'<<8)+'P')
+
+typedef struct
+{
+ char name[56];
+ int filepos, filelen;
+} dpackfile_t;
+
+typedef struct
+{
+ int ident; // == IDPAKHEADER
+ int dirofs;
+ int dirlen;
+} dpackheader_t;
+
+#define MAX_FILES_IN_PACK 4096
+
+
+/*
+========================================================================
+
+PCX files are used for as many images as possible
+
+========================================================================
+*/
+
+typedef struct
+{
+ char manufacturer;
+ char version;
+ char encoding;
+ char bits_per_pixel;
+ unsigned short xmin,ymin,xmax,ymax;
+ unsigned short hres,vres;
+ unsigned char palette[48];
+ char reserved;
+ char color_planes;
+ unsigned short bytes_per_line;
+ unsigned short palette_type;
+ char filler[58];
+ unsigned char data; // unbounded
+} pcx_t;
+
+
+/*
+========================================================================
+
+.MD2 triangle model file format
+
+========================================================================
+*/
+
+#define IDALIASHEADER (('2'<<24)+('P'<<16)+('D'<<8)+'I')
+#define ALIAS_VERSION 8
+
+#define MAX_TRIANGLES 4096
+#define MAX_VERTS 2048
+#define MAX_FRAMES 512
+#define MAX_MD2SKINS 32
+#define MAX_SKINNAME 64
+
+typedef struct
+{
+ short s;
+ short t;
+} dstvert_t;
+
+typedef struct
+{
+ short index_xyz[3];
+ short index_st[3];
+} dtriangle_t;
+
+typedef struct
+{
+ byte v[3]; // scaled byte to fit in frame mins/maxs
+ byte lightnormalindex;
+} dtrivertx_t;
+
+#define DTRIVERTX_V0 0
+#define DTRIVERTX_V1 1
+#define DTRIVERTX_V2 2
+#define DTRIVERTX_LNI 3
+#define DTRIVERTX_SIZE 4
+
+typedef struct
+{
+ float scale[3]; // multiply byte verts by this
+ float translate[3]; // then add this
+ char name[16]; // frame name from grabbing
+ dtrivertx_t verts[1]; // variable sized
+} daliasframe_t;
+
+
+// the glcmd format:
+// a positive integer starts a tristrip command, followed by that many
+// vertex structures.
+// a negative integer starts a trifan command, followed by -x vertexes
+// a zero indicates the end of the command list.
+// a vertex consists of a floating point s, a floating point t,
+// and an integer vertex index.
+
+
+typedef struct
+{
+ int ident;
+ int version;
+
+ int skinwidth;
+ int skinheight;
+ int framesize; // byte size of each frame
+
+ int num_skins;
+ int num_xyz;
+ int num_st; // greater than num_xyz for seams
+ int num_tris;
+ int num_glcmds; // dwords in strip/fan command list
+ int num_frames;
+
+ int ofs_skins; // each skin is a MAX_SKINNAME string
+ int ofs_st; // byte offset from start for stverts
+ int ofs_tris; // offset for dtriangles
+ int ofs_frames; // offset for first frame
+ int ofs_glcmds;
+ int ofs_end; // end of file
+
+} dmdl_t;
+
+/*
+========================================================================
+
+.SP2 sprite file format
+
+========================================================================
+*/
+
+#define IDSPRITEHEADER (('2'<<24)+('S'<<16)+('D'<<8)+'I')
+ // little-endian "IDS2"
+#define SPRITE_VERSION 2
+
+typedef struct
+{
+ int width, height;
+ int origin_x, origin_y; // raster coordinates inside pic
+ char name[MAX_SKINNAME]; // name of pcx file
+} dsprframe_t;
+
+typedef struct {
+ int ident;
+ int version;
+ int numframes;
+ dsprframe_t frames[1]; // variable sized
+} dsprite_t;
+
+/*
+==============================================================================
+
+ .WAL texture file format
+
+==============================================================================
+*/
+
+
+#define MIPLEVELS 4
+typedef struct miptex_s
+{
+ char name[32];
+ unsigned width, height;
+ unsigned offsets[MIPLEVELS]; // four mip maps stored
+ char animname[32]; // next frame in animation chain
+ int flags;
+ int contents;
+ int value;
+} miptex_t;
+
+
+
+/*
+==============================================================================
+
+ .BSP file format
+
+==============================================================================
+*/
+
+#define IDBSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I')
+ // little-endian "IBSP"
+
+#define BSPVERSION 38
+
+
+// upper design bounds
+// leaffaces, leafbrushes, planes, and verts are still bounded by
+// 16 bit short limits
+#define MAX_MAP_MODELS 1024
+#define MAX_MAP_BRUSHES 8192
+#define MAX_MAP_ENTITIES 2048
+#define MAX_MAP_ENTSTRING 0x40000
+#define MAX_MAP_TEXINFO 8192
+
+#define MAX_MAP_AREAS 256
+#define MAX_MAP_AREAPORTALS 1024
+#define MAX_MAP_PLANES 65536
+#define MAX_MAP_NODES 65536
+#define MAX_MAP_BRUSHSIDES 65536
+#define MAX_MAP_LEAFS 65536
+#define MAX_MAP_VERTS 65536
+#define MAX_MAP_FACES 65536
+#define MAX_MAP_LEAFFACES 65536
+#define MAX_MAP_LEAFBRUSHES 65536
+#define MAX_MAP_PORTALS 65536
+#define MAX_MAP_EDGES 128000
+#define MAX_MAP_SURFEDGES 256000
+#define MAX_MAP_LIGHTING 0x320000
+#define MAX_MAP_VISIBILITY 0x280000
+
+// key / value pair sizes
+
+#define MAX_KEY 32
+#define MAX_VALUE 1024
+
+//=============================================================================
+
+typedef struct
+{
+ int fileofs, filelen;
+} lump_t;
+
+#define LUMP_ENTITIES 0
+#define LUMP_PLANES 1
+#define LUMP_VERTEXES 2
+#define LUMP_VISIBILITY 3
+#define LUMP_NODES 4
+#define LUMP_TEXINFO 5
+#define LUMP_FACES 6
+#define LUMP_LIGHTING 7
+#define LUMP_LEAFS 8
+#define LUMP_LEAFFACES 9
+#define LUMP_LEAFBRUSHES 10
+#define LUMP_EDGES 11
+#define LUMP_SURFEDGES 12
+#define LUMP_MODELS 13
+#define LUMP_BRUSHES 14
+#define LUMP_BRUSHSIDES 15
+#define LUMP_POP 16
+#define LUMP_AREAS 17
+#define LUMP_AREAPORTALS 18
+#define HEADER_LUMPS 19
+
+typedef struct
+{
+ int ident;
+ int version;
+ lump_t lumps[HEADER_LUMPS];
+} dheader_t;
+
+typedef struct
+{
+ float mins[3], maxs[3];
+ float origin[3]; // for sounds or lights
+ int headnode;
+ int firstface, numfaces; // submodels just draw faces
+ // without walking the bsp tree
+} dmodel_t;
+
+
+typedef struct
+{
+ float point[3];
+} dvertex_t;
+
+
+// 0-2 are axial planes
+#define PLANE_X 0
+#define PLANE_Y 1
+#define PLANE_Z 2
+
+// 3-5 are non-axial planes snapped to the nearest
+#define PLANE_ANYX 3
+#define PLANE_ANYY 4
+#define PLANE_ANYZ 5
+
+// planes (x&~1) and (x&~1)+1 are allways opposites
+
+typedef struct
+{
+ float normal[3];
+ float dist;
+ int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
+} dplane_t;
+
+
+// contents flags are seperate bits
+// a given brush can contribute multiple content bits
+// multiple brushes can be in a single leaf
+
+// these definitions also need to be in q_shared.h!
+
+// lower bits are stronger, and will eat weaker brushes completely
+#define CONTENTS_SOLID 1 // an eye is never valid in a solid
+#define CONTENTS_WINDOW 2 // translucent, but not watery
+#define CONTENTS_AUX 4
+#define CONTENTS_LAVA 8
+#define CONTENTS_SLIME 16
+#define CONTENTS_WATER 32
+#define CONTENTS_MIST 64
+#define LAST_VISIBLE_CONTENTS 64
+
+// remaining contents are non-visible, and don't eat brushes
+
+#define CONTENTS_AREAPORTAL 0x8000
+
+#define CONTENTS_PLAYERCLIP 0x10000
+#define CONTENTS_MONSTERCLIP 0x20000
+
+// currents can be added to any other contents, and may be mixed
+#define CONTENTS_CURRENT_0 0x40000
+#define CONTENTS_CURRENT_90 0x80000
+#define CONTENTS_CURRENT_180 0x100000
+#define CONTENTS_CURRENT_270 0x200000
+#define CONTENTS_CURRENT_UP 0x400000
+#define CONTENTS_CURRENT_DOWN 0x800000
+
+#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity
+
+#define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game
+#define CONTENTS_DEADMONSTER 0x4000000
+#define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs
+//renamed because it's in conflict with the Q3A translucent contents
+#define CONTENTS_Q2TRANSLUCENT 0x10000000 // auto set if any surface has trans
+#define CONTENTS_LADDER 0x20000000
+
+
+
+#define SURF_LIGHT 0x1 // value will hold the light strength
+
+#define SURF_SLICK 0x2 // effects game physics
+
+#define SURF_SKY 0x4 // don't draw, but add to skybox
+#define SURF_WARP 0x8 // turbulent water warp
+#define SURF_TRANS33 0x10
+#define SURF_TRANS66 0x20
+#define SURF_FLOWING 0x40 // scroll towards angle
+#define SURF_NODRAW 0x80 // don't bother referencing the texture
+
+#define SURF_HINT 0x100 // make a primary bsp splitter
+#define SURF_SKIP 0x200 // completely ignore, allowing non-closed brushes
+
+
+
+typedef struct
+{
+ int planenum;
+ int children[2]; // negative numbers are -(leafs+1), not nodes
+ short mins[3]; // for frustom culling
+ short maxs[3];
+ unsigned short firstface;
+ unsigned short numfaces; // counting both sides
+} dnode_t;
+
+
+typedef struct texinfo_s
+{
+ float vecs[2][4]; // [s/t][xyz offset]
+ int flags; // miptex flags + overrides
+ int value; // light emission, etc
+ char texture[32]; // texture name (textures/*.wal)
+ int nexttexinfo; // for animations, -1 = end of chain
+} texinfo_t;
+
+
+// note that edge 0 is never used, because negative edge nums are used for
+// counterclockwise use of the edge in a face
+typedef struct
+{
+ unsigned short v[2]; // vertex numbers
+} dedge_t;
+
+#define MAXLIGHTMAPS 4
+typedef struct
+{
+ unsigned short planenum;
+ short side;
+
+ int firstedge; // we must support > 64k edges
+ short numedges;
+ short texinfo;
+
+// lighting info
+ byte styles[MAXLIGHTMAPS];
+ int lightofs; // start of [numstyles*surfsize] samples
+} dface_t;
+
+typedef struct
+{
+ int contents; // OR of all brushes (not needed?)
+
+ short cluster;
+ short area;
+
+ short mins[3]; // for frustum culling
+ short maxs[3];
+
+ unsigned short firstleafface;
+ unsigned short numleaffaces;
+
+ unsigned short firstleafbrush;
+ unsigned short numleafbrushes;
+} dleaf_t;
+
+typedef struct
+{
+ unsigned short planenum; // facing out of the leaf
+ short texinfo;
+} dbrushside_t;
+
+typedef struct
+{
+ int firstside;
+ int numsides;
+ int contents;
+} dbrush_t;
+
+#define ANGLE_UP -1
+#define ANGLE_DOWN -2
+
+
+// the visibility lump consists of a header with a count, then
+// byte offsets for the PVS and PHS of each cluster, then the raw
+// compressed bit vectors
+#define DVIS_PVS 0
+#define DVIS_PHS 1
+typedef struct
+{
+ int numclusters;
+ int bitofs[8][2]; // bitofs[numclusters][2]
+} dvis_t;
+
+// each area has a list of portals that lead into other areas
+// when portals are closed, other areas may not be visible or
+// hearable even if the vis info says that it should be
+typedef struct
+{
+ int portalnum;
+ int otherarea;
+} dareaportal_t;
+
+typedef struct
+{
+ int numareaportals;
+ int firstareaportal;
+} darea_t;
diff --git a/code/bspc/sinfiles.h b/code/bspc/sinfiles.h
index 31091c5..bcb5ee6 100755
--- a/code/bspc/sinfiles.h
+++ b/code/bspc/sinfiles.h
@@ -1,365 +1,365 @@
-/*
-===========================================================================
-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
-===========================================================================
-*/
-
-/*
-==============================================================================
-
- .BSP file format
-
-==============================================================================
-*/
-
-#define SIN
-
-#define SINBSPVERSION 41
-
-// upper design bounds
-// leaffaces, leafbrushes, planes, and verts are still bounded by
-// 16 bit short limits
-#define SIN_MAX_MAP_MODELS 1024
-#define SIN_MAX_MAP_BRUSHES 8192
-#define SIN_MAX_MAP_ENTITIES 2048
-#define SIN_MAX_MAP_ENTSTRING 0x40000
-#define SIN_MAX_MAP_TEXINFO 8192
-
-#define SIN_MAX_MAP_AREAS 256
-#define SIN_MAX_MAP_AREAPORTALS 1024
-#define SIN_MAX_MAP_PLANES 65536
-#define SIN_MAX_MAP_NODES 65536
-#define SIN_MAX_MAP_BRUSHSIDES 65536
-#define SIN_MAX_MAP_LEAFS 65536
-#define SIN_MAX_MAP_VERTS 65536
-#define SIN_MAX_MAP_FACES 65536
-#define SIN_MAX_MAP_LEAFFACES 65536
-#define SIN_MAX_MAP_LEAFBRUSHES 65536
-#define SIN_MAX_MAP_PORTALS 65536
-#define SIN_MAX_MAP_EDGES 128000
-#define SIN_MAX_MAP_SURFEDGES 256000
-#define SIN_MAX_MAP_LIGHTING 0x320000
-#define SIN_MAX_MAP_VISIBILITY 0x280000
-
-#ifdef SIN
-#define SIN_MAX_MAP_LIGHTINFO 8192
-#endif
-
-#ifdef SIN
-#undef SIN_MAX_MAP_LIGHTING //undef the Quake2 bsp version
-#define SIN_MAX_MAP_LIGHTING 0x300000
-#endif
-
-#ifdef SIN
-#undef SIN_MAX_MAP_VISIBILITY //undef the Quake2 bsp version
-#define SIN_MAX_MAP_VISIBILITY 0x280000
-#endif
-
-//=============================================================================
-
-typedef struct
-{
- int fileofs, filelen;
-} sin_lump_t;
-
-#define SIN_LUMP_ENTITIES 0
-#define SIN_LUMP_PLANES 1
-#define SIN_LUMP_VERTEXES 2
-#define SIN_LUMP_VISIBILITY 3
-#define SIN_LUMP_NODES 4
-#define SIN_LUMP_TEXINFO 5
-#define SIN_LUMP_FACES 6
-#define SIN_LUMP_LIGHTING 7
-#define SIN_LUMP_LEAFS 8
-#define SIN_LUMP_LEAFFACES 9
-#define SIN_LUMP_LEAFBRUSHES 10
-#define SIN_LUMP_EDGES 11
-#define SIN_LUMP_SURFEDGES 12
-#define SIN_LUMP_MODELS 13
-#define SIN_LUMP_BRUSHES 14
-#define SIN_LUMP_BRUSHSIDES 15
-#define SIN_LUMP_POP 16
-#define SIN_LUMP_AREAS 17
-#define SIN_LUMP_AREAPORTALS 18
-
-#ifdef SIN
-#define SIN_LUMP_LIGHTINFO 19
-#define SINHEADER_LUMPS 20
-#endif
-
-typedef struct
-{
- int ident;
- int version;
- sin_lump_t lumps[SINHEADER_LUMPS];
-} sin_dheader_t;
-
-typedef struct
-{
- float mins[3], maxs[3];
- float origin[3]; // for sounds or lights
- int headnode;
- int firstface, numfaces; // submodels just draw faces
- // without walking the bsp tree
-} sin_dmodel_t;
-
-typedef struct
-{
- float point[3];
-} sin_dvertex_t;
-
-
-// 0-2 are axial planes
-#define PLANE_X 0
-#define PLANE_Y 1
-#define PLANE_Z 2
-
-// 3-5 are non-axial planes snapped to the nearest
-#define PLANE_ANYX 3
-#define PLANE_ANYY 4
-#define PLANE_ANYZ 5
-
-// planes (x&~1) and (x&~1)+1 are allways opposites
-
-typedef struct
-{
- float normal[3];
- float dist;
- int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
-} sin_dplane_t;
-
-
-// contents flags are seperate bits
-// a given brush can contribute multiple content bits
-// multiple brushes can be in a single leaf
-
-// these definitions also need to be in q_shared.h!
-
-// lower bits are stronger, and will eat weaker brushes completely
-#ifdef SIN
-#define CONTENTS_FENCE 4
-#endif
-// remaining contents are non-visible, and don't eat brushes
-
-#ifdef SIN
-#define CONTENTS_DUMMYFENCE 0x1000
-#endif
-
-#ifdef SIN
-#define SURF_MASKED 0x2 // surface texture is masked
-#endif
-
-#define SURF_SKY 0x4 // don't draw, but add to skybox
-#define SURF_WARP 0x8 // turbulent water warp
-
-#ifdef SIN
-#define SURF_NONLIT 0x10 // surface is not lit
-#define SURF_NOFILTER 0x20 // surface is not bi-linear filtered
-#endif
-
-#define SURF_FLOWING 0x40 // scroll towards angle
-#define SURF_NODRAW 0x80 // don't bother referencing the texture
-
-#define SURF_HINT 0x100 // make a primary bsp splitter
-#define SURF_SKIP 0x200 // completely ignore, allowing non-closed brushes
-
-#ifdef SIN
-#define SURF_CONVEYOR 0x40 // surface is not lit
-#endif
-
-#ifdef SIN
-#define SURF_WAVY 0x400 // surface has waves
-#define SURF_RICOCHET 0x800 // projectiles bounce literally bounce off this surface
-#define SURF_PRELIT 0x1000 // surface has intensity information for pre-lighting
-#define SURF_MIRROR 0x2000 // surface is a mirror
-#define SURF_CONSOLE 0x4000 // surface is a console
-#define SURF_USECOLOR 0x8000 // surface is lit with non-lit * color
-#define SURF_HARDWAREONLY 0x10000 // surface has been damaged
-#define SURF_DAMAGE 0x20000 // surface can be damaged
-#define SURF_WEAK 0x40000 // surface has weak hit points
-#define SURF_NORMAL 0x80000 // surface has normal hit points
-#define SURF_ADD 0x100000 // surface will be additive
-#define SURF_ENVMAPPED 0x200000 // surface is envmapped
-#define SURF_RANDOMANIMATE 0x400000 // surface start animating on a random frame
-#define SURF_ANIMATE 0x800000 // surface animates
-#define SURF_RNDTIME 0x1000000 // time between animations is random
-#define SURF_TRANSLATE 0x2000000 // surface translates
-#define SURF_NOMERGE 0x4000000 // surface is not merged in csg phase
-#define SURF_TYPE_BIT0 0x8000000 // 0 bit of surface type
-#define SURF_TYPE_BIT1 0x10000000 // 1 bit of surface type
-#define SURF_TYPE_BIT2 0x20000000 // 2 bit of surface type
-#define SURF_TYPE_BIT3 0x40000000 // 3 bit of surface type
-
-#define SURF_START_BIT 27
-#define SURFACETYPE_FROM_FLAGS( x ) ( ( x >> (SURF_START_BIT) ) & 0xf )
-
-
-#define SURF_TYPE_SHIFT(x) ( (x) << (SURF_START_BIT) ) // macro for getting proper bit mask
-
-#define SURF_TYPE_NONE SURF_TYPE_SHIFT(0)
-#define SURF_TYPE_WOOD SURF_TYPE_SHIFT(1)
-#define SURF_TYPE_METAL SURF_TYPE_SHIFT(2)
-#define SURF_TYPE_STONE SURF_TYPE_SHIFT(3)
-#define SURF_TYPE_CONCRETE SURF_TYPE_SHIFT(4)
-#define SURF_TYPE_DIRT SURF_TYPE_SHIFT(5)
-#define SURF_TYPE_FLESH SURF_TYPE_SHIFT(6)
-#define SURF_TYPE_GRILL SURF_TYPE_SHIFT(7)
-#define SURF_TYPE_GLASS SURF_TYPE_SHIFT(8)
-#define SURF_TYPE_FABRIC SURF_TYPE_SHIFT(9)
-#define SURF_TYPE_MONITOR SURF_TYPE_SHIFT(10)
-#define SURF_TYPE_GRAVEL SURF_TYPE_SHIFT(11)
-#define SURF_TYPE_VEGETATION SURF_TYPE_SHIFT(12)
-#define SURF_TYPE_PAPER SURF_TYPE_SHIFT(13)
-#define SURF_TYPE_DUCT SURF_TYPE_SHIFT(14)
-#define SURF_TYPE_WATER SURF_TYPE_SHIFT(15)
-#endif
-
-
-typedef struct
-{
- int planenum;
- int children[2]; // negative numbers are -(leafs+1), not nodes
- short mins[3]; // for frustom culling
- short maxs[3];
- unsigned short firstface;
- unsigned short numfaces; // counting both sides
-} sin_dnode_t;
-
-#ifdef SIN
-
-typedef struct sin_lightvalue_s
-{
- int value; // light emission, etc
- vec3_t color;
- float direct;
- float directangle;
- float directstyle;
- char directstylename[32];
-} sin_lightvalue_t;
-
-typedef struct sin_texinfo_s
-{
- float vecs[2][4]; // [s/t][xyz offset]
- int flags; // miptex flags + overrides
- char texture[64]; // texture name (textures/*.wal)
- int nexttexinfo; // for animations, -1 = end of chain
- float trans_mag;
- int trans_angle;
- int base_angle;
- float animtime;
- float nonlit;
- float translucence;
- float friction;
- float restitution;
- vec3_t color;
- char groupname[32];
-} sin_texinfo_t;
-
-#endif //SIN
-
-// note that edge 0 is never used, because negative edge nums are used for
-// counterclockwise use of the edge in a face
-typedef struct
-{
- unsigned short v[2]; // vertex numbers
-} sin_dedge_t;
-
-#ifdef MAXLIGHTMAPS
-#undef MAXLIGHTMAPS
-#endif
-#define MAXLIGHTMAPS 16
-typedef struct
-{
- unsigned short planenum;
- short side;
-
- int firstedge; // we must support > 64k edges
- short numedges;
- short texinfo;
-
-// lighting info
- byte styles[MAXLIGHTMAPS];
- int lightofs; // start of [numstyles*surfsize] samples
-#ifdef SIN
- int lightinfo;
-#endif
-} sin_dface_t;
-
-typedef struct
-{
- int contents; // OR of all brushes (not needed?)
-
- short cluster;
- short area;
-
- short mins[3]; // for frustum culling
- short maxs[3];
-
- unsigned short firstleafface;
- unsigned short numleaffaces;
-
- unsigned short firstleafbrush;
- unsigned short numleafbrushes;
-} sin_dleaf_t;
-
-typedef struct
-{
- unsigned short planenum; // facing out of the leaf
- short texinfo;
-#ifdef SIN
- int lightinfo;
-#endif
-} sin_dbrushside_t;
-
-typedef struct
-{
- int firstside;
- int numsides;
- int contents;
-} sin_dbrush_t;
-
-#define ANGLE_UP -1
-#define ANGLE_DOWN -2
-
-
-// the visibility lump consists of a header with a count, then
-// byte offsets for the PVS and PHS of each cluster, then the raw
-// compressed bit vectors
-#define DVIS_PVS 0
-#define DVIS_PHS 1
-typedef struct
-{
- int numclusters;
- int bitofs[8][2]; // bitofs[numclusters][2]
-} sin_dvis_t;
-
-// each area has a list of portals that lead into other areas
-// when portals are closed, other areas may not be visible or
-// hearable even if the vis info says that it should be
-typedef struct
-{
- int portalnum;
- int otherarea;
-} sin_dareaportal_t;
-
-typedef struct
-{
- int numareaportals;
- int firstareaportal;
-} sin_darea_t;
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+/*
+==============================================================================
+
+ .BSP file format
+
+==============================================================================
+*/
+
+#define SIN
+
+#define SINBSPVERSION 41
+
+// upper design bounds
+// leaffaces, leafbrushes, planes, and verts are still bounded by
+// 16 bit short limits
+#define SIN_MAX_MAP_MODELS 1024
+#define SIN_MAX_MAP_BRUSHES 8192
+#define SIN_MAX_MAP_ENTITIES 2048
+#define SIN_MAX_MAP_ENTSTRING 0x40000
+#define SIN_MAX_MAP_TEXINFO 8192
+
+#define SIN_MAX_MAP_AREAS 256
+#define SIN_MAX_MAP_AREAPORTALS 1024
+#define SIN_MAX_MAP_PLANES 65536
+#define SIN_MAX_MAP_NODES 65536
+#define SIN_MAX_MAP_BRUSHSIDES 65536
+#define SIN_MAX_MAP_LEAFS 65536
+#define SIN_MAX_MAP_VERTS 65536
+#define SIN_MAX_MAP_FACES 65536
+#define SIN_MAX_MAP_LEAFFACES 65536
+#define SIN_MAX_MAP_LEAFBRUSHES 65536
+#define SIN_MAX_MAP_PORTALS 65536
+#define SIN_MAX_MAP_EDGES 128000
+#define SIN_MAX_MAP_SURFEDGES 256000
+#define SIN_MAX_MAP_LIGHTING 0x320000
+#define SIN_MAX_MAP_VISIBILITY 0x280000
+
+#ifdef SIN
+#define SIN_MAX_MAP_LIGHTINFO 8192
+#endif
+
+#ifdef SIN
+#undef SIN_MAX_MAP_LIGHTING //undef the Quake2 bsp version
+#define SIN_MAX_MAP_LIGHTING 0x300000
+#endif
+
+#ifdef SIN
+#undef SIN_MAX_MAP_VISIBILITY //undef the Quake2 bsp version
+#define SIN_MAX_MAP_VISIBILITY 0x280000
+#endif
+
+//=============================================================================
+
+typedef struct
+{
+ int fileofs, filelen;
+} sin_lump_t;
+
+#define SIN_LUMP_ENTITIES 0
+#define SIN_LUMP_PLANES 1
+#define SIN_LUMP_VERTEXES 2
+#define SIN_LUMP_VISIBILITY 3
+#define SIN_LUMP_NODES 4
+#define SIN_LUMP_TEXINFO 5
+#define SIN_LUMP_FACES 6
+#define SIN_LUMP_LIGHTING 7
+#define SIN_LUMP_LEAFS 8
+#define SIN_LUMP_LEAFFACES 9
+#define SIN_LUMP_LEAFBRUSHES 10
+#define SIN_LUMP_EDGES 11
+#define SIN_LUMP_SURFEDGES 12
+#define SIN_LUMP_MODELS 13
+#define SIN_LUMP_BRUSHES 14
+#define SIN_LUMP_BRUSHSIDES 15
+#define SIN_LUMP_POP 16
+#define SIN_LUMP_AREAS 17
+#define SIN_LUMP_AREAPORTALS 18
+
+#ifdef SIN
+#define SIN_LUMP_LIGHTINFO 19
+#define SINHEADER_LUMPS 20
+#endif
+
+typedef struct
+{
+ int ident;
+ int version;
+ sin_lump_t lumps[SINHEADER_LUMPS];
+} sin_dheader_t;
+
+typedef struct
+{
+ float mins[3], maxs[3];
+ float origin[3]; // for sounds or lights
+ int headnode;
+ int firstface, numfaces; // submodels just draw faces
+ // without walking the bsp tree
+} sin_dmodel_t;
+
+typedef struct
+{
+ float point[3];
+} sin_dvertex_t;
+
+
+// 0-2 are axial planes
+#define PLANE_X 0
+#define PLANE_Y 1
+#define PLANE_Z 2
+
+// 3-5 are non-axial planes snapped to the nearest
+#define PLANE_ANYX 3
+#define PLANE_ANYY 4
+#define PLANE_ANYZ 5
+
+// planes (x&~1) and (x&~1)+1 are allways opposites
+
+typedef struct
+{
+ float normal[3];
+ float dist;
+ int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
+} sin_dplane_t;
+
+
+// contents flags are seperate bits
+// a given brush can contribute multiple content bits
+// multiple brushes can be in a single leaf
+
+// these definitions also need to be in q_shared.h!
+
+// lower bits are stronger, and will eat weaker brushes completely
+#ifdef SIN
+#define CONTENTS_FENCE 4
+#endif
+// remaining contents are non-visible, and don't eat brushes
+
+#ifdef SIN
+#define CONTENTS_DUMMYFENCE 0x1000
+#endif
+
+#ifdef SIN
+#define SURF_MASKED 0x2 // surface texture is masked
+#endif
+
+#define SURF_SKY 0x4 // don't draw, but add to skybox
+#define SURF_WARP 0x8 // turbulent water warp
+
+#ifdef SIN
+#define SURF_NONLIT 0x10 // surface is not lit
+#define SURF_NOFILTER 0x20 // surface is not bi-linear filtered
+#endif
+
+#define SURF_FLOWING 0x40 // scroll towards angle
+#define SURF_NODRAW 0x80 // don't bother referencing the texture
+
+#define SURF_HINT 0x100 // make a primary bsp splitter
+#define SURF_SKIP 0x200 // completely ignore, allowing non-closed brushes
+
+#ifdef SIN
+#define SURF_CONVEYOR 0x40 // surface is not lit
+#endif
+
+#ifdef SIN
+#define SURF_WAVY 0x400 // surface has waves
+#define SURF_RICOCHET 0x800 // projectiles bounce literally bounce off this surface
+#define SURF_PRELIT 0x1000 // surface has intensity information for pre-lighting
+#define SURF_MIRROR 0x2000 // surface is a mirror
+#define SURF_CONSOLE 0x4000 // surface is a console
+#define SURF_USECOLOR 0x8000 // surface is lit with non-lit * color
+#define SURF_HARDWAREONLY 0x10000 // surface has been damaged
+#define SURF_DAMAGE 0x20000 // surface can be damaged
+#define SURF_WEAK 0x40000 // surface has weak hit points
+#define SURF_NORMAL 0x80000 // surface has normal hit points
+#define SURF_ADD 0x100000 // surface will be additive
+#define SURF_ENVMAPPED 0x200000 // surface is envmapped
+#define SURF_RANDOMANIMATE 0x400000 // surface start animating on a random frame
+#define SURF_ANIMATE 0x800000 // surface animates
+#define SURF_RNDTIME 0x1000000 // time between animations is random
+#define SURF_TRANSLATE 0x2000000 // surface translates
+#define SURF_NOMERGE 0x4000000 // surface is not merged in csg phase
+#define SURF_TYPE_BIT0 0x8000000 // 0 bit of surface type
+#define SURF_TYPE_BIT1 0x10000000 // 1 bit of surface type
+#define SURF_TYPE_BIT2 0x20000000 // 2 bit of surface type
+#define SURF_TYPE_BIT3 0x40000000 // 3 bit of surface type
+
+#define SURF_START_BIT 27
+#define SURFACETYPE_FROM_FLAGS( x ) ( ( x >> (SURF_START_BIT) ) & 0xf )
+
+
+#define SURF_TYPE_SHIFT(x) ( (x) << (SURF_START_BIT) ) // macro for getting proper bit mask
+
+#define SURF_TYPE_NONE SURF_TYPE_SHIFT(0)
+#define SURF_TYPE_WOOD SURF_TYPE_SHIFT(1)
+#define SURF_TYPE_METAL SURF_TYPE_SHIFT(2)
+#define SURF_TYPE_STONE SURF_TYPE_SHIFT(3)
+#define SURF_TYPE_CONCRETE SURF_TYPE_SHIFT(4)
+#define SURF_TYPE_DIRT SURF_TYPE_SHIFT(5)
+#define SURF_TYPE_FLESH SURF_TYPE_SHIFT(6)
+#define SURF_TYPE_GRILL SURF_TYPE_SHIFT(7)
+#define SURF_TYPE_GLASS SURF_TYPE_SHIFT(8)
+#define SURF_TYPE_FABRIC SURF_TYPE_SHIFT(9)
+#define SURF_TYPE_MONITOR SURF_TYPE_SHIFT(10)
+#define SURF_TYPE_GRAVEL SURF_TYPE_SHIFT(11)
+#define SURF_TYPE_VEGETATION SURF_TYPE_SHIFT(12)
+#define SURF_TYPE_PAPER SURF_TYPE_SHIFT(13)
+#define SURF_TYPE_DUCT SURF_TYPE_SHIFT(14)
+#define SURF_TYPE_WATER SURF_TYPE_SHIFT(15)
+#endif
+
+
+typedef struct
+{
+ int planenum;
+ int children[2]; // negative numbers are -(leafs+1), not nodes
+ short mins[3]; // for frustom culling
+ short maxs[3];
+ unsigned short firstface;
+ unsigned short numfaces; // counting both sides
+} sin_dnode_t;
+
+#ifdef SIN
+
+typedef struct sin_lightvalue_s
+{
+ int value; // light emission, etc
+ vec3_t color;
+ float direct;
+ float directangle;
+ float directstyle;
+ char directstylename[32];
+} sin_lightvalue_t;
+
+typedef struct sin_texinfo_s
+{
+ float vecs[2][4]; // [s/t][xyz offset]
+ int flags; // miptex flags + overrides
+ char texture[64]; // texture name (textures/*.wal)
+ int nexttexinfo; // for animations, -1 = end of chain
+ float trans_mag;
+ int trans_angle;
+ int base_angle;
+ float animtime;
+ float nonlit;
+ float translucence;
+ float friction;
+ float restitution;
+ vec3_t color;
+ char groupname[32];
+} sin_texinfo_t;
+
+#endif //SIN
+
+// note that edge 0 is never used, because negative edge nums are used for
+// counterclockwise use of the edge in a face
+typedef struct
+{
+ unsigned short v[2]; // vertex numbers
+} sin_dedge_t;
+
+#ifdef MAXLIGHTMAPS
+#undef MAXLIGHTMAPS
+#endif
+#define MAXLIGHTMAPS 16
+typedef struct
+{
+ unsigned short planenum;
+ short side;
+
+ int firstedge; // we must support > 64k edges
+ short numedges;
+ short texinfo;
+
+// lighting info
+ byte styles[MAXLIGHTMAPS];
+ int lightofs; // start of [numstyles*surfsize] samples
+#ifdef SIN
+ int lightinfo;
+#endif
+} sin_dface_t;
+
+typedef struct
+{
+ int contents; // OR of all brushes (not needed?)
+
+ short cluster;
+ short area;
+
+ short mins[3]; // for frustum culling
+ short maxs[3];
+
+ unsigned short firstleafface;
+ unsigned short numleaffaces;
+
+ unsigned short firstleafbrush;
+ unsigned short numleafbrushes;
+} sin_dleaf_t;
+
+typedef struct
+{
+ unsigned short planenum; // facing out of the leaf
+ short texinfo;
+#ifdef SIN
+ int lightinfo;
+#endif
+} sin_dbrushside_t;
+
+typedef struct
+{
+ int firstside;
+ int numsides;
+ int contents;
+} sin_dbrush_t;
+
+#define ANGLE_UP -1
+#define ANGLE_DOWN -2
+
+
+// the visibility lump consists of a header with a count, then
+// byte offsets for the PVS and PHS of each cluster, then the raw
+// compressed bit vectors
+#define DVIS_PVS 0
+#define DVIS_PHS 1
+typedef struct
+{
+ int numclusters;
+ int bitofs[8][2]; // bitofs[numclusters][2]
+} sin_dvis_t;
+
+// each area has a list of portals that lead into other areas
+// when portals are closed, other areas may not be visible or
+// hearable even if the vis info says that it should be
+typedef struct
+{
+ int portalnum;
+ int otherarea;
+} sin_dareaportal_t;
+
+typedef struct
+{
+ int numareaportals;
+ int firstareaportal;
+} sin_darea_t;
diff --git a/code/bspc/tetrahedron.c b/code/bspc/tetrahedron.c
index 36c10af..4c4d251 100755
--- a/code/bspc/tetrahedron.c
+++ b/code/bspc/tetrahedron.c
@@ -1,1389 +1,1389 @@
-/*
-===========================================================================
-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 "l_mem.h"
-#include "../botlib/aasfile.h"
-#include "aas_store.h"
-#include "aas_cfg.h"
-#include "aas_file.h"
-
-//
-// creating tetrahedrons from a arbitrary world bounded by triangles
-//
-// a triangle has 3 corners and 3 edges
-// a tetrahedron is build out of 4 triangles
-// a tetrahedron has 6 edges
-// we start with a world bounded by triangles, a side of a triangle facing
-// towards the oudside of the world is marked as part of tetrahedron -1
-//
-// a tetrahedron is defined by two non-coplanar triangles with a shared edge
-//
-// a tetrahedron is defined by one triangle and a vertex not in the triangle plane
-//
-// if all triangles using a specific vertex have tetrahedrons
-// at both sides then this vertex will never be part of a new tetrahedron
-//
-// if all triangles using a specific edge have tetrahedrons
-// at both sides then this vertex will never be part of a new tetrahedron
-//
-// each triangle can only be shared by two tetrahedrons
-// when all triangles have tetrahedrons at both sides then we're done
-//
-// if we cannot create any new tetrahedrons and there is at least one triangle
-// which has a tetrahedron only at one side then the world leaks
-//
-
-#define Sign(x) (x < 0 ? 1 : 0)
-
-#define MAX_TH_VERTEXES 128000
-#define MAX_TH_PLANES 128000
-#define MAX_TH_EDGES 512000
-#define MAX_TH_TRIANGLES 51200
-#define MAX_TH_TETRAHEDRONS 12800
-
-#define PLANEHASH_SIZE 1024
-#define EDGEHASH_SIZE 1024
-#define TRIANGLEHASH_SIZE 1024
-#define VERTEXHASH_SHIFT 7
-#define VERTEXHASH_SIZE ((MAX_MAP_BOUNDS>>(VERTEXHASH_SHIFT-1))+1) //was 64
-
-#define NORMAL_EPSILON 0.0001
-#define DIST_EPSILON 0.1
-#define VERTEX_EPSILON 0.01
-#define INTEGRAL_EPSILON 0.01
-
-
-//plane
-typedef struct th_plane_s
-{
- vec3_t normal;
- float dist;
- int type;
- int signbits;
- struct th_plane_s *hashnext; //next plane in hash
-} th_plane_t;
-
-//vertex
-typedef struct th_vertex_s
-{
- vec3_t v;
- int usercount; //2x the number of to be processed
- //triangles using this vertex
- struct th_vertex_s *hashnext; //next vertex in hash
-} th_vertex_t;
-
-//edge
-typedef struct th_edge_s
-{
- int v[2]; //vertex indexes
- int usercount; //number of to be processed
- //triangles using this edge
- struct th_edge_s *hashnext; //next edge in hash
-} th_edge_t;
-
-//triangle
-typedef struct th_triangle_s
-{
- int edges[3]; //negative if edge is flipped
- th_plane_t planes[3]; //triangle bounding planes
- int planenum; //plane the triangle is in
- int front; //tetrahedron at the front
- int back; //tetrahedron at the back
- vec3_t mins, maxs; //triangle bounding box
- struct th_triangle_s *prev, *next; //links in linked triangle lists
- struct th_triangle_s *hashnext; //next triangle in hash
-} th_triangle_t;
-
-//tetrahedron
-typedef struct th_tetrahedron_s
-{
- int triangles[4]; //negative if at backside of triangle
- float volume; //tetrahedron volume
-} th_tetrahedron_t;
-
-typedef struct th_s
-{
- //vertexes
- int numvertexes;
- th_vertex_t *vertexes;
- th_vertex_t *vertexhash[VERTEXHASH_SIZE * VERTEXHASH_SIZE];
- //planes
- int numplanes;
- th_plane_t *planes;
- th_plane_t *planehash[PLANEHASH_SIZE];
- //edges
- int numedges;
- th_edge_t *edges;
- th_edge_t *edgehash[EDGEHASH_SIZE];
- //triangles
- int numtriangles;
- th_triangle_t *triangles;
- th_triangle_t *trianglehash[TRIANGLEHASH_SIZE];
- //tetrahedrons
- int numtetrahedrons;
- th_tetrahedron_t *tetrahedrons;
-} th_t;
-
-th_t thworld;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void TH_InitMaxTH(void)
-{
- //get memory for the tetrahedron data
- thworld.vertexes = (th_vertex_t *) GetClearedMemory(MAX_TH_VERTEXES * sizeof(th_vertex_t));
- thworld.planes = (th_plane_t *) GetClearedMemory(MAX_TH_PLANES * sizeof(th_plane_t));
- thworld.edges = (th_edge_t *) GetClearedMemory(MAX_TH_EDGES * sizeof(th_edge_t));
- thworld.triangles = (th_triangle_t *) GetClearedMemory(MAX_TH_TRIANGLES * sizeof(th_triangle_t));
- thworld.tetrahedrons = (th_tetrahedron_t *) GetClearedMemory(MAX_TH_TETRAHEDRONS * sizeof(th_tetrahedron_t));
- //reset the hash tables
- memset(thworld.vertexhash, 0, VERTEXHASH_SIZE * sizeof(th_vertex_t *));
- memset(thworld.planehash, 0, PLANEHASH_SIZE * sizeof(th_plane_t *));
- memset(thworld.edgehash, 0, EDGEHASH_SIZE * sizeof(th_edge_t *));
- memset(thworld.trianglehash, 0, TRIANGLEHASH_SIZE * sizeof(th_triangle_t *));
-} //end of the function TH_InitMaxTH
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void TH_FreeMaxTH(void)
-{
- if (thworld.vertexes) FreeMemory(thworld.vertexes);
- thworld.vertexes = NULL;
- thworld.numvertexes = 0;
- if (thworld.planes) FreeMemory(thworld.planes);
- thworld.planes = NULL;
- thworld.numplanes = 0;
- if (thworld.edges) FreeMemory(thworld.edges);
- thworld.edges = NULL;
- thworld.numedges = 0;
- if (thworld.triangles) FreeMemory(thworld.triangles);
- thworld.triangles = NULL;
- thworld.numtriangles = 0;
- if (thworld.tetrahedrons) FreeMemory(thworld.tetrahedrons);
- thworld.tetrahedrons = NULL;
- thworld.numtetrahedrons = 0;
-} //end of the function TH_FreeMaxTH
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float TH_TriangleArea(th_triangle_t *tri)
-{
- return 0;
-} //end of the function TH_TriangleArea
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float TH_TetrahedronVolume(th_tetrahedron_t *tetrahedron)
-{
- int edgenum, verts[3], i, j, v2;
- float volume, d;
- th_triangle_t *tri, *tri2;
- th_plane_t *plane;
-
- tri = &thworld.triangles[abs(tetrahedron->triangles[0])];
- for (i = 0; i < 3; i++)
- {
- edgenum = tri->edges[i];
- if (edgenum < 0) verts[i] = thworld.edges[abs(edgenum)].v[1];
- else verts[i] = thworld.edges[edgenum].v[0];
- } //end for
- //
- tri2 = &thworld.triangles[abs(tetrahedron->triangles[1])];
- for (j = 0; j < 3; j++)
- {
- edgenum = tri2->edges[i];
- if (edgenum < 0) v2 = thworld.edges[abs(edgenum)].v[1];
- else v2 = thworld.edges[edgenum].v[0];
- if (v2 != verts[0] &&
- v2 != verts[1] &&
- v2 != verts[2]) break;
- } //end for
-
- plane = &thworld.planes[tri->planenum];
- d = -(DotProduct (thworld.vertexes[v2].v, plane->normal) - plane->dist);
- volume = TH_TriangleArea(tri) * d / 3;
- return volume;
-} //end of the function TH_TetrahedronVolume
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TH_PlaneSignBits(vec3_t normal)
-{
- int i, signbits;
-
- signbits = 0;
- for (i = 2; i >= 0; i--)
- {
- signbits = (signbits << 1) + Sign(normal[i]);
- } //end for
- return signbits;
-} //end of the function TH_PlaneSignBits
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TH_PlaneTypeForNormal(vec3_t normal)
-{
- vec_t ax, ay, az;
-
-// NOTE: should these have an epsilon around 1.0?
- if (normal[0] == 1.0 || normal[0] == -1.0)
- return PLANE_X;
- if (normal[1] == 1.0 || normal[1] == -1.0)
- return PLANE_Y;
- if (normal[2] == 1.0 || normal[2] == -1.0)
- 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 TH_PlaneTypeForNormal
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean TH_PlaneEqual(th_plane_t *p, vec3_t normal, vec_t dist)
-{
- if (
- fabs(p->normal[0] - normal[0]) < NORMAL_EPSILON
- && fabs(p->normal[1] - normal[1]) < NORMAL_EPSILON
- && fabs(p->normal[2] - normal[2]) < NORMAL_EPSILON
- && fabs(p->dist - dist) < DIST_EPSILON )
- return true;
- return false;
-} //end of the function TH_PlaneEqual
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void TH_AddPlaneToHash(th_plane_t *p)
-{
- int hash;
-
- hash = (int)fabs(p->dist) / 8;
- hash &= (PLANEHASH_SIZE-1);
-
- p->hashnext = thworld.planehash[hash];
- thworld.planehash[hash] = p;
-} //end of the function TH_AddPlaneToHash
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TH_CreateFloatPlane(vec3_t normal, vec_t dist)
-{
- th_plane_t *p, temp;
-
- if (VectorLength(normal) < 0.5)
- Error ("FloatPlane: bad normal");
- // create a new plane
- if (thworld.numplanes+2 > MAX_TH_PLANES)
- Error ("MAX_TH_PLANES");
-
- p = &thworld.planes[thworld.numplanes];
- VectorCopy (normal, p->normal);
- p->dist = dist;
- p->type = (p+1)->type = TH_PlaneTypeForNormal (p->normal);
- p->signbits = TH_PlaneSignBits(p->normal);
-
- VectorSubtract (vec3_origin, normal, (p+1)->normal);
- (p+1)->dist = -dist;
- (p+1)->signbits = TH_PlaneSignBits((p+1)->normal);
-
- thworld.numplanes += 2;
-
- // allways put axial planes facing positive first
- if (p->type < 3)
- {
- if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0)
- {
- // flip order
- temp = *p;
- *p = *(p+1);
- *(p+1) = temp;
-
- TH_AddPlaneToHash(p);
- TH_AddPlaneToHash(p+1);
- return thworld.numplanes - 1;
- } //end if
- } //end if
-
- TH_AddPlaneToHash(p);
- TH_AddPlaneToHash(p+1);
- return thworld.numplanes - 2;
-} //end of the function TH_CreateFloatPlane
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void TH_SnapVector(vec3_t normal)
-{
- int i;
-
- for (i = 0; i < 3; i++)
- {
- if ( fabs(normal[i] - 1) < NORMAL_EPSILON )
- {
- VectorClear (normal);
- normal[i] = 1;
- break;
- } //end if
- if ( fabs(normal[i] - -1) < NORMAL_EPSILON )
- {
- VectorClear (normal);
- normal[i] = -1;
- break;
- } //end if
- } //end for
-} //end of the function TH_SnapVector
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void TH_SnapPlane(vec3_t normal, vec_t *dist)
-{
- TH_SnapVector(normal);
-
- if (fabs(*dist-Q_rint(*dist)) < DIST_EPSILON)
- *dist = Q_rint(*dist);
-} //end of the function TH_SnapPlane
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TH_FindFloatPlane(vec3_t normal, vec_t dist)
-{
- int i;
- th_plane_t *p;
- int hash, h;
-
- TH_SnapPlane (normal, &dist);
- hash = (int)fabs(dist) / 8;
- hash &= (PLANEHASH_SIZE-1);
-
- // search the border bins as well
- for (i = -1; i <= 1; i++)
- {
- h = (hash+i)&(PLANEHASH_SIZE-1);
- for (p = thworld.planehash[h]; p; p = p->hashnext)
- {
- if (TH_PlaneEqual(p, normal, dist))
- {
- return p - thworld.planes;
- } //end if
- } //end for
- } //end for
- return TH_CreateFloatPlane(normal, dist);
-} //end of the function TH_FindFloatPlane
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TH_PlaneFromPoints(int v1, int v2, int v3)
-{
- vec3_t t1, t2, normal;
- vec_t dist;
- float *p0, *p1, *p2;
-
- p0 = thworld.vertexes[v1].v;
- p1 = thworld.vertexes[v2].v;
- p2 = thworld.vertexes[v3].v;
-
- VectorSubtract(p0, p1, t1);
- VectorSubtract(p2, p1, t2);
- CrossProduct(t1, t2, normal);
- VectorNormalize(normal);
-
- dist = DotProduct(p0, normal);
-
- return TH_FindFloatPlane(normal, dist);
-} //end of the function TH_PlaneFromPoints
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void TH_AddEdgeUser(int edgenum)
-{
- th_edge_t *edge;
-
- edge = &thworld.edges[abs(edgenum)];
- //increase edge user count
- edge->usercount++;
- //increase vertex user count as well
- thworld.vertexes[edge->v[0]].usercount++;
- thworld.vertexes[edge->v[1]].usercount++;
-} //end of the function TH_AddEdgeUser
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void TH_RemoveEdgeUser(int edgenum)
-{
- th_edge_t *edge;
-
- edge = &thworld.edges[abs(edgenum)];
- //decrease edge user count
- edge->usercount--;
- //decrease vertex user count as well
- thworld.vertexes[edge->v[0]].usercount--;
- thworld.vertexes[edge->v[1]].usercount--;
-} //end of the function TH_RemoveEdgeUser
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void TH_FreeTriangleEdges(th_triangle_t *tri)
-{
- int i;
-
- for (i = 0; i < 3; i++)
- {
- TH_RemoveEdgeUser(abs(tri->edges[i]));
- } //end for
-} //end of the function TH_FreeTriangleEdges
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-unsigned TH_HashVec(vec3_t vec)
-{
- int x, y;
-
- x = (MAX_MAP_BOUNDS + (int)(vec[0]+0.5)) >> VERTEXHASH_SHIFT;
- y = (MAX_MAP_BOUNDS + (int)(vec[1]+0.5)) >> VERTEXHASH_SHIFT;
-
- if (x < 0 || x >= VERTEXHASH_SIZE || y < 0 || y >= VERTEXHASH_SIZE)
- Error("HashVec: point %f %f %f outside valid range", vec[0], vec[1], vec[2]);
-
- return y*VERTEXHASH_SIZE + x;
-} //end of the function TH_HashVec
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TH_FindVertex(vec3_t v)
-{
- int i, h;
- th_vertex_t *vertex;
- 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 = TH_HashVec(vert);
-
- for (vertex = thworld.vertexhash[h]; vertex; vertex = vertex->hashnext)
- {
- if (fabs(vertex->v[0] - vert[0]) < VERTEX_EPSILON &&
- fabs(vertex->v[1] - vert[1]) < VERTEX_EPSILON &&
- fabs(vertex->v[2] - vert[2]) < VERTEX_EPSILON)
- {
- return vertex - thworld.vertexes;
- } //end if
- } //end for
- return 0;
-} //end of the function TH_FindVertex
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void TH_AddVertexToHash(th_vertex_t *vertex)
-{
- int hashvalue;
-
- hashvalue = TH_HashVec(vertex->v);
- vertex->hashnext = thworld.vertexhash[hashvalue];
- thworld.vertexhash[hashvalue] = vertex;
-} //end of the function TH_AddVertexToHash
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TH_CreateVertex(vec3_t v)
-{
- if (thworld.numvertexes == 0) thworld.numvertexes = 1;
- if (thworld.numvertexes >= MAX_TH_VERTEXES)
- Error("MAX_TH_VERTEXES");
- VectorCopy(v, thworld.vertexes[thworld.numvertexes].v);
- thworld.vertexes[thworld.numvertexes].usercount = 0;
- TH_AddVertexToHash(&thworld.vertexes[thworld.numvertexes]);
- thworld.numvertexes++;
- return thworld.numvertexes-1;
-} //end of the function TH_CreateVertex
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TH_FindOrCreateVertex(vec3_t v)
-{
- int vertexnum;
-
- vertexnum = TH_FindVertex(v);
- if (!vertexnum) vertexnum = TH_CreateVertex(v);
- return vertexnum;
-} //end of the function TH_FindOrCreateVertex
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TH_FindEdge(int v1, int v2)
-{
- int hashvalue;
- th_edge_t *edge;
-
- hashvalue = (v1 + v2) & (EDGEHASH_SIZE-1);
-
- for (edge = thworld.edgehash[hashvalue]; edge; edge = edge->hashnext)
- {
- if (edge->v[0] == v1 && edge->v[1] == v2) return edge - thworld.edges;
- if (edge->v[1] == v1 && edge->v[0] == v2) return -(edge - thworld.edges);
- } //end for
- return 0;
-} //end of the function TH_FindEdge
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void TH_AddEdgeToHash(th_edge_t *edge)
-{
- int hashvalue;
-
- hashvalue = (edge->v[0] + edge->v[1]) & (EDGEHASH_SIZE-1);
- edge->hashnext = thworld.edgehash[hashvalue];
- thworld.edgehash[hashvalue] = edge;
-} //end of the function TH_AddEdgeToHash
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TH_CreateEdge(int v1, int v2)
-{
- th_edge_t *edge;
-
- if (thworld.numedges == 0) thworld.numedges = 1;
- if (thworld.numedges >= MAX_TH_EDGES)
- Error("MAX_TH_EDGES");
- edge = &thworld.edges[thworld.numedges++];
- edge->v[0] = v1;
- edge->v[1] = v2;
- TH_AddEdgeToHash(edge);
- return thworld.numedges-1;
-} //end of the function TH_CreateEdge
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TH_FindOrCreateEdge(int v1, int v2)
-{
- int edgenum;
-
- edgenum = TH_FindEdge(v1, v2);
- if (!edgenum) edgenum = TH_CreateEdge(v1, v2);
- return edgenum;
-} //end of the function TH_FindOrCreateEdge
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TH_FindTriangle(int verts[3])
-{
- int i, hashvalue, edges[3];
- th_triangle_t *tri;
-
- for (i = 0; i < 3; i++)
- {
- edges[i] = TH_FindEdge(verts[i], verts[(i+1)%3]);
- if (!edges[i]) return false;
- } //end for
- hashvalue = (abs(edges[0]) + abs(edges[1]) + abs(edges[2])) & (TRIANGLEHASH_SIZE-1);
- for (tri = thworld.trianglehash[hashvalue]; tri; tri = tri->next)
- {
- for (i = 0; i < 3; i++)
- {
- if (abs(tri->edges[i]) != abs(edges[0]) &&
- abs(tri->edges[i]) != abs(edges[1]) &&
- abs(tri->edges[i]) != abs(edges[2])) break;
- } //end for
- if (i >= 3) return tri - thworld.triangles;
- } //end for
- return 0;
-} //end of the function TH_FindTriangle
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void TH_AddTriangleToHash(th_triangle_t *tri)
-{
- int hashvalue;
-
- hashvalue = (abs(tri->edges[0]) + abs(tri->edges[1]) + abs(tri->edges[2])) & (TRIANGLEHASH_SIZE-1);
- tri->hashnext = thworld.trianglehash[hashvalue];
- thworld.trianglehash[hashvalue] = tri;
-} //end of the function TH_AddTriangleToHash
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void TH_CreateTrianglePlanes(int verts[3], th_plane_t *triplane, th_plane_t *planes)
-{
- int i;
- vec3_t dir;
-
- for (i = 0; i < 3; i++)
- {
- VectorSubtract(thworld.vertexes[verts[(i+1)%3]].v, thworld.vertexes[verts[i]].v, dir);
- CrossProduct(dir, triplane->normal, planes[i].normal);
- VectorNormalize(planes[i].normal);
- planes[i].dist = DotProduct(thworld.vertexes[verts[i]].v, planes[i].normal);
- } //end for
-} //end of the function TH_CreateTrianglePlanes
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TH_CreateTriangle(int verts[3])
-{
- th_triangle_t *tri;
- int i;
-
- if (thworld.numtriangles == 0) thworld.numtriangles = 1;
- if (thworld.numtriangles >= MAX_TH_TRIANGLES)
- Error("MAX_TH_TRIANGLES");
- tri = &thworld.triangles[thworld.numtriangles++];
- for (i = 0; i < 3; i++)
- {
- tri->edges[i] = TH_FindOrCreateEdge(verts[i], verts[(i+1)%3]);
- TH_AddEdgeUser(abs(tri->edges[i]));
- } //end for
- tri->front = 0;
- tri->back = 0;
- tri->planenum = TH_PlaneFromPoints(verts[0], verts[1], verts[2]);
- tri->prev = NULL;
- tri->next = NULL;
- tri->hashnext = NULL;
- TH_CreateTrianglePlanes(verts, &thworld.planes[tri->planenum], tri->planes);
- TH_AddTriangleToHash(tri);
- ClearBounds(tri->mins, tri->maxs);
- for (i = 0; i < 3; i++)
- {
- AddPointToBounds(thworld.vertexes[verts[i]].v, tri->mins, tri->maxs);
- } //end for
- return thworld.numtriangles-1;
-} //end of the function TH_CreateTriangle
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TH_CreateTetrahedron(int triangles[4])
-{
- th_tetrahedron_t *tetrahedron;
- int i;
-
- if (thworld.numtetrahedrons == 0) thworld.numtetrahedrons = 1;
- if (thworld.numtetrahedrons >= MAX_TH_TETRAHEDRONS)
- Error("MAX_TH_TETRAHEDRONS");
- tetrahedron = &thworld.tetrahedrons[thworld.numtetrahedrons++];
- for (i = 0; i < 4; i++)
- {
- tetrahedron->triangles[i] = triangles[i];
- if (thworld.triangles[abs(triangles[i])].front)
- {
- thworld.triangles[abs(triangles[i])].back = thworld.numtetrahedrons-1;
- } //end if
- else
- {
- thworld.triangles[abs(triangles[i])].front = thworld.numtetrahedrons-1;
- } //end else
- } //end for
- tetrahedron->volume = 0;
- return thworld.numtetrahedrons-1;
-} //end of the function TH_CreateTetrahedron
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TH_IntersectTrianglePlanes(int v1, int v2, th_plane_t *triplane, th_plane_t *planes)
-{
- float *p1, *p2, front, back, frac, d;
- int i, side, lastside;
- vec3_t mid;
-
- p1 = thworld.vertexes[v1].v;
- p2 = thworld.vertexes[v2].v;
-
- front = DotProduct(p1, triplane->normal) - triplane->dist;
- back = DotProduct(p2, triplane->normal) - triplane->dist;
- //if both points at the same side of the plane
- if (front < 0.1 && back < 0.1) return false;
- if (front > -0.1 && back > -0.1) return false;
- //
- frac = front/(front-back);
- mid[0] = p1[0] + (p2[0] - p1[0]) * frac;
- mid[1] = p1[1] + (p2[1] - p1[1]) * frac;
- mid[2] = p1[2] + (p2[2] - p1[2]) * frac;
- //if the mid point is at the same side of all the tri bounding planes
- lastside = 0;
- for (i = 0; i < 3; i++)
- {
- d = DotProduct(mid, planes[i].normal) - planes[i].dist;
- side = d < 0;
- if (i && side != lastside) return false;
- lastside = side;
- } //end for
- return true;
-} //end of the function TH_IntersectTrianglePlanes
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TH_OutsideBoundingBox(int v1, int v2, vec3_t mins, vec3_t maxs)
-{
- float *p1, *p2;
- int i;
-
- p1 = thworld.vertexes[v1].v;
- p2 = thworld.vertexes[v2].v;
- //if both points are at the outer side of one of the bounding box planes
- for (i = 0; i < 3; i++)
- {
- if (p1[i] < mins[i] && p2[i] < mins[i]) return true;
- if (p1[i] > maxs[i] && p2[i] > maxs[i]) return true;
- } //end for
- return false;
-} //end of the function TH_OutsideBoundingBox
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TH_TryEdge(int v1, int v2)
-{
- int i, j, v;
- th_plane_t *plane;
- th_triangle_t *tri;
-
- //if the edge already exists it must be valid
- if (TH_FindEdge(v1, v2)) return true;
- //test the edge with all existing triangles
- for (i = 1; i < thworld.numtriangles; i++)
- {
- tri = &thworld.triangles[i];
- //if triangle is enclosed by two tetrahedrons we don't have to test it
- //because the edge always has to go through another triangle of those
- //tetrahedrons first to reach the enclosed triangle
- if (tri->front && tri->back) continue;
- //if the edges is totally outside the triangle bounding box
- if (TH_OutsideBoundingBox(v1, v2, tri->mins, tri->maxs)) continue;
- //if one of the edge vertexes is used by this triangle
- for (j = 0; j < 3; j++)
- {
- v = thworld.edges[abs(tri->edges[j])].v[tri->edges[j] < 0];
- if (v == v1 || v == v2) break;
- } //end for
- if (j < 3) continue;
- //get the triangle plane
- plane = &thworld.planes[tri->planenum];
- //if the edge intersects with a triangle then it's not valid
- if (TH_IntersectTrianglePlanes(v1, v2, plane, tri->planes)) return false;
- } //end for
- return true;
-} //end of the function TH_TryEdge
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TH_TryTriangle(int verts[3])
-{
- th_plane_t planes[3], triplane;
- vec3_t t1, t2;
- float *p0, *p1, *p2;
- int i, j;
-
- p0 = thworld.vertexes[verts[0]].v;
- p1 = thworld.vertexes[verts[1]].v;
- p2 = thworld.vertexes[verts[2]].v;
-
- VectorSubtract(p0, p1, t1);
- VectorSubtract(p2, p1, t2);
- CrossProduct(t1, t2, triplane.normal);
- VectorNormalize(triplane.normal);
- triplane.dist = DotProduct(p0, triplane.normal);
- //
- TH_CreateTrianglePlanes(verts, &triplane, planes);
- //test if any existing edge intersects with this triangle
- for (i = 1; i < thworld.numedges; i++)
- {
- //if the edge is only used by triangles with tetrahedrons at both sides
- if (!thworld.edges[i].usercount) continue;
- //if one of the triangle vertexes is used by this edge
- for (j = 0; j < 3; j++)
- {
- if (verts[j] == thworld.edges[j].v[0] ||
- verts[j] == thworld.edges[j].v[1]) break;
- } //end for
- if (j < 3) continue;
- //if this edge intersects with the triangle
- if (TH_IntersectTrianglePlanes(thworld.edges[i].v[0], thworld.edges[i].v[1], &triplane, planes)) return false;
- } //end for
- return true;
-} //end of the function TH_TryTriangle
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void TH_AddTriangleToList(th_triangle_t **trianglelist, th_triangle_t *tri)
-{
- tri->prev = NULL;
- tri->next = *trianglelist;
- if (*trianglelist) (*trianglelist)->prev = tri;
- *trianglelist = tri;
-} //end of the function TH_AddTriangleToList
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void TH_RemoveTriangleFromList(th_triangle_t **trianglelist, th_triangle_t *tri)
-{
- if (tri->next) tri->next->prev = tri->prev;
- if (tri->prev) tri->prev->next = tri->next;
- else *trianglelist = tri->next;
-} //end of the function TH_RemoveTriangleFromList
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TH_FindTetrahedron1(th_triangle_t *tri, int *triangles)
-{
- int i, j, edgenum, side, v1, v2, v3, v4;
- int verts1[3], verts2[3];
- th_triangle_t *tri2;
-
- //find another triangle with a shared edge
- for (tri2 = tri->next; tri2; tri2 = tri2->next)
- {
- //if the triangles are in the same plane
- if ((tri->planenum & ~1) == (tri2->planenum & ~1)) continue;
- //try to find a shared edge
- for (i = 0; i < 3; i++)
- {
- edgenum = abs(tri->edges[i]);
- for (j = 0; j < 3; j++)
- {
- if (edgenum == abs(tri2->edges[j])) break;
- } //end for
- if (j < 3) break;
- } //end for
- //if the triangles have a shared edge
- if (i < 3)
- {
- edgenum = tri->edges[(i+1)%3];
- if (edgenum < 0) v1 = thworld.edges[abs(edgenum)].v[0];
- else v1 = thworld.edges[edgenum].v[1];
- edgenum = tri2->edges[(j+1)%3];
- if (edgenum < 0) v2 = thworld.edges[abs(edgenum)].v[0];
- else v2 = thworld.edges[edgenum].v[1];
- //try the new edge
- if (TH_TryEdge(v1, v2))
- {
- edgenum = tri->edges[i];
- side = edgenum < 0;
- //get the vertexes of the shared edge
- v3 = thworld.edges[abs(edgenum)].v[side];
- v4 = thworld.edges[abs(edgenum)].v[!side];
- //try the two new triangles
- verts1[0] = v1;
- verts1[1] = v2;
- verts1[2] = v3;
- triangles[2] = TH_FindTriangle(verts1);
- if (triangles[2] || TH_TryTriangle(verts1))
- {
- verts2[0] = v2;
- verts2[1] = v1;
- verts2[2] = v4;
- triangles[3] = TH_FindTriangle(verts2);
- if (triangles[3] || TH_TryTriangle(verts2))
- {
- triangles[0] = tri - thworld.triangles;
- triangles[1] = tri2 - thworld.triangles;
- if (!triangles[2]) triangles[2] = TH_CreateTriangle(verts1);
- if (!triangles[3]) triangles[3] = TH_CreateTriangle(verts2);
- return true;
- } //end if
- } //end if
- } //end if
- } //end if
- } //end for
- return false;
-} //end of the function TH_FindTetrahedron
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TH_FindTetrahedron2(th_triangle_t *tri, int *triangles)
-{
- int i, edgenum, v1, verts[3], triverts[3];
- float d;
- th_plane_t *plane;
-
- //get the verts of this triangle
- for (i = 0; i < 3; i++)
- {
- edgenum = tri->edges[i];
- if (edgenum < 0) verts[i] = thworld.edges[abs(edgenum)].v[1];
- else verts[i] = thworld.edges[edgenum].v[0];
- } //end for
- //
- plane = &thworld.planes[tri->planenum];
- for (v1 = 0; v1 < thworld.numvertexes; v1++)
- {
- //if the vertex is only used by triangles with tetrahedrons at both sides
- if (!thworld.vertexes[v1].usercount) continue;
- //check if the vertex is not coplanar with the triangle
- d = DotProduct(thworld.vertexes[v1].v, plane->normal) - plane->dist;
- if (fabs(d) < 1) continue;
- //check if we can create edges from the triangle towards this new vertex
- for (i = 0; i < 3; i++)
- {
- if (v1 == verts[i]) break;
- if (!TH_TryEdge(v1, verts[i])) break;
- } //end for
- if (i < 3) continue;
- //check if the triangles are valid
- for (i = 0; i < 3; i++)
- {
- triverts[0] = v1;
- triverts[1] = verts[i];
- triverts[2] = verts[(i+1)%3];
- //if the triangle already exists then it is valid
- triangles[i] = TH_FindTriangle(triverts);
- if (!triangles[i])
- {
- if (!TH_TryTriangle(triverts)) break;
- } //end if
- } //end for
- if (i < 3) continue;
- //create the tetrahedron triangles using the new vertex
- for (i = 0; i < 3; i++)
- {
- if (!triangles[i])
- {
- triverts[0] = v1;
- triverts[1] = verts[i];
- triverts[2] = verts[(i+1)%3];
- triangles[i] = TH_CreateTriangle(triverts);
- } //end if
- } //end for
- //add the existing triangle
- triangles[3] = tri - thworld.triangles;
- //
- return true;
- } //end for
- return false;
-} //end of the function TH_FindTetrahedron2
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void TH_TetrahedralDecomposition(th_triangle_t *triangles)
-{
- int i, thtriangles[4], numtriangles;
- th_triangle_t *donetriangles, *tri;
-
- donetriangles = NULL;
-
- /*
- numtriangles = 0;
- qprintf("%6d triangles", numtriangles);
- for (tri = triangles; tri; tri = triangles)
- {
- qprintf("\r%6d", numtriangles++);
- if (!TH_FindTetrahedron1(tri, thtriangles))
- {
-// if (!TH_FindTetrahedron2(tri, thtriangles))
- {
-// Error("triangle without tetrahedron");
- TH_RemoveTriangleFromList(&triangles, tri);
- continue;
- } //end if
- } //end if
- //create a tetrahedron from the triangles
- TH_CreateTetrahedron(thtriangles);
- //
- for (i = 0; i < 4; i++)
- {
- if (thworld.triangles[abs(thtriangles[i])].front &&
- thworld.triangles[abs(thtriangles[i])].back)
- {
- TH_RemoveTriangleFromList(&triangles, &thworld.triangles[abs(thtriangles[i])]);
- TH_AddTriangleToList(&donetriangles, &thworld.triangles[abs(thtriangles[i])]);
- TH_FreeTriangleEdges(&thworld.triangles[abs(thtriangles[i])]);
- } //end if
- else
- {
- TH_AddTriangleToList(&triangles, &thworld.triangles[abs(thtriangles[i])]);
- } //end else
- } //end for
- } //end for*/
- qprintf("%6d tetrahedrons", thworld.numtetrahedrons);
- do
- {
- do
- {
- numtriangles = 0;
- for (i = 1; i < thworld.numtriangles; i++)
- {
- tri = &thworld.triangles[i];
- if (tri->front && tri->back) continue;
- //qprintf("\r%6d", numtriangles++);
- if (!TH_FindTetrahedron1(tri, thtriangles))
- {
-// if (!TH_FindTetrahedron2(tri, thtriangles))
- {
- continue;
- } //end if
- } //end if
- numtriangles++;
- //create a tetrahedron from the triangles
- TH_CreateTetrahedron(thtriangles);
- qprintf("\r%6d", thworld.numtetrahedrons);
- } //end for
- } while(numtriangles);
- for (i = 1; i < thworld.numtriangles; i++)
- {
- tri = &thworld.triangles[i];
- if (tri->front && tri->back) continue;
- //qprintf("\r%6d", numtriangles++);
-// if (!TH_FindTetrahedron1(tri, thtriangles))
- {
- if (!TH_FindTetrahedron2(tri, thtriangles))
- {
- continue;
- } //end if
- } //end if
- numtriangles++;
- //create a tetrahedron from the triangles
- TH_CreateTetrahedron(thtriangles);
- qprintf("\r%6d", thworld.numtetrahedrons);
- } //end for
- } while(numtriangles);
- //
- numtriangles = 0;
- for (i = 1; i < thworld.numtriangles; i++)
- {
- tri = &thworld.triangles[i];
- if (!tri->front && !tri->back) numtriangles++;
- } //end for
- Log_Print("\r%6d triangles with front only\n", numtriangles);
- Log_Print("\r%6d tetrahedrons\n", thworld.numtetrahedrons-1);
-} //end of the function TH_TetrahedralDecomposition
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void TH_AASFaceVertex(aas_face_t *face, int index, vec3_t vertex)
-{
- int edgenum, side;
-
- edgenum = aasworld.edgeindex[face->firstedge + index];
- side = edgenum < 0;
- VectorCopy(aasworld.vertexes[aasworld.edges[abs(edgenum)].v[side]], vertex);
-} //end of the function TH_AASFaceVertex
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TH_Colinear(float *v0, float *v1, float *v2)
-{
- vec3_t t1, t2, vcross;
- float d;
-
- VectorSubtract(v1, v0, t1);
- VectorSubtract(v2, v0, t2);
- CrossProduct (t1, t2, vcross);
- d = VectorLength( vcross );
-
- // if cross product is zero point is colinear
- if (d < 10)
- {
- return true;
- } //end if
- return false;
-} //end of the function TH_Colinear
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void TH_FaceCenter(aas_face_t *face, vec3_t center)
-{
- int i, edgenum, side;
- aas_edge_t *edge;
-
- VectorClear(center);
- for (i = 0; i < face->numedges; i++)
- {
- edgenum = abs(aasworld.edgeindex[face->firstedge + i]);
- side = edgenum < 0;
- edge = &aasworld.edges[abs(edgenum)];
- VectorAdd(aasworld.vertexes[edge->v[side]], center, center);
- } //end for
- VectorScale(center, 1.0 / face->numedges, center);
-} //end of the function TH_FaceCenter
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-th_triangle_t *TH_CreateAASFaceTriangles(aas_face_t *face)
-{
- int i, first, verts[3], trinum;
- vec3_t p0, p1, p2, p3, p4, center;
- th_triangle_t *tri, *triangles;
-
- triangles = NULL;
- //find three points that are not colinear
- for (i = 0; i < face->numedges; i++)
- {
- TH_AASFaceVertex(face, (face->numedges + i-2)%face->numedges, p0);
- TH_AASFaceVertex(face, (face->numedges + i-1)%face->numedges, p1);
- TH_AASFaceVertex(face, (i )%face->numedges, p2);
- if (TH_Colinear(p2, p0, p1)) continue;
- TH_AASFaceVertex(face, (i+1)%face->numedges, p3);
- TH_AASFaceVertex(face, (i+2)%face->numedges, p4);
- if (TH_Colinear(p2, p3, p4)) continue;
- break;
- } //end for
- //if there are three points that are not colinear
- if (i < face->numedges)
- {
- //normal triangulation
- first = i; //left and right most point of three non-colinear points
- TH_AASFaceVertex(face, first, p0);
- verts[0] = TH_FindOrCreateVertex(p0);
- for (i = 1; i < face->numedges-1; i++)
- {
- TH_AASFaceVertex(face, (first+i )%face->numedges, p1);
- TH_AASFaceVertex(face, (first+i+1)%face->numedges, p2);
- verts[1] = TH_FindOrCreateVertex(p1);
- verts[2] = TH_FindOrCreateVertex(p2);
- trinum = TH_CreateTriangle(verts);
- tri = &thworld.triangles[trinum];
- tri->front = -1;
- TH_AddTriangleToList(&triangles, tri);
- } //end for
- } //end if
- else
- {
- //fan triangulation
- TH_FaceCenter(face, center);
- //
- verts[0] = TH_FindOrCreateVertex(center);
- for (i = 0; i < face->numedges; i++)
- {
- TH_AASFaceVertex(face, (i )%face->numedges, p1);
- TH_AASFaceVertex(face, (i+1)%face->numedges, p2);
- if (TH_Colinear(center, p1, p2)) continue;
- verts[1] = TH_FindOrCreateVertex(p1);
- verts[2] = TH_FindOrCreateVertex(p2);
- trinum = TH_CreateTriangle(verts);
- tri = &thworld.triangles[trinum];
- tri->front = -1;
- TH_AddTriangleToList(&triangles, tri);
- } //end for
- } //end else
- return triangles;
-} //end of the function TH_CreateAASFaceTriangles
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-th_triangle_t *TH_AASToTriangleMesh(void)
-{
- int i, j, facenum, otherareanum;
- aas_face_t *face;
- th_triangle_t *tri, *nexttri, *triangles;
-
- triangles = NULL;
- for (i = 1; i < aasworld.numareas; i++)
- {
- //if (!(aasworld.areasettings[i].presencetype & PRESENCE_NORMAL)) continue;
- for (j = 0; j < aasworld.areas[i].numfaces; j++)
- {
- facenum = abs(aasworld.faceindex[aasworld.areas[i].firstface + j]);
- face = &aasworld.faces[facenum];
- //only convert solid faces into triangles
- if (!(face->faceflags & FACE_SOLID))
- {
- /*
- if (face->frontarea == i) otherareanum = face->backarea;
- else otherareanum = face->frontarea;
- if (aasworld.areasettings[otherareanum].presencetype & PRESENCE_NORMAL) continue;
- */
- continue;
- } //end if
- //
- tri = TH_CreateAASFaceTriangles(face);
- for (; tri; tri = nexttri)
- {
- nexttri = tri->next;
- TH_AddTriangleToList(&triangles, tri);
- } //end for
- } //end if
- } //end for
- return triangles;
-} //end of the function TH_AASToTriangleMesh
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void TH_AASToTetrahedrons(char *filename)
-{
- th_triangle_t *triangles, *tri, *lasttri;
- int cnt;
-
- if (!AAS_LoadAASFile(filename, 0, 0))
- Error("couldn't load %s\n", filename);
-
- //
- TH_InitMaxTH();
- //create a triangle mesh from the solid faces in the AAS file
- triangles = TH_AASToTriangleMesh();
- //
- cnt = 0;
- lasttri = NULL;
- for (tri = triangles; tri; tri = tri->next)
- {
- cnt++;
- if (tri->prev != lasttri) Log_Print("BAH\n");
- lasttri = tri;
- } //end for
- Log_Print("%6d triangles\n", cnt);
- //create a tetrahedral decomposition of the world bounded by triangles
- TH_TetrahedralDecomposition(triangles);
- //
- TH_FreeMaxTH();
-} //end of the function TH_AASToTetrahedrons
+/*
+===========================================================================
+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 "l_mem.h"
+#include "../botlib/aasfile.h"
+#include "aas_store.h"
+#include "aas_cfg.h"
+#include "aas_file.h"
+
+//
+// creating tetrahedrons from a arbitrary world bounded by triangles
+//
+// a triangle has 3 corners and 3 edges
+// a tetrahedron is build out of 4 triangles
+// a tetrahedron has 6 edges
+// we start with a world bounded by triangles, a side of a triangle facing
+// towards the oudside of the world is marked as part of tetrahedron -1
+//
+// a tetrahedron is defined by two non-coplanar triangles with a shared edge
+//
+// a tetrahedron is defined by one triangle and a vertex not in the triangle plane
+//
+// if all triangles using a specific vertex have tetrahedrons
+// at both sides then this vertex will never be part of a new tetrahedron
+//
+// if all triangles using a specific edge have tetrahedrons
+// at both sides then this vertex will never be part of a new tetrahedron
+//
+// each triangle can only be shared by two tetrahedrons
+// when all triangles have tetrahedrons at both sides then we're done
+//
+// if we cannot create any new tetrahedrons and there is at least one triangle
+// which has a tetrahedron only at one side then the world leaks
+//
+
+#define Sign(x) (x < 0 ? 1 : 0)
+
+#define MAX_TH_VERTEXES 128000
+#define MAX_TH_PLANES 128000
+#define MAX_TH_EDGES 512000
+#define MAX_TH_TRIANGLES 51200
+#define MAX_TH_TETRAHEDRONS 12800
+
+#define PLANEHASH_SIZE 1024
+#define EDGEHASH_SIZE 1024
+#define TRIANGLEHASH_SIZE 1024
+#define VERTEXHASH_SHIFT 7
+#define VERTEXHASH_SIZE ((MAX_MAP_BOUNDS>>(VERTEXHASH_SHIFT-1))+1) //was 64
+
+#define NORMAL_EPSILON 0.0001
+#define DIST_EPSILON 0.1
+#define VERTEX_EPSILON 0.01
+#define INTEGRAL_EPSILON 0.01
+
+
+//plane
+typedef struct th_plane_s
+{
+ vec3_t normal;
+ float dist;
+ int type;
+ int signbits;
+ struct th_plane_s *hashnext; //next plane in hash
+} th_plane_t;
+
+//vertex
+typedef struct th_vertex_s
+{
+ vec3_t v;
+ int usercount; //2x the number of to be processed
+ //triangles using this vertex
+ struct th_vertex_s *hashnext; //next vertex in hash
+} th_vertex_t;
+
+//edge
+typedef struct th_edge_s
+{
+ int v[2]; //vertex indexes
+ int usercount; //number of to be processed
+ //triangles using this edge
+ struct th_edge_s *hashnext; //next edge in hash
+} th_edge_t;
+
+//triangle
+typedef struct th_triangle_s
+{
+ int edges[3]; //negative if edge is flipped
+ th_plane_t planes[3]; //triangle bounding planes
+ int planenum; //plane the triangle is in
+ int front; //tetrahedron at the front
+ int back; //tetrahedron at the back
+ vec3_t mins, maxs; //triangle bounding box
+ struct th_triangle_s *prev, *next; //links in linked triangle lists
+ struct th_triangle_s *hashnext; //next triangle in hash
+} th_triangle_t;
+
+//tetrahedron
+typedef struct th_tetrahedron_s
+{
+ int triangles[4]; //negative if at backside of triangle
+ float volume; //tetrahedron volume
+} th_tetrahedron_t;
+
+typedef struct th_s
+{
+ //vertexes
+ int numvertexes;
+ th_vertex_t *vertexes;
+ th_vertex_t *vertexhash[VERTEXHASH_SIZE * VERTEXHASH_SIZE];
+ //planes
+ int numplanes;
+ th_plane_t *planes;
+ th_plane_t *planehash[PLANEHASH_SIZE];
+ //edges
+ int numedges;
+ th_edge_t *edges;
+ th_edge_t *edgehash[EDGEHASH_SIZE];
+ //triangles
+ int numtriangles;
+ th_triangle_t *triangles;
+ th_triangle_t *trianglehash[TRIANGLEHASH_SIZE];
+ //tetrahedrons
+ int numtetrahedrons;
+ th_tetrahedron_t *tetrahedrons;
+} th_t;
+
+th_t thworld;
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void TH_InitMaxTH(void)
+{
+ //get memory for the tetrahedron data
+ thworld.vertexes = (th_vertex_t *) GetClearedMemory(MAX_TH_VERTEXES * sizeof(th_vertex_t));
+ thworld.planes = (th_plane_t *) GetClearedMemory(MAX_TH_PLANES * sizeof(th_plane_t));
+ thworld.edges = (th_edge_t *) GetClearedMemory(MAX_TH_EDGES * sizeof(th_edge_t));
+ thworld.triangles = (th_triangle_t *) GetClearedMemory(MAX_TH_TRIANGLES * sizeof(th_triangle_t));
+ thworld.tetrahedrons = (th_tetrahedron_t *) GetClearedMemory(MAX_TH_TETRAHEDRONS * sizeof(th_tetrahedron_t));
+ //reset the hash tables
+ memset(thworld.vertexhash, 0, VERTEXHASH_SIZE * sizeof(th_vertex_t *));
+ memset(thworld.planehash, 0, PLANEHASH_SIZE * sizeof(th_plane_t *));
+ memset(thworld.edgehash, 0, EDGEHASH_SIZE * sizeof(th_edge_t *));
+ memset(thworld.trianglehash, 0, TRIANGLEHASH_SIZE * sizeof(th_triangle_t *));
+} //end of the function TH_InitMaxTH
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void TH_FreeMaxTH(void)
+{
+ if (thworld.vertexes) FreeMemory(thworld.vertexes);
+ thworld.vertexes = NULL;
+ thworld.numvertexes = 0;
+ if (thworld.planes) FreeMemory(thworld.planes);
+ thworld.planes = NULL;
+ thworld.numplanes = 0;
+ if (thworld.edges) FreeMemory(thworld.edges);
+ thworld.edges = NULL;
+ thworld.numedges = 0;
+ if (thworld.triangles) FreeMemory(thworld.triangles);
+ thworld.triangles = NULL;
+ thworld.numtriangles = 0;
+ if (thworld.tetrahedrons) FreeMemory(thworld.tetrahedrons);
+ thworld.tetrahedrons = NULL;
+ thworld.numtetrahedrons = 0;
+} //end of the function TH_FreeMaxTH
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+float TH_TriangleArea(th_triangle_t *tri)
+{
+ return 0;
+} //end of the function TH_TriangleArea
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+float TH_TetrahedronVolume(th_tetrahedron_t *tetrahedron)
+{
+ int edgenum, verts[3], i, j, v2;
+ float volume, d;
+ th_triangle_t *tri, *tri2;
+ th_plane_t *plane;
+
+ tri = &thworld.triangles[abs(tetrahedron->triangles[0])];
+ for (i = 0; i < 3; i++)
+ {
+ edgenum = tri->edges[i];
+ if (edgenum < 0) verts[i] = thworld.edges[abs(edgenum)].v[1];
+ else verts[i] = thworld.edges[edgenum].v[0];
+ } //end for
+ //
+ tri2 = &thworld.triangles[abs(tetrahedron->triangles[1])];
+ for (j = 0; j < 3; j++)
+ {
+ edgenum = tri2->edges[i];
+ if (edgenum < 0) v2 = thworld.edges[abs(edgenum)].v[1];
+ else v2 = thworld.edges[edgenum].v[0];
+ if (v2 != verts[0] &&
+ v2 != verts[1] &&
+ v2 != verts[2]) break;
+ } //end for
+
+ plane = &thworld.planes[tri->planenum];
+ d = -(DotProduct (thworld.vertexes[v2].v, plane->normal) - plane->dist);
+ volume = TH_TriangleArea(tri) * d / 3;
+ return volume;
+} //end of the function TH_TetrahedronVolume
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TH_PlaneSignBits(vec3_t normal)
+{
+ int i, signbits;
+
+ signbits = 0;
+ for (i = 2; i >= 0; i--)
+ {
+ signbits = (signbits << 1) + Sign(normal[i]);
+ } //end for
+ return signbits;
+} //end of the function TH_PlaneSignBits
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TH_PlaneTypeForNormal(vec3_t normal)
+{
+ vec_t ax, ay, az;
+
+// NOTE: should these have an epsilon around 1.0?
+ if (normal[0] == 1.0 || normal[0] == -1.0)
+ return PLANE_X;
+ if (normal[1] == 1.0 || normal[1] == -1.0)
+ return PLANE_Y;
+ if (normal[2] == 1.0 || normal[2] == -1.0)
+ 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 TH_PlaneTypeForNormal
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+qboolean TH_PlaneEqual(th_plane_t *p, vec3_t normal, vec_t dist)
+{
+ if (
+ fabs(p->normal[0] - normal[0]) < NORMAL_EPSILON
+ && fabs(p->normal[1] - normal[1]) < NORMAL_EPSILON
+ && fabs(p->normal[2] - normal[2]) < NORMAL_EPSILON
+ && fabs(p->dist - dist) < DIST_EPSILON )
+ return true;
+ return false;
+} //end of the function TH_PlaneEqual
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void TH_AddPlaneToHash(th_plane_t *p)
+{
+ int hash;
+
+ hash = (int)fabs(p->dist) / 8;
+ hash &= (PLANEHASH_SIZE-1);
+
+ p->hashnext = thworld.planehash[hash];
+ thworld.planehash[hash] = p;
+} //end of the function TH_AddPlaneToHash
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TH_CreateFloatPlane(vec3_t normal, vec_t dist)
+{
+ th_plane_t *p, temp;
+
+ if (VectorLength(normal) < 0.5)
+ Error ("FloatPlane: bad normal");
+ // create a new plane
+ if (thworld.numplanes+2 > MAX_TH_PLANES)
+ Error ("MAX_TH_PLANES");
+
+ p = &thworld.planes[thworld.numplanes];
+ VectorCopy (normal, p->normal);
+ p->dist = dist;
+ p->type = (p+1)->type = TH_PlaneTypeForNormal (p->normal);
+ p->signbits = TH_PlaneSignBits(p->normal);
+
+ VectorSubtract (vec3_origin, normal, (p+1)->normal);
+ (p+1)->dist = -dist;
+ (p+1)->signbits = TH_PlaneSignBits((p+1)->normal);
+
+ thworld.numplanes += 2;
+
+ // allways put axial planes facing positive first
+ if (p->type < 3)
+ {
+ if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0)
+ {
+ // flip order
+ temp = *p;
+ *p = *(p+1);
+ *(p+1) = temp;
+
+ TH_AddPlaneToHash(p);
+ TH_AddPlaneToHash(p+1);
+ return thworld.numplanes - 1;
+ } //end if
+ } //end if
+
+ TH_AddPlaneToHash(p);
+ TH_AddPlaneToHash(p+1);
+ return thworld.numplanes - 2;
+} //end of the function TH_CreateFloatPlane
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void TH_SnapVector(vec3_t normal)
+{
+ int i;
+
+ for (i = 0; i < 3; i++)
+ {
+ if ( fabs(normal[i] - 1) < NORMAL_EPSILON )
+ {
+ VectorClear (normal);
+ normal[i] = 1;
+ break;
+ } //end if
+ if ( fabs(normal[i] - -1) < NORMAL_EPSILON )
+ {
+ VectorClear (normal);
+ normal[i] = -1;
+ break;
+ } //end if
+ } //end for
+} //end of the function TH_SnapVector
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void TH_SnapPlane(vec3_t normal, vec_t *dist)
+{
+ TH_SnapVector(normal);
+
+ if (fabs(*dist-Q_rint(*dist)) < DIST_EPSILON)
+ *dist = Q_rint(*dist);
+} //end of the function TH_SnapPlane
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TH_FindFloatPlane(vec3_t normal, vec_t dist)
+{
+ int i;
+ th_plane_t *p;
+ int hash, h;
+
+ TH_SnapPlane (normal, &dist);
+ hash = (int)fabs(dist) / 8;
+ hash &= (PLANEHASH_SIZE-1);
+
+ // search the border bins as well
+ for (i = -1; i <= 1; i++)
+ {
+ h = (hash+i)&(PLANEHASH_SIZE-1);
+ for (p = thworld.planehash[h]; p; p = p->hashnext)
+ {
+ if (TH_PlaneEqual(p, normal, dist))
+ {
+ return p - thworld.planes;
+ } //end if
+ } //end for
+ } //end for
+ return TH_CreateFloatPlane(normal, dist);
+} //end of the function TH_FindFloatPlane
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TH_PlaneFromPoints(int v1, int v2, int v3)
+{
+ vec3_t t1, t2, normal;
+ vec_t dist;
+ float *p0, *p1, *p2;
+
+ p0 = thworld.vertexes[v1].v;
+ p1 = thworld.vertexes[v2].v;
+ p2 = thworld.vertexes[v3].v;
+
+ VectorSubtract(p0, p1, t1);
+ VectorSubtract(p2, p1, t2);
+ CrossProduct(t1, t2, normal);
+ VectorNormalize(normal);
+
+ dist = DotProduct(p0, normal);
+
+ return TH_FindFloatPlane(normal, dist);
+} //end of the function TH_PlaneFromPoints
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void TH_AddEdgeUser(int edgenum)
+{
+ th_edge_t *edge;
+
+ edge = &thworld.edges[abs(edgenum)];
+ //increase edge user count
+ edge->usercount++;
+ //increase vertex user count as well
+ thworld.vertexes[edge->v[0]].usercount++;
+ thworld.vertexes[edge->v[1]].usercount++;
+} //end of the function TH_AddEdgeUser
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void TH_RemoveEdgeUser(int edgenum)
+{
+ th_edge_t *edge;
+
+ edge = &thworld.edges[abs(edgenum)];
+ //decrease edge user count
+ edge->usercount--;
+ //decrease vertex user count as well
+ thworld.vertexes[edge->v[0]].usercount--;
+ thworld.vertexes[edge->v[1]].usercount--;
+} //end of the function TH_RemoveEdgeUser
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void TH_FreeTriangleEdges(th_triangle_t *tri)
+{
+ int i;
+
+ for (i = 0; i < 3; i++)
+ {
+ TH_RemoveEdgeUser(abs(tri->edges[i]));
+ } //end for
+} //end of the function TH_FreeTriangleEdges
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+unsigned TH_HashVec(vec3_t vec)
+{
+ int x, y;
+
+ x = (MAX_MAP_BOUNDS + (int)(vec[0]+0.5)) >> VERTEXHASH_SHIFT;
+ y = (MAX_MAP_BOUNDS + (int)(vec[1]+0.5)) >> VERTEXHASH_SHIFT;
+
+ if (x < 0 || x >= VERTEXHASH_SIZE || y < 0 || y >= VERTEXHASH_SIZE)
+ Error("HashVec: point %f %f %f outside valid range", vec[0], vec[1], vec[2]);
+
+ return y*VERTEXHASH_SIZE + x;
+} //end of the function TH_HashVec
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TH_FindVertex(vec3_t v)
+{
+ int i, h;
+ th_vertex_t *vertex;
+ 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 = TH_HashVec(vert);
+
+ for (vertex = thworld.vertexhash[h]; vertex; vertex = vertex->hashnext)
+ {
+ if (fabs(vertex->v[0] - vert[0]) < VERTEX_EPSILON &&
+ fabs(vertex->v[1] - vert[1]) < VERTEX_EPSILON &&
+ fabs(vertex->v[2] - vert[2]) < VERTEX_EPSILON)
+ {
+ return vertex - thworld.vertexes;
+ } //end if
+ } //end for
+ return 0;
+} //end of the function TH_FindVertex
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void TH_AddVertexToHash(th_vertex_t *vertex)
+{
+ int hashvalue;
+
+ hashvalue = TH_HashVec(vertex->v);
+ vertex->hashnext = thworld.vertexhash[hashvalue];
+ thworld.vertexhash[hashvalue] = vertex;
+} //end of the function TH_AddVertexToHash
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TH_CreateVertex(vec3_t v)
+{
+ if (thworld.numvertexes == 0) thworld.numvertexes = 1;
+ if (thworld.numvertexes >= MAX_TH_VERTEXES)
+ Error("MAX_TH_VERTEXES");
+ VectorCopy(v, thworld.vertexes[thworld.numvertexes].v);
+ thworld.vertexes[thworld.numvertexes].usercount = 0;
+ TH_AddVertexToHash(&thworld.vertexes[thworld.numvertexes]);
+ thworld.numvertexes++;
+ return thworld.numvertexes-1;
+} //end of the function TH_CreateVertex
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TH_FindOrCreateVertex(vec3_t v)
+{
+ int vertexnum;
+
+ vertexnum = TH_FindVertex(v);
+ if (!vertexnum) vertexnum = TH_CreateVertex(v);
+ return vertexnum;
+} //end of the function TH_FindOrCreateVertex
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TH_FindEdge(int v1, int v2)
+{
+ int hashvalue;
+ th_edge_t *edge;
+
+ hashvalue = (v1 + v2) & (EDGEHASH_SIZE-1);
+
+ for (edge = thworld.edgehash[hashvalue]; edge; edge = edge->hashnext)
+ {
+ if (edge->v[0] == v1 && edge->v[1] == v2) return edge - thworld.edges;
+ if (edge->v[1] == v1 && edge->v[0] == v2) return -(edge - thworld.edges);
+ } //end for
+ return 0;
+} //end of the function TH_FindEdge
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void TH_AddEdgeToHash(th_edge_t *edge)
+{
+ int hashvalue;
+
+ hashvalue = (edge->v[0] + edge->v[1]) & (EDGEHASH_SIZE-1);
+ edge->hashnext = thworld.edgehash[hashvalue];
+ thworld.edgehash[hashvalue] = edge;
+} //end of the function TH_AddEdgeToHash
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TH_CreateEdge(int v1, int v2)
+{
+ th_edge_t *edge;
+
+ if (thworld.numedges == 0) thworld.numedges = 1;
+ if (thworld.numedges >= MAX_TH_EDGES)
+ Error("MAX_TH_EDGES");
+ edge = &thworld.edges[thworld.numedges++];
+ edge->v[0] = v1;
+ edge->v[1] = v2;
+ TH_AddEdgeToHash(edge);
+ return thworld.numedges-1;
+} //end of the function TH_CreateEdge
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TH_FindOrCreateEdge(int v1, int v2)
+{
+ int edgenum;
+
+ edgenum = TH_FindEdge(v1, v2);
+ if (!edgenum) edgenum = TH_CreateEdge(v1, v2);
+ return edgenum;
+} //end of the function TH_FindOrCreateEdge
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TH_FindTriangle(int verts[3])
+{
+ int i, hashvalue, edges[3];
+ th_triangle_t *tri;
+
+ for (i = 0; i < 3; i++)
+ {
+ edges[i] = TH_FindEdge(verts[i], verts[(i+1)%3]);
+ if (!edges[i]) return false;
+ } //end for
+ hashvalue = (abs(edges[0]) + abs(edges[1]) + abs(edges[2])) & (TRIANGLEHASH_SIZE-1);
+ for (tri = thworld.trianglehash[hashvalue]; tri; tri = tri->next)
+ {
+ for (i = 0; i < 3; i++)
+ {
+ if (abs(tri->edges[i]) != abs(edges[0]) &&
+ abs(tri->edges[i]) != abs(edges[1]) &&
+ abs(tri->edges[i]) != abs(edges[2])) break;
+ } //end for
+ if (i >= 3) return tri - thworld.triangles;
+ } //end for
+ return 0;
+} //end of the function TH_FindTriangle
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void TH_AddTriangleToHash(th_triangle_t *tri)
+{
+ int hashvalue;
+
+ hashvalue = (abs(tri->edges[0]) + abs(tri->edges[1]) + abs(tri->edges[2])) & (TRIANGLEHASH_SIZE-1);
+ tri->hashnext = thworld.trianglehash[hashvalue];
+ thworld.trianglehash[hashvalue] = tri;
+} //end of the function TH_AddTriangleToHash
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void TH_CreateTrianglePlanes(int verts[3], th_plane_t *triplane, th_plane_t *planes)
+{
+ int i;
+ vec3_t dir;
+
+ for (i = 0; i < 3; i++)
+ {
+ VectorSubtract(thworld.vertexes[verts[(i+1)%3]].v, thworld.vertexes[verts[i]].v, dir);
+ CrossProduct(dir, triplane->normal, planes[i].normal);
+ VectorNormalize(planes[i].normal);
+ planes[i].dist = DotProduct(thworld.vertexes[verts[i]].v, planes[i].normal);
+ } //end for
+} //end of the function TH_CreateTrianglePlanes
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TH_CreateTriangle(int verts[3])
+{
+ th_triangle_t *tri;
+ int i;
+
+ if (thworld.numtriangles == 0) thworld.numtriangles = 1;
+ if (thworld.numtriangles >= MAX_TH_TRIANGLES)
+ Error("MAX_TH_TRIANGLES");
+ tri = &thworld.triangles[thworld.numtriangles++];
+ for (i = 0; i < 3; i++)
+ {
+ tri->edges[i] = TH_FindOrCreateEdge(verts[i], verts[(i+1)%3]);
+ TH_AddEdgeUser(abs(tri->edges[i]));
+ } //end for
+ tri->front = 0;
+ tri->back = 0;
+ tri->planenum = TH_PlaneFromPoints(verts[0], verts[1], verts[2]);
+ tri->prev = NULL;
+ tri->next = NULL;
+ tri->hashnext = NULL;
+ TH_CreateTrianglePlanes(verts, &thworld.planes[tri->planenum], tri->planes);
+ TH_AddTriangleToHash(tri);
+ ClearBounds(tri->mins, tri->maxs);
+ for (i = 0; i < 3; i++)
+ {
+ AddPointToBounds(thworld.vertexes[verts[i]].v, tri->mins, tri->maxs);
+ } //end for
+ return thworld.numtriangles-1;
+} //end of the function TH_CreateTriangle
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TH_CreateTetrahedron(int triangles[4])
+{
+ th_tetrahedron_t *tetrahedron;
+ int i;
+
+ if (thworld.numtetrahedrons == 0) thworld.numtetrahedrons = 1;
+ if (thworld.numtetrahedrons >= MAX_TH_TETRAHEDRONS)
+ Error("MAX_TH_TETRAHEDRONS");
+ tetrahedron = &thworld.tetrahedrons[thworld.numtetrahedrons++];
+ for (i = 0; i < 4; i++)
+ {
+ tetrahedron->triangles[i] = triangles[i];
+ if (thworld.triangles[abs(triangles[i])].front)
+ {
+ thworld.triangles[abs(triangles[i])].back = thworld.numtetrahedrons-1;
+ } //end if
+ else
+ {
+ thworld.triangles[abs(triangles[i])].front = thworld.numtetrahedrons-1;
+ } //end else
+ } //end for
+ tetrahedron->volume = 0;
+ return thworld.numtetrahedrons-1;
+} //end of the function TH_CreateTetrahedron
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TH_IntersectTrianglePlanes(int v1, int v2, th_plane_t *triplane, th_plane_t *planes)
+{
+ float *p1, *p2, front, back, frac, d;
+ int i, side, lastside;
+ vec3_t mid;
+
+ p1 = thworld.vertexes[v1].v;
+ p2 = thworld.vertexes[v2].v;
+
+ front = DotProduct(p1, triplane->normal) - triplane->dist;
+ back = DotProduct(p2, triplane->normal) - triplane->dist;
+ //if both points at the same side of the plane
+ if (front < 0.1 && back < 0.1) return false;
+ if (front > -0.1 && back > -0.1) return false;
+ //
+ frac = front/(front-back);
+ mid[0] = p1[0] + (p2[0] - p1[0]) * frac;
+ mid[1] = p1[1] + (p2[1] - p1[1]) * frac;
+ mid[2] = p1[2] + (p2[2] - p1[2]) * frac;
+ //if the mid point is at the same side of all the tri bounding planes
+ lastside = 0;
+ for (i = 0; i < 3; i++)
+ {
+ d = DotProduct(mid, planes[i].normal) - planes[i].dist;
+ side = d < 0;
+ if (i && side != lastside) return false;
+ lastside = side;
+ } //end for
+ return true;
+} //end of the function TH_IntersectTrianglePlanes
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TH_OutsideBoundingBox(int v1, int v2, vec3_t mins, vec3_t maxs)
+{
+ float *p1, *p2;
+ int i;
+
+ p1 = thworld.vertexes[v1].v;
+ p2 = thworld.vertexes[v2].v;
+ //if both points are at the outer side of one of the bounding box planes
+ for (i = 0; i < 3; i++)
+ {
+ if (p1[i] < mins[i] && p2[i] < mins[i]) return true;
+ if (p1[i] > maxs[i] && p2[i] > maxs[i]) return true;
+ } //end for
+ return false;
+} //end of the function TH_OutsideBoundingBox
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TH_TryEdge(int v1, int v2)
+{
+ int i, j, v;
+ th_plane_t *plane;
+ th_triangle_t *tri;
+
+ //if the edge already exists it must be valid
+ if (TH_FindEdge(v1, v2)) return true;
+ //test the edge with all existing triangles
+ for (i = 1; i < thworld.numtriangles; i++)
+ {
+ tri = &thworld.triangles[i];
+ //if triangle is enclosed by two tetrahedrons we don't have to test it
+ //because the edge always has to go through another triangle of those
+ //tetrahedrons first to reach the enclosed triangle
+ if (tri->front && tri->back) continue;
+ //if the edges is totally outside the triangle bounding box
+ if (TH_OutsideBoundingBox(v1, v2, tri->mins, tri->maxs)) continue;
+ //if one of the edge vertexes is used by this triangle
+ for (j = 0; j < 3; j++)
+ {
+ v = thworld.edges[abs(tri->edges[j])].v[tri->edges[j] < 0];
+ if (v == v1 || v == v2) break;
+ } //end for
+ if (j < 3) continue;
+ //get the triangle plane
+ plane = &thworld.planes[tri->planenum];
+ //if the edge intersects with a triangle then it's not valid
+ if (TH_IntersectTrianglePlanes(v1, v2, plane, tri->planes)) return false;
+ } //end for
+ return true;
+} //end of the function TH_TryEdge
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TH_TryTriangle(int verts[3])
+{
+ th_plane_t planes[3], triplane;
+ vec3_t t1, t2;
+ float *p0, *p1, *p2;
+ int i, j;
+
+ p0 = thworld.vertexes[verts[0]].v;
+ p1 = thworld.vertexes[verts[1]].v;
+ p2 = thworld.vertexes[verts[2]].v;
+
+ VectorSubtract(p0, p1, t1);
+ VectorSubtract(p2, p1, t2);
+ CrossProduct(t1, t2, triplane.normal);
+ VectorNormalize(triplane.normal);
+ triplane.dist = DotProduct(p0, triplane.normal);
+ //
+ TH_CreateTrianglePlanes(verts, &triplane, planes);
+ //test if any existing edge intersects with this triangle
+ for (i = 1; i < thworld.numedges; i++)
+ {
+ //if the edge is only used by triangles with tetrahedrons at both sides
+ if (!thworld.edges[i].usercount) continue;
+ //if one of the triangle vertexes is used by this edge
+ for (j = 0; j < 3; j++)
+ {
+ if (verts[j] == thworld.edges[j].v[0] ||
+ verts[j] == thworld.edges[j].v[1]) break;
+ } //end for
+ if (j < 3) continue;
+ //if this edge intersects with the triangle
+ if (TH_IntersectTrianglePlanes(thworld.edges[i].v[0], thworld.edges[i].v[1], &triplane, planes)) return false;
+ } //end for
+ return true;
+} //end of the function TH_TryTriangle
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void TH_AddTriangleToList(th_triangle_t **trianglelist, th_triangle_t *tri)
+{
+ tri->prev = NULL;
+ tri->next = *trianglelist;
+ if (*trianglelist) (*trianglelist)->prev = tri;
+ *trianglelist = tri;
+} //end of the function TH_AddTriangleToList
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void TH_RemoveTriangleFromList(th_triangle_t **trianglelist, th_triangle_t *tri)
+{
+ if (tri->next) tri->next->prev = tri->prev;
+ if (tri->prev) tri->prev->next = tri->next;
+ else *trianglelist = tri->next;
+} //end of the function TH_RemoveTriangleFromList
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TH_FindTetrahedron1(th_triangle_t *tri, int *triangles)
+{
+ int i, j, edgenum, side, v1, v2, v3, v4;
+ int verts1[3], verts2[3];
+ th_triangle_t *tri2;
+
+ //find another triangle with a shared edge
+ for (tri2 = tri->next; tri2; tri2 = tri2->next)
+ {
+ //if the triangles are in the same plane
+ if ((tri->planenum & ~1) == (tri2->planenum & ~1)) continue;
+ //try to find a shared edge
+ for (i = 0; i < 3; i++)
+ {
+ edgenum = abs(tri->edges[i]);
+ for (j = 0; j < 3; j++)
+ {
+ if (edgenum == abs(tri2->edges[j])) break;
+ } //end for
+ if (j < 3) break;
+ } //end for
+ //if the triangles have a shared edge
+ if (i < 3)
+ {
+ edgenum = tri->edges[(i+1)%3];
+ if (edgenum < 0) v1 = thworld.edges[abs(edgenum)].v[0];
+ else v1 = thworld.edges[edgenum].v[1];
+ edgenum = tri2->edges[(j+1)%3];
+ if (edgenum < 0) v2 = thworld.edges[abs(edgenum)].v[0];
+ else v2 = thworld.edges[edgenum].v[1];
+ //try the new edge
+ if (TH_TryEdge(v1, v2))
+ {
+ edgenum = tri->edges[i];
+ side = edgenum < 0;
+ //get the vertexes of the shared edge
+ v3 = thworld.edges[abs(edgenum)].v[side];
+ v4 = thworld.edges[abs(edgenum)].v[!side];
+ //try the two new triangles
+ verts1[0] = v1;
+ verts1[1] = v2;
+ verts1[2] = v3;
+ triangles[2] = TH_FindTriangle(verts1);
+ if (triangles[2] || TH_TryTriangle(verts1))
+ {
+ verts2[0] = v2;
+ verts2[1] = v1;
+ verts2[2] = v4;
+ triangles[3] = TH_FindTriangle(verts2);
+ if (triangles[3] || TH_TryTriangle(verts2))
+ {
+ triangles[0] = tri - thworld.triangles;
+ triangles[1] = tri2 - thworld.triangles;
+ if (!triangles[2]) triangles[2] = TH_CreateTriangle(verts1);
+ if (!triangles[3]) triangles[3] = TH_CreateTriangle(verts2);
+ return true;
+ } //end if
+ } //end if
+ } //end if
+ } //end if
+ } //end for
+ return false;
+} //end of the function TH_FindTetrahedron
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TH_FindTetrahedron2(th_triangle_t *tri, int *triangles)
+{
+ int i, edgenum, v1, verts[3], triverts[3];
+ float d;
+ th_plane_t *plane;
+
+ //get the verts of this triangle
+ for (i = 0; i < 3; i++)
+ {
+ edgenum = tri->edges[i];
+ if (edgenum < 0) verts[i] = thworld.edges[abs(edgenum)].v[1];
+ else verts[i] = thworld.edges[edgenum].v[0];
+ } //end for
+ //
+ plane = &thworld.planes[tri->planenum];
+ for (v1 = 0; v1 < thworld.numvertexes; v1++)
+ {
+ //if the vertex is only used by triangles with tetrahedrons at both sides
+ if (!thworld.vertexes[v1].usercount) continue;
+ //check if the vertex is not coplanar with the triangle
+ d = DotProduct(thworld.vertexes[v1].v, plane->normal) - plane->dist;
+ if (fabs(d) < 1) continue;
+ //check if we can create edges from the triangle towards this new vertex
+ for (i = 0; i < 3; i++)
+ {
+ if (v1 == verts[i]) break;
+ if (!TH_TryEdge(v1, verts[i])) break;
+ } //end for
+ if (i < 3) continue;
+ //check if the triangles are valid
+ for (i = 0; i < 3; i++)
+ {
+ triverts[0] = v1;
+ triverts[1] = verts[i];
+ triverts[2] = verts[(i+1)%3];
+ //if the triangle already exists then it is valid
+ triangles[i] = TH_FindTriangle(triverts);
+ if (!triangles[i])
+ {
+ if (!TH_TryTriangle(triverts)) break;
+ } //end if
+ } //end for
+ if (i < 3) continue;
+ //create the tetrahedron triangles using the new vertex
+ for (i = 0; i < 3; i++)
+ {
+ if (!triangles[i])
+ {
+ triverts[0] = v1;
+ triverts[1] = verts[i];
+ triverts[2] = verts[(i+1)%3];
+ triangles[i] = TH_CreateTriangle(triverts);
+ } //end if
+ } //end for
+ //add the existing triangle
+ triangles[3] = tri - thworld.triangles;
+ //
+ return true;
+ } //end for
+ return false;
+} //end of the function TH_FindTetrahedron2
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void TH_TetrahedralDecomposition(th_triangle_t *triangles)
+{
+ int i, thtriangles[4], numtriangles;
+ th_triangle_t *donetriangles, *tri;
+
+ donetriangles = NULL;
+
+ /*
+ numtriangles = 0;
+ qprintf("%6d triangles", numtriangles);
+ for (tri = triangles; tri; tri = triangles)
+ {
+ qprintf("\r%6d", numtriangles++);
+ if (!TH_FindTetrahedron1(tri, thtriangles))
+ {
+// if (!TH_FindTetrahedron2(tri, thtriangles))
+ {
+// Error("triangle without tetrahedron");
+ TH_RemoveTriangleFromList(&triangles, tri);
+ continue;
+ } //end if
+ } //end if
+ //create a tetrahedron from the triangles
+ TH_CreateTetrahedron(thtriangles);
+ //
+ for (i = 0; i < 4; i++)
+ {
+ if (thworld.triangles[abs(thtriangles[i])].front &&
+ thworld.triangles[abs(thtriangles[i])].back)
+ {
+ TH_RemoveTriangleFromList(&triangles, &thworld.triangles[abs(thtriangles[i])]);
+ TH_AddTriangleToList(&donetriangles, &thworld.triangles[abs(thtriangles[i])]);
+ TH_FreeTriangleEdges(&thworld.triangles[abs(thtriangles[i])]);
+ } //end if
+ else
+ {
+ TH_AddTriangleToList(&triangles, &thworld.triangles[abs(thtriangles[i])]);
+ } //end else
+ } //end for
+ } //end for*/
+ qprintf("%6d tetrahedrons", thworld.numtetrahedrons);
+ do
+ {
+ do
+ {
+ numtriangles = 0;
+ for (i = 1; i < thworld.numtriangles; i++)
+ {
+ tri = &thworld.triangles[i];
+ if (tri->front && tri->back) continue;
+ //qprintf("\r%6d", numtriangles++);
+ if (!TH_FindTetrahedron1(tri, thtriangles))
+ {
+// if (!TH_FindTetrahedron2(tri, thtriangles))
+ {
+ continue;
+ } //end if
+ } //end if
+ numtriangles++;
+ //create a tetrahedron from the triangles
+ TH_CreateTetrahedron(thtriangles);
+ qprintf("\r%6d", thworld.numtetrahedrons);
+ } //end for
+ } while(numtriangles);
+ for (i = 1; i < thworld.numtriangles; i++)
+ {
+ tri = &thworld.triangles[i];
+ if (tri->front && tri->back) continue;
+ //qprintf("\r%6d", numtriangles++);
+// if (!TH_FindTetrahedron1(tri, thtriangles))
+ {
+ if (!TH_FindTetrahedron2(tri, thtriangles))
+ {
+ continue;
+ } //end if
+ } //end if
+ numtriangles++;
+ //create a tetrahedron from the triangles
+ TH_CreateTetrahedron(thtriangles);
+ qprintf("\r%6d", thworld.numtetrahedrons);
+ } //end for
+ } while(numtriangles);
+ //
+ numtriangles = 0;
+ for (i = 1; i < thworld.numtriangles; i++)
+ {
+ tri = &thworld.triangles[i];
+ if (!tri->front && !tri->back) numtriangles++;
+ } //end for
+ Log_Print("\r%6d triangles with front only\n", numtriangles);
+ Log_Print("\r%6d tetrahedrons\n", thworld.numtetrahedrons-1);
+} //end of the function TH_TetrahedralDecomposition
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void TH_AASFaceVertex(aas_face_t *face, int index, vec3_t vertex)
+{
+ int edgenum, side;
+
+ edgenum = aasworld.edgeindex[face->firstedge + index];
+ side = edgenum < 0;
+ VectorCopy(aasworld.vertexes[aasworld.edges[abs(edgenum)].v[side]], vertex);
+} //end of the function TH_AASFaceVertex
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TH_Colinear(float *v0, float *v1, float *v2)
+{
+ vec3_t t1, t2, vcross;
+ float d;
+
+ VectorSubtract(v1, v0, t1);
+ VectorSubtract(v2, v0, t2);
+ CrossProduct (t1, t2, vcross);
+ d = VectorLength( vcross );
+
+ // if cross product is zero point is colinear
+ if (d < 10)
+ {
+ return true;
+ } //end if
+ return false;
+} //end of the function TH_Colinear
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void TH_FaceCenter(aas_face_t *face, vec3_t center)
+{
+ int i, edgenum, side;
+ aas_edge_t *edge;
+
+ VectorClear(center);
+ for (i = 0; i < face->numedges; i++)
+ {
+ edgenum = abs(aasworld.edgeindex[face->firstedge + i]);
+ side = edgenum < 0;
+ edge = &aasworld.edges[abs(edgenum)];
+ VectorAdd(aasworld.vertexes[edge->v[side]], center, center);
+ } //end for
+ VectorScale(center, 1.0 / face->numedges, center);
+} //end of the function TH_FaceCenter
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+th_triangle_t *TH_CreateAASFaceTriangles(aas_face_t *face)
+{
+ int i, first, verts[3], trinum;
+ vec3_t p0, p1, p2, p3, p4, center;
+ th_triangle_t *tri, *triangles;
+
+ triangles = NULL;
+ //find three points that are not colinear
+ for (i = 0; i < face->numedges; i++)
+ {
+ TH_AASFaceVertex(face, (face->numedges + i-2)%face->numedges, p0);
+ TH_AASFaceVertex(face, (face->numedges + i-1)%face->numedges, p1);
+ TH_AASFaceVertex(face, (i )%face->numedges, p2);
+ if (TH_Colinear(p2, p0, p1)) continue;
+ TH_AASFaceVertex(face, (i+1)%face->numedges, p3);
+ TH_AASFaceVertex(face, (i+2)%face->numedges, p4);
+ if (TH_Colinear(p2, p3, p4)) continue;
+ break;
+ } //end for
+ //if there are three points that are not colinear
+ if (i < face->numedges)
+ {
+ //normal triangulation
+ first = i; //left and right most point of three non-colinear points
+ TH_AASFaceVertex(face, first, p0);
+ verts[0] = TH_FindOrCreateVertex(p0);
+ for (i = 1; i < face->numedges-1; i++)
+ {
+ TH_AASFaceVertex(face, (first+i )%face->numedges, p1);
+ TH_AASFaceVertex(face, (first+i+1)%face->numedges, p2);
+ verts[1] = TH_FindOrCreateVertex(p1);
+ verts[2] = TH_FindOrCreateVertex(p2);
+ trinum = TH_CreateTriangle(verts);
+ tri = &thworld.triangles[trinum];
+ tri->front = -1;
+ TH_AddTriangleToList(&triangles, tri);
+ } //end for
+ } //end if
+ else
+ {
+ //fan triangulation
+ TH_FaceCenter(face, center);
+ //
+ verts[0] = TH_FindOrCreateVertex(center);
+ for (i = 0; i < face->numedges; i++)
+ {
+ TH_AASFaceVertex(face, (i )%face->numedges, p1);
+ TH_AASFaceVertex(face, (i+1)%face->numedges, p2);
+ if (TH_Colinear(center, p1, p2)) continue;
+ verts[1] = TH_FindOrCreateVertex(p1);
+ verts[2] = TH_FindOrCreateVertex(p2);
+ trinum = TH_CreateTriangle(verts);
+ tri = &thworld.triangles[trinum];
+ tri->front = -1;
+ TH_AddTriangleToList(&triangles, tri);
+ } //end for
+ } //end else
+ return triangles;
+} //end of the function TH_CreateAASFaceTriangles
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+th_triangle_t *TH_AASToTriangleMesh(void)
+{
+ int i, j, facenum, otherareanum;
+ aas_face_t *face;
+ th_triangle_t *tri, *nexttri, *triangles;
+
+ triangles = NULL;
+ for (i = 1; i < aasworld.numareas; i++)
+ {
+ //if (!(aasworld.areasettings[i].presencetype & PRESENCE_NORMAL)) continue;
+ for (j = 0; j < aasworld.areas[i].numfaces; j++)
+ {
+ facenum = abs(aasworld.faceindex[aasworld.areas[i].firstface + j]);
+ face = &aasworld.faces[facenum];
+ //only convert solid faces into triangles
+ if (!(face->faceflags & FACE_SOLID))
+ {
+ /*
+ if (face->frontarea == i) otherareanum = face->backarea;
+ else otherareanum = face->frontarea;
+ if (aasworld.areasettings[otherareanum].presencetype & PRESENCE_NORMAL) continue;
+ */
+ continue;
+ } //end if
+ //
+ tri = TH_CreateAASFaceTriangles(face);
+ for (; tri; tri = nexttri)
+ {
+ nexttri = tri->next;
+ TH_AddTriangleToList(&triangles, tri);
+ } //end for
+ } //end if
+ } //end for
+ return triangles;
+} //end of the function TH_AASToTriangleMesh
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void TH_AASToTetrahedrons(char *filename)
+{
+ th_triangle_t *triangles, *tri, *lasttri;
+ int cnt;
+
+ if (!AAS_LoadAASFile(filename, 0, 0))
+ Error("couldn't load %s\n", filename);
+
+ //
+ TH_InitMaxTH();
+ //create a triangle mesh from the solid faces in the AAS file
+ triangles = TH_AASToTriangleMesh();
+ //
+ cnt = 0;
+ lasttri = NULL;
+ for (tri = triangles; tri; tri = tri->next)
+ {
+ cnt++;
+ if (tri->prev != lasttri) Log_Print("BAH\n");
+ lasttri = tri;
+ } //end for
+ Log_Print("%6d triangles\n", cnt);
+ //create a tetrahedral decomposition of the world bounded by triangles
+ TH_TetrahedralDecomposition(triangles);
+ //
+ TH_FreeMaxTH();
+} //end of the function TH_AASToTetrahedrons
diff --git a/code/bspc/tetrahedron.h b/code/bspc/tetrahedron.h
index 89003f1..2c6293d 100755
--- a/code/bspc/tetrahedron.h
+++ b/code/bspc/tetrahedron.h
@@ -1,24 +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 TH_AASToTetrahedrons(char *filename);
-
+/*
+===========================================================================
+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 TH_AASToTetrahedrons(char *filename);
+
diff --git a/code/bspc/textures.c b/code/bspc/textures.c
index ad6a8f5..76cc0fd 100755
--- a/code/bspc/textures.c
+++ b/code/bspc/textures.c
@@ -1,228 +1,228 @@
-/*
-===========================================================================
-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 "l_bsp_q2.h"
-
-int nummiptex;
-textureref_t textureref[MAX_MAP_TEXTURES];
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int FindMiptex (char *name)
-{
- int i;
- char path[1024];
- miptex_t *mt;
-
- for (i = 0; i < nummiptex; i++)
- {
- if (!strcmp (name, textureref[i].name))
- {
- return i;
- } //end if
- } //end for
- if (nummiptex == MAX_MAP_TEXTURES)
- Error ("MAX_MAP_TEXTURES");
- strcpy (textureref[i].name, name);
-
- // load the miptex to get the flags and values
- sprintf (path, "%stextures/%s.wal", gamedir, name);
- if (TryLoadFile (path, (void **)&mt) != -1)
- {
- textureref[i].value = LittleLong (mt->value);
- textureref[i].flags = LittleLong (mt->flags);
- textureref[i].contents = LittleLong (mt->contents);
- strcpy (textureref[i].animname, mt->animname);
- FreeMemory(mt);
- } //end if
- nummiptex++;
-
- if (textureref[i].animname[0])
- FindMiptex (textureref[i].animname);
-
- return i;
-} //end of the function FindMipTex
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-vec3_t baseaxis[18] =
-{
-{0,0,1}, {1,0,0}, {0,-1,0}, // floor
-{0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
-{1,0,0}, {0,1,0}, {0,0,-1}, // west wall
-{-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
-{0,1,0}, {1,0,0}, {0,0,-1}, // south wall
-{0,-1,0}, {1,0,0}, {0,0,-1} // north wall
-};
-
-void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv)
-{
- int bestaxis;
- vec_t dot,best;
- int i;
-
- best = 0;
- bestaxis = 0;
-
- for (i=0 ; i<6 ; i++)
- {
- dot = DotProduct (pln->normal, baseaxis[i*3]);
- if (dot > best)
- {
- best = dot;
- bestaxis = i;
- }
- }
-
- VectorCopy (baseaxis[bestaxis*3+1], xv);
- VectorCopy (baseaxis[bestaxis*3+2], yv);
-} //end of the function TextureAxisFromPlane
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int TexinfoForBrushTexture(plane_t *plane, brush_texture_t *bt, vec3_t origin)
-{
- vec3_t vecs[2];
- int sv, tv;
- vec_t ang, sinv, cosv;
- vec_t ns, nt;
- texinfo_t tx, *tc;
- int i, j, k;
- float shift[2];
- brush_texture_t anim;
- int mt;
-
- if (!bt->name[0])
- return 0;
-
- memset (&tx, 0, sizeof(tx));
- strcpy (tx.texture, bt->name);
-
- TextureAxisFromPlane(plane, vecs[0], vecs[1]);
-
- shift[0] = DotProduct (origin, vecs[0]);
- shift[1] = DotProduct (origin, vecs[1]);
-
- if (!bt->scale[0])
- bt->scale[0] = 1;
- if (!bt->scale[1])
- bt->scale[1] = 1;
-
-
-// rotate axis
- if (bt->rotate == 0)
- { sinv = 0 ; cosv = 1; }
- else if (bt->rotate == 90)
- { sinv = 1 ; cosv = 0; }
- else if (bt->rotate == 180)
- { sinv = 0 ; cosv = -1; }
- else if (bt->rotate == 270)
- { sinv = -1 ; cosv = 0; }
- else
- {
- ang = bt->rotate / 180 * Q_PI;
- sinv = sin(ang);
- cosv = cos(ang);
- }
-
- if (vecs[0][0])
- sv = 0;
- else if (vecs[0][1])
- sv = 1;
- else
- sv = 2;
-
- if (vecs[1][0])
- tv = 0;
- else if (vecs[1][1])
- tv = 1;
- else
- tv = 2;
-
- for (i=0 ; i<2 ; i++)
- {
- ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
- nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
- vecs[i][sv] = ns;
- vecs[i][tv] = nt;
- }
-
- for (i=0 ; i<2 ; i++)
- for (j=0 ; j<3 ; j++)
- tx.vecs[i][j] = vecs[i][j] / bt->scale[i];
-
- tx.vecs[0][3] = bt->shift[0] + shift[0];
- tx.vecs[1][3] = bt->shift[1] + shift[1];
- tx.flags = bt->flags;
- tx.value = bt->value;
-
- //
- // find the texinfo
- //
- tc = texinfo;
- for (i=0 ; i<numtexinfo ; i++, tc++)
- {
- if (tc->flags != tx.flags)
- continue;
- if (tc->value != tx.value)
- continue;
- for (j=0 ; j<2 ; j++)
- {
- if (strcmp (tc->texture, tx.texture))
- goto skip;
- for (k=0 ; k<4 ; k++)
- {
- if (tc->vecs[j][k] != tx.vecs[j][k])
- goto skip;
- }
- }
- return i;
-skip:;
- }
- *tc = tx;
- numtexinfo++;
-
- // load the next animation
- mt = FindMiptex (bt->name);
- if (textureref[mt].animname[0])
- {
- anim = *bt;
- strcpy (anim.name, textureref[mt].animname);
- tc->nexttexinfo = TexinfoForBrushTexture (plane, &anim, origin);
- }
- else
- tc->nexttexinfo = -1;
-
-
- return i;
-} //end of the function TexinfoForBrushTexture
+/*
+===========================================================================
+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 "l_bsp_q2.h"
+
+int nummiptex;
+textureref_t textureref[MAX_MAP_TEXTURES];
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int FindMiptex (char *name)
+{
+ int i;
+ char path[1024];
+ miptex_t *mt;
+
+ for (i = 0; i < nummiptex; i++)
+ {
+ if (!strcmp (name, textureref[i].name))
+ {
+ return i;
+ } //end if
+ } //end for
+ if (nummiptex == MAX_MAP_TEXTURES)
+ Error ("MAX_MAP_TEXTURES");
+ strcpy (textureref[i].name, name);
+
+ // load the miptex to get the flags and values
+ sprintf (path, "%stextures/%s.wal", gamedir, name);
+ if (TryLoadFile (path, (void **)&mt) != -1)
+ {
+ textureref[i].value = LittleLong (mt->value);
+ textureref[i].flags = LittleLong (mt->flags);
+ textureref[i].contents = LittleLong (mt->contents);
+ strcpy (textureref[i].animname, mt->animname);
+ FreeMemory(mt);
+ } //end if
+ nummiptex++;
+
+ if (textureref[i].animname[0])
+ FindMiptex (textureref[i].animname);
+
+ return i;
+} //end of the function FindMipTex
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+vec3_t baseaxis[18] =
+{
+{0,0,1}, {1,0,0}, {0,-1,0}, // floor
+{0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
+{1,0,0}, {0,1,0}, {0,0,-1}, // west wall
+{-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
+{0,1,0}, {1,0,0}, {0,0,-1}, // south wall
+{0,-1,0}, {1,0,0}, {0,0,-1} // north wall
+};
+
+void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv)
+{
+ int bestaxis;
+ vec_t dot,best;
+ int i;
+
+ best = 0;
+ bestaxis = 0;
+
+ for (i=0 ; i<6 ; i++)
+ {
+ dot = DotProduct (pln->normal, baseaxis[i*3]);
+ if (dot > best)
+ {
+ best = dot;
+ bestaxis = i;
+ }
+ }
+
+ VectorCopy (baseaxis[bestaxis*3+1], xv);
+ VectorCopy (baseaxis[bestaxis*3+2], yv);
+} //end of the function TextureAxisFromPlane
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int TexinfoForBrushTexture(plane_t *plane, brush_texture_t *bt, vec3_t origin)
+{
+ vec3_t vecs[2];
+ int sv, tv;
+ vec_t ang, sinv, cosv;
+ vec_t ns, nt;
+ texinfo_t tx, *tc;
+ int i, j, k;
+ float shift[2];
+ brush_texture_t anim;
+ int mt;
+
+ if (!bt->name[0])
+ return 0;
+
+ memset (&tx, 0, sizeof(tx));
+ strcpy (tx.texture, bt->name);
+
+ TextureAxisFromPlane(plane, vecs[0], vecs[1]);
+
+ shift[0] = DotProduct (origin, vecs[0]);
+ shift[1] = DotProduct (origin, vecs[1]);
+
+ if (!bt->scale[0])
+ bt->scale[0] = 1;
+ if (!bt->scale[1])
+ bt->scale[1] = 1;
+
+
+// rotate axis
+ if (bt->rotate == 0)
+ { sinv = 0 ; cosv = 1; }
+ else if (bt->rotate == 90)
+ { sinv = 1 ; cosv = 0; }
+ else if (bt->rotate == 180)
+ { sinv = 0 ; cosv = -1; }
+ else if (bt->rotate == 270)
+ { sinv = -1 ; cosv = 0; }
+ else
+ {
+ ang = bt->rotate / 180 * Q_PI;
+ sinv = sin(ang);
+ cosv = cos(ang);
+ }
+
+ if (vecs[0][0])
+ sv = 0;
+ else if (vecs[0][1])
+ sv = 1;
+ else
+ sv = 2;
+
+ if (vecs[1][0])
+ tv = 0;
+ else if (vecs[1][1])
+ tv = 1;
+ else
+ tv = 2;
+
+ for (i=0 ; i<2 ; i++)
+ {
+ ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
+ nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
+ vecs[i][sv] = ns;
+ vecs[i][tv] = nt;
+ }
+
+ for (i=0 ; i<2 ; i++)
+ for (j=0 ; j<3 ; j++)
+ tx.vecs[i][j] = vecs[i][j] / bt->scale[i];
+
+ tx.vecs[0][3] = bt->shift[0] + shift[0];
+ tx.vecs[1][3] = bt->shift[1] + shift[1];
+ tx.flags = bt->flags;
+ tx.value = bt->value;
+
+ //
+ // find the texinfo
+ //
+ tc = texinfo;
+ for (i=0 ; i<numtexinfo ; i++, tc++)
+ {
+ if (tc->flags != tx.flags)
+ continue;
+ if (tc->value != tx.value)
+ continue;
+ for (j=0 ; j<2 ; j++)
+ {
+ if (strcmp (tc->texture, tx.texture))
+ goto skip;
+ for (k=0 ; k<4 ; k++)
+ {
+ if (tc->vecs[j][k] != tx.vecs[j][k])
+ goto skip;
+ }
+ }
+ return i;
+skip:;
+ }
+ *tc = tx;
+ numtexinfo++;
+
+ // load the next animation
+ mt = FindMiptex (bt->name);
+ if (textureref[mt].animname[0])
+ {
+ anim = *bt;
+ strcpy (anim.name, textureref[mt].animname);
+ tc->nexttexinfo = TexinfoForBrushTexture (plane, &anim, origin);
+ }
+ else
+ tc->nexttexinfo = -1;
+
+
+ return i;
+} //end of the function TexinfoForBrushTexture
diff --git a/code/bspc/tree.c b/code/bspc/tree.c
index 3d2ee9c..bc3cb8e 100755
--- a/code/bspc/tree.c
+++ b/code/bspc/tree.c
@@ -1,283 +1,283 @@
-/*
-===========================================================================
-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"
-
-extern int c_nodes;
-int c_pruned;
-int freedtreemem = 0;
-
-void RemovePortalFromNode (portal_t *portal, node_t *l);
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-node_t *NodeForPoint (node_t *node, vec3_t origin)
-{
- plane_t *plane;
- vec_t d;
-
- while (node->planenum != PLANENUM_LEAF)
- {
- plane = &mapplanes[node->planenum];
- d = DotProduct (origin, plane->normal) - plane->dist;
- if (d >= 0)
- node = node->children[0];
- else
- node = node->children[1];
- }
- return node;
-} //end of the function NodeForPoint
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Tree_FreePortals_r (node_t *node)
-{
- portal_t *p, *nextp;
- int s;
-
- // free children
- if (node->planenum != PLANENUM_LEAF)
- {
- Tree_FreePortals_r(node->children[0]);
- Tree_FreePortals_r(node->children[1]);
- }
-
- // free portals
- for (p = node->portals; p; p = nextp)
- {
- s = (p->nodes[1] == node);
- nextp = p->next[s];
-
- RemovePortalFromNode (p, p->nodes[!s]);
-#ifdef ME
- if (p->winding) freedtreemem += MemorySize(p->winding);
- freedtreemem += MemorySize(p);
-#endif //ME
- FreePortal(p);
- }
- node->portals = NULL;
-} //end of the function Tree_FreePortals_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Tree_Free_r (node_t *node)
-{
-// face_t *f, *nextf;
- bspbrush_t *brush, *nextbrush;
-
- //free children
- if (node->planenum != PLANENUM_LEAF)
- {
- Tree_Free_r (node->children[0]);
- Tree_Free_r (node->children[1]);
- } //end if
- //free bspbrushes
-// FreeBrushList (node->brushlist);
- for (brush = node->brushlist; brush; brush = nextbrush)
- {
- nextbrush = brush->next;
-#ifdef ME
- freedtreemem += MemorySize(brush);
-#endif //ME
- FreeBrush(brush);
- } //end for
- node->brushlist = NULL;
-
- /*
- NOTE: only used when creating Q2 bsp
- // free faces
- for (f = node->faces; f; f = nextf)
- {
- nextf = f->next;
-#ifdef ME
- if (f->w) freedtreemem += MemorySize(f->w);
- freedtreemem += sizeof(face_t);
-#endif //ME
- FreeFace(f);
- } //end for
- */
-
- // free the node
- if (node->volume)
- {
-#ifdef ME
- freedtreemem += MemorySize(node->volume);
-#endif //ME
- FreeBrush (node->volume);
- } //end if
-
- if (numthreads == 1) c_nodes--;
-#ifdef ME
- freedtreemem += MemorySize(node);
-#endif //ME
- FreeMemory(node);
-} //end of the function Tree_Free_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Tree_Free(tree_t *tree)
-{
- //if no tree just return
- if (!tree) return;
- //
- freedtreemem = 0;
- //
- Tree_FreePortals_r(tree->headnode);
- Tree_Free_r(tree->headnode);
-#ifdef ME
- freedtreemem += MemorySize(tree);
-#endif //ME
- FreeMemory(tree);
-#ifdef ME
- Log_Print("freed ");
- PrintMemorySize(freedtreemem);
- Log_Print(" of tree memory\n");
-#endif //ME
-} //end of the function Tree_Free
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-tree_t *Tree_Alloc(void)
-{
- tree_t *tree;
-
- tree = GetMemory(sizeof(*tree));
- memset (tree, 0, sizeof(*tree));
- ClearBounds (tree->mins, tree->maxs);
-
- return tree;
-} //end of the function Tree_Alloc
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Tree_Print_r (node_t *node, int depth)
-{
- int i;
- plane_t *plane;
- bspbrush_t *bb;
-
- for (i=0 ; i<depth ; i++)
- printf (" ");
- if (node->planenum == PLANENUM_LEAF)
- {
- if (!node->brushlist)
- printf ("NULL\n");
- else
- {
- for (bb=node->brushlist ; bb ; bb=bb->next)
- printf ("%i ", bb->original->brushnum);
- printf ("\n");
- }
- return;
- }
-
- plane = &mapplanes[node->planenum];
- printf ("#%i (%5.2f %5.2f %5.2f):%5.2f\n", node->planenum,
- plane->normal[0], plane->normal[1], plane->normal[2],
- plane->dist);
- Tree_Print_r (node->children[0], depth+1);
- Tree_Print_r (node->children[1], depth+1);
-} //end of the function Tree_Print_r
-//===========================================================================
-// NODES THAT DON'T SEPERATE DIFFERENT CONTENTS CAN BE PRUNED
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Tree_PruneNodes_r (node_t *node)
-{
- bspbrush_t *b, *next;
-
- if (node->planenum == PLANENUM_LEAF) return;
-
- Tree_PruneNodes_r (node->children[0]);
- Tree_PruneNodes_r (node->children[1]);
-
- if (create_aas)
- {
- if ((node->children[0]->contents & CONTENTS_LADDER) ||
- (node->children[1]->contents & CONTENTS_LADDER)) return;
- }
-
- if ((node->children[0]->contents & CONTENTS_SOLID)
- && (node->children[1]->contents & CONTENTS_SOLID))
- {
- if (node->faces)
- Error ("node->faces seperating CONTENTS_SOLID");
- if (node->children[0]->faces || node->children[1]->faces)
- Error ("!node->faces with children");
- // FIXME: free stuff
- node->planenum = PLANENUM_LEAF;
- node->contents = CONTENTS_SOLID;
- node->detail_seperator = false;
-
- if (node->brushlist)
- Error ("PruneNodes: node->brushlist");
- // combine brush lists
- node->brushlist = node->children[1]->brushlist;
-
- for (b = node->children[0]->brushlist; b; b = next)
- {
- next = b->next;
- b->next = node->brushlist;
- node->brushlist = b;
- } //end for
- //free the child nodes
- FreeMemory(node->children[0]);
- FreeMemory(node->children[1]);
- //two nodes are cut away
- c_pruned += 2;
- } //end if
-} //end of the function Tree_PruneNodes_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Tree_PruneNodes(node_t *node)
-{
- Log_Print("------- Prune Nodes --------\n");
- c_pruned = 0;
- Tree_PruneNodes_r(node);
- Log_Print("%5i pruned nodes\n", c_pruned);
-} //end of the function Tree_PruneNodes
+/*
+===========================================================================
+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"
+
+extern int c_nodes;
+int c_pruned;
+int freedtreemem = 0;
+
+void RemovePortalFromNode (portal_t *portal, node_t *l);
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+node_t *NodeForPoint (node_t *node, vec3_t origin)
+{
+ plane_t *plane;
+ vec_t d;
+
+ while (node->planenum != PLANENUM_LEAF)
+ {
+ plane = &mapplanes[node->planenum];
+ d = DotProduct (origin, plane->normal) - plane->dist;
+ if (d >= 0)
+ node = node->children[0];
+ else
+ node = node->children[1];
+ }
+ return node;
+} //end of the function NodeForPoint
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Tree_FreePortals_r (node_t *node)
+{
+ portal_t *p, *nextp;
+ int s;
+
+ // free children
+ if (node->planenum != PLANENUM_LEAF)
+ {
+ Tree_FreePortals_r(node->children[0]);
+ Tree_FreePortals_r(node->children[1]);
+ }
+
+ // free portals
+ for (p = node->portals; p; p = nextp)
+ {
+ s = (p->nodes[1] == node);
+ nextp = p->next[s];
+
+ RemovePortalFromNode (p, p->nodes[!s]);
+#ifdef ME
+ if (p->winding) freedtreemem += MemorySize(p->winding);
+ freedtreemem += MemorySize(p);
+#endif //ME
+ FreePortal(p);
+ }
+ node->portals = NULL;
+} //end of the function Tree_FreePortals_r
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Tree_Free_r (node_t *node)
+{
+// face_t *f, *nextf;
+ bspbrush_t *brush, *nextbrush;
+
+ //free children
+ if (node->planenum != PLANENUM_LEAF)
+ {
+ Tree_Free_r (node->children[0]);
+ Tree_Free_r (node->children[1]);
+ } //end if
+ //free bspbrushes
+// FreeBrushList (node->brushlist);
+ for (brush = node->brushlist; brush; brush = nextbrush)
+ {
+ nextbrush = brush->next;
+#ifdef ME
+ freedtreemem += MemorySize(brush);
+#endif //ME
+ FreeBrush(brush);
+ } //end for
+ node->brushlist = NULL;
+
+ /*
+ NOTE: only used when creating Q2 bsp
+ // free faces
+ for (f = node->faces; f; f = nextf)
+ {
+ nextf = f->next;
+#ifdef ME
+ if (f->w) freedtreemem += MemorySize(f->w);
+ freedtreemem += sizeof(face_t);
+#endif //ME
+ FreeFace(f);
+ } //end for
+ */
+
+ // free the node
+ if (node->volume)
+ {
+#ifdef ME
+ freedtreemem += MemorySize(node->volume);
+#endif //ME
+ FreeBrush (node->volume);
+ } //end if
+
+ if (numthreads == 1) c_nodes--;
+#ifdef ME
+ freedtreemem += MemorySize(node);
+#endif //ME
+ FreeMemory(node);
+} //end of the function Tree_Free_r
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Tree_Free(tree_t *tree)
+{
+ //if no tree just return
+ if (!tree) return;
+ //
+ freedtreemem = 0;
+ //
+ Tree_FreePortals_r(tree->headnode);
+ Tree_Free_r(tree->headnode);
+#ifdef ME
+ freedtreemem += MemorySize(tree);
+#endif //ME
+ FreeMemory(tree);
+#ifdef ME
+ Log_Print("freed ");
+ PrintMemorySize(freedtreemem);
+ Log_Print(" of tree memory\n");
+#endif //ME
+} //end of the function Tree_Free
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+tree_t *Tree_Alloc(void)
+{
+ tree_t *tree;
+
+ tree = GetMemory(sizeof(*tree));
+ memset (tree, 0, sizeof(*tree));
+ ClearBounds (tree->mins, tree->maxs);
+
+ return tree;
+} //end of the function Tree_Alloc
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Tree_Print_r (node_t *node, int depth)
+{
+ int i;
+ plane_t *plane;
+ bspbrush_t *bb;
+
+ for (i=0 ; i<depth ; i++)
+ printf (" ");
+ if (node->planenum == PLANENUM_LEAF)
+ {
+ if (!node->brushlist)
+ printf ("NULL\n");
+ else
+ {
+ for (bb=node->brushlist ; bb ; bb=bb->next)
+ printf ("%i ", bb->original->brushnum);
+ printf ("\n");
+ }
+ return;
+ }
+
+ plane = &mapplanes[node->planenum];
+ printf ("#%i (%5.2f %5.2f %5.2f):%5.2f\n", node->planenum,
+ plane->normal[0], plane->normal[1], plane->normal[2],
+ plane->dist);
+ Tree_Print_r (node->children[0], depth+1);
+ Tree_Print_r (node->children[1], depth+1);
+} //end of the function Tree_Print_r
+//===========================================================================
+// NODES THAT DON'T SEPERATE DIFFERENT CONTENTS CAN BE PRUNED
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Tree_PruneNodes_r (node_t *node)
+{
+ bspbrush_t *b, *next;
+
+ if (node->planenum == PLANENUM_LEAF) return;
+
+ Tree_PruneNodes_r (node->children[0]);
+ Tree_PruneNodes_r (node->children[1]);
+
+ if (create_aas)
+ {
+ if ((node->children[0]->contents & CONTENTS_LADDER) ||
+ (node->children[1]->contents & CONTENTS_LADDER)) return;
+ }
+
+ if ((node->children[0]->contents & CONTENTS_SOLID)
+ && (node->children[1]->contents & CONTENTS_SOLID))
+ {
+ if (node->faces)
+ Error ("node->faces seperating CONTENTS_SOLID");
+ if (node->children[0]->faces || node->children[1]->faces)
+ Error ("!node->faces with children");
+ // FIXME: free stuff
+ node->planenum = PLANENUM_LEAF;
+ node->contents = CONTENTS_SOLID;
+ node->detail_seperator = false;
+
+ if (node->brushlist)
+ Error ("PruneNodes: node->brushlist");
+ // combine brush lists
+ node->brushlist = node->children[1]->brushlist;
+
+ for (b = node->children[0]->brushlist; b; b = next)
+ {
+ next = b->next;
+ b->next = node->brushlist;
+ node->brushlist = b;
+ } //end for
+ //free the child nodes
+ FreeMemory(node->children[0]);
+ FreeMemory(node->children[1]);
+ //two nodes are cut away
+ c_pruned += 2;
+ } //end if
+} //end of the function Tree_PruneNodes_r
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Tree_PruneNodes(node_t *node)
+{
+ Log_Print("------- Prune Nodes --------\n");
+ c_pruned = 0;
+ Tree_PruneNodes_r(node);
+ Log_Print("%5i pruned nodes\n", c_pruned);
+} //end of the function Tree_PruneNodes
diff --git a/code/bspc/writebsp.c b/code/bspc/writebsp.c
index 38e9980..b6cf4e4 100755
--- a/code/bspc/writebsp.c
+++ b/code/bspc/writebsp.c
@@ -1,595 +1,595 @@
-/*
-===========================================================================
-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"
-
-int c_nofaces;
-int c_facenodes;
-
-
-/*
-=========================================================
-
-ONLY SAVE OUT PLANES THAT ARE ACTUALLY USED AS NODES
-
-=========================================================
-*/
-
-int planeused[MAX_MAP_PLANES];
-
-/*
-============
-EmitPlanes
-
-There is no oportunity to discard planes, because all of the original
-brushes will be saved in the map.
-============
-*/
-void EmitPlanes (void)
-{
- int i;
- dplane_t *dp;
- plane_t *mp;
- //ME: this causes a crash??
-// int planetranslate[MAX_MAP_PLANES];
-
- mp = mapplanes;
- for (i=0 ; i<nummapplanes ; i++, mp++)
- {
- dp = &dplanes[numplanes];
-// planetranslate[i] = numplanes;
- VectorCopy ( mp->normal, dp->normal);
- dp->dist = mp->dist;
- dp->type = mp->type;
- numplanes++;
- if (numplanes >= MAX_MAP_PLANES)
- Error("MAX_MAP_PLANES");
- }
-}
-
-
-//========================================================
-
-void EmitMarkFace (dleaf_t *leaf_p, face_t *f)
-{
- int i;
- int facenum;
-
- while (f->merged)
- f = f->merged;
-
- if (f->split[0])
- {
- EmitMarkFace (leaf_p, f->split[0]);
- EmitMarkFace (leaf_p, f->split[1]);
- return;
- }
-
- facenum = f->outputnumber;
- if (facenum == -1)
- return; // degenerate face
-
- if (facenum < 0 || facenum >= numfaces)
- Error ("Bad leafface");
- for (i=leaf_p->firstleafface ; i<numleaffaces ; i++)
- if (dleaffaces[i] == facenum)
- break; // merged out face
- if (i == numleaffaces)
- {
- if (numleaffaces >= MAX_MAP_LEAFFACES)
- Error ("MAX_MAP_LEAFFACES");
-
- dleaffaces[numleaffaces] = facenum;
- numleaffaces++;
- }
-
-}
-
-
-/*
-==================
-EmitLeaf
-==================
-*/
-void EmitLeaf (node_t *node)
-{
- dleaf_t *leaf_p;
- portal_t *p;
- int s;
- face_t *f;
- bspbrush_t *b;
- int i;
- int brushnum;
-
- // emit a leaf
- if (numleafs >= MAX_MAP_LEAFS)
- Error ("MAX_MAP_LEAFS");
-
- leaf_p = &dleafs[numleafs];
- numleafs++;
-
- leaf_p->contents = node->contents;
- leaf_p->cluster = node->cluster;
- leaf_p->area = node->area;
-
- //
- // write bounding box info
- //
- VectorCopy (node->mins, leaf_p->mins);
- VectorCopy (node->maxs, leaf_p->maxs);
-
- //
- // write the leafbrushes
- //
- leaf_p->firstleafbrush = numleafbrushes;
- for (b=node->brushlist ; b ; b=b->next)
- {
- if (numleafbrushes >= MAX_MAP_LEAFBRUSHES)
- Error ("MAX_MAP_LEAFBRUSHES");
-
- brushnum = b->original - mapbrushes;
- for (i=leaf_p->firstleafbrush ; i<numleafbrushes ; i++)
- if (dleafbrushes[i] == brushnum)
- break;
- if (i == numleafbrushes)
- {
- dleafbrushes[numleafbrushes] = brushnum;
- numleafbrushes++;
- }
- }
- leaf_p->numleafbrushes = numleafbrushes - leaf_p->firstleafbrush;
-
- //
- // write the leaffaces
- //
- if (leaf_p->contents & CONTENTS_SOLID)
- return; // no leaffaces in solids
-
- leaf_p->firstleafface = numleaffaces;
-
- for (p = node->portals ; p ; p = p->next[s])
- {
- s = (p->nodes[1] == node);
- f = p->face[s];
- if (!f)
- continue; // not a visible portal
-
- EmitMarkFace (leaf_p, f);
- }
-
- leaf_p->numleaffaces = numleaffaces - leaf_p->firstleafface;
-}
-
-
-/*
-==================
-EmitFace
-==================
-*/
-void EmitFace (face_t *f)
-{
- dface_t *df;
- int i;
- int e;
-
- f->outputnumber = -1;
-
- if (f->numpoints < 3)
- {
- return; // degenerated
- }
- if (f->merged || f->split[0] || f->split[1])
- {
- return; // not a final face
- }
-
- // save output number so leaffaces can use
- f->outputnumber = numfaces;
-
- if (numfaces >= MAX_MAP_FACES)
- Error ("numfaces == MAX_MAP_FACES");
- df = &dfaces[numfaces];
- numfaces++;
-
- // planenum is used by qlight, but not quake
- df->planenum = f->planenum & (~1);
- df->side = f->planenum & 1;
-
- df->firstedge = numsurfedges;
- df->numedges = f->numpoints;
- df->texinfo = f->texinfo;
- for (i=0 ; i<f->numpoints ; i++)
- {
-// e = GetEdge (f->pts[i], f->pts[(i+1)%f->numpoints], f);
- e = GetEdge2 (f->vertexnums[i], f->vertexnums[(i+1)%f->numpoints], f);
- if (numsurfedges >= MAX_MAP_SURFEDGES)
- Error ("numsurfedges == MAX_MAP_SURFEDGES");
- dsurfedges[numsurfedges] = e;
- numsurfedges++;
- }
-}
-
-/*
-============
-EmitDrawingNode_r
-============
-*/
-int EmitDrawNode_r (node_t *node)
-{
- dnode_t *n;
- face_t *f;
- int i;
-
- if (node->planenum == PLANENUM_LEAF)
- {
- EmitLeaf (node);
- return -numleafs;
- }
-
- // emit a node
- if (numnodes == MAX_MAP_NODES)
- Error ("MAX_MAP_NODES");
- n = &dnodes[numnodes];
- numnodes++;
-
- VectorCopy (node->mins, n->mins);
- VectorCopy (node->maxs, n->maxs);
-
- planeused[node->planenum]++;
- planeused[node->planenum^1]++;
-
- if (node->planenum & 1)
- Error ("WriteDrawNodes_r: odd planenum");
- n->planenum = node->planenum;
- n->firstface = numfaces;
-
- if (!node->faces)
- c_nofaces++;
- else
- c_facenodes++;
-
- for (f=node->faces ; f ; f=f->next)
- EmitFace (f);
-
- n->numfaces = numfaces - n->firstface;
-
-
- //
- // recursively output the other nodes
- //
- for (i=0 ; i<2 ; i++)
- {
- if (node->children[i]->planenum == PLANENUM_LEAF)
- {
- n->children[i] = -(numleafs + 1);
- EmitLeaf (node->children[i]);
- }
- else
- {
- n->children[i] = numnodes;
- EmitDrawNode_r (node->children[i]);
- }
- }
-
- return n - dnodes;
-}
-
-//=========================================================
-
-
-/*
-============
-WriteBSP
-============
-*/
-void WriteBSP (node_t *headnode)
-{
- int oldfaces;
-
- c_nofaces = 0;
- c_facenodes = 0;
-
- qprintf ("--- WriteBSP ---\n");
-
- oldfaces = numfaces;
- dmodels[nummodels].headnode = EmitDrawNode_r (headnode);
- EmitAreaPortals (headnode);
-
- qprintf ("%5i nodes with faces\n", c_facenodes);
- qprintf ("%5i nodes without faces\n", c_nofaces);
- qprintf ("%5i faces\n", numfaces-oldfaces);
-}
-
-//===========================================================
-
-/*
-============
-SetModelNumbers
-============
-*/
-void SetModelNumbers (void)
-{
- int i;
- int models;
- char value[10];
-
- models = 1;
- for (i=1 ; i<num_entities ; i++)
- {
- if (entities[i].numbrushes)
- {
- sprintf (value, "*%i", models);
- models++;
- SetKeyValue (&entities[i], "model", value);
- }
- }
-
-}
-
-/*
-============
-SetLightStyles
-============
-*/
-#define MAX_SWITCHED_LIGHTS 32
-void SetLightStyles (void)
-{
- int stylenum;
- char *t;
- entity_t *e;
- int i, j;
- char value[10];
- char lighttargets[MAX_SWITCHED_LIGHTS][64];
-
-
- // any light that is controlled (has a targetname)
- // must have a unique style number generated for it
-
- stylenum = 0;
- for (i=1 ; i<num_entities ; i++)
- {
- e = &entities[i];
-
- t = ValueForKey (e, "classname");
- if (Q_strncasecmp (t, "light", 5))
- continue;
- t = ValueForKey (e, "targetname");
- if (!t[0])
- continue;
-
- // find this targetname
- for (j=0 ; j<stylenum ; j++)
- if (!strcmp (lighttargets[j], t))
- break;
- if (j == stylenum)
- {
- if (stylenum == MAX_SWITCHED_LIGHTS)
- Error ("stylenum == MAX_SWITCHED_LIGHTS");
- strcpy (lighttargets[j], t);
- stylenum++;
- }
- sprintf (value, "%i", 32 + j);
- SetKeyValue (e, "style", value);
- }
-
-}
-
-//===========================================================
-
-/*
-============
-EmitBrushes
-============
-*/
-void EmitBrushes (void)
-{
- int i, j, bnum, s, x;
- dbrush_t *db;
- mapbrush_t *b;
- dbrushside_t *cp;
- vec3_t normal;
- vec_t dist;
- int planenum;
-
- numbrushsides = 0;
- numbrushes = nummapbrushes;
-
- for (bnum=0 ; bnum<nummapbrushes ; bnum++)
- {
- b = &mapbrushes[bnum];
- db = &dbrushes[bnum];
-
- db->contents = b->contents;
- db->firstside = numbrushsides;
- db->numsides = b->numsides;
- for (j=0 ; j<b->numsides ; j++)
- {
- if (numbrushsides == MAX_MAP_BRUSHSIDES)
- Error ("MAX_MAP_BRUSHSIDES");
- cp = &dbrushsides[numbrushsides];
- numbrushsides++;
- cp->planenum = b->original_sides[j].planenum;
- cp->texinfo = b->original_sides[j].texinfo;
- }
-
-#ifdef ME
- //for collision detection, bounding boxes are axial :)
- //brushes are convex so just add dot or line touching planes on the sides of
- //the brush parallell to the axis planes
-#endif
- // add any axis planes not contained in the brush to bevel off corners
- for (x=0 ; x<3 ; x++)
- for (s=-1 ; s<=1 ; s+=2)
- {
- // add the plane
- VectorCopy (vec3_origin, normal);
- normal[x] = s;
- if (s == -1)
- dist = -b->mins[x];
- else
- dist = b->maxs[x];
- planenum = FindFloatPlane (normal, dist);
- for (i=0 ; i<b->numsides ; i++)
- if (b->original_sides[i].planenum == planenum)
- break;
- if (i == b->numsides)
- {
- if (numbrushsides >= MAX_MAP_BRUSHSIDES)
- Error ("MAX_MAP_BRUSHSIDES");
-
- dbrushsides[numbrushsides].planenum = planenum;
- dbrushsides[numbrushsides].texinfo =
- dbrushsides[numbrushsides-1].texinfo;
- numbrushsides++;
- db->numsides++;
- }
- }
-
- }
-
-}
-
-//===========================================================
-
-/*
-==================
-BeginBSPFile
-==================
-*/
-void BeginBSPFile (void)
-{
- // these values may actually be initialized
- // if the file existed when loaded, so clear them explicitly
- nummodels = 0;
- numfaces = 0;
- numnodes = 0;
- numbrushsides = 0;
- numvertexes = 0;
- numleaffaces = 0;
- numleafbrushes = 0;
- numsurfedges = 0;
-
- // edge 0 is not used, because 0 can't be negated
- numedges = 1;
-
- // leave vertex 0 as an error
- numvertexes = 1;
-
- // leave leaf 0 as an error
- numleafs = 1;
- dleafs[0].contents = CONTENTS_SOLID;
-}
-
-
-/*
-============
-EndBSPFile
-============
-*/
-void EndBSPFile (void)
-{
-#if 0
- char path[1024];
- int len;
- byte *buf;
-#endif
-
-
- EmitBrushes ();
- EmitPlanes ();
- Q2_UnparseEntities ();
-
- // load the pop
-#if 0
- sprintf (path, "%s/pics/pop.lmp", gamedir);
- len = LoadFile (path, &buf);
- memcpy (dpop, buf, sizeof(dpop));
- FreeMemory(buf);
-#endif
-}
-
-
-/*
-==================
-BeginModel
-==================
-*/
-int firstmodleaf;
-extern int firstmodeledge;
-extern int firstmodelface;
-void BeginModel (void)
-{
- dmodel_t *mod;
- int start, end;
- mapbrush_t *b;
- int j;
- entity_t *e;
- vec3_t mins, maxs;
-
- if (nummodels == MAX_MAP_MODELS)
- Error ("MAX_MAP_MODELS");
- mod = &dmodels[nummodels];
-
- mod->firstface = numfaces;
-
- firstmodleaf = numleafs;
- firstmodeledge = numedges;
- firstmodelface = numfaces;
-
- //
- // bound the brushes
- //
- e = &entities[entity_num];
-
- start = e->firstbrush;
- end = start + e->numbrushes;
- ClearBounds (mins, maxs);
-
- for (j=start ; j<end ; j++)
- {
- b = &mapbrushes[j];
- if (!b->numsides)
- continue; // not a real brush (origin brush)
- AddPointToBounds (b->mins, mins, maxs);
- AddPointToBounds (b->maxs, mins, maxs);
- }
-
- VectorCopy (mins, mod->mins);
- VectorCopy (maxs, mod->maxs);
-}
-
-
-/*
-==================
-EndModel
-==================
-*/
-void EndModel (void)
-{
- dmodel_t *mod;
-
- mod = &dmodels[nummodels];
-
- mod->numfaces = numfaces - mod->firstface;
-
- nummodels++;
-}
-
+/*
+===========================================================================
+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"
+
+int c_nofaces;
+int c_facenodes;
+
+
+/*
+=========================================================
+
+ONLY SAVE OUT PLANES THAT ARE ACTUALLY USED AS NODES
+
+=========================================================
+*/
+
+int planeused[MAX_MAP_PLANES];
+
+/*
+============
+EmitPlanes
+
+There is no oportunity to discard planes, because all of the original
+brushes will be saved in the map.
+============
+*/
+void EmitPlanes (void)
+{
+ int i;
+ dplane_t *dp;
+ plane_t *mp;
+ //ME: this causes a crash??
+// int planetranslate[MAX_MAP_PLANES];
+
+ mp = mapplanes;
+ for (i=0 ; i<nummapplanes ; i++, mp++)
+ {
+ dp = &dplanes[numplanes];
+// planetranslate[i] = numplanes;
+ VectorCopy ( mp->normal, dp->normal);
+ dp->dist = mp->dist;
+ dp->type = mp->type;
+ numplanes++;
+ if (numplanes >= MAX_MAP_PLANES)
+ Error("MAX_MAP_PLANES");
+ }
+}
+
+
+//========================================================
+
+void EmitMarkFace (dleaf_t *leaf_p, face_t *f)
+{
+ int i;
+ int facenum;
+
+ while (f->merged)
+ f = f->merged;
+
+ if (f->split[0])
+ {
+ EmitMarkFace (leaf_p, f->split[0]);
+ EmitMarkFace (leaf_p, f->split[1]);
+ return;
+ }
+
+ facenum = f->outputnumber;
+ if (facenum == -1)
+ return; // degenerate face
+
+ if (facenum < 0 || facenum >= numfaces)
+ Error ("Bad leafface");
+ for (i=leaf_p->firstleafface ; i<numleaffaces ; i++)
+ if (dleaffaces[i] == facenum)
+ break; // merged out face
+ if (i == numleaffaces)
+ {
+ if (numleaffaces >= MAX_MAP_LEAFFACES)
+ Error ("MAX_MAP_LEAFFACES");
+
+ dleaffaces[numleaffaces] = facenum;
+ numleaffaces++;
+ }
+
+}
+
+
+/*
+==================
+EmitLeaf
+==================
+*/
+void EmitLeaf (node_t *node)
+{
+ dleaf_t *leaf_p;
+ portal_t *p;
+ int s;
+ face_t *f;
+ bspbrush_t *b;
+ int i;
+ int brushnum;
+
+ // emit a leaf
+ if (numleafs >= MAX_MAP_LEAFS)
+ Error ("MAX_MAP_LEAFS");
+
+ leaf_p = &dleafs[numleafs];
+ numleafs++;
+
+ leaf_p->contents = node->contents;
+ leaf_p->cluster = node->cluster;
+ leaf_p->area = node->area;
+
+ //
+ // write bounding box info
+ //
+ VectorCopy (node->mins, leaf_p->mins);
+ VectorCopy (node->maxs, leaf_p->maxs);
+
+ //
+ // write the leafbrushes
+ //
+ leaf_p->firstleafbrush = numleafbrushes;
+ for (b=node->brushlist ; b ; b=b->next)
+ {
+ if (numleafbrushes >= MAX_MAP_LEAFBRUSHES)
+ Error ("MAX_MAP_LEAFBRUSHES");
+
+ brushnum = b->original - mapbrushes;
+ for (i=leaf_p->firstleafbrush ; i<numleafbrushes ; i++)
+ if (dleafbrushes[i] == brushnum)
+ break;
+ if (i == numleafbrushes)
+ {
+ dleafbrushes[numleafbrushes] = brushnum;
+ numleafbrushes++;
+ }
+ }
+ leaf_p->numleafbrushes = numleafbrushes - leaf_p->firstleafbrush;
+
+ //
+ // write the leaffaces
+ //
+ if (leaf_p->contents & CONTENTS_SOLID)
+ return; // no leaffaces in solids
+
+ leaf_p->firstleafface = numleaffaces;
+
+ for (p = node->portals ; p ; p = p->next[s])
+ {
+ s = (p->nodes[1] == node);
+ f = p->face[s];
+ if (!f)
+ continue; // not a visible portal
+
+ EmitMarkFace (leaf_p, f);
+ }
+
+ leaf_p->numleaffaces = numleaffaces - leaf_p->firstleafface;
+}
+
+
+/*
+==================
+EmitFace
+==================
+*/
+void EmitFace (face_t *f)
+{
+ dface_t *df;
+ int i;
+ int e;
+
+ f->outputnumber = -1;
+
+ if (f->numpoints < 3)
+ {
+ return; // degenerated
+ }
+ if (f->merged || f->split[0] || f->split[1])
+ {
+ return; // not a final face
+ }
+
+ // save output number so leaffaces can use
+ f->outputnumber = numfaces;
+
+ if (numfaces >= MAX_MAP_FACES)
+ Error ("numfaces == MAX_MAP_FACES");
+ df = &dfaces[numfaces];
+ numfaces++;
+
+ // planenum is used by qlight, but not quake
+ df->planenum = f->planenum & (~1);
+ df->side = f->planenum & 1;
+
+ df->firstedge = numsurfedges;
+ df->numedges = f->numpoints;
+ df->texinfo = f->texinfo;
+ for (i=0 ; i<f->numpoints ; i++)
+ {
+// e = GetEdge (f->pts[i], f->pts[(i+1)%f->numpoints], f);
+ e = GetEdge2 (f->vertexnums[i], f->vertexnums[(i+1)%f->numpoints], f);
+ if (numsurfedges >= MAX_MAP_SURFEDGES)
+ Error ("numsurfedges == MAX_MAP_SURFEDGES");
+ dsurfedges[numsurfedges] = e;
+ numsurfedges++;
+ }
+}
+
+/*
+============
+EmitDrawingNode_r
+============
+*/
+int EmitDrawNode_r (node_t *node)
+{
+ dnode_t *n;
+ face_t *f;
+ int i;
+
+ if (node->planenum == PLANENUM_LEAF)
+ {
+ EmitLeaf (node);
+ return -numleafs;
+ }
+
+ // emit a node
+ if (numnodes == MAX_MAP_NODES)
+ Error ("MAX_MAP_NODES");
+ n = &dnodes[numnodes];
+ numnodes++;
+
+ VectorCopy (node->mins, n->mins);
+ VectorCopy (node->maxs, n->maxs);
+
+ planeused[node->planenum]++;
+ planeused[node->planenum^1]++;
+
+ if (node->planenum & 1)
+ Error ("WriteDrawNodes_r: odd planenum");
+ n->planenum = node->planenum;
+ n->firstface = numfaces;
+
+ if (!node->faces)
+ c_nofaces++;
+ else
+ c_facenodes++;
+
+ for (f=node->faces ; f ; f=f->next)
+ EmitFace (f);
+
+ n->numfaces = numfaces - n->firstface;
+
+
+ //
+ // recursively output the other nodes
+ //
+ for (i=0 ; i<2 ; i++)
+ {
+ if (node->children[i]->planenum == PLANENUM_LEAF)
+ {
+ n->children[i] = -(numleafs + 1);
+ EmitLeaf (node->children[i]);
+ }
+ else
+ {
+ n->children[i] = numnodes;
+ EmitDrawNode_r (node->children[i]);
+ }
+ }
+
+ return n - dnodes;
+}
+
+//=========================================================
+
+
+/*
+============
+WriteBSP
+============
+*/
+void WriteBSP (node_t *headnode)
+{
+ int oldfaces;
+
+ c_nofaces = 0;
+ c_facenodes = 0;
+
+ qprintf ("--- WriteBSP ---\n");
+
+ oldfaces = numfaces;
+ dmodels[nummodels].headnode = EmitDrawNode_r (headnode);
+ EmitAreaPortals (headnode);
+
+ qprintf ("%5i nodes with faces\n", c_facenodes);
+ qprintf ("%5i nodes without faces\n", c_nofaces);
+ qprintf ("%5i faces\n", numfaces-oldfaces);
+}
+
+//===========================================================
+
+/*
+============
+SetModelNumbers
+============
+*/
+void SetModelNumbers (void)
+{
+ int i;
+ int models;
+ char value[10];
+
+ models = 1;
+ for (i=1 ; i<num_entities ; i++)
+ {
+ if (entities[i].numbrushes)
+ {
+ sprintf (value, "*%i", models);
+ models++;
+ SetKeyValue (&entities[i], "model", value);
+ }
+ }
+
+}
+
+/*
+============
+SetLightStyles
+============
+*/
+#define MAX_SWITCHED_LIGHTS 32
+void SetLightStyles (void)
+{
+ int stylenum;
+ char *t;
+ entity_t *e;
+ int i, j;
+ char value[10];
+ char lighttargets[MAX_SWITCHED_LIGHTS][64];
+
+
+ // any light that is controlled (has a targetname)
+ // must have a unique style number generated for it
+
+ stylenum = 0;
+ for (i=1 ; i<num_entities ; i++)
+ {
+ e = &entities[i];
+
+ t = ValueForKey (e, "classname");
+ if (Q_strncasecmp (t, "light", 5))
+ continue;
+ t = ValueForKey (e, "targetname");
+ if (!t[0])
+ continue;
+
+ // find this targetname
+ for (j=0 ; j<stylenum ; j++)
+ if (!strcmp (lighttargets[j], t))
+ break;
+ if (j == stylenum)
+ {
+ if (stylenum == MAX_SWITCHED_LIGHTS)
+ Error ("stylenum == MAX_SWITCHED_LIGHTS");
+ strcpy (lighttargets[j], t);
+ stylenum++;
+ }
+ sprintf (value, "%i", 32 + j);
+ SetKeyValue (e, "style", value);
+ }
+
+}
+
+//===========================================================
+
+/*
+============
+EmitBrushes
+============
+*/
+void EmitBrushes (void)
+{
+ int i, j, bnum, s, x;
+ dbrush_t *db;
+ mapbrush_t *b;
+ dbrushside_t *cp;
+ vec3_t normal;
+ vec_t dist;
+ int planenum;
+
+ numbrushsides = 0;
+ numbrushes = nummapbrushes;
+
+ for (bnum=0 ; bnum<nummapbrushes ; bnum++)
+ {
+ b = &mapbrushes[bnum];
+ db = &dbrushes[bnum];
+
+ db->contents = b->contents;
+ db->firstside = numbrushsides;
+ db->numsides = b->numsides;
+ for (j=0 ; j<b->numsides ; j++)
+ {
+ if (numbrushsides == MAX_MAP_BRUSHSIDES)
+ Error ("MAX_MAP_BRUSHSIDES");
+ cp = &dbrushsides[numbrushsides];
+ numbrushsides++;
+ cp->planenum = b->original_sides[j].planenum;
+ cp->texinfo = b->original_sides[j].texinfo;
+ }
+
+#ifdef ME
+ //for collision detection, bounding boxes are axial :)
+ //brushes are convex so just add dot or line touching planes on the sides of
+ //the brush parallell to the axis planes
+#endif
+ // add any axis planes not contained in the brush to bevel off corners
+ for (x=0 ; x<3 ; x++)
+ for (s=-1 ; s<=1 ; s+=2)
+ {
+ // add the plane
+ VectorCopy (vec3_origin, normal);
+ normal[x] = s;
+ if (s == -1)
+ dist = -b->mins[x];
+ else
+ dist = b->maxs[x];
+ planenum = FindFloatPlane (normal, dist);
+ for (i=0 ; i<b->numsides ; i++)
+ if (b->original_sides[i].planenum == planenum)
+ break;
+ if (i == b->numsides)
+ {
+ if (numbrushsides >= MAX_MAP_BRUSHSIDES)
+ Error ("MAX_MAP_BRUSHSIDES");
+
+ dbrushsides[numbrushsides].planenum = planenum;
+ dbrushsides[numbrushsides].texinfo =
+ dbrushsides[numbrushsides-1].texinfo;
+ numbrushsides++;
+ db->numsides++;
+ }
+ }
+
+ }
+
+}
+
+//===========================================================
+
+/*
+==================
+BeginBSPFile
+==================
+*/
+void BeginBSPFile (void)
+{
+ // these values may actually be initialized
+ // if the file existed when loaded, so clear them explicitly
+ nummodels = 0;
+ numfaces = 0;
+ numnodes = 0;
+ numbrushsides = 0;
+ numvertexes = 0;
+ numleaffaces = 0;
+ numleafbrushes = 0;
+ numsurfedges = 0;
+
+ // edge 0 is not used, because 0 can't be negated
+ numedges = 1;
+
+ // leave vertex 0 as an error
+ numvertexes = 1;
+
+ // leave leaf 0 as an error
+ numleafs = 1;
+ dleafs[0].contents = CONTENTS_SOLID;
+}
+
+
+/*
+============
+EndBSPFile
+============
+*/
+void EndBSPFile (void)
+{
+#if 0
+ char path[1024];
+ int len;
+ byte *buf;
+#endif
+
+
+ EmitBrushes ();
+ EmitPlanes ();
+ Q2_UnparseEntities ();
+
+ // load the pop
+#if 0
+ sprintf (path, "%s/pics/pop.lmp", gamedir);
+ len = LoadFile (path, &buf);
+ memcpy (dpop, buf, sizeof(dpop));
+ FreeMemory(buf);
+#endif
+}
+
+
+/*
+==================
+BeginModel
+==================
+*/
+int firstmodleaf;
+extern int firstmodeledge;
+extern int firstmodelface;
+void BeginModel (void)
+{
+ dmodel_t *mod;
+ int start, end;
+ mapbrush_t *b;
+ int j;
+ entity_t *e;
+ vec3_t mins, maxs;
+
+ if (nummodels == MAX_MAP_MODELS)
+ Error ("MAX_MAP_MODELS");
+ mod = &dmodels[nummodels];
+
+ mod->firstface = numfaces;
+
+ firstmodleaf = numleafs;
+ firstmodeledge = numedges;
+ firstmodelface = numfaces;
+
+ //
+ // bound the brushes
+ //
+ e = &entities[entity_num];
+
+ start = e->firstbrush;
+ end = start + e->numbrushes;
+ ClearBounds (mins, maxs);
+
+ for (j=start ; j<end ; j++)
+ {
+ b = &mapbrushes[j];
+ if (!b->numsides)
+ continue; // not a real brush (origin brush)
+ AddPointToBounds (b->mins, mins, maxs);
+ AddPointToBounds (b->maxs, mins, maxs);
+ }
+
+ VectorCopy (mins, mod->mins);
+ VectorCopy (maxs, mod->maxs);
+}
+
+
+/*
+==================
+EndModel
+==================
+*/
+void EndModel (void)
+{
+ dmodel_t *mod;
+
+ mod = &dmodels[nummodels];
+
+ mod->numfaces = numfaces - mod->firstface;
+
+ nummodels++;
+}
+