summaryrefslogtreecommitdiff
path: root/utils/xwad
diff options
context:
space:
mode:
Diffstat (limited to 'utils/xwad')
-rw-r--r--utils/xwad/goldsrc_bspfile.h310
-rw-r--r--utils/xwad/goldsrc_standin.cpp322
-rw-r--r--utils/xwad/goldsrc_standin.h42
-rw-r--r--utils/xwad/lbmlib.cpp741
-rw-r--r--utils/xwad/lbmlib.h55
-rw-r--r--utils/xwad/wadlib.cpp336
-rw-r--r--utils/xwad/wadlib.h61
-rw-r--r--utils/xwad/xwad.cpp1182
-rw-r--r--utils/xwad/xwad.vcproj185
9 files changed, 3234 insertions, 0 deletions
diff --git a/utils/xwad/goldsrc_bspfile.h b/utils/xwad/goldsrc_bspfile.h
new file mode 100644
index 0000000..2ae1812
--- /dev/null
+++ b/utils/xwad/goldsrc_bspfile.h
@@ -0,0 +1,310 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#ifndef BSPFILE_H
+#define BSPFILE_H
+
+// upper design bounds
+
+#define MAX_MAP_HULLS 4
+
+#define MAX_MAP_MODELS 400
+#define MAX_MAP_BRUSHES 4096
+#define MAX_MAP_ENTITIES 1024
+#define MAX_MAP_ENTSTRING (128*1024)
+
+#define MAX_MAP_PLANES 32767
+#define MAX_MAP_NODES 32767 // because negative shorts are contents
+#define MAX_MAP_CLIPNODES 32767 //
+#define MAX_MAP_LEAFS 8192
+#define MAX_MAP_VERTS 65535
+#define MAX_MAP_FACES 65535
+#define MAX_MAP_MARKSURFACES 65535
+#define MAX_MAP_TEXINFO 8192
+#define MAX_MAP_EDGES 256000
+#define MAX_MAP_SURFEDGES 512000
+#define MAX_MAP_TEXTURES 512
+#define MAX_MAP_MIPTEX 0x400000
+#define MAX_MAP_LIGHTING 0x100000
+#define MAX_MAP_VISIBILITY 0x100000
+
+#define MAX_MAP_PORTALS 65536
+
+// key / value pair sizes
+
+#define MAX_KEY 32
+#define MAX_VALUE 1024
+
+//=============================================================================
+
+
+#define BSPVERSION 30
+#define TOOLVERSION 2
+
+typedef struct
+{
+ int fileofs, filelen;
+} lump_t;
+
+#define LUMP_ENTITIES 0
+#define LUMP_PLANES 1
+#define LUMP_TEXTURES 2
+#define LUMP_VERTEXES 3
+#define LUMP_VISIBILITY 4
+#define LUMP_NODES 5
+#define LUMP_TEXINFO 6
+#define LUMP_FACES 7
+#define LUMP_LIGHTING 8
+#define LUMP_CLIPNODES 9
+#define LUMP_LEAFS 10
+#define LUMP_MARKSURFACES 11
+#define LUMP_EDGES 12
+#define LUMP_SURFEDGES 13
+#define LUMP_MODELS 14
+
+#define HEADER_LUMPS 15
+
+typedef struct
+{
+ float mins[3], maxs[3];
+ float origin[3];
+ int headnode[MAX_MAP_HULLS];
+ int visleafs; // not including the solid leaf 0
+ int firstface, numfaces;
+} dmodel_t;
+
+typedef struct
+{
+ int version;
+ lump_t lumps[HEADER_LUMPS];
+} dheader_t;
+
+typedef struct
+{
+ int nummiptex;
+ int dataofs[4]; // [nummiptex]
+} dmiptexlump_t;
+
+#define MIPLEVELS 4
+typedef struct miptex_s
+{
+ char name[16];
+ unsigned width, height;
+ unsigned offsets[MIPLEVELS]; // four mip maps stored
+} miptex_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
+
+typedef struct
+{
+ float normal[3];
+ float dist;
+ int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
+} dplane_t;
+
+
+/*** -1..-6 now in const.h ***/
+#define CONTENTS_ORIGIN -7 // removed at csg time
+#define CONTENTS_CLIP -8 // changed to contents_solid
+#define CONTENTS_CURRENT_0 -9
+#define CONTENTS_CURRENT_90 -10
+#define CONTENTS_CURRENT_180 -11
+#define CONTENTS_CURRENT_270 -12
+#define CONTENTS_CURRENT_UP -13
+#define CONTENTS_CURRENT_DOWN -14
+
+#define CONTENTS_TRANSLUCENT -15
+
+
+// !!! if this is changed, it must be changed in asm_i386.h too !!!
+typedef struct
+{
+ int planenum;
+ short children[2]; // negative numbers are -(leafs+1), not nodes
+ short mins[3]; // for sphere culling
+ short maxs[3];
+ unsigned short firstface;
+ unsigned short numfaces; // counting both sides
+} dnode_t;
+
+typedef struct
+{
+ int planenum;
+ short children[2]; // negative numbers are contents
+} dclipnode_t;
+
+
+typedef struct texinfo_s
+{
+ float vecs[2][4]; // [s/t][xyz offset]
+ int miptex;
+ int flags;
+} texinfo_t;
+#define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision
+
+// note that edge 0 is never used, because negative edge nums are used for
+// counterclockwise use of the edge in a face
+typedef struct
+{
+ unsigned short v[2]; // vertex numbers
+} dedge_t;
+
+#define MAXLIGHTMAPS 4
+typedef struct
+{
+ short planenum;
+ short side;
+
+ int firstedge; // we must support > 64k edges
+ short numedges;
+ short texinfo;
+
+// lighting info
+ byte styles[MAXLIGHTMAPS];
+ int lightofs; // start of [numstyles*surfsize] samples
+} dface_t;
+
+
+
+#define AMBIENT_WATER 0
+#define AMBIENT_SKY 1
+#define AMBIENT_SLIME 2
+#define AMBIENT_LAVA 3
+
+#define NUM_AMBIENTS 4 // automatic ambient sounds
+
+// leaf 0 is the generic CONTENTS_SOLID leaf, used for all solid areas
+// all other leafs need visibility info
+typedef struct
+{
+ int contents;
+ int visofs; // -1 = no visibility info
+
+ short mins[3]; // for frustum culling
+ short maxs[3];
+
+ unsigned short firstmarksurface;
+ unsigned short nummarksurfaces;
+
+ byte ambient_level[NUM_AMBIENTS];
+} dleaf_t;
+
+
+//============================================================================
+
+#ifndef QUAKE_GAME
+
+#define ANGLE_UP -1
+#define ANGLE_DOWN -2
+
+
+// the utilities get to be lazy and just use large static arrays
+
+extern int nummodels;
+extern dmodel_t dmodels[MAX_MAP_MODELS];
+
+extern int visdatasize;
+extern byte dvisdata[MAX_MAP_VISIBILITY];
+
+extern int lightdatasize;
+extern byte dlightdata[MAX_MAP_LIGHTING];
+
+extern int texdatasize;
+extern byte dtexdata[MAX_MAP_MIPTEX]; // (dmiptexlump_t)
+
+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 numclipnodes;
+extern dclipnode_t dclipnodes[MAX_MAP_CLIPNODES];
+
+extern int numedges;
+extern dedge_t dedges[MAX_MAP_EDGES];
+
+extern int nummarksurfaces;
+extern unsigned short dmarksurfaces[MAX_MAP_MARKSURFACES];
+
+extern int numsurfedges;
+extern int dsurfedges[MAX_MAP_SURFEDGES];
+
+
+void DecompressVis (byte *in, byte *decompressed);
+int CompressVis (byte *vis, byte *dest);
+
+void LoadBSPFile (char *filename);
+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;
+} 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);
+
+#endif
+
+#endif
diff --git a/utils/xwad/goldsrc_standin.cpp b/utils/xwad/goldsrc_standin.cpp
new file mode 100644
index 0000000..8ae8df0
--- /dev/null
+++ b/utils/xwad/goldsrc_standin.cpp
@@ -0,0 +1,322 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include "goldsrc_standin.h"
+
+
+extern int errno;
+
+
+static unsigned short g_InitialColor = 0xFFFF;
+static unsigned short g_LastColor = 0xFFFF;
+static unsigned short g_BadColor = 0xFFFF;
+static WORD g_BackgroundFlags = 0xFFFF;
+static bool g_bGotInitialColors = false;
+
+static void GetInitialColors( )
+{
+ if ( g_bGotInitialColors )
+ return;
+
+ g_bGotInitialColors = true;
+
+ // Get the old background attributes.
+ CONSOLE_SCREEN_BUFFER_INFO oldInfo;
+ GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &oldInfo );
+ g_InitialColor = g_LastColor = oldInfo.wAttributes & (FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY);
+ g_BackgroundFlags = oldInfo.wAttributes & (BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE|BACKGROUND_INTENSITY);
+
+ g_BadColor = 0;
+ if (g_BackgroundFlags & BACKGROUND_RED)
+ g_BadColor |= FOREGROUND_RED;
+ if (g_BackgroundFlags & BACKGROUND_GREEN)
+ g_BadColor |= FOREGROUND_GREEN;
+ if (g_BackgroundFlags & BACKGROUND_BLUE)
+ g_BadColor |= FOREGROUND_BLUE;
+ if (g_BackgroundFlags & BACKGROUND_INTENSITY)
+ g_BadColor |= FOREGROUND_INTENSITY;
+}
+
+static WORD SetConsoleTextColor( int red, int green, int blue, int intensity )
+{
+ GetInitialColors();
+
+ WORD ret = g_LastColor;
+
+ g_LastColor = 0;
+ if( red ) g_LastColor |= FOREGROUND_RED;
+ if( green ) g_LastColor |= FOREGROUND_GREEN;
+ if( blue ) g_LastColor |= FOREGROUND_BLUE;
+ if( intensity ) g_LastColor |= FOREGROUND_INTENSITY;
+
+ // Just use the initial color if there's a match...
+ if (g_LastColor == g_BadColor)
+ g_LastColor = g_InitialColor;
+
+ SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), g_LastColor | g_BackgroundFlags );
+ return ret;
+}
+
+
+static void RestoreConsoleTextColor( WORD color )
+{
+ SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), color | g_BackgroundFlags );
+ g_LastColor = color;
+}
+
+
+void Msg( const char *pMsg, ... )
+{
+ va_list marker;
+ va_start( marker, pMsg );
+ vprintf( pMsg, marker );
+ va_end( marker );
+}
+
+
+void Warning( const char *pMsg, ... )
+{
+ WORD old = SetConsoleTextColor( 1, 1, 0, 1 );
+
+ va_list marker;
+ va_start( marker, pMsg );
+ vprintf( pMsg, marker );
+ va_end( marker );
+
+ RestoreConsoleTextColor( old );
+}
+
+
+void Error (const char *error, ...)
+{
+ WORD old = SetConsoleTextColor( 1, 0, 0, 1 );
+
+ va_list argptr;
+
+ printf ("\n************ ERROR ************\n");
+
+ va_start (argptr,error);
+ vprintf (error,argptr);
+ va_end (argptr);
+ printf ("\n");
+
+ extern void PrintExitStuff();
+ PrintExitStuff();
+
+ RestoreConsoleTextColor( old );
+
+ TerminateProcess( GetCurrentProcess(), 100 );
+}
+
+
+/*
+================
+filelength
+================
+*/
+int filelength (FILE *f)
+{
+ int pos;
+ int end;
+
+ pos = ftell (f);
+ fseek (f, 0, SEEK_END);
+ end = ftell (f);
+ fseek (f, pos, SEEK_SET);
+
+ return end;
+}
+
+
+FILE *SafeOpenWrite (char *filename)
+{
+ FILE *f;
+
+ f = fopen(filename, "wb");
+
+ if (!f)
+ Error ("Error opening %s: %s",filename,strerror(errno));
+
+ return f;
+}
+
+FILE *SafeOpenRead (char *filename)
+{
+ FILE *f;
+
+ f = fopen(filename, "rb");
+
+ if (!f)
+ Error ("Error opening %s: %s",filename,strerror(errno));
+
+ return f;
+}
+
+
+void SafeRead (FILE *f, void *buffer, int count)
+{
+ if ( fread (buffer, 1, count, f) != (size_t)count)
+ Error ("File read failure");
+}
+
+
+void SafeWrite (FILE *f, void *buffer, int count)
+{
+ if (fwrite (buffer, 1, count, f) != (size_t)count)
+ Error ("File read failure");
+}
+
+
+
+/*
+==============
+LoadFile
+==============
+*/
+int LoadFile (char *filename, void **bufferptr)
+{
+ FILE *f;
+ int length;
+ void *buffer;
+
+ f = SafeOpenRead (filename);
+ length = filelength (f);
+ buffer = malloc (length+1);
+ ((char *)buffer)[length] = 0;
+ SafeRead (f, buffer, length);
+ fclose (f);
+
+ *bufferptr = buffer;
+ return length;
+}
+
+
+void SaveFile (char *filename, void *buffer, int count)
+{
+ FILE *f;
+
+ f = SafeOpenWrite (filename);
+ SafeWrite (f, buffer, count);
+ fclose (f);
+}
+
+
+#ifdef __BIG_ENDIAN__
+
+short LittleShort (short l)
+{
+ byte b1,b2;
+
+ b1 = l&255;
+ b2 = (l>>8)&255;
+
+ return (b1<<8) + b2;
+}
+
+short BigShort (short l)
+{
+ return l;
+}
+
+
+int LittleLong (int l)
+{
+ byte b1,b2,b3,b4;
+
+ b1 = l&255;
+ b2 = (l>>8)&255;
+ b3 = (l>>16)&255;
+ b4 = (l>>24)&255;
+
+ return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
+}
+
+int BigLong (int l)
+{
+ return l;
+}
+
+
+float LittleFloat (float l)
+{
+ union {byte b[4]; float f;} in, out;
+
+ in.f = l;
+ out.b[0] = in.b[3];
+ out.b[1] = in.b[2];
+ out.b[2] = in.b[1];
+ out.b[3] = in.b[0];
+
+ return out.f;
+}
+
+float BigFloat (float l)
+{
+ return l;
+}
+
+
+#else
+
+
+short BigShort (short l)
+{
+ byte b1,b2;
+
+ b1 = l&255;
+ b2 = (l>>8)&255;
+
+ return (b1<<8) + b2;
+}
+
+short LittleShort (short l)
+{
+ return l;
+}
+
+
+int BigLong (int l)
+{
+ byte b1,b2,b3,b4;
+
+ b1 = l&255;
+ b2 = (l>>8)&255;
+ b3 = (l>>16)&255;
+ b4 = (l>>24)&255;
+
+ return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
+}
+
+int LittleLong (int l)
+{
+ return l;
+}
+
+float BigFloat (float l)
+{
+ union {byte b[4]; float f;} in, out;
+
+ in.f = l;
+ out.b[0] = in.b[3];
+ out.b[1] = in.b[2];
+ out.b[2] = in.b[1];
+ out.b[3] = in.b[0];
+
+ return out.f;
+}
+
+float LittleFloat (float l)
+{
+ return l;
+}
+
+
+#endif
diff --git a/utils/xwad/goldsrc_standin.h b/utils/xwad/goldsrc_standin.h
new file mode 100644
index 0000000..2acb7be
--- /dev/null
+++ b/utils/xwad/goldsrc_standin.h
@@ -0,0 +1,42 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: This file provides some of the goldsrc functionality for xwad.
+//
+//=============================================================================//
+
+#ifndef GOLDSRC_STANDIN_H
+#define GOLDSRC_STANDIN_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+typedef float vec_t;
+typedef float vec3_t[3];
+
+typedef unsigned char byte;
+typedef int qboolean;
+
+
+void Msg( PRINTF_FORMAT_STRING const char *pMsg, ... );
+void Warning( PRINTF_FORMAT_STRING const char *pMsg, ... );
+void Error( PRINTF_FORMAT_STRING const char *pMsg, ... );
+
+int LoadFile (char *filename, void **bufferptr);
+void SaveFile (char *filename, void *buffer, int count);
+
+short BigShort (short l);
+short LittleShort (short l);
+int BigLong (int l);
+int LittleLong (int l);
+float BigFloat (float l);
+float LittleFloat (float l);
+
+
+FILE *SafeOpenWrite (char *filename);
+FILE *SafeOpenRead (char *filename);
+void SafeRead (FILE *f, void *buffer, int count);
+void SafeWrite (FILE *f, void *buffer, int count);
+
+
+#endif // GOLDSRC_STANDIN_H
diff --git a/utils/xwad/lbmlib.cpp b/utils/xwad/lbmlib.cpp
new file mode 100644
index 0000000..c3dfad8
--- /dev/null
+++ b/utils/xwad/lbmlib.cpp
@@ -0,0 +1,741 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+// lbmlib.c
+
+#include <WINDOWS.H>
+#include <STDIO.H>
+#include "lbmlib.h"
+#include "goldsrc_standin.h"
+
+
+
+/*
+============================================================================
+
+ LBM STUFF
+
+============================================================================
+*/
+
+
+#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;
+}
+
+
+#define BPLANESIZE 128
+byte bitplanes[9][BPLANESIZE]; // max size 1024 by 9 bit planes
+
+
+/*
+=================
+=
+= MungeBitPlanes8
+=
+= This destroys the bit plane data!
+=
+=================
+*/
+
+void MungeBitPlanes8 (int width, byte *dest)
+{
+ *dest=width; // shut up the compiler warning
+ Error ("MungeBitPlanes8 not rewritten!");
+#if 0
+asm les di,[dest]
+asm mov si,-1
+asm mov cx,[width]
+mungebyte:
+asm inc si
+asm mov dx,8
+mungebit:
+asm shl [BYTE PTR bitplanes + BPLANESIZE*7 +si],1
+asm rcl al,1
+asm shl [BYTE PTR bitplanes + BPLANESIZE*6 +si],1
+asm rcl al,1
+asm shl [BYTE PTR bitplanes + BPLANESIZE*5 +si],1
+asm rcl al,1
+asm shl [BYTE PTR bitplanes + BPLANESIZE*4 +si],1
+asm rcl al,1
+asm shl [BYTE PTR bitplanes + BPLANESIZE*3 +si],1
+asm rcl al,1
+asm shl [BYTE PTR bitplanes + BPLANESIZE*2 +si],1
+asm rcl al,1
+asm shl [BYTE PTR bitplanes + BPLANESIZE*1 +si],1
+asm rcl al,1
+asm shl [BYTE PTR bitplanes + BPLANESIZE*0 +si],1
+asm rcl al,1
+asm stosb
+asm dec cx
+asm jz done
+asm dec dx
+asm jnz mungebit
+asm jmp mungebyte
+
+done:
+#endif
+}
+
+
+void MungeBitPlanes4 (int width, byte *dest)
+{
+ *dest=width; // shut up the compiler warning
+ Error ("MungeBitPlanes4 not rewritten!");
+#if 0
+
+asm les di,[dest]
+asm mov si,-1
+asm mov cx,[width]
+mungebyte:
+asm inc si
+asm mov dx,8
+mungebit:
+asm xor al,al
+asm shl [BYTE PTR bitplanes + BPLANESIZE*3 +si],1
+asm rcl al,1
+asm shl [BYTE PTR bitplanes + BPLANESIZE*2 +si],1
+asm rcl al,1
+asm shl [BYTE PTR bitplanes + BPLANESIZE*1 +si],1
+asm rcl al,1
+asm shl [BYTE PTR bitplanes + BPLANESIZE*0 +si],1
+asm rcl al,1
+asm stosb
+asm dec cx
+asm jz done
+asm dec dx
+asm jnz mungebit
+asm jmp mungebyte
+
+done:
+#endif
+}
+
+
+void MungeBitPlanes2 (int width, byte *dest)
+{
+ *dest=width; // shut up the compiler warning
+ Error ("MungeBitPlanes2 not rewritten!");
+#if 0
+asm les di,[dest]
+asm mov si,-1
+asm mov cx,[width]
+mungebyte:
+asm inc si
+asm mov dx,8
+mungebit:
+asm xor al,al
+asm shl [BYTE PTR bitplanes + BPLANESIZE*1 +si],1
+asm rcl al,1
+asm shl [BYTE PTR bitplanes + BPLANESIZE*0 +si],1
+asm rcl al,1
+asm stosb
+asm dec cx
+asm jz done
+asm dec dx
+asm jnz mungebit
+asm jmp mungebyte
+
+done:
+#endif
+}
+
+
+void MungeBitPlanes1 (int width, byte *dest)
+{
+ *dest=width; // shut up the compiler warning
+ Error ("MungeBitPlanes1 not rewritten!");
+#if 0
+asm les di,[dest]
+asm mov si,-1
+asm mov cx,[width]
+mungebyte:
+asm inc si
+asm mov dx,8
+mungebit:
+asm xor al,al
+asm shl [BYTE PTR bitplanes + BPLANESIZE*0 +si],1
+asm rcl al,1
+asm stosb
+asm dec cx
+asm jz done
+asm dec dx
+asm jnz mungebit
+asm jmp mungebyte
+
+done:
+#endif
+}
+
+int LoadBMP (const char* szFile, BYTE** ppbBits, BYTE** ppbPalette)
+{
+ int i, rc = 0;
+ FILE *pfile = NULL;
+ BITMAPFILEHEADER bmfh;
+ BITMAPINFOHEADER bmih;
+ RGBQUAD rgrgbPalette[256];
+ ULONG cbBmpBits;
+ BYTE* pbBmpBits;
+ byte *pb, *pbPal = NULL;
+ ULONG cbPalBytes;
+ ULONG biTrueWidth;
+
+ // Bogus parameter check
+ if (!(ppbPalette != NULL && ppbBits != NULL))
+ { fprintf(stderr, "invalid BMP file\n"); rc = -1000; goto GetOut; }
+
+ // File exists?
+ if ((pfile = fopen(szFile, "rb")) == NULL)
+ { fprintf(stderr, "unable to open BMP file\n"); rc = -1; goto GetOut; }
+
+ // Read file header
+ if (fread(&bmfh, sizeof bmfh, 1/*count*/, pfile) != 1)
+ { rc = -2; goto GetOut; }
+
+ // Bogus file header check
+ if (!(bmfh.bfReserved1 == 0 && bmfh.bfReserved2 == 0))
+ { rc = -2000; goto GetOut; }
+
+ // Read info header
+ if (fread(&bmih, sizeof bmih, 1/*count*/, pfile) != 1)
+ { rc = -3; goto GetOut; }
+
+ // Bogus info header check
+ if (!(bmih.biSize == sizeof bmih && bmih.biPlanes == 1))
+ { fprintf(stderr, "invalid BMP file header\n"); rc = -3000; goto GetOut; }
+
+ // Bogus bit depth? Only 8-bit supported.
+ if (bmih.biBitCount != 8)
+ { fprintf(stderr, "BMP file not 8 bit\n"); rc = -4; goto GetOut; }
+
+ // Bogus compression? Only non-compressed supported.
+ if (bmih.biCompression != BI_RGB)
+ { fprintf(stderr, "invalid BMP compression type\n"); rc = -5; goto GetOut; }
+
+ // Figure out how many entires are actually in the table
+ if (bmih.biClrUsed == 0)
+ {
+ bmih.biClrUsed = 256;
+ cbPalBytes = (1 << bmih.biBitCount) * sizeof( RGBQUAD );
+ }
+ else
+ {
+ cbPalBytes = bmih.biClrUsed * sizeof( RGBQUAD );
+ }
+
+ // Read palette (bmih.biClrUsed entries)
+ if (fread(rgrgbPalette, cbPalBytes, 1/*count*/, pfile) != 1)
+ { rc = -6; goto GetOut; }
+
+ // convert to a packed 768 byte palette
+ pbPal = (unsigned char*)malloc(768);
+ if (pbPal == NULL)
+ { rc = -7; goto GetOut; }
+
+ pb = pbPal;
+
+ // Copy over used entries
+ for (i = 0; i < (int)bmih.biClrUsed; i++)
+ {
+ *pb++ = rgrgbPalette[i].rgbRed;
+ *pb++ = rgrgbPalette[i].rgbGreen;
+ *pb++ = rgrgbPalette[i].rgbBlue;
+ }
+
+ // Fill in unused entires will 0,0,0
+ for (i = bmih.biClrUsed; i < 256; i++)
+ {
+ *pb++ = 0;
+ *pb++ = 0;
+ *pb++ = 0;
+ }
+
+ // Read bitmap bits (remainder of file)
+ cbBmpBits = bmfh.bfSize - ftell(pfile);
+ pb = (unsigned char*)malloc(cbBmpBits);
+ if (fread(pb, cbBmpBits, 1/*count*/, pfile) != 1)
+ { rc = -7; goto GetOut; }
+
+ pbBmpBits = (unsigned char*)malloc(cbBmpBits);
+
+ // data is actually stored with the width being rounded up to a multiple of 4
+ biTrueWidth = (bmih.biWidth + 3) & ~3;
+
+ // reverse the order of the data.
+ pb += (bmih.biHeight - 1) * biTrueWidth;
+ for(i = 0; i < bmih.biHeight; i++)
+ {
+ memmove(&pbBmpBits[biTrueWidth * i], pb, biTrueWidth);
+ pb -= biTrueWidth;
+ }
+
+ pb += biTrueWidth;
+ free(pb);
+
+ bmhd.w = (WORD)bmih.biWidth;
+ bmhd.h = (WORD)bmih.biHeight;
+ // Set output parameters
+ *ppbPalette = pbPal;
+ *ppbBits = pbBmpBits;
+
+GetOut:
+ if (pfile)
+ fclose(pfile);
+
+ return rc;
+}
+
+
+int WriteBMPfile (char *szFile, byte *pbBits, int width, int height, byte *pbPalette)
+{
+ int i, rc = 0;
+ FILE *pfile = NULL;
+ BITMAPFILEHEADER bmfh;
+ BITMAPINFOHEADER bmih;
+ RGBQUAD rgrgbPalette[256];
+ ULONG cbBmpBits;
+ BYTE* pbBmpBits;
+ byte *pb, *pbPal = NULL;
+ ULONG cbPalBytes;
+ ULONG biTrueWidth;
+
+ // Bogus parameter check
+ if (!(pbPalette != NULL && pbBits != NULL))
+ { rc = -1000; goto GetOut; }
+
+ // File exists?
+ if ((pfile = fopen(szFile, "wb")) == NULL)
+ { rc = -1; goto GetOut; }
+
+ biTrueWidth = ((width + 3) & ~3);
+ cbBmpBits = biTrueWidth * height;
+ cbPalBytes = 256 * sizeof( RGBQUAD );
+
+ // Bogus file header check
+ bmfh.bfType = MAKEWORD( 'B', 'M' );
+ bmfh.bfSize = sizeof bmfh + sizeof bmih + cbBmpBits + cbPalBytes;
+ bmfh.bfReserved1 = 0;
+ bmfh.bfReserved2 = 0;
+ bmfh.bfOffBits = sizeof bmfh + sizeof bmih + cbPalBytes;
+
+ // Write file header
+ if (fwrite(&bmfh, sizeof bmfh, 1/*count*/, pfile) != 1)
+ { rc = -2; goto GetOut; }
+
+ // Size of structure
+ bmih.biSize = sizeof bmih;
+ // Width
+ bmih.biWidth = biTrueWidth;
+ // Height
+ bmih.biHeight = height;
+ // Only 1 plane
+ bmih.biPlanes = 1;
+ // Only 8-bit supported.
+ bmih.biBitCount = 8;
+ // Only non-compressed supported.
+ bmih.biCompression = BI_RGB;
+ bmih.biSizeImage = 0;
+
+ // huh?
+ bmih.biXPelsPerMeter = 0;
+ bmih.biYPelsPerMeter = 0;
+
+ // Always full palette
+ bmih.biClrUsed = 256;
+ bmih.biClrImportant = 0;
+
+ // Write info header
+ if (fwrite(&bmih, sizeof bmih, 1/*count*/, pfile) != 1)
+ { rc = -3; goto GetOut; }
+
+
+ // convert to expanded palette
+ pb = pbPalette;
+
+ // Copy over used entries
+ for (i = 0; i < (int)bmih.biClrUsed; i++)
+ {
+ rgrgbPalette[i].rgbRed = *pb++;
+ rgrgbPalette[i].rgbGreen = *pb++;
+ rgrgbPalette[i].rgbBlue = *pb++;
+ rgrgbPalette[i].rgbReserved = 0;
+ }
+
+ // Write palette (bmih.biClrUsed entries)
+ cbPalBytes = bmih.biClrUsed * sizeof( RGBQUAD );
+ if (fwrite(rgrgbPalette, cbPalBytes, 1/*count*/, pfile) != 1)
+ { rc = -6; goto GetOut; }
+
+
+ pbBmpBits = (unsigned char*)malloc(cbBmpBits);
+
+ pb = pbBits;
+ // reverse the order of the data.
+ pb += (height - 1) * width;
+ for(i = 0; i < bmih.biHeight; i++)
+ {
+ memmove(&pbBmpBits[biTrueWidth * i], pb, width);
+ pb -= width;
+ }
+
+ // Write bitmap bits (remainder of file)
+ if (fwrite(pbBmpBits, cbBmpBits, 1/*count*/, pfile) != 1)
+ { rc = -7; goto GetOut; }
+
+ free(pbBmpBits);
+
+GetOut:
+ if (pfile)
+ fclose(pfile);
+
+ return rc;
+}
+
+/*
+=================
+=
+= LoadLBM
+=
+=================
+*/
+
+void LoadLBM (char *filename, byte **picture, byte **palette)
+{
+ byte *LBMbuffer, *picbuffer, *cmapbuffer;
+ int y,p,planes;
+ byte *LBM_P, *LBMEND_P;
+ byte *pic_p;
+ byte *body_p;
+ unsigned rowsize;
+
+ int formtype,formlength;
+ int chunktype,chunklength;
+ void (*mungecall) (int, byte *);
+
+// qiet compiler warnings
+ picbuffer = NULL;
+ cmapbuffer = NULL;
+ mungecall = 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 = (unsigned char*)malloc (768);
+ memset (cmapbuffer, 0, 768);
+ memcpy (cmapbuffer, LBM_P, chunklength);
+ break;
+
+ case BODYID:
+ body_p = LBM_P;
+
+ pic_p = picbuffer = (unsigned char*)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
+ //
+ planes = bmhd.nPlanes;
+ if (bmhd.masking == ms_mask)
+ planes++;
+ rowsize = (bmhd.w+15)/16 * 2;
+ switch (bmhd.nPlanes)
+ {
+ case 1:
+ mungecall = MungeBitPlanes1;
+ break;
+ case 2:
+ mungecall = MungeBitPlanes2;
+ break;
+ case 4:
+ mungecall = MungeBitPlanes4;
+ break;
+ case 8:
+ mungecall = MungeBitPlanes8;
+ break;
+ default:
+ Error ("Can't munge %i bit planes!\n",bmhd.nPlanes);
+ }
+
+ for (y=0 ; y<bmhd.h ; y++, pic_p += bmhd.w)
+ {
+ for (p=0 ; p<planes ; p++)
+ if (bmhd.compression == cm_rle1)
+ body_p = LBMRLEDecompress ((byte *)body_p
+ , bitplanes[p] , rowsize);
+ else if (bmhd.compression == cm_none)
+ {
+ memcpy (bitplanes[p],body_p,rowsize);
+ body_p += rowsize;
+ }
+
+ mungecall (bmhd.w , pic_p);
+ }
+ }
+ break;
+ }
+
+ LBM_P += Align(chunklength);
+ }
+
+ free (LBMbuffer);
+
+ *picture = picbuffer;
+ *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 = (unsigned char*)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 = (BYTE)BigShort(8);
+ basebmhd.xAspect = (BYTE)BigShort(5);
+ basebmhd.yAspect = (BYTE)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);
+}
+
diff --git a/utils/xwad/lbmlib.h b/utils/xwad/lbmlib.h
new file mode 100644
index 0000000..23ac560
--- /dev/null
+++ b/utils/xwad/lbmlib.h
@@ -0,0 +1,55 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+// lbmlib.h
+
+typedef unsigned char UBYTE;
+
+#ifndef _WINDOWS_
+typedef short WORD;
+#endif
+
+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;
+ WORD x,y;
+ UBYTE nPlanes;
+ UBYTE masking;
+ UBYTE compression;
+ UBYTE pad1;
+ UWORD transparentColor;
+ UBYTE xAspect,yAspect;
+ WORD pageWidth,pageHeight;
+} bmhd_t;
+
+extern bmhd_t bmhd; // will be in native byte order
+
+
+void LoadLBM (char *filename, byte **picture, byte **palette);
+int LoadBMP (const char* szFile, byte** ppbBits, byte** ppbPalette);
+void WriteLBMfile (char *filename, byte *data, int width, int height
+ , byte *palette);
+int WriteBMPfile (char *szFile, byte *pbBits, int width, int height, byte *pbPalette);
+
diff --git a/utils/xwad/wadlib.cpp b/utils/xwad/wadlib.cpp
new file mode 100644
index 0000000..c7d4750
--- /dev/null
+++ b/utils/xwad/wadlib.cpp
@@ -0,0 +1,336 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+// wad2lib.c
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+//#include <sys/file.h>
+#include <stdarg.h>
+
+#ifdef NeXT
+#include <libc.h>
+#endif
+#include "goldsrc_standin.h"
+#include "wadlib.h"
+
+/*
+============================================================================
+
+ WAD READING
+
+============================================================================
+*/
+
+
+lumpinfo_t *lumpinfo; // location of each lump on disk
+int numlumps;
+
+wadinfo_t header;
+FILE *wadhandle;
+
+
+/*
+====================
+W_OpenWad
+====================
+*/
+void W_OpenWad (const char *filename)
+{
+ lumpinfo_t *lump_p;
+ int i;
+ int length;
+
+//
+// open the file and add to directory
+//
+ wadhandle = SafeOpenRead ((char*)filename);
+ SafeRead (wadhandle, &header, sizeof(header));
+
+ if (strncmp(header.identification,"WAD2",4) &&
+ strncmp(header.identification, "WAD3", 4))
+ Error ("Wad file %s doesn't have WAD2/WAD3 id\n",filename);
+
+ header.numlumps = LittleLong(header.numlumps);
+ header.infotableofs = LittleLong(header.infotableofs);
+
+ numlumps = header.numlumps;
+
+ length = numlumps*sizeof(lumpinfo_t);
+ lumpinfo = (lumpinfo_t*)malloc (length);
+ lump_p = lumpinfo;
+
+ fseek (wadhandle, header.infotableofs, SEEK_SET);
+ SafeRead (wadhandle, lumpinfo, length);
+
+//
+// Fill in lumpinfo
+//
+
+ for (i=0 ; i<numlumps ; i++,lump_p++)
+ {
+ lump_p->filepos = LittleLong(lump_p->filepos);
+ lump_p->size = LittleLong(lump_p->size);
+ }
+}
+
+
+void CleanupName (char *in, char *out)
+{
+ int i;
+
+ for (i=0 ; i<sizeof( ((lumpinfo_t *)0)->name ) ; i++ )
+ {
+ if (!in[i])
+ break;
+
+ out[i] = toupper(in[i]);
+ }
+
+ for ( ; i<sizeof( ((lumpinfo_t *)0)->name ); i++ )
+ out[i] = 0;
+}
+
+
+/*
+====================
+W_CheckNumForName
+
+Returns -1 if name not found
+====================
+*/
+int W_CheckNumForName (char *name)
+{
+ char cleanname[16];
+ int v1,v2, v3, v4;
+ int i;
+ lumpinfo_t *lump_p;
+
+ CleanupName (name, cleanname);
+
+// make the name into four integers for easy compares
+
+ v1 = *(int *)cleanname;
+ v2 = *(int *)&cleanname[4];
+ v3 = *(int *)&cleanname[8];
+ v4 = *(int *)&cleanname[12];
+
+// find it
+
+ lump_p = lumpinfo;
+ for (i=0 ; i<numlumps ; i++, lump_p++)
+ {
+ if ( *(int *)lump_p->name == v1
+ && *(int *)&lump_p->name[4] == v2
+ && *(int *)&lump_p->name[8] == v3
+ && *(int *)&lump_p->name[12] == v4)
+ return i;
+ }
+
+ return -1;
+}
+
+
+/*
+====================
+W_GetNumForName
+
+Calls W_CheckNumForName, but bombs out if not found
+====================
+*/
+int W_GetNumForName (char *name)
+{
+ int i;
+
+ i = W_CheckNumForName (name);
+ if (i != -1)
+ return i;
+
+ Error ("W_GetNumForName: %s not found!",name);
+ return -1;
+}
+
+
+/*
+====================
+W_LumpLength
+
+Returns the buffer size needed to load the given lump
+====================
+*/
+int W_LumpLength (int lump)
+{
+ if (lump >= numlumps)
+ Error ("W_LumpLength: %i >= numlumps",lump);
+ return lumpinfo[lump].size;
+}
+
+
+/*
+====================
+W_ReadLumpNum
+
+Loads the lump into the given buffer, which must be >= W_LumpLength()
+====================
+*/
+void W_ReadLumpNum (int lump, void *dest)
+{
+ lumpinfo_t *l;
+
+ if (lump >= numlumps)
+ Error ("W_ReadLump: %i >= numlumps",lump);
+ l = lumpinfo+lump;
+
+ fseek (wadhandle, l->filepos, SEEK_SET);
+ SafeRead (wadhandle, dest, l->size);
+}
+
+
+
+/*
+====================
+W_LoadLumpNum
+====================
+*/
+void *W_LoadLumpNum (int lump)
+{
+ void *buf;
+
+ if ((unsigned)lump >= (unsigned)numlumps)
+ Error ("W_CacheLumpNum: %i >= numlumps",lump);
+
+ buf = malloc (W_LumpLength (lump));
+ W_ReadLumpNum (lump, buf);
+
+ return buf;
+}
+
+
+/*
+====================
+W_LoadLumpName
+====================
+*/
+void *W_LoadLumpName (char *name)
+{
+ return W_LoadLumpNum (W_GetNumForName(name));
+}
+
+
+/*
+===============================================================================
+
+ WAD CREATION
+
+===============================================================================
+*/
+
+FILE *outwad;
+
+lumpinfo_t outinfo[4096];
+int outlumps;
+
+short (*wadshort) (short l);
+int (*wadlong) (int l);
+
+/*
+===============
+NewWad
+===============
+*/
+
+void NewWad (char *pathname, qboolean bigendien)
+{
+ outwad = SafeOpenWrite (pathname);
+ fseek (outwad, sizeof(wadinfo_t), SEEK_SET);
+ memset (outinfo, 0, sizeof(outinfo));
+
+ if (bigendien)
+ {
+ wadshort = BigShort;
+ wadlong = BigLong;
+ }
+ else
+ {
+ wadshort = LittleShort;
+ wadlong = LittleLong;
+ }
+
+ outlumps = 0;
+}
+
+
+/*
+===============
+AddLump
+===============
+*/
+
+void AddLump (char *name, void *buffer, int length, int type, int compress)
+{
+ lumpinfo_t *info;
+ int ofs;
+
+ info = &outinfo[outlumps];
+ outlumps++;
+
+ memset (info,0,sizeof(info));
+
+ strcpy (info->name, name);
+ strupr (info->name);
+
+ ofs = ftell(outwad);
+ info->filepos = wadlong(ofs);
+ info->size = info->disksize = wadlong(length);
+ info->type = type;
+ info->compression = compress;
+
+// FIXME: do compression
+
+ SafeWrite (outwad, buffer, length);
+}
+
+
+/*
+===============
+WriteWad
+===============
+*/
+
+void WriteWad (int wad3)
+{
+ wadinfo_t header;
+ int ofs;
+
+// write the lumpingo
+ ofs = ftell(outwad);
+
+ SafeWrite (outwad, outinfo, outlumps*sizeof(lumpinfo_t) );
+
+// write the header
+
+// a program will be able to tell the ednieness of a wad by the id
+ header.identification[0] = 'W';
+ header.identification[1] = 'A';
+ header.identification[2] = 'D';
+ header.identification[3] = wad3 ? '3' : '2';
+
+ header.numlumps = wadlong(outlumps);
+ header.infotableofs = wadlong(ofs);
+
+ fseek (outwad, 0, SEEK_SET);
+ SafeWrite (outwad, &header, sizeof(header));
+ fclose (outwad);
+}
+
+
diff --git a/utils/xwad/wadlib.h b/utils/xwad/wadlib.h
new file mode 100644
index 0000000..e675fa3
--- /dev/null
+++ b/utils/xwad/wadlib.h
@@ -0,0 +1,61 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+// wadlib.h
+
+//
+// wad reading
+//
+
+#define CMP_NONE 0
+#define CMP_LZSS 1
+
+#define TYP_NONE 0
+#define TYP_LABEL 1
+#define TYP_LUMPY 64 // 64 + grab command number
+
+typedef struct
+{
+ char identification[4]; // should be WAD2 or 2DAW
+ int numlumps;
+ int infotableofs;
+} wadinfo_t;
+
+
+typedef struct
+{
+ int filepos;
+ int disksize;
+ int size; // uncompressed
+ char type;
+ char compression;
+ char pad1, pad2;
+ char name[16]; // must be null terminated
+} lumpinfo_t;
+
+extern lumpinfo_t *lumpinfo; // location of each lump on disk
+extern int numlumps;
+extern wadinfo_t header;
+
+void W_OpenWad (const char *filename);
+int W_CheckNumForName (char *name);
+int W_GetNumForName (char *name);
+int W_LumpLength (int lump);
+void W_ReadLumpNum (int lump, void *dest);
+void *W_LoadLumpNum (int lump);
+void *W_LoadLumpName (char *name);
+
+void CleanupName (char *in, char *out);
+
+//
+// wad creation
+//
+void NewWad (char *pathname, qboolean bigendien);
+void AddLump (char *name, void *buffer, int length, int type, int compress);
+void WriteWad (int wad3);
+
diff --git a/utils/xwad/xwad.cpp b/utils/xwad/xwad.cpp
new file mode 100644
index 0000000..dce4b7f
--- /dev/null
+++ b/utils/xwad/xwad.cpp
@@ -0,0 +1,1182 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <conio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <io.h>
+#include <direct.h>
+#include <stdarg.h>
+
+#include "goldsrc_standin.h"
+
+#include "wadlib.h"
+#include "goldsrc_bspfile.h"
+
+
+extern FILE *wadhandle;
+
+
+#pragma pack( 1 )
+ struct TGAHeader_t
+ {
+ unsigned char id_length;
+ unsigned char colormap_type;
+ unsigned char image_type;
+ unsigned short colormap_index;
+ unsigned short colormap_length;
+ unsigned char colormap_size;
+ unsigned short x_origin;
+ unsigned short y_origin;
+ unsigned short width;
+ unsigned short height;
+ unsigned char pixel_size;
+ unsigned char attributes;
+ };
+#pragma pack()
+
+
+typedef enum {ST_SYNC=0, ST_RAND } synctype_t;
+typedef enum { SPR_SINGLE=0, SPR_GROUP } spriteframetype_t;
+
+typedef struct {
+ int ident;
+ int version;
+ int type;
+ int texFormat;
+ float boundingradius;
+ int width;
+ int height;
+ int numframes;
+ float beamlength;
+ synctype_t synctype;
+} dsprite_t;
+
+typedef struct {
+ int origin[2];
+ int width;
+ int height;
+} dspriteframe_t;
+
+
+class RGBAColor
+{
+public:
+ unsigned char r,g,b,a;
+};
+
+
+const char *g_pDefaultShader = "LightmappedGeneric";
+const char *g_pShader = g_pDefaultShader;
+bool g_bBMPAllowTranslucent = false;
+bool g_bDecal = false;
+bool g_bQuiet = false;
+
+#define MAX_VMT_PARAMS 16
+
+struct VTexVMTParam_t
+{
+ const char *m_szParam;
+ const char *m_szValue;
+};
+
+static VTexVMTParam_t g_VMTParams[MAX_VMT_PARAMS];
+
+static int g_NumVMTParams = 0;
+
+void PrintExitStuff()
+{
+ if ( !g_bQuiet )
+ {
+ printf( "Press a key to quit.\n" );
+ getch();
+ }
+}
+
+
+RGBAColor* ConvertToRGBUpsideDown( byte *pBits, int width, int height, byte *pPalette, bool *bTranslucent )
+{
+ RGBAColor *pRet = new RGBAColor[width*height];
+
+ byte newPalette[256][3];
+ for ( int i=0; i < 256; i++ )
+ {
+ newPalette[i][0] = pPalette[i*3+2];
+ newPalette[i][1] = pPalette[i*3+1];
+ newPalette[i][2] = pPalette[i*3+0];
+ }
+
+ // Write the lines upside-down.
+ for ( int y=0; y < height; y++ )
+ {
+ byte *pLine = &pBits[(height-y-1)*width];
+ for ( int x=0; x < width; x++ )
+ {
+ pRet[y*width+x].r = newPalette[pLine[x]][0];
+ pRet[y*width+x].g = newPalette[pLine[x]][1];
+ pRet[y*width+x].b = newPalette[pLine[x]][2];
+ if ( pLine[x] == 255 )
+ {
+ *bTranslucent = true;
+ pRet[y*width+x].a = 0;
+ }
+ else
+ {
+ pRet[y*width+x].a = 255;
+ }
+ }
+ }
+
+ return pRet;
+}
+
+
+void FloodSolidPixels( RGBAColor *pTexels, int width, int height )
+{
+ byte *pAlphaMap = new byte[width*height];
+ byte *pNewAlphaMap = new byte[width*height];
+
+ for ( int y=0; y < height; y++ )
+ for ( int x=0; x < width; x++ )
+ pAlphaMap[y*width+x] = pTexels[y*width+x].a;
+
+ bool bHappy = false;
+ while ( !bHappy )
+ {
+ bHappy = true;
+
+ memcpy( pNewAlphaMap, pAlphaMap, width * height );
+
+ for ( int y=0; y < height; y++ )
+ {
+ RGBAColor *pLine = &pTexels[y*width];
+
+ for ( int x=0; x < width; x++ )
+ {
+ if ( pAlphaMap[y*width+x] == 0 )
+ {
+ int nNeighbors = 0;
+ int neighborTotal[3] = {0,0,0};
+
+ // Blend all the neighboring solid pixels.
+ for ( int offsetX=-1; offsetX <= 1; offsetX++ )
+ {
+ for ( int offsetY=-1; offsetY <= 1; offsetY++ )
+ {
+ int testX = x + offsetX;
+ int testY = y + offsetY;
+ if ( testX >= 0 && testY >= 0 && testX < width && testY < height )
+ {
+ if ( pAlphaMap[testY*width+testX] )
+ {
+ RGBAColor *pNeighbor = &pTexels[testY*width+testX];
+ ++nNeighbors;
+ neighborTotal[0] += pNeighbor->r;
+ neighborTotal[1] += pNeighbor->g;
+ neighborTotal[2] += pNeighbor->b;
+ }
+ }
+ }
+ }
+
+ if ( nNeighbors )
+ {
+ pNewAlphaMap[y*width+x] = 255;
+ bHappy = false;
+ pLine[x].r = (byte)( neighborTotal[0] / nNeighbors );
+ pLine[x].g = (byte)( neighborTotal[1] / nNeighbors );
+ pLine[x].b = (byte)( neighborTotal[2] / nNeighbors );
+ }
+ }
+ }
+ }
+
+ memcpy( pAlphaMap, pNewAlphaMap, width * height );
+ }
+
+ delete [] pAlphaMap;
+ delete [] pNewAlphaMap;
+}
+
+
+RGBAColor* ResampleImage( RGBAColor *pRGB, int width, int height, int newWidth, int newHeight )
+{
+ RGBAColor *pResampled = new RGBAColor[newWidth * newHeight];
+ for ( int y=0; y < newHeight; y++ )
+ {
+ float yPercent = (float)y / (newHeight - 1);
+ float flSrcY = yPercent * (height - 1.00001f);
+ int iSrcY = (int)flSrcY;
+ float flYFrac = flSrcY - iSrcY;
+
+ for ( int x=0; x < newWidth; x++ )
+ {
+ float xPercent = (float)x / (newWidth - 1);
+ float flSrcX = xPercent * (width - 1.00001f);
+ int iSrcX = (int)flSrcX;
+ float flXFrac = flSrcX - iSrcX;
+
+ byte *pSrc0 = ((byte*)&pRGB[iSrcY*width+iSrcX]);
+ byte *pSrc1 = ((byte*)&pRGB[iSrcY*width+iSrcX+1]);
+ byte *pSrc2 = ((byte*)&pRGB[(iSrcY+1)*width+iSrcX]);
+ byte *pSrc3 = ((byte*)&pRGB[(iSrcY+1)*width+iSrcX+1]);
+ byte *pDest = (byte*)&pResampled[y*newWidth+x];
+
+ // Now blend the nearest 4 source pixels.
+ for ( int i=0; i < 4; i++ )
+ {
+ //pDest[i] = pSrc0[i];
+ float topColor = ( pSrc0[i]*(1-flXFrac) + pSrc1[i]*flXFrac );
+ float bottomColor = ( pSrc2[i]*(1-flXFrac) + pSrc3[i]*flXFrac );
+ pDest[i] = (byte)( topColor*(1-flYFrac) + bottomColor*flYFrac );
+ }
+ }
+ }
+ return pResampled;
+}
+
+
+bool WriteTGAFile(
+ const char *pFilename,
+ bool bAllowTranslucent,
+ byte *pBits,
+ int width,
+ int height,
+ byte *pPalette,
+ bool bPowerOf2,
+ bool *bTranslucent,
+ bool *bResized
+ )
+{
+ *bResized = *bTranslucent = false;
+
+ RGBAColor *pRGB = ConvertToRGBUpsideDown( pBits, width, height, pPalette, bTranslucent );
+
+ // Unless the filename starts with '{', we don't allow translucency.
+ if ( !bAllowTranslucent )
+ *bTranslucent = false;
+
+ // Flood the solid texel colors into the transparent texels.
+ // Since we turn on point sampling for these textures, this only matters if we're resizing the texture.
+ if ( *bTranslucent )
+ {
+ FloodSolidPixels( pRGB, width, height );
+ }
+
+ if ( bPowerOf2 )
+ {
+ // Is it not a power of 2?
+ if ( (width & (width - 1)) || (height & (height - 1)) )
+ {
+ // Ok, resize it to the next highest power of 2.
+ int newWidth = width;
+ while ( (newWidth & (newWidth - 1)) )
+ ++newWidth;
+
+ int newHeight = height;
+ while ( (newHeight & (newHeight - 1)) )
+ ++newHeight;
+
+ printf( "\t(%dx%d) -> (%dx%d)", width, height, newWidth, newHeight );
+
+ RGBAColor *pResampled = ResampleImage( pRGB, width, height, newWidth, newHeight );
+ delete [] pRGB;
+ pRGB = pResampled;
+
+ width = newWidth;
+ height = newHeight;
+
+ *bResized = true;
+ }
+ }
+
+ // Write it..
+ TGAHeader_t hdr;
+ memset( &hdr, 0, sizeof( hdr ) );
+
+ hdr.width = width;
+ hdr.height = height;
+ hdr.colormap_type = 0; // no, no colormap please
+ hdr.image_type = 2; // uncompressed, true-color
+ hdr.pixel_size = 32; // 32 bits per pixel
+
+ FILE *fp = fopen( pFilename, "wb" );
+ if ( !fp )
+ return false;
+
+ SafeWrite( fp, &hdr, sizeof( hdr ) );
+ SafeWrite( fp, pRGB, sizeof( RGBAColor ) * width * height );
+ fclose( fp );
+
+ delete [] pRGB;
+ return true;
+}
+
+
+int PrintUsage( const char *pExtra, ... )
+{
+ va_list marker;
+ va_start( marker, pExtra );
+ vprintf( pExtra, marker );
+ va_end( marker );
+
+ printf(
+ "%s \n"
+ "\t[-AutoDir]\n"
+ "\t\tAutomatically detects -basedir and -wadfile or -bmpfile based\n"
+ "\t\ton the last parameter (it must be a WAD file or a BMP file.\n"
+ "\t[-decal]\n"
+ "\t\tCreates VMTs for decals and creates VMTs for model decals.\n"
+ "\t[-onlytex <tex name>]\n"
+ "\t[-shader <shader name>]\n"
+ "\t\tSpecify the shader to use in the VMT file (default\n"
+ "\t\tis LightmappedGeneric.\n"
+ "\t[-vtex]\n"
+ "\t\tIf -vtex is specified, then it calls vtex on each newly-created\n"
+ "\t\t.TGA file.\n"
+ "\t[-vmtparam <ParamName> <ParamValue>]\n"
+ "\t\tif -vtex was specified, passes the parameters to that process.\n"
+ "\t\tUsed to add parameters to the generated .vmt file\n"
+ "\t-BaseDir <basedir>\n"
+ "\t-game <basedir>\n"
+ "\t\tSpecifies where the root mod directory is.\n"
+ "\t-WadFile <wildcard>\n"
+ "\t\t-wadfile will make (power-of-2) TGAs, VTFs, and VMTs for each\n"
+ "\t\ttexture in the WAD. It will also place them under a directory\n"
+ "\t\twith the name of the WAD. In addition, it will create\n"
+ "\t\t.resizeinfo files in the materials directory if it has to\n"
+ "\t\tresize the texture. Then Hammer's File->WAD To Material\n"
+ "\t\tcommand will use them to rescale texture coordinates.\n"
+ "\t-bmpfile <wildcard>\n"
+ "\t\t-bmpfile acts like -WadFile but for BMP files, and it'll place\n"
+ "\t\tthem in the root materials directory.\n"
+ "\t-sprfile <wildcard>\n"
+ "\t\tActs like -bmpfile, but ports a sprite.\n"
+ "\t-Transparent (BMP files only)\n"
+ "\t\tIf this is set, then it will treat palette index 255 as a\n"
+ "\t\ttransparent pixel."
+ "\t-SubDir <subdirectory>\n"
+ "\t\t-SubDir tells it what directory under materials to place the\n"
+ "\t\tfinal art. If using a WAD file, then it will automatically\n"
+ "\t\tuse the WAD filename if no -SubDir is specified.\n"
+ "\t-Quiet\n"
+ "\t\tDon't print out anything or wait for a keypress on exit.\n"
+ "\n"
+ , __argv[0] );
+ printf( "ex: %s -vtex -BaseDir c:\\hl2\\dod -WadFile c:\\hl1\\dod\\*.wad\n", __argv[0] );
+ printf( "ex: %s -vtex -BaseDir c:\\hl2\\dod -bmpfile test.bmp -SubDir models\\props\n", __argv[0] );
+ printf( "ex: %s -vtex -vmtparam $ignorez 1 -BaseDir c:\\hl2\\dod -sprfile test.spr -SubDir sprites\\props\n", __argv[0] );
+
+ PrintExitStuff();
+ return 1;
+}
+
+
+// Take something like "c:/a/b/c/filename.ext" and return "filename".
+void GetBaseFilename( const char *pWadFilename, char wadBaseName[512] )
+{
+ const char *pBase = strrchr( pWadFilename, '\\' );
+ if ( strrchr( pWadFilename, '/' ) > pBase )
+ pBase = strrchr( pWadFilename, '/' );
+
+ if ( pBase )
+ strcpy( wadBaseName, pBase+1 );
+ else
+ strcpy( wadBaseName, pWadFilename );
+
+ char *pDot = strchr( wadBaseName, '.' );
+ if ( pDot )
+ *pDot = 0;
+}
+
+
+const char *LastSlash( const char *pSrc )
+{
+ const char *pRet = strrchr( pSrc, '/' );
+ const char *pRet2 = strrchr( pSrc, '\\' );
+ return (pRet > pRet2) ? pRet : pRet2;
+}
+
+
+void EnsureDirExists( const char *pDir )
+{
+ if ( _access( pDir, 0 ) != 0 )
+ {
+ // We use the shell's "md" command here instead of the _mkdir() function because
+ // md will create all the subdirectories leading up to the bottom one and _mkdir() won't.
+ char cmd[1024];
+ _snprintf( cmd, sizeof( cmd ), "md \"%s\"", pDir );
+ system( cmd );
+
+ if ( _access( pDir, 0 ) != 0 )
+ Error( "\tCan't create directory: %s.\n", pDir );
+ }
+}
+
+
+void WriteVMTFile( const char *pBaseDir, const char *pSubDir, const char *pName, bool bTranslucent )
+{
+ char vmtFilename[512];
+ sprintf( vmtFilename, "%s\\materials\\%s\\%s.vmt", pBaseDir, pSubDir, pName );
+
+ FILE *fp = fopen( vmtFilename, "wt" );
+ if ( !fp )
+ {
+ Error( "\tWriteVMTFile failed to open %s for writing.\n", vmtFilename );
+ return;
+ }
+
+ fprintf( fp, "\"%s\"\n{\n", g_pShader );
+ fprintf( fp, "\t\"$basetexture\"\t\"%s\\%s\"\n", pSubDir, pName );
+
+ if ( bTranslucent || g_bDecal )
+ {
+ fprintf( fp, "\t\"$alphatest\"\t\"1\"\n" );
+ fprintf( fp, "\t\"$ALPHATESTREFERENCE\"\t\"0.5\"\n" );
+ }
+
+ if ( g_bDecal )
+ {
+ fprintf( fp, "\t\"$decal\"\t\t\"1\"\n" );
+
+ }
+
+ int i;
+ for( i=0;i<g_NumVMTParams;i++ )
+ {
+ fprintf( fp, "\t\"%s\" \"%s\"\n", g_VMTParams[i].m_szParam, g_VMTParams[i].m_szValue );
+ }
+
+ fprintf( fp, "}" );
+
+ fclose( fp );
+}
+
+
+void WriteTXTFile( const char *pBaseDir, const char *pSubDir, const char *pName )
+{
+ char filename[512];
+ sprintf( filename, "%s\\materialsrc\\%s\\%s.txt", pBaseDir, pSubDir, pName );
+
+ FILE *fp = fopen( filename, "wt" );
+ if ( !fp )
+ Error( "\tWriteTXTFile: can't open %s for writing.\n", filename );
+
+ fprintf( fp, "\"pointsample\" \"1\"\n" );
+ fclose( fp );
+}
+
+
+void WriteResizeInfoFile( const char *pBaseDir, const char *pSubDir, const char *pName, int width, int height )
+{
+ char filename[512];
+ sprintf( filename, "%s\\materials\\%s\\%s.resizeinfo", pBaseDir, pSubDir, pName );
+
+ FILE *fp = fopen( filename, "wt" );
+ if ( !fp )
+ {
+ Error( "\tWriteResizeInfoFile failed to open %s for writing.\n", filename );
+ return;
+ }
+
+ fprintf( fp, "%d %d", width, height );
+ fclose( fp );
+}
+
+
+void RunVTexOnFile( const char *pBaseDir, const char *pFilename )
+{
+ char executableDir[MAX_PATH];
+ GetModuleFileName( NULL, executableDir, sizeof( executableDir ) );
+
+ char *pLastSlash = max( strrchr( executableDir, '/' ), strrchr( executableDir, '\\' ) );
+ if ( !pLastSlash )
+ Error( "Can't find filename in '%s'.\n", executableDir );
+
+ *pLastSlash = 0;
+
+ // Set the vproject environment variable (vtex doesn't allow game yet).
+ char envStr[MAX_PATH];
+ _snprintf( envStr, sizeof( envStr ), "vproject=%s", pBaseDir );
+ putenv( envStr );
+
+ // Call vtex on this texture now.
+ char vtexCommand[1024];
+ sprintf( vtexCommand, "%s\\vtex.exe -quiet -nopause \"%s\"", executableDir, pFilename );
+ if ( system( vtexCommand ) != 0 )
+ {
+ Error( "\tCommand '%s' failed!\n", vtexCommand );
+ }
+}
+
+
+void WriteOutputFiles(
+ const char *pBaseDir,
+ const char *pSubDir,
+ const char *pName,
+ bool bAllowTranslucent,
+ byte *buffer,
+ int width,
+ int height,
+ byte *pPalette,
+ bool bVTex
+)
+{
+ bool bTranslucent, bResized;
+ bool bPowerOf2 = true;
+
+ char tgaFilename[1024];
+ sprintf( tgaFilename, "%s\\materialsrc\\%s\\%s.tga", pBaseDir, pSubDir, pName );
+ if ( !WriteTGAFile(
+ tgaFilename,
+ bAllowTranslucent,
+ buffer,
+ width,
+ height,
+ pPalette,
+ bPowerOf2,
+ &bTranslucent,
+ &bResized ) )
+ {
+ Error( "\tError writing %s.\n", tgaFilename );
+ }
+
+ // Write its .VMT file.
+ WriteVMTFile( pBaseDir, pSubDir, pName, bTranslucent );
+
+ // Write a text file for it if it's translucent so we can enable pointsample for vtex.
+// if ( bTranslucent )
+// WriteTXTFile( pBaseDir, pSubDir, pName );
+
+ // Write its .resizeinfo file.
+ if ( bResized )
+ {
+ WriteResizeInfoFile( pBaseDir, pSubDir, pName, width, height );
+ }
+
+ if ( bVTex )
+ {
+ RunVTexOnFile( pBaseDir, tgaFilename );
+ }
+}
+
+
+void EnsureDirectoriesExist( const char *pBaseDir, const char *pSubDir )
+{
+ char materialsrcDir[512], materialsDir[512];
+ sprintf( materialsrcDir, "%s\\materialsrc\\%s", pBaseDir, pSubDir );
+ sprintf( materialsDir, "%s\\materials\\%s", pBaseDir, pSubDir );
+ EnsureDirExists( materialsrcDir );
+ EnsureDirExists( materialsDir );
+}
+
+
+void ProcessWadFile( const char *pWadFilename, const char *pBaseDir, const char *pSubDir, const char *pOnlyTex, bool bVTex )
+{
+ if ( !g_bQuiet )
+ printf( "\n\n[WADFILE %s]\n\n", pWadFilename );
+
+ // If no -subdir was specified, then figure it out from the wad filename.
+ char wadBaseName[512];
+ if ( !pSubDir )
+ {
+ // Get the base wad filename.
+ GetBaseFilename( pWadFilename, wadBaseName );
+ pSubDir = wadBaseName;
+ }
+
+ EnsureDirectoriesExist( pBaseDir, pSubDir );
+
+
+ // Now process all the images in the wad.
+ W_OpenWad( pWadFilename );
+
+ #define MAXLUMP (640*480*85/64)
+ byte inbuffer[MAXLUMP];
+
+ for (int i = 0; i < numlumps; i++)
+ {
+ if ( pOnlyTex && stricmp( pOnlyTex, lumpinfo[i].name ) != 0 )
+ continue;
+
+ fseek( wadhandle, lumpinfo[i].filepos, SEEK_SET );
+ SafeRead ( wadhandle, inbuffer, lumpinfo[i].size );
+
+ miptex_t *qtex = (miptex_t *)inbuffer;
+ int width = LittleLong(qtex->width);
+ int height = LittleLong(qtex->height);
+
+ if ( width <= 0 || height <= 0 || width > 5000 || height > 5000 )
+ {
+ if ( !g_bQuiet )
+ printf("\tskipping %s @ %d size %d (not an image?)\n", lumpinfo[i].name, lumpinfo[i].filepos, lumpinfo[i].size );
+ continue;
+ }
+ else
+ {
+ if ( !g_bQuiet )
+ printf( "\t%s", lumpinfo[i].name );
+ }
+
+ byte *pPalette = inbuffer + LittleLong( qtex->offsets[3] ) + width * height / 64 + 2;
+ byte *psrc, *pdest;
+
+ byte outbuffer[(640+320)*480];
+
+ // The old xwad put the mipmaps in there too, but we don't want that now (usually).
+ // copy in 0 image
+ psrc = inbuffer + LittleLong( qtex->offsets[0] );
+ pdest = outbuffer;
+ for (int t = 0; t < height; t++)
+ {
+ memcpy( pdest + t * width, psrc + t * width, width );
+ }
+
+
+ WriteOutputFiles(
+ pBaseDir, // base directory
+ pSubDir, // subdir under materials
+ qtex->name, // filename (w/o extension)
+ qtex->name[0] == '{', // allow transparency?
+ outbuffer,
+ width,
+ height,
+ pPalette,
+ bVTex
+ );
+
+ if ( !g_bQuiet )
+ printf( "\n" );
+ }
+}
+
+
+void ProcessBMPFile( const char *pBaseDir, const char *pSubDir, const char *pFilename, bool bVTex )
+{
+ if ( !g_bQuiet )
+ printf( "[%s]\n", pFilename );
+
+ if ( !pSubDir )
+ pSubDir = ".";
+
+ // First make directories under materialsrc and materials if they don't exist.
+ EnsureDirectoriesExist( pBaseDir, pSubDir );
+
+ // Read in the 8-bit BMP file.
+ FILE *fp = fopen( pFilename, "rb" );
+ if ( !fp )
+ Error( "ProcessBMPFile( %s ) can't open the file for reading.\n", pFilename );
+
+ BITMAPFILEHEADER bfh;
+ BITMAPINFOHEADER bih;
+ unsigned char pixelData[512*512];
+
+ SafeRead( fp, &bfh, sizeof( bfh ) );
+ SafeRead( fp, &bih, sizeof( bih ) );
+
+ // Make sure it's an 8-bit one like we want.
+ if ( bih.biSize != sizeof( bih ) ||
+ bih.biPlanes != 1 ||
+ bih.biBitCount != 8 ||
+ bih.biCompression != BI_RGB ||
+ bih.biHeight < 0 ||
+ bih.biWidth * bih.biHeight > sizeof( pixelData ) )
+ {
+ Error( "ProcessBMPFile( %s ) - invalid format.\n", pFilename );
+ }
+
+ int nColorsUsed = 256;
+ if ( bih.biClrUsed != 0 )
+ {
+ nColorsUsed = bih.biClrUsed;
+ if ( nColorsUsed > 256 )
+ Error( "ProcessBMPFile( %s ) - bih.biClrUsed = %d.\n", pFilename, bih.biClrUsed );
+ }
+
+ RGBQUAD quadPalette[256];
+ SafeRead( fp, quadPalette, sizeof( quadPalette[0] ) * nColorsUsed );
+
+ // Usually, bfOffBits is the same place we are at now, but sometimes it's a little different.
+ fseek( fp, bfh.bfOffBits, SEEK_SET );
+
+ // Now read the bitmap data.
+ SafeRead( fp, pixelData, bih.biWidth * bih.biHeight );
+
+ fclose( fp );
+
+
+ // Convert the palette.
+ byte palette[256][3];
+ for ( int i=0; i < 256; i++ )
+ {
+ palette[i][0] = quadPalette[i].rgbRed;
+ palette[i][1] = quadPalette[i].rgbGreen;
+ palette[i][2] = quadPalette[i].rgbBlue;
+ }
+
+ // Unflip the pixel data.
+ for ( int y=0; y < bih.biHeight / 2; y++ )
+ {
+ byte tempLine[1024];
+ memcpy( tempLine, &pixelData[y*bih.biWidth], bih.biWidth );
+ memcpy( &pixelData[y*bih.biWidth], &pixelData[(bih.biHeight-y-1)*bih.biWidth], bih.biWidth );
+ memcpy( &pixelData[(bih.biHeight-y-1)*bih.biWidth], tempLine, bih.biWidth );
+ }
+
+
+ char baseFilename[512];
+ GetBaseFilename( pFilename, baseFilename );
+
+ // Save it out.
+ WriteOutputFiles(
+ pBaseDir, // base directory
+ pSubDir, // subdir under materials
+ baseFilename, // filename (w/o extension)
+ g_bBMPAllowTranslucent, // allow transparency
+ pixelData,
+ bih.biWidth,
+ bih.biHeight,
+ (byte*)palette,
+ bVTex
+ );
+}
+
+
+void ProcessSPRFile( const char *pBaseDir, const char *pSubDir, const char *pFilename, bool bVTex )
+{
+ if ( !g_bQuiet )
+ printf( "[%s]\n", pFilename );
+
+ if ( !pSubDir )
+ pSubDir = ".";
+
+ char baseFilename[512];
+ GetBaseFilename( pFilename, baseFilename );
+
+ // First make directories under materialsrc and materials if they don't exist.
+ EnsureDirectoriesExist( pBaseDir, pSubDir );
+
+ // Read in the SPR file.
+ FILE *fp = fopen( pFilename, "rb" );
+ if ( !fp )
+ Error( "ProcessSPRFile( %s ) can't open the file for reading.\n", pFilename );
+
+ dsprite_t header;
+ SafeRead( fp, &header, sizeof( header ) );
+
+ // Make sure it's a sprite file.
+ if ( ((header.ident>>0) & 0xFF) != 'I' ||
+ ((header.ident>>8) & 0xFF) != 'D' ||
+ ((header.ident>>16) & 0xFF) != 'S' ||
+ ((header.ident>>24) & 0xFF) != 'P' )
+ {
+ Warning( "WARNING: sprite %s is not a sprite file. Skipping.\n", pFilename );
+ fclose( fp );
+ return;
+ }
+
+ if ( header.version != 2 )
+ {
+ Warning( "WARNING: sprite %s is not a version 2 sprite file. Skipping.\n", pFilename );
+ fclose( fp );
+ return;
+ }
+
+ // Read the palette.
+ short cnt;
+ byte palette[768];
+ SafeRead( fp, &cnt, sizeof( cnt ) );
+ SafeRead( fp, palette, sizeof( palette ) );
+
+ // Read the frames.
+ int i;
+ for ( i=0; i < header.numframes; i++ )
+ {
+ spriteframetype_t type;
+ SafeRead( fp, &type, sizeof( type ) );
+ if ( type == SPR_SINGLE )
+ {
+ dspriteframe_t frame;
+ SafeRead( fp, &frame, sizeof( frame ) );
+ if ( frame.width > 5000 || frame.height > 5000 || frame.width < 1 || frame.height < 1 )
+ {
+ Warning( "WARNING: sprite %s has an invalid frame size (%d x %d) for frame %d.\n", pFilename, frame.width, frame.height, i );
+ fclose( fp );
+ return;
+ }
+
+ byte *frameData = new byte[frame.width * frame.height];
+ SafeRead( fp, frameData, frame.width * frame.height );
+
+ Msg( "\tFrame %d ", i );
+
+ // Write the TGA file for this frame.
+ bool bTranslucent, bResized;
+ char frameFilename[512];
+ _snprintf( frameFilename, sizeof( frameFilename ), "%s\\materialsrc\\%s\\%s%03d.tga", pBaseDir, pSubDir, baseFilename, i );
+ if ( !WriteTGAFile(
+ frameFilename,
+ g_bBMPAllowTranslucent,
+ frameData,
+ frame.width,
+ frame.height,
+ palette,
+ true, // allow power-of-2
+ &bTranslucent,
+ &bResized ) )
+ {
+ Error( "\tError writing %s.\n", frameFilename );
+ }
+
+ if ( !g_bQuiet )
+ printf( "\n" );
+
+ delete [] frameData;
+ }
+ else if ( type == SPR_GROUP )
+ {
+ Error( "Sprite %s uses type SPR_GROUP. Get a programmer to add support for it.\n", pFilename );
+ }
+ else
+ {
+ Warning( "WARNING: sprite %s has an invalid frame type (%d) for frame %d.\n", pFilename, type, i );
+ fclose( fp );
+ return;
+ }
+ }
+
+ fclose( fp );
+
+ //
+ // Generate a .txt file for the sprite.
+ //
+ char txtFilename[512];
+ sprintf( txtFilename, "%s\\materialsrc\\%s\\%s.txt", pBaseDir, pSubDir, baseFilename );
+
+ fp = fopen( txtFilename, "wt" );
+ if ( !fp )
+ Error( "\tProcessSPRFile: can't open %s for writing.\n", txtFilename );
+
+ fprintf( fp, "\"startframe\" \"0\"\n" );
+ fprintf( fp, "\"endframe\" \"%d\"\n", header.numframes-1 );
+ fprintf( fp, "\"nomip\" \"1\"\n" );
+ fprintf( fp, "\"nolod\" \"1\"\n" );
+ fclose( fp );
+
+ //
+ // Run VTEX on the .txt file?
+ //
+ if ( bVTex )
+ {
+ RunVTexOnFile( pBaseDir, txtFilename );
+ }
+
+ //
+ // Generate a .vmt file.
+ //
+ char vmtFilename[512];
+ _snprintf( vmtFilename, sizeof( vmtFilename ), "%s\\materials\\%s\\%s.vmt", pBaseDir, pSubDir, baseFilename );
+ fp = fopen( vmtFilename, "wt" );
+ if ( !fp )
+ Error( "\tProcessSPRFile: can't open %s for writing.\n", vmtFilename );
+
+ if ( g_pShader == g_pDefaultShader )
+ fprintf( fp, "\"UnlitGeneric\"\n" );
+ else
+ fprintf( fp, "\"%s\"\n", g_pShader );
+
+ fprintf( fp, "{\n" );
+ fprintf( fp, "\t\"$spriteorientation\" \"vp_parallel\"\n" );
+ fprintf( fp, "\t\"$spriteorigin\" \"[ 0.50 0.50 ]\"\n" );
+ fprintf( fp, "\t\"$basetexture\" \"%s/%s\"\n", pSubDir, baseFilename );
+
+ for( i=0;i<g_NumVMTParams;i++ )
+ {
+ fprintf( fp, "\t\"%s\" \"%s\"\n", g_VMTParams[i].m_szParam, g_VMTParams[i].m_szValue );
+ }
+
+ fprintf( fp, "}" );
+
+ fclose( fp );
+}
+
+
+void ExtractDirectory( const char *pFilename, char *prefix )
+{
+ const char *pSlash = strrchr( pFilename, '/' );
+ if ( strrchr( pFilename, '\\' ) > pSlash )
+ pSlash = strrchr( pFilename, '\\' );
+
+ if ( pSlash )
+ {
+ memcpy( prefix, pFilename, pSlash - pFilename );
+ prefix[ pSlash - pFilename ] = 0;
+ }
+ else
+ {
+ strcpy( prefix, ".\\" );
+ }
+}
+
+
+// This allows them to have a WAD or BMP under their materialsrc directory and it'll try to figure out
+// all the other parameters for them.
+bool DragAndDropCheck(
+ const char **pBaseDir,
+ const char **pSubDir,
+ const char **pWadFilenames,
+ const char **pBMPFilenames,
+ const char **pSPRFilenames,
+ bool *bVTex )
+{
+ const char *pLastParam = __argv[__argc-1];
+
+ // Get the first argument in upper case.
+ char arg1[512];
+ strncpy( arg1, pLastParam, sizeof( arg1 ) );
+ strupr( arg1 );
+
+ // Only handle it if there's a full path (with a colon).
+ if ( !strchr( arg1, ':' ) )
+ return false;
+
+ if ( strstr( arg1, ".WAD" ) )
+ *pWadFilenames = pLastParam;
+ else if ( strstr( arg1, ".BMP" ) )
+ *pBMPFilenames = pLastParam;
+ else if ( strstr( arg1, ".SPR" ) )
+ *pSPRFilenames = pLastParam;
+ else
+ return false;
+
+ // Ok, we know that argv[1] has a valid filename. Is it under materialsrc?
+ char *pMatSrc = strstr( arg1, "MATERIALSRC" );
+ if ( !pMatSrc || pMatSrc == arg1 )
+ return false;
+
+ // The base directory is everything before materialsrc.
+ static char baseDir[512];
+ *pBaseDir = baseDir;
+ memcpy( baseDir, arg1, pMatSrc-arg1 );
+ baseDir[pMatSrc-arg1-1] = 0;
+
+ // The subdirectory is everything after materialsrc, minus the filename.
+ char *pSubDirSrc = pMatSrc + strlen( "MATERIALSRC" ) + 1;
+ char *pEnd = strrchr( pSubDirSrc, '\\' );
+ if ( strrchr( pSubDirSrc, '/' ) > pEnd )
+ pEnd = strrchr( pSubDirSrc, '/' );
+
+ if ( !pEnd )
+ return false;
+
+ static char subDir[512];
+ *pSubDir = subDir;
+ memcpy( subDir, pSubDirSrc, pEnd - pSubDirSrc );
+ subDir[pEnd-pSubDirSrc] = 0;
+
+ // Always use vtex in drag-and-drop mode.
+ *bVTex = true;
+ return true;
+}
+
+
+int main (int argc, char **argv)
+{
+ if (argc < 2)
+ {
+ return PrintUsage( "" );
+ }
+
+ bool bWriteTGA = true;
+ bool bWriteBMP = false;
+ bool bPowerOf2 = true;
+ bool bAutoDir = false;
+
+ bool bVTex = false;
+ const char *pBaseDir = NULL;
+ const char *pWadFilenames = NULL;
+ const char *pBMPFilenames = NULL;
+ const char *pSPRFilenames = NULL;
+ const char *pSubDir = NULL;
+ const char *pOnlyTex = NULL;
+
+ // Scan for options.
+ for ( int i=1; i < argc; i++ )
+ {
+ if ( (i+2) < argc )
+ {
+ if ( stricmp( argv[i], "-vmtparam" ) == 0 && g_NumVMTParams < MAX_VMT_PARAMS )
+ {
+ g_VMTParams[g_NumVMTParams].m_szParam = argv[i+1];
+ g_VMTParams[g_NumVMTParams].m_szValue = argv[i+2];
+
+ if( !g_bQuiet )
+ {
+ fprintf( stderr, "Adding .vmt parameter: \"%s\"\t\"%s\"\n",
+ g_VMTParams[g_NumVMTParams].m_szParam,
+ g_VMTParams[g_NumVMTParams].m_szValue );
+ }
+
+ g_NumVMTParams++;
+
+ i += 2;
+ }
+ }
+
+ if ( (i+1) < argc )
+ {
+ if ( stricmp( argv[i], "-basedir" ) == 0 )
+ {
+ pBaseDir = argv[i+1];
+ ++i;
+ }
+ else if ( stricmp( argv[i], "-wadfile" ) == 0 )
+ {
+ pWadFilenames = argv[i+1];
+ ++i;
+ }
+ else if ( stricmp( argv[i], "-bmpfile" ) == 0 )
+ {
+ pBMPFilenames = argv[i+1];
+ ++i;
+ }
+ else if ( stricmp( argv[i], "-sprfile" ) == 0 )
+ {
+ pSPRFilenames = argv[i+1];
+ ++i;
+ }
+ else if ( stricmp( argv[i], "-OnlyTex" ) == 0 )
+ {
+ pOnlyTex = argv[i+1];
+ ++i;
+ }
+ else if ( stricmp( argv[i], "-SubDir" ) == 0 )
+ {
+ pSubDir = argv[i+1];
+ ++i;
+ }
+ else if ( stricmp( argv[i], "-shader" ) == 0 )
+ {
+ g_pShader = argv[i+1];
+ ++i;
+ }
+ }
+
+ if ( stricmp( argv[i], "-AutoDir" ) == 0 )
+ {
+ bAutoDir = true;
+ }
+ else if ( stricmp( argv[i], "-Transparent" ) == 0 )
+ {
+ g_bBMPAllowTranslucent = true;
+ }
+ else if ( stricmp( argv[i], "-Decal" ) == 0 )
+ {
+ g_bDecal = true;
+ if ( g_pShader == g_pDefaultShader )
+ g_pShader = "DecalModulate";
+ }
+ else if ( stricmp( argv[i], "-quiet" ) == 0 )
+ {
+ g_bQuiet = true;
+ }
+ else if ( stricmp( argv[i], "-vtex" ) == 0 )
+ {
+ bVTex = true;
+ }
+ }
+
+ if ( bAutoDir )
+ {
+ if ( !DragAndDropCheck( &pBaseDir, &pSubDir, &pWadFilenames, &pBMPFilenames, &pSPRFilenames, &bVTex ) )
+ return PrintUsage( "-AutoDir failed to setup directories." );
+ }
+
+ if ( !pBaseDir || (!pWadFilenames && !pBMPFilenames && !pSPRFilenames) )
+ return PrintUsage( "Missing a parameter.\n" );
+
+ char prefix[512];
+
+ // Scan through each wadfile.
+ if ( pWadFilenames )
+ {
+ ExtractDirectory( pWadFilenames, prefix );
+
+ _finddata_t findData;
+ long handle = _findfirst( pWadFilenames, &findData );
+ if ( handle != -1 )
+ {
+ do
+ {
+ if ( !(findData.attrib & _A_SUBDIR) )
+ {
+ char fullFilename[512];
+ sprintf( fullFilename, "%s\\%s", prefix, findData.name );
+ ProcessWadFile( fullFilename, pBaseDir, pSubDir, pOnlyTex, bVTex );
+ }
+ } while( _findnext( handle, &findData ) == 0 );
+
+ _findclose( handle );
+ }
+ }
+
+ // Process BMP files.
+ if ( pBMPFilenames )
+ {
+ ExtractDirectory( pBMPFilenames, prefix );
+
+ _finddata_t findData;
+ long handle = _findfirst( pBMPFilenames, &findData );
+ if ( handle != -1 )
+ {
+ do
+ {
+ if ( !(findData.attrib & _A_SUBDIR) )
+ {
+ char fullFilename[512];
+ sprintf( fullFilename, "%s\\%s", prefix, findData.name );
+ ProcessBMPFile( pBaseDir, pSubDir, fullFilename, bVTex );
+ }
+ } while( _findnext( handle, &findData ) == 0 );
+
+ _findclose( handle );
+ }
+ }
+
+ if ( pSPRFilenames )
+ {
+ ExtractDirectory( pSPRFilenames, prefix );
+
+ _finddata_t findData;
+ long handle = _findfirst( pSPRFilenames, &findData );
+ if ( handle != -1 )
+ {
+ do
+ {
+ if ( !(findData.attrib & _A_SUBDIR) )
+ {
+ char fullFilename[512];
+ sprintf( fullFilename, "%s\\%s", prefix, findData.name );
+ ProcessSPRFile( pBaseDir, pSubDir, fullFilename, bVTex );
+ }
+ } while( _findnext( handle, &findData ) == 0 );
+
+ _findclose( handle );
+ }
+ }
+
+ PrintExitStuff();
+ return 0;
+}
+
diff --git a/utils/xwad/xwad.vcproj b/utils/xwad/xwad.vcproj
new file mode 100644
index 0000000..76bc9d8
--- /dev/null
+++ b/utils/xwad/xwad.vcproj
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="xwad"
+ ProjectGUID="{B850012C-98A2-42F7-B023-9F65C448D938}"
+ SccProjectName=""
+ SccAuxPath=""
+ SccLocalPath=""
+ SccProvider="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\Debug"
+ IntermediateDirectory=".\Debug"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\Debug/xwad.pch"
+ AssemblerListingLocation=".\Debug/"
+ ObjectFile=".\Debug/"
+ ProgramDataBaseFileName=".\Debug/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="if exist ..\..\..\game\bin\&quot;$(TargetName)&quot;.exe attrib -r ..\..\..\game\bin\&quot;$(TargetName)&quot;.exe
+copy &quot;$(TargetPath)&quot; ..\..\..\game\bin\&quot;$(TargetName)&quot;.exe
+if exist ..\..\..\game\bin\&quot;$(TargetName)&quot;.pdb attrib -r ..\..\..\game\bin\&quot;$(TargetName)&quot;.pdb
+copy &quot;$(TargetPath)&quot; ..\..\..\game\bin\&quot;$(TargetName)&quot;.pdb"
+ Outputs="..\..\..\game\bin\xwad.exe;..\..\..\game\bin\xwad.pdb"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile=".\Debug/xwad.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\Debug/xwad.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\Debug/xwad.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\Release"
+ IntermediateDirectory=".\Release"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ StringPooling="TRUE"
+ RuntimeLibrary="4"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\Release/xwad.pch"
+ AssemblerListingLocation=".\Release/"
+ ObjectFile=".\Release/"
+ ProgramDataBaseFileName=".\Release/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="if exist ..\..\..\game\bin\&quot;$(TargetName)&quot;.exe attrib -r ..\..\..\game\bin\&quot;$(TargetName)&quot;.exe
+copy &quot;$(TargetPath)&quot; ..\..\..\game\bin\&quot;$(TargetName)&quot;.exe
+if exist ..\..\..\game\bin\&quot;$(TargetName)&quot;.pdb attrib -r ..\..\..\game\bin\&quot;$(TargetName)&quot;.pdb
+copy &quot;$(TargetPath)&quot; ..\..\..\game\bin\&quot;$(TargetName)&quot;.pdb"
+ Outputs="..\..\..\game\bin\xwad.exe;..\..\..\game\bin\xwad.pdb"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile=".\Release/xwad.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ ProgramDatabaseFile=".\Release/xwad.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\Release/xwad.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
+ <File
+ RelativePath="goldsrc_bspfile.h">
+ </File>
+ <File
+ RelativePath="goldsrc_standin.cpp">
+ </File>
+ <File
+ RelativePath="goldsrc_standin.h">
+ </File>
+ <File
+ RelativePath="lbmlib.cpp">
+ </File>
+ <File
+ RelativePath="lbmlib.h">
+ </File>
+ <File
+ RelativePath="wadlib.cpp">
+ </File>
+ <File
+ RelativePath="wadlib.h">
+ </File>
+ <File
+ RelativePath="xwad.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl">
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>