--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
--- /dev/null
+# Microsoft Developer Studio Project File - Name="Unpack" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Java Virtual Machine Java Project" 0x0809
+
+CFG=Unpack - Java Virtual Machine Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "Unpack.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "Unpack.mak" CFG="Unpack - Java Virtual Machine Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "Unpack - Java Virtual Machine Release" (based on\
+ "Java Virtual Machine Java Project")
+!MESSAGE "Unpack - Java Virtual Machine Debug" (based on\
+ "Java Virtual Machine Java Project")
+!MESSAGE
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+JAVA=jvc.exe
+
+!IF "$(CFG)" == "Unpack - Java Virtual Machine Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ""
+# PROP BASE Intermediate_Dir ""
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Target_Dir ""
+# ADD BASE JAVA /O
+# ADD JAVA /O
+
+!ELSEIF "$(CFG)" == "Unpack - Java Virtual Machine Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ""
+# PROP BASE Intermediate_Dir ""
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Target_Dir ""
+# ADD BASE JAVA /g
+# ADD JAVA /g
+
+!ENDIF
+
+# Begin Target
+
+# Name "Unpack - Java Virtual Machine Release"
+# Name "Unpack - Java Virtual Machine Debug"
+# Begin Source File
+
+SOURCE=.\Unpack.java
+# End Source File
+# End Target
+# End Project
--- /dev/null
+Microsoft Developer Studio Workspace File, Format Version 5.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "Unpack"=.\Unpack.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
--- /dev/null
+/*
+===========================================================================
+Copyright (C) 1997-2006 Id Software, Inc.
+
+This file is part of Quake 2 Tools source code.
+
+Quake 2 Tools 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 2 Tools 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 Quake 2 Tools source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+/*
+ * Unpack -- a completely non-object oriented utility...
+ *
+ */
+
+import java.io.*;
+
+class Unpack {
+ static final int IDPAKHEADER = (('K'<<24)+('C'<<16)+('A'<<8)+'P');
+
+ static int intSwap(int i) {
+ int a, b, c, d;
+
+ a = i & 255;
+ b = (i >> 8) & 255;
+ c = (i >> 16) & 255;
+ d = (i >> 24) & 255;
+
+ return (a << 24) + (b << 16) + (c << 8) + d;
+ }
+
+ static boolean patternMatch (String pattern, String s) {
+ int index;
+ int remaining;
+
+ if (pattern.equals(s)) {
+ return true;
+ }
+
+ // fairly lame single wildcard matching
+ index = pattern.indexOf('*');
+ if (index == -1) {
+ return false;
+ }
+ if (!pattern.regionMatches(0, s, 0, index)) {
+ return false;
+ }
+
+ index += 1; // skip the *
+ remaining = pattern.length() - index;
+ if (s.length() < remaining) {
+ return false;
+ }
+
+ if (!pattern.regionMatches(index, s, s.length()-remaining, remaining)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ static void usage() {
+ System.out.println ("Usage: unpack <packfile> <match> <basedir>");
+ System.out.println (" or: unpack -list <packfile>");
+ System.out.println ("<match> may contain a single * wildcard");
+ System.exit (1);
+ }
+
+ public static void main (String[] args) {
+ int ident;
+ int dirofs;
+ int dirlen;
+ int i;
+ int numLumps;
+ byte[] name = new byte[56];
+ String nameString;
+ int filepos;
+ int filelen;
+ RandomAccessFile readLump;
+ DataInputStream directory;
+ String pakName;
+ String pattern;
+
+ if (args.length == 2) {
+ if (!args[0].equals("-list")) {
+ usage();
+ }
+ pakName = args[1];
+ pattern = null;
+ } else if (args.length == 3) {
+ pakName = args[0];
+ pattern = args[1];
+ } else {
+ pakName = null;
+ pattern = null;
+ usage ();
+ }
+
+ try {
+ // one stream to read the directory
+ directory = new DataInputStream(new FileInputStream(pakName));
+
+ // another to read lumps
+ readLump = new RandomAccessFile(pakName, "r");
+
+ // read the header
+ ident = intSwap(directory.readInt());
+ dirofs = intSwap(directory.readInt());
+ dirlen = intSwap(directory.readInt());
+
+ if (ident != IDPAKHEADER) {
+ System.out.println ( pakName + " is not a pakfile.");
+ System.exit (1);
+ }
+
+ // read the directory
+ directory.skipBytes (dirofs - 12);
+ numLumps = dirlen / 64;
+
+ System.out.println (numLumps + " lumps in " + pakName);
+
+ for (i = 0 ; i < numLumps ; i++) {
+ directory.readFully(name);
+ filepos = intSwap(directory.readInt());
+ filelen = intSwap(directory.readInt());
+
+ nameString = new String (name, 0);
+ // chop to the first 0 byte
+ nameString = nameString.substring (0, nameString.indexOf(0));
+
+ if (pattern == null) {
+ // listing mode
+ System.out.println (nameString + " : " + filelen + "bytes");
+ } else if (patternMatch (pattern, nameString) ) {
+ File writeFile;
+ DataOutputStream writeLump;
+ byte[] buffer = new byte[filelen];
+ StringBuffer fixedString;
+ String finalName;
+ int index;
+
+ System.out.println ("Unpaking " + nameString + " " + filelen
+ + " bytes");
+
+ // load the lump
+ readLump.seek(filepos);
+ readLump.readFully(buffer);
+
+ // quake uses forward slashes, but java requires
+ // they only by the host's seperator, which
+ // varies from win to unix
+ fixedString = new StringBuffer (args[2] + File.separator + nameString);
+ for (index = 0 ; index < fixedString.length() ; index++) {
+ if (fixedString.charAt(index) == '/') {
+ fixedString.setCharAt(index, File.separatorChar);
+ }
+ }
+ finalName = fixedString.toString ();
+
+ index = finalName.lastIndexOf(File.separatorChar);
+ if (index != -1) {
+ String finalPath;
+ File writePath;
+
+ finalPath = finalName.substring(0, index);
+ writePath = new File (finalPath);
+ writePath.mkdirs();
+ }
+
+ writeFile = new File (finalName);
+ writeLump = new DataOutputStream ( new FileOutputStream(writeFile) );
+ writeLump.write(buffer);
+ writeLump.close();
+
+ }
+ }
+
+ readLump.close();
+ directory.close();
+
+ } catch (IOException e) {
+ System.out.println ( e.toString() );
+ }
+ }
+
+}
--- /dev/null
+# Microsoft Developer Studio Generated NMAKE File, Format Version 4.20
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+!IF "$(CFG)" == ""
+CFG=bspinfo3 - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to bspinfo3 - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "bsp - Win32 Release" && "$(CFG)" != "bsp - Win32 Debug" &&\
+ "$(CFG)" != "qbsp3 - Win32 Release" && "$(CFG)" != "qbsp3 - Win32 Debug" &&\
+ "$(CFG)" != "qvis3 - Win32 Release" && "$(CFG)" != "qvis3 - Win32 Debug" &&\
+ "$(CFG)" != "qrad3 - Win32 Release" && "$(CFG)" != "qrad3 - Win32 Debug" &&\
+ "$(CFG)" != "bspinfo3 - Win32 Release" && "$(CFG)" != "bspinfo3 - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE on this makefile
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "bsp.mak" CFG="bspinfo3 - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "bsp - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "bsp - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "qbsp3 - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "qbsp3 - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "qvis3 - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "qvis3 - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "qrad3 - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "qrad3 - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "bspinfo3 - Win32 Release" (based on\
+ "Win32 (x86) Console Application")
+!MESSAGE "bspinfo3 - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+################################################################################
+# Begin Project
+# PROP Target_Last_Scanned "bspinfo3 - Win32 Debug"
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "bsp - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+OUTDIR=.\Release
+INTDIR=.\Release
+
+ALL :
+
+CLEAN :
+ -@erase
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+CPP_PROJ=/nologo /MT /W3 /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\
+ "_CONSOLE" /Fp"$(INTDIR)/bsp.pch" /YX /Fo"$(INTDIR)/" /c
+CPP_OBJS=.\Release/
+CPP_SBRS=.\.
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/bsp.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+LINK32_FLAGS=wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib\
+ user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib\
+ ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo\
+ /subsystem:console /incremental:no /pdb:"$(OUTDIR)/bsp.pdb" /machine:I386\
+ /out:"$(OUTDIR)/bsp.exe"
+LINK32_OBJS= \
+
+
+!ELSEIF "$(CFG)" == "bsp - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+OUTDIR=.\Debug
+INTDIR=.\Debug
+
+ALL :
+
+CLEAN :
+ -@erase
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /MT /W3 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
+CPP_PROJ=/nologo /MT /W3 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG"\
+ /D "_CONSOLE" /Fp"$(INTDIR)/bsp.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
+CPP_OBJS=.\Debug/
+CPP_SBRS=.\.
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/bsp.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
+# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
+LINK32_FLAGS=wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib\
+ user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib\
+ ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo\
+ /subsystem:console /incremental:yes /pdb:"$(OUTDIR)/bsp.pdb" /debug\
+ /machine:I386 /out:"$(OUTDIR)/bsp.exe"
+LINK32_OBJS= \
+
+
+!ELSEIF "$(CFG)" == "qbsp3 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "qbsp3\Release"
+# PROP BASE Intermediate_Dir "qbsp3\Release"
+# PROP BASE Target_Dir "qbsp3"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "qbsp3\Release"
+# PROP Intermediate_Dir "qbsp3\Release"
+# PROP Target_Dir "qbsp3"
+OUTDIR=.\qbsp3\Release
+INTDIR=.\qbsp3\Release
+
+ALL : "$(OUTDIR)\qbsp3.exe"
+
+CLEAN :
+ -@erase "$(INTDIR)\brushbsp.obj"
+ -@erase "$(INTDIR)\bspfile.obj"
+ -@erase "$(INTDIR)\cmdlib.obj"
+ -@erase "$(INTDIR)\csg.obj"
+ -@erase "$(INTDIR)\faces.obj"
+ -@erase "$(INTDIR)\gldraw.obj"
+ -@erase "$(INTDIR)\glfile.obj"
+ -@erase "$(INTDIR)\lbmlib.obj"
+ -@erase "$(INTDIR)\leakfile.obj"
+ -@erase "$(INTDIR)\map.obj"
+ -@erase "$(INTDIR)\mathlib.obj"
+ -@erase "$(INTDIR)\polylib.obj"
+ -@erase "$(INTDIR)\portals.obj"
+ -@erase "$(INTDIR)\prtfile.obj"
+ -@erase "$(INTDIR)\qbsp3.obj"
+ -@erase "$(INTDIR)\scriplib.obj"
+ -@erase "$(INTDIR)\textures.obj"
+ -@erase "$(INTDIR)\threads.obj"
+ -@erase "$(INTDIR)\tree.obj"
+ -@erase "$(INTDIR)\writebsp.obj"
+ -@erase "$(OUTDIR)\qbsp3.exe"
+ -@erase "$(OUTDIR)\qbsp3.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /MT /W3 /GX /Zd /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+CPP_PROJ=/nologo /MT /W3 /GX /Zd /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\
+ "_CONSOLE" /Fp"$(INTDIR)/qbsp3.pch" /YX /Fo"$(INTDIR)/" /c
+CPP_OBJS=.\qbsp3\Release/
+CPP_SBRS=.\.
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/qbsp3.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
+LINK32_FLAGS=wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib\
+ user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib\
+ ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo\
+ /subsystem:console /incremental:no /pdb:"$(OUTDIR)/qbsp3.pdb" /debug\
+ /machine:I386 /out:"$(OUTDIR)/qbsp3.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\brushbsp.obj" \
+ "$(INTDIR)\bspfile.obj" \
+ "$(INTDIR)\cmdlib.obj" \
+ "$(INTDIR)\csg.obj" \
+ "$(INTDIR)\faces.obj" \
+ "$(INTDIR)\gldraw.obj" \
+ "$(INTDIR)\glfile.obj" \
+ "$(INTDIR)\lbmlib.obj" \
+ "$(INTDIR)\leakfile.obj" \
+ "$(INTDIR)\map.obj" \
+ "$(INTDIR)\mathlib.obj" \
+ "$(INTDIR)\polylib.obj" \
+ "$(INTDIR)\portals.obj" \
+ "$(INTDIR)\prtfile.obj" \
+ "$(INTDIR)\qbsp3.obj" \
+ "$(INTDIR)\scriplib.obj" \
+ "$(INTDIR)\textures.obj" \
+ "$(INTDIR)\threads.obj" \
+ "$(INTDIR)\tree.obj" \
+ "$(INTDIR)\writebsp.obj"
+
+"$(OUTDIR)\qbsp3.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "qbsp3\Debug"
+# PROP BASE Intermediate_Dir "qbsp3\Debug"
+# PROP BASE Target_Dir "qbsp3"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "qbsp3\Debug"
+# PROP Intermediate_Dir "qbsp3\Debug"
+# PROP Target_Dir "qbsp3"
+OUTDIR=.\qbsp3\Debug
+INTDIR=.\qbsp3\Debug
+
+ALL : "$(OUTDIR)\qbsp3.exe"
+
+CLEAN :
+ -@erase "$(INTDIR)\brushbsp.obj"
+ -@erase "$(INTDIR)\bspfile.obj"
+ -@erase "$(INTDIR)\cmdlib.obj"
+ -@erase "$(INTDIR)\csg.obj"
+ -@erase "$(INTDIR)\faces.obj"
+ -@erase "$(INTDIR)\gldraw.obj"
+ -@erase "$(INTDIR)\glfile.obj"
+ -@erase "$(INTDIR)\lbmlib.obj"
+ -@erase "$(INTDIR)\leakfile.obj"
+ -@erase "$(INTDIR)\map.obj"
+ -@erase "$(INTDIR)\mathlib.obj"
+ -@erase "$(INTDIR)\polylib.obj"
+ -@erase "$(INTDIR)\portals.obj"
+ -@erase "$(INTDIR)\prtfile.obj"
+ -@erase "$(INTDIR)\qbsp3.obj"
+ -@erase "$(INTDIR)\scriplib.obj"
+ -@erase "$(INTDIR)\textures.obj"
+ -@erase "$(INTDIR)\threads.obj"
+ -@erase "$(INTDIR)\tree.obj"
+ -@erase "$(INTDIR)\vc40.idb"
+ -@erase "$(INTDIR)\vc40.pdb"
+ -@erase "$(INTDIR)\writebsp.obj"
+ -@erase "$(OUTDIR)\qbsp3.exe"
+ -@erase "$(OUTDIR)\qbsp3.ilk"
+ -@erase "$(OUTDIR)\qbsp3.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /MT /W3 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
+CPP_PROJ=/nologo /MT /W3 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG"\
+ /D "_CONSOLE" /Fp"$(INTDIR)/qbsp3.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
+CPP_OBJS=.\qbsp3\Debug/
+CPP_SBRS=.\.
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/qbsp3.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
+# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
+LINK32_FLAGS=wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib\
+ user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib\
+ ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo\
+ /subsystem:console /incremental:yes /pdb:"$(OUTDIR)/qbsp3.pdb" /debug\
+ /machine:I386 /out:"$(OUTDIR)/qbsp3.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\brushbsp.obj" \
+ "$(INTDIR)\bspfile.obj" \
+ "$(INTDIR)\cmdlib.obj" \
+ "$(INTDIR)\csg.obj" \
+ "$(INTDIR)\faces.obj" \
+ "$(INTDIR)\gldraw.obj" \
+ "$(INTDIR)\glfile.obj" \
+ "$(INTDIR)\lbmlib.obj" \
+ "$(INTDIR)\leakfile.obj" \
+ "$(INTDIR)\map.obj" \
+ "$(INTDIR)\mathlib.obj" \
+ "$(INTDIR)\polylib.obj" \
+ "$(INTDIR)\portals.obj" \
+ "$(INTDIR)\prtfile.obj" \
+ "$(INTDIR)\qbsp3.obj" \
+ "$(INTDIR)\scriplib.obj" \
+ "$(INTDIR)\textures.obj" \
+ "$(INTDIR)\threads.obj" \
+ "$(INTDIR)\tree.obj" \
+ "$(INTDIR)\writebsp.obj"
+
+"$(OUTDIR)\qbsp3.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "qvis3 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "qvis3\Release"
+# PROP BASE Intermediate_Dir "qvis3\Release"
+# PROP BASE Target_Dir "qvis3"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "qvis3\Release"
+# PROP Intermediate_Dir "qvis3\Release"
+# PROP Target_Dir "qvis3"
+OUTDIR=.\qvis3\Release
+INTDIR=.\qvis3\Release
+
+ALL : "$(OUTDIR)\qvis3.exe"
+
+CLEAN :
+ -@erase "$(INTDIR)\bspfile.obj"
+ -@erase "$(INTDIR)\cmdlib.obj"
+ -@erase "$(INTDIR)\flow.obj"
+ -@erase "$(INTDIR)\mathlib.obj"
+ -@erase "$(INTDIR)\qvis3.obj"
+ -@erase "$(INTDIR)\scriplib.obj"
+ -@erase "$(INTDIR)\threads.obj"
+ -@erase "$(OUTDIR)\qvis3.exe"
+ -@erase "$(OUTDIR)\qvis3.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /MT /W3 /GX /Zd /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+CPP_PROJ=/nologo /MT /W3 /GX /Zd /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\
+ "_CONSOLE" /Fp"$(INTDIR)/qvis3.pch" /YX /Fo"$(INTDIR)/" /c
+CPP_OBJS=.\qvis3\Release/
+CPP_SBRS=.\.
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/qvis3.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
+LINK32_FLAGS=wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib\
+ user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib\
+ ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo\
+ /subsystem:console /incremental:no /pdb:"$(OUTDIR)/qvis3.pdb" /debug\
+ /machine:I386 /out:"$(OUTDIR)/qvis3.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\bspfile.obj" \
+ "$(INTDIR)\cmdlib.obj" \
+ "$(INTDIR)\flow.obj" \
+ "$(INTDIR)\mathlib.obj" \
+ "$(INTDIR)\qvis3.obj" \
+ "$(INTDIR)\scriplib.obj" \
+ "$(INTDIR)\threads.obj"
+
+"$(OUTDIR)\qvis3.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "qvis3 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "qvis3\Debug"
+# PROP BASE Intermediate_Dir "qvis3\Debug"
+# PROP BASE Target_Dir "qvis3"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "qvis3\Debug"
+# PROP Intermediate_Dir "qvis3\Debug"
+# PROP Target_Dir "qvis3"
+OUTDIR=.\qvis3\Debug
+INTDIR=.\qvis3\Debug
+
+ALL : "$(OUTDIR)\qvis3.exe"
+
+CLEAN :
+ -@erase "$(INTDIR)\bspfile.obj"
+ -@erase "$(INTDIR)\cmdlib.obj"
+ -@erase "$(INTDIR)\flow.obj"
+ -@erase "$(INTDIR)\mathlib.obj"
+ -@erase "$(INTDIR)\qvis3.obj"
+ -@erase "$(INTDIR)\scriplib.obj"
+ -@erase "$(INTDIR)\threads.obj"
+ -@erase "$(INTDIR)\vc40.idb"
+ -@erase "$(INTDIR)\vc40.pdb"
+ -@erase "$(OUTDIR)\qvis3.exe"
+ -@erase "$(OUTDIR)\qvis3.ilk"
+ -@erase "$(OUTDIR)\qvis3.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /MT /W3 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
+CPP_PROJ=/nologo /MT /W3 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG"\
+ /D "_CONSOLE" /Fp"$(INTDIR)/qvis3.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
+CPP_OBJS=.\qvis3\Debug/
+CPP_SBRS=.\.
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/qvis3.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
+# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
+LINK32_FLAGS=wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib\
+ user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib\
+ ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo\
+ /subsystem:console /incremental:yes /pdb:"$(OUTDIR)/qvis3.pdb" /debug\
+ /machine:I386 /out:"$(OUTDIR)/qvis3.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\bspfile.obj" \
+ "$(INTDIR)\cmdlib.obj" \
+ "$(INTDIR)\flow.obj" \
+ "$(INTDIR)\mathlib.obj" \
+ "$(INTDIR)\qvis3.obj" \
+ "$(INTDIR)\scriplib.obj" \
+ "$(INTDIR)\threads.obj"
+
+"$(OUTDIR)\qvis3.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "qrad3 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "qrad3\Release"
+# PROP BASE Intermediate_Dir "qrad3\Release"
+# PROP BASE Target_Dir "qrad3"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "qrad3\Release"
+# PROP Intermediate_Dir "qrad3\Release"
+# PROP Target_Dir "qrad3"
+OUTDIR=.\qrad3\Release
+INTDIR=.\qrad3\Release
+
+ALL : "$(OUTDIR)\qrad3.exe"
+
+CLEAN :
+ -@erase "$(INTDIR)\bspfile.obj"
+ -@erase "$(INTDIR)\cmdlib.obj"
+ -@erase "$(INTDIR)\lbmlib.obj"
+ -@erase "$(INTDIR)\lightmap.obj"
+ -@erase "$(INTDIR)\mathlib.obj"
+ -@erase "$(INTDIR)\patches.obj"
+ -@erase "$(INTDIR)\polylib.obj"
+ -@erase "$(INTDIR)\qrad3.obj"
+ -@erase "$(INTDIR)\scriplib.obj"
+ -@erase "$(INTDIR)\threads.obj"
+ -@erase "$(INTDIR)\trace.obj"
+ -@erase "$(OUTDIR)\qrad3.exe"
+ -@erase "$(OUTDIR)\qrad3.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /MT /W3 /GX /Zd /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+CPP_PROJ=/nologo /MT /W3 /GX /Zd /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\
+ "_CONSOLE" /Fp"$(INTDIR)/qrad3.pch" /YX /Fo"$(INTDIR)/" /c
+CPP_OBJS=.\qrad3\Release/
+CPP_SBRS=.\.
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/qrad3.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
+LINK32_FLAGS=wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib\
+ user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib\
+ ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo\
+ /subsystem:console /incremental:no /pdb:"$(OUTDIR)/qrad3.pdb" /debug\
+ /machine:I386 /out:"$(OUTDIR)/qrad3.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\bspfile.obj" \
+ "$(INTDIR)\cmdlib.obj" \
+ "$(INTDIR)\lbmlib.obj" \
+ "$(INTDIR)\lightmap.obj" \
+ "$(INTDIR)\mathlib.obj" \
+ "$(INTDIR)\patches.obj" \
+ "$(INTDIR)\polylib.obj" \
+ "$(INTDIR)\qrad3.obj" \
+ "$(INTDIR)\scriplib.obj" \
+ "$(INTDIR)\threads.obj" \
+ "$(INTDIR)\trace.obj"
+
+"$(OUTDIR)\qrad3.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "qrad3 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "qrad3\Debug"
+# PROP BASE Intermediate_Dir "qrad3\Debug"
+# PROP BASE Target_Dir "qrad3"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "qrad3\Debug"
+# PROP Intermediate_Dir "qrad3\Debug"
+# PROP Target_Dir "qrad3"
+OUTDIR=.\qrad3\Debug
+INTDIR=.\qrad3\Debug
+
+ALL : "$(OUTDIR)\qrad3.exe"
+
+CLEAN :
+ -@erase "$(INTDIR)\bspfile.obj"
+ -@erase "$(INTDIR)\cmdlib.obj"
+ -@erase "$(INTDIR)\lbmlib.obj"
+ -@erase "$(INTDIR)\lightmap.obj"
+ -@erase "$(INTDIR)\mathlib.obj"
+ -@erase "$(INTDIR)\patches.obj"
+ -@erase "$(INTDIR)\polylib.obj"
+ -@erase "$(INTDIR)\qrad3.obj"
+ -@erase "$(INTDIR)\scriplib.obj"
+ -@erase "$(INTDIR)\threads.obj"
+ -@erase "$(INTDIR)\trace.obj"
+ -@erase "$(INTDIR)\vc40.idb"
+ -@erase "$(INTDIR)\vc40.pdb"
+ -@erase "$(OUTDIR)\qrad3.exe"
+ -@erase "$(OUTDIR)\qrad3.ilk"
+ -@erase "$(OUTDIR)\qrad3.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /MT /W3 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
+CPP_PROJ=/nologo /MT /W3 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG"\
+ /D "_CONSOLE" /Fp"$(INTDIR)/qrad3.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
+CPP_OBJS=.\qrad3\Debug/
+CPP_SBRS=.\.
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/qrad3.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
+# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
+LINK32_FLAGS=wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib\
+ user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib\
+ ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo\
+ /subsystem:console /incremental:yes /pdb:"$(OUTDIR)/qrad3.pdb" /debug\
+ /machine:I386 /out:"$(OUTDIR)/qrad3.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\bspfile.obj" \
+ "$(INTDIR)\cmdlib.obj" \
+ "$(INTDIR)\lbmlib.obj" \
+ "$(INTDIR)\lightmap.obj" \
+ "$(INTDIR)\mathlib.obj" \
+ "$(INTDIR)\patches.obj" \
+ "$(INTDIR)\polylib.obj" \
+ "$(INTDIR)\qrad3.obj" \
+ "$(INTDIR)\scriplib.obj" \
+ "$(INTDIR)\threads.obj" \
+ "$(INTDIR)\trace.obj"
+
+"$(OUTDIR)\qrad3.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "bspinfo3 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "bspinfo3\Release"
+# PROP BASE Intermediate_Dir "bspinfo3\Release"
+# PROP BASE Target_Dir "bspinfo3"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "bspinfo3\Release"
+# PROP Intermediate_Dir "bspinfo3\Release"
+# PROP Target_Dir "bspinfo3"
+OUTDIR=.\bspinfo3\Release
+INTDIR=.\bspinfo3\Release
+
+ALL : "$(OUTDIR)\bspinfo3.exe"
+
+CLEAN :
+ -@erase "$(INTDIR)\bspfile.obj"
+ -@erase "$(INTDIR)\bspinfo3.obj"
+ -@erase "$(INTDIR)\cmdlib.obj"
+ -@erase "$(INTDIR)\mathlib.obj"
+ -@erase "$(INTDIR)\scriplib.obj"
+ -@erase "$(OUTDIR)\bspinfo3.exe"
+ -@erase "$(OUTDIR)\bspinfo3.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /MT /W3 /GX /Zd /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+CPP_PROJ=/nologo /MT /W3 /GX /Zd /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\
+ "_CONSOLE" /Fp"$(INTDIR)/bspinfo3.pch" /YX /Fo"$(INTDIR)/" /c
+CPP_OBJS=.\bspinfo3\Release/
+CPP_SBRS=.\.
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/bspinfo3.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
+LINK32_FLAGS=wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib\
+ user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib\
+ ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo\
+ /subsystem:console /incremental:no /pdb:"$(OUTDIR)/bspinfo3.pdb" /debug\
+ /machine:I386 /out:"$(OUTDIR)/bspinfo3.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\bspfile.obj" \
+ "$(INTDIR)\bspinfo3.obj" \
+ "$(INTDIR)\cmdlib.obj" \
+ "$(INTDIR)\mathlib.obj" \
+ "$(INTDIR)\scriplib.obj"
+
+"$(OUTDIR)\bspinfo3.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "bspinfo3 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "bspinfo3\Debug"
+# PROP BASE Intermediate_Dir "bspinfo3\Debug"
+# PROP BASE Target_Dir "bspinfo3"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "bspinfo3\Debug"
+# PROP Intermediate_Dir "bspinfo3\Debug"
+# PROP Target_Dir "bspinfo3"
+OUTDIR=.\bspinfo3\Debug
+INTDIR=.\bspinfo3\Debug
+
+ALL : "$(OUTDIR)\bspinfo3.exe"
+
+CLEAN :
+ -@erase "$(INTDIR)\bspfile.obj"
+ -@erase "$(INTDIR)\bspinfo3.obj"
+ -@erase "$(INTDIR)\cmdlib.obj"
+ -@erase "$(INTDIR)\mathlib.obj"
+ -@erase "$(INTDIR)\scriplib.obj"
+ -@erase "$(INTDIR)\vc40.idb"
+ -@erase "$(INTDIR)\vc40.pdb"
+ -@erase "$(OUTDIR)\bspinfo3.exe"
+ -@erase "$(OUTDIR)\bspinfo3.ilk"
+ -@erase "$(OUTDIR)\bspinfo3.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /MT /W3 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
+CPP_PROJ=/nologo /MT /W3 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG"\
+ /D "_CONSOLE" /Fp"$(INTDIR)/bspinfo3.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/"\
+ /c
+CPP_OBJS=.\bspinfo3\Debug/
+CPP_SBRS=.\.
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/bspinfo3.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
+# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
+LINK32_FLAGS=wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib\
+ user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib\
+ ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo\
+ /subsystem:console /incremental:yes /pdb:"$(OUTDIR)/bspinfo3.pdb" /debug\
+ /machine:I386 /out:"$(OUTDIR)/bspinfo3.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\bspfile.obj" \
+ "$(INTDIR)\bspinfo3.obj" \
+ "$(INTDIR)\cmdlib.obj" \
+ "$(INTDIR)\mathlib.obj" \
+ "$(INTDIR)\scriplib.obj"
+
+"$(OUTDIR)\bspinfo3.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF
+
+.c{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.c{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+################################################################################
+# Begin Target
+
+# Name "bsp - Win32 Release"
+# Name "bsp - Win32 Debug"
+
+!IF "$(CFG)" == "bsp - Win32 Release"
+
+!ELSEIF "$(CFG)" == "bsp - Win32 Debug"
+
+!ENDIF
+
+# End Target
+################################################################################
+# Begin Target
+
+# Name "qbsp3 - Win32 Release"
+# Name "qbsp3 - Win32 Debug"
+
+!IF "$(CFG)" == "qbsp3 - Win32 Release"
+
+!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug"
+
+!ENDIF
+
+################################################################################
+# Begin Source File
+
+SOURCE=.\qbsp3\writebsp.c
+
+!IF "$(CFG)" == "qbsp3 - Win32 Release"
+
+DEP_CPP_WRITE=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\polylib.h"\
+ "..\common\qfiles.h"\
+ "..\common\scriplib.h"\
+ "..\common\threads.h"\
+ ".\qbsp3\qbsp.h"\
+
+
+"$(INTDIR)\writebsp.obj" : $(SOURCE) $(DEP_CPP_WRITE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug"
+
+DEP_CPP_WRITE=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\polylib.h"\
+ "..\common\qfiles.h"\
+ "..\common\scriplib.h"\
+ "..\common\threads.h"\
+ ".\qbsp3\qbsp.h"\
+
+
+"$(INTDIR)\writebsp.obj" : $(SOURCE) $(DEP_CPP_WRITE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qbsp3\brushbsp.c
+DEP_CPP_BRUSH=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\polylib.h"\
+ "..\common\qfiles.h"\
+ "..\common\scriplib.h"\
+ "..\common\threads.h"\
+ ".\qbsp3\qbsp.h"\
+
+
+"$(INTDIR)\brushbsp.obj" : $(SOURCE) $(DEP_CPP_BRUSH) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qbsp3\csg.c
+DEP_CPP_CSG_C=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\polylib.h"\
+ "..\common\qfiles.h"\
+ "..\common\scriplib.h"\
+ "..\common\threads.h"\
+ ".\qbsp3\qbsp.h"\
+
+
+"$(INTDIR)\csg.obj" : $(SOURCE) $(DEP_CPP_CSG_C) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qbsp3\faces.c
+DEP_CPP_FACES=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\polylib.h"\
+ "..\common\qfiles.h"\
+ "..\common\scriplib.h"\
+ "..\common\threads.h"\
+ ".\qbsp3\qbsp.h"\
+
+
+"$(INTDIR)\faces.obj" : $(SOURCE) $(DEP_CPP_FACES) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qbsp3\gldraw.c
+
+!IF "$(CFG)" == "qbsp3 - Win32 Release"
+
+DEP_CPP_GLDRA=\
+ ".\qbsp3\qbsp.h"\
+ {$(INCLUDE)}"\gl\GL.H"\
+ {$(INCLUDE)}"\gl\GLAUX.H"\
+ {$(INCLUDE)}"\gl\GLU.H"\
+
+
+"$(INTDIR)\gldraw.obj" : $(SOURCE) $(DEP_CPP_GLDRA) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug"
+
+DEP_CPP_GLDRA=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\polylib.h"\
+ "..\common\qfiles.h"\
+ "..\common\scriplib.h"\
+ "..\common\threads.h"\
+ ".\qbsp3\qbsp.h"\
+ {$(INCLUDE)}"\gl\GL.H"\
+ {$(INCLUDE)}"\gl\GLAUX.H"\
+ {$(INCLUDE)}"\gl\GLU.H"\
+
+
+"$(INTDIR)\gldraw.obj" : $(SOURCE) $(DEP_CPP_GLDRA) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qbsp3\glfile.c
+
+!IF "$(CFG)" == "qbsp3 - Win32 Release"
+
+DEP_CPP_GLFIL=\
+ ".\qbsp3\qbsp.h"\
+
+
+"$(INTDIR)\glfile.obj" : $(SOURCE) $(DEP_CPP_GLFIL) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug"
+
+DEP_CPP_GLFIL=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\polylib.h"\
+ "..\common\qfiles.h"\
+ "..\common\scriplib.h"\
+ "..\common\threads.h"\
+ ".\qbsp3\qbsp.h"\
+
+
+"$(INTDIR)\glfile.obj" : $(SOURCE) $(DEP_CPP_GLFIL) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qbsp3\leakfile.c
+
+!IF "$(CFG)" == "qbsp3 - Win32 Release"
+
+DEP_CPP_LEAKF=\
+ ".\qbsp3\qbsp.h"\
+
+
+"$(INTDIR)\leakfile.obj" : $(SOURCE) $(DEP_CPP_LEAKF) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug"
+
+DEP_CPP_LEAKF=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\polylib.h"\
+ "..\common\qfiles.h"\
+ "..\common\scriplib.h"\
+ "..\common\threads.h"\
+ ".\qbsp3\qbsp.h"\
+
+
+"$(INTDIR)\leakfile.obj" : $(SOURCE) $(DEP_CPP_LEAKF) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qbsp3\map.c
+DEP_CPP_MAP_C=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\polylib.h"\
+ "..\common\qfiles.h"\
+ "..\common\scriplib.h"\
+ "..\common\threads.h"\
+ ".\qbsp3\qbsp.h"\
+
+
+"$(INTDIR)\map.obj" : $(SOURCE) $(DEP_CPP_MAP_C) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qbsp3\portals.c
+DEP_CPP_PORTA=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\polylib.h"\
+ "..\common\qfiles.h"\
+ "..\common\scriplib.h"\
+ "..\common\threads.h"\
+ ".\qbsp3\qbsp.h"\
+
+
+"$(INTDIR)\portals.obj" : $(SOURCE) $(DEP_CPP_PORTA) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qbsp3\prtfile.c
+DEP_CPP_PRTFI=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\polylib.h"\
+ "..\common\qfiles.h"\
+ "..\common\scriplib.h"\
+ "..\common\threads.h"\
+ ".\qbsp3\qbsp.h"\
+
+
+"$(INTDIR)\prtfile.obj" : $(SOURCE) $(DEP_CPP_PRTFI) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qbsp3\qbsp.h
+
+!IF "$(CFG)" == "qbsp3 - Win32 Release"
+
+!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qbsp3\qbsp3.c
+DEP_CPP_QBSP3=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\polylib.h"\
+ "..\common\qfiles.h"\
+ "..\common\scriplib.h"\
+ "..\common\threads.h"\
+ ".\qbsp3\qbsp.h"\
+
+
+"$(INTDIR)\qbsp3.obj" : $(SOURCE) $(DEP_CPP_QBSP3) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qbsp3\textures.c
+DEP_CPP_TEXTU=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\polylib.h"\
+ "..\common\qfiles.h"\
+ "..\common\scriplib.h"\
+ "..\common\threads.h"\
+ ".\qbsp3\qbsp.h"\
+
+
+"$(INTDIR)\textures.obj" : $(SOURCE) $(DEP_CPP_TEXTU) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qbsp3\tree.c
+DEP_CPP_TREE_=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\polylib.h"\
+ "..\common\qfiles.h"\
+ "..\common\scriplib.h"\
+ "..\common\threads.h"\
+ ".\qbsp3\qbsp.h"\
+
+
+"$(INTDIR)\tree.obj" : $(SOURCE) $(DEP_CPP_TREE_) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\threads.c
+DEP_CPP_THREA=\
+ "..\common\cmdlib.h"\
+ "..\common\threads.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+
+"$(INTDIR)\threads.obj" : $(SOURCE) $(DEP_CPP_THREA) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\cmdlib.c
+DEP_CPP_CMDLI=\
+ "..\common\cmdlib.h"\
+ {$(INCLUDE)}"\sys\stat.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+
+"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\lbmlib.c
+DEP_CPP_LBMLI=\
+ "..\common\cmdlib.h"\
+ "..\common\lbmlib.h"\
+
+
+"$(INTDIR)\lbmlib.obj" : $(SOURCE) $(DEP_CPP_LBMLI) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\mathlib.c
+DEP_CPP_MATHL=\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+
+
+"$(INTDIR)\mathlib.obj" : $(SOURCE) $(DEP_CPP_MATHL) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\polylib.c
+DEP_CPP_POLYL=\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\polylib.h"\
+
+
+"$(INTDIR)\polylib.obj" : $(SOURCE) $(DEP_CPP_POLYL) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\scriplib.c
+DEP_CPP_SCRIP=\
+ "..\common\cmdlib.h"\
+ "..\common\scriplib.h"\
+
+
+"$(INTDIR)\scriplib.obj" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\bspfile.c
+DEP_CPP_BSPFI=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\qfiles.h"\
+ "..\common\scriplib.h"\
+
+
+"$(INTDIR)\bspfile.obj" : $(SOURCE) $(DEP_CPP_BSPFI) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\threads.h
+
+!IF "$(CFG)" == "qbsp3 - Win32 Release"
+
+!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\cmdlib.h
+
+!IF "$(CFG)" == "qbsp3 - Win32 Release"
+
+!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\lbmlib.h
+
+!IF "$(CFG)" == "qbsp3 - Win32 Release"
+
+!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\mathlib.h
+
+!IF "$(CFG)" == "qbsp3 - Win32 Release"
+
+!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\polylib.h
+
+!IF "$(CFG)" == "qbsp3 - Win32 Release"
+
+!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\scriplib.h
+
+!IF "$(CFG)" == "qbsp3 - Win32 Release"
+
+!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\bspfile.h
+
+!IF "$(CFG)" == "qbsp3 - Win32 Release"
+
+!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\qfiles.h
+
+!IF "$(CFG)" == "qbsp3 - Win32 Release"
+
+!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# End Target
+################################################################################
+# Begin Target
+
+# Name "qvis3 - Win32 Release"
+# Name "qvis3 - Win32 Debug"
+
+!IF "$(CFG)" == "qvis3 - Win32 Release"
+
+!ELSEIF "$(CFG)" == "qvis3 - Win32 Debug"
+
+!ENDIF
+
+################################################################################
+# Begin Source File
+
+SOURCE=.\qvis3\vis.h
+
+!IF "$(CFG)" == "qvis3 - Win32 Release"
+
+!ELSEIF "$(CFG)" == "qvis3 - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qvis3\qvis3.c
+DEP_CPP_QVIS3=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\qfiles.h"\
+ "..\common\threads.h"\
+ ".\qvis3\vis.h"\
+
+
+"$(INTDIR)\qvis3.obj" : $(SOURCE) $(DEP_CPP_QVIS3) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qvis3\flow.c
+DEP_CPP_FLOW_=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\qfiles.h"\
+ ".\qvis3\vis.h"\
+
+
+"$(INTDIR)\flow.obj" : $(SOURCE) $(DEP_CPP_FLOW_) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\cmdlib.c
+DEP_CPP_CMDLI=\
+ "..\common\cmdlib.h"\
+ {$(INCLUDE)}"\sys\stat.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+
+"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\mathlib.c
+DEP_CPP_MATHL=\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+
+
+"$(INTDIR)\mathlib.obj" : $(SOURCE) $(DEP_CPP_MATHL) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\scriplib.c
+DEP_CPP_SCRIP=\
+ "..\common\cmdlib.h"\
+ "..\common\scriplib.h"\
+
+
+"$(INTDIR)\scriplib.obj" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\threads.c
+DEP_CPP_THREA=\
+ "..\common\cmdlib.h"\
+ "..\common\threads.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+
+"$(INTDIR)\threads.obj" : $(SOURCE) $(DEP_CPP_THREA) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\bspfile.c
+DEP_CPP_BSPFI=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\qfiles.h"\
+ "..\common\scriplib.h"\
+
+
+"$(INTDIR)\bspfile.obj" : $(SOURCE) $(DEP_CPP_BSPFI) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+# End Target
+################################################################################
+# Begin Target
+
+# Name "qrad3 - Win32 Release"
+# Name "qrad3 - Win32 Debug"
+
+!IF "$(CFG)" == "qrad3 - Win32 Release"
+
+!ELSEIF "$(CFG)" == "qrad3 - Win32 Debug"
+
+!ENDIF
+
+################################################################################
+# Begin Source File
+
+SOURCE=.\qrad3\patches.c
+DEP_CPP_PATCH=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\lbmlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\polylib.h"\
+ "..\common\qfiles.h"\
+ "..\common\threads.h"\
+ ".\qrad3\qrad.h"\
+
+
+"$(INTDIR)\patches.obj" : $(SOURCE) $(DEP_CPP_PATCH) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qrad3\lightmap.c
+DEP_CPP_LIGHT=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\lbmlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\polylib.h"\
+ "..\common\qfiles.h"\
+ "..\common\threads.h"\
+ ".\qrad3\qrad.h"\
+
+
+"$(INTDIR)\lightmap.obj" : $(SOURCE) $(DEP_CPP_LIGHT) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qrad3\qrad.h
+
+!IF "$(CFG)" == "qrad3 - Win32 Release"
+
+!ELSEIF "$(CFG)" == "qrad3 - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qrad3\qrad3.c
+DEP_CPP_QRAD3=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\lbmlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\polylib.h"\
+ "..\common\qfiles.h"\
+ "..\common\threads.h"\
+ ".\qrad3\qrad.h"\
+
+
+"$(INTDIR)\qrad3.obj" : $(SOURCE) $(DEP_CPP_QRAD3) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qrad3\trace.c
+DEP_CPP_TRACE=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\qfiles.h"\
+
+
+"$(INTDIR)\trace.obj" : $(SOURCE) $(DEP_CPP_TRACE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\threads.c
+DEP_CPP_THREA=\
+ "..\common\cmdlib.h"\
+ "..\common\threads.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+
+"$(INTDIR)\threads.obj" : $(SOURCE) $(DEP_CPP_THREA) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\cmdlib.c
+DEP_CPP_CMDLI=\
+ "..\common\cmdlib.h"\
+ {$(INCLUDE)}"\sys\stat.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+
+"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\mathlib.c
+DEP_CPP_MATHL=\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+
+
+"$(INTDIR)\mathlib.obj" : $(SOURCE) $(DEP_CPP_MATHL) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\polylib.c
+DEP_CPP_POLYL=\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\polylib.h"\
+
+
+"$(INTDIR)\polylib.obj" : $(SOURCE) $(DEP_CPP_POLYL) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\scriplib.c
+DEP_CPP_SCRIP=\
+ "..\common\cmdlib.h"\
+ "..\common\scriplib.h"\
+
+
+"$(INTDIR)\scriplib.obj" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\bspfile.c
+DEP_CPP_BSPFI=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\qfiles.h"\
+ "..\common\scriplib.h"\
+
+
+"$(INTDIR)\bspfile.obj" : $(SOURCE) $(DEP_CPP_BSPFI) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\lbmlib.c
+DEP_CPP_LBMLI=\
+ "..\common\cmdlib.h"\
+ "..\common\lbmlib.h"\
+
+
+"$(INTDIR)\lbmlib.obj" : $(SOURCE) $(DEP_CPP_LBMLI) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+# End Target
+################################################################################
+# Begin Target
+
+# Name "bspinfo3 - Win32 Release"
+# Name "bspinfo3 - Win32 Debug"
+
+!IF "$(CFG)" == "bspinfo3 - Win32 Release"
+
+!ELSEIF "$(CFG)" == "bspinfo3 - Win32 Debug"
+
+!ENDIF
+
+################################################################################
+# Begin Source File
+
+SOURCE=.\bspinfo3\bspinfo3.c
+DEP_CPP_BSPIN=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\qfiles.h"\
+
+
+"$(INTDIR)\bspinfo3.obj" : $(SOURCE) $(DEP_CPP_BSPIN) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\mathlib.c
+DEP_CPP_MATHL=\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+
+
+"$(INTDIR)\mathlib.obj" : $(SOURCE) $(DEP_CPP_MATHL) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\cmdlib.c
+DEP_CPP_CMDLI=\
+ "..\common\cmdlib.h"\
+ {$(INCLUDE)}"\sys\stat.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+
+"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\bspfile.c
+DEP_CPP_BSPFI=\
+ "..\common\bspfile.h"\
+ "..\common\cmdlib.h"\
+ "..\common\mathlib.h"\
+ "..\common\qfiles.h"\
+ "..\common\scriplib.h"\
+
+
+"$(INTDIR)\bspfile.obj" : $(SOURCE) $(DEP_CPP_BSPFI) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=..\common\scriplib.c
+DEP_CPP_SCRIP=\
+ "..\common\cmdlib.h"\
+ "..\common\scriplib.h"\
+
+
+"$(INTDIR)\scriplib.obj" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+# End Target
+# End Project
+################################################################################
--- /dev/null
+/*
+===========================================================================
+Copyright (C) 1997-2006 Id Software, Inc.
+
+This file is part of Quake 2 Tools source code.
+
+Quake 2 Tools 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 2 Tools 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 Quake 2 Tools source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#include "cmdlib.h"
+#include "mathlib.h"
+#include "bspfile.h"
+
+void main (int argc, char **argv)
+{
+ int i;
+ char source[1024];
+ int size;
+ FILE *f;
+
+ if (argc == 1)
+ Error ("usage: bspinfo bspfile [bspfiles]");
+
+ for (i=1 ; i<argc ; i++)
+ {
+ printf ("---------------------\n");
+ strcpy (source, argv[i]);
+ DefaultExtension (source, ".bsp");
+ f = fopen (source, "rb");
+ if (f)
+ {
+ size = Q_filelength (f);
+ fclose (f);
+ }
+ else
+ size = 0;
+ printf ("%s: %i\n", source, size);
+
+ LoadBSPFile (source);
+ PrintBSPFileSizes ();
+ printf ("---------------------\n");
+ }
+}
--- /dev/null
+
+CFLAGS = -c
+LDFLAGS =
+ODIR = baddir
+
+EXEBASE = bspinfo3
+EXE = $(ODIR)/bspinfo3
+all: $(EXE)
+
+_next:
+ make "CFLAGS = -c -g -I../../common -DDOUBLEVEC_T" "ODIR = next"
+
+_irix:
+ make "CFLAGS = -c -Ofast=ip32_10k -I../../common -Xcpluscomm -DDOUBLEVEC_T" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix"
+
+_irixdebug:
+ make "CFLAGS = -c -O2 -g -I../../common -Xcpluscomm -DDOUBLEVEC_T" "LDFLAGS = -g" "ODIR = irix"
+
+_irixinst:
+ make "CFLAGS = -c -Ofast=ip32_10k -I../../common -Xcpluscomm -DDOUBLEVEC_T" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix"
+ cp irix/$(EXEBASE) /limbo/quake2/bin_irix
+
+_irixclean:
+ rm -f irix/*.o irix/$(EXEBASE)
+
+_osf:
+ make "CFLAGS = -c -O4 -I../../common -threads -DDOUBLEVEC_T" "LDFLAGS = -threads" "ODIR = osf"
+
+clean:
+ rm -f irix/*.o irix/$(EXEBASE)
+
+install:
+ cp irix/$(EXEBASE) /limbo/quake2/bin_irix
+
+
+FILES = $(ODIR)/bspinfo3.o $(ODIR)/bspfile.o $(ODIR)/cmdlib.o $(ODIR)/scriplib.o
+
+$(EXE) : $(FILES)
+ cc -o $(EXE) $(LDFLAGS) $(FILES)
+
+$(ODIR)/bspinfo3.o : bspinfo3.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/cmdlib.o : ../../common/cmdlib.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/scriplib.o : ../../common/scriplib.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/bspfile.o : ../../common/bspfile.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
--- /dev/null
+/*
+===========================================================================
+Copyright (C) 1997-2006 Id Software, Inc.
+
+This file is part of Quake 2 Tools source code.
+
+Quake 2 Tools 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 2 Tools 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 Quake 2 Tools source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#include "qbsp.h"
+
+
+int c_nodes;
+int c_nonvis;
+int c_active_brushes;
+
+// if a brush just barely pokes onto the other side,
+// let it slide by without chopping
+#define PLANESIDE_EPSILON 0.001
+//0.1
+
+#define PSIDE_FRONT 1
+#define PSIDE_BACK 2
+#define PSIDE_BOTH (PSIDE_FRONT|PSIDE_BACK)
+#define PSIDE_FACING 4
+
+
+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)
+ printf ("here\n");
+ return;
+ }
+ FindBrushInTree (node->children[0], brushnum);
+ FindBrushInTree (node->children[1], brushnum);
+}
+
+//==================================================
+
+/*
+================
+DrawBrushList
+================
+*/
+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->visible)
+ GLS_Winding (s->winding, 2);
+ else
+ GLS_Winding (s->winding, 0);
+ }
+ }
+ GLS_EndScene ();
+}
+
+/*
+================
+WriteBrushList
+================
+*/
+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->visible)
+ continue;
+ OutputWinding (brush->sides[i].winding, f);
+ }
+ }
+
+ fclose (f);
+}
+
+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");
+ }
+}
+
+/*
+==================
+BoundBrush
+
+Sets the mins/maxs based on the windings
+==================
+*/
+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);
+ }
+}
+
+/*
+==================
+CreateBrushWindings
+
+==================
+*/
+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].bevel)
+ continue;
+ plane = &mapplanes[brush->sides[j].planenum^1];
+ ChopWindingInPlace (&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
+ }
+
+ side->winding = w;
+ }
+
+ BoundBrush (brush);
+}
+
+/*
+==================
+BrushFromBounds
+
+Creates a new axial brush
+==================
+*/
+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;
+}
+
+/*
+==================
+BrushVolume
+
+==================
+*/
+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;
+ }
+ 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;
+ }
+
+ volume /= 3;
+ return volume;
+}
+
+/*
+================
+CountBrushList
+================
+*/
+int CountBrushList (bspbrush_t *brushes)
+{
+ int c;
+
+ c = 0;
+ for ( ; brushes ; brushes = brushes->next)
+ c++;
+ return c;
+}
+
+/*
+================
+AllocTree
+================
+*/
+tree_t *AllocTree (void)
+{
+ tree_t *tree;
+
+ tree = malloc(sizeof(*tree));
+ memset (tree, 0, sizeof(*tree));
+ ClearBounds (tree->mins, tree->maxs);
+
+ return tree;
+}
+
+/*
+================
+AllocNode
+================
+*/
+node_t *AllocNode (void)
+{
+ node_t *node;
+
+ node = malloc(sizeof(*node));
+ memset (node, 0, sizeof(*node));
+
+ return node;
+}
+
+
+/*
+================
+AllocBrush
+================
+*/
+bspbrush_t *AllocBrush (int numsides)
+{
+ bspbrush_t *bb;
+ int c;
+
+ c = (int)&(((bspbrush_t *)0)->sides[numsides]);
+ bb = malloc(c);
+ memset (bb, 0, c);
+ if (numthreads == 1)
+ c_active_brushes++;
+ return bb;
+}
+
+/*
+================
+FreeBrush
+================
+*/
+void FreeBrush (bspbrush_t *brushes)
+{
+ int i;
+
+ for (i=0 ; i<brushes->numsides ; i++)
+ if (brushes->sides[i].winding)
+ FreeWinding(brushes->sides[i].winding);
+ free (brushes);
+ if (numthreads == 1)
+ c_active_brushes--;
+}
+
+
+/*
+================
+FreeBrushList
+================
+*/
+void FreeBrushList (bspbrush_t *brushes)
+{
+ bspbrush_t *next;
+
+ for ( ; brushes ; brushes = next)
+ {
+ next = brushes->next;
+
+ FreeBrush (brushes);
+ }
+}
+
+/*
+==================
+CopyBrush
+
+Duplicates the brush, the sides, and the windings
+==================
+*/
+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;
+}
+
+
+/*
+==================
+PointInLeaf
+
+==================
+*/
+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;
+}
+
+//========================================================
+
+/*
+==============
+BoxOnPlaneSide
+
+Returns PSIDE_FRONT, PSIDE_BACK, or PSIDE_BOTH
+==============
+*/
+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;
+}
+
+/*
+============
+QuickTestBrushToPlanenum
+
+============
+*/
+int QuickTestBrushToPlanenum (bspbrush_t *brush, int planenum, int *numsplits)
+{
+ int i, num;
+ plane_t *plane;
+ int s;
+
+ *numsplits = 0;
+
+ // 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 >= 0x10000)
+ Error ("bad planenum");
+ if (num == planenum)
+ return PSIDE_BACK|PSIDE_FACING;
+ if (num == (planenum ^ 1) )
+ return PSIDE_FRONT|PSIDE_FACING;
+ }
+
+ // box on plane side
+ plane = &mapplanes[planenum];
+ s = BoxOnPlaneSide (brush->mins, brush->maxs, plane);
+
+ // if both sides, count the visible faces split
+ if (s == PSIDE_BOTH)
+ {
+ *numsplits += 3;
+ }
+
+ return s;
+}
+
+/*
+============
+TestBrushToPlanenum
+
+============
+*/
+int TestBrushToPlanenum (bspbrush_t *brush, int planenum,
+ int *numsplits, qboolean *hintsplit, int *epsilonbrush)
+{
+ int i, j, num;
+ plane_t *plane;
+ int s;
+ winding_t *w;
+ vec_t d, d_front, d_back;
+ int front, back;
+
+ *numsplits = 0;
+ *hintsplit = false;
+
+ // 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 >= 0x10000)
+ Error ("bad planenum");
+ if (num == planenum)
+ return PSIDE_BACK|PSIDE_FACING;
+ if (num == (planenum ^ 1) )
+ return PSIDE_FRONT|PSIDE_FACING;
+ }
+
+ // box on plane side
+ plane = &mapplanes[planenum];
+ s = BoxOnPlaneSide (brush->mins, brush->maxs, plane);
+
+ if (s != PSIDE_BOTH)
+ return s;
+
+// 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].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;
+ }
+ if (front && back)
+ {
+ if ( !(brush->sides[i].surf & SURF_SKIP) )
+ {
+ (*numsplits)++;
+ if (brush->sides[i].surf & SURF_HINT)
+ *hintsplit = true;
+ }
+ }
+ }
+
+ 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;
+}
+
+//========================================================
+
+/*
+================
+WindingIsTiny
+
+Returns true if the winding would be crunched out of
+existance by the vertex snapping.
+================
+*/
+#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
+}
+
+/*
+================
+WindingIsHuge
+
+Returns true if the winding still has one of the points
+from basewinding for plane
+================
+*/
+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] < -8000 || w->p[i][j] > 8000)
+ return true;
+ }
+ return false;
+}
+
+//============================================================
+
+/*
+================
+Leafnode
+================
+*/
+void LeafNode (node_t *node, bspbrush_t *brushes)
+{
+ bspbrush_t *b;
+ int i;
+
+ 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;
+ }
+ }
+ node->contents |= b->original->contents;
+ }
+
+ node->brushlist = brushes;
+}
+
+
+//============================================================
+
+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");
+ }
+}
+
+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;
+}
+
+/*
+================
+SelectSplitSide
+
+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..
+================
+*/
+side_t *SelectSplitSide (bspbrush_t *brushes, node_t *node)
+{
+ int value, bestvalue;
+ bspbrush_t *brush, *test;
+ side_t *side, *bestside;
+ int i, j, pass, numpasses;
+ int pnum;
+ int s;
+ int front, back, both, facing, splits;
+ int bsplits;
+ int bestsplits;
+ int epsilonbrush;
+ qboolean hintsplit;
+
+ 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 = 4;
+ for (pass = 0 ; pass < numpasses ; pass++)
+ {
+ for (brush = brushes ; brush ; brush=brush->next)
+ {
+ 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->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->tested)
+ continue; // we allready have metrics for this plane
+ if (side->surf & SURF_SKIP)
+ continue; // skip surfaces are never chosen
+ if ( side->visible ^ (pass<2) )
+ continue; // only check visible faces on first 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;
+
+ 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 the brush shares this face, don't bother
+ // testing that facenum as a splitter again
+ if (s & PSIDE_FACING)
+ {
+ facing++;
+ for (j=0 ; j<test->numsides ; j++)
+ {
+ if ( (test->sides[j].planenum&~1) == pnum)
+ test->sides[j].tested = true;
+ }
+ }
+ if (s & PSIDE_FRONT)
+ front++;
+ if (s & PSIDE_BACK)
+ back++;
+ if (s == PSIDE_BOTH)
+ both++;
+ }
+
+ // 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;
+ }
+ }
+ }
+
+ // 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;
+ }
+ }
+
+ //
+ // clear all the tested flags we set
+ //
+ for (brush = brushes ; brush ; brush=brush->next)
+ {
+ for (i=0 ; i<brush->numsides ; i++)
+ brush->sides[i].tested = false;
+ }
+
+ return bestside;
+}
+
+
+/*
+==================
+BrushMostlyOnSide
+
+==================
+*/
+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;
+}
+
+/*
+================
+SplitBrush
+
+Generates two new brushes, leaving the original
+unchanged
+================
+*/
+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.1) // PLANESIDE_EPSILON)
+ { // only on back
+ *back = CopyBrush (brush);
+ return;
+ }
+ if (d_back > -0.1) // 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);
+ return;
+ }
+
+ if (WindingIsHuge (w))
+ {
+ qprintf ("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->visible = s->visible;
+// cs->original = s->original;
+ cs->winding = cw[j];
+ cs->tested = false;
+ }
+ }
+
+
+ // 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)
+ {
+ qprintf ("bogus brush after clip\n");
+ break;
+ }
+ }
+
+ if (b[i]->numsides < 3 || j < 3)
+ {
+ FreeBrush (b[i]);
+ b[i] = NULL;
+ }
+ }
+
+ if ( !(b[0] && b[1]) )
+ {
+ if (!b[0] && !b[1])
+ qprintf ("split removed brush\n");
+ else
+ qprintf ("split not on both sides\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;
+ cs->visible = false;
+ cs->tested = false;
+ 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;
+// qprintf ("tiny volume after clip\n");
+ }
+ }
+}
+
+ *front = b[0];
+ *back = b[1];
+}
+
+/*
+================
+SplitBrushList
+================
+*/
+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;
+ }
+ if (newbrush2)
+ {
+ newbrush2->next = *back;
+ *back = newbrush2;
+ }
+ continue;
+ }
+
+ 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;
+ }
+ }
+
+
+ if (sides & PSIDE_FRONT)
+ {
+ newbrush->next = *front;
+ *front = newbrush;
+ continue;
+ }
+ if (sides & PSIDE_BACK)
+ {
+ newbrush->next = *back;
+ *back = newbrush;
+ continue;
+ }
+ }
+}
+
+
+/*
+================
+BuildTree_r
+================
+*/
+node_t *BuildTree_r (node_t *node, bspbrush_t *brushes)
+{
+ node_t *newnode;
+ side_t *bestside;
+ int i;
+ bspbrush_t *children[2];
+
+ if (numthreads == 1)
+ c_nodes++;
+
+ 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);
+ return node;
+ }
+
+ // this is a splitplane node
+ node->side = bestside;
+ node->planenum = bestside->planenum & ~1; // always use front facing
+
+ SplitBrushList (brushes, node, &children[0], &children[1]);
+ FreeBrushList (brushes);
+
+ // allocate children before recursing
+ for (i=0 ; i<2 ; i++)
+ {
+ newnode = AllocNode ();
+ newnode->parent = node;
+ node->children[i] = newnode;
+ }
+
+ SplitBrush (node->volume, node->planenum, &node->children[0]->volume,
+ &node->children[1]->volume);
+
+ // recursively process children
+ for (i=0 ; i<2 ; i++)
+ {
+ node->children[i] = BuildTree_r (node->children[i], children[i]);
+ }
+
+ return node;
+}
+
+//===========================================================
+
+/*
+=================
+BrushBSP
+
+The incoming list will be freed before exiting
+=================
+*/
+tree_t *BrushBSP (bspbrush_t *brushlist, vec3_t mins, vec3_t maxs)
+{
+ node_t *node;
+ bspbrush_t *b;
+ int c_faces, c_nonvisfaces;
+ int c_brushes;
+ tree_t *tree;
+ int i;
+ vec_t volume;
+
+ qprintf ("--- BrushBSP ---\n");
+
+ tree = AllocTree ();
+
+ c_faces = 0;
+ c_nonvisfaces = 0;
+ c_brushes = 0;
+ for (b=brushlist ; b ; b=b->next)
+ {
+ c_brushes++;
+
+ volume = BrushVolume (b);
+ if (volume < microvolume)
+ {
+ printf ("WARNING: entity %i, brush %i: microbrush\n",
+ b->original->entitynum, b->original->brushnum);
+ }
+
+ for (i=0 ; i<b->numsides ; i++)
+ {
+ if (b->sides[i].bevel)
+ continue;
+ if (!b->sides[i].winding)
+ continue;
+ if (b->sides[i].texinfo == TEXINFO_NODE)
+ continue;
+ if (b->sides[i].visible)
+ c_faces++;
+ else
+ c_nonvisfaces++;
+ }
+
+ AddPointToBounds (b->mins, tree->mins, tree->maxs);
+ AddPointToBounds (b->maxs, tree->mins, tree->maxs);
+ }
+
+ qprintf ("%5i brushes\n", c_brushes);
+ qprintf ("%5i visible faces\n", c_faces);
+ qprintf ("%5i nonvisible faces\n", c_nonvisfaces);
+
+ c_nodes = 0;
+ c_nonvis = 0;
+ node = AllocNode ();
+
+ node->volume = BrushFromBounds (mins, maxs);
+
+ tree->headnode = node;
+
+ node = BuildTree_r (node, brushlist);
+ qprintf ("%5i visible nodes\n", c_nodes/2 - c_nonvis);
+ qprintf ("%5i nonvis nodes\n", c_nonvis);
+ qprintf ("%5i leafs\n", (c_nodes+1)/2);
+#if 0
+{ // debug code
+static node_t *tnode;
+vec3_t p;
+
+p[0] = -1469;
+p[1] = -118;
+p[2] = 119;
+tnode = PointInLeaf (tree->headnode, p);
+printf ("contents: %i\n", tnode->contents);
+p[0] = 0;
+}
+#endif
+ return tree;
+}
+
--- /dev/null
+/*
+===========================================================================
+Copyright (C) 1997-2006 Id Software, Inc.
+
+This file is part of Quake 2 Tools source code.
+
+Quake 2 Tools 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 2 Tools 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 Quake 2 Tools source code; 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
+
+
+
+
+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++;
+}
+
+
+ */
+
+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
+}
+
+/*
+===============
+SubtractBrush
+
+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.
+===============
+*/
+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;
+ }
+ in = back;
+ }
+ if (in)
+ FreeBrush (in);
+ else
+ { // didn't really intersect
+ FreeBrushList (out);
+ return a;
+ }
+ return out;
+}
+
+/*
+===============
+IntersectBrush
+
+Returns a single brush made up by the intersection of the
+two provided brushes, or NULL if they are disjoint.
+
+The originals are undisturbed.
+===============
+*/
+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;
+ }
+
+ if (in == a)
+ return NULL;
+
+ in->next = NULL;
+ return in;
+}
+
+
+/*
+===============
+BrushesDisjoint
+
+Returns true if the two brushes definately do not intersect.
+There will be false negatives for some non-axial combinations.
+===============
+*/
+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
+}
+
+/*
+===============
+IntersectionContents
+
+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.
+===============
+*/
+int IntersectionContents (int c1, int c2)
+{
+ int out;
+
+ out = c1 | c2;
+
+ if (out & CONTENTS_SOLID)
+ out = CONTENTS_SOLID;
+
+ return out;
+}
+
+
+int minplanenums[3];
+int maxplanenums[3];
+
+/*
+===============
+ClipBrushToBox
+
+Any planes shared with the box edge will be set to no texinfo
+===============
+*/
+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].visible = false;
+ }
+ }
+ return brush;
+}
+
+/*
+===============
+MakeBspBrushList
+===============
+*/
+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].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].visible = true; // 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;
+}
+
+/*
+===============
+AddBspBrushListToTail
+===============
+*/
+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;
+ }
+
+ return tail;
+}
+
+/*
+===========
+CullList
+
+Builds a new list that doesn't hold the given brush
+===========
+*/
+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;
+}
+
+
+/*
+==================
+WriteBrushMap
+==================
+*/
+void WriteBrushMap (char *name, bspbrush_t *list)
+{
+ FILE *f;
+ side_t *s;
+ int i;
+ winding_t *w;
+
+ printf ("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);
+
+}
+
+/*
+==================
+BrushGE
+
+Returns true if b1 is allowed to bite b2
+==================
+*/
+qboolean BrushGE (bspbrush_t *b1, bspbrush_t *b2)
+{
+ // detail brushes never bite structural brushes
+ if ( (b1->original->contents & CONTENTS_DETAIL)
+ && !(b2->original->contents & CONTENTS_DETAIL) )
+ return false;
+ if (b1->original->contents & CONTENTS_SOLID)
+ return true;
+ return false;
+}
+
+/*
+=================
+ChopBrushes
+
+Carves any intersecting solid brushes into the minimum number
+of non-intersecting brushes.
+=================
+*/
+bspbrush_t *ChopBrushes (bspbrush_t *head)
+{
+ bspbrush_t *b1, *b2, *next;
+ bspbrush_t *tail;
+ bspbrush_t *keep;
+ bspbrush_t *sub, *sub2;
+ int c1, c2;
+
+ qprintf ("---- ChopBrushes ----\n");
+ qprintf ("original brushes: %i\n", CountBrushList (head));
+
+#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;
+ 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
+ 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
+ // (commening 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;
+ }
+ else
+ {
+ if (sub)
+ FreeBrushList (sub);
+ tail = AddBrushListToTail (sub2, tail);
+ head = CullList (b1, b2);
+ goto newlist;
+ }
+ }
+
+ if (!b2)
+ { // b1 is no longer intersecting anything, so keep it
+ b1->next = keep;
+ keep = b1;
+ }
+ }
+
+ qprintf ("output brushes: %i\n", CountBrushList (keep));
+#if 0
+ {
+ WriteBrushList ("after.gl", keep, false);
+ WriteBrushMap ("after.map", keep);
+ }
+#endif
+ return keep;
+}
+
+
+/*
+=================
+InitialBrushList
+=================
+*/
+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].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].visible = false;
+ }
+ }
+
+ return out;
+}
+
+/*
+=================
+OptimizedBrushList
+=================
+*/
+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].visible)
+ break;
+ if (i == b->numsides)
+ continue;
+ newb = CopyBrush (b);
+ newb->next = out;
+ out = newb;
+ }
+
+// WriteBrushList ("vis.gl", out, true);
+
+ return out;
+}
--- /dev/null
+/*
+===========================================================================
+Copyright (C) 1997-2006 Id Software, Inc.
+
+This file is part of Quake 2 Tools source code.
+
+Quake 2 Tools 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 2 Tools 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 Quake 2 Tools source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#include "qbsp.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];
+
+
+float subdivide_size = 240;
+
+
+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 beeb 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, 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 = malloc(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);
+ free (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
+
+===========================================================================
+*/
+
+#define CONTINUOUS_EPSILON 0.001
+
+/*
+=============
+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]) > EQUAL_EPSILON)
+ break;
+ if (fabs(p2[k] - p3[k]) > EQUAL_EPSILON)
+ break;
+ }
+ if (k==3)
+ break;
+ }
+ if (j < f2->numpoints)
+ break;
+ }
+
+ 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, 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, 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;
+}
+
+/*
+=============
+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;
+ 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, 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);
+}
--- /dev/null
+/*
+===========================================================================
+Copyright (C) 1997-2006 Id Software, Inc.
+
+This file is part of Quake 2 Tools source code.
+
+Quake 2 Tools 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 2 Tools 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 Quake 2 Tools source code; 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;
+}
--- /dev/null
+/*
+===========================================================================
+Copyright (C) 1997-2006 Id Software, Inc.
+
+This file is part of Quake 2 Tools source code.
+
+Quake 2 Tools 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 2 Tools 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 Quake 2 Tools source code; 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);
+}
+
--- /dev/null
+/*
+===========================================================================
+Copyright (C) 1997-2006 Id Software, Inc.
+
+This file is part of Quake 2 Tools source code.
+
+Quake 2 Tools 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 2 Tools 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 Quake 2 Tools source code; 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);
+ 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);
+}
+
--- /dev/null
+
+CFLAGS = -c
+LDFLAGS =
+ODIR = baddir
+
+EXEBASE = qbsp3
+EXE = $(ODIR)/qbsp3
+all: $(EXE)
+
+_next:
+ make "CFLAGS = -c -g -I../../common -DDOUBLEVEC_T" "ODIR = next"
+
+_irix:
+ make "CFLAGS = -c -Ofast=ip27 -OPT:IEEE_arithmetic=3 -I../../common -Xcpluscomm -DDOUBLEVEC_T" "LDFLAGS = -Ofast=ip27 -OPT:IEEE_arithmetic=3" "ODIR = irix"
+
+_irixdebug:
+ make "CFLAGS = -c -O2 -g -I../../common -Xcpluscomm -DDOUBLEVEC_T" "LDFLAGS = -g" "ODIR = irix"
+
+_irixinst:
+ make "CFLAGS = -c -Ofast=ip27 -OPT:IEEE_arithmetic=3 -I../../common -Xcpluscomm -DDOUBLEVEC_T" "LDFLAGS = -Ofast=ip27 -OPT:IEEE_arithmetic=3" "ODIR = irix"
+ cp irix/$(EXEBASE) /limbo/quake2/bin_irix
+
+_irixclean:
+ rm -f irix/*.o irix/$(EXEBASE)
+
+_osf:
+ make "CFLAGS = -c -O4 -I../../common -threads -DDOUBLEVEC_T" "LDFLAGS = -threads" "ODIR = osf"
+
+clean:
+ rm -f irix/*.o irix/$(EXEBASE)
+
+install:
+ cp irix/$(EXEBASE) /limbo/quake2/bin_irix
+
+
+FILES = $(ODIR)/brushbsp.o $(ODIR)/bspfile.o $(ODIR)/cmdlib.o $(ODIR)/faces.o $(ODIR)/nodraw.o $(ODIR)/glfile.o $(ODIR)/leakfile.o $(ODIR)/map.o $(ODIR)/mathlib.o $(ODIR)/polylib.o $(ODIR)/portals.o $(ODIR)/prtfile.o $(ODIR)/qbsp3.o $(ODIR)/scriplib.o $(ODIR)/textures.o $(ODIR)/threads.o $(ODIR)/tree.o $(ODIR)/writebsp.o $(ODIR)/csg.o
+
+$(EXE) : $(FILES)
+ cc -o $(EXE) $(LDFLAGS) $(FILES) -lm
+
+$(ODIR)/brushbsp.o : brushbsp.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/faces.o : faces.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/nodraw.o : nodraw.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/glfile.o : glfile.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/leakfile.o : leakfile.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/map.o : map.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/portals.o : portals.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/prtfile.o : prtfile.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/qbsp3.o : qbsp3.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/tree.o : tree.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/textures.o : textures.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/writebsp.o : writebsp.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/csg.o : csg.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/cmdlib.o : ../../common/cmdlib.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/mathlib.o : ../../common/mathlib.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/polylib.o : ../../common/polylib.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/scriplib.o : ../../common/scriplib.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/threads.o : ../../common/threads.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/bspfile.o : ../../common/bspfile.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
--- /dev/null
+/*
+===========================================================================
+Copyright (C) 1997-2006 Id Software, Inc.
+
+This file is part of Quake 2 Tools source code.
+
+Quake 2 Tools 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 2 Tools 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 Quake 2 Tools source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#include "qbsp.h"
+
+extern qboolean onlyents;
+
+int nummapbrushes;
+mapbrush_t mapbrushes[MAX_MAP_BRUSHES];
+
+int nummapbrushsides;
+side_t brushsides[MAX_MAP_SIDES];
+brush_texture_t side_brushtextures[MAX_MAP_SIDES];
+
+int nummapplanes;
+plane_t mapplanes[MAX_MAP_PLANES];
+
+#define PLANE_HASHES 1024
+plane_t *planehash[PLANE_HASHES];
+
+vec3_t map_mins, map_maxs;
+
+// undefine to make plane finding use linear sort
+#define USE_HASHING
+
+void TestExpandBrushes (void);
+
+int c_boxbevels;
+int c_edgebevels;
+
+int c_areaportals;
+
+int c_clipbrushes;
+
+/*
+=============================================================================
+
+PLANE FINDING
+
+=============================================================================
+*/
+
+
+/*
+=================
+PlaneTypeForNormal
+=================
+*/
+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;
+}
+
+/*
+================
+PlaneEqual
+================
+*/
+#define NORMAL_EPSILON 0.00001
+#define DIST_EPSILON 0.01
+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;
+}
+
+/*
+================
+AddPlaneToHash
+================
+*/
+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;
+}
+
+/*
+================
+CreateNewFloatPlane
+================
+*/
+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_MAP_PLANES)
+ Error ("MAX_MAP_PLANES");
+
+ p = &mapplanes[nummapplanes];
+ VectorCopy (normal, p->normal);
+ p->dist = dist;
+ p->type = (p+1)->type = PlaneTypeForNormal (p->normal);
+
+ VectorSubtract (vec3_origin, normal, (p+1)->normal);
+ (p+1)->dist = -dist;
+
+ 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;
+}
+
+/*
+==============
+SnapVector
+==============
+*/
+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;
+ }
+ }
+}
+
+/*
+==============
+SnapPlane
+==============
+*/
+void SnapPlane (vec3_t normal, vec_t *dist)
+{
+ SnapVector (normal);
+
+ if (fabs(*dist-Q_rint(*dist)) < DIST_EPSILON)
+ *dist = Q_rint(*dist);
+}
+
+/*
+=============
+FindFloatPlane
+
+=============
+*/
+#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))
+ return i;
+ }
+
+ return CreateNewFloatPlane (normal, dist);
+}
+#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))
+ return p-mapplanes;
+ }
+ }
+
+ return CreateNewFloatPlane (normal, dist);
+}
+#endif
+
+/*
+================
+PlaneFromPoints
+================
+*/
+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, normal);
+
+ dist = DotProduct (p0, normal);
+
+ return FindFloatPlane (normal, dist);
+}
+
+
+//====================================================================
+
+
+/*
+===========
+BrushContents
+===========
+*/
+int 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)
+ {
+ printf ("Entity %i, Brush %i: mixed face contents\n"
+ , b->entitynum, b->brushnum);
+ break;
+ }
+ }
+
+ // if any side is translucent, mark the contents
+ // and change solid to window
+ if ( trans & (SURF_TRANS33|SURF_TRANS66) )
+ {
+ contents |= CONTENTS_TRANSLUCENT;
+ if (contents & CONTENTS_SOLID)
+ {
+ contents &= ~CONTENTS_SOLID;
+ contents |= CONTENTS_WINDOW;
+ }
+ }
+
+ return contents;
+}
+
+
+//============================================================================
+
+/*
+=================
+AddBrushBevels
+
+Adds any additional planes necessary to allow the brush to be expanded
+against axial bounding boxes
+=================
+*/
+void AddBrushBevels (mapbrush_t *b)
+{
+ int axis, dir;
+ int i, j, k, l, order;
+ side_t sidetemp;
+ brush_texture_t tdtemp;
+ 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;
+ s->contents = b->original_sides[0].contents;
+ s->bevel = true;
+ 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;
+ }
+ }
+ }
+
+ //
+ // 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, 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, 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;
+ s2->contents = b->original_sides[0].contents;
+ s2->bevel = true;
+ c_edgebevels++;
+ b->numsides++;
+ }
+ }
+ }
+ }
+}
+
+
+/*
+================
+MakeBrushWindings
+
+makes basewindigs for sides and mins / maxs for the brush
+================
+*/
+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].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->visible = true;
+ for (j=0 ; j<w->numpoints ; j++)
+ AddPointToBounds (w->p[j], ob->mins, ob->maxs);
+ }
+ }
+
+ for (i=0 ; i<3 ; i++)
+ {
+ if (ob->mins[0] < -4096 || ob->maxs[0] > 4096)
+ printf ("entity %i, brush %i: bounds out of range\n", ob->entitynum, ob->brushnum);
+ if (ob->mins[0] > 4096 || ob->maxs[0] < -4096)
+ printf ("entity %i, brush %i: no visible sides on brush\n", ob->entitynum, ob->brushnum);
+ }
+
+ return true;
+}
+
+
+/*
+=================
+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;
+ 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);
+ td.rotate = atoi(token);
+ GetToken (false);
+ td.scale[0] = atof(token);
+ GetToken (false);
+ td.scale[1] = atof(token);
+
+ // 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;
+
+ if (TokenAvailable())
+ {
+ GetToken (false);
+ side->contents = atoi(token);
+ GetToken (false);
+ side->surf = td.flags = atoi(token);
+ GetToken (false);
+ td.value = atoi(token);
+ }
+
+ // 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;
+ }
+
+
+ //
+ // 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;
+ 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 = 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 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 ();
+ e->next = mapent->epairs;
+ mapent->epairs = e;
+ }
+ } 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")))
+ {
+ 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);
+ MoveBrushesToWorld (mapent);
+ return true;
+ }
+
+ return true;
+}
+
+//===================================================================
+
+/*
+================
+LoadMapFile
+================
+*/
+void LoadMapFile (char *filename)
+{
+ int i;
+
+ 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);
+ }
+
+ 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]);
+
+// TestExpandBrushes ();
+}
+
+
+//====================================================================
+
+
+/*
+================
+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;
+
+ printf ("writing %s\n", name);
+ f = fopen (name, "wb");
+ if (!f)
+ Error ("Can't write %s\b", 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");
+}
--- /dev/null
+/*
+===========================================================================
+Copyright (C) 1997-2006 Id Software, Inc.
+
+This file is part of Quake 2 Tools source code.
+
+Quake 2 Tools 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 2 Tools 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 Quake 2 Tools source code; 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)
+{
+}
--- /dev/null
+/*
+===========================================================================
+Copyright (C) 1997-2006 Id Software, Inc.
+
+This file is part of Quake 2 Tools source code.
+
+Quake 2 Tools 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 2 Tools 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 Quake 2 Tools source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#include "qbsp.h"
+
+
+int c_active_portals;
+int c_peak_portals;
+int c_boundary;
+int c_boundary_sides;
+
+/*
+===========
+AllocPortal
+===========
+*/
+portal_t *AllocPortal (void)
+{
+ portal_t *p;
+
+ if (numthreads == 1)
+ c_active_portals++;
+ if (c_active_portals > c_peak_portals)
+ c_peak_portals = c_active_portals;
+
+ p = malloc (sizeof(portal_t));
+ memset (p, 0, sizeof(portal_t));
+
+ return p;
+}
+
+void FreePortal (portal_t *p)
+{
+ if (p->winding)
+ FreeWinding (p->winding);
+ if (numthreads == 1)
+ c_active_portals--;
+ free (p);
+}
+
+//==============================================================
+
+/*
+==============
+VisibleContents
+
+Returns the single content bit of the
+strongest visible content present
+==============
+*/
+int VisibleContents (int contents)
+{
+ int i;
+
+ for (i=1 ; i<=LAST_VISIBLE_CONTENTS ; i<<=1)
+ if (contents & i )
+ return i;
+
+ return 0;
+}
+
+
+/*
+===============
+ClusterContents
+===============
+*/
+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;
+}
+
+/*
+=============
+Portal_VisFlood
+
+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 leafs, so all contents should be ored together
+=============
+*/
+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_TRANSLUCENT|CONTENTS_DETAIL))
+ c1 = 0;
+ if (c2 & (CONTENTS_TRANSLUCENT|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;
+}
+
+
+/*
+===============
+Portal_EntityFlood
+
+The entity flood determines which areas are
+"outside" on the map, which are then filled in.
+Flowing from side s to side !s
+===============
+*/
+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;
+
+/*
+=============
+AddPortalToNodes
+=============
+*/
+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;
+}
+
+
+/*
+=============
+RemovePortalFromNode
+=============
+*/
+void RemovePortalFromNode (portal_t *portal, node_t *l)
+{
+ portal_t **pp, *t;
+
+// 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;
+ }
+ else if (portal->nodes[1] == l)
+ {
+ *pp = portal->next[1];
+ portal->nodes[1] = NULL;
+ }
+}
+
+//============================================================================
+
+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]);
+}
+
+/*
+================
+MakeHeadnodePortals
+
+The created portals will face the global outside_node
+================
+*/
+#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 leafs
+ for (i=0 ; i<3 ; i++)
+ {
+ bounds[0][i] = tree->mins[i] - SIDESPACE;
+ bounds[1][i] = tree->maxs[i] + SIDESPACE;
+ }
+
+ 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);
+ }
+ }
+}
+
+//===================================================
+
+
+/*
+================
+BaseWindingForNode
+================
+*/
+#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;
+}
+
+//============================================================
+
+qboolean WindingIsTiny (winding_t *w);
+
+/*
+==================
+MakeNodePortal
+
+create the new portal by taking the full plane winding for the cutting plane
+and clipping it by all of parents of this node
+==================
+*/
+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;
+ }
+ else if (p->nodes[1] == node)
+ {
+ side = 1;
+ VectorSubtract (vec3_origin, p->plane.normal, normal);
+ dist = -p->plane.dist;
+ }
+ else
+ Error ("CutNodePortals_r: mislinked portal");
+
+ ChopWindingInPlace (&w, normal, dist, 0.1);
+ }
+
+ if (!w)
+ {
+ return;
+ }
+
+ if (WindingIsTiny (w))
+ {
+ c_tinyportals++;
+ FreeWinding (w);
+ return;
+ }
+
+
+ new_portal = AllocPortal ();
+ new_portal->plane = mapplanes[node->planenum];
+ new_portal->onnode = node;
+ new_portal->winding = w;
+ AddPortalToNodes (new_portal, node->children[0], node->children[1]);
+}
+
+
+/*
+==============
+SplitNodePortals
+
+Move or split the portals that bound node so that the node's
+children have portals instead of node.
+==============
+*/
+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 ("CutNodePortals_r: 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++;
+ }
+
+ if (backwinding && WindingIsTiny(backwinding))
+ {
+ FreeWinding (backwinding);
+ backwinding = NULL;
+ c_tinyportals++;
+ }
+
+ 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);
+ }
+ else
+ {
+ AddPortalToNodes (p, other_node, f);
+ AddPortalToNodes (new_portal, other_node, b);
+ }
+ }
+
+ node->portals = NULL;
+}
+
+
+/*
+================
+CalcNodeBounds
+================
+*/
+void CalcNodeBounds (node_t *node)
+{
+ portal_t *p;
+ int s;
+ int i;
+
+ // calc mins/maxs for both leafs 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);
+ }
+}
+
+
+/*
+==================
+MakeTreePortals_r
+==================
+*/
+void MakeTreePortals_r (node_t *node)
+{
+ int i;
+
+ CalcNodeBounds (node);
+ if (node->mins[0] >= node->maxs[0])
+ {
+ printf ("WARNING: node without a volume\n");
+ }
+
+ for (i=0 ; i<3 ; i++)
+ {
+ if (node->mins[i] < -8000 || node->maxs[i] > 8000)
+ {
+ printf ("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]);
+}
+
+/*
+==================
+MakeTreePortals
+==================
+*/
+void MakeTreePortals (tree_t *tree)
+{
+ MakeHeadnodePortals (tree);
+ MakeTreePortals_r (tree->headnode);
+}
+
+/*
+=========================================================
+
+FLOOD ENTITIES
+
+=========================================================
+*/
+
+/*
+=============
+FloodPortals_r
+=============
+*/
+void FloodPortals_r (node_t *node, int dist)
+{
+ portal_t *p;
+ int s;
+
+ node->occupied = dist;
+
+ for (p=node->portals ; p ; p = p->next[s])
+ {
+ s = (p->nodes[1] == node);
+
+ if (p->nodes[!s]->occupied)
+ continue;
+
+ if (!Portal_EntityFlood (p, s))
+ continue;
+
+ FloodPortals_r (p->nodes[!s], dist+1);
+ }
+}
+
+/*
+=============
+PlaceOccupant
+=============
+*/
+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)
+ {
+ 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->contents == CONTENTS_SOLID)
+ return false;
+ node->occupant = occupant;
+
+ FloodPortals_r (node, 1);
+
+ return true;
+}
+
+/*
+=============
+FloodEntities
+
+Marks all nodes that can be reached by entites
+=============
+*/
+qboolean FloodEntities (tree_t *tree)
+{
+ int i;
+ vec3_t origin;
+ char *cl;
+ qboolean inside;
+ node_t *headnode;
+
+ headnode = tree->headnode;
+ qprintf ("--- FloodEntities ---\n");
+ inside = false;
+ tree->outside_node.occupied = 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
+
+ // nudge playerstart around if needed so clipping hulls allways
+ // have a vlaid point
+ if (!strcmp (cl, "info_player_start"))
+ {
+ int x, y;
+
+ 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;
+ goto gotit;
+ }
+ origin[0] -= x;
+ origin[1] -= y;
+ }
+ }
+gotit: ;
+ }
+ else
+ {
+ if (PlaceOccupant (headnode, origin, &entities[i]))
+ inside = true;
+ }
+ }
+
+ if (!inside)
+ {
+ qprintf ("no entities in open -- no filling\n");
+ }
+ else if (tree->outside_node.occupied)
+ {
+ qprintf ("entity reached from outside -- no filling\n");
+ }
+
+ return (qboolean)(inside && !tree->outside_node.occupied);
+}
+
+/*
+=========================================================
+
+FLOOD AREAS
+
+=========================================================
+*/
+
+int c_areas;
+
+/*
+=============
+FloodAreas_r
+=============
+*/
+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])
+ {
+ printf ("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;
+ }
+
+ 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]);
+ }
+}
+
+/*
+=============
+FindAreas_r
+
+Just decend the tree, and for each node that hasn't had an
+area set, flood fill out from there
+=============
+*/
+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);
+}
+
+/*
+=============
+SetAreaPortalAreas_r
+
+Just decend the tree, and for each node that hasn't had an
+area set, flood fill out from there
+=============
+*/
+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;
+ }
+
+ 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])
+ {
+ printf ("WARNING: areaportal entity %i doesn't touch two areas\n", b->original->entitynum);
+ return;
+ }
+ }
+}
+
+/*
+=============
+EmitAreaPortals
+
+=============
+*/
+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++;
+ }
+ else if (e->portalareas[1] == i)
+ {
+ dp->portalnum = e->areaportalnum;
+ dp->otherarea = e->portalareas[0];
+ numareaportals++;
+ }
+ }
+ dareas[i].numareaportals = numareaportals - dareas[i].firstareaportal;
+ }
+
+ qprintf ("%5i numareas\n", numareas);
+ qprintf ("%5i numareaportals\n", numareaportals);
+}
+
+/*
+=============
+FloodAreas
+
+Mark each leaf with an area, bounded by CONTENTS_AREAPORTAL
+=============
+*/
+void FloodAreas (tree_t *tree)
+{
+ qprintf ("--- FloodAreas ---\n");
+ FindAreas_r (tree->headnode);
+ SetAreaPortalAreas_r (tree->headnode);
+ qprintf ("%5i areas\n", c_areas);
+}
+
+//======================================================
+
+int c_outside;
+int c_inside;
+int c_solid;
+
+void FillOutside_r (node_t *node)
+{
+ if (node->planenum != PLANENUM_LEAF)
+ {
+ FillOutside_r (node->children[0]);
+ FillOutside_r (node->children[1]);
+ return;
+ }
+
+ // anything not reachable by an entity
+ // can be filled away
+ if (!node->occupied)
+ {
+ if (node->contents != CONTENTS_SOLID)
+ {
+ c_outside++;
+ node->contents = CONTENTS_SOLID;
+ }
+ else
+ c_solid++;
+ }
+ else
+ c_inside++;
+
+}
+
+/*
+=============
+FillOutside
+
+Fill all nodes that can't be reached by entities
+=============
+*/
+void FillOutside (node_t *headnode)
+{
+ c_outside = 0;
+ c_inside = 0;
+ c_solid = 0;
+ qprintf ("--- FillOutside ---\n");
+ FillOutside_r (headnode);
+ qprintf ("%5i solid leafs\n", c_solid);
+ qprintf ("%5i leafs filled\n", c_outside);
+ qprintf ("%5i inside leafs\n", c_inside);
+}
+
+
+//==============================================================
+
+/*
+============
+FindPortalSide
+
+Finds a brush side to use for texturing the given portal
+============
+*/
+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->bevel)
+ continue;
+ if (side->texinfo == TEXINFO_NODE)
+ continue; // non-visible
+ if ((side->planenum&~1) == planenum)
+ { // exact match
+ bestside = &brush->original_sides[i];
+ goto gotit;
+ }
+ // see how close the match is
+ p2 = &mapplanes[side->planenum&~1];
+ dot = DotProduct (p1->normal, p2->normal);
+ if (dot > bestdot)
+ {
+ bestdot = dot;
+ bestside = side;
+ }
+ }
+ }
+ }
+
+gotit:
+ if (!bestside)
+ qprintf ("WARNING: side not found for portal\n");
+
+ p->sidefound = true;
+ p->side = bestside;
+}
+
+
+/*
+===============
+MarkVisibleSides_r
+
+===============
+*/
+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;
+ }
+
+ // empty leafs are never boundary leafs
+ 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->visible = true;
+ }
+
+}
+
+/*
+=============
+MarkVisibleSides
+
+=============
+*/
+void MarkVisibleSides (tree_t *tree, int startbrush, int endbrush)
+{
+ int i, j;
+ mapbrush_t *mb;
+ int numsides;
+
+ qprintf ("--- 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].visible = false;
+ }
+
+ // set visible flags on the sides that are used by portals
+ MarkVisibleSides_r (tree->headnode);
+}
+
--- /dev/null
+/*
+===========================================================================
+Copyright (C) 1997-2006 Id Software, Inc.
+
+This file is part of Quake 2 Tools source code.
+
+Quake 2 Tools 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 2 Tools 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 Quake 2 Tools source code; 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 WriteFloat (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,"(");
+ WriteFloat (pf, w->p[i][0]);
+ WriteFloat (pf, w->p[i][1]);
+ WriteFloat (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;
+
+ FreeTreePortals_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);
+}
+
--- /dev/null
+/*
+===========================================================================
+Copyright (C) 1997-2006 Id Software, Inc.
+
+This file is part of Quake 2 Tools source code.
+
+Quake 2 Tools 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 2 Tools 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 Quake 2 Tools source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#include "cmdlib.h"
+#include "mathlib.h"
+#include "scriplib.h"
+#include "polylib.h"
+#include "threads.h"
+#include "bspfile.h"
+
+#define MAX_BRUSH_SIDES 128
+#define CLIP_EPSILON 0.1
+
+#define BOGUS_RANGE 8192
+
+#define TEXINFO_NODE -1 // side is allready on a node
+
+typedef struct plane_s
+{
+ vec3_t normal;
+ vec_t dist;
+ int type;
+ struct plane_s *hash_chain;
+} plane_t;
+
+typedef struct
+{
+ vec_t shift[2];
+ vec_t rotate;
+ vec_t scale[2];
+ char name[32];
+ int flags;
+ int value;
+} brush_texture_t;