Q2Tools source - didn't import this in initially
authorTimothee TTimo Besset <ttimo@idsoftware.com>
Sat, 7 Apr 2012 23:53:01 +0000 (18:53 -0500)
committerTimothee TTimo Besset <ttimo@idsoftware.com>
Sat, 7 Apr 2012 23:53:01 +0000 (18:53 -0500)
131 files changed:
tools/quake2/extra/COPYING.txt [new file with mode: 0644]
tools/quake2/extra/Unpack/Unpack.dsp [new file with mode: 0644]
tools/quake2/extra/Unpack/Unpack.dsw [new file with mode: 0644]
tools/quake2/extra/Unpack/Unpack.java [new file with mode: 0644]
tools/quake2/extra/bsp/bsp.mak [new file with mode: 0644]
tools/quake2/extra/bsp/bspinfo3/bspinfo3.c [new file with mode: 0644]
tools/quake2/extra/bsp/bspinfo3/makefile [new file with mode: 0644]
tools/quake2/extra/bsp/qbsp3/brushbsp.c [new file with mode: 0644]
tools/quake2/extra/bsp/qbsp3/csg.c [new file with mode: 0644]
tools/quake2/extra/bsp/qbsp3/faces.c [new file with mode: 0644]
tools/quake2/extra/bsp/qbsp3/gldraw.c [new file with mode: 0644]
tools/quake2/extra/bsp/qbsp3/glfile.c [new file with mode: 0644]
tools/quake2/extra/bsp/qbsp3/leakfile.c [new file with mode: 0644]
tools/quake2/extra/bsp/qbsp3/makefile [new file with mode: 0644]
tools/quake2/extra/bsp/qbsp3/map.c [new file with mode: 0644]
tools/quake2/extra/bsp/qbsp3/nodraw.c [new file with mode: 0644]
tools/quake2/extra/bsp/qbsp3/portals.c [new file with mode: 0644]
tools/quake2/extra/bsp/qbsp3/prtfile.c [new file with mode: 0644]
tools/quake2/extra/bsp/qbsp3/qbsp.h [new file with mode: 0644]
tools/quake2/extra/bsp/qbsp3/qbsp3.c [new file with mode: 0644]
tools/quake2/extra/bsp/qbsp3/textures.c [new file with mode: 0644]
tools/quake2/extra/bsp/qbsp3/tree.c [new file with mode: 0644]
tools/quake2/extra/bsp/qbsp3/writebsp.c [new file with mode: 0644]
tools/quake2/extra/bsp/qrad3/lightmap.c [new file with mode: 0644]
tools/quake2/extra/bsp/qrad3/makefile [new file with mode: 0644]
tools/quake2/extra/bsp/qrad3/patches.c [new file with mode: 0644]
tools/quake2/extra/bsp/qrad3/qrad.h [new file with mode: 0644]
tools/quake2/extra/bsp/qrad3/qrad3.c [new file with mode: 0644]
tools/quake2/extra/bsp/qrad3/trace.c [new file with mode: 0644]
tools/quake2/extra/bsp/qvis3/flow.c [new file with mode: 0644]
tools/quake2/extra/bsp/qvis3/makefile [new file with mode: 0644]
tools/quake2/extra/bsp/qvis3/qvis3.c [new file with mode: 0644]
tools/quake2/extra/bsp/qvis3/vis.h [new file with mode: 0644]
tools/quake2/extra/common/bspfile.c [new file with mode: 0644]
tools/quake2/extra/common/bspfile.h [new file with mode: 0644]
tools/quake2/extra/common/cmdlib.c [new file with mode: 0644]
tools/quake2/extra/common/cmdlib.h [new file with mode: 0644]
tools/quake2/extra/common/l3dslib.c [new file with mode: 0644]
tools/quake2/extra/common/l3dslib.h [new file with mode: 0644]
tools/quake2/extra/common/lbmlib.c [new file with mode: 0644]
tools/quake2/extra/common/lbmlib.h [new file with mode: 0644]
tools/quake2/extra/common/mathlib.c [new file with mode: 0644]
tools/quake2/extra/common/mathlib.h [new file with mode: 0644]
tools/quake2/extra/common/mdfour.c [new file with mode: 0644]
tools/quake2/extra/common/mdfour.h [new file with mode: 0644]
tools/quake2/extra/common/polylib.c [new file with mode: 0644]
tools/quake2/extra/common/polylib.h [new file with mode: 0644]
tools/quake2/extra/common/qfiles.h [new file with mode: 0644]
tools/quake2/extra/common/scriplib.c [new file with mode: 0644]
tools/quake2/extra/common/scriplib.h [new file with mode: 0644]
tools/quake2/extra/common/threads.c [new file with mode: 0644]
tools/quake2/extra/common/threads.h [new file with mode: 0644]
tools/quake2/extra/common/trilib.c [new file with mode: 0644]
tools/quake2/extra/common/trilib.h [new file with mode: 0644]
tools/quake2/extra/qdata/anorms.h [new file with mode: 0644]
tools/quake2/extra/qdata/images.c [new file with mode: 0644]
tools/quake2/extra/qdata/makefile [new file with mode: 0644]
tools/quake2/extra/qdata/models.c [new file with mode: 0644]
tools/quake2/extra/qdata/qdata.c [new file with mode: 0644]
tools/quake2/extra/qdata/qdata.dsp [new file with mode: 0644]
tools/quake2/extra/qdata/qdata.dsw [new file with mode: 0644]
tools/quake2/extra/qdata/qdata.h [new file with mode: 0644]
tools/quake2/extra/qdata/qdata.mak [new file with mode: 0644]
tools/quake2/extra/qdata/sprites.c [new file with mode: 0644]
tools/quake2/extra/qdata/tables.c [new file with mode: 0644]
tools/quake2/extra/qdata/video.c [new file with mode: 0644]
tools/quake2/extra/qe4/brush.c [new file with mode: 0644]
tools/quake2/extra/qe4/brush.h [new file with mode: 0644]
tools/quake2/extra/qe4/bspfile.h [new file with mode: 0644]
tools/quake2/extra/qe4/camera.c [new file with mode: 0644]
tools/quake2/extra/qe4/camera.h [new file with mode: 0644]
tools/quake2/extra/qe4/cmdlib.c [new file with mode: 0644]
tools/quake2/extra/qe4/cmdlib.h [new file with mode: 0644]
tools/quake2/extra/qe4/csg.c [new file with mode: 0644]
tools/quake2/extra/qe4/drag.c [new file with mode: 0644]
tools/quake2/extra/qe4/eclass.c [new file with mode: 0644]
tools/quake2/extra/qe4/entity.c [new file with mode: 0644]
tools/quake2/extra/qe4/entity.h [new file with mode: 0644]
tools/quake2/extra/qe4/entityw.h [new file with mode: 0644]
tools/quake2/extra/qe4/glingr.h [new file with mode: 0644]
tools/quake2/extra/qe4/icon1.ico [new file with mode: 0644]
tools/quake2/extra/qe4/lbmlib.c [new file with mode: 0644]
tools/quake2/extra/qe4/lbmlib.h [new file with mode: 0644]
tools/quake2/extra/qe4/makefile [new file with mode: 0644]
tools/quake2/extra/qe4/map.c [new file with mode: 0644]
tools/quake2/extra/qe4/map.h [new file with mode: 0644]
tools/quake2/extra/qe4/mathlib.c [new file with mode: 0644]
tools/quake2/extra/qe4/mathlib.h [new file with mode: 0644]
tools/quake2/extra/qe4/mru.c [new file with mode: 0644]
tools/quake2/extra/qe4/mru.h [new file with mode: 0644]
tools/quake2/extra/qe4/parse.c [new file with mode: 0644]
tools/quake2/extra/qe4/parse.h [new file with mode: 0644]
tools/quake2/extra/qe4/points.c [new file with mode: 0644]
tools/quake2/extra/qe4/q.bmp [new file with mode: 0644]
tools/quake2/extra/qe4/qe3.c [new file with mode: 0644]
tools/quake2/extra/qe4/qe3.h [new file with mode: 0644]
tools/quake2/extra/qe4/qe4.mak [new file with mode: 0644]
tools/quake2/extra/qe4/qedefs.h [new file with mode: 0644]
tools/quake2/extra/qe4/qfiles.h [new file with mode: 0644]
tools/quake2/extra/qe4/resource.h [new file with mode: 0644]
tools/quake2/extra/qe4/select.c [new file with mode: 0644]
tools/quake2/extra/qe4/select.h [new file with mode: 0644]
tools/quake2/extra/qe4/textures.c [new file with mode: 0644]
tools/quake2/extra/qe4/textures.h [new file with mode: 0644]
tools/quake2/extra/qe4/toolbar1.bmp [new file with mode: 0644]
tools/quake2/extra/qe4/vertsel.c [new file with mode: 0644]
tools/quake2/extra/qe4/view.h [new file with mode: 0644]
tools/quake2/extra/qe4/win_cam.c [new file with mode: 0644]
tools/quake2/extra/qe4/win_dlg.c [new file with mode: 0644]
tools/quake2/extra/qe4/win_ent.c [new file with mode: 0644]
tools/quake2/extra/qe4/win_main.c [new file with mode: 0644]
tools/quake2/extra/qe4/win_qe3.aps [new file with mode: 0644]
tools/quake2/extra/qe4/win_qe3.c [new file with mode: 0644]
tools/quake2/extra/qe4/win_qe3.rc [new file with mode: 0644]
tools/quake2/extra/qe4/win_xy.c [new file with mode: 0644]
tools/quake2/extra/qe4/win_z.c [new file with mode: 0644]
tools/quake2/extra/qe4/xy.c [new file with mode: 0644]
tools/quake2/extra/qe4/xy.h [new file with mode: 0644]
tools/quake2/extra/qe4/z.c [new file with mode: 0644]
tools/quake2/extra/qe4/z.h [new file with mode: 0644]
tools/quake2/extra/texpaint/docs.txt [new file with mode: 0644]
tools/quake2/extra/texpaint/resource.h [new file with mode: 0644]
tools/quake2/extra/texpaint/texmake.aps [new file with mode: 0644]
tools/quake2/extra/texpaint/texmake.rc [new file with mode: 0644]
tools/quake2/extra/texpaint/texpaint.c [new file with mode: 0644]
tools/quake2/extra/texpaint/texpaint.h [new file with mode: 0644]
tools/quake2/extra/texpaint/texpaint.mak [new file with mode: 0644]
tools/quake2/extra/texpaint/win_cam.c [new file with mode: 0644]
tools/quake2/extra/texpaint/win_main.c [new file with mode: 0644]
tools/quake2/extra/texpaint/win_pal.c [new file with mode: 0644]
tools/quake2/extra/texpaint/win_skin.c [new file with mode: 0644]

diff --git a/tools/quake2/extra/COPYING.txt b/tools/quake2/extra/COPYING.txt
new file mode 100644 (file)
index 0000000..98443f3
--- /dev/null
@@ -0,0 +1,281 @@
+                   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
diff --git a/tools/quake2/extra/Unpack/Unpack.dsp b/tools/quake2/extra/Unpack/Unpack.dsp
new file mode 100644 (file)
index 0000000..89bea7c
--- /dev/null
@@ -0,0 +1,72 @@
+# 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
diff --git a/tools/quake2/extra/Unpack/Unpack.dsw b/tools/quake2/extra/Unpack/Unpack.dsw
new file mode 100644 (file)
index 0000000..29aef98
--- /dev/null
@@ -0,0 +1,29 @@
+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>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/tools/quake2/extra/Unpack/Unpack.java b/tools/quake2/extra/Unpack/Unpack.java
new file mode 100644 (file)
index 0000000..a18e72f
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+===========================================================================
+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() );
+               }
+       }
+
+}
diff --git a/tools/quake2/extra/bsp/bsp.mak b/tools/quake2/extra/bsp/bsp.mak
new file mode 100644 (file)
index 0000000..17218de
--- /dev/null
@@ -0,0 +1,1776 @@
+# 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
+################################################################################
diff --git a/tools/quake2/extra/bsp/bspinfo3/bspinfo3.c b/tools/quake2/extra/bsp/bspinfo3/bspinfo3.c
new file mode 100644 (file)
index 0000000..75a414f
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+===========================================================================
+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");
+       }
+}
diff --git a/tools/quake2/extra/bsp/bspinfo3/makefile b/tools/quake2/extra/bsp/bspinfo3/makefile
new file mode 100644 (file)
index 0000000..96ac757
--- /dev/null
@@ -0,0 +1,53 @@
+
+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
diff --git a/tools/quake2/extra/bsp/qbsp3/brushbsp.c b/tools/quake2/extra/bsp/qbsp3/brushbsp.c
new file mode 100644 (file)
index 0000000..a111bd3
--- /dev/null
@@ -0,0 +1,1330 @@
+/*
+===========================================================================
+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;
+}
+
diff --git a/tools/quake2/extra/bsp/qbsp3/csg.c b/tools/quake2/extra/bsp/qbsp3/csg.c
new file mode 100644 (file)
index 0000000..2d69aa2
--- /dev/null
@@ -0,0 +1,635 @@
+/*
+===========================================================================
+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;
+}
diff --git a/tools/quake2/extra/bsp/qbsp3/faces.c b/tools/quake2/extra/bsp/qbsp3/faces.c
new file mode 100644 (file)
index 0000000..1bbc922
--- /dev/null
@@ -0,0 +1,1076 @@
+/*
+===========================================================================
+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);
+}
diff --git a/tools/quake2/extra/bsp/qbsp3/gldraw.c b/tools/quake2/extra/bsp/qbsp3/gldraw.c
new file mode 100644 (file)
index 0000000..08ab9c4
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+===========================================================================
+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;
+}
diff --git a/tools/quake2/extra/bsp/qbsp3/glfile.c b/tools/quake2/extra/bsp/qbsp3/glfile.c
new file mode 100644 (file)
index 0000000..6d76777
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+===========================================================================
+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);
+}
+
diff --git a/tools/quake2/extra/bsp/qbsp3/leakfile.c b/tools/quake2/extra/bsp/qbsp3/leakfile.c
new file mode 100644 (file)
index 0000000..53d4837
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+===========================================================================
+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);
+}
+
diff --git a/tools/quake2/extra/bsp/qbsp3/makefile b/tools/quake2/extra/bsp/qbsp3/makefile
new file mode 100644 (file)
index 0000000..7368e5b
--- /dev/null
@@ -0,0 +1,98 @@
+
+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
diff --git a/tools/quake2/extra/bsp/qbsp3/map.c b/tools/quake2/extra/bsp/qbsp3/map.c
new file mode 100644 (file)
index 0000000..232979c
--- /dev/null
@@ -0,0 +1,1017 @@
+/*
+===========================================================================
+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");
+}
diff --git a/tools/quake2/extra/bsp/qbsp3/nodraw.c b/tools/quake2/extra/bsp/qbsp3/nodraw.c
new file mode 100644 (file)
index 0000000..fd6959d
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+===========================================================================
+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)
+{
+}
diff --git a/tools/quake2/extra/bsp/qbsp3/portals.c b/tools/quake2/extra/bsp/qbsp3/portals.c
new file mode 100644 (file)
index 0000000..ef57cae
--- /dev/null
@@ -0,0 +1,1111 @@
+/*
+===========================================================================
+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);
+}
+
diff --git a/tools/quake2/extra/bsp/qbsp3/prtfile.c b/tools/quake2/extra/bsp/qbsp3/prtfile.c
new file mode 100644 (file)
index 0000000..2a5b08f
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+===========================================================================
+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);
+}
+
diff --git a/tools/quake2/extra/bsp/qbsp3/qbsp.h b/tools/quake2/extra/bsp/qbsp3/qbsp.h
new file mode 100644 (file)
index 0000000..af032e4
--- /dev/null
@@ -0,0 +1,355 @@
+/*
+===========================================================================
+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;