tools/heretic2: move heretic2 stuff to its own directory
authorThomas Debesse <dev@illwieckz.net>
Fri, 5 Jul 2019 22:33:50 +0000 (00:33 +0200)
committerThomas Debesse <dev@illwieckz.net>
Sat, 13 Jul 2019 17:57:15 +0000 (19:57 +0200)
134 files changed:
Makefile
tools/CMakeLists.txt
tools/heretic2/CMakeLists.txt [new file with mode: 0644]
tools/heretic2/common/bspfile.c [new file with mode: 0644]
tools/heretic2/common/bspfile.h [new file with mode: 0644]
tools/heretic2/common/cmdlib.c [new file with mode: 0644]
tools/heretic2/common/cmdlib.h [new file with mode: 0644]
tools/heretic2/common/her2_threads.h [new file with mode: 0644]
tools/heretic2/common/inout.c [new file with mode: 0644]
tools/heretic2/common/inout.h [new file with mode: 0644]
tools/heretic2/common/l3dslib.c [new file with mode: 0644]
tools/heretic2/common/l3dslib.h [new file with mode: 0644]
tools/heretic2/common/lbmlib.c [new file with mode: 0644]
tools/heretic2/common/lbmlib.h [new file with mode: 0644]
tools/heretic2/common/mathlib.c [new file with mode: 0644]
tools/heretic2/common/mathlib.h [new file with mode: 0644]
tools/heretic2/common/md4.c [new file with mode: 0644]
tools/heretic2/common/md4.h [new file with mode: 0644]
tools/heretic2/common/path_init.c [new file with mode: 0644]
tools/heretic2/common/polylib.c [new file with mode: 0644]
tools/heretic2/common/polylib.h [new file with mode: 0644]
tools/heretic2/common/qfiles.c [new file with mode: 0644]
tools/heretic2/common/qfiles.h [new file with mode: 0644]
tools/heretic2/common/scriplib.c [new file with mode: 0644]
tools/heretic2/common/scriplib.h [new file with mode: 0644]
tools/heretic2/common/threads.c [new file with mode: 0644]
tools/heretic2/common/token.c [new file with mode: 0644]
tools/heretic2/common/token.h [new file with mode: 0644]
tools/heretic2/common/trilib.c [new file with mode: 0644]
tools/heretic2/common/trilib.h [new file with mode: 0644]
tools/heretic2/h2data/adpcm.h [new file with mode: 0644]
tools/heretic2/h2data/animcomp.c [new file with mode: 0644]
tools/heretic2/h2data/animcomp.h [new file with mode: 0644]
tools/heretic2/h2data/anorms.h [new file with mode: 0644]
tools/heretic2/h2data/book.c [new file with mode: 0644]
tools/heretic2/h2data/fmodels.c [new file with mode: 0644]
tools/heretic2/h2data/h2data.rc [new file with mode: 0644]
tools/heretic2/h2data/images.c [new file with mode: 0644]
tools/heretic2/h2data/jointed.c [new file with mode: 0644]
tools/heretic2/h2data/jointed.h [new file with mode: 0644]
tools/heretic2/h2data/joints.h [new file with mode: 0644]
tools/heretic2/h2data/models.c [new file with mode: 0644]
tools/heretic2/h2data/pics.c [new file with mode: 0644]
tools/heretic2/h2data/qd_fmodel.h [new file with mode: 0644]
tools/heretic2/h2data/qd_skeletons.c [new file with mode: 0644]
tools/heretic2/h2data/qd_skeletons.h [new file with mode: 0644]
tools/heretic2/h2data/qdata.c [new file with mode: 0644]
tools/heretic2/h2data/qdata.h [new file with mode: 0644]
tools/heretic2/h2data/resource.h [new file with mode: 0644]
tools/heretic2/h2data/sprites.c [new file with mode: 0644]
tools/heretic2/h2data/svdcmp.c [new file with mode: 0644]
tools/heretic2/h2data/tables.c [new file with mode: 0644]
tools/heretic2/h2data/tmix.c [new file with mode: 0644]
tools/heretic2/h2data/video.c [new file with mode: 0644]
tools/heretic2/qcommon/angles.h [new file with mode: 0644]
tools/heretic2/qcommon/arrayedlist.h [new file with mode: 0644]
tools/heretic2/qcommon/flex.h [new file with mode: 0644]
tools/heretic2/qcommon/fmodel.h [new file with mode: 0644]
tools/heretic2/qcommon/h2common.h [new file with mode: 0644]
tools/heretic2/qcommon/placement.h [new file with mode: 0644]
tools/heretic2/qcommon/q_typedef.h [new file with mode: 0644]
tools/heretic2/qcommon/qfiles.h [new file with mode: 0644]
tools/heretic2/qcommon/reference.c [new file with mode: 0644]
tools/heretic2/qcommon/reference.h [new file with mode: 0644]
tools/heretic2/qcommon/resourcemanager.c [new file with mode: 0644]
tools/heretic2/qcommon/resourcemanager.h [new file with mode: 0644]
tools/heretic2/qcommon/skeletons.c [new file with mode: 0644]
tools/heretic2/qcommon/skeletons.h [new file with mode: 0644]
tools/quake2/qdata_heretic2/CMakeLists.txt [deleted file]
tools/quake2/qdata_heretic2/adpcm.h [deleted file]
tools/quake2/qdata_heretic2/animcomp.c [deleted file]
tools/quake2/qdata_heretic2/animcomp.h [deleted file]
tools/quake2/qdata_heretic2/anorms.h [deleted file]
tools/quake2/qdata_heretic2/book.c [deleted file]
tools/quake2/qdata_heretic2/common/bspfile.c [deleted file]
tools/quake2/qdata_heretic2/common/bspfile.h [deleted file]
tools/quake2/qdata_heretic2/common/cmdlib.c [deleted file]
tools/quake2/qdata_heretic2/common/cmdlib.h [deleted file]
tools/quake2/qdata_heretic2/common/her2_threads.h [deleted file]
tools/quake2/qdata_heretic2/common/inout.c [deleted file]
tools/quake2/qdata_heretic2/common/inout.h [deleted file]
tools/quake2/qdata_heretic2/common/l3dslib.c [deleted file]
tools/quake2/qdata_heretic2/common/l3dslib.h [deleted file]
tools/quake2/qdata_heretic2/common/lbmlib.c [deleted file]
tools/quake2/qdata_heretic2/common/lbmlib.h [deleted file]
tools/quake2/qdata_heretic2/common/mathlib.c [deleted file]
tools/quake2/qdata_heretic2/common/mathlib.h [deleted file]
tools/quake2/qdata_heretic2/common/md4.c [deleted file]
tools/quake2/qdata_heretic2/common/md4.h [deleted file]
tools/quake2/qdata_heretic2/common/path_init.c [deleted file]
tools/quake2/qdata_heretic2/common/polylib.c [deleted file]
tools/quake2/qdata_heretic2/common/polylib.h [deleted file]
tools/quake2/qdata_heretic2/common/qfiles.c [deleted file]
tools/quake2/qdata_heretic2/common/qfiles.h [deleted file]
tools/quake2/qdata_heretic2/common/scriplib.c [deleted file]
tools/quake2/qdata_heretic2/common/scriplib.h [deleted file]
tools/quake2/qdata_heretic2/common/threads.c [deleted file]
tools/quake2/qdata_heretic2/common/token.c [deleted file]
tools/quake2/qdata_heretic2/common/token.h [deleted file]
tools/quake2/qdata_heretic2/common/trilib.c [deleted file]
tools/quake2/qdata_heretic2/common/trilib.h [deleted file]
tools/quake2/qdata_heretic2/fmodels.c [deleted file]
tools/quake2/qdata_heretic2/h2data.rc [deleted file]
tools/quake2/qdata_heretic2/images.c [deleted file]
tools/quake2/qdata_heretic2/jointed.c [deleted file]
tools/quake2/qdata_heretic2/jointed.h [deleted file]
tools/quake2/qdata_heretic2/joints.h [deleted file]
tools/quake2/qdata_heretic2/models.c [deleted file]
tools/quake2/qdata_heretic2/pics.c [deleted file]
tools/quake2/qdata_heretic2/qcommon/angles.h [deleted file]
tools/quake2/qdata_heretic2/qcommon/arrayedlist.h [deleted file]
tools/quake2/qdata_heretic2/qcommon/flex.h [deleted file]
tools/quake2/qdata_heretic2/qcommon/fmodel.h [deleted file]
tools/quake2/qdata_heretic2/qcommon/h2common.h [deleted file]
tools/quake2/qdata_heretic2/qcommon/placement.h [deleted file]
tools/quake2/qdata_heretic2/qcommon/q_typedef.h [deleted file]
tools/quake2/qdata_heretic2/qcommon/qfiles.h [deleted file]
tools/quake2/qdata_heretic2/qcommon/reference.c [deleted file]
tools/quake2/qdata_heretic2/qcommon/reference.h [deleted file]
tools/quake2/qdata_heretic2/qcommon/resourcemanager.c [deleted file]
tools/quake2/qdata_heretic2/qcommon/resourcemanager.h [deleted file]
tools/quake2/qdata_heretic2/qcommon/skeletons.c [deleted file]
tools/quake2/qdata_heretic2/qcommon/skeletons.h [deleted file]
tools/quake2/qdata_heretic2/qd_fmodel.h [deleted file]
tools/quake2/qdata_heretic2/qd_skeletons.c [deleted file]
tools/quake2/qdata_heretic2/qd_skeletons.h [deleted file]
tools/quake2/qdata_heretic2/qdata.c [deleted file]
tools/quake2/qdata_heretic2/qdata.h [deleted file]
tools/quake2/qdata_heretic2/resource.h [deleted file]
tools/quake2/qdata_heretic2/sprites.c [deleted file]
tools/quake2/qdata_heretic2/svdcmp.c [deleted file]
tools/quake2/qdata_heretic2/tables.c [deleted file]
tools/quake2/qdata_heretic2/tmix.c [deleted file]
tools/quake2/qdata_heretic2/video.c [deleted file]

index 85049a8..cdfbff0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1019,38 +1019,38 @@ $(INSTALLDIR)/plugins/bkgrnd2d.$(DLL): \
        contrib/bkgrnd2d/plugin.o \
 
 $(INSTALLDIR)/heretic2/h2data.$(EXE): LIBS_EXTRA := $(LIBS_XML)
-$(INSTALLDIR)/heretic2/h2data.$(EXE): CPPFLAGS_EXTRA := $(CPPFLAGS_XML) -Itools/quake2/qdata_heretic2/common -Itools/quake2/qdata_heretic2/qcommon -Itools/quake2/qdata_heretic2 -Itools/quake2/common -Ilibs -Iinclude
+$(INSTALLDIR)/heretic2/h2data.$(EXE): CPPFLAGS_EXTRA := $(CPPFLAGS_XML) -Itools/heretic2/common -Itools/heretic2/qcommon -Itools/heretic2/h2data -Itools/quake2/common -Ilibs -Iinclude
 $(INSTALLDIR)/heretic2/h2data.$(EXE): \
-       tools/quake2/qdata_heretic2/common/bspfile.o \
-       tools/quake2/qdata_heretic2/common/cmdlib.o \
-       tools/quake2/qdata_heretic2/common/inout.o \
-       tools/quake2/qdata_heretic2/common/l3dslib.o \
-       tools/quake2/qdata_heretic2/common/lbmlib.o \
-       tools/quake2/qdata_heretic2/common/mathlib.o \
-       tools/quake2/qdata_heretic2/common/md4.o \
-       tools/quake2/qdata_heretic2/common/path_init.o \
-       tools/quake2/qdata_heretic2/common/qfiles.o \
-       tools/quake2/qdata_heretic2/common/scriplib.o \
-       tools/quake2/qdata_heretic2/common/threads.o \
-       tools/quake2/qdata_heretic2/common/token.o \
-       tools/quake2/qdata_heretic2/common/trilib.o \
-       tools/quake2/qdata_heretic2/qcommon/reference.o \
-       tools/quake2/qdata_heretic2/qcommon/resourcemanager.o \
-       tools/quake2/qdata_heretic2/qcommon/skeletons.o \
-       tools/quake2/qdata_heretic2/animcomp.o \
-       tools/quake2/qdata_heretic2/book.o \
-       tools/quake2/qdata_heretic2/fmodels.o \
-       tools/quake2/qdata_heretic2/images.o \
-       tools/quake2/qdata_heretic2/jointed.o \
-       tools/quake2/qdata_heretic2/models.o \
-       tools/quake2/qdata_heretic2/pics.o \
-       tools/quake2/qdata_heretic2/qdata.o \
-       tools/quake2/qdata_heretic2/qd_skeletons.o \
-       tools/quake2/qdata_heretic2/sprites.o \
-       tools/quake2/qdata_heretic2/svdcmp.o \
-       tools/quake2/qdata_heretic2/tables.o \
-       tools/quake2/qdata_heretic2/tmix.o \
-       tools/quake2/qdata_heretic2/video.o \
+       tools/heretic2/common/bspfile.o \
+       tools/heretic2/common/cmdlib.o \
+       tools/heretic2/common/inout.o \
+       tools/heretic2/common/l3dslib.o \
+       tools/heretic2/common/lbmlib.o \
+       tools/heretic2/common/mathlib.o \
+       tools/heretic2/common/md4.o \
+       tools/heretic2/common/path_init.o \
+       tools/heretic2/common/qfiles.o \
+       tools/heretic2/common/scriplib.o \
+       tools/heretic2/common/threads.o \
+       tools/heretic2/common/token.o \
+       tools/heretic2/common/trilib.o \
+       tools/heretic2/qcommon/reference.o \
+       tools/heretic2/qcommon/resourcemanager.o \
+       tools/heretic2/qcommon/skeletons.o \
+       tools/heretic2/h2data/animcomp.o \
+       tools/heretic2/h2data/book.o \
+       tools/heretic2/h2data/fmodels.o \
+       tools/heretic2/h2data/images.o \
+       tools/heretic2/h2data/jointed.o \
+       tools/heretic2/h2data/models.o \
+       tools/heretic2/h2data/pics.o \
+       tools/heretic2/h2data/qdata.o \
+       tools/heretic2/h2data/qd_skeletons.o \
+       tools/heretic2/h2data/sprites.o \
+       tools/heretic2/h2data/svdcmp.o \
+       tools/heretic2/h2data/tables.o \
+       tools/heretic2/h2data/tmix.o \
+       tools/heretic2/h2data/video.o \
        libl_net.$(A) \
        $(if $(findstring $(OS),Win32),icons/h2data.o,) \
 
index b36bb6c..b8f8565 100644 (file)
@@ -1,7 +1,7 @@
 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
 
 add_subdirectory(quake2)
-add_subdirectory(quake2/qdata_heretic2)
+add_subdirectory(heretic2)
 add_subdirectory(quake3)
 
 add_custom_target(tools)
diff --git a/tools/heretic2/CMakeLists.txt b/tools/heretic2/CMakeLists.txt
new file mode 100644 (file)
index 0000000..0cb9cb4
--- /dev/null
@@ -0,0 +1,73 @@
+include_directories(BEFORE h2data common qcommon)
+
+find_package(OpenGL REQUIRED)
+
+find_package(LibXml2 REQUIRED)
+include_directories(${LIBXML2_INCLUDE_DIR})
+
+radiant_tool(h2data
+    h2data/h2data.rc
+
+    common/bspfile.c common/bspfile.h
+    common/cmdlib.c common/cmdlib.h
+    common/inout.c common/inout.h
+    common/l3dslib.c common/l3dslib.h
+    common/lbmlib.c common/lbmlib.h
+    common/mathlib.c common/mathlib.h
+    common/md4.c common/md4.h
+    common/path_init.c
+    common/polylib.c common/polylib.h
+    common/qfiles.c common/qfiles.h
+    common/scriplib.c common/scriplib.h
+    common/threads.c common/her2_threads.h
+    common/token.c common/token.h
+    common/trilib.c common/trilib.h
+
+    qcommon/angles.h
+    qcommon/arrayedlist.h
+    qcommon/flex.h
+    qcommon/fmodel.h
+    qcommon/h2common.h
+    qcommon/placement.h
+    qcommon/qfiles.h
+    qcommon/q_typedef.h
+    qcommon/reference.c qcommon/reference.h
+    qcommon/resourcemanager.c qcommon/resourcemanager.h
+    qcommon/skeletons.c qcommon/skeletons.h
+
+    h2data/adpcm.h
+    h2data/animcomp.c h2data/animcomp.h 
+    h2data/anorms.h
+    h2data/book.c
+    h2data/fmodels.c h2data/qd_fmodel.h
+    h2data/images.c
+    h2data/jointed.c
+    h2data/jointed.h
+    h2data/joints.h
+    h2data/models.c
+    h2data/pics.c
+    h2data/qdata.c h2data/qdata.h
+    h2data/qd_skeletons.c h2data/qd_skeletons.h
+    h2data/resource.h
+    h2data/sprites.c
+    h2data/svdcmp.c
+    h2data/tables.c
+    h2data/tmix.c
+    h2data/video.c
+)
+
+target_compile_definitions(h2data
+    PRIVATE
+)
+
+target_link_libraries(h2data
+    ${LIBXML2_LIBRARIES}
+    l_net
+)
+
+add_custom_target(heretic2)
+add_dependencies(heretic2 h2data)
+
+if (UNIX)
+    target_link_libraries(h2data pthread m)
+endif ()
diff --git a/tools/heretic2/common/bspfile.c b/tools/heretic2/common/bspfile.c
new file mode 100644 (file)
index 0000000..add0ef3
--- /dev/null
@@ -0,0 +1,793 @@
+/*
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+
+#include "cmdlib.h"
+#include "inout.h"
+#include "mathlib.h"
+#include "bspfile.h"
+#include "scriplib.h"
+
+void GetLeafNums( void );
+
+//=============================================================================
+
+int nummodels;
+dmodel_t dmodels[MAX_MAP_MODELS];
+
+int visdatasize;
+byte dvisdata[MAX_MAP_VISIBILITY];
+dvis_t      *dvis = (dvis_t *)dvisdata;
+
+int lightdatasize;
+byte dlightdata[MAX_MAP_LIGHTING];
+
+int entdatasize;
+char dentdata[MAX_MAP_ENTSTRING];
+
+int numleafs;
+dleaf_t dleafs[MAX_MAP_LEAFS];
+
+int numplanes;
+dplane_t dplanes[MAX_MAP_PLANES];
+
+int numvertexes;
+dvertex_t dvertexes[MAX_MAP_VERTS];
+
+int numnodes;
+dnode_t dnodes[MAX_MAP_NODES];
+
+int numtexinfo;
+texinfo_t texinfo[MAX_MAP_TEXINFO];
+
+int numfaces;
+dface_t dfaces[MAX_MAP_FACES];
+
+int numedges;
+dedge_t dedges[MAX_MAP_EDGES];
+
+int numleaffaces;
+unsigned short dleaffaces[MAX_MAP_LEAFFACES];
+
+int numleafbrushes;
+unsigned short dleafbrushes[MAX_MAP_LEAFBRUSHES];
+
+int numsurfedges;
+int dsurfedges[MAX_MAP_SURFEDGES];
+
+int numbrushes;
+dbrush_t dbrushes[MAX_MAP_BRUSHES];
+
+int numbrushsides;
+dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES];
+
+int numareas;
+darea_t dareas[MAX_MAP_AREAS];
+
+int numareaportals;
+dareaportal_t dareaportals[MAX_MAP_AREAPORTALS];
+
+byte dpop[256];
+
+/*
+   ===============
+   CompressVis
+
+   ===============
+ */
+int CompressVis( byte *vis, byte *dest ){
+       int j;
+       int rep;
+       int visrow;
+       byte    *dest_p;
+
+       dest_p = dest;
+//     visrow = (r_numvisleafs + 7)>>3;
+       visrow = ( dvis->numclusters + 7 ) >> 3;
+
+       for ( j = 0 ; j < visrow ; j++ )
+       {
+               *dest_p++ = vis[j];
+               if ( vis[j] ) {
+                       continue;
+               }
+
+               rep = 1;
+               for ( j++; j < visrow ; j++ )
+                       if ( vis[j] || rep == 255 ) {
+                               break;
+                       }
+                       else{
+                               rep++;
+                       }
+               *dest_p++ = rep;
+               j--;
+       }
+
+       return dest_p - dest;
+}
+
+
+/*
+   ===================
+   DecompressVis
+   ===================
+ */
+void DecompressVis( byte *in, byte *decompressed ){
+       int c;
+       byte    *out;
+       int row;
+
+//     row = (r_numvisleafs+7)>>3;
+       row = ( dvis->numclusters + 7 ) >> 3;
+       out = decompressed;
+
+       do
+       {
+               if ( *in ) {
+                       *out++ = *in++;
+                       continue;
+               }
+
+               c = in[1];
+               if ( !c ) {
+                       Error( "DecompressVis: 0 repeat" );
+               }
+               in += 2;
+               while ( c )
+               {
+                       *out++ = 0;
+                       c--;
+               }
+       } while ( out - decompressed < row );
+}
+
+//=============================================================================
+
+/*
+   =============
+   SwapBSPFile
+
+   Byte swaps all data in a bsp file.
+   =============
+ */
+void SwapBSPFile( qboolean todisk ){
+       int i, j;
+       dmodel_t        *d;
+
+
+// models
+       for ( i = 0 ; i < nummodels ; i++ )
+       {
+               d = &dmodels[i];
+
+               d->firstface = LittleLong( d->firstface );
+               d->numfaces = LittleLong( d->numfaces );
+               d->headnode = LittleLong( d->headnode );
+
+               for ( j = 0 ; j < 3 ; j++ )
+               {
+                       d->mins[j] = LittleFloat( d->mins[j] );
+                       d->maxs[j] = LittleFloat( d->maxs[j] );
+                       d->origin[j] = LittleFloat( d->origin[j] );
+               }
+       }
+
+//
+// vertexes
+//
+       for ( i = 0 ; i < numvertexes ; i++ )
+       {
+               for ( j = 0 ; j < 3 ; j++ )
+                       dvertexes[i].point[j] = LittleFloat( dvertexes[i].point[j] );
+       }
+
+//
+// planes
+//
+       for ( i = 0 ; i < numplanes ; i++ )
+       {
+               for ( j = 0 ; j < 3 ; j++ )
+                       dplanes[i].normal[j] = LittleFloat( dplanes[i].normal[j] );
+               dplanes[i].dist = LittleFloat( dplanes[i].dist );
+               dplanes[i].type = LittleLong( dplanes[i].type );
+       }
+
+//
+// texinfos
+//
+       for ( i = 0 ; i < numtexinfo ; i++ )
+       {
+               for ( j = 0 ; j < 8 ; j++ )
+                       texinfo[i].vecs[0][j] = LittleFloat( texinfo[i].vecs[0][j] );
+               texinfo[i].flags = LittleLong( texinfo[i].flags );
+               texinfo[i].value = LittleLong( texinfo[i].value );
+               texinfo[i].nexttexinfo = LittleLong( texinfo[i].nexttexinfo );
+       }
+
+//
+// faces
+//
+       for ( i = 0 ; i < numfaces ; i++ )
+       {
+               dfaces[i].texinfo = LittleShort( dfaces[i].texinfo );
+               dfaces[i].planenum = LittleShort( dfaces[i].planenum );
+               dfaces[i].side = LittleShort( dfaces[i].side );
+               dfaces[i].lighting.c = LittleLong( dfaces[i].lighting.c );
+               dfaces[i].lightofs = LittleLong( dfaces[i].lightofs );
+               dfaces[i].firstedge = LittleLong( dfaces[i].firstedge );
+               dfaces[i].numedges = LittleShort( dfaces[i].numedges );
+       }
+
+//
+// nodes
+//
+       for ( i = 0 ; i < numnodes ; i++ )
+       {
+               dnodes[i].planenum = LittleLong( dnodes[i].planenum );
+               for ( j = 0 ; j < 3 ; j++ )
+               {
+                       dnodes[i].mins[j] = LittleShort( dnodes[i].mins[j] );
+                       dnodes[i].maxs[j] = LittleShort( dnodes[i].maxs[j] );
+               }
+               dnodes[i].children[0] = LittleLong( dnodes[i].children[0] );
+               dnodes[i].children[1] = LittleLong( dnodes[i].children[1] );
+               dnodes[i].firstface = LittleShort( dnodes[i].firstface );
+               dnodes[i].numfaces = LittleShort( dnodes[i].numfaces );
+       }
+
+//
+// leafs
+//
+       for ( i = 0 ; i < numleafs ; i++ )
+       {
+               dleafs[i].contents = LittleLong( dleafs[i].contents );
+               dleafs[i].cluster = LittleShort( dleafs[i].cluster );
+               dleafs[i].area = LittleShort( dleafs[i].area );
+               for ( j = 0 ; j < 3 ; j++ )
+               {
+                       dleafs[i].mins[j] = LittleShort( dleafs[i].mins[j] );
+                       dleafs[i].maxs[j] = LittleShort( dleafs[i].maxs[j] );
+               }
+
+               dleafs[i].firstleafface = LittleShort( dleafs[i].firstleafface );
+               dleafs[i].numleaffaces = LittleShort( dleafs[i].numleaffaces );
+               dleafs[i].firstleafbrush = LittleShort( dleafs[i].firstleafbrush );
+               dleafs[i].numleafbrushes = LittleShort( dleafs[i].numleafbrushes );
+       }
+
+//
+// leaffaces
+//
+       for ( i = 0 ; i < numleaffaces ; i++ )
+               dleaffaces[i] = LittleShort( dleaffaces[i] );
+
+//
+// leafbrushes
+//
+       for ( i = 0 ; i < numleafbrushes ; i++ )
+               dleafbrushes[i] = LittleShort( dleafbrushes[i] );
+
+//
+// surfedges
+//
+       for ( i = 0 ; i < numsurfedges ; i++ )
+               dsurfedges[i] = LittleLong( dsurfedges[i] );
+
+//
+// edges
+//
+       for ( i = 0 ; i < numedges ; i++ )
+       {
+               dedges[i].v[0] = LittleShort( dedges[i].v[0] );
+               dedges[i].v[1] = LittleShort( dedges[i].v[1] );
+       }
+
+//
+// brushes
+//
+       for ( i = 0 ; i < numbrushes ; i++ )
+       {
+               dbrushes[i].firstside = LittleLong( dbrushes[i].firstside );
+               dbrushes[i].numsides = LittleLong( dbrushes[i].numsides );
+               dbrushes[i].contents = LittleLong( dbrushes[i].contents );
+       }
+
+//
+// areas
+//
+       for ( i = 0 ; i < numareas ; i++ )
+       {
+               dareas[i].numareaportals = LittleLong( dareas[i].numareaportals );
+               dareas[i].firstareaportal = LittleLong( dareas[i].firstareaportal );
+       }
+
+//
+// areasportals
+//
+       for ( i = 0 ; i < numareaportals ; i++ )
+       {
+               dareaportals[i].portalnum = LittleLong( dareaportals[i].portalnum );
+               dareaportals[i].otherarea = LittleLong( dareaportals[i].otherarea );
+       }
+
+//
+// brushsides
+//
+       for ( i = 0 ; i < numbrushsides ; i++ )
+       {
+               dbrushsides[i].planenum = LittleShort( dbrushsides[i].planenum );
+               dbrushsides[i].texinfo = LittleShort( dbrushsides[i].texinfo );
+       }
+
+//
+// visibility
+//
+       if ( todisk ) {
+               j = dvis->numclusters;
+       }
+       else{
+               j = LittleLong( dvis->numclusters );
+       }
+       dvis->numclusters = LittleLong( dvis->numclusters );
+       for ( i = 0 ; i < j ; i++ )
+       {
+               dvis->bitofs[i][0] = LittleLong( dvis->bitofs[i][0] );
+               dvis->bitofs[i][1] = LittleLong( dvis->bitofs[i][1] );
+       }
+}
+
+
+dheader_t   *header;
+
+int CopyLump( int lump, void *dest, int size ){
+       int length, ofs;
+
+       length = header->lumps[lump].filelen;
+       ofs = header->lumps[lump].fileofs;
+
+       if ( length % size ) {
+               Error( "LoadBSPFile: odd lump size" );
+       }
+
+       memcpy( dest, (byte *)header + ofs, length );
+
+       return length / size;
+}
+
+/*
+   =============
+   LoadBSPFile
+   =============
+ */
+void    LoadBSPFile( char *filename ){
+       int i;
+
+//
+// load the file header
+//
+       LoadFile( filename, (void **)&header );
+
+// swap the header
+       for ( i = 0 ; i < sizeof( dheader_t ) / 4 ; i++ )
+               ( (int *)header )[i] = LittleLong( ( (int *)header )[i] );
+
+       if ( header->ident != IDBSPHEADER ) {
+               Error( "%s is not a IBSP file", filename );
+       }
+       if ( header->version != BSPVERSION ) {
+               Error( "%s is version %i, not %i", filename, header->version, BSPVERSION );
+       }
+
+       nummodels = CopyLump( LUMP_MODELS, dmodels, sizeof( dmodel_t ) );
+       numvertexes = CopyLump( LUMP_VERTEXES, dvertexes, sizeof( dvertex_t ) );
+       numplanes = CopyLump( LUMP_PLANES, dplanes, sizeof( dplane_t ) );
+       numleafs = CopyLump( LUMP_LEAFS, dleafs, sizeof( dleaf_t ) );
+       numnodes = CopyLump( LUMP_NODES, dnodes, sizeof( dnode_t ) );
+       numtexinfo = CopyLump( LUMP_TEXINFO, texinfo, sizeof( texinfo_t ) );
+       numfaces = CopyLump( LUMP_FACES, dfaces, sizeof( dface_t ) );
+       numleaffaces = CopyLump( LUMP_LEAFFACES, dleaffaces, sizeof( dleaffaces[0] ) );
+       numleafbrushes = CopyLump( LUMP_LEAFBRUSHES, dleafbrushes, sizeof( dleafbrushes[0] ) );
+       numsurfedges = CopyLump( LUMP_SURFEDGES, dsurfedges, sizeof( dsurfedges[0] ) );
+       numedges = CopyLump( LUMP_EDGES, dedges, sizeof( dedge_t ) );
+       numbrushes = CopyLump( LUMP_BRUSHES, dbrushes, sizeof( dbrush_t ) );
+       numbrushsides = CopyLump( LUMP_BRUSHSIDES, dbrushsides, sizeof( dbrushside_t ) );
+       numareas = CopyLump( LUMP_AREAS, dareas, sizeof( darea_t ) );
+       numareaportals = CopyLump( LUMP_AREAPORTALS, dareaportals, sizeof( dareaportal_t ) );
+
+       visdatasize = CopyLump( LUMP_VISIBILITY, dvisdata, 1 );
+       lightdatasize = CopyLump( LUMP_LIGHTING, dlightdata, 1 );
+       entdatasize = CopyLump( LUMP_ENTITIES, dentdata, 1 );
+
+       CopyLump( LUMP_POP, dpop, 1 );
+
+       free( header );      // everything has been copied out
+
+//
+// swap everything
+//
+       SwapBSPFile( false );
+}
+
+
+/*
+   =============
+   LoadBSPFileTexinfo
+
+   Only loads the texinfo lump, so qdata can scan for textures
+   =============
+ */
+void    LoadBSPFileTexinfo( char *filename ){
+       int i;
+       FILE        *f;
+       int length, ofs;
+
+       header = malloc( sizeof( dheader_t ) );
+
+       f = fopen( filename, "rb" );
+       fread( header, sizeof( dheader_t ), 1, f );
+
+// swap the header
+       for ( i = 0 ; i < sizeof( dheader_t ) / 4 ; i++ )
+               ( (int *)header )[i] = LittleLong( ( (int *)header )[i] );
+
+       if ( header->ident != IDBSPHEADER ) {
+               Error( "%s is not a IBSP file", filename );
+       }
+       if ( header->version != BSPVERSION ) {
+               Error( "%s is version %i, not %i", filename, header->version, BSPVERSION );
+       }
+
+
+       length = header->lumps[LUMP_TEXINFO].filelen;
+       ofs = header->lumps[LUMP_TEXINFO].fileofs;
+
+       fseek( f, ofs, SEEK_SET );
+       fread( texinfo, length, 1, f );
+       fclose( f );
+
+       numtexinfo = length / sizeof( texinfo_t );
+
+       free( header );      // everything has been copied out
+
+       SwapBSPFile( false );
+}
+
+
+//============================================================================
+
+FILE        *wadfile;
+dheader_t outheader;
+
+void AddLump( int lumpnum, void *data, int len ){
+       lump_t *lump;
+
+       lump = &header->lumps[lumpnum];
+
+       lump->fileofs = LittleLong( ftell( wadfile ) );
+       lump->filelen = LittleLong( len );
+       SafeWrite( wadfile, data, ( len + 3 ) & ~3 );
+}
+
+/*
+   =============
+   WriteBSPFile
+
+   Swaps the bsp file in place, so it should not be referenced again
+   =============
+ */
+void    WriteBSPFile( char *filename ){
+       header = &outheader;
+       memset( header, 0, sizeof( dheader_t ) );
+
+       SwapBSPFile( true );
+
+       header->ident = LittleLong( IDBSPHEADER );
+       header->version = LittleLong( BSPVERSION );
+
+       wadfile = SafeOpenWrite( filename );
+       SafeWrite( wadfile, header, sizeof( dheader_t ) ); // overwritten later
+
+       AddLump( LUMP_PLANES, dplanes, numplanes * sizeof( dplane_t ) );
+       AddLump( LUMP_LEAFS, dleafs, numleafs * sizeof( dleaf_t ) );
+       AddLump( LUMP_VERTEXES, dvertexes, numvertexes * sizeof( dvertex_t ) );
+       AddLump( LUMP_NODES, dnodes, numnodes * sizeof( dnode_t ) );
+       AddLump( LUMP_TEXINFO, texinfo, numtexinfo * sizeof( texinfo_t ) );
+       AddLump( LUMP_FACES, dfaces, numfaces * sizeof( dface_t ) );
+       AddLump( LUMP_BRUSHES, dbrushes, numbrushes * sizeof( dbrush_t ) );
+       AddLump( LUMP_BRUSHSIDES, dbrushsides, numbrushsides * sizeof( dbrushside_t ) );
+       AddLump( LUMP_LEAFFACES, dleaffaces, numleaffaces * sizeof( dleaffaces[0] ) );
+       AddLump( LUMP_LEAFBRUSHES, dleafbrushes, numleafbrushes * sizeof( dleafbrushes[0] ) );
+       AddLump( LUMP_SURFEDGES, dsurfedges, numsurfedges * sizeof( dsurfedges[0] ) );
+       AddLump( LUMP_EDGES, dedges, numedges * sizeof( dedge_t ) );
+       AddLump( LUMP_MODELS, dmodels, nummodels * sizeof( dmodel_t ) );
+       AddLump( LUMP_AREAS, dareas, numareas * sizeof( darea_t ) );
+       AddLump( LUMP_AREAPORTALS, dareaportals, numareaportals * sizeof( dareaportal_t ) );
+
+       AddLump( LUMP_LIGHTING, dlightdata, lightdatasize );
+       AddLump( LUMP_VISIBILITY, dvisdata, visdatasize );
+       AddLump( LUMP_ENTITIES, dentdata, entdatasize );
+       AddLump( LUMP_POP, dpop, sizeof( dpop ) );
+
+       fseek( wadfile, 0, SEEK_SET );
+       SafeWrite( wadfile, header, sizeof( dheader_t ) );
+       fclose( wadfile );
+}
+
+//============================================================================
+
+/*
+   =============
+   PrintBSPFileSizes
+
+   Dumps info about current file
+   =============
+ */
+void PrintBSPFileSizes( void ){
+       if ( !num_entities ) {
+               ParseEntities();
+       }
+
+       printf( "%5i models       %7i\n"
+                       ,nummodels, (int)( nummodels * sizeof( dmodel_t ) ) );
+       printf( "%5i brushes      %7i\n"
+                       ,numbrushes, (int)( numbrushes * sizeof( dbrush_t ) ) );
+       printf( "%5i brushsides   %7i\n"
+                       ,numbrushsides, (int)( numbrushsides * sizeof( dbrushside_t ) ) );
+       printf( "%5i planes       %7i\n"
+                       ,numplanes, (int)( numplanes * sizeof( dplane_t ) ) );
+       printf( "%5i texinfo      %7i\n"
+                       ,numtexinfo, (int)( numtexinfo * sizeof( texinfo_t ) ) );
+       printf( "%5i entdata      %7i\n", num_entities, entdatasize );
+
+       printf( "\n" );
+
+       printf( "%5i vertexes     %7i\n"
+                       ,numvertexes, (int)( numvertexes * sizeof( dvertex_t ) ) );
+       printf( "%5i nodes        %7i\n"
+                       ,numnodes, (int)( numnodes * sizeof( dnode_t ) ) );
+       printf( "%5i faces        %7i\n"
+                       ,numfaces, (int)( numfaces * sizeof( dface_t ) ) );
+       printf( "%5i leafs        %7i\n"
+                       ,numleafs, (int)( numleafs * sizeof( dleaf_t ) ) );
+       printf( "%5i leaffaces    %7i\n"
+                       ,numleaffaces, (int)( numleaffaces * sizeof( dleaffaces[0] ) ) );
+       printf( "%5i leafbrushes  %7i\n"
+                       ,numleafbrushes, (int)( numleafbrushes * sizeof( dleafbrushes[0] ) ) );
+       printf( "%5i surfedges    %7i\n"
+                       ,numsurfedges, (int)( numsurfedges * sizeof( dsurfedges[0] ) ) );
+       printf( "%5i edges        %7i\n"
+                       ,numedges, (int)( numedges * sizeof( dedge_t ) ) );
+       printf( "      lightdata    %7i\n", lightdatasize );
+       printf( "      visdata      %7i\n", visdatasize );
+}
+
+
+//============================================
+
+int num_entities;
+entity_t entities[MAX_MAP_ENTITIES];
+
+void StripTrailing( char *e ){
+       char    *s;
+
+       s = e + strlen( e ) - 1;
+       while ( s >= e && *s <= 32 )
+       {
+               *s = 0;
+               s--;
+       }
+}
+
+/*
+   =================
+   ParseEpair
+   =================
+ */
+epair_t *ParseEpair( void ){
+       epair_t *e;
+
+       e = malloc( sizeof( epair_t ) );
+       memset( e, 0, sizeof( epair_t ) );
+
+       if ( strlen( token ) >= MAX_KEY - 1 ) {
+               Error( "ParseEpar: token too long" );
+       }
+       e->key = copystring( token );
+       GetScriptToken( false );
+       if ( strlen( token ) >= MAX_VALUE - 1 ) {
+               Error( "ParseEpar: token too long" );
+       }
+       e->value = copystring( token );
+
+       // strip trailing spaces
+       StripTrailing( e->key );
+       StripTrailing( e->value );
+
+       return e;
+}
+
+
+/*
+   ================
+   ParseEntity
+   ================
+ */
+qboolean    ParseEntity( void ){
+       epair_t     *e;
+       entity_t    *mapent;
+
+       if ( !GetScriptToken( true ) ) {
+               return false;
+       }
+
+       if ( strcmp( token, "{" ) ) {
+               Error( "ParseEntity: { not found" );
+       }
+
+       if ( num_entities == MAX_MAP_ENTITIES ) {
+               Error( "num_entities == MAX_MAP_ENTITIES" );
+       }
+
+       mapent = &entities[num_entities];
+       num_entities++;
+
+       do
+       {
+               if ( !GetScriptToken( true ) ) {
+                       Error( "ParseEntity: EOF without closing brace" );
+               }
+               if ( !strcmp( token, "}" ) ) {
+                       break;
+               }
+               e = ParseEpair();
+               e->next = mapent->epairs;
+               mapent->epairs = e;
+       } while ( 1 );
+
+       return true;
+}
+
+/*
+   ================
+   ParseEntities
+
+   Parses the dentdata string into entities
+   ================
+ */
+void ParseEntities( void ){
+       num_entities = 0;
+       ParseFromMemory( dentdata, entdatasize );
+
+       while ( ParseEntity() )
+       {
+       }
+}
+
+
+/*
+   ================
+   UnparseEntities
+
+   Generates the dentdata string from all the entities
+   ================
+ */
+void UnparseEntities( void ){
+       char    *buf, *end;
+       epair_t *ep;
+       char line[2048];
+       int i;
+       char key[1024], value[1024];
+
+       buf = dentdata;
+       end = buf;
+       *end = 0;
+
+       for ( i = 0 ; i < num_entities ; i++ )
+       {
+               ep = entities[i].epairs;
+               if ( !ep ) {
+                       continue;   // ent got removed
+
+               }
+               strcat( end,"{\n" );
+               end += 2;
+
+               for ( ep = entities[i].epairs ; ep ; ep = ep->next )
+               {
+                       strcpy( key, ep->key );
+                       StripTrailing( key );
+                       strcpy( value, ep->value );
+                       StripTrailing( value );
+
+                       sprintf( line, "\"%s\" \"%s\"\n", key, value );
+                       strcat( end, line );
+                       end += strlen( line );
+               }
+               strcat( end,"}\n" );
+               end += 2;
+
+               if ( end > buf + MAX_MAP_ENTSTRING ) {
+                       Error( "Entity text too long" );
+               }
+       }
+       entdatasize = end - buf + 1;
+}
+
+void PrintEntity( entity_t *ent ){
+       epair_t *ep;
+
+       printf( "------- entity %p -------\n", ent );
+       for ( ep = ent->epairs ; ep ; ep = ep->next )
+       {
+               printf( "%s = %s\n", ep->key, ep->value );
+       }
+
+}
+
+void    SetKeyValue( entity_t *ent, char *key, char *value ){
+       epair_t *ep;
+
+       for ( ep = ent->epairs ; ep ; ep = ep->next )
+               if ( !strcmp( ep->key, key ) ) {
+                       free( ep->value );
+                       ep->value = copystring( value );
+                       return;
+               }
+       ep = malloc( sizeof( *ep ) );
+       if ( !ep ) {
+               Error( "SetKeyValue MALLOC failed!  Could not allocate %s bytes.", sizeof( *ep ) );
+       }
+       ep->next = ent->epairs;
+       ent->epairs = ep;
+       ep->key = copystring( key );
+       ep->value = copystring( value );
+}
+
+char    *ValueForKey( entity_t *ent, char *key ){
+       epair_t *ep;
+
+       for ( ep = ent->epairs ; ep ; ep = ep->next )
+               if ( !strcmp( ep->key, key ) ) {
+                       return ep->value;
+               }
+       return "";
+}
+
+vec_t   FloatForKey( entity_t *ent, char *key ){
+       char    *k;
+
+       k = ValueForKey( ent, key );
+       return atof( k );
+}
+
+void    GetVectorForKey( entity_t *ent, char *key, vec3_t vec ){
+       char    *k;
+       double v1, v2, v3;
+
+       k = ValueForKey( ent, key );
+// scanf into doubles, then assign, so it is vec_t size independent
+       v1 = v2 = v3 = 0;
+       sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );
+       vec[0] = v1;
+       vec[1] = v2;
+       vec[2] = v3;
+}
diff --git a/tools/heretic2/common/bspfile.h b/tools/heretic2/common/bspfile.h
new file mode 100644 (file)
index 0000000..f66659b
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef _QBSP3_H
+#define _QBSP3_H
+
+
+#include "qfiles.h"
+
+
+extern int nummodels;
+extern dmodel_t dmodels[MAX_MAP_MODELS];
+
+extern int visdatasize;
+extern byte dvisdata[MAX_MAP_VISIBILITY];
+extern dvis_t      *dvis;
+
+extern int lightdatasize;
+extern byte dlightdata[MAX_MAP_LIGHTING];
+
+extern int entdatasize;
+extern char dentdata[MAX_MAP_ENTSTRING];
+
+extern int numleafs;
+extern dleaf_t dleafs[MAX_MAP_LEAFS];
+
+extern int numplanes;
+extern dplane_t dplanes[MAX_MAP_PLANES];
+
+extern int numvertexes;
+extern dvertex_t dvertexes[MAX_MAP_VERTS];
+
+extern int numnodes;
+extern dnode_t dnodes[MAX_MAP_NODES];
+
+extern int numtexinfo;
+extern texinfo_t texinfo[MAX_MAP_TEXINFO];
+
+extern int numfaces;
+extern dface_t dfaces[MAX_MAP_FACES];
+
+extern int numedges;
+extern dedge_t dedges[MAX_MAP_EDGES];
+
+extern int numleaffaces;
+extern unsigned short dleaffaces[MAX_MAP_LEAFFACES];
+
+extern int numleafbrushes;
+extern unsigned short dleafbrushes[MAX_MAP_LEAFBRUSHES];
+
+extern int numsurfedges;
+extern int dsurfedges[MAX_MAP_SURFEDGES];
+
+extern int numareas;
+extern darea_t dareas[MAX_MAP_AREAS];
+
+extern int numareaportals;
+extern dareaportal_t dareaportals[MAX_MAP_AREAPORTALS];
+
+extern int numbrushes;
+extern dbrush_t dbrushes[MAX_MAP_BRUSHES];
+
+extern int numbrushsides;
+extern dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES];
+
+extern byte dpop[256];
+
+void DecompressVis( byte *in, byte *decompressed );
+int CompressVis( byte *vis, byte *dest );
+
+void    LoadBSPFile( char *filename );
+void    LoadBSPFileTexinfo( char *filename );    // just for qdata
+void    WriteBSPFile( char *filename );
+void    PrintBSPFileSizes( void );
+
+//===============
+
+
+typedef struct epair_s
+{
+       struct epair_s  *next;
+       char    *key;
+       char    *value;
+} epair_t;
+
+typedef struct
+{
+       vec3_t origin;
+       int firstbrush;
+       int numbrushes;
+       epair_t     *epairs;
+
+// only valid for func_areaportals
+       int areaportalnum;
+       int portalareas[2];
+} entity_t;
+
+extern int num_entities;
+extern entity_t entities[MAX_MAP_ENTITIES];
+
+void    ParseEntities( void );
+void    UnparseEntities( void );
+
+void    SetKeyValue( entity_t *ent, char *key, char *value );
+char    *ValueForKey( entity_t *ent, char *key );
+// will return "" if not present
+
+vec_t   FloatForKey( entity_t *ent, char *key );
+void    GetVectorForKey( entity_t *ent, char *key, vec3_t vec );
+
+epair_t *ParseEpair( void );
+
+void PrintEntity( entity_t *ent );
+
+#endif //_QBSP3_H
diff --git a/tools/heretic2/common/cmdlib.c b/tools/heretic2/common/cmdlib.c
new file mode 100644 (file)
index 0000000..c45ff16
--- /dev/null
@@ -0,0 +1,1186 @@
+/*
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+// Nurail: Swiped from quake3/common
+
+#include "cmdlib.h"
+#include "globaldefs.h"
+#include "mathlib.h"
+#include "inout.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if GDEF_OS_WINDOWS
+#include <direct.h>
+#include <windows.h>
+#elif GDEF_OS_NEXT
+#include <libc.h>
+#else // OTHER OSES
+#include <unistd.h>
+#endif // OTHER OSES
+
+#if !GDEF_OS_WINDOWS
+#define strlwr strlower
+#endif // !GDEF_OS_WINDOWS
+
+#define BASEDIRNAME "h"
+#define PATHSEPERATOR '/'
+
+extern qboolean verbose;
+
+qboolean g_dokeypress = false;
+
+qboolean g_nomkdir = false;
+
+
+#ifdef SAFE_MALLOC
+void *safe_malloc( size_t size ){
+       void *p;
+
+       p = malloc( size );
+       if ( !p ) {
+               Error( "safe_malloc failed on allocation of %i bytes", size );
+       }
+
+       return p;
+}
+
+void *safe_malloc_info( size_t size, char* info ){
+       void *p;
+
+       p = malloc( size );
+       if ( !p ) {
+               Error( "%s: safe_malloc failed on allocation of %i bytes", info, size );
+       }
+
+       return p;
+}
+#endif // !SAFE_MALLOC
+
+void *SafeMalloc( size_t n, char *desc ){
+       void *p;
+
+       if ( ( p = malloc( n ) ) == NULL ) {
+               Error( "Failed to allocate %d bytes for '%s'.\n", n, desc );
+       }
+       memset( p, 0, n );
+       return p;
+}
+
+// set these before calling CheckParm
+int myargc;
+char **myargv;
+
+char com_token[1024];
+qboolean com_eof;
+
+qboolean archive;
+char archivedir[1024];
+
+
+/*
+   ===================
+   ExpandWildcards
+
+   Mimic unix command line expansion
+   ===================
+ */
+#define MAX_EX_ARGC 1024
+
+int ex_argc;
+char    *ex_argv[MAX_EX_ARGC];
+
+#if GDEF_OS_WINDOWS
+#include "io.h"
+void ExpandWildcards( int *argc, char ***argv ){
+       struct _finddata_t fileinfo;
+       int handle;
+       int i;
+       char filename[1024];
+       char filebase[1024];
+       char    *path;
+
+       ex_argc = 0;
+       for ( i = 0 ; i < *argc ; i++ )
+       {
+               path = ( *argv )[i];
+               if ( path[0] == '-'
+                        || ( !strstr( path, "*" ) && !strstr( path, "?" ) ) ) {
+                       ex_argv[ex_argc++] = path;
+                       continue;
+               }
+
+               handle = _findfirst( path, &fileinfo );
+               if ( handle == -1 ) {
+                       return;
+               }
+
+               ExtractFilePath( path, filebase );
+
+               do
+               {
+                       sprintf( filename, "%s%s", filebase, fileinfo.name );
+                       ex_argv[ex_argc++] = copystring( filename );
+               } while ( _findnext( handle, &fileinfo ) != -1 );
+
+               _findclose( handle );
+       }
+
+       *argc = ex_argc;
+       *argv = ex_argv;
+}
+#else // !GDEF_OS_WINDOWS
+void ExpandWildcards( int *argc, char ***argv ){
+}
+#endif // !GDEF_OS_WINDOWS
+
+/*
+
+   qdir will hold the path up to the quake directory, including the slash
+
+   f:\quake\
+   /raid/quake/
+
+   gamedir will hold qdir + the game directory (id1, id2, etc)
+
+ */
+
+char qdir[1024];
+char gamedir[1024];
+char writedir[1024];
+
+void SetQdirFromPath( const char *path ){
+       char temp[1024];
+       const char  *c;
+       const char *sep;
+       int len, count;
+
+       if ( !( path[0] == '/' || path[0] == '\\' || path[1] == ':' ) ) { // path is partial
+               Q_getwd( temp );
+               strcat( temp, path );
+               path = temp;
+       }
+
+       // search for "quake2" in path
+
+       len = strlen( BASEDIRNAME );
+       for ( c = path + strlen( path ) - 1 ; c != path ; c-- )
+       {
+               int i;
+
+               if ( !Q_strncasecmp( c, BASEDIRNAME, len ) ) {
+                       //
+                       //strncpy (qdir, path, c+len+2-path);
+                       // the +2 assumes a 2 or 3 following quake which is not the
+                       // case with a retail install
+                       // so we need to add up how much to the next separator
+                       sep = c + len;
+                       count = 1;
+                       while ( *sep && *sep != '/' && *sep != '\\' )
+                       {
+                               sep++;
+                               count++;
+                       }
+                       strncpy( qdir, path, c + len + count - path );
+                       Sys_Printf( "qdir: %s\n", qdir );
+                       for ( i = 0; i < strlen( qdir ); i++ )
+                       {
+                               if ( qdir[i] == '\\' ) {
+                                       qdir[i] = '/';
+                               }
+                       }
+
+                       c += len + count;
+                       while ( *c )
+                       {
+                               if ( *c == '/' || *c == '\\' ) {
+                                       strncpy( gamedir, path, c + 1 - path );
+
+                                       for ( i = 0; i < strlen( gamedir ); i++ )
+                                       {
+                                               if ( gamedir[i] == '\\' ) {
+                                                       gamedir[i] = '/';
+                                               }
+                                       }
+
+                                       Sys_Printf( "gamedir: %s\n", gamedir );
+
+                                       if ( !writedir[0] ) {
+                                               strcpy( writedir, gamedir );
+                                       }
+                                       else if ( writedir[strlen( writedir ) - 1] != '/' ) {
+                                               writedir[strlen( writedir )] = '/';
+                                               writedir[strlen( writedir ) + 1] = 0;
+                                       }
+
+                                       return;
+                               }
+                               c++;
+                       }
+                       Error( "No gamedir in %s", path );
+                       return;
+               }
+       }
+       Error( "SetQdirFromPath: no '%s' in %s", BASEDIRNAME, path );
+}
+
+char *ExpandArg( const char *path ){
+       static char full[1024];
+
+       if ( path[0] != '/' && path[0] != '\\' && path[1] != ':' ) {
+               Q_getwd( full );
+               strcat( full, path );
+       }
+       else{
+               strcpy( full, path );
+       }
+       return full;
+}
+
+char *ExpandPath( const char *path ){
+       static char full[1024];
+       if ( !qdir ) {
+               Error( "ExpandPath called without qdir set" );
+       }
+       if ( path[0] == '/' || path[0] == '\\' || path[1] == ':' ) {
+               strcpy( full, path );
+               return full;
+       }
+       sprintf( full, "%s%s", qdir, path );
+       return full;
+}
+
+char *ExpandGamePath( const char *path ){
+       static char full[1024];
+       if ( !qdir ) {
+               Error( "ExpandGamePath called without qdir set" );
+       }
+       if ( path[0] == '/' || path[0] == '\\' || path[1] == ':' ) {
+               strcpy( full, path );
+               return full;
+       }
+       sprintf( full, "%s%s", gamedir, path );
+       return full;
+}
+
+char *ExpandPathAndArchive( const char *path ){
+       char    *expanded;
+       char archivename[1024];
+
+       expanded = ExpandPath( path );
+
+       if ( archive ) {
+               sprintf( archivename, "%s/%s", archivedir, path );
+               QCopyFile( expanded, archivename );
+       }
+       return expanded;
+}
+
+
+char *copystring( const char *s ){
+       char    *b;
+       b = safe_malloc( strlen( s ) + 1 );
+       strcpy( b, s );
+       return b;
+}
+
+
+
+/*
+   ================
+   I_FloatTime
+   ================
+ */
+double I_FloatTime( void ){
+       time_t t;
+
+       time( &t );
+
+       return t;
+#if 0
+// more precise, less portable
+       struct timeval tp;
+       struct timezone tzp;
+       static int secbase;
+
+       gettimeofday( &tp, &tzp );
+
+       if ( !secbase ) {
+               secbase = tp.tv_sec;
+               return tp.tv_usec / 1000000.0;
+       }
+
+       return ( tp.tv_sec - secbase ) + tp.tv_usec / 1000000.0;
+#endif
+}
+
+void Q_getwd( char *out ){
+       int i = 0;
+
+#if GDEF_OS_WINDOWS
+       _getcwd( out, 256 );
+       strcat( out, "\\" );
+#else // !GDEF_OS_WINDOWS
+       // Gef: Changed from getwd() to getcwd() to avoid potential buffer overflow
+       getcwd( out, 256 );
+       strcat( out, "/" );
+#endif // !GDEF_OS_WINDOWS
+       while ( out[i] != 0 )
+       {
+               if ( out[i] == '\\' ) {
+                       out[i] = '/';
+               }
+               i++;
+       }
+}
+
+
+void Q_mkdir( const char *path ){
+#if GDEF_OS_WINDOWS
+       if ( _mkdir( path ) != -1 ) {
+               return;
+       }
+#else // !GDEF_OS_WINDOWS
+       if ( mkdir( path, 0777 ) != -1 ) {
+               return;
+       }
+#endif // !GDEF_OS_WINDOWS
+       if ( errno != EEXIST ) {
+               Error( "mkdir %s: %s",path, strerror( errno ) );
+       }
+}
+
+/*
+   ============
+   FileTime
+
+   returns -1 if not present
+   ============
+ */
+int FileTime( const char *path ){
+       struct  stat buf;
+
+       if ( stat( path,&buf ) == -1 ) {
+               return -1;
+       }
+
+       return buf.st_mtime;
+}
+
+
+
+/*
+   ==============
+   COM_Parse
+
+   Parse a token out of a string
+   ==============
+ */
+char *COM_Parse( char *data ){
+       int c;
+       int len;
+
+       len = 0;
+       com_token[0] = 0;
+
+       if ( !data ) {
+               return NULL;
+       }
+
+// skip whitespace
+skipwhite:
+       while ( ( c = *data ) <= ' ' )
+       {
+               if ( c == 0 ) {
+                       com_eof = true;
+                       return NULL;            // end of file;
+               }
+               data++;
+       }
+
+// skip // comments
+       if ( c == '/' && data[1] == '/' ) {
+               while ( *data && *data != '\n' )
+                       data++;
+               goto skipwhite;
+       }
+
+
+// handle quoted strings specially
+       if ( c == '\"' ) {
+               data++;
+               do
+               {
+                       c = *data++;
+                       if ( c == '\"' ) {
+                               com_token[len] = 0;
+                               return data;
+                       }
+                       com_token[len] = c;
+                       len++;
+               } while ( 1 );
+       }
+
+// parse single characters
+       if ( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':' ) {
+               com_token[len] = c;
+               len++;
+               com_token[len] = 0;
+               return data + 1;
+       }
+
+// parse a regular word
+       do
+       {
+               com_token[len] = c;
+               data++;
+               len++;
+               c = *data;
+               if ( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':' ) {
+                       break;
+               }
+       } while ( c > 32 );
+
+       com_token[len] = 0;
+       return data;
+}
+
+int Q_strncasecmp( const char *s1, const char *s2, int n ){
+       int c1, c2;
+
+       do
+       {
+               c1 = *s1++;
+               c2 = *s2++;
+
+               if ( !n-- ) {
+                       return 0;       // strings are equal until end point
+
+               }
+               if ( c1 != c2 ) {
+                       if ( c1 >= 'a' && c1 <= 'z' ) {
+                               c1 -= ( 'a' - 'A' );
+                       }
+                       if ( c2 >= 'a' && c2 <= 'z' ) {
+                               c2 -= ( 'a' - 'A' );
+                       }
+                       if ( c1 != c2 ) {
+                               return -1;      // strings not equal
+                       }
+               }
+       } while ( c1 );
+
+       return 0;       // strings are equal
+}
+
+int Q_stricmp( const char *s1, const char *s2 ){
+       return Q_strncasecmp( s1, s2, 99999 );
+}
+
+int Q_strcasecmp( const char *s1, const char *s2 ){
+       return Q_strncasecmp( s1, s2, 99999 );
+}
+
+// NOTE TTimo when switching to Multithread DLL (Release/Debug) in the config
+//   started getting warnings about that function, prolly a duplicate with the runtime function
+//   maybe we still need to have it in linux builds
+/*
+   char *strupr (char *start)
+   {
+    char       *in;
+    in = start;
+    while (*in)
+    {
+   *in = toupper(*in);
+        in++;
+    }
+    return start;
+   }
+ */
+
+char *strlower( char *start ){
+       char    *in;
+       in = start;
+       while ( *in )
+       {
+               *in = tolower( *in );
+               in++;
+       }
+       return start;
+}
+
+
+/*
+   =============================================================================
+
+                        MISC FUNCTIONS
+
+   =============================================================================
+ */
+
+
+/*
+   =================
+   CheckParm
+
+   Checks for the given parameter in the program's command line arguments
+   Returns the argument number (1 to argc-1) or 0 if not present
+   =================
+ */
+int CheckParm( const char *check ){
+       int i;
+
+       for ( i = 1; i < myargc; i++ )
+       {
+               if ( !Q_stricmp( check, myargv[i] ) ) {
+                       return i;
+               }
+       }
+
+       return 0;
+}
+
+
+
+/*
+   ================
+   Q_filelength
+   ================
+ */
+int Q_filelength( FILE *f ){
+       int pos;
+       int end;
+
+       pos = ftell( f );
+       fseek( f, 0, SEEK_END );
+       end = ftell( f );
+       fseek( f, pos, SEEK_SET );
+
+       return end;
+}
+
+
+FILE *SafeOpenWrite( const char *filename ){
+       FILE    *f;
+
+       f = fopen( filename, "wb" );
+
+       if ( !f ) {
+               Error( "Error opening %s: %s",filename,strerror( errno ) );
+       }
+
+       return f;
+}
+
+FILE *SafeOpenRead( const char *filename ){
+       FILE    *f;
+
+       f = fopen( filename, "rb" );
+
+       if ( !f ) {
+               Error( "Error opening %s: %s",filename,strerror( errno ) );
+       }
+
+       return f;
+}
+
+
+void SafeRead( FILE *f, void *buffer, int count ){
+       if ( fread( buffer, 1, count, f ) != (size_t)count ) {
+               Error( "File read failure" );
+       }
+}
+
+
+void SafeWrite( FILE *f, const void *buffer, int count ){
+       if ( fwrite( buffer, 1, count, f ) != (size_t)count ) {
+               Error( "File write failure" );
+       }
+}
+
+
+/*
+   ==============
+   FileExists
+   ==============
+ */
+qboolean    FileExists( const char *filename ){
+       FILE    *f;
+
+       f = fopen( filename, "r" );
+       if ( !f ) {
+               return false;
+       }
+       fclose( f );
+       return true;
+}
+
+/*
+   ==============
+   LoadFile
+   ==============
+ */
+int    LoadFile( const char *filename, void **bufferptr ){
+       FILE    *f;
+       int length;
+       void    *buffer;
+
+       f = SafeOpenRead( filename );
+       length = Q_filelength( f );
+       buffer = safe_malloc( length + 1 );
+       ( (char *)buffer )[length] = 0;
+       SafeRead( f, buffer, length );
+       fclose( f );
+
+       *bufferptr = buffer;
+       return length;
+}
+
+
+/*
+   ==============
+   LoadFileBlock
+   -
+   rounds up memory allocation to 4K boundry
+   -
+   ==============
+ */
+int    LoadFileBlock( const char *filename, void **bufferptr ){
+       FILE    *f;
+       int length, nBlock, nAllocSize;
+       void    *buffer;
+
+       f = SafeOpenRead( filename );
+       length = Q_filelength( f );
+       nAllocSize = length;
+       nBlock = nAllocSize % MEM_BLOCKSIZE;
+       if ( nBlock > 0 ) {
+               nAllocSize += MEM_BLOCKSIZE - nBlock;
+       }
+       buffer = safe_malloc( nAllocSize + 1 );
+       memset( buffer, 0, nAllocSize + 1 );
+       SafeRead( f, buffer, length );
+       fclose( f );
+
+       *bufferptr = buffer;
+       return length;
+}
+
+
+/*
+   ==============
+   TryLoadFile
+
+   Allows failure
+   ==============
+ */
+int    TryLoadFile( const char *filename, void **bufferptr ){
+       FILE    *f;
+       int length;
+       void    *buffer;
+
+       *bufferptr = NULL;
+
+       f = fopen( filename, "rb" );
+       if ( !f ) {
+               return -1;
+       }
+       length = Q_filelength( f );
+       buffer = safe_malloc( length + 1 );
+       ( (char *)buffer )[length] = 0;
+       SafeRead( f, buffer, length );
+       fclose( f );
+
+       *bufferptr = buffer;
+       return length;
+}
+
+
+/*
+   ==============
+   SaveFile
+   ==============
+ */
+void    SaveFile( const char *filename, const void *buffer, int count ){
+       FILE    *f;
+
+       f = SafeOpenWrite( filename );
+       SafeWrite( f, buffer, count );
+       fclose( f );
+}
+
+
+
+void DefaultExtension( char *path, const char *extension ){
+       char    *src;
+//
+// if path doesnt have a .EXT, append extension
+// (extension should include the .)
+//
+       src = path + strlen( path ) - 1;
+
+       while ( *src != '/' && *src != '\\' && src != path )
+       {
+               if ( *src == '.' ) {
+                       return;                 // it has an extension
+               }
+               src--;
+       }
+
+       strcat( path, extension );
+}
+
+
+void DefaultPath( char *path, const char *basepath ){
+       char temp[128];
+
+       if ( path[ 0 ] == '/' || path[ 0 ] == '\\' ) {
+               return;                   // absolute path location
+       }
+       strcpy( temp,path );
+       strcpy( path,basepath );
+       strcat( path,temp );
+}
+
+
+void    StripFilename( char *path ){
+       int length;
+
+       length = strlen( path ) - 1;
+       while ( length > 0 && path[length] != '/' && path[ length ] != '\\' )
+               length--;
+       path[length] = 0;
+}
+
+void    StripExtension( char *path ){
+       int length;
+
+       length = strlen( path ) - 1;
+       while ( length > 0 && path[length] != '.' )
+       {
+               length--;
+               if ( path[length] == '/' || path[ length ] == '\\' ) {
+                       return;     // no extension
+               }
+       }
+       if ( length ) {
+               path[length] = 0;
+       }
+}
+
+
+/*
+   ====================
+   Extract file parts
+   ====================
+ */
+
+// FIXME: should include the slash, otherwise
+// backing to an empty path will be wrong when appending a slash
+void ExtractFilePath( const char *path, char *dest ){
+       const char    *src;
+
+       src = path + strlen( path ) - 1;
+
+//
+// back up until a \ or the start
+//
+       while ( src != path && *( src - 1 ) != '\\' && *( src - 1 ) != '/' )
+               src--;
+
+       memcpy( dest, path, src - path );
+       dest[src - path] = 0;
+}
+
+void ExtractFileBase( const char *path, char *dest ){
+       const char    *src;
+
+       src = path + strlen( path ) - 1;
+
+//
+// back up until a \ or the start
+//
+       while ( src != path && *( src - 1 ) != '/' && *( src - 1 ) != '\\' )
+               src--;
+
+       while ( *src && *src != '.' )
+       {
+               *dest++ = *src++;
+       }
+       *dest = 0;
+}
+
+void ExtractFileExtension( const char *path, char *dest ){
+       const char    *src;
+
+       src = path + strlen( path ) - 1;
+
+//
+// back up until a . or the start
+//
+       while ( src != path && *( src - 1 ) != '.' )
+               src--;
+       if ( src == path ) {
+               *dest = 0;  // no extension
+               return;
+       }
+
+       strcpy( dest,src );
+}
+
+
+/*
+   ==============
+   ParseNum / ParseHex
+   ==============
+ */
+int ParseHex( const char *hex ){
+       const char    *str;
+       int num;
+
+       num = 0;
+       str = hex;
+
+       while ( *str )
+       {
+               num <<= 4;
+               if ( *str >= '0' && *str <= '9' ) {
+                       num += *str - '0';
+               }
+               else if ( *str >= 'a' && *str <= 'f' ) {
+                       num += 10 + *str - 'a';
+               }
+               else if ( *str >= 'A' && *str <= 'F' ) {
+                       num += 10 + *str - 'A';
+               }
+               else{
+                       Error( "Bad hex number: %s",hex );
+               }
+               str++;
+       }
+
+       return num;
+}
+
+
+int ParseNum( const char *str ){
+       if ( str[0] == '$' ) {
+               return ParseHex( str + 1 );
+       }
+       if ( str[0] == '0' && str[1] == 'x' ) {
+               return ParseHex( str + 2 );
+       }
+       return atol( str );
+}
+/*
+   // all output ends up through here
+   void FPrintf (int flag, char *buf)
+   {
+   printf(buf);
+
+   }
+
+   void Sys_FPrintf (int flag, const char *format, ...)
+   {
+   char out_buffer[4096];
+    va_list argptr;
+
+   if ((flag == SYS_VRB) && (verbose == false))
+    return;
+
+   va_start (argptr, format);
+    vsprintf (out_buffer, format, argptr);
+    va_end (argptr);
+
+   FPrintf (flag, out_buffer);
+   }
+
+   void Sys_Printf (const char *format, ...)
+   {
+   char out_buffer[4096];
+    va_list argptr;
+
+   va_start (argptr, format);
+    vsprintf (out_buffer, format, argptr);
+    va_end (argptr);
+
+   FPrintf (SYS_STD, out_buffer);
+   }
+
+   //=================
+   //Error
+   //
+   //For abnormal program terminations
+   //=================
+
+   void Error( const char *error, ...)
+   {
+   char out_buffer[4096];
+   char tmp[4096];
+    va_list argptr;
+
+    va_start (argptr,error);
+    vsprintf (tmp, error, argptr);
+    va_end (argptr);
+
+   sprintf( out_buffer, "************ ERROR ************\n%s\n", tmp );
+
+   FPrintf( SYS_ERR, out_buffer );
+
+    exit (1);
+   }
+
+ */
+
+/*
+   ============================================================================
+
+                    BYTE ORDER FUNCTIONS
+
+   ============================================================================
+ */
+
+#if GDEF_ARCH_ENDIAN_BIG
+
+short   LittleShort( short l ){
+       byte b1,b2;
+
+       b1 = l & 255;
+       b2 = ( l >> 8 ) & 255;
+
+       return ( b1 << 8 ) + b2;
+}
+
+short   BigShort( short l ){
+       return l;
+}
+
+
+int    LittleLong( int l ){
+       byte b1,b2,b3,b4;
+
+       b1 = l & 255;
+       b2 = ( l >> 8 ) & 255;
+       b3 = ( l >> 16 ) & 255;
+       b4 = ( l >> 24 ) & 255;
+
+       return ( (int)b1 << 24 ) + ( (int)b2 << 16 ) + ( (int)b3 << 8 ) + b4;
+}
+
+int    BigLong( int l ){
+       return l;
+}
+
+
+float   LittleFloat( float l ){
+       union {byte b[4]; float f; } in, out;
+
+       in.f = l;
+       out.b[0] = in.b[3];
+       out.b[1] = in.b[2];
+       out.b[2] = in.b[1];
+       out.b[3] = in.b[0];
+
+       return out.f;
+}
+
+float   BigFloat( float l ){
+       return l;
+}
+
+
+#else // !GDEF_ARCH_ENDIAN_BIG
+
+
+short   BigShort( short l ){
+       byte b1,b2;
+
+       b1 = l & 255;
+       b2 = ( l >> 8 ) & 255;
+
+       return ( b1 << 8 ) + b2;
+}
+
+short   LittleShort( short l ){
+       return l;
+}
+
+
+int    BigLong( int l ){
+       byte b1,b2,b3,b4;
+
+       b1 = l & 255;
+       b2 = ( l >> 8 ) & 255;
+       b3 = ( l >> 16 ) & 255;
+       b4 = ( l >> 24 ) & 255;
+
+       return ( (int)b1 << 24 ) + ( (int)b2 << 16 ) + ( (int)b3 << 8 ) + b4;
+}
+
+int    LittleLong( int l ){
+       return l;
+}
+
+float   BigFloat( float l ){
+       union {byte b[4]; float f; } in, out;
+
+       in.f = l;
+       out.b[0] = in.b[3];
+       out.b[1] = in.b[2];
+       out.b[2] = in.b[1];
+       out.b[3] = in.b[0];
+
+       return out.f;
+}
+
+float   LittleFloat( float l ){
+       return l;
+}
+
+#endif // ! GDEF_ARCH_ENDIAN_BIG
+
+
+//=======================================================
+
+
+// FIXME: byte swap?
+
+// this is a 16 bit, non-reflected CRC using the polynomial 0x1021
+// and the initial and final xor values shown below...  in other words, the
+// CCITT standard CRC used by XMODEM
+
+#define CRC_INIT_VALUE  0xffff
+#define CRC_XOR_VALUE   0x0000
+
+static unsigned short crctable[256] =
+{
+       0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+       0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+       0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+       0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+       0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+       0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+       0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+       0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+       0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+       0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+       0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+       0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+       0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+       0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+       0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+       0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+       0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+       0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+       0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+       0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+       0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+       0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+       0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+       0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+       0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+       0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+       0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+       0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+       0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+       0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+       0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+       0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+};
+
+void CRC_Init( unsigned short *crcvalue ){
+       *crcvalue = CRC_INIT_VALUE;
+}
+
+void CRC_ProcessByte( unsigned short *crcvalue, byte data ){
+       *crcvalue = ( *crcvalue << 8 ) ^ crctable[( *crcvalue >> 8 ) ^ data];
+}
+
+unsigned short CRC_Value( unsigned short crcvalue ){
+       return crcvalue ^ CRC_XOR_VALUE;
+}
+//=============================================================================
+
+/*
+   ============
+   CreatePath
+   ============
+ */
+void    CreatePath( const char *path ){
+       const char  *ofs;
+       char c;
+       char dir[1024];
+
+#if GDEF_OS_WINDOWS
+       int olddrive = -1;
+
+       if ( path[1] == ':' ) {
+               olddrive = _getdrive();
+               _chdrive( toupper( path[0] ) - 'A' + 1 );
+       }
+#endif // !GDEF_OS_WINDOWS
+
+       if ( path[1] == ':' ) {
+               path += 2;
+       }
+
+       for ( ofs = path + 1 ; *ofs ; ofs++ )
+       {
+               c = *ofs;
+               if ( c == '/' || c == '\\' ) { // create the directory
+                       memcpy( dir, path, ofs - path );
+                       dir[ ofs - path ] = 0;
+                       Q_mkdir( dir );
+               }
+       }
+
+#if GDEF_OS_WINDOWS
+       if ( olddrive != -1 ) {
+               _chdrive( olddrive );
+       }
+#endif // !GDEF_OS_WINDOWS
+}
+
+
+/*
+   ============
+   QCopyFile
+
+   Used to archive source files
+   ============
+ */
+void QCopyFile( const char *from, const char *to ){
+       void    *buffer;
+       int length;
+
+       length = LoadFile( from, &buffer );
+       CreatePath( to );
+       SaveFile( to, buffer, length );
+       free( buffer );
+}
+
+void Sys_Sleep( int n ){
+#if GDEF_OS_WINDOWS
+       Sleep( n );
+#else // !GDEF_OS_WINDOWS
+       usleep( n * 1000 );
+#endif // !GDEF_OS_WINDOWS
+}
diff --git a/tools/heretic2/common/cmdlib.h b/tools/heretic2/common/cmdlib.h
new file mode 100644 (file)
index 0000000..b8b1aa3
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+// cmdlib.h
+
+#ifndef __CMDLIB__
+#define __CMDLIB__
+
+#if GDEF_COMPILER_MSVC
+#pragma warning(disable : 4244)     // MIPS
+#pragma warning(disable : 4136)     // X86
+#pragma warning(disable : 4051)     // ALPHA
+
+#pragma warning(disable : 4018)     // signed/unsigned mismatch
+#pragma warning(disable : 4305)     // truncate from double to float
+
+#pragma check_stack(off)
+
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <stdarg.h>
+
+#if GDEF_COMPILER_MSVC
+
+#pragma intrinsic( memset, memcpy )
+
+#endif
+
+#ifndef __BYTEBOOL__
+  #define __BYTEBOOL__
+//typedef enum {false, true} qboolean;
+//typedef unsigned char byte;
+  #include "q_typedef.h"
+#endif
+
+#ifdef PATH_MAX
+#define MAX_OS_PATH     PATH_MAX
+#else
+#define MAX_OS_PATH     1024
+#endif
+#define MEM_BLOCKSIZE 4096
+/*
+   extern      qboolean verbose;
+   #define SYS_VRB 0 // verbose support (on/off)
+   #define SYS_STD 1 // standard print level
+   #define SYS_WRN 2 // warnings
+   #define SYS_ERR 3 // error
+ */
+// the dec offsetof macro doesnt work very well...
+#define myoffsetof( type,identifier ) ( (size_t)& ( (type *)0 )->identifier )
+
+#define SAFE_MALLOC
+#ifdef SAFE_MALLOC
+void *safe_malloc( size_t size );
+void *safe_malloc_info( size_t size, char* info );
+#else
+#define safe_malloc( a ) malloc( a )
+#endif /* SAFE_MALLOC */
+
+// set these before calling CheckParm
+extern int myargc;
+extern char **myargv;
+
+char *strlower( char *in );
+int Q_strncasecmp( const char *s1, const char *s2, int n );
+int Q_stricmp( const char *s1, const char *s2 );
+int Q_strcasecmp( const char *s1, const char *s2 );
+void Q_getwd( char *out );
+
+int Q_filelength( FILE *f );
+int FileTime( const char *path );
+
+void    Q_mkdir( const char *path );
+
+extern char qdir[1024];
+extern char gamedir[1024];
+extern char writedir[1024];
+extern char    *moddirparam;
+void SetQdirFromPath( const char *path );
+char *ExpandArg( const char *path );    // from cmd line
+char *ExpandPath( const char *path );   // from scripts
+char *ExpandGamePath( const char *path );
+char *ExpandPathAndArchive( const char *path );
+void ExpandWildcards( int *argc, char ***argv );
+
+
+double I_FloatTime( void );
+
+int     CheckParm( const char *check );
+
+void    *SafeMalloc( size_t n, char *desc );
+FILE    *SafeOpenWrite( const char *filename );
+FILE    *SafeOpenRead( const char *filename );
+void    SafeRead( FILE *f, void *buffer, int count );
+void    SafeWrite( FILE *f, const void *buffer, int count );
+
+int     LoadFile( const char *filename, void **bufferptr );
+int   LoadFileBlock( const char *filename, void **bufferptr );
+int     TryLoadFile( const char *filename, void **bufferptr );
+void    SaveFile( const char *filename, const void *buffer, int count );
+qboolean    FileExists( const char *filename );
+
+void    DefaultExtension( char *path, const char *extension );
+void    DefaultPath( char *path, const char *basepath );
+void    StripFilename( char *path );
+void    StripExtension( char *path );
+
+void    ExtractFilePath( const char *path, char *dest );
+void    ExtractFileBase( const char *path, char *dest );
+void    ExtractFileExtension( const char *path, char *dest );
+
+int     ParseNum( const char *str );
+/*
+   void Sys_Printf (const char *text, ...);
+   void Sys_FPrintf (int flag, const char *text, ...);
+   void        Error( const char *error, ... );
+ */
+short   BigShort( short l );
+short   LittleShort( short l );
+int     BigLong( int l );
+int     LittleLong( int l );
+float   BigFloat( float l );
+float   LittleFloat( float l );
+
+
+char *COM_Parse( char *data );
+
+extern char com_token[1024];
+extern qboolean com_eof;
+
+char *copystring( const char *s );
+
+
+void CRC_Init( unsigned short *crcvalue );
+void CRC_ProcessByte( unsigned short *crcvalue, byte data );
+unsigned short CRC_Value( unsigned short crcvalue );
+
+void    CreatePath( const char *path );
+void    QCopyFile( const char *from, const char *to );
+
+extern qboolean archive;
+extern char archivedir[1024];
+
+extern qboolean g_dokeypress;
+
+// sleep for the given amount of milliseconds
+void Sys_Sleep( int n );
+
+// for compression routines
+typedef struct
+{
+       byte    *data;
+       int count;
+} cblock_t;
+
+
+#endif
diff --git a/tools/heretic2/common/her2_threads.h b/tools/heretic2/common/her2_threads.h
new file mode 100644 (file)
index 0000000..6027a69
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#ifndef _THREADS_H
+
+#define _THREADS_H
+
+
+extern int numthreads;
+
+void ThreadSetDefault( void );
+int GetThreadWork( void );
+void RunThreadsOnIndividual( int workcnt, qboolean showpacifier, void ( *func )( int ) );
+void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) );
+void ThreadLock( void );
+void ThreadUnlock( void );
+
+#endif //_THREADS_H
diff --git a/tools/heretic2/common/inout.c b/tools/heretic2/common/inout.c
new file mode 100644 (file)
index 0000000..e0c1484
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+//-----------------------------------------------------------------------------
+//
+//
+// DESCRIPTION:
+// deal with in/out tasks, for either stdin/stdout or network/XML stream
+//
+
+#include "globaldefs.h"
+#include "cmdlib.h"
+#include "mathlib.h"
+#include "polylib.h"
+#include "inout.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if GDEF_OS_WINDOWS
+#include <direct.h>
+#include <windows.h>
+#endif
+
+// network broadcasting
+#include "l_net/l_net.h"
+#include "libxml/tree.h"
+
+#if GDEF_OS_WINDOWS
+HWND hwndOut = NULL;
+qboolean lookedForServer = false;
+UINT wm_BroadcastCommand = -1;
+#endif
+
+socket_t *brdcst_socket;
+netmessage_t msg;
+
+qboolean verbose = false;
+
+// our main document
+// is streamed through the network to Radiant
+// possibly written to disk at the end of the run
+//++timo FIXME: need to be global, required when creating nodes?
+xmlDocPtr doc;
+xmlNodePtr tree;
+
+// some useful stuff
+xmlNodePtr xml_NodeForVec( vec3_t v ){
+       xmlNodePtr ret;
+       char buf[1024];
+
+       sprintf( buf, "%f %f %f", v[0], v[1], v[2] );
+       ret = xmlNewNode( NULL, "point" );
+       xmlNodeAddContent( ret, buf );
+       return ret;
+}
+
+// send a node down the stream, add it to the document
+void xml_SendNode( xmlNodePtr node ){
+       xmlBufferPtr xml_buf;
+       char xmlbuf[MAX_NETMESSAGE]; // we have to copy content from the xmlBufferPtr into an aux buffer .. that sucks ..
+       // this index loops through the node buffer
+       int pos = 0;
+       int size;
+
+       xmlAddChild( doc->children, node );
+
+       if ( brdcst_socket ) {
+               xml_buf = xmlBufferCreate();
+               xmlNodeDump( xml_buf, doc, node, 0, 0 );
+
+               // the XML node might be too big to fit in a single network message
+               // l_net library defines an upper limit of MAX_NETMESSAGE
+               // there are some size check errors, so we use MAX_NETMESSAGE-10 to be safe
+               // if the size of the buffer exceeds MAX_NETMESSAGE-10 we'll send in several network messages
+               while ( pos < xml_buf->use )
+               {
+                       // what size are we gonna send now?
+                       ( xml_buf->use - pos < MAX_NETMESSAGE - 10 ) ? ( size = xml_buf->use - pos ) : ( size = MAX_NETMESSAGE - 10 );
+                       //++timo just a debug thing
+                       if ( size == MAX_NETMESSAGE - 10 ) {
+                               Sys_FPrintf( SYS_NOXML, "Got to split the buffer\n" );
+                       }
+                       memcpy( xmlbuf, xml_buf->content + pos, size );
+                       xmlbuf[size] = '\0';
+                       NMSG_Clear( &msg );
+                       NMSG_WriteString( &msg, xmlbuf );
+                       Net_Send( brdcst_socket, &msg );
+                       // now that the thing is sent prepare to loop again
+                       pos += size;
+               }
+
+#if 0
+               // NOTE: the NMSG_WriteString is limited to MAX_NETMESSAGE
+               // we will need to split into chunks
+               // (we could also go lower level, in the end it's using send and receiv which are not size limited)
+               //++timo FIXME: MAX_NETMESSAGE is not exactly the max size we can stick in the message
+               //  there's some tweaking to do in l_net for that .. so let's give us a margin for now
+
+               //++timo we need to handle the case of a buffer too big to fit in a single message
+               // try without checks for now
+               if ( xml_buf->use > MAX_NETMESSAGE - 10 ) {
+                       // if we send that we are probably gonna break the stream at the other end..
+                       // and Error will call right there
+                       //Error( "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use);
+                       Sys_FPrintf( SYS_NOXML, "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use );
+                       xml_buf->content[xml_buf->use] = '\0'; //++timo this corrupts the buffer but we don't care it's for printing
+                       Sys_FPrintf( SYS_NOXML, xml_buf->content );
+
+               }
+
+               size = xml_buf->use;
+               memcpy( xmlbuf, xml_buf->content, size );
+               xmlbuf[size] = '\0';
+               NMSG_Clear( &msg );
+               NMSG_WriteString( &msg, xmlbuf );
+               Net_Send( brdcst_socket, &msg );
+#endif
+
+               xmlBufferFree( xml_buf );
+       }
+}
+
+void xml_Select( char *msg, int entitynum, int brushnum, qboolean bError ){
+       xmlNodePtr node, select;
+       char buf[1024];
+       char level[2];
+
+       // now build a proper "select" XML node
+       sprintf( buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg );
+       node = xmlNewNode( NULL, "select" );
+       xmlNodeAddContent( node, buf );
+       level[0] = (int)'0' + ( bError ? SYS_ERR : SYS_WRN )  ;
+       level[1] = 0;
+       xmlSetProp( node, "level", (char *)&level );
+       // a 'select' information
+       sprintf( buf, "%i %i", entitynum, brushnum );
+       select = xmlNewNode( NULL, "brush" );
+       xmlNodeAddContent( select, buf );
+       xmlAddChild( node, select );
+       xml_SendNode( node );
+
+       sprintf( buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg );
+       if ( bError ) {
+               Error( buf );
+       }
+       else{
+               Sys_FPrintf( SYS_NOXML, "%s\n", buf );
+       }
+
+}
+
+void xml_Point( char *msg, vec3_t pt ){
+       xmlNodePtr node, point;
+       char buf[1024];
+       char level[2];
+
+       node = xmlNewNode( NULL, "pointmsg" );
+       xmlNodeAddContent( node, msg );
+       level[0] = (int)'0' + SYS_ERR;
+       level[1] = 0;
+       xmlSetProp( node, "level", (char *)&level );
+       // a 'point' node
+       sprintf( buf, "%g %g %g", pt[0], pt[1], pt[2] );
+       point = xmlNewNode( NULL, "point" );
+       xmlNodeAddContent( point, buf );
+       xmlAddChild( node, point );
+       xml_SendNode( node );
+
+       sprintf( buf, "%s (%g %g %g)", msg, pt[0], pt[1], pt[2] );
+       Error( buf );
+}
+
+#define WINDING_BUFSIZE 2048
+void xml_Winding( char *msg, vec3_t p[], int numpoints, qboolean die ){
+       xmlNodePtr node, winding;
+       char buf[WINDING_BUFSIZE];
+       char smlbuf[128];
+       char level[2];
+       int i;
+
+       node = xmlNewNode( NULL, "windingmsg" );
+       xmlNodeAddContent( node, msg );
+       level[0] = (int)'0' + SYS_ERR;
+       level[1] = 0;
+       xmlSetProp( node, "level", (char *)&level );
+       // a 'winding' node
+       sprintf( buf, "%i ", numpoints );
+       for ( i = 0; i < numpoints; i++ )
+       {
+               sprintf( smlbuf, "(%g %g %g)", p[i][0], p[i][1], p[i][2] );
+               // don't overflow
+               if ( strlen( buf ) + strlen( smlbuf ) > WINDING_BUFSIZE ) {
+                       break;
+               }
+               strcat( buf, smlbuf );
+       }
+
+       winding = xmlNewNode( NULL, "winding" );
+       xmlNodeAddContent( winding, buf );
+       xmlAddChild( node, winding );
+       xml_SendNode( node );
+
+       if ( die ) {
+               Error( msg );
+       }
+       else
+       {
+               Sys_Printf( msg );
+               Sys_Printf( "\n" );
+       }
+}
+
+// in include
+#include "stream_version.h"
+
+void Broadcast_Setup( const char *dest ){
+       address_t address;
+       char sMsg[1024];
+
+       Net_Setup();
+       Net_StringToAddress( (char *)dest, &address );
+       brdcst_socket = Net_Connect( &address, 0 );
+       if ( brdcst_socket ) {
+               // send in a header
+               sprintf( sMsg, "<?xml version=\"1.0\"?><q3map_feedback version=\"" Q3MAP_STREAM_VERSION "\">" );
+               NMSG_Clear( &msg );
+               NMSG_WriteString( &msg, sMsg );
+               Net_Send( brdcst_socket, &msg );
+       }
+}
+
+void Broadcast_Shutdown(){
+       if ( brdcst_socket ) {
+               Sys_Printf( "Disconnecting\n" );
+               Net_Disconnect( brdcst_socket );
+               brdcst_socket = NULL;
+       }
+}
+
+// all output ends up through here
+void FPrintf( int flag, char *buf ){
+       xmlNodePtr node;
+       static qboolean bGotXML = false;
+       char level[2];
+
+       printf( buf );
+
+       // the following part is XML stuff only.. but maybe we don't want that message to go down the XML pipe?
+       if ( flag == SYS_NOXML ) {
+               return;
+       }
+
+       // ouput an XML file of the run
+       // use the DOM interface to build a tree
+       /*
+          <message level='flag'>
+          message string
+          .. various nodes to describe corresponding geometry ..
+          </message>
+        */
+       if ( !bGotXML ) {
+               // initialize
+               doc = xmlNewDoc( "1.0" );
+               doc->children = xmlNewDocRawNode( doc, NULL, "q3map_feedback", NULL );
+               bGotXML = true;
+       }
+       node = xmlNewNode( NULL, "message" );
+       xmlNodeAddContent( node, buf );
+       level[0] = (int)'0' + flag;
+       level[1] = 0;
+       xmlSetProp( node, "level", (char *)&level );
+
+       xml_SendNode( node );
+}
+
+#ifdef DBG_XML
+void DumpXML(){
+       xmlSaveFile( "XMLDump.xml", doc );
+}
+#endif
+
+void Sys_FPrintf( int flag, const char *format, ... ){
+       char out_buffer[4096];
+       va_list argptr;
+
+       if ( ( flag == SYS_VRB ) && ( verbose == false ) ) {
+               return;
+       }
+
+       va_start( argptr, format );
+       vsprintf( out_buffer, format, argptr );
+       va_end( argptr );
+
+       FPrintf( flag, out_buffer );
+}
+
+void Sys_Printf( const char *format, ... ){
+       char out_buffer[4096];
+       va_list argptr;
+
+       va_start( argptr, format );
+       vsprintf( out_buffer, format, argptr );
+       va_end( argptr );
+
+       FPrintf( SYS_STD, out_buffer );
+}
+
+/*
+   =================
+   Error
+
+   For abnormal program terminations
+   =================
+ */
+void Error( const char *error, ... ){
+       char out_buffer[4096];
+       char tmp[4096];
+       va_list argptr;
+
+       va_start( argptr,error );
+       vsprintf( tmp, error, argptr );
+       va_end( argptr );
+
+       sprintf( out_buffer, "************ ERROR ************\n%s\n", tmp );
+
+       FPrintf( SYS_ERR, out_buffer );
+
+#ifdef DBG_XML
+       DumpXML();
+#endif
+
+       //++timo HACK ALERT .. if we shut down too fast the xml stream won't reach the listener.
+       // a clean solution is to send a sync request node in the stream and wait for an answer before exiting
+       Sys_Sleep( 1000 );
+
+       Broadcast_Shutdown();
+
+       exit( 1 );
+}
diff --git a/tools/heretic2/common/inout.h b/tools/heretic2/common/inout.h
new file mode 100644 (file)
index 0000000..934189f
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __INOUT__
+#define __INOUT__
+
+#include "globaldefs.h"
+// inout is the only stuff relying on xml, include the headers there
+#include "libxml/tree.h"
+#include "mathlib.h"
+
+// some useful xml routines
+xmlNodePtr xml_NodeForVec( vec3_t v );
+void xml_SendNode( xmlNodePtr node );
+// print a message in q3map output and send the corresponding select information down the xml stream
+// bError: do we end with an error on this one or do we go ahead?
+void xml_Select( char *msg, int entitynum, int brushnum, qboolean bError );
+// end q3map with an error message and send a point information in the xml stream
+// note: we might want to add a boolean to use this as a warning or an error thing..
+void xml_Winding( char *msg, vec3_t p[], int numpoints, qboolean die );
+void xml_Point( char *msg, vec3_t pt );
+
+extern qboolean bNetworkBroadcast;
+void Broadcast_Setup( const char *dest );
+void Broadcast_Shutdown();
+
+#define SYS_VRB 0 // verbose support (on/off)
+#define SYS_STD 1 // standard print level
+#define SYS_WRN 2 // warnings
+#define SYS_ERR 3 // error
+#define SYS_NOXML 4 // don't send that down the XML stream
+
+extern qboolean verbose;
+void Sys_Printf( const char *text, ... );
+void Sys_FPrintf( int flag, const char *text, ... );
+void Error( const char *error, ... );
+
+#if GDEF_DEBUG
+#define DBG_XML 1
+#endif
+
+#ifdef DBG_XML
+void DumpXML();
+#endif
+
+#endif
diff --git a/tools/heretic2/common/l3dslib.c b/tools/heretic2/common/l3dslib.c
new file mode 100644 (file)
index 0000000..708577a
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+//
+// l3dslib.c: library for loading triangles from an Alias triangle file
+//
+
+#include <stdio.h>
+#include "cmdlib.h"
+#include "inout.h"
+#include "mathlib.h"
+#include "trilib.h"
+#include "l3dslib.h"
+#include "token.h"
+#include "fmodel.h"
+#include "bspfile.h"
+
+#define MAIN3DS       0x4D4D
+#define EDIT3DS       0x3D3D  // this is the start of the editor config
+#define EDIT_OBJECT   0x4000
+#define OBJ_TRIMESH   0x4100
+#define TRI_VERTEXL   0x4110
+#define TRI_FACEL1    0x4120
+
+#define MAXVERTS    2000
+
+typedef struct {
+       int v[4];
+} tri;
+
+float fverts[MAXVERTS][3];
+tri tris[MAXTRIANGLES];
+
+int bytesread, level, numtris, totaltris;
+int vertsfound, trisfound;
+
+triangle_t  *ptri;
+
+
+
+void DefaultNodesList( mesh_node_t **nodesList, int *num_mesh_nodes, int *numtriangles ){
+       int pos, bit, i;
+
+       if ( nodesList ) {
+               *num_mesh_nodes = 1;
+               memset( &( *nodesList )[0], 0, sizeof( mesh_node_t ) );
+               strcpy( ( *nodesList )[0].name, "default" );
+
+               // set all of the tris to be used for the top node
+               for ( i = 0; i < ( *numtriangles ); i++ )
+               {
+                       pos = ( i ) >> 3;
+                       bit = 1 << ( ( i ) & 7 );
+
+                       ( *nodesList )[0].tris[pos] |= bit;
+               }
+       }
+}
+
+
+// Alias stores triangles as 3 explicit vertices in .tri files, so even though we
+// start out with a vertex pool and vertex indices for triangles, we have to convert
+// to raw, explicit triangles
+void StoreAliasTriangles( void ){
+       int i, j, k;
+
+       if ( ( totaltris + numtris ) > MAXTRIANGLES ) {
+               Error( "Error: Too many triangles" );
+       }
+
+       for ( i = 0; i < numtris ; i++ )
+       {
+               for ( j = 0 ; j < 3 ; j++ )
+               {
+                       for ( k = 0 ; k < 3 ; k++ )
+                       {
+                               ptri[i + totaltris].verts[j][k] = fverts[tris[i].v[j]][k];
+                       }
+               }
+       }
+
+       totaltris += numtris;
+       numtris = 0;
+       vertsfound = 0;
+       trisfound = 0;
+}
+
+
+int ParseVertexL( FILE *input ){
+       int i, j, startbytesread, numverts;
+       unsigned short tshort;
+
+       if ( vertsfound ) {
+               Error( "Error: Multiple vertex chunks" );
+       }
+
+       vertsfound = 1;
+       startbytesread = bytesread;
+
+       if ( feof( input ) ) {
+               Error( "Error: unexpected end of file" );
+       }
+
+       fread( &tshort, sizeof( tshort ), 1, input );
+       bytesread += sizeof( tshort );
+       numverts = (int)tshort;
+
+       if ( numverts > MAXVERTS ) {
+               Error( "Error: Too many vertices" );
+       }
+
+       for ( i = 0 ; i < numverts ; i++ )
+       {
+               for ( j = 0 ; j < 3 ; j++ )
+               {
+                       if ( feof( input ) ) {
+                               Error( "Error: unexpected end of file" );
+                       }
+
+                       fread( &fverts[i][j], sizeof( float ), 1, input );
+                       bytesread += sizeof( float );
+               }
+       }
+
+       if ( vertsfound && trisfound ) {
+               StoreAliasTriangles();
+       }
+
+       return bytesread - startbytesread;
+}
+
+
+int ParseFaceL1( FILE *input ){
+
+       int i, j, startbytesread;
+       unsigned short tshort;
+
+       if ( trisfound ) {
+               Error( "Error: Multiple face chunks" );
+       }
+
+       trisfound = 1;
+       startbytesread = bytesread;
+
+       if ( feof( input ) ) {
+               Error( "Error: unexpected end of file" );
+       }
+
+       fread( &tshort, sizeof( tshort ), 1, input );
+       bytesread += sizeof( tshort );
+       numtris = (int)tshort;
+
+       if ( numtris > MAXTRIANGLES ) {
+               Error( "Error: Too many triangles" );
+       }
+
+       for ( i = 0 ; i < numtris ; i++ )
+       {
+               for ( j = 0 ; j < 4 ; j++ )
+               {
+                       if ( feof( input ) ) {
+                               Error( "Error: unexpected end of file" );
+                       }
+
+                       fread( &tshort, sizeof( tshort ), 1, input );
+                       bytesread += sizeof( tshort );
+                       tris[i].v[j] = (int)tshort;
+               }
+       }
+
+       if ( vertsfound && trisfound ) {
+               StoreAliasTriangles();
+       }
+
+       return bytesread - startbytesread;
+}
+
+
+int ParseChunk( FILE *input ){
+#define BLOCK_SIZE  4096
+       char temp[BLOCK_SIZE];
+       unsigned short type;
+       int i, length, w, t, retval;
+
+       level++;
+       retval = 0;
+
+// chunk type
+       if ( feof( input ) ) {
+               Error( "Error: unexpected end of file" );
+       }
+
+       fread( &type, sizeof( type ), 1, input );
+       bytesread += sizeof( type );
+
+// chunk length
+       if ( feof( input ) ) {
+               Error( "Error: unexpected end of file" );
+       }
+
+       fread( &length, sizeof( length ), 1, input );
+       bytesread += sizeof( length );
+       w = length - 6;
+
+// process chunk if we care about it, otherwise skip it
+       switch ( type )
+       {
+       case TRI_VERTEXL:
+               w -= ParseVertexL( input );
+               goto ParseSubchunk;
+
+       case TRI_FACEL1:
+               w -= ParseFaceL1( input );
+               goto ParseSubchunk;
+
+       case EDIT_OBJECT:
+               // read the name
+               i = 0;
+
+               do
+               {
+                       if ( feof( input ) ) {
+                               Error( "Error: unexpected end of file" );
+                       }
+
+                       fread( &temp[i], 1, 1, input );
+                       i++;
+                       w--;
+                       bytesread++;
+               } while ( temp[i - 1] );
+
+       case MAIN3DS:
+       case OBJ_TRIMESH:
+       case EDIT3DS:
+               // parse through subchunks
+ParseSubchunk:
+               while ( w > 0 )
+               {
+                       w -= ParseChunk( input );
+               }
+
+               retval = length;
+               goto Done;
+
+       default:
+               // skip other chunks
+               while ( w > 0 )
+               {
+                       t = w;
+
+                       if ( t > BLOCK_SIZE ) {
+                               t = BLOCK_SIZE;
+                       }
+
+                       if ( feof( input ) ) {
+                               Error( "Error: unexpected end of file" );
+                       }
+
+                       fread( &temp, t, 1, input );
+                       bytesread += t;
+
+                       w -= t;
+               }
+
+               retval = length;
+               goto Done;
+       }
+
+Done:
+       level--;
+       return retval;
+}
+
+
+void Load3DSTriangleList( char *filename, triangle_t **pptri, int *numtriangles, mesh_node_t **nodesList, int *num_mesh_nodes ){
+       FILE        *input;
+       short int tshort;
+
+       if ( nodesList ) {
+               *num_mesh_nodes = 0;
+               *nodesList = (mesh_node_t *) SafeMalloc( MAX_FM_MESH_NODES * sizeof( mesh_node_t ), "Mesh Node List" );
+       }
+
+       bytesread = 0;
+       level = 0;
+       numtris = 0;
+       totaltris = 0;
+       vertsfound = 0;
+       trisfound = 0;
+
+       if ( ( input = fopen( filename, "rb" ) ) == 0 ) {
+               fprintf( stderr,"reader: could not open file '%s'\n", filename );
+               exit( 0 );
+       }
+
+       fread( &tshort, sizeof( tshort ), 1, input );
+
+// should only be MAIN3DS, but some files seem to start with EDIT3DS, with
+// no MAIN3DS
+       if ( ( tshort != MAIN3DS ) && ( tshort != EDIT3DS ) ) {
+               fprintf( stderr,"File is not a 3DS file.\n" );
+               exit( 0 );
+       }
+
+// back to top of file so we can parse the first chunk descriptor
+       fseek( input, 0, SEEK_SET );
+
+       ptri = malloc( MAXTRIANGLES * sizeof( triangle_t ) );
+
+       *pptri = ptri;
+
+// parse through looking for the relevant chunk tree (MAIN3DS | EDIT3DS | EDIT_OBJECT |
+// OBJ_TRIMESH | {TRI_VERTEXL, TRI_FACEL1}) and skipping other chunks
+       ParseChunk( input );
+
+       if ( vertsfound || trisfound ) {
+               Error( "Incomplete triangle set" );
+       }
+
+       *numtriangles = totaltris;
+
+       fclose( input );
+
+       DefaultNodesList( nodesList,num_mesh_nodes,numtriangles );
+}
+
+//==========================================================================
+//
+// LoadASC
+//
+//==========================================================================
+
+void LoadASC( char *fileName, triangle_t **triList, int *triangleCount, mesh_node_t **nodesList, int *num_mesh_nodes ){
+       int i, j;
+       int vertexCount;
+       struct
+       {
+               float v[3];
+       }           *vList;
+       int triCount;
+       triangle_t  *tList;
+       float x, y, z;
+//     float           x2, y2, z2;
+//     float           rx, ry, rz;
+       qboolean goodObject;
+
+       if ( nodesList ) {
+               *num_mesh_nodes = 0;
+               *nodesList = (mesh_node_t *) SafeMalloc( MAX_FM_MESH_NODES * sizeof( mesh_node_t ), "Mesh Node List" );
+       }
+
+       TK_OpenSource( fileName );
+
+       goodObject = false;
+       while ( goodObject == false )
+       {
+               TK_Beyond( TK_C_NAMED );
+               TK_Beyond( TK_OBJECT );
+               TK_Beyond( TK_C_TRI );
+               TK_Beyond( TK_MESH );
+               TK_BeyondRequire( TK_C_VERTICES, TK_COLON );
+               TK_FetchRequire( TK_INTNUMBER );
+               vertexCount = tk_IntNumber;
+               if ( vertexCount > 0 ) {
+                       goodObject = true;
+               }
+       }
+       TK_BeyondRequire( TK_C_FACES, TK_COLON );
+       TK_FetchRequire( TK_INTNUMBER );
+       triCount = tk_IntNumber;
+       if ( triCount >= MAXTRIANGLES ) {
+               Error( "Too many triangles in file %s\n", fileName );
+       }
+       *triangleCount = triCount;
+       tList = (triangle_t *) SafeMalloc( MAXTRIANGLES * sizeof( triangle_t ), "Triangle list" );
+       *triList = tList;
+
+       memset( *triList,0,MAXTRIANGLES * sizeof( triangle_t ) );
+       TK_BeyondRequire( TK_C_VERTEX, TK_LIST );
+
+/*     rx = ((rotation[0]+90.0)/360.0)*2.0*M_PI;
+    //rx = (rotation[0]/360.0)*2.0*M_PI;
+    ry = (rotation[1]/360.0)*2.0*M_PI;
+    rz = (rotation[2]/360.0)*2.0*M_PI;
+ */
+       vList = (void *) SafeMalloc( vertexCount * sizeof vList[0], "Vertex list" );
+       for ( i = 0; i < vertexCount; i++ )
+       {
+               TK_BeyondRequire( TK_C_VERTEX, TK_INTNUMBER );
+               if ( tk_IntNumber != i ) {
+                       Error( "File '%s', line %d:\nVertex index mismatch.\n",
+                                  tk_SourceName, tk_Line );
+               }
+               TK_FetchRequireFetch( TK_COLON );
+
+               TK_BeyondRequire( TK_COLON, TK_FLOATNUMBER );
+               x = tk_FloatNumber;
+               TK_BeyondRequire( TK_COLON, TK_FLOATNUMBER );
+               y = tk_FloatNumber;
+               TK_BeyondRequire( TK_COLON, TK_FLOATNUMBER );
+               z = tk_FloatNumber;
+
+/*             x2 = x*cos(rz)+y*sin(rz);
+        y2 = -x*sin(rz)+y*cos(rz);
+        x = x2;
+        y = y2;
+        y2 = y*cos(rx)+z*sin(rx);
+        z2 = -y*sin(rx)+z*cos(rx);
+        y = y2;
+        z = z2;
+        x2 = x*cos(ry)-z*sin(ry);
+        z2 = x*sin(ry)+z*cos(ry);
+        x = x2;
+        z = z2;
+ */
+               vList[i].v[0] = x;
+               vList[i].v[1] = y;
+               vList[i].v[2] = z;
+       }
+       TK_BeyondRequire( TK_C_FACE, TK_LIST );
+       for ( i = 0; i < triCount; i++ )
+       {
+               TK_BeyondRequire( TK_C_FACE, TK_INTNUMBER );
+               if ( tk_IntNumber != i ) {
+                       Error( "File '%s', line %d:\nTriangle index mismatch.\n",
+                                  tk_SourceName, tk_Line );
+               }
+               for ( j = 0; j < 3; j++ )
+               {
+                       TK_BeyondRequire( TK_IDENTIFIER, TK_COLON );
+                       TK_FetchRequire( TK_INTNUMBER );
+                       if ( tk_IntNumber >= vertexCount ) {
+                               Error( "File '%s', line %d:\nVertex number"
+                                          " > vertexCount: %d\n", tk_SourceName, tk_Line,
+                                          tk_IntNumber );
+                       }
+                       tList[i].verts[2 - j][0] = vList[tk_IntNumber].v[0];
+                       tList[i].verts[2 - j][1] = vList[tk_IntNumber].v[1];
+                       tList[i].verts[2 - j][2] = vList[tk_IntNumber].v[2];
+#ifdef _QDATA
+                       tList[i].indicies[2 - j] = tk_IntNumber;
+#endif
+               }
+
+/*             printf("Face %i:\n  v0: %f, %f, %f\n  v1: %f, %f, %f\n"
+            "  v2: %f, %f, %f\n", i,
+            tList[i].verts[0][0],
+            tList[i].verts[0][1],
+            tList[i].verts[0][2],
+            tList[i].verts[1][0],
+            tList[i].verts[1][1],
+            tList[i].verts[1][2],
+            tList[i].verts[2][0],
+            tList[i].verts[2][1],
+            tList[i].verts[2][2]);
+ */
+       }
+
+       DefaultNodesList( nodesList,num_mesh_nodes,triangleCount );
+}
diff --git a/tools/heretic2/common/l3dslib.h b/tools/heretic2/common/l3dslib.h
new file mode 100644 (file)
index 0000000..0b1b537
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+//
+// l3dslib.h: header file for loading triangles from a 3DS triangle file
+//
+void DefaultNodesList( mesh_node_t **nodesList, int *num_mesh_nodes, int *numtriangles );
+
+void Load3DSTriangleList( char *filename, triangle_t **pptri, int *numtriangles, mesh_node_t **ppmnodes, int *num_mesh_nodes );
+void LoadASC( char *fileName, triangle_t **triList, int *triangleCount, mesh_node_t **ppmnodes, int *num_mesh_nodes );
diff --git a/tools/heretic2/common/lbmlib.c b/tools/heretic2/common/lbmlib.c
new file mode 100644 (file)
index 0000000..7eabd19
--- /dev/null
@@ -0,0 +1,1043 @@
+/*
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+// lbmlib.c
+
+#include "cmdlib.h"
+#include "inout.h"
+#include "lbmlib.h"
+
+// Ups the palette values so no pixels except 0 appear transparent
+// Need a value of 8 to cater for 16bit renderers
+
+typedef struct
+{
+       byte r;
+       byte g;
+       byte b;
+} paletteRGB_t;
+
+
+void CorrectPalette( byte *pal ){
+       paletteRGB_t    *p;
+
+       p = (paletteRGB_t *)pal;
+       // Color 0 always transparent
+       p->r = 0;
+       p->g = 0;
+       p->b = 0;
+}
+
+/*
+   ============================================================================
+
+                        LBM STUFF
+
+   ============================================================================
+ */
+
+
+typedef unsigned char UBYTE;
+//conflicts with windows typedef short                 WORD;
+typedef unsigned short UWORD;
+typedef long LONG;
+
+typedef enum
+{
+       ms_none,
+       ms_mask,
+       ms_transcolor,
+       ms_lasso
+} mask_t;
+
+typedef enum
+{
+       cm_none,
+       cm_rle1
+} compress_t;
+
+typedef struct
+{
+       UWORD w,h;
+       short x,y;
+       UBYTE nPlanes;
+       UBYTE masking;
+       UBYTE compression;
+       UBYTE pad1;
+       UWORD transparentColor;
+       UBYTE xAspect,yAspect;
+       short pageWidth,pageHeight;
+} bmhd_t;
+
+extern bmhd_t bmhd;                         // will be in native byte order
+
+
+
+#define FORMID ( 'F' + ( 'O' << 8 ) + ( (int)'R' << 16 ) + ( (int)'M' << 24 ) )
+#define ILBMID ( 'I' + ( 'L' << 8 ) + ( (int)'B' << 16 ) + ( (int)'M' << 24 ) )
+#define PBMID  ( 'P' + ( 'B' << 8 ) + ( (int)'M' << 16 ) + ( (int)' ' << 24 ) )
+#define BMHDID ( 'B' + ( 'M' << 8 ) + ( (int)'H' << 16 ) + ( (int)'D' << 24 ) )
+#define BODYID ( 'B' + ( 'O' << 8 ) + ( (int)'D' << 16 ) + ( (int)'Y' << 24 ) )
+#define CMAPID ( 'C' + ( 'M' << 8 ) + ( (int)'A' << 16 ) + ( (int)'P' << 24 ) )
+
+
+bmhd_t bmhd;
+
+int    Align( int l ){
+       if ( l & 1 ) {
+               return l + 1;
+       }
+       return l;
+}
+
+
+
+/*
+   ================
+   LBMRLEdecompress
+
+   Source must be evenly aligned!
+   ================
+ */
+byte  *LBMRLEDecompress( byte *source,byte *unpacked, int bpwidth ){
+       int count;
+       byte b,rept;
+
+       count = 0;
+
+       do
+       {
+               rept = *source++;
+
+               if ( rept > 0x80 ) {
+                       rept = ( rept ^ 0xff ) + 2;
+                       b = *source++;
+                       memset( unpacked,b,rept );
+                       unpacked += rept;
+               }
+               else if ( rept < 0x80 ) {
+                       rept++;
+                       memcpy( unpacked,source,rept );
+                       unpacked += rept;
+                       source += rept;
+               }
+               else{
+                       rept = 0;               // rept of 0x80 is NOP
+
+               }
+               count += rept;
+
+       } while ( count < bpwidth );
+
+       if ( count > bpwidth ) {
+               Error( "Decompression exceeded width!\n" );
+       }
+
+
+       return source;
+}
+
+
+/*
+   =================
+   LoadLBM
+   =================
+ */
+void LoadLBM( char *filename, byte **picture, byte **palette ){
+       byte    *LBMbuffer, *picbuffer, *cmapbuffer;
+       int y;
+       byte    *LBM_P, *LBMEND_P;
+       byte    *pic_p;
+       byte    *body_p;
+
+       int formtype,formlength;
+       int chunktype,chunklength;
+
+// qiet compiler warnings
+       picbuffer = NULL;
+       cmapbuffer = NULL;
+
+//
+// load the LBM
+//
+       LoadFile( filename, (void **)&LBMbuffer );
+
+//
+// parse the LBM header
+//
+       LBM_P = LBMbuffer;
+       if ( *(int *)LBMbuffer != LittleLong( FORMID ) ) {
+               Error( "No FORM ID at start of file!\n" );
+       }
+
+       LBM_P += 4;
+       formlength = BigLong( *(int *)LBM_P );
+       LBM_P += 4;
+       LBMEND_P = LBM_P + Align( formlength );
+
+       formtype = LittleLong( *(int *)LBM_P );
+
+       if ( formtype != ILBMID && formtype != PBMID ) {
+               Error( "Unrecognized form type: %c%c%c%c\n", formtype & 0xff
+                          ,( formtype >> 8 ) & 0xff,( formtype >> 16 ) & 0xff,( formtype >> 24 ) & 0xff );
+       }
+
+       LBM_P += 4;
+
+//
+// parse chunks
+//
+
+       while ( LBM_P < LBMEND_P )
+       {
+               chunktype = LBM_P[0] + ( LBM_P[1] << 8 ) + ( LBM_P[2] << 16 ) + ( LBM_P[3] << 24 );
+               LBM_P += 4;
+               chunklength = LBM_P[3] + ( LBM_P[2] << 8 ) + ( LBM_P[1] << 16 ) + ( LBM_P[0] << 24 );
+               LBM_P += 4;
+
+               switch ( chunktype )
+               {
+               case BMHDID:
+                       memcpy( &bmhd,LBM_P,sizeof( bmhd ) );
+                       bmhd.w = BigShort( bmhd.w );
+                       bmhd.h = BigShort( bmhd.h );
+                       bmhd.x = BigShort( bmhd.x );
+                       bmhd.y = BigShort( bmhd.y );
+                       bmhd.pageWidth = BigShort( bmhd.pageWidth );
+                       bmhd.pageHeight = BigShort( bmhd.pageHeight );
+                       break;
+
+               case CMAPID:
+                       cmapbuffer = malloc( 768 );
+                       memset( cmapbuffer, 0, 768 );
+                       memcpy( cmapbuffer, LBM_P, chunklength );
+                       CorrectPalette( cmapbuffer );
+                       break;
+
+               case BODYID:
+                       body_p = LBM_P;
+
+                       pic_p = picbuffer = malloc( bmhd.w * bmhd.h );
+                       if ( formtype == PBMID ) {
+                               //
+                               // unpack PBM
+                               //
+                               for ( y = 0 ; y < bmhd.h ; y++, pic_p += bmhd.w )
+                               {
+                                       if ( bmhd.compression == cm_rle1 ) {
+                                               body_p = LBMRLEDecompress( (byte *)body_p
+                                                                                                  , pic_p, bmhd.w );
+                                       }
+                                       else if ( bmhd.compression == cm_none ) {
+                                               memcpy( pic_p,body_p,bmhd.w );
+                                               body_p += Align( bmhd.w );
+                                       }
+                               }
+
+                       }
+                       else
+                       {
+                               //
+                               // unpack ILBM
+                               //
+                               Error( "%s is an interlaced LBM, not packed", filename );
+                       }
+                       break;
+               }
+
+               LBM_P += Align( chunklength );
+       }
+
+       free( LBMbuffer );
+
+       *picture = picbuffer;
+
+       if ( palette ) {
+               *palette = cmapbuffer;
+       }
+}
+
+
+/*
+   ============================================================================
+
+                            WRITE LBM
+
+   ============================================================================
+ */
+
+/*
+   ==============
+   WriteLBMfile
+   ==============
+ */
+void WriteLBMfile( char *filename, byte *data,
+                                  int width, int height, byte *palette ){
+       byte    *lbm, *lbmptr;
+       int    *formlength, *bmhdlength, *cmaplength, *bodylength;
+       int length;
+       bmhd_t basebmhd;
+
+       lbm = lbmptr = malloc( width * height + 1000 );
+
+//
+// start FORM
+//
+       *lbmptr++ = 'F';
+       *lbmptr++ = 'O';
+       *lbmptr++ = 'R';
+       *lbmptr++ = 'M';
+
+       formlength = (int*)lbmptr;
+       lbmptr += 4;                      // leave space for length
+
+       *lbmptr++ = 'P';
+       *lbmptr++ = 'B';
+       *lbmptr++ = 'M';
+       *lbmptr++ = ' ';
+
+//
+// write BMHD
+//
+       *lbmptr++ = 'B';
+       *lbmptr++ = 'M';
+       *lbmptr++ = 'H';
+       *lbmptr++ = 'D';
+
+       bmhdlength = (int *)lbmptr;
+       lbmptr += 4;                      // leave space for length
+
+       memset( &basebmhd,0,sizeof( basebmhd ) );
+       basebmhd.w = BigShort( (short)width );
+       basebmhd.h = BigShort( (short)height );
+       basebmhd.nPlanes = BigShort( 8 );
+       basebmhd.xAspect = BigShort( 5 );
+       basebmhd.yAspect = BigShort( 6 );
+       basebmhd.pageWidth = BigShort( (short)width );
+       basebmhd.pageHeight = BigShort( (short)height );
+
+       memcpy( lbmptr,&basebmhd,sizeof( basebmhd ) );
+       lbmptr += sizeof( basebmhd );
+
+       length = lbmptr - (byte *)bmhdlength - 4;
+       *bmhdlength = BigLong( length );
+       if ( length & 1 ) {
+               *lbmptr++ = 0;          // pad chunk to even offset
+
+       }
+//
+// write CMAP
+//
+       *lbmptr++ = 'C';
+       *lbmptr++ = 'M';
+       *lbmptr++ = 'A';
+       *lbmptr++ = 'P';
+
+       cmaplength = (int *)lbmptr;
+       lbmptr += 4;                      // leave space for length
+
+       memcpy( lbmptr,palette,768 );
+       lbmptr += 768;
+
+       length = lbmptr - (byte *)cmaplength - 4;
+       *cmaplength = BigLong( length );
+       if ( length & 1 ) {
+               *lbmptr++ = 0;          // pad chunk to even offset
+
+       }
+//
+// write BODY
+//
+       *lbmptr++ = 'B';
+       *lbmptr++ = 'O';
+       *lbmptr++ = 'D';
+       *lbmptr++ = 'Y';
+
+       bodylength = (int *)lbmptr;
+       lbmptr += 4;                      // leave space for length
+
+       memcpy( lbmptr,data,width * height );
+       lbmptr += width * height;
+
+       length = lbmptr - (byte *)bodylength - 4;
+       *bodylength = BigLong( length );
+       if ( length & 1 ) {
+               *lbmptr++ = 0;          // pad chunk to even offset
+
+       }
+//
+// done
+//
+       length = lbmptr - (byte *)formlength - 4;
+       *formlength = BigLong( length );
+       if ( length & 1 ) {
+               *lbmptr++ = 0;          // pad chunk to even offset
+
+       }
+//
+// write output file
+//
+       SaveFile( filename, lbm, lbmptr - lbm );
+       free( lbm );
+}
+
+
+/*
+   ============================================================================
+
+   LOAD PCX
+
+   ============================================================================
+ */
+
+typedef struct
+{
+       char manufacturer;
+       char version;
+       char encoding;
+       char bits_per_pixel;
+       unsigned short xmin,ymin,xmax,ymax;
+       unsigned short hres,vres;
+       unsigned char palette[48];
+       char reserved;
+       char color_planes;
+       unsigned short bytes_per_line;
+       unsigned short palette_type;
+       char filler[58];
+       unsigned char data;             // unbounded
+} pcx_t;
+
+/*
+   ==============
+   LoadPCX
+   ==============
+ */
+void LoadPCX( char *filename, byte **pic, byte **palette, int *width, int *height ){
+       byte    *raw;
+       pcx_t   *pcx;
+       int x, y;
+       int len;
+       int dataByte, runLength;
+       byte    *out, *pix;
+
+       //
+       // load the file
+       //
+       len = LoadFile( filename, (void **)&raw );
+
+       //
+       // parse the PCX file
+       //
+       pcx = (pcx_t *)raw;
+       raw = &pcx->data;
+
+       pcx->xmin = LittleShort( pcx->xmin );
+       pcx->ymin = LittleShort( pcx->ymin );
+       pcx->xmax = LittleShort( pcx->xmax );
+       pcx->ymax = LittleShort( pcx->ymax );
+       pcx->hres = LittleShort( pcx->hres );
+       pcx->vres = LittleShort( pcx->vres );
+       pcx->bytes_per_line = LittleShort( pcx->bytes_per_line );
+       pcx->palette_type = LittleShort( pcx->palette_type );
+
+       if ( pcx->manufacturer != 0x0a
+                || pcx->version != 5
+                || pcx->encoding != 1
+                || pcx->bits_per_pixel != 8
+                || pcx->xmax >= 640
+                || pcx->ymax >= 480 ) {
+               Error( "Bad pcx file %s", filename );
+       }
+
+       if ( palette ) {
+               *palette = malloc( 768 );
+               memcpy( *palette, (byte *)pcx + len - 768, 768 );
+               CorrectPalette( *palette );
+       }
+
+       if ( width ) {
+               *width = pcx->xmax + 1;
+       }
+       if ( height ) {
+               *height = pcx->ymax + 1;
+       }
+
+       if ( !pic ) {
+               return;
+       }
+
+       out = malloc( ( pcx->ymax + 1 ) * ( pcx->xmax + 1 ) );
+       if ( !out ) {
+               Error( "Skin_Cache: couldn't allocate" );
+       }
+
+       *pic = out;
+
+       pix = out;
+
+       for ( y = 0 ; y <= pcx->ymax ; y++, pix += pcx->xmax + 1 )
+       {
+               for ( x = 0 ; x <= pcx->xmax ; )
+               {
+                       dataByte = *raw++;
+
+                       if ( ( dataByte & 0xC0 ) == 0xC0 ) {
+                               runLength = dataByte & 0x3F;
+                               dataByte = *raw++;
+                       }
+                       else{
+                               runLength = 1;
+                       }
+
+                       while ( runLength-- > 0 )
+                               pix[x++] = dataByte;
+               }
+
+       }
+
+       if ( raw - (byte *)pcx > len ) {
+               Error( "PCX file %s was malformed", filename );
+       }
+
+       free( pcx );
+}
+
+/*
+   ==============
+   WritePCXfile
+   ==============
+ */
+
+void StuffPackedByte( int curRepCount, byte curByte, byte** packPtr ){
+       byte* pack;
+
+       pack = *packPtr;
+
+       while ( curRepCount > 0 )
+       {
+               if ( curRepCount == 1 ) {
+                       if ( ( curByte & 0xc0 ) != 0xc0 ) {
+                               *pack++ = curByte;
+                       }
+                       else
+                       {
+                               *pack++ = 0xc1;
+                               *pack++ = curByte;
+                       }
+                       break;
+               }
+               if ( curRepCount < 0x0040 ) {
+                       *pack++ = ( 0x00c0 | curRepCount );
+                       curRepCount = 0;
+               }
+               else
+               {
+                       *pack++ = 0xff;
+                       curRepCount -= 0x003f;
+               }
+               *pack++ = curByte;
+       }
+       *packPtr = pack;
+}
+
+void WritePCXfile( char *filename, byte *data,
+                                  int width, int height, byte *palette ){
+       int i, j, length;
+       pcx_t       *pcx;
+       byte        *pack;
+       byte curByte;
+       int curRepCount;
+
+       pcx = malloc( width * height * 2 + 1000 );
+       memset( pcx, 0, sizeof( *pcx ) );
+
+       pcx->manufacturer = 0x0a;   // PCX id
+       pcx->version = 5;           // 256 color
+       pcx->encoding = 1;      // RLE
+       pcx->bits_per_pixel = 8;        // 256 color
+       pcx->xmin = 0;
+       pcx->ymin = 0;
+       pcx->xmax = LittleShort( (short)( width - 1 ) );
+       pcx->ymax = LittleShort( (short)( height - 1 ) );
+       pcx->hres = LittleShort( (short)width );
+       pcx->vres = LittleShort( (short)height );
+       pcx->color_planes = 1;      // chunky image
+       pcx->bytes_per_line = LittleShort( (short)width );
+       pcx->palette_type = LittleShort( 1 );     // not a grey scale
+
+       // pack the image
+       pack = &pcx->data;
+
+/*     for (i=0 ; i<height ; i++)
+    {
+        for (j=0 ; j<width ; j++)
+        {
+            if ( (*data & 0xc0) != 0xc0)
+   *pack++ = *data++;
+            else
+            {
+   *pack++ = 0xc1;
+   *pack++ = *data++;
+            }
+        }
+    }
+ */
+       for ( i = 0 ; i < height ; i++ )
+       {
+               curByte = *data;
+               curRepCount = 0;
+               for ( j = 0 ; j < width ; j++ )
+               {
+                       if ( *data == curByte ) {
+                               curRepCount++;
+                               data++;
+                               continue;
+                       }
+                       StuffPackedByte( curRepCount, curByte, &pack );
+                       curByte = *data++;
+                       curRepCount = 1;
+               }
+               StuffPackedByte( curRepCount, curByte, &pack );
+       }
+       // write the palette
+       *pack++ = 0x0c; // palette ID byte
+       for ( i = 0 ; i < 768 ; i++ )
+               *pack++ = *palette++;
+
+// write output file
+       length = pack - (byte *)pcx;
+       SaveFile( filename, pcx, length );
+
+       free( pcx );
+}
+
+
+/*
+   ============================================================================
+
+   LOAD IMAGE
+
+   ============================================================================
+ */
+
+/*
+   ==============
+   Load256Image
+
+   Will load either an lbm or pcx, depending on extension.
+   Any of the return pointers can be NULL if you don't want them.
+   ==============
+ */
+void Load256Image( char *name, byte **pixels, byte **palette,
+                                  int *width, int *height ){
+       char ext[128];
+
+       ExtractFileExtension( name, ext );
+       if ( !Q_strcasecmp( ext, "lbm" ) ) {
+               LoadLBM( name, pixels, palette );
+               if ( width ) {
+                       *width = bmhd.w;
+               }
+               if ( height ) {
+                       *height = bmhd.h;
+               }
+       }
+       else if ( !Q_strcasecmp( ext, "pcx" ) ) {
+               LoadPCX( name, pixels, palette, width, height );
+       }
+       else{
+               Error( "%s doesn't have a known image extension", name );
+       }
+}
+
+
+/*
+   ==============
+   Save256Image
+
+   Will save either an lbm or pcx, depending on extension.
+   ==============
+ */
+void Save256Image( char *name, byte *pixels, byte *palette,
+                                  int width, int height ){
+       char ext[128];
+
+       ExtractFileExtension( name, ext );
+       if ( !Q_strcasecmp( ext, "lbm" ) ) {
+               WriteLBMfile( name, pixels, width, height, palette );
+       }
+       else if ( !Q_strcasecmp( ext, "pcx" ) ) {
+               WritePCXfile( name, pixels, width, height, palette );
+       }
+       else{
+               Error( "%s doesn't have a known image extension", name );
+       }
+}
+
+
+
+
+/*
+   ============================================================================
+
+   TARGA IMAGE
+
+   ============================================================================
+ */
+
+typedef struct _TargaHeader
+{
+       unsigned char id_length, colormap_type, image_type;
+       unsigned short colormap_index, colormap_length;
+       unsigned char colormap_size;
+       unsigned short x_origin, y_origin, width, height;
+       unsigned char pixel_size, attributes;
+} TargaHeader;
+
+int fgetLittleShort( FILE *f ){
+       byte b1, b2;
+
+       b1 = fgetc( f );
+       b2 = fgetc( f );
+
+       return( (short)( b1 + ( b2 << 8 ) ) );
+}
+
+int fgetLittleLong( FILE *f ){
+       byte b1, b2, b3, b4;
+
+       b1 = fgetc( f );
+       b2 = fgetc( f );
+       b3 = fgetc( f );
+       b4 = fgetc( f );
+
+       return( b1 + ( b2 << 8 ) + ( b3 << 16 ) + ( b4 << 24 ) );
+}
+
+
+/*
+   =============
+   LoadTGA
+   =============
+ */
+void LoadTGA( char *name, byte **pixels, int *width, int *height ){
+       int columns, rows, numPixels;
+       byte            *pixbuf;
+       byte            *rowBuf;
+       int row, column;
+       FILE            *fin;
+       byte            *targa_rgba;
+       TargaHeader targa_header;
+       unsigned char red, green, blue, alphabyte;
+       unsigned char packetHeader, packetSize, j;
+       int flip;
+       int mirror;
+       int rowOffset;
+       int pixDirection;
+
+       fin = fopen( name, "rb" );
+       if ( !fin ) {
+               Error( "Couldn't read %s", name );
+       }
+
+       targa_header.id_length = fgetc( fin );
+       targa_header.colormap_type = fgetc( fin );
+       targa_header.image_type = fgetc( fin );
+
+       targa_header.colormap_index = fgetLittleShort( fin );
+       targa_header.colormap_length = fgetLittleShort( fin );
+       targa_header.colormap_size = fgetc( fin );
+       targa_header.x_origin = fgetLittleShort( fin );
+       targa_header.y_origin = fgetLittleShort( fin );
+       targa_header.width = fgetLittleShort( fin );
+       targa_header.height = fgetLittleShort( fin );
+       targa_header.pixel_size = fgetc( fin );
+       targa_header.attributes = fgetc( fin );
+       flip = ( targa_header.attributes & 0x020 ) == 0;
+       mirror = ( targa_header.attributes & 0x010 ) != 0;
+
+       if ( ( targa_header.image_type != 2 ) && ( targa_header.image_type != 10 ) ) {
+               Error( "LoadTGA: Only type 2 and 10 targa RGB images supported\n" );
+       }
+
+       if ( targa_header.colormap_type || ( ( targa_header.pixel_size != 32 ) && ( targa_header.pixel_size != 24 ) ) ) {
+               Error( "Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n" );
+       }
+
+       columns = targa_header.width;
+       rows = targa_header.height;
+       numPixels = columns * rows;
+
+       if ( width ) {
+               *width = columns;
+       }
+       if ( height ) {
+               *height = rows;
+       }
+
+       if ( !pixels ) {
+               return;
+       }
+
+       targa_rgba = malloc( numPixels * 4 );
+       *pixels = targa_rgba;
+
+       if ( flip ) {
+               pixbuf = targa_rgba + ( ( rows - 1 ) * columns * 4 );
+               rowOffset = -columns * 4;
+       }
+       else
+       {
+               pixbuf = targa_rgba;
+               rowOffset = columns * 4;
+       }
+       if ( mirror ) {
+               pixDirection = -4;
+               pixbuf += ( ( columns - 1 ) * 4 );
+       }
+       else
+       {
+               pixDirection = 4;
+       }
+
+       if ( targa_header.id_length ) {
+               fseek( fin, targa_header.id_length, SEEK_CUR );  // skip TARGA image comment
+
+       }
+       if ( targa_header.image_type == 2 ) {                 // Uncompressed, RGB images
+               for ( row = 0; row < rows; row++ )
+               {
+                       rowBuf = pixbuf;
+                       for ( column = 0; column < columns; column++ )
+                       {
+                               switch ( targa_header.pixel_size )
+                               {
+                               case 24:
+                                       blue = getc( fin );
+                                       green = getc( fin );
+                                       red = getc( fin );
+                                       rowBuf[0] = red;
+                                       rowBuf[1] = green;
+                                       rowBuf[2] = blue;
+                                       rowBuf[3] = 255;
+                                       rowBuf += pixDirection;
+                                       break;
+                               case 32:
+                                       blue = getc( fin );
+                                       green = getc( fin );
+                                       red = getc( fin );
+                                       alphabyte = getc( fin );
+                                       rowBuf[0] = red;
+                                       rowBuf[1] = green;
+                                       rowBuf[2] = blue;
+                                       rowBuf[3] = alphabyte;
+                                       rowBuf += pixDirection;
+                                       break;
+                               }
+                       }
+                       pixbuf += rowOffset;
+               }
+       }
+       else if ( targa_header.image_type == 10 ) {        // Runlength encoded RGB images
+               for ( row = 0; row < rows; row++ )
+               {
+                       rowBuf = pixbuf;
+                       for ( column = 0; column < columns; )
+                       {
+                               packetHeader = getc( fin );
+                               packetSize = 1 + ( packetHeader & 0x7f );
+                               if ( packetHeader & 0x80 ) {          // run-length packet
+                                       switch ( targa_header.pixel_size )
+                                       {
+                                       case 24:
+                                               blue = getc( fin );
+                                               green = getc( fin );
+                                               red = getc( fin );
+                                               alphabyte = 255;
+                                               break;
+                                       case 32:
+                                               blue = getc( fin );
+                                               green = getc( fin );
+                                               red = getc( fin );
+                                               alphabyte = getc( fin );
+                                               break;
+                                       }
+
+                                       for ( j = 0; j < packetSize; j++ )
+                                       {
+                                               rowBuf[0] = red;
+                                               rowBuf[1] = green;
+                                               rowBuf[2] = blue;
+                                               rowBuf[3] = alphabyte;
+                                               rowBuf += pixDirection;
+                                               column++;
+                                               if ( column == columns ) {             // run spans across rows
+                                                       column = 0;
+                                                       row++;
+                                                       if ( row >= rows ) {
+                                                               goto breakOut;
+                                                       }
+                                                       pixbuf += rowOffset;
+                                                       rowBuf = pixbuf;
+                                               }
+                                       }
+                               }
+                               else
+                               {                                       // non run-length packet
+                                       for ( j = 0; j < packetSize; j++ )
+                                       {
+                                               switch ( targa_header.pixel_size )
+                                               {
+                                               case 24:
+                                                       blue = getc( fin );
+                                                       green = getc( fin );
+                                                       red = getc( fin );
+                                                       rowBuf[0] = red;
+                                                       rowBuf[1] = green;
+                                                       rowBuf[2] = blue;
+                                                       rowBuf[3] = 255;
+                                                       rowBuf += pixDirection;
+                                                       break;
+                                               case 32:
+                                                       blue = getc( fin );
+                                                       green = getc( fin );
+                                                       red = getc( fin );
+                                                       alphabyte = getc( fin );
+                                                       rowBuf[0] = red;
+                                                       rowBuf[1] = green;
+                                                       rowBuf[2] = blue;
+                                                       rowBuf[3] = alphabyte;
+                                                       rowBuf += pixDirection;
+                                                       break;
+                                               }
+                                               column++;
+                                               if ( column == columns ) {    // pixel packet run spans across rows
+                                                       column = 0;
+                                                       row++;
+                                                       if ( row >= rows ) {
+                                                               goto breakOut;
+                                                       }
+                                                       pixbuf += rowOffset;
+                                                       rowBuf = pixbuf;
+                                               }
+                                       }
+                               }
+                       }
+breakOut:;
+                       pixbuf += rowOffset;
+               }
+       }
+       fclose( fin );
+}
+
+void MergeAlpha( byte *pix, byte *alpha, byte *pal, byte **out, int width, int height ){
+       int size, i;
+       byte    *data, *src, *srca;
+
+       size = width * height;
+       data = malloc( size * 4 );
+       if ( !data ) {
+               Error( "Could not allocate memory for true color image" );
+       }
+
+       *out = data;
+       src = pix;
+       srca = alpha;
+
+       for ( i = 0; i < size; i++, src++, srca++ )
+       {
+               *data++ = pal[*src * 3 + 0];      // r
+               *data++ = pal[*src * 3 + 1];      // g
+               *data++ = pal[*src * 3 + 2];      // b
+               *data++ = *srca;                  // a
+       }
+       free( pix );
+       free( alpha );
+       free( pal );
+}
+
+/*
+   ==============
+   LoadAnyImage
+
+   Return Value:
+    false: paletted texture
+    true:  true color RGBA image (no palette)
+   ==============
+ */
+qboolean LoadAnyImage( char *name, byte **pixels, byte **palette, int *width, int *height ){
+       char ext[128];
+       int len;
+       int alpha_width, alpha_height;
+       char alpha_name[128];
+       byte    *alpha_pixels;
+
+       ExtractFileExtension( name, ext );
+
+       if ( palette ) {
+               *palette = NULL;
+       }
+
+       if ( !Q_strcasecmp( ext, "lbm" ) ) {
+               LoadLBM( name, pixels, palette );
+               if ( width ) {
+                       *width = bmhd.w;
+               }
+               if ( height ) {
+                       *height = bmhd.h;
+               }
+               return false;
+       }
+       else if ( !Q_strcasecmp( ext, "pcx" ) ) {
+               len = strlen( name );
+               strcpy( alpha_name, name );
+               strcpy( &alpha_name[len - 4], "_a.pcx" );                 // Alpha map name (may not exist)
+
+               if ( FileExists( alpha_name ) ) {
+                       LoadPCX( name, pixels, palette, width, height );                         // Load in image
+                       LoadPCX( alpha_name, &alpha_pixels, NULL, &alpha_width, &alpha_height ); // Load in alpha map
+                       if ( ( *width != alpha_width ) || ( *height != alpha_height ) ) {
+                               Error( "Alpha image dimensions not equal to graphic image dimensions" );
+                       }
+                       MergeAlpha( *pixels, alpha_pixels, *palette, pixels, *width, *height );
+                       *palette = NULL; //Merge Frees pal
+                       return true;
+               }
+               else
+               {
+                       LoadPCX( name, pixels, palette, width, height );         // Load in image
+                       return false;
+               }
+       }
+       else if ( !Q_strcasecmp( ext, "tga" ) ) {
+               LoadTGA( name, pixels, width, height );
+               if ( palette ) {
+                       *palette = NULL;
+               }
+
+               return true;
+       }
+       else{
+               Error( "%s doesn't have a known image extension", name );
+       }
+
+       return false;
+}
diff --git a/tools/heretic2/common/lbmlib.h b/tools/heretic2/common/lbmlib.h
new file mode 100644 (file)
index 0000000..5ee2909
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+// piclib.h
+
+
+void LoadLBM( char *filename, byte **picture, byte **palette );
+void WriteLBMfile( char *filename, byte *data, int width, int height
+                                  , byte *palette );
+void LoadPCX( char *filename, byte **picture, byte **palette, int *width, int *height );
+void WritePCXfile( char *filename, byte *data, int width, int height
+                                  , byte *palette );
+
+// loads / saves either lbm or pcx, depending on extension
+void Load256Image( char *name, byte **pixels, byte **palette,
+                                  int *width, int *height );
+void Save256Image( char *name, byte *pixels, byte *palette,
+                                  int width, int height );
+
+
+void LoadTGA( char *filename, byte **pixels, int *width, int *height );
+
+qboolean LoadAnyImage( char *name, byte **pixels, byte **palette, int *width, int *height );
diff --git a/tools/heretic2/common/mathlib.c b/tools/heretic2/common/mathlib.c
new file mode 100644 (file)
index 0000000..8243d86
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+// mathlib.c -- math primitives
+
+#include "cmdlib.h"
+#include "mathlib.h"
+
+vec3_t vec3_origin = {0,0,0};
+
+
+double VectorLength( vec3_t v ){
+       int i;
+       double length;
+
+       length = 0;
+       for ( i = 0 ; i < 3 ; i++ )
+               length += v[i] * v[i];
+       length = sqrt( length );     // FIXME
+
+       return length;
+}
+
+qboolean VectorCompare( vec3_t v1, vec3_t v2 ){
+       int i;
+
+       for ( i = 0 ; i < 3 ; i++ )
+               if ( fabs( v1[i] - v2[i] ) > EQUAL_EPSILON ) {
+                       return false;
+               }
+
+       return true;
+}
+
+vec_t Q_rint( vec_t in ){
+       return floor( in + 0.5 );
+}
+
+void VectorMA( vec3_t va, double scale, vec3_t vb, vec3_t vc ){
+       vc[0] = va[0] + scale * vb[0];
+       vc[1] = va[1] + scale * vb[1];
+       vc[2] = va[2] + scale * vb[2];
+}
+
+void CrossProduct( vec3_t v1, vec3_t v2, vec3_t cross ){
+       cross[0] = v1[1] * v2[2] - v1[2] * v2[1];
+       cross[1] = v1[2] * v2[0] - v1[0] * v2[2];
+       cross[2] = v1[0] * v2[1] - v1[1] * v2[0];
+}
+
+vec_t _DotProduct( vec3_t v1, vec3_t v2 ){
+       return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
+}
+
+void _VectorSubtract( vec3_t va, vec3_t vb, vec3_t out ){
+       out[0] = va[0] - vb[0];
+       out[1] = va[1] - vb[1];
+       out[2] = va[2] - vb[2];
+}
+
+void _VectorAdd( vec3_t va, vec3_t vb, vec3_t out ){
+       out[0] = va[0] + vb[0];
+       out[1] = va[1] + vb[1];
+       out[2] = va[2] + vb[2];
+}
+
+void _VectorCopy( vec3_t in, vec3_t out ){
+       out[0] = in[0];
+       out[1] = in[1];
+       out[2] = in[2];
+}
+
+void _VectorScale( vec3_t v, vec_t scale, vec3_t out ){
+       out[0] = v[0] * scale;
+       out[1] = v[1] * scale;
+       out[2] = v[2] * scale;
+}
+
+#if GDEF_COMPILER_MSVC
+#pragma optimize("g", off)  // went back to turning optimization off,
+                            // the bug_fix thing stopped working
+#endif
+
+vec_t VectorNormalize( vec3_t in, vec3_t out ){
+       vec_t length, ilength;
+
+       length = sqrt( in[0] * in[0] + in[1] * in[1] + in[2] * in[2] );
+       if ( length == 0 ) {
+               VectorClear( out );
+               return 0;
+       }
+
+       ilength = 1.0 / length;
+       out[0] = in[0] * ilength;
+       out[1] = in[1] * ilength;
+       out[2] = in[2] * ilength;
+
+       return length;
+}
+
+vec_t ColorNormalize( vec3_t in, vec3_t out ){
+       float max, scale;
+
+       max = in[0];
+       if ( in[1] > max ) {
+               max = in[1];
+       }
+       if ( in[2] > max ) {
+               max = in[2];
+       }
+
+       if ( max == 0 ) {
+               return 0;
+       }
+
+       scale = 1.0 / max;
+
+       VectorScale( in, scale, out );
+
+       return max;
+}
+
+#if GDEF_COMPILER_MSVC
+#pragma optimize("", on)
+#endif
+
+void VectorInverse( vec3_t v ){
+       v[0] = -v[0];
+       v[1] = -v[1];
+       v[2] = -v[2];
+}
+
+void ClearBounds( vec3_t mins, vec3_t maxs ){
+       mins[0] = mins[1] = mins[2] = 99999;
+       maxs[0] = maxs[1] = maxs[2] = -99999;
+}
+
+void AddPointToBounds( vec3_t v, vec3_t mins, vec3_t maxs ){
+       int i;
+       vec_t val;
+
+       for ( i = 0 ; i < 3 ; i++ )
+       {
+               val = v[i];
+               if ( val < mins[i] ) {
+                       mins[i] = val;
+               }
+               if ( val > maxs[i] ) {
+                       maxs[i] = val;
+               }
+       }
+}
diff --git a/tools/heretic2/common/mathlib.h b/tools/heretic2/common/mathlib.h
new file mode 100644 (file)
index 0000000..cd989ea
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __MATHLIB__
+#define __MATHLIB__
+
+// mathlib.h
+
+#include <math.h>
+/*
+   #ifdef DOUBLEVEC_T
+   typedef double vec_t;
+   #else
+   typedef float vec_t;
+   #endif
+   typedef vec_t vec3_t[3];
+ */
+#define SIDE_FRONT      0
+#define SIDE_ON         2
+#define SIDE_BACK       1
+#define SIDE_CROSS      -2
+
+#define Q_PI    3.14159265358979323846
+
+extern vec3_t vec3_origin;
+
+#define EQUAL_EPSILON   0.001
+
+qboolean VectorCompare( vec3_t v1, vec3_t v2 );
+
+#define DotProduct( x,y ) ( x[0] * y[0] + x[1] * y[1] + x[2] * y[2] )
+#define VectorSubtract( a,b,c ) {c[0] = a[0] - b[0]; c[1] = a[1] - b[1]; c[2] = a[2] - b[2]; }
+#define VectorAdd( a,b,c ) {c[0] = a[0] + b[0]; c[1] = a[1] + b[1]; c[2] = a[2] + b[2]; }
+#define VectorCopy( a,b ) {b[0] = a[0]; b[1] = a[1]; b[2] = a[2]; }
+#define VectorScale( a,b,c ) {c[0] = b * a[0]; c[1] = b * a[1]; c[2] = b * a[2]; }
+#define VectorClear( x ) {x[0] = x[1] = x[2] = 0; }
+#define VectorNegate( x ) {x[0] = -x[0]; x[1] = -x[1]; x[2] = -x[2]; }
+
+vec_t Q_rint( vec_t in );
+vec_t _DotProduct( vec3_t v1, vec3_t v2 );
+void _VectorSubtract( vec3_t va, vec3_t vb, vec3_t out );
+void _VectorAdd( vec3_t va, vec3_t vb, vec3_t out );
+void _VectorCopy( vec3_t in, vec3_t out );
+void _VectorScale( vec3_t v, vec_t scale, vec3_t out );
+
+double VectorLength( vec3_t v );
+
+void VectorMA( vec3_t va, double scale, vec3_t vb, vec3_t vc );
+
+void CrossProduct( vec3_t v1, vec3_t v2, vec3_t cross );
+vec_t VectorNormalize( vec3_t in, vec3_t out );
+vec_t ColorNormalize( vec3_t in, vec3_t out );
+void VectorInverse( vec3_t v );
+
+void ClearBounds( vec3_t mins, vec3_t maxs );
+void AddPointToBounds( vec3_t v, vec3_t mins, vec3_t maxs );
+
+#endif
diff --git a/tools/heretic2/common/md4.c b/tools/heretic2/common/md4.c
new file mode 100644 (file)
index 0000000..f503422
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+    mdfour.c
+
+    An implementation of MD4 designed for use in the samba SMB
+    authentication protocol
+
+    Copyright (C) 1997-1998  Andrew Tridgell
+
+    This program 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.
+
+    This program 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 this program; if not, write to:
+
+        Free Software Foundation, Inc.
+        59 Temple Place - Suite 330
+        Boston, MA  02111-1307, USA
+
+    $Id: mdfour.c 7689 2007-11-12 14:28:40Z divverent $
+ */
+
+#include <string.h>     /* XoXus: needed for memset call */
+#include "md4.h"
+
+/* NOTE: This code makes no attempt to be fast!
+
+   It assumes that a int is at least 32 bits long
+ */
+
+static struct mdfour *m;
+
+#define F( X,Y,Z ) ( ( (X)&( Y ) ) | ( ( ~( X ) ) & ( Z ) ) )
+#define G( X,Y,Z ) ( ( (X)&( Y ) ) | ( (X)&( Z ) ) | ( (Y)&( Z ) ) )
+#define H( X,Y,Z ) ( ( X ) ^ ( Y ) ^ ( Z ) )
+#ifdef LARGE_INT32
+#define lshift( x,s ) ( ( ( ( x ) << ( s ) ) & 0xFFFFFFFF ) | ( ( ( x ) >> ( 32 - ( s ) ) ) & 0xFFFFFFFF ) )
+#else
+#define lshift( x,s ) ( ( ( x ) << ( s ) ) | ( ( x ) >> ( 32 - ( s ) ) ) )
+#endif
+
+#define ROUND1( a,b,c,d,k,s ) a = lshift( a + F( b,c,d ) + X[k], s )
+#define ROUND2( a,b,c,d,k,s ) a = lshift( a + G( b,c,d ) + X[k] + 0x5A827999,s )
+#define ROUND3( a,b,c,d,k,s ) a = lshift( a + H( b,c,d ) + X[k] + 0x6ED9EBA1,s )
+
+/* this applies md4 to 64 byte chunks */
+static void mdfour64( uint32 *M ){
+       int j;
+       uint32 AA, BB, CC, DD;
+       uint32 X[16];
+       uint32 A,B,C,D;
+
+       for ( j = 0; j < 16; j++ )
+               X[j] = M[j];
+
+       A = m->A; B = m->B; C = m->C; D = m->D;
+       AA = A; BB = B; CC = C; DD = D;
+
+       ROUND1( A,B,C,D,  0,  3 );  ROUND1( D,A,B,C,  1,  7 );
+       ROUND1( C,D,A,B,  2, 11 );  ROUND1( B,C,D,A,  3, 19 );
+       ROUND1( A,B,C,D,  4,  3 );  ROUND1( D,A,B,C,  5,  7 );
+       ROUND1( C,D,A,B,  6, 11 );  ROUND1( B,C,D,A,  7, 19 );
+       ROUND1( A,B,C,D,  8,  3 );  ROUND1( D,A,B,C,  9,  7 );
+       ROUND1( C,D,A,B, 10, 11 );  ROUND1( B,C,D,A, 11, 19 );
+       ROUND1( A,B,C,D, 12,  3 );  ROUND1( D,A,B,C, 13,  7 );
+       ROUND1( C,D,A,B, 14, 11 );  ROUND1( B,C,D,A, 15, 19 );
+
+       ROUND2( A,B,C,D,  0,  3 );  ROUND2( D,A,B,C,  4,  5 );
+       ROUND2( C,D,A,B,  8,  9 );  ROUND2( B,C,D,A, 12, 13 );
+       ROUND2( A,B,C,D,  1,  3 );  ROUND2( D,A,B,C,  5,  5 );
+       ROUND2( C,D,A,B,  9,  9 );  ROUND2( B,C,D,A, 13, 13 );
+       ROUND2( A,B,C,D,  2,  3 );  ROUND2( D,A,B,C,  6,  5 );
+       ROUND2( C,D,A,B, 10,  9 );  ROUND2( B,C,D,A, 14, 13 );
+       ROUND2( A,B,C,D,  3,  3 );  ROUND2( D,A,B,C,  7,  5 );
+       ROUND2( C,D,A,B, 11,  9 );  ROUND2( B,C,D,A, 15, 13 );
+
+       ROUND3( A,B,C,D,  0,  3 );  ROUND3( D,A,B,C,  8,  9 );
+       ROUND3( C,D,A,B,  4, 11 );  ROUND3( B,C,D,A, 12, 15 );
+       ROUND3( A,B,C,D,  2,  3 );  ROUND3( D,A,B,C, 10,  9 );
+       ROUND3( C,D,A,B,  6, 11 );  ROUND3( B,C,D,A, 14, 15 );
+       ROUND3( A,B,C,D,  1,  3 );  ROUND3( D,A,B,C,  9,  9 );
+       ROUND3( C,D,A,B,  5, 11 );  ROUND3( B,C,D,A, 13, 15 );
+       ROUND3( A,B,C,D,  3,  3 );  ROUND3( D,A,B,C, 11,  9 );
+       ROUND3( C,D,A,B,  7, 11 );  ROUND3( B,C,D,A, 15, 15 );
+
+       A += AA; B += BB; C += CC; D += DD;
+
+#ifdef LARGE_INT32
+       A &= 0xFFFFFFFF; B &= 0xFFFFFFFF;
+       C &= 0xFFFFFFFF; D &= 0xFFFFFFFF;
+#endif
+
+       for ( j = 0; j < 16; j++ )
+               X[j] = 0;
+
+       m->A = A; m->B = B; m->C = C; m->D = D;
+}
+
+static void copy64( uint32 *M, unsigned char *in ){
+       int i;
+
+       for ( i = 0; i < 16; i++ )
+               M[i] = ( in[i * 4 + 3] << 24 ) | ( in[i * 4 + 2] << 16 ) |
+                          ( in[i * 4 + 1] << 8 ) | ( in[i * 4 + 0] << 0 );
+}
+
+static void copy4( unsigned char *out,uint32 x ){
+       out[0] = x & 0xFF;
+       out[1] = ( x >> 8 ) & 0xFF;
+       out[2] = ( x >> 16 ) & 0xFF;
+       out[3] = ( x >> 24 ) & 0xFF;
+}
+
+void mdfour_begin( struct mdfour *md ){
+       md->A = 0x67452301;
+       md->B = 0xefcdab89;
+       md->C = 0x98badcfe;
+       md->D = 0x10325476;
+       md->totalN = 0;
+}
+
+
+static void mdfour_tail( unsigned char *in, int n ){
+       unsigned char buf[128];
+       uint32 M[16];
+       uint32 b;
+
+       m->totalN += n;
+
+       b = m->totalN * 8;
+
+       memset( buf, 0, 128 );
+       if ( n ) {
+               memcpy( buf, in, n );
+       }
+       buf[n] = 0x80;
+
+       if ( n <= 55 ) {
+               copy4( buf + 56, b );
+               copy64( M, buf );
+               mdfour64( M );
+       }
+       else {
+               copy4( buf + 120, b );
+               copy64( M, buf );
+               mdfour64( M );
+               copy64( M, buf + 64 );
+               mdfour64( M );
+       }
+}
+
+void mdfour_update( struct mdfour *md, unsigned char *in, int n ){
+       uint32 M[16];
+
+// start of edit by Forest 'LordHavoc' Hale
+// commented out to prevent crashing when length is 0
+//     if (n == 0) mdfour_tail(in, n);
+// end of edit by Forest 'LordHavoc' Hale
+
+       m = md;
+
+       while ( n >= 64 ) {
+               copy64( M, in );
+               mdfour64( M );
+               in += 64;
+               n -= 64;
+               m->totalN += 64;
+       }
+
+       mdfour_tail( in, n );
+}
+
+
+void mdfour_result( struct mdfour *md, unsigned char *out ){
+       m = md;
+
+       copy4( out, m->A );
+       copy4( out + 4, m->B );
+       copy4( out + 8, m->C );
+       copy4( out + 12, m->D );
+}
+
+
+void mdfour( unsigned char *out, unsigned char *in, int n ){
+       struct mdfour md;
+       mdfour_begin( &md );
+       mdfour_update( &md, in, n );
+       mdfour_result( &md, out );
+}
+
+///////////////////////////////////////////////////////////////
+//     MD4-based checksum utility functions
+//
+//     Copyright (C) 2000       Jeff Teunissen <d2deek@pmail.net>
+//
+//     Author: Jeff Teunissen  <d2deek@pmail.net>
+//     Date: 01 Jan 2000
+
+unsigned Com_BlockChecksum( void *buffer, int length ){
+       int digest[4];
+       unsigned val;
+
+       mdfour( (unsigned char *) digest, (unsigned char *) buffer, length );
+
+       val = digest[0] ^ digest[1] ^ digest[2] ^ digest[3];
+
+       return val;
+}
+
+void Com_BlockFullChecksum( void *buffer, int len, unsigned char *outbuf ){
+       mdfour( outbuf, (unsigned char *) buffer, len );
+}
diff --git a/tools/heretic2/common/md4.h b/tools/heretic2/common/md4.h
new file mode 100644 (file)
index 0000000..6f64c28
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+    mdfour.h
+
+    an implementation of MD4 designed for use in the SMB authentication
+    protocol
+
+    Copyright (C) Andrew Tridgell 1997-1998
+
+    This program 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.
+
+    This program 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 this program; if not, write to:
+
+        Free Software Foundation, Inc.
+        59 Temple Place - Suite 330
+        Boston, MA  02111-1307, USA
+ */
+
+#ifndef _MDFOUR_H
+#define _MDFOUR_H
+
+#ifndef int32
+#define int32 int
+#endif
+
+#if SIZEOF_INT > 4
+#define LARGE_INT32
+#endif
+
+#ifndef uint32
+#define uint32 unsigned int32
+#endif
+
+struct mdfour {
+       uint32 A, B, C, D;
+       uint32 totalN;
+};
+
+void mdfour_begin( struct mdfour *md ); // old: MD4Init
+void mdfour_update( struct mdfour *md, unsigned char *in, int n ); //old: MD4Update
+void mdfour_result( struct mdfour *md, unsigned char *out ); // old: MD4Final
+void mdfour( unsigned char *out, unsigned char *in, int n );
+
+unsigned Com_BlockChecksum( void *buffer, int length );
+void Com_BlockFullChecksum( void *buffer, int len, unsigned char *outbuf );
+
+#endif  // _MDFOUR_H
diff --git a/tools/heretic2/common/path_init.c b/tools/heretic2/common/path_init.c
new file mode 100644 (file)
index 0000000..254977b
--- /dev/null
@@ -0,0 +1,391 @@
+/* -------------------------------------------------------------------------------
+
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/*
+   Nurail: Swiped from Q3Map2
+ */
+
+#include "globaldefs.h"
+
+#if !GDEF_OS_WINDOWS
+       #include <unistd.h>
+       #include <pwd.h>
+       #include <limits.h>
+#endif // !GDEF_OS_WINDOWS
+
+/* dependencies */
+#include "cmdlib.h"
+#include "inout.h"
+
+/* path support */
+#define MAX_BASE_PATHS  10
+#define MAX_GAME_PATHS  10
+
+char                    *homePath;
+char installPath[ MAX_OS_PATH ];
+
+int numBasePaths;
+char                    *basePaths[ MAX_BASE_PATHS ];
+int numGamePaths;
+char                    *gamePaths[ MAX_GAME_PATHS ];
+
+/*
+   some of this code is based off the original q3map port from loki
+   and finds various paths. moved here from bsp.c for clarity.
+ */
+
+/*
+   PathLokiGetHomeDir()
+   gets the user's home dir (for ~/.q3a)
+ */
+
+char *LokiGetHomeDir( void ){
+       #if GDEF_OS_WINDOWS
+       return NULL;
+       #else // !GDEF_OS_WINDOWS
+       char            *home;
+       uid_t id;
+       struct passwd   *pwd;
+
+
+       /* get the home environment variable */
+       home = getenv( "HOME" );
+       if ( home == NULL ) {
+               /* do some more digging */
+               id = getuid();
+               setpwent();
+               while ( ( pwd = getpwent() ) != NULL )
+               {
+                       if ( pwd->pw_uid == id ) {
+                               home = pwd->pw_dir;
+                               break;
+                       }
+               }
+               endpwent();
+       }
+
+       /* return it */
+       return home;
+       #endif // !GDEF_OS_WINDOWS
+}
+
+
+
+/*
+   PathLokiInitPaths()
+   initializes some paths on linux/os x
+ */
+
+void LokiInitPaths( char *argv0 ){
+       #if GDEF_OS_WINDOWS
+       /* this is kinda crap, but hey */
+       strcpy( installPath, "../" );
+       #else // !GDEF_OS_WINDOWS
+       char temp[ MAX_OS_PATH ];
+       char        *home;
+       char        *path;
+       char        *last;
+       qboolean found;
+
+
+       /* get home dir */
+       home = LokiGetHomeDir();
+       if ( home == NULL ) {
+               home = ".";
+       }
+
+       /* do some path divining */
+       strcpy( temp, argv0 );
+       if ( strrchr( temp, '/' ) ) {
+               argv0 = strrchr( argv0, '/' ) + 1;
+       }
+       else
+       {
+               /* get path environment variable */
+               path = getenv( "PATH" );
+
+               /* minor setup */
+               last[ 0 ] = path[ 0 ];
+               last[ 1 ] = '\0';
+               found = false;
+
+               /* go through each : segment of path */
+               while ( last[ 0 ] != '\0' && found == false )
+               {
+                       /* null out temp */
+                       temp[ 0 ] = '\0';
+
+                       /* find next chunk */
+                       last = strchr( path, ':' );
+                       if ( last == NULL ) {
+                               last = path + strlen( path );
+                       }
+
+                       /* found home dir candidate */
+                       if ( *path == '~' ) {
+                               strcpy( temp, home );
+                               path++;
+                       }
+
+                       /* concatenate */
+                       if ( last > ( path + 1 ) ) {
+                               strncat( temp, path, ( last - path ) );
+                               strcat( temp, "/" );
+                       }
+                       strcat( temp, "./" );
+                       strcat( temp, argv0 );
+
+                       /* verify the path */
+                       if ( access( temp, X_OK ) == 0 ) {
+                               found++;
+                       }
+                       path = last + 1;
+               }
+       }
+
+       /* flake */
+       if ( realpath( temp, installPath ) ) {
+               /* q3map is in "tools/" */
+               *( strrchr( installPath, '/' ) ) = '\0';
+               *( strrchr( installPath, '/' ) + 1 ) = '\0';
+       }
+
+       /* set home path */
+       homePath = home;
+       #endif // !GDEF_OS_WINDOWS
+}
+
+
+
+/*
+   CleanPath() - ydnar
+   cleans a dos path \ -> /
+ */
+
+void CleanPath( char *path ){
+       while ( *path )
+       {
+               if ( *path == '\\' ) {
+                       *path = '/';
+               }
+               path++;
+       }
+}
+
+/*
+   AddBasePath() - ydnar
+   adds a base path to the list
+ */
+
+void AddBasePath( char *path ){
+       /* dummy check */
+       if ( path == NULL || path[ 0 ] == '\0' || numBasePaths >= MAX_BASE_PATHS ) {
+               return;
+       }
+
+       /* add it to the list */
+       basePaths[ numBasePaths ] = safe_malloc( strlen( path ) + 1 );
+       strcpy( basePaths[ numBasePaths ], path );
+       CleanPath( basePaths[ numBasePaths ] );
+       numBasePaths++;
+}
+
+
+
+/*
+   AddHomeBasePath() - ydnar
+   adds a base path to the beginning of the list, prefixed by ~/
+ */
+
+void AddHomeBasePath( char *path ){
+       #if !GDEF_OS_WINDOWS
+       int i;
+       char temp[ MAX_OS_PATH ];
+
+
+       /* dummy check */
+       if ( path == NULL || path[ 0 ] == '\0' ) {
+               return;
+       }
+
+       /* make a hole */
+       for ( i = 0; i < ( MAX_BASE_PATHS - 1 ); i++ )
+               basePaths[ i + 1 ] = basePaths[ i ];
+
+       /* concatenate home dir and path */
+       sprintf( temp, "%s/%s", homePath, path );
+
+       /* add it to the list */
+       basePaths[ 0 ] = safe_malloc( strlen( temp ) + 1 );
+       strcpy( basePaths[ 0 ], temp );
+       CleanPath( basePaths[ 0 ] );
+       numBasePaths++;
+       #endif // !GDEF_OS_WINDOWS
+}
+
+
+
+/*
+   AddGamePath() - ydnar
+   adds a game path to the list
+ */
+
+void AddGamePath( char *path ){
+       /* dummy check */
+       if ( path == NULL || path[ 0 ] == '\0' || numGamePaths >= MAX_GAME_PATHS ) {
+               return;
+       }
+
+       /* add it to the list */
+       gamePaths[ numGamePaths ] = safe_malloc( strlen( path ) + 1 );
+       strcpy( gamePaths[ numGamePaths ], path );
+       CleanPath( gamePaths[ numGamePaths ] );
+       numGamePaths++;
+}
+
+
+
+
+/*
+   InitPaths() - ydnar
+   cleaned up some of the path initialization code from bsp.c
+   will remove any arguments it uses
+ */
+
+void InitPaths( int *argc, char **argv ){
+       int i, j, k, len, len2;
+       char temp[ MAX_OS_PATH ];
+       char gamePath[MAX_OS_PATH], homeBasePath[MAX_OS_PATH], game_magic[10];
+
+       strcpy( gamePath, "base" );
+       strcpy( game_magic, "h" );
+       strcpy( homeBasePath, ".heretic2" );
+
+       /* note it */
+       Sys_FPrintf( SYS_VRB, "--- InitPaths ---\n" );
+
+       /* get the install path for backup */
+       LokiInitPaths( argv[ 0 ] );
+
+       /* set game to default (q3a) */
+       numBasePaths = 0;
+       numGamePaths = 0;
+
+       /* parse through the arguments and extract those relevant to paths */
+       for ( i = 0; i < *argc; i++ )
+       {
+               /* check for null */
+               if ( argv[ i ] == NULL ) {
+                       continue;
+               }
+
+               /* -fs_basepath */
+               if ( strcmp( argv[ i ], "-fs_basepath" ) == 0 ) {
+                       if ( ++i >= *argc ) {
+                               Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
+                       }
+                       argv[ i - 1 ] = NULL;
+                       AddBasePath( argv[ i ] );
+                       argv[ i ] = NULL;
+               }
+
+       }
+
+       /* remove processed arguments */
+       for ( i = 0, j = 0, k = 0; i < *argc && j < *argc; i++, j++ )
+       {
+               for ( j; j < *argc && argv[ j ] == NULL; j++ ) ;
+               argv[ i ] = argv[ j ];
+               if ( argv[ i ] != NULL ) {
+                       k++;
+               }
+       }
+       *argc = k;
+
+       /* add standard game path */
+       AddGamePath( gamePath );
+
+       /* if there is no base path set, figure it out */
+       if ( numBasePaths == 0 ) {
+               /* this is another crappy replacement for SetQdirFromPath() */
+               len2 = strlen( game_magic );
+               for ( i = 0; i < *argc && numBasePaths == 0; i++ )
+               {
+                       /* extract the arg */
+                       strcpy( temp, argv[ i ] );
+                       CleanPath( temp );
+                       len = strlen( temp );
+                       Sys_FPrintf( SYS_VRB, "Searching for \"%s\" in \"%s\" (%d)...\n", game_magic, temp, i );
+
+                       /* this is slow, but only done once */
+                       for ( j = 0; j < ( len - len2 ); j++ )
+                       {
+                               /* check for the game's magic word */
+                               if ( Q_strncasecmp( &temp[ j ], game_magic, len2 ) == 0 ) {
+                                       /* now find the next slash and nuke everything after it */
+                                       while ( temp[ ++j ] != '/' && temp[ j ] != '\0' ) ;
+                                       temp[ j ] = '\0';
+
+                                       /* add this as a base path */
+                                       AddBasePath( temp );
+                                       break;
+                               }
+                       }
+               }
+
+               /* add install path */
+               if ( numBasePaths == 0 ) {
+                       AddBasePath( installPath );
+               }
+
+               /* check again */
+               if ( numBasePaths == 0 ) {
+                       Error( "Failed to find a valid base path." );
+               }
+       }
+
+       /* this only affects unix */
+       AddHomeBasePath( homeBasePath );
+
+       /* initialize vfs paths */
+       if ( numBasePaths > MAX_BASE_PATHS ) {
+               numBasePaths = MAX_BASE_PATHS;
+       }
+       if ( numGamePaths > MAX_GAME_PATHS ) {
+               numGamePaths = MAX_GAME_PATHS;
+       }
+
+       /* walk the list of game paths */
+       //for( j = 0; j < numGamePaths; j++ )
+       //{
+       /* walk the list of base paths */
+       //      for( i = 0; i < numBasePaths; i++ )
+       //      {
+       /* create a full path and initialize it */
+       //              sprintf( temp, "%s/%s/", basePaths[ i ], gamePaths[ j ] );
+       //              vfsInitDirectory( temp );
+       //      }
+       //}
+
+       /* done */
+       Sys_Printf( "\n" );
+}
diff --git a/tools/heretic2/common/polylib.c b/tools/heretic2/common/polylib.c
new file mode 100644 (file)
index 0000000..af5df49
--- /dev/null
@@ -0,0 +1,665 @@
+/*
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+
+#include "cmdlib.h"
+#include "inout.h"
+#include "mathlib.h"
+#include "polylib.h"
+
+
+extern int numthreads;
+
+// counters are only bumped when running single threaded,
+// because they are an awefull coherence problem
+int c_active_windings;
+int c_peak_windings;
+int c_winding_allocs;
+int c_winding_points;
+
+#define BOGUS_RANGE 8192
+
+void pw( winding_t *w ){
+       int i;
+       for ( i = 0 ; i < w->numpoints ; i++ )
+               printf( "(%5.1f, %5.1f, %5.1f)\n",w->p[i][0], w->p[i][1],w->p[i][2] );
+}
+
+
+/*
+   =============
+   AllocWinding
+   =============
+ */
+winding_t   *AllocWinding( int points ){
+       winding_t   *w;
+       int s;
+
+       if ( numthreads == 1 ) {
+               c_winding_allocs++;
+               c_winding_points += points;
+               c_active_windings++;
+               if ( c_active_windings > c_peak_windings ) {
+                       c_peak_windings = c_active_windings;
+               }
+       }
+       s = sizeof( vec_t ) * 3 * points + sizeof( int );
+       w = malloc( s );
+       if ( !w ) {
+               Error( "AllocWinding MALLOC failed!  Could not allocate %s bytes.", s );
+       }
+       memset( w, 0, s );
+       return w;
+}
+
+void FreeWinding( winding_t *w ){
+       if ( *(unsigned *)w == 0xdeaddead ) {
+               Error( "FreeWinding: freed a freed winding" );
+       }
+       *(unsigned *)w = 0xdeaddead;
+
+       if ( numthreads == 1 ) {
+               c_active_windings--;
+       }
+       free( w );
+}
+
+/*
+   ============
+   RemoveColinearPoints
+   ============
+ */
+int c_removed;
+
+void    RemoveColinearPoints( winding_t *w ){
+       int i, j, k;
+       vec3_t v1, v2;
+       int nump;
+       vec3_t p[MAX_POINTS_ON_WINDING];
+
+       nump = 0;
+       for ( i = 0 ; i < w->numpoints ; i++ )
+       {
+               j = ( i + 1 ) % w->numpoints;
+               k = ( i + w->numpoints - 1 ) % w->numpoints;
+               VectorSubtract( w->p[j], w->p[i], v1 );
+               VectorSubtract( w->p[i], w->p[k], v2 );
+               VectorNormalize( v1,v1 );
+               VectorNormalize( v2,v2 );
+               if ( DotProduct( v1, v2 ) < 0.999 ) {
+                       VectorCopy( w->p[i], p[nump] );
+                       nump++;
+               }
+       }
+
+       if ( nump == w->numpoints ) {
+               return;
+       }
+
+       if ( numthreads == 1 ) {
+               c_removed += w->numpoints - nump;
+       }
+       w->numpoints = nump;
+       memcpy( w->p, p, nump * sizeof( p[0] ) );
+}
+
+/*
+   ============
+   WindingPlane
+   ============
+ */
+void WindingPlane( winding_t *w, vec3_t normal, vec_t *dist ){
+       vec3_t v1, v2;
+
+       VectorSubtract( w->p[1], w->p[0], v1 );
+       VectorSubtract( w->p[2], w->p[0], v2 );
+       CrossProduct( v2, v1, normal );
+       VectorNormalize( normal, normal );
+       *dist = DotProduct( w->p[0], normal );
+
+}
+
+/*
+   =============
+   WindingArea
+   =============
+ */
+vec_t   WindingArea( winding_t *w ){
+       int i;
+       vec3_t d1, d2, cross;
+       vec_t total;
+
+       total = 0;
+       for ( i = 2 ; i < w->numpoints ; i++ )
+       {
+               VectorSubtract( w->p[i - 1], w->p[0], d1 );
+               VectorSubtract( w->p[i], w->p[0], d2 );
+               CrossProduct( d1, d2, cross );
+               total += 0.5 * VectorLength( cross );
+       }
+       return total;
+}
+
+void    WindingBounds( winding_t *w, vec3_t mins, vec3_t maxs ){
+       vec_t v;
+       int i,j;
+
+       mins[0] = mins[1] = mins[2] = 99999;
+       maxs[0] = maxs[1] = maxs[2] = -99999;
+
+       for ( i = 0 ; i < w->numpoints ; i++ )
+       {
+               for ( j = 0 ; j < 3 ; j++ )
+               {
+                       v = w->p[i][j];
+                       if ( v < mins[j] ) {
+                               mins[j] = v;
+                       }
+                       if ( v > maxs[j] ) {
+                               maxs[j] = v;
+                       }
+               }
+       }
+}
+
+/*
+   =============
+   WindingCenter
+   =============
+ */
+void    WindingCenter( winding_t *w, vec3_t center ){
+       int i;
+       float scale;
+
+       VectorCopy( vec3_origin, center );
+       for ( i = 0 ; i < w->numpoints ; i++ )
+               VectorAdd( w->p[i], center, center );
+
+       scale = 1.0 / w->numpoints;
+       VectorScale( center, scale, center );
+}
+
+/*
+   =================
+   BaseWindingForPlane
+   =================
+ */
+winding_t *BaseWindingForPlane( vec3_t normal, vec_t dist ){
+       int i, x;
+       vec_t max, v;
+       vec3_t org, vright, vup;
+       winding_t   *w;
+
+// find the major axis
+
+       max = -BOGUS_RANGE;
+       x = -1;
+       for ( i = 0 ; i < 3; i++ )
+       {
+               v = fabs( normal[i] );
+               if ( v > max ) {
+                       x = i;
+                       max = v;
+               }
+       }
+       if ( x == -1 ) {
+               Error( "BaseWindingForPlane: no axis found" );
+       }
+
+       VectorCopy( vec3_origin, vup );
+       switch ( x )
+       {
+       case 0:
+       case 1:
+               vup[2] = 1;
+               break;
+       case 2:
+               vup[0] = 1;
+               break;
+       }
+
+       v = DotProduct( vup, normal );
+       VectorMA( vup, -v, normal, vup );
+       VectorNormalize( vup, vup );
+
+       VectorScale( normal, dist, org );
+
+       CrossProduct( vup, normal, vright );
+
+       VectorScale( vup, 8192, vup );
+       VectorScale( vright, 8192, vright );
+
+// project a really big        axis aligned box onto the plane
+       w = AllocWinding( 4 );
+
+       VectorSubtract( org, vright, w->p[0] );
+       VectorAdd( w->p[0], vup, w->p[0] );
+
+       VectorAdd( org, vright, w->p[1] );
+       VectorAdd( w->p[1], vup, w->p[1] );
+
+       VectorAdd( org, vright, w->p[2] );
+       VectorSubtract( w->p[2], vup, w->p[2] );
+
+       VectorSubtract( org, vright, w->p[3] );
+       VectorSubtract( w->p[3], vup, w->p[3] );
+
+       w->numpoints = 4;
+
+       return w;
+}
+
+/*
+   ==================
+   CopyWinding
+   ==================
+ */
+winding_t   *CopyWinding( winding_t *w ){
+       int size;
+       winding_t   *c;
+
+       c = AllocWinding( w->numpoints );
+       size = (int)( (winding_t *)0 )->p[w->numpoints];
+       memcpy( c, w, size );
+       return c;
+}
+
+/*
+   ==================
+   ReverseWinding
+   ==================
+ */
+winding_t   *ReverseWinding( winding_t *w ){
+       int i;
+       winding_t   *c;
+
+       c = AllocWinding( w->numpoints );
+       for ( i = 0 ; i < w->numpoints ; i++ )
+       {
+               VectorCopy( w->p[w->numpoints - 1 - i], c->p[i] );
+       }
+       c->numpoints = w->numpoints;
+       return c;
+}
+
+
+/*
+   =============
+   ClipWindingEpsilon
+   =============
+ */
+void    ClipWindingEpsilon( winding_t *in, vec3_t normal, vec_t dist,
+                                                       vec_t epsilon, winding_t **front, winding_t **back ){
+       vec_t dists[MAX_POINTS_ON_WINDING + 4];
+       int sides[MAX_POINTS_ON_WINDING + 4];
+       int counts[3];
+       vec_t dot;          // VC 4.2 optimizer bug if not static
+       int i, j;
+       vec_t   *p1, *p2;
+       vec3_t mid;
+       winding_t   *f, *b;
+       int maxpts;
+
+       if ( in->numpoints >= MAX_POINTS_ON_WINDING - 4 ) {
+               Error( "ClipWinding: MAX_POINTS_ON_WINDING" );
+       }
+
+       counts[0] = counts[1] = counts[2] = 0;
+
+// determine sides for each point
+       for ( i = 0 ; i < in->numpoints ; i++ )
+       {
+               dot = DotProduct( in->p[i], normal );
+               dot -= dist;
+               dists[i] = dot;
+               if ( dot > epsilon ) {
+                       sides[i] = SIDE_FRONT;
+               }
+               else if ( dot < -epsilon ) {
+                       sides[i] = SIDE_BACK;
+               }
+               else
+               {
+                       sides[i] = SIDE_ON;
+               }
+               counts[sides[i]]++;
+       }
+       sides[i] = sides[0];
+       dists[i] = dists[0];
+
+       *front = *back = NULL;
+
+       if ( !counts[0] ) {
+               *back = CopyWinding( in );
+               return;
+       }
+       if ( !counts[1] ) {
+               *front = CopyWinding( in );
+               return;
+       }
+
+       maxpts = in->numpoints + 4;   // cant use counts[0]+2 because
+                                     // of fp grouping errors
+
+       *front = f = AllocWinding( maxpts );
+       *back = b = AllocWinding( maxpts );
+
+       for ( i = 0 ; i < in->numpoints ; i++ )
+       {
+               p1 = in->p[i];
+
+               if ( sides[i] == SIDE_ON ) {
+                       VectorCopy( p1, f->p[f->numpoints] );
+                       f->numpoints++;
+                       VectorCopy( p1, b->p[b->numpoints] );
+                       b->numpoints++;
+                       continue;
+               }
+
+               if ( sides[i] == SIDE_FRONT ) {
+                       VectorCopy( p1, f->p[f->numpoints] );
+                       f->numpoints++;
+               }
+               if ( sides[i] == SIDE_BACK ) {
+                       VectorCopy( p1, b->p[b->numpoints] );
+                       b->numpoints++;
+               }
+
+               if ( sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i] ) {
+                       continue;
+               }
+
+               // generate a split point
+               p2 = in->p[( i + 1 ) % in->numpoints];
+
+               dot = dists[i] / ( dists[i] - dists[i + 1] );
+               for ( j = 0 ; j < 3 ; j++ )
+               {   // avoid round off error when possible
+                       if ( normal[j] == 1 ) {
+                               mid[j] = dist;
+                       }
+                       else if ( normal[j] == -1 ) {
+                               mid[j] = -dist;
+                       }
+                       else{
+                               mid[j] = p1[j] + dot * ( p2[j] - p1[j] );
+                       }
+               }
+
+               VectorCopy( mid, f->p[f->numpoints] );
+               f->numpoints++;
+               VectorCopy( mid, b->p[b->numpoints] );
+               b->numpoints++;
+       }
+
+       if ( f->numpoints > maxpts || b->numpoints > maxpts ) {
+               Error( "ClipWinding: points exceeded estimate" );
+       }
+       if ( f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING ) {
+               Error( "ClipWinding: MAX_POINTS_ON_WINDING" );
+       }
+}
+
+
+/*
+   =============
+   ChopWindingInPlace
+   =============
+ */
+void ChopWindingInPlace( winding_t **inout, vec3_t normal, vec_t dist, vec_t epsilon ){
+       winding_t   *in;
+       vec_t dists[MAX_POINTS_ON_WINDING + 4];
+       int sides[MAX_POINTS_ON_WINDING + 4];
+       int counts[3];
+       vec_t dot;          // VC 4.2 optimizer bug if not static
+       int i, j;
+       vec_t   *p1, *p2;
+       vec3_t mid;
+       winding_t   *f;
+       int maxpts;
+
+       in = *inout;
+       counts[0] = counts[1] = counts[2] = 0;
+
+       if ( !in ) {
+               printf( "Warning: NULL passed to ChopWindingInPlace\n" );
+               return;
+       }
+       if ( in->numpoints >= MAX_POINTS_ON_WINDING - 4 ) {
+               Error( "ChopWinding: MAX_POINTS_ON_WINDING" );
+       }
+
+// determine sides for each point
+       for ( i = 0 ; i < in->numpoints ; i++ )
+       {
+               dot = DotProduct( in->p[i], normal );
+               dot -= dist;
+               dists[i] = dot;
+               if ( dot > epsilon ) {
+                       sides[i] = SIDE_FRONT;
+               }
+               else if ( dot < -epsilon ) {
+                       sides[i] = SIDE_BACK;
+               }
+               else
+               {
+                       sides[i] = SIDE_ON;
+               }
+               counts[sides[i]]++;
+       }
+       sides[i] = sides[0];
+       dists[i] = dists[0];
+
+       if ( !counts[0] ) {
+               FreeWinding( in );
+               *inout = NULL;
+               return;
+       }
+       if ( !counts[1] ) {
+               return;     // inout stays the same
+
+       }
+       maxpts = in->numpoints + 4;   // cant use counts[0]+2 because
+                                     // of fp grouping errors
+
+       f = AllocWinding( maxpts );
+
+       for ( i = 0 ; i < in->numpoints ; i++ )
+       {
+               p1 = in->p[i];
+
+               if ( sides[i] == SIDE_ON ) {
+                       VectorCopy( p1, f->p[f->numpoints] );
+                       f->numpoints++;
+                       continue;
+               }
+
+               if ( sides[i] == SIDE_FRONT ) {
+                       VectorCopy( p1, f->p[f->numpoints] );
+                       f->numpoints++;
+               }
+
+               if ( sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i] ) {
+                       continue;
+               }
+
+               // generate a split point
+               p2 = in->p[( i + 1 ) % in->numpoints];
+
+               dot = dists[i] / ( dists[i] - dists[i + 1] );
+               for ( j = 0 ; j < 3 ; j++ )
+               {   // avoid round off error when possible
+                       if ( normal[j] == 1 ) {
+                               mid[j] = dist;
+                       }
+                       else if ( normal[j] == -1 ) {
+                               mid[j] = -dist;
+                       }
+                       else{
+                               mid[j] = p1[j] + dot * ( p2[j] - p1[j] );
+                       }
+               }
+
+               VectorCopy( mid, f->p[f->numpoints] );
+               f->numpoints++;
+       }
+
+       if ( f->numpoints > maxpts ) {
+               Error( "ClipWinding: points exceeded estimate" );
+       }
+       if ( f->numpoints > MAX_POINTS_ON_WINDING ) {
+               Error( "ClipWinding: MAX_POINTS_ON_WINDING" );
+       }
+
+       FreeWinding( in );
+       *inout = f;
+}
+
+
+/*
+   =================
+   ChopWinding
+
+   Returns the fragment of in that is on the front side
+   of the cliping plane.  The original is freed.
+   =================
+ */
+winding_t   *ChopWinding( winding_t *in, vec3_t normal, vec_t dist ){
+       winding_t   *f, *b;
+
+       ClipWindingEpsilon( in, normal, dist, ON_EPSILON, &f, &b );
+       FreeWinding( in );
+       if ( b ) {
+               FreeWinding( b );
+       }
+       return f;
+}
+
+
+/*
+   =================
+   CheckWinding
+
+   =================
+ */
+void CheckWinding( winding_t *w ){
+       int i, j;
+       vec_t   *p1, *p2;
+       vec_t d, edgedist;
+       vec3_t dir, edgenormal, facenormal;
+       vec_t area;
+       vec_t facedist;
+
+       if ( w->numpoints < 3 ) {
+               Error( "CheckWinding: %i points",w->numpoints );
+       }
+
+       area = WindingArea( w );
+       if ( area < 1 ) {
+               Error( "CheckWinding: %f area", area );
+       }
+
+       WindingPlane( w, facenormal, &facedist );
+
+       for ( i = 0 ; i < w->numpoints ; i++ )
+       {
+               p1 = w->p[i];
+
+               for ( j = 0 ; j < 3 ; j++ )
+                       if ( p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE ) {
+                               Error( "CheckFace: BUGUS_RANGE: %f",p1[j] );
+                       }
+
+               j = i + 1 == w->numpoints ? 0 : i + 1;
+
+               // check the point is on the face plane
+               d = DotProduct( p1, facenormal ) - facedist;
+               if ( d < -ON_EPSILON || d > ON_EPSILON ) {
+                       Error( "CheckWinding: point off plane" );
+               }
+
+               // check the edge isnt degenerate
+               p2 = w->p[j];
+               VectorSubtract( p2, p1, dir );
+
+               if ( VectorLength( dir ) < ON_EPSILON ) {
+                       Error( "CheckWinding: degenerate edge" );
+               }
+
+               CrossProduct( facenormal, dir, edgenormal );
+               VectorNormalize( edgenormal, edgenormal );
+               edgedist = DotProduct( p1, edgenormal );
+               edgedist += ON_EPSILON;
+
+               // all other points must be on front side
+               for ( j = 0 ; j < w->numpoints ; j++ )
+               {
+                       if ( j == i ) {
+                               continue;
+                       }
+                       d = DotProduct( w->p[j], edgenormal );
+                       if ( d > edgedist ) {
+                               Error( "CheckWinding: non-convex" );
+                       }
+               }
+       }
+}
+
+
+/*
+   ============
+   WindingOnPlaneSide
+   ============
+ */
+int     WindingOnPlaneSide( winding_t *w, vec3_t normal, vec_t dist ){
+       qboolean front, back;
+       int i;
+       vec_t d;
+
+       front = false;
+       back = false;
+       for ( i = 0 ; i < w->numpoints ; i++ )
+       {
+               d = DotProduct( w->p[i], normal ) - dist;
+               if ( d < -ON_EPSILON ) {
+                       if ( front ) {
+                               return SIDE_CROSS;
+                       }
+                       back = true;
+                       continue;
+               }
+               if ( d > ON_EPSILON ) {
+                       if ( back ) {
+                               return SIDE_CROSS;
+                       }
+                       front = true;
+                       continue;
+               }
+       }
+
+       if ( back ) {
+               return SIDE_BACK;
+       }
+       if ( front ) {
+               return SIDE_FRONT;
+       }
+       return SIDE_ON;
+}
diff --git a/tools/heretic2/common/polylib.h b/tools/heretic2/common/polylib.h
new file mode 100644 (file)
index 0000000..00b7b39
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+
+typedef struct
+{
+       int numpoints;
+       vec3_t p[4];        // variable sized
+} winding_t;
+
+#define MAX_POINTS_ON_WINDING   64
+
+// you can define on_epsilon in the makefile as tighter
+#ifndef ON_EPSILON
+#define ON_EPSILON  0.1
+#endif
+
+winding_t   *AllocWinding( int points );
+vec_t   WindingArea( winding_t *w );
+void    WindingCenter( winding_t *w, vec3_t center );
+void    ClipWindingEpsilon( winding_t *in, vec3_t normal, vec_t dist,
+                                                       vec_t epsilon, winding_t **front, winding_t **back );
+winding_t   *ChopWinding( winding_t *in, vec3_t normal, vec_t dist );
+winding_t   *CopyWinding( winding_t *w );
+winding_t   *ReverseWinding( winding_t *w );
+winding_t   *BaseWindingForPlane( vec3_t normal, vec_t dist );
+void    CheckWinding( winding_t *w );
+void    WindingPlane( winding_t *w, vec3_t normal, vec_t *dist );
+void    RemoveColinearPoints( winding_t *w );
+int     WindingOnPlaneSide( winding_t *w, vec3_t normal, vec_t dist );
+void    FreeWinding( winding_t *w );
+void    WindingBounds( winding_t *w, vec3_t mins, vec3_t maxs );
+
+void    ChopWindingInPlace( winding_t **w, vec3_t normal, vec_t dist, vec_t epsilon );
+// frees the original if clipped
+
+void pw( winding_t *w );
diff --git a/tools/heretic2/common/qfiles.c b/tools/heretic2/common/qfiles.c
new file mode 100644 (file)
index 0000000..53452f3
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "qfiles.h"
+#include "scriplib.h"
+//#include <windows.h>
+
+materialtype_t defaultmaterialtypes[] =
+{
+       {"gravel",  MATERIAL_GRAVEL},
+       {"metal",   MATERIAL_METAL},
+       {"stone",   MATERIAL_STONE},
+       {"wood",    MATERIAL_WOOD},
+       {NULL,      0}
+};
+
+materialtype_t  *materialtypes;
+
+void QFile_ReadMaterialTypes( char* filename ){
+       int i;
+       FILE    *f;
+
+       f = fopen( filename, "rb" );
+       if ( !f ) {
+               materialtypes = defaultmaterialtypes;
+               return;
+       }
+       fclose( f );
+
+       free( materialtypes );
+       materialtypes = (materialtype_t*)malloc( 256 * sizeof( materialtype_t ) );
+
+       LoadScriptFile( filename );
+       i = 0;
+
+       while ( i < 255 )
+       {
+               GetScriptToken( true );
+               if ( endofscript ) {
+                       break;
+               }
+               if ( strcmp( token, "material" ) != 0 ) {
+                       while ( ScriptTokenAvailable() )
+                       {
+                               GetScriptToken( false );
+                       }
+               }
+               else
+               {
+                       GetScriptToken( false );
+                       materialtypes[i].name = (char*)malloc( strlen( token ) + 1 );
+                       strcpy( materialtypes[i].name, token );
+                       GetScriptToken( false );
+                       materialtypes[i].value = atoi( token );
+               }
+               i++;
+       }
+       materialtypes[i].name = NULL;
+       materialtypes[i].value = 0;
+}
diff --git a/tools/heretic2/common/qfiles.h b/tools/heretic2/common/qfiles.h
new file mode 100644 (file)
index 0000000..bee4b4f
--- /dev/null
@@ -0,0 +1,619 @@
+/*
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef _QFILES_H
+#define _QFILES_H
+
+#include "q_typedef.h"
+
+//
+// qfiles.h: quake file formats
+// This file must be identical in the quake and utils directories
+//
+
+/*
+   ========================================================================
+
+   The .pak files are just a linear collapse of a directory tree
+
+   ========================================================================
+ */
+
+#define IDPAKHEADER     ( ( 'K' << 24 ) + ( 'C' << 16 ) + ( 'A' << 8 ) + 'P' )
+
+typedef struct
+{
+       char name[56];
+       int filepos, filelen;
+} dpackfile_t;
+
+typedef struct
+{
+       int ident;          // == IDPAKHEADER
+       int dirofs;
+       int dirlen;
+} dpackheader_t;
+
+#define MAX_FILES_IN_PACK   4096
+
+
+/*
+   ========================================================================
+
+   PCX files are used for as many images as possible
+
+   ========================================================================
+ */
+
+typedef struct
+{
+       char manufacturer;
+       char version;
+       char encoding;
+       char bits_per_pixel;
+       unsigned short xmin,ymin,xmax,ymax;
+       unsigned short hres,vres;
+       unsigned char palette[48];
+       char reserved;
+       char color_planes;
+       unsigned short bytes_per_line;
+       unsigned short palette_type;
+       char filler[58];
+       unsigned char data;             // unbounded
+} pcx_t;
+
+
+/*
+   ========================================================================
+
+   .MD2 compressed triangle model file format
+
+   ========================================================================
+ */
+#define IDJOINTEDALIASHEADER    ( ( '2' << 24 ) + ( 'J' << 16 ) + ( 'D' << 8 ) + 'I' )
+
+/*
+   ========================================================================
+
+   .MD2 triangle model file format
+
+   ========================================================================
+ */
+
+#define IDALIASHEADER       ( ( '2' << 24 ) + ( 'P' << 16 ) + ( 'D' << 8 ) + 'I' )
+#define ALIAS_VERSION   8
+
+#define MAX_TRIANGLES   2048
+#define MAX_VERTS       2048
+#define MAX_FRAMES      512
+#define MAX_MD2SKINS    64
+#define MAX_SKINNAME    64
+
+typedef struct
+{
+       short s;
+       short t;
+} dstvert_t;
+
+typedef struct
+{
+       short index_xyz[3];
+       short index_st[3];
+} dtriangle_t;
+
+typedef struct
+{
+       byte v[3];              // scaled byte to fit in frame mins/maxs
+       byte lightnormalindex;
+} dtrivertx_t;
+
+#define DTRIVERTX_V0   0
+#define DTRIVERTX_V1   1
+#define DTRIVERTX_V2   2
+#define DTRIVERTX_LNI  3
+#define DTRIVERTX_SIZE 4
+
+typedef struct
+{
+       float scale[3];         // multiply byte verts by this
+       float translate[3];         // then add this
+       char name[16];          // frame name from grabbing
+       dtrivertx_t verts[1];   // variable sized
+} daliasframe_t;
+
+
+// the glcmd format:
+// a positive integer starts a tristrip command, followed by that many
+// vertex structures.
+// a negative integer starts a trifan command, followed by -x vertexes
+// a zero indicates the end of the command list.
+// a vertex consists of a floating point s, a floating point t,
+// and an integer vertex index.
+
+
+typedef struct
+{
+       int ident;
+       int version;
+
+       int skinwidth;
+       int skinheight;
+       int framesize;              // byte size of each frame
+
+       int num_skins;
+       int num_xyz;
+       int num_st;                 // greater than num_xyz for seams
+       int num_tris;
+       int num_glcmds;             // dwords in strip/fan command list
+       int num_frames;
+
+       int ofs_skins;              // each skin is a MAX_SKINNAME string
+       int ofs_st;                 // byte offset from start for stverts
+       int ofs_tris;               // offset for dtriangles
+       int ofs_frames;             // offset for first frame
+       int ofs_glcmds;
+       int ofs_end;                // end of file
+
+} dmdl_t;
+
+/*
+   ========================================================================
+
+   .BK file format
+
+   ========================================================================
+ */
+
+#define IDBOOKHEADER    ( ( 'K' << 24 ) + ( 'O' << 16 ) + ( 'O' << 8 ) + 'B' )
+#define BOOK_VERSION    2
+
+typedef struct bookframe_s
+{
+       int x;
+       int y;
+       int w;
+       int h;
+       char name[MAX_SKINNAME];            // name of gfx file
+} bookframe_t;
+
+typedef struct bookheader_s
+{
+       unsigned int ident;
+       unsigned int version;
+       int num_segments;
+       int total_w;
+       int total_h;
+} bookheader_t;
+
+typedef struct book_s
+{
+       bookheader_t bheader;
+       bookframe_t bframes[MAX_MD2SKINS];
+} book_t;
+
+/*
+   ========================================================================
+
+   .SP2 sprite file format
+
+   ========================================================================
+ */
+
+#define IDSPRITEHEADER  ( ( '2' << 24 ) + ( 'S' << 16 ) + ( 'D' << 8 ) + 'I' )
+// little-endian "IDS2"
+#define SPRITE_VERSION  2
+
+typedef struct
+{
+       int width, height;
+       int origin_x, origin_y;         // raster coordinates inside pic
+       char name[MAX_SKINNAME];        // name of pcx file
+} dsprframe_t;
+
+typedef struct {
+       int ident;
+       int version;
+       int numframes;
+       dsprframe_t frames[1];          // variable sized
+} dsprite_t;
+
+/*
+   ==============================================================================
+
+   .M8 texture file format
+
+   ==============================================================================
+ */
+
+typedef struct palette_s
+{
+       union
+       {
+               struct
+               {
+                       byte r,g,b;
+               };
+       };
+} palette_t;
+
+#define MIP_VERSION     2
+#define PAL_SIZE        256
+#define MIPLEVELS       16
+
+typedef struct miptex_s
+{
+       int version;
+       char name[32];
+       unsigned width[MIPLEVELS], height[MIPLEVELS];
+       unsigned offsets[MIPLEVELS];        // four mip maps stored
+       char animname[32];                  // next frame in animation chain
+       palette_t palette[PAL_SIZE];
+       int flags;
+       int contents;
+       int value;
+} miptex_t;
+
+
+#define MIP32_VERSION   4
+
+#define MIP32_NOMIP_FLAG2           0x00000001
+#define MIP32_DETAILER_FLAG2        0x00000002
+
+typedef struct miptex32_s
+{
+       int version;
+       char name[128];
+       char altname[128];                  // texture substitution
+       char animname[128];                 // next frame in animation chain
+       char damagename[128];               // image that should be shown when damaged
+       unsigned width[MIPLEVELS], height[MIPLEVELS];
+       unsigned offsets[MIPLEVELS];
+       int flags;
+       int contents;
+       int value;
+       float scale_x, scale_y;
+       int mip_scale;
+
+       // detail texturing info
+       char dt_name[128];              // detailed texture name
+       float dt_scale_x, dt_scale_y;
+       float dt_u, dt_v;
+       float dt_alpha;
+       int dt_src_blend_mode, dt_dst_blend_mode;
+
+       int flags2;
+       int unused[19];                     // future expansion to maintain compatibility with h2
+} miptex32_t;
+
+
+
+/*
+   ==============================================================================
+
+   .BSP file format
+
+   ==============================================================================
+ */
+
+#define IDBSPHEADER ( ( 'P' << 24 ) + ( 'S' << 16 ) + ( 'B' << 8 ) + 'I' )
+// little-endian "IBSP"
+
+#define BSPVERSION  38
+
+
+// upper design bounds
+// leaffaces, leafbrushes, planes, and verts are still bounded by
+// 16 bit short limits
+#define MAX_MAP_MODELS      1024
+#define MAX_MAP_BRUSHES     8192
+#define MAX_MAP_ENTITIES    2048
+#define MAX_MAP_ENTSTRING   0x40000
+#define MAX_MAP_TEXINFO     8192
+
+#define MAX_MAP_AREAS       256
+#define MAX_MAP_AREAPORTALS 1024
+#define MAX_MAP_PLANES      65536
+#define MAX_MAP_NODES       65536
+#define MAX_MAP_BRUSHSIDES  65536
+#define MAX_MAP_LEAFS       65536
+#define MAX_MAP_VERTS       65536
+#define MAX_MAP_FACES       65536
+#define MAX_MAP_LEAFFACES   65536
+#define MAX_MAP_LEAFBRUSHES 65536
+#define MAX_MAP_PORTALS     65536
+#define MAX_MAP_EDGES       128000
+#define MAX_MAP_SURFEDGES   256000
+#define MAX_MAP_LIGHTING    0x200000
+#define MAX_MAP_VISIBILITY  0x180000
+
+// key / value pair sizes
+
+#define MAX_KEY     32
+#define MAX_VALUE   1024
+
+//=============================================================================
+
+typedef struct
+{
+       int fileofs, filelen;
+} lump_t;
+
+#define LUMP_ENTITIES       0
+#define LUMP_PLANES         1
+#define LUMP_VERTEXES       2
+#define LUMP_VISIBILITY     3
+#define LUMP_NODES          4
+#define LUMP_TEXINFO        5
+#define LUMP_FACES          6
+#define LUMP_LIGHTING       7
+#define LUMP_LEAFS          8
+#define LUMP_LEAFFACES      9
+#define LUMP_LEAFBRUSHES    10
+#define LUMP_EDGES          11
+#define LUMP_SURFEDGES      12
+#define LUMP_MODELS         13
+#define LUMP_BRUSHES        14
+#define LUMP_BRUSHSIDES     15
+#define LUMP_POP            16
+#define LUMP_AREAS          17
+#define LUMP_AREAPORTALS    18
+#define HEADER_LUMPS        19
+
+typedef struct
+{
+       int ident;
+       int version;
+       lump_t lumps[HEADER_LUMPS];
+} dheader_t;
+
+typedef struct
+{
+       float mins[3], maxs[3];
+       float origin[3];            // for sounds or lights
+       int headnode;
+       int firstface, numfaces;            // submodels just draw faces
+                                           // without walking the bsp tree
+} dmodel_t;
+
+
+typedef struct
+{
+       float point[3];
+} dvertex_t;
+
+
+// 0-2 are axial planes
+#define PLANE_X         0
+#define PLANE_Y         1
+#define PLANE_Z         2
+
+// 3-5 are non-axial planes snapped to the nearest
+#define PLANE_ANYX      3
+#define PLANE_ANYY      4
+#define PLANE_ANYZ      5
+
+// planes (x&~1) and (x&~1)+1 are allways opposites
+
+typedef struct
+{
+       float normal[3];
+       float dist;
+       int type;           // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
+} dplane_t;
+
+
+// contents flags are seperate bits
+// a given brush can contribute multiple content bits
+// multiple brushes can be in a single leaf
+
+// these definitions also need to be in q_shared.h!
+
+// lower bits are stronger, and will eat weaker brushes completely
+#define CONTENTS_SOLID          0x00000001      // an eye is never valid in a solid
+#define CONTENTS_WINDOW         0x00000002      // translucent, but not watery
+#define CONTENTS_PUSHPULL       0x00000004
+#define CONTENTS_LAVA           0x00000008
+#define CONTENTS_SLIME          0x00000010
+#define CONTENTS_WATER          0x00000020
+#define CONTENTS_MIST           0x00000040      // 64
+#define LAST_VISIBLE_CONTENTS   64              // this one worries me a bit JKH
+
+// remaining contents are non-visible, and don't eat brushes
+
+#define CONTENTS_AREAPORTAL     0x00008000
+
+#define CONTENTS_PLAYERCLIP     0x00010000
+#define CONTENTS_MONSTERCLIP    0x00020000
+
+// currents can be added to any other contents, and may be mixed
+#define CONTENTS_CURRENT_0      0x00040000
+#define CONTENTS_CURRENT_90     0x00080000
+#define CONTENTS_CURRENT_180    0x00100000
+#define CONTENTS_CURRENT_270    0x00200000
+#define CONTENTS_CURRENT_UP     0x00400000
+#define CONTENTS_CURRENT_DOWN   0x00800000
+
+#define CONTENTS_ORIGIN         0x01000000  // removed before bsping an entity
+
+#define CONTENTS_MONSTER        0x02000000  // should never be on a brush, only in game
+#define CONTENTS_DEADMONSTER    0x04000000
+#define CONTENTS_DETAIL         0x08000000  // brushes to be added after vis leafs
+#define CONTENTS_TRANSLUCENT    0x10000000  // auto set if any surface has trans
+#define CONTENTS_LADDER         0x20000000
+
+
+
+#define SURF_LIGHT              0x00000001      // value will hold the light strength
+
+#define SURF_SLICK              0x00000002      // effects game physics
+
+#define SURF_SKY                0x00000004      // don't draw, but add to skybox
+#define SURF_WARP               0x00000008      // turbulent water warp
+#define SURF_TRANS33            0x00000010
+#define SURF_TRANS66            0x00000020
+#define SURF_FLOWING            0x00000040  // scroll towards angle
+#define SURF_NODRAW             0x00000080  // don't bother referencing the texture
+
+#define SURF_HINT               0x00000100  // make a primary bsp splitter
+#define SURF_SKIP               0x00000200  // completely ignore, allowing non-closed brushes
+#define SURF_TALL_WALL          0x00000400  // face doesn't get broken up as normal
+
+#define SURF_ALPHA_TEXTURE      0x00000800  // texture has alpha in it, and should show through in bsp process
+#define SURF_ANIMSPEED          0x00001000      // value will hold the anim speed in fps
+
+#define SURF_UNDULATE           0x00002000  // rock surface up and down...
+#define SURF_SKYREFLECT         0x00004000  // liquid will somewhat reflect the sky - not quite finished....
+
+#define SURF_TYPE_GRAVEL        0x00000000
+#define SURF_TYPE_METAL         0x01000000
+#define SURF_TYPE_STONE         0x02000000
+#define SURF_TYPE_WOOD          0x03000000
+#define SURF_MATERIAL           0xFF000000
+
+
+
+typedef struct
+{
+       int planenum;
+       int children[2];            // negative numbers are -(leafs+1), not nodes
+       short mins[3];              // for frustom culling
+       short maxs[3];
+       unsigned short firstface;
+       unsigned short numfaces;    // counting both sides
+} dnode_t;
+
+
+typedef struct texinfo_s
+{
+       float vecs[2][4];           // [s/t][xyz offset]
+       int flags;                  // miptex flags + overrides
+       int value;                  // light emission, etc
+       char texture[32];           // texture name (textures/*.wal)
+       int nexttexinfo;            // for animations, -1 = end of chain
+} texinfo_t;
+
+
+// note that edge 0 is never used, because negative edge nums are used for
+// counterclockwise use of the edge in a face
+typedef struct
+{
+       unsigned short v[2];        // vertex numbers
+} dedge_t;
+
+#define MAXLIGHTMAPS    4
+typedef struct
+{
+       unsigned short planenum;
+       short side;
+
+       int firstedge;              // we must support > 64k edges
+       short numedges;
+       short texinfo;
+
+// lighting info
+       union {
+               byte styles[MAXLIGHTMAPS];
+               paletteRGBA_t lighting;
+       };
+       int lightofs;               // start of [numstyles*surfsize] samples
+} dface_t;
+
+typedef struct
+{
+       int contents;                       // OR of all brushes (not needed?)
+
+       short cluster;
+       short area;
+
+       short mins[3];                      // for frustum culling
+       short maxs[3];
+
+       unsigned short firstleafface;
+       unsigned short numleaffaces;
+
+       unsigned short firstleafbrush;
+       unsigned short numleafbrushes;
+} dleaf_t;
+
+typedef struct
+{
+       unsigned short planenum;        // facing out of the leaf
+       short texinfo;
+} dbrushside_t;
+
+typedef struct
+{
+       int firstside;
+       int numsides;
+       int contents;
+} dbrush_t;
+
+#define ANGLE_UP    -1
+#define ANGLE_DOWN  -2
+
+
+// the visibility lump consists of a header with a count, then
+// byte offsets for the PVS and PHS of each cluster, then the raw
+// compressed bit vectors
+#define DVIS_PVS    0
+#define DVIS_PHS    1
+typedef struct
+{
+       int numclusters;
+       int bitofs[8][2];           // bitofs[numclusters][2]
+} dvis_t;
+
+// each area has a list of portals that lead into other areas
+// when portals are closed, other areas may not be visible or
+// hearable even if the vis info says that it should be
+typedef struct
+{
+       int portalnum;
+       int otherarea;
+} dareaportal_t;
+
+
+typedef struct
+{
+       int numareaportals;
+       int firstareaportal;
+} darea_t;
+
+typedef struct
+{
+       char    *name;
+       int value;
+} materialtype_t;
+
+enum
+{
+       MATERIAL_GRAVEL,
+       MATERIAL_METAL,
+       MATERIAL_STONE,
+       MATERIAL_WOOD,
+};
+
+materialtype_t  *materialtypes;
+
+void QFile_ReadMaterialTypes( char* filename );
+
+
+#endif //_QFILES_H
diff --git a/tools/heretic2/common/scriplib.c b/tools/heretic2/common/scriplib.c
new file mode 100644 (file)
index 0000000..af5e571
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+// scriplib.c
+
+#include "cmdlib.h"
+#include "inout.h"
+#include "scriplib.h"
+
+/*
+   =============================================================================
+
+                        PARSING STUFF
+
+   =============================================================================
+ */
+
+typedef struct
+{
+       char filename[1024];
+       char    *buffer,*script_p,*end_p;
+       int line;
+} script_t;
+
+#define MAX_INCLUDES    8
+script_t scriptstack[MAX_INCLUDES];
+script_t    *script;
+int scriptline;
+
+char token[MAXTOKEN];
+qboolean endofscript;
+qboolean tokenready;                     // only true if UnGetScriptToken was just called
+
+/*
+   ==============
+   AddScriptToStack
+   ==============
+ */
+void AddScriptToStack( char *filename ){
+       int size;
+
+       script++;
+       if ( script == &scriptstack[MAX_INCLUDES] ) {
+               Error( "script file exceeded MAX_INCLUDES" );
+       }
+       strcpy( script->filename, ExpandPath( filename ) );
+
+       size = LoadFile( script->filename, (void **)&script->buffer );
+
+       printf( "entering %s\n", script->filename );
+
+       script->line = 1;
+
+       script->script_p = script->buffer;
+       script->end_p = script->buffer + size;
+}
+
+
+/*
+   ==============
+   LoadScriptFile
+   ==============
+ */
+void LoadScriptFile( char *filename ){
+       script = scriptstack;
+       AddScriptToStack( filename );
+
+       endofscript = false;
+       tokenready = false;
+}
+
+
+/*
+   ==============
+   ParseFromMemory
+   ==============
+ */
+void ParseFromMemory( char *buffer, int size ){
+       script = scriptstack;
+       script++;
+       if ( script == &scriptstack[MAX_INCLUDES] ) {
+               Error( "script file exceeded MAX_INCLUDES" );
+       }
+       strcpy( script->filename, "memory buffer" );
+
+       script->buffer = buffer;
+       script->line = 1;
+       script->script_p = script->buffer;
+       script->end_p = script->buffer + size;
+
+       endofscript = false;
+       tokenready = false;
+}
+
+
+/*
+   ==============
+   UnGetScriptToken
+
+   Signals that the current token was not used, and should be reported
+   for the next GetScriptToken.  Note that
+
+   GetScriptToken (true);
+   UnGetScriptToken ();
+   GetScriptToken (false);
+
+   could cross a line boundary.
+   ==============
+ */
+void UnGetScriptToken( void ){
+       tokenready = true;
+}
+
+
+qboolean EndOfScript( qboolean crossline ){
+       if ( !crossline ) {
+               Error( "Line %i is incomplete\n",scriptline );
+       }
+
+       if ( !strcmp( script->filename, "memory buffer" ) ) {
+               endofscript = true;
+               return false;
+       }
+
+       free( script->buffer );
+       if ( script == scriptstack + 1 ) {
+               endofscript = true;
+               return false;
+       }
+       script--;
+       scriptline = script->line;
+       printf( "returning to %s\n", script->filename );
+       return GetScriptToken( crossline );
+}
+
+/*
+   ==============
+   GetScriptToken
+   ==============
+ */
+qboolean GetScriptToken( qboolean crossline ){
+       char    *token_p;
+
+       if ( tokenready ) {                       // is a token allready waiting?
+               tokenready = false;
+               return true;
+       }
+
+       if ( script->script_p >= script->end_p ) {
+               return EndOfScript( crossline );
+       }
+
+//
+// skip space
+//
+skipspace:
+       while ( *script->script_p <= 32 )
+       {
+               if ( script->script_p >= script->end_p ) {
+                       return EndOfScript( crossline );
+               }
+               if ( *script->script_p++ == '\n' ) {
+                       if ( !crossline ) {
+                               Error( "Line %i is incomplete\n",scriptline );
+                       }
+                       scriptline = script->line++;
+               }
+       }
+
+       if ( script->script_p >= script->end_p ) {
+               return EndOfScript( crossline );
+       }
+
+       // ; # // comments
+       if ( *script->script_p == ';' || *script->script_p == '#'
+                || ( script->script_p[0] == '/' && script->script_p[1] == '/' ) ) {
+               if ( !crossline ) {
+                       Error( "Line %i is incomplete\n",scriptline );
+               }
+               while ( *script->script_p++ != '\n' )
+                       if ( script->script_p >= script->end_p ) {
+                               return EndOfScript( crossline );
+                       }
+               goto skipspace;
+       }
+
+       // /* */ comments
+       if ( script->script_p[0] == '/' && script->script_p[1] == '*' ) {
+               if ( !crossline ) {
+                       Error( "Line %i is incomplete\n",scriptline );
+               }
+               script->script_p += 2;
+               while ( script->script_p[0] != '*' && script->script_p[1] != '/' )
+               {
+                       script->script_p++;
+                       if ( script->script_p >= script->end_p ) {
+                               return EndOfScript( crossline );
+                       }
+               }
+               script->script_p += 2;
+               goto skipspace;
+       }
+
+//
+// copy token
+//
+       token_p = token;
+
+       if ( *script->script_p == '"' ) {
+               // quoted token
+               script->script_p++;
+               while ( *script->script_p != '"' )
+               {
+                       *token_p++ = *script->script_p++;
+                       if ( script->script_p == script->end_p ) {
+                               break;
+                       }
+                       if ( token_p == &token[MAXTOKEN] ) {
+                               Error( "Token too large on line %i\n",scriptline );
+                       }
+               }
+               script->script_p++;
+       }
+       else{   // regular token
+               while ( *script->script_p > 32 && *script->script_p != ';' )
+               {
+                       *token_p++ = *script->script_p++;
+                       if ( script->script_p == script->end_p ) {
+                               break;
+                       }
+                       if ( token_p == &token[MAXTOKEN] ) {
+                               Error( "Token too large on line %i\n",scriptline );
+                       }
+               }
+       }
+
+       *token_p = 0;
+
+       if ( !strcmp( token, "$include" ) ) {
+               GetScriptToken( false );
+               AddScriptToStack( token );
+               return GetScriptToken( crossline );
+       }
+
+       return true;
+}
+
+
+/*
+   ==============
+   ScriptTokenAvailable
+
+   Returns true if there is another token on the line
+   ==============
+ */
+qboolean ScriptTokenAvailable( void ){
+       char    *search_p;
+
+       search_p = script->script_p;
+
+       if ( search_p >= script->end_p ) {
+               return false;
+       }
+
+       while ( *search_p <= 32 )
+       {
+               if ( *search_p == '\n' ) {
+                       return false;
+               }
+               search_p++;
+               if ( search_p == script->end_p ) {
+                       return false;
+               }
+
+       }
+
+       if ( *search_p == ';' ) {
+               return false;
+       }
+
+       return true;
+}
diff --git a/tools/heretic2/common/scriplib.h b/tools/heretic2/common/scriplib.h
new file mode 100644 (file)
index 0000000..8c441c8
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+// scriplib.h
+
+#ifndef __CMDLIB__
+#include "cmdlib.h"
+#endif
+
+#define MAXTOKEN    1024
+
+extern char token[MAXTOKEN];
+extern char    *scriptbuffer,*script_p,*scriptend_p;
+extern int grabbed;
+extern int scriptline;
+extern qboolean endofscript;
+
+
+void LoadScriptFile( char *filename );
+void ParseFromMemory( char *buffer, int size );
+
+qboolean GetScriptToken( qboolean crossline );
+void UnGetScriptToken( void );
+qboolean ScriptTokenAvailable( void );
diff --git a/tools/heretic2/common/threads.c b/tools/heretic2/common/threads.c
new file mode 100644 (file)
index 0000000..239226b
--- /dev/null
@@ -0,0 +1,606 @@
+/*
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "globaldefs.h"
+
+#if !GDEF_OS_WINDOWS
+// The below define is necessary to use
+// pthreads extensions like pthread_mutexattr_settype
+#define _GNU_SOURCE
+#endif // !GDEF_OS_WINDOWS
+
+#include "cmdlib.h"
+#include "mathlib.h"
+#include "inout.h"
+#include "her2_threads.h"
+
+#define MAX_THREADS 64
+
+int dispatch;
+int workcount;
+int oldf;
+qboolean pacifier;
+
+qboolean threaded;
+
+/*
+   =============
+   GetThreadWork
+
+   =============
+ */
+int GetThreadWork( void ){
+       int r;
+       int f;
+
+       ThreadLock();
+
+       if ( dispatch == workcount ) {
+               ThreadUnlock();
+               return -1;
+       }
+
+       f = 10 * dispatch / workcount;
+       if ( f != oldf ) {
+               oldf = f;
+               if ( pacifier ) {
+                       Sys_Printf( "%i...", f );
+                       fflush( stdout );   /* ydnar */
+               }
+       }
+
+       r = dispatch;
+       dispatch++;
+       ThreadUnlock();
+
+       return r;
+}
+
+
+void ( *workfunction )( int );
+
+void ThreadWorkerFunction( int threadnum ){
+       int work;
+
+       while ( 1 )
+       {
+               work = GetThreadWork();
+               if ( work == -1 ) {
+                       break;
+               }
+               //Sys_Printf ("thread %i, work %i\n", threadnum, work);
+               workfunction( work );
+       }
+}
+
+void RunThreadsOnIndividual( int workcnt, qboolean showpacifier, void ( *func )( int ) ){
+       if ( numthreads == -1 ) {
+               ThreadSetDefault();
+       }
+       workfunction = func;
+       RunThreadsOn( workcnt, showpacifier, ThreadWorkerFunction );
+}
+
+
+#if GDEF_OS_WINDOWS
+
+/*
+   ===================================================================
+
+   WIN32
+
+   ===================================================================
+ */
+
+#include <windows.h>
+
+// Setting default Threads to 1
+int numthreads = 1;
+CRITICAL_SECTION crit;
+static int enter;
+
+void ThreadSetDefault( void ){
+       SYSTEM_INFO info;
+
+       if ( numthreads == -1 ) { // not set manually
+               GetSystemInfo( &info );
+               numthreads = info.dwNumberOfProcessors;
+               if ( numthreads < 1 || numthreads > 32 ) {
+                       numthreads = 1;
+               }
+       }
+
+       Sys_Printf( "%i threads\n", numthreads );
+}
+
+
+void ThreadLock( void ){
+       if ( !threaded ) {
+               return;
+       }
+       EnterCriticalSection( &crit );
+       if ( enter ) {
+               Error( "Recursive ThreadLock\n" );
+       }
+       enter = 1;
+}
+
+void ThreadUnlock( void ){
+       if ( !threaded ) {
+               return;
+       }
+       if ( !enter ) {
+               Error( "ThreadUnlock without lock\n" );
+       }
+       enter = 0;
+       LeaveCriticalSection( &crit );
+}
+
+/*
+   =============
+   RunThreadsOn
+   =============
+ */
+void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) ){
+       int threadid[MAX_THREADS];
+       HANDLE threadhandle[MAX_THREADS];
+       int i;
+       int start, end;
+
+       start = I_FloatTime();
+       dispatch = 0;
+       workcount = workcnt;
+       oldf = -1;
+       pacifier = showpacifier;
+       threaded = true;
+
+       //
+       // run threads in parallel
+       //
+       InitializeCriticalSection( &crit );
+
+       if ( numthreads == 1 ) { // use same thread
+               func( 0 );
+       }
+       else
+       {
+               for ( i = 0 ; i < numthreads ; i++ )
+               {
+                       threadhandle[i] = CreateThread(
+                               NULL,   // LPSECURITY_ATTRIBUTES lpsa,
+                           //0,                // DWORD cbStack,
+
+                           /* ydnar: cranking stack size to eliminate radiosity crash with 1MB stack on win32 */
+                               ( 4096 * 1024 ),
+
+                               (LPTHREAD_START_ROUTINE)func,   // LPTHREAD_START_ROUTINE lpStartAddr,
+                               (LPVOID)i,  // LPVOID lpvThreadParm,
+                               0,          //   DWORD fdwCreate,
+                               &threadid[i] );
+               }
+
+               for ( i = 0 ; i < numthreads ; i++ )
+                       WaitForSingleObject( threadhandle[i], INFINITE );
+       }
+       DeleteCriticalSection( &crit );
+
+       threaded = false;
+       end = I_FloatTime();
+       if ( pacifier ) {
+               Sys_Printf( " (%i)\n", end - start );
+       }
+}
+
+
+#elif GDEF_OS_OSF1
+
+/*
+   ===================================================================
+
+   OSF1
+
+   ===================================================================
+ */
+
+int numthreads = 4;
+
+void ThreadSetDefault( void ){
+       if ( numthreads == -1 ) { // not set manually
+               numthreads = 4;
+       }
+}
+
+
+#include <pthread.h>
+
+pthread_mutex_t *my_mutex;
+
+void ThreadLock( void ){
+       if ( my_mutex ) {
+               pthread_mutex_lock( my_mutex );
+       }
+}
+
+void ThreadUnlock( void ){
+       if ( my_mutex ) {
+               pthread_mutex_unlock( my_mutex );
+       }
+}
+
+
+/*
+   =============
+   RunThreadsOn
+   =============
+ */
+void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) ){
+       int i;
+       pthread_t work_threads[MAX_THREADS];
+       pthread_addr_t status;
+       pthread_attr_t attrib;
+       pthread_mutexattr_t mattrib;
+       int start, end;
+
+       start = I_FloatTime();
+       dispatch = 0;
+       workcount = workcnt;
+       oldf = -1;
+       pacifier = showpacifier;
+       threaded = true;
+
+       if ( pacifier ) {
+               setbuf( stdout, NULL );
+       }
+
+       if ( !my_mutex ) {
+               my_mutex = safe_malloc( sizeof( *my_mutex ) );
+               if ( pthread_mutexattr_create( &mattrib ) == -1 ) {
+                       Error( "pthread_mutex_attr_create failed" );
+               }
+               if ( pthread_mutexattr_setkind_np( &mattrib, MUTEX_FAST_NP ) == -1 ) {
+                       Error( "pthread_mutexattr_setkind_np failed" );
+               }
+               if ( pthread_mutex_init( my_mutex, mattrib ) == -1 ) {
+                       Error( "pthread_mutex_init failed" );
+               }
+       }
+
+       if ( pthread_attr_create( &attrib ) == -1 ) {
+               Error( "pthread_attr_create failed" );
+       }
+       if ( pthread_attr_setstacksize( &attrib, 0x100000 ) == -1 ) {
+               Error( "pthread_attr_setstacksize failed" );
+       }
+
+       for ( i = 0 ; i < numthreads ; i++ )
+       {
+               if ( pthread_create( &work_threads[i], attrib
+                                                        , (pthread_startroutine_t)func, (pthread_addr_t)i ) == -1 ) {
+                       Error( "pthread_create failed" );
+               }
+       }
+
+       for ( i = 0 ; i < numthreads ; i++ )
+       {
+               if ( pthread_join( work_threads[i], &status ) == -1 ) {
+                       Error( "pthread_join failed" );
+               }
+       }
+
+       threaded = false;
+
+       end = I_FloatTime();
+       if ( pacifier ) {
+               Sys_Printf( " (%i)\n", end - start );
+       }
+}
+
+
+#elif GDEF_OS_IRIX
+
+/*
+   ===================================================================
+
+   IRIX
+
+   ===================================================================
+ */
+
+#include <task.h>
+#include <abi_mutex.h>
+#include <sys/types.h>
+#include <sys/prctl.h>
+
+int numthreads = -1;
+abilock_t lck;
+
+void ThreadSetDefault( void ){
+       if ( numthreads == -1 ) {
+               numthreads = prctl( PR_MAXPPROCS );
+       }
+       Sys_Printf( "%i threads\n", numthreads );
+       usconfig( CONF_INITUSERS, numthreads );
+}
+
+
+void ThreadLock( void ){
+       spin_lock( &lck );
+}
+
+void ThreadUnlock( void ){
+       release_lock( &lck );
+}
+
+
+/*
+   =============
+   RunThreadsOn
+   =============
+ */
+void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) ){
+       int i;
+       int pid[MAX_THREADS];
+       int start, end;
+
+       start = I_FloatTime();
+       dispatch = 0;
+       workcount = workcnt;
+       oldf = -1;
+       pacifier = showpacifier;
+       threaded = true;
+
+       if ( pacifier ) {
+               setbuf( stdout, NULL );
+       }
+
+       init_lock( &lck );
+
+       for ( i = 0 ; i < numthreads - 1 ; i++ )
+       {
+               pid[i] = sprocsp( ( void ( * )( void *, size_t ) )func, PR_SALL, (void *)i
+                                                 , NULL, 0x200000 ); // 2 meg stacks
+               if ( pid[i] == -1 ) {
+                       perror( "sproc" );
+                       Error( "sproc failed" );
+               }
+       }
+
+       func( i );
+
+       for ( i = 0 ; i < numthreads - 1 ; i++ )
+               wait( NULL );
+
+       threaded = false;
+
+       end = I_FloatTime();
+       if ( pacifier ) {
+               Sys_Printf( " (%i)\n", end - start );
+       }
+}
+
+
+#elif GDEF_OS_LINUX || GDEF_OS_BSD || GDEF_OS_MACOS
+
+/*
+   =======================================================================
+
+   Linux pthreads
+
+   =======================================================================
+ */
+
+// Setting default Threads to 1
+int numthreads = 1;
+
+void ThreadSetDefault( void ){
+       if ( numthreads == -1 ) { // not set manually
+               /* default to one thread, only multi-thread when specifically told to */
+               numthreads = 1;
+       }
+       if ( numthreads > 1 ) {
+               Sys_Printf( "threads: %d\n", numthreads );
+       }
+}
+
+#include <pthread.h>
+
+typedef struct pt_mutex_s
+{
+       pthread_t       *owner;
+       pthread_mutex_t a_mutex;
+       pthread_cond_t cond;
+       unsigned int lock;
+} pt_mutex_t;
+
+pt_mutex_t global_lock;
+
+void ThreadLock( void ){
+       pt_mutex_t *pt_mutex = &global_lock;
+
+       if ( !threaded ) {
+               return;
+       }
+
+       pthread_mutex_lock( &pt_mutex->a_mutex );
+       if ( pthread_equal( pthread_self(), (pthread_t)&pt_mutex->owner ) ) {
+               pt_mutex->lock++;
+       }
+       else
+       {
+               if ( ( !pt_mutex->owner ) && ( pt_mutex->lock == 0 ) ) {
+                       pt_mutex->owner = (pthread_t *)pthread_self();
+                       pt_mutex->lock  = 1;
+               }
+               else
+               {
+                       while ( 1 )
+                       {
+                               pthread_cond_wait( &pt_mutex->cond, &pt_mutex->a_mutex );
+                               if ( ( !pt_mutex->owner ) && ( pt_mutex->lock == 0 ) ) {
+                                       pt_mutex->owner = (pthread_t *)pthread_self();
+                                       pt_mutex->lock  = 1;
+                                       break;
+                               }
+                       }
+               }
+       }
+       pthread_mutex_unlock( &pt_mutex->a_mutex );
+}
+
+void ThreadUnlock( void ){
+       pt_mutex_t *pt_mutex = &global_lock;
+
+       if ( !threaded ) {
+               return;
+       }
+
+       pthread_mutex_lock( &pt_mutex->a_mutex );
+       pt_mutex->lock--;
+
+       if ( pt_mutex->lock == 0 ) {
+               pt_mutex->owner = NULL;
+               pthread_cond_signal( &pt_mutex->cond );
+       }
+
+       pthread_mutex_unlock( &pt_mutex->a_mutex );
+}
+
+void recursive_mutex_init( pthread_mutexattr_t attribs ){
+       pt_mutex_t *pt_mutex = &global_lock;
+
+       pt_mutex->owner = NULL;
+       if ( pthread_mutex_init( &pt_mutex->a_mutex, &attribs ) != 0 ) {
+               Error( "pthread_mutex_init failed\n" );
+       }
+       if ( pthread_cond_init( &pt_mutex->cond, NULL ) != 0 ) {
+               Error( "pthread_cond_init failed\n" );
+       }
+
+       pt_mutex->lock = 0;
+}
+
+/*
+   =============
+   RunThreadsOn
+   =============
+ */
+void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) ){
+       pthread_mutexattr_t mattrib;
+       pthread_t work_threads[MAX_THREADS];
+
+       int start, end;
+       int i = 0, status = 0;
+
+       start     = I_FloatTime();
+       pacifier  = showpacifier;
+
+       dispatch  = 0;
+       oldf      = -1;
+       workcount = workcnt;
+
+       if ( numthreads == 1 ) {
+               func( 0 );
+       }
+       else
+       {
+               threaded  = true;
+
+               if ( pacifier ) {
+                       setbuf( stdout, NULL );
+               }
+
+               if ( pthread_mutexattr_init( &mattrib ) != 0 ) {
+                       Error( "pthread_mutexattr_init failed" );
+               }
+               if ( pthread_mutexattr_settype( &mattrib, PTHREAD_MUTEX_ERRORCHECK ) != 0 ) {
+                       Error( "pthread_mutexattr_settype failed" );
+               }
+               recursive_mutex_init( mattrib );
+
+               for ( i = 0 ; i < numthreads ; i++ )
+               {
+                       /* Default pthread attributes: joinable & non-realtime scheduling */
+                       if ( pthread_create( &work_threads[i], NULL, (void*)func, (void*)i ) != 0 ) {
+                               Error( "pthread_create failed" );
+                       }
+               }
+               for ( i = 0 ; i < numthreads ; i++ )
+               {
+                       if ( pthread_join( work_threads[i], (void **)&status ) != 0 ) {
+                               Error( "pthread_join failed" );
+                       }
+               }
+               pthread_mutexattr_destroy( &mattrib );
+               threaded = false;
+       }
+
+       end = I_FloatTime();
+       if ( pacifier ) {
+               Sys_Printf( " (%i)\n", end - start );
+       }
+}
+
+
+#else // UNKNOWN OS
+
+/*
+   =======================================================================
+
+   SINGLE THREAD
+
+   =======================================================================
+ */
+
+int numthreads = 1;
+
+void ThreadSetDefault( void ){
+       numthreads = 1;
+}
+
+void ThreadLock( void ){
+}
+
+void ThreadUnlock( void ){
+}
+
+/*
+   =============
+   RunThreadsOn
+   =============
+ */
+void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) ){
+       int i;
+       int start, end;
+
+       dispatch = 0;
+       workcount = workcnt;
+       oldf = -1;
+       pacifier = showpacifier;
+       start = I_FloatTime();
+       func( 0 );
+
+       end = I_FloatTime();
+       if ( pacifier ) {
+               Sys_Printf( " (%i)\n", end - start );
+       }
+}
+
+#endif // UNKNOWN OS
diff --git a/tools/heretic2/common/token.c b/tools/heretic2/common/token.c
new file mode 100644 (file)
index 0000000..632cfe4
--- /dev/null
@@ -0,0 +1,515 @@
+/*
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+
+//**************************************************************************
+//**
+//** token.c
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "token.h"
+#include "inout.h"
+
+// MACROS ------------------------------------------------------------------
+
+// TYPES -------------------------------------------------------------------
+
+typedef enum
+{
+       CHR_EOF,
+       CHR_LETTER,
+       CHR_NUMBER,
+       CHR_QUOTE,
+       CHR_SPECIAL
+} chr_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void ProcessLetterToken( void );
+static void ProcessNumberToken( void );
+static void ProcessQuoteToken( void );
+static void ProcessSpecialToken( void );
+static qboolean CheckForKeyword( void );
+static void NextChr( void );
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+tokenType_t tk_Token;
+int tk_Line;
+int tk_IntNumber;
+float tk_FloatNumber;
+char *tk_String;
+char tk_SourceName[MAX_FILE_NAME_LENGTH];
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static char Chr;
+static char *FileStart;
+static char *FilePtr;
+static char *FileEnd;
+static qboolean SourceOpen;
+static char ASCIIToChrCode[256];
+static char TokenStringBuffer[MAX_QUOTED_LENGTH];
+static qboolean IncLineNumber;
+static char TempBuffer[2048];
+
+static struct
+{
+       char *name;
+       tokenType_t token;
+} Keywords[] =
+{
+       "model",            TK_MODEL,
+       "mesh",             TK_MESH,
+       "vertices",         TK_VERTICES,
+       "edges",            TK_EDGES,
+       "position",         TK_POSITION,
+       "polygons",         TK_POLYGONS,
+       "nodes",            TK_NODES,
+       "rotation",         TK_ROTATION,
+       "scaling",          TK_SCALING,
+       "translation",      TK_TRANSLATION,
+       "vertex",           TK_VERTEX,
+       "HRCH",             TK_HRCH,
+       "Softimage",        TK_SOFTIMAGE,
+       "material",         TK_MATERIAL,
+       "spline",           TK_SPLINE,
+
+       "Named",            TK_C_NAMED,
+       "object",           TK_OBJECT,
+       "Tri",              TK_C_TRI,
+       "Vertices",         TK_C_VERTICES,
+       "Faces",            TK_C_FACES,
+       "Vertex",           TK_C_VERTEX,
+       "list",             TK_LIST,
+       "Face",             TK_C_FACE,
+
+       "Hexen",            TK_C_HEXEN,
+       "Triangles",        TK_C_TRIANGLES,
+       "Version",          TK_C_VERSION,
+       "faces",            TK_FACES,
+       "face",             TK_FACE,
+       "origin",           TK_ORIGIN,
+
+       "DK_clusters",      TK_CLUSTERS,
+       "DK_cluster_ncvs",  TK_NUM_CLUSTER_VERTICES,
+       "name",             TK_NAME,
+       "DK_cluster_name",  TK_CLUSTER_NAME,
+       "DK_cluster_state", TK_CLUSTER_STATE,
+
+       "actor_data",       TK_ACTOR_DATA,
+       "uvTexture",        TK_UVTEXTURE,
+
+       NULL,               -1
+};
+
+static char *TokenNames[] =
+{
+       "<nothing>",
+       "<unknown_char>",
+       "<EOF>",
+       "<identifier>",
+       "<string>",
+       "<int_number>",
+       "<float_number>",
+       "(",
+       ")",
+       "{",
+       "}",
+       "[",
+       "]",
+       ":",
+       "mesh",
+       "model",
+       "nodes",
+       "rotation",
+       "scaling",
+       "translation",
+       "polygons",
+       "position",
+       "vertex",
+       "vertices",
+       "HRCH",
+       "Softimage"
+};
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// TK_Init
+//
+//==========================================================================
+
+void TK_Init( void ){
+       int i;
+
+       for ( i = 0; i < 256; i++ )
+       {
+               ASCIIToChrCode[i] = CHR_SPECIAL;
+       }
+       for ( i = '0'; i <= '9'; i++ )
+       {
+               ASCIIToChrCode[i] = CHR_NUMBER;
+       }
+       for ( i = 'A'; i <= 'Z'; i++ )
+       {
+               ASCIIToChrCode[i] = CHR_LETTER;
+       }
+       for ( i = 'a'; i <= 'z'; i++ )
+       {
+               ASCIIToChrCode[i] = CHR_LETTER;
+       }
+       ASCIIToChrCode[ASCII_QUOTE] = CHR_QUOTE;
+       ASCIIToChrCode[ASCII_UNDERSCORE] = CHR_LETTER;
+       ASCIIToChrCode[EOF_CHARACTER] = CHR_EOF;
+       tk_String = TokenStringBuffer;
+       IncLineNumber = FALSE;
+       SourceOpen = FALSE;
+}
+
+//==========================================================================
+//
+// TK_OpenSource
+//
+//==========================================================================
+
+void TK_OpenSource( char *fileName ){
+       int size;
+
+       TK_CloseSource();
+       size = LoadFile( fileName, (void **)&FileStart );
+       strcpy( tk_SourceName, fileName );
+       SourceOpen = TRUE;
+       FileEnd = FileStart + size;
+       FilePtr = FileStart;
+       tk_Line = 1;
+       tk_Token = TK_NONE;
+       NextChr();
+}
+
+//==========================================================================
+//
+// TK_CloseSource
+//
+//==========================================================================
+
+void TK_CloseSource( void ){
+       if ( SourceOpen ) {
+               free( FileStart );
+               SourceOpen = FALSE;
+       }
+}
+
+//==========================================================================
+//
+// TK_Fetch
+//
+//==========================================================================
+
+tokenType_t TK_Fetch( void ){
+       while ( Chr == ASCII_SPACE )
+       {
+               NextChr();
+       }
+       if ( Chr == '-' ) {
+               ProcessNumberToken();
+       }
+       else{switch ( ASCIIToChrCode[(byte)Chr] )
+                {
+                case CHR_EOF:
+                        tk_Token = TK_EOF;
+                        break;
+                case CHR_LETTER:
+                        ProcessLetterToken();
+                        break;
+                case CHR_NUMBER:
+                        ProcessNumberToken();
+                        break;
+                case CHR_QUOTE:
+                        ProcessQuoteToken();
+                        break;
+                default:
+                        ProcessSpecialToken();
+                        break;
+                }}
+       return tk_Token;
+}
+
+//==========================================================================
+//
+// TK_Require
+//
+//==========================================================================
+
+void TK_Require( tokenType_t tokType ){
+       if ( tokType == TK_FLOATNUMBER && tk_Token == TK_INTNUMBER ) {
+               tk_FloatNumber = (float)tk_IntNumber;
+               tk_Token = TK_FLOATNUMBER;
+               return;
+       }
+       if ( tk_Token != tokType ) {
+               Error( "File '%s', line %d:\nExpected '%s', found '%s'.\n",
+                          tk_SourceName, tk_Line, TokenNames[tokType],
+                          TokenNames[tk_Token] );
+       }
+}
+
+void TK_FetchRequire( tokenType_t tokType ){
+       TK_Fetch();
+       TK_Require( tokType );
+}
+
+tokenType_t TK_RequireFetch( tokenType_t tokType ){
+       TK_Require( tokType );
+       return TK_Fetch();
+}
+
+tokenType_t TK_FetchRequireFetch( tokenType_t tokType ){
+       TK_Fetch();
+       TK_Require( tokType );
+       return TK_Fetch();
+}
+
+tokenType_t TK_Beyond( tokenType_t tokType ){
+       while ( tk_Token != tokType )
+       {
+               if ( TK_Fetch() == TK_EOF ) {
+                       Error( "File '%s':\nCould not find token '%s'.\n",       // FIXME: TokenNames table not big enuff
+                                  tk_SourceName, TokenNames[tokType] );
+               }
+       }
+       return TK_Fetch();
+}
+
+void TK_BeyondRequire( tokenType_t bTok, tokenType_t rTok ){
+       TK_Beyond( bTok );
+       TK_Require( rTok );
+}
+
+tokenType_t TK_Search( tokenType_t tokType ){
+       while ( tk_Token != tokType )
+       {
+               if ( TK_Fetch() == TK_EOF ) {
+                       return TK_EOF;
+               }
+       }
+       return TK_Fetch();
+}
+
+tokenType_t TK_Get( tokenType_t tokType ){
+       while ( tk_Token != tokType )
+       {
+               if ( TK_Fetch() == TK_EOF ) {
+                       Error( "File '%s':\nCould not find token '%s'.\n",
+                                  tk_SourceName, TokenNames[tokType] );
+               }
+       }
+       return tk_Token;
+}
+
+//==========================================================================
+//
+// ProcessLetterToken
+//
+//==========================================================================
+
+static void ProcessLetterToken( void ){
+       int i;
+       char *text;
+
+       i = 0;
+       text = TokenStringBuffer;
+       while ( ASCIIToChrCode[(byte)Chr] == CHR_LETTER
+                       || ASCIIToChrCode[(byte)Chr] == CHR_NUMBER )
+       {
+               if ( ++i == MAX_IDENTIFIER_LENGTH ) {
+                       Error( "File '%s', line %d:\nIdentifier too long.\n",
+                                  tk_SourceName, tk_Line );
+               }
+               *text++ = Chr;
+               NextChr();
+       }
+       *text = 0;
+       if ( CheckForKeyword() == FALSE ) {
+               tk_Token = TK_IDENTIFIER;
+       }
+}
+
+//==========================================================================
+//
+// CheckForKeyword
+//
+//==========================================================================
+
+static qboolean CheckForKeyword( void ){
+       int i;
+
+       for ( i = 0; Keywords[i].name != NULL; i++ )
+       {
+               if ( strcmp( tk_String, Keywords[i].name ) == 0 ) {
+                       tk_Token = Keywords[i].token;
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+//==========================================================================
+//
+// ProcessNumberToken
+//
+//==========================================================================
+
+static void ProcessNumberToken( void ){
+       char *buffer;
+
+       buffer = TempBuffer;
+       *buffer++ = Chr;
+       NextChr();
+       while ( ASCIIToChrCode[(byte)Chr] == CHR_NUMBER )
+       {
+               *buffer++ = Chr;
+               NextChr();
+       }
+       if ( Chr == '.' ) { // Float
+               *buffer++ = Chr;
+               NextChr(); // Skip period
+               while ( ASCIIToChrCode[(byte)Chr] == CHR_NUMBER )
+               {
+                       *buffer++ = Chr;
+                       NextChr();
+               }
+               *buffer = 0;
+               tk_FloatNumber = (float)atof( TempBuffer );
+               tk_Token = TK_FLOATNUMBER;
+               return;
+       }
+
+       // Integer
+       *buffer = 0;
+       tk_IntNumber = atoi( TempBuffer );
+       tk_Token = TK_INTNUMBER;
+}
+
+//==========================================================================
+//
+// ProcessQuoteToken
+//
+//==========================================================================
+
+static void ProcessQuoteToken( void ){
+       int i;
+       char *text;
+
+       i = 0;
+       text = TokenStringBuffer;
+       NextChr();
+       while ( Chr != ASCII_QUOTE )
+       {
+               if ( Chr == EOF_CHARACTER ) {
+                       Error( "File '%s', line %d:\n<EOF> inside string.\n",
+                                  tk_SourceName, tk_Line );
+               }
+               if ( ++i > MAX_QUOTED_LENGTH - 1 ) {
+                       Error( "File '%s', line %d:\nString literal too long.\n",
+                                  tk_SourceName, tk_Line );
+               }
+               *text++ = Chr;
+               NextChr();
+       }
+       *text = 0;
+       NextChr();
+       tk_Token = TK_STRING;
+}
+
+//==========================================================================
+//
+// ProcessSpecialToken
+//
+//==========================================================================
+
+static void ProcessSpecialToken( void ){
+       char c;
+
+       c = Chr;
+       NextChr();
+       switch ( c )
+       {
+       case '(':
+               tk_Token = TK_LPAREN;
+               break;
+       case ')':
+               tk_Token = TK_RPAREN;
+               break;
+       case '{':
+               tk_Token = TK_LBRACE;
+               break;
+       case '}':
+               tk_Token = TK_RBRACE;
+               break;
+       case '[':
+               tk_Token = TK_LBRACKET;
+               break;
+       case ']':
+               tk_Token = TK_RBRACKET;
+               break;
+       case ':':
+               tk_Token = TK_COLON;
+               break;
+       default:
+               tk_Token = TK_UNKNOWNCHAR;
+               break;
+       }
+}
+
+//==========================================================================
+//
+// NextChr
+//
+//==========================================================================
+
+static void NextChr( void ){
+       if ( FilePtr >= FileEnd ) {
+               Chr = EOF_CHARACTER;
+               return;
+       }
+       if ( IncLineNumber == TRUE ) {
+               tk_Line++;
+               IncLineNumber = FALSE;
+       }
+       Chr = *FilePtr++;
+       if ( Chr < ASCII_SPACE ) {
+               if ( Chr == '\n' ) {
+                       IncLineNumber = TRUE;
+               }
+               Chr = ASCII_SPACE;
+       }
+}
diff --git a/tools/heretic2/common/token.h b/tools/heretic2/common/token.h
new file mode 100644 (file)
index 0000000..6dca1a1
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+
+//**************************************************************************
+//**
+//** token.h
+//**
+//**************************************************************************
+
+#ifndef __TOKEN_H__
+#define __TOKEN_H__
+
+#include "cmdlib.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef YES
+#define YES 1
+#endif
+#ifndef NO
+#define NO 0
+#endif
+#define ASCII_SPACE 32
+#define ASCII_QUOTE 34
+#define ASCII_UNDERSCORE 95
+#define EOF_CHARACTER 127
+#define MAX_IDENTIFIER_LENGTH 64
+#define MAX_QUOTED_LENGTH 1024
+#define MAX_FILE_NAME_LENGTH 1024
+
+typedef enum
+{
+       TK_NONE,
+       TK_UNKNOWNCHAR,
+       TK_EOF,
+       TK_IDENTIFIER,          // VALUE: (char *) tk_String
+       TK_STRING,              // VALUE: (char *) tk_String
+       TK_INTNUMBER,           // VALUE: (int) tk_IntNumber
+       TK_FLOATNUMBER,         // VALUE: (float) tk_FloatNumber
+       TK_LPAREN,
+       TK_RPAREN,
+       TK_LBRACE,
+       TK_RBRACE,              // 10
+       TK_LBRACKET,
+       TK_RBRACKET,
+       TK_COLON,
+       TK_MESH,
+       TK_MODEL,               // 15
+       TK_NODES,
+       TK_ROTATION,
+       TK_SCALING,
+       TK_TRANSLATION,
+       TK_POLYGONS,            // 20
+       TK_POSITION,
+       TK_VERTEX,
+       TK_VERTICES,
+       TK_EDGES,
+       TK_HRCH,                // 25
+       TK_SOFTIMAGE,
+       TK_MATERIAL,
+       TK_SPLINE,              // 28
+
+       TK_C_NAMED,
+       TK_OBJECT,              // 30
+       TK_C_TRI,
+       TK_C_VERTICES,
+       TK_C_FACES,
+       TK_C_VERTEX,
+       TK_LIST,                // 35
+       TK_C_FACE,
+
+       TK_C_HEXEN,
+       TK_C_TRIANGLES,
+       TK_C_VERSION,
+       TK_FACES,               // 40
+       TK_FACE,
+       TK_ORIGIN,
+
+       TK_CLUSTERS,
+       TK_NUM_CLUSTER_VERTICES,
+       TK_NAME,                // 45
+       TK_CLUSTER_NAME,
+       TK_CLUSTER_STATE,
+
+       TK_ACTOR_DATA,
+       TK_UVTEXTURE,
+} tokenType_t;
+
+void TK_Init( void );
+void TK_OpenSource( char *fileName );
+void TK_CloseSource( void );
+tokenType_t TK_Fetch( void );
+void TK_Require( tokenType_t tokType );
+void TK_FetchRequire( tokenType_t tokType );
+tokenType_t TK_RequireFetch( tokenType_t tokType );
+tokenType_t TK_FetchRequireFetch( tokenType_t tokType );
+tokenType_t TK_Beyond( tokenType_t tokType );
+void TK_BeyondRequire( tokenType_t bTok, tokenType_t rTok );
+tokenType_t TK_Search( tokenType_t tokType );
+tokenType_t TK_Get( tokenType_t tokType );
+
+extern tokenType_t tk_Token;
+extern int tk_Line;
+extern int tk_IntNumber;
+extern float tk_FloatNumber;
+extern char *tk_String;
+extern char tk_SourceName[MAX_FILE_NAME_LENGTH];
+
+#endif
diff --git a/tools/heretic2/common/trilib.c b/tools/heretic2/common/trilib.c
new file mode 100644 (file)
index 0000000..29acab6
--- /dev/null
@@ -0,0 +1,1039 @@
+/*
+   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant 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.
+
+   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+//
+// trilib.c: library for loading triangles from an Alias triangle file
+//
+
+#include <stdio.h>
+#include "cmdlib.h"
+#include "inout.h"
+#include "mathlib.h"
+#include "trilib.h"
+#include "token.h"
+#include "l3dslib.h"
+#include "fmodel.h"
+#if 1
+#include "qd_skeletons.h"
+#endif
+
+// on disk representation of a face
+#define FLOAT_START 99999.0
+#define FLOAT_END   -FLOAT_START
+#define MAGIC       123322
+#ifndef M_PI
+  #define M_PI      3.14159265
+#endif
+
+float FixHTRRotateX = 0.0;
+float FixHTRRotateY = 0.0;
+float FixHTRRotateZ = 0.0;
+float FixHTRTranslateX = 0.0;
+float FixHTRTranslateY = 0.0;
+float FixHTRTranslateZ = 0.0;
+
+//#define NOISY 1
+
+typedef struct {
+       float v[3];
+} vector;
+
+typedef struct
+{
+       vector n;    /* normal */
+       vector p;    /* point */
+       vector c;    /* color */
+       float u;     /* u */
+       float v;     /* v */
+} aliaspoint_t;
+
+typedef struct {
+       aliaspoint_t pt[3];
+} tf_triangle;
+
+
+void ByteSwapTri( tf_triangle *tri ){
+       int i;
+
+       for ( i = 0 ; i < sizeof( tf_triangle ) / 4 ; i++ )
+       {
+               ( (int *)tri )[i] = BigLong( ( (int *)tri )[i] );
+       }
+}
+
+void LoadTRI( char *filename, triangle_t **pptri, int *numtriangles, mesh_node_t **nodesList, int *num_mesh_nodes ){
+       FILE        *input;
+       float start;
+       char name[256], tex[256];
+       int i, count, magic;
+       tf_triangle tri;
+       triangle_t  *ptri;
+       int iLevel;
+       int exitpattern;
+       float t;
+
+       if ( nodesList ) {
+               *num_mesh_nodes = 0;
+               *nodesList = (mesh_node_t *) SafeMalloc( MAX_FM_MESH_NODES * sizeof( mesh_node_t ), "Mesh Node List" );
+       }
+
+       t = -FLOAT_START;
+       *( (unsigned char *)&exitpattern + 0 ) = *( (unsigned char *)&t + 3 );
+       *( (unsigned char *)&exitpattern + 1 ) = *( (unsigned char *)&t + 2 );
+       *( (unsigned char *)&exitpattern + 2 ) = *( (unsigned char *)&t + 1 );
+       *( (unsigned char *)&exitpattern + 3 ) = *( (unsigned char *)&t + 0 );
+
+       if ( ( input = fopen( filename, "rb" ) ) == 0 ) {
+               Error( "reader: could not open file '%s'", filename );
+       }
+
+       iLevel = 0;
+
+       fread( &magic, sizeof( int ), 1, input );
+       if ( BigLong( magic ) != MAGIC ) {
+               Error( "%s is not a Alias object separated triangle file, magic number is wrong.", filename );
+       }
+
+       ptri = malloc( MAXTRIANGLES * sizeof( triangle_t ) );
+
+       *pptri = ptri;
+
+       while ( feof( input ) == 0 ) {
+               if ( fread( &start,  sizeof( float ), 1, input ) < 1 ) {
+                       break;
+               }
+               *(int *)&start = BigLong( *(int *)&start );
+               if ( *(int *)&start != exitpattern ) {
+                       if ( start == FLOAT_START ) {
+                               /* Start of an object or group of objects. */
+                               i = -1;
+                               do {
+                                       /* There are probably better ways to read a string from */
+                                       /* a file, but this does allow you to do error checking */
+                                       /* (which I'm not doing) on a per character basis.      */
+                                       ++i;
+                                       fread( &( name[i] ), sizeof( char ), 1, input );
+                               } while ( name[i] != '\0' );
+
+//                             indent();
+//                             fprintf(stdout,"OBJECT START: %s\n",name);
+                               fread( &count, sizeof( int ), 1, input );
+                               count = BigLong( count );
+                               ++iLevel;
+                               if ( count != 0 ) {
+//                                     indent();
+//                                     fprintf(stdout,"NUMBER OF TRIANGLES: %d\n",count);
+
+                                       i = -1;
+                                       do {
+                                               ++i;
+                                               fread( &( tex[i] ), sizeof( char ), 1, input );
+                                       } while ( tex[i] != '\0' );
+
+//                                     indent();
+//                                     fprintf(stdout,"  Object texture name: '%s'\n",tex);
+                               }
+
+                               /* Else (count == 0) this is the start of a group, and */
+                               /* no texture name is present. */
+                       }
+                       else if ( start == FLOAT_END ) {
+                               /* End of an object or group. Yes, the name should be */
+                               /* obvious from context, but it is in here just to be */
+                               /* safe and to provide a little extra information for */
+                               /* those who do not wish to write a recursive reader. */
+                               /* Mia culpa. */
+                               --iLevel;
+                               i = -1;
+                               do {
+                                       ++i;
+                                       fread( &( name[i] ), sizeof( char ), 1, input );
+                               } while ( name[i] != '\0' );
+
+//                             indent();
+//                             fprintf(stdout,"OBJECT END: %s\n",name);
+                               continue;
+                       }
+               }
+
+//
+// read the triangles
+//
+               for ( i = 0; i < count; ++i ) {
+                       int j;
+
+                       fread( &tri, sizeof( tf_triangle ), 1, input );
+                       ByteSwapTri( &tri );
+                       for ( j = 0 ; j < 3 ; j++ )
+                       {
+                               int k;
+
+                               for ( k = 0 ; k < 3 ; k++ )
+                               {
+                                       ptri->verts[j][k] = tri.pt[j].p.v[k];
+                               }
+                       }
+
+                       ptri++;
+
+                       if ( ( ptri - *pptri ) >= MAXTRIANGLES ) {
+                               Error( "Error: too many triangles; increase MAXTRIANGLES\n" );
+