Jake Todd avatar Jake Todd committed 42c613d

Add files in common.

Comments (0)

Files changed (18)

+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <stdarg.h>
+#include "cmdlib.h"
+#include <math.h>
+#include "mathlib.h"
+#include "bspfile.h"
+
+//=============================================================================
+
+int nummodels;
+dmodel_t dmodels[MAX_MAP_MODELS];
+
+int visdatasize;
+byte dvisdata[MAX_MAP_VISIBILITY];
+
+int lightdatasize;
+byte dlightdata[MAX_MAP_LIGHTING];
+
+int texdatasize;
+byte dtexdata[MAX_MAP_MIPTEX];	// (dmiptexlump_t)
+
+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 numclipnodes;
+dclipnode_t dclipnodes[MAX_MAP_CLIPNODES];
+
+int numedges;
+dedge_t dedges[MAX_MAP_EDGES];
+
+int nummarksurfaces;
+unsigned short dmarksurfaces[MAX_MAP_MARKSURFACES];
+
+int numsurfedges;
+int dsurfedges[MAX_MAP_SURFEDGES];
+
+//=============================================================================
+
+/*
+=============
+SwapBSPFile
+
+Byte swaps all data in a bsp file.
+=============
+*/
+void
+SwapBSPFile(qboolean todisk)
+{
+	int i, j, c;
+	dmodel_t *d;
+	dmiptexlump_t *mtl;
+
+
+// models   
+	for(i = 0; i < nummodels; i++) {
+		d = &dmodels[i];
+
+		for(j = 0; j < MAX_MAP_HULLS; j++)
+			d->headnode[j] = LittleLong(d->headnode[j]);
+
+		d->visleafs = LittleLong(d->visleafs);
+		d->firstface = LittleLong(d->firstface);
+		d->numfaces = LittleLong(d->numfaces);
+
+		for(j = 0; j < 3; j++) {
+			d->mins[j] = LittleFloat(d->mins[j]);
+			d->maxs[j] = LittleFloat(d->maxs[j]);
+			d->origin[j] = LittleFloat(d->origin[j]);
+		}
+	}
+
+//
+// vertexes
+//
+	for(i = 0; i < 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].miptex = LittleLong(texinfo[i].miptex);
+		texinfo[i].flags = LittleLong(texinfo[i].flags);
+	}
+
+//
+// faces
+//
+	for(i = 0; i < numfaces; i++) {
+		dfaces[i].texinfo = LittleShort(dfaces[i].texinfo);
+		dfaces[i].planenum = LittleShort(dfaces[i].planenum);
+		dfaces[i].side = LittleShort(dfaces[i].side);
+		dfaces[i].lightofs = LittleLong(dfaces[i].lightofs);
+		dfaces[i].firstedge = LittleLong(dfaces[i].firstedge);
+		dfaces[i].numedges = LittleShort(dfaces[i].numedges);
+	}
+
+//
+// nodes
+//
+	for(i = 0; i < numnodes; i++) {
+		dnodes[i].planenum = LittleLong(dnodes[i].planenum);
+		for(j = 0; j < 3; j++) {
+			dnodes[i].mins[j] = LittleShort(dnodes[i].mins[j]);
+			dnodes[i].maxs[j] = LittleShort(dnodes[i].maxs[j]);
+		}
+		dnodes[i].children[0] = LittleShort(dnodes[i].children[0]);
+		dnodes[i].children[1] = LittleShort(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);
+		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].firstmarksurface = LittleShort(dleafs[i].firstmarksurface);
+		dleafs[i].nummarksurfaces = LittleShort(dleafs[i].nummarksurfaces);
+		dleafs[i].visofs = LittleLong(dleafs[i].visofs);
+	}
+
+//
+// clipnodes
+//
+	for(i = 0; i < numclipnodes; i++) {
+		dclipnodes[i].planenum = LittleLong(dclipnodes[i].planenum);
+		dclipnodes[i].children[0] = LittleShort(dclipnodes[i].children[0]);
+		dclipnodes[i].children[1] = LittleShort(dclipnodes[i].children[1]);
+	}
+
+//
+// miptex
+//
+	if(texdatasize) {
+		mtl = (dmiptexlump_t *) dtexdata;
+		if(todisk)
+			c = mtl->nummiptex;
+		else
+			c = LittleLong(mtl->nummiptex);
+		mtl->nummiptex = LittleLong(mtl->nummiptex);
+		for(i = 0; i < c; i++)
+			mtl->dataofs[i] = LittleLong(mtl->dataofs[i]);
+	}
+//
+// marksurfaces
+//
+	for(i = 0; i < nummarksurfaces; i++)
+		dmarksurfaces[i] = LittleShort(dmarksurfaces[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]);
+	}
+}
+
+
+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->version != BSPVERSION)
+		Error("%s is version %i, not %i", filename, i, 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));
+	numclipnodes = CopyLump(LUMP_CLIPNODES, dclipnodes, sizeof(dclipnode_t));
+	numfaces = CopyLump(LUMP_FACES, dfaces, sizeof(dface_t));
+	nummarksurfaces =
+		CopyLump(LUMP_MARKSURFACES, dmarksurfaces, sizeof(dmarksurfaces[0]));
+	numsurfedges =
+		CopyLump(LUMP_SURFEDGES, dsurfedges, sizeof(dsurfedges[0]));
+	numedges = CopyLump(LUMP_EDGES, dedges, sizeof(dedge_t));
+
+	texdatasize = CopyLump(LUMP_TEXTURES, dtexdata, 1);
+	visdatasize = CopyLump(LUMP_VISIBILITY, dvisdata, 1);
+	lightdatasize = CopyLump(LUMP_LIGHTING, dlightdata, 1);
+	entdatasize = CopyLump(LUMP_ENTITIES, dentdata, 1);
+
+	free(header);				// everything has been copied out
+
+//
+// swap everything
+//  
+	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->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_CLIPNODES, dclipnodes, numclipnodes * sizeof(dclipnode_t));
+	AddLump(LUMP_MARKSURFACES, dmarksurfaces,
+			nummarksurfaces * sizeof(dmarksurfaces[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_LIGHTING, dlightdata, lightdatasize);
+	AddLump(LUMP_VISIBILITY, dvisdata, visdatasize);
+	AddLump(LUMP_ENTITIES, dentdata, entdatasize);
+	AddLump(LUMP_TEXTURES, dtexdata, texdatasize);
+
+	fseek(wadfile, 0, SEEK_SET);
+	SafeWrite(wadfile, header, sizeof(dheader_t));
+	fclose(wadfile);
+}
+
+//============================================================================
+
+/*
+=============
+PrintBSPFileSizes
+
+Dumps info about current file
+=============
+*/
+void
+PrintBSPFileSizes(void)
+{
+	printf("%5i planes       %6i\n", numplanes,
+		   (int)(numplanes * sizeof(dplane_t)));
+	printf("%5i vertexes     %6i\n", numvertexes,
+		   (int)(numvertexes * sizeof(dvertex_t)));
+	printf("%5i nodes        %6i\n", numnodes,
+		   (int)(numnodes * sizeof(dnode_t)));
+	printf("%5i texinfo      %6i\n", numtexinfo,
+		   (int)(numtexinfo * sizeof(texinfo_t)));
+	printf("%5i faces        %6i\n", numfaces,
+		   (int)(numfaces * sizeof(dface_t)));
+	printf("%5i clipnodes    %6i\n", numclipnodes,
+		   (int)(numclipnodes * sizeof(dclipnode_t)));
+	printf("%5i leafs        %6i\n", numleafs,
+		   (int)(numleafs * sizeof(dleaf_t)));
+	printf("%5i marksurfaces %6i\n", nummarksurfaces,
+		   (int)(nummarksurfaces * sizeof(dmarksurfaces[0])));
+	printf("%5i surfedges    %6i\n", numsurfedges,
+		   (int)(numsurfedges * sizeof(dmarksurfaces[0])));
+	printf("%5i edges        %6i\n", numedges,
+		   (int)(numedges * sizeof(dedge_t)));
+	if(!texdatasize)
+		printf("    0 textures          0\n");
+	else
+		printf("%5i textures     %6i\n",
+			   ((dmiptexlump_t *) dtexdata)->nummiptex, texdatasize);
+	printf("      lightdata    %6i\n", lightdatasize);
+	printf("      visdata      %6i\n", visdatasize);
+	printf("      entdata      %6i\n", entdatasize);
+}
+// upper design bounds
+
+#define	MAX_MAP_HULLS		4
+
+#define	MAX_MAP_MODELS		256
+#define	MAX_MAP_BRUSHES		4096
+#define	MAX_MAP_ENTITIES	1024
+#define	MAX_MAP_ENTSTRING	65536
+
+#define	MAX_MAP_PLANES		8192
+#define	MAX_MAP_NODES		32767		// because negative shorts are contents
+#define	MAX_MAP_CLIPNODES	32767		//
+#define	MAX_MAP_LEAFS		32767		// 
+#define	MAX_MAP_VERTS		65535
+#define	MAX_MAP_FACES		65535
+#define	MAX_MAP_MARKSURFACES 65535
+#define	MAX_MAP_TEXINFO		4096
+#define	MAX_MAP_EDGES		256000
+#define	MAX_MAP_SURFEDGES	512000
+#define	MAX_MAP_MIPTEX		0x200000
+#define	MAX_MAP_LIGHTING	0x100000
+#define	MAX_MAP_VISIBILITY	0x100000
+
+// key / value pair sizes
+#define	MAX_KEY		32
+#define	MAX_VALUE	1024
+
+
+#define BSPVERSION	29
+
+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;
+
+
+
+#define	CONTENTS_EMPTY		-1
+#define	CONTENTS_SOLID		-2
+#define	CONTENTS_WATER		-3
+#define	CONTENTS_SLIME		-4
+#define	CONTENTS_LAVA		-5
+#define	CONTENTS_SKY		-6
+
+// !!! if this is changed, it must be changed in asm_i386.h too !!!
+typedef struct
+{
+	int			planenum;
+	short		children[2];	// negative numbers are -(leafs+1), not nodes
+	short		mins[3];		// for sphere culling
+	short		maxs[3];
+	unsigned short	firstface;
+	unsigned short	numfaces;	// counting both sides
+} 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
+
+// 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	LoadBSPFile (char *filename);
+void	WriteBSPFile (char *filename);
+void	PrintBSPFileSizes (void);
+
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include "cmdlib.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define PATHSEPERATOR   '/'
+
+// set these before calling CheckParm
+int myargc;
+char **myargv;
+
+char com_token[1024];
+qboolean com_eof;
+
+qboolean archive;
+char archivedir[1024];
+
+
+/*
+=================
+Error
+
+For abnormal program terminations
+=================
+*/
+void
+Error(char *error, ...)
+{
+	va_list argptr;
+
+	printf("************ ERROR ************\n");
+
+	va_start(argptr, error);
+	vprintf(error, argptr);
+	va_end(argptr);
+	printf("\n");
+	exit(1);
+}
+
+
+/*
+
+qdir will hold the path up to the quake directory, including the slash
+
+  f:\quake\
+  /raid/quake/
+
+gamedir will hold qdir + the game directory (id1, id2, etc)
+
+  */
+
+char qdir[1024];
+char gamedir[1024];
+
+void
+SetQdirFromPath(char *path)
+{
+	char temp[1024];
+	char *c;
+
+	if(!(path[0] == '/' || path[0] == '\\' || path[1] == ':')) {	// path is partial
+		Q_getwd(temp);
+		strcat(temp, path);
+		path = temp;
+	}
+	// search for "quake" in path
+
+	for(c = path; *c; c++)
+		if(!Q_strncasecmp(c, "quake", 5)) {
+			strncpy(qdir, path, c + 6 - path);
+			printf("qdir: %s\n", qdir);
+			c += 6;
+			while(*c) {
+				if(*c == '/' || *c == '\\') {
+					strncpy(gamedir, path, c + 1 - path);
+					printf("gamedir: %s\n", gamedir);
+					return;
+				}
+				c++;
+			}
+			Error("No gamedir in %s", path);
+			return;
+		}
+	Error("SeetQdirFromPath: no 'quake' in %s", path);
+}
+
+char *
+ExpandPath(char *path)
+{
+	static char full[1024];
+
+	if(!qdir)
+		Error("ExpandPath called without qdir set");
+	if(path[0] == '/' || path[0] == '\\' || path[1] == ':')
+		return path;
+	sprintf(full, "%s%s", qdir, path);
+	return full;
+}
+
+char *
+ExpandPathAndArchive(char *path)
+{
+	char *expanded;
+	char archivename[1024];
+
+	expanded = ExpandPath(path);
+
+	if(archive) {
+		sprintf(archivename, "%s/%s", archivedir, path);
+		CopyFile(expanded, archivename);
+	}
+	return expanded;
+}
+
+
+char *
+copystring(char *s)
+{
+	char *b;
+
+	b = 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)
+{
+#ifdef WIN32
+	_getcwd(out, 256);
+	strcat(out, "\\");
+#else
+	getwd(out);
+#endif
+}
+
+
+void
+Q_mkdir(char *path)
+{
+#ifdef WIN32
+	if(_mkdir(path) != -1)
+		return;
+#else
+	if(mkdir(path, 0777) != -1)
+		return;
+#endif
+	if(errno != EEXIST)
+		Error("mkdir %s: %s", path, strerror(errno));
+}
+
+/*
+============
+FileTime
+
+returns -1 if not present
+============
+*/
+int
+FileTime(char *path)
+{
+	struct stat buf;
+
+	if(stat(path, &buf) == -1)
+		return -1;
+
+	return buf.st_mtime;
+}
+
+
+
+/*
+==============
+COM_Parse
+
+Parse a token out of a string
+==============
+*/
+char *
+COM_Parse(char *data)
+{
+	int c;
+	int len;
+
+	len = 0;
+	com_token[0] = 0;
+
+	if(!data)
+		return NULL;
+
+// skip whitespace
+  skipwhite:
+	while((c = *data) <= ' ') {
+		if(c == 0) {
+			com_eof = true;
+			return NULL;		// end of file;
+		}
+		data++;
+	}
+
+// skip // comments
+	if(c == '/' && data[1] == '/') {
+		while(*data && *data != '\n')
+			data++;
+		goto skipwhite;
+	}
+
+// handle quoted strings specially
+	if(c == '\"') {
+		data++;
+		do {
+			c = *data++;
+			if(c == '\"') {
+				com_token[len] = 0;
+				return data;
+			}
+			com_token[len] = c;
+			len++;
+		} while(1);
+	}
+// parse single characters
+	if(c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':') {
+		com_token[len] = c;
+		len++;
+		com_token[len] = 0;
+		return data + 1;
+	}
+// parse a regular word
+	do {
+		com_token[len] = c;
+		data++;
+		len++;
+		c = *data;
+		if(c == '{' || c == '}' || c == ')' || c == '(' || c == '\''
+		   || c == ':')
+			break;
+	} while(c > 32);
+
+	com_token[len] = 0;
+	return data;
+}
+
+
+int
+Q_strncasecmp(char *s1, char *s2, int n)
+{
+	int c1, c2;
+
+	while(1) {
+		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
+		}
+		if(!c1)
+			return 0;			// strings are equal
+	}
+
+	return -1;
+}
+
+int
+Q_strcasecmp(char *s1, char *s2)
+{
+	return Q_strncasecmp(s1, s2, 99999);
+}
+
+
+char *
+strupr(char *start)
+{
+	char *in;
+
+	in = start;
+	while(*in) {
+		*in = toupper(*in);
+		in++;
+	}
+	return start;
+}
+
+char *
+strlower(char *start)
+{
+	char *in;
+
+	in = start;
+	while(*in) {
+		*in = tolower(*in);
+		in++;
+	}
+	return start;
+}
+
+
+/*
+=============================================================================
+
+						MISC FUNCTIONS
+
+=============================================================================
+*/
+
+
+/*
+=================
+CheckParm
+
+Checks for the given parameter in the program's command line arguments
+Returns the argument number (1 to argc-1) or 0 if not present
+=================
+*/
+int
+CheckParm(char *check)
+{
+	int i;
+
+	for(i = 1; i < myargc; i++) {
+		if(!Q_strcasecmp(check, myargv[i]))
+			return i;
+	}
+
+	return 0;
+}
+
+
+
+/*
+================
+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;
+}
+
+
+/*
+==============
+SaveFile
+==============
+*/
+void
+SaveFile(char *filename, void *buffer, int count)
+{
+	FILE *f;
+
+	f = SafeOpenWrite(filename);
+	SafeWrite(f, buffer, count);
+	fclose(f);
+}
+
+
+
+void
+DefaultExtension(char *path, char *extension)
+{
+	char *src;
+
+//
+// if path doesn't have a .EXT, append extension
+// (extension should include the .)
+//
+	src = path + strlen(path) - 1;
+
+	while(*src != PATHSEPERATOR && src != path) {
+		if(*src == '.')
+			return;				// it has an extension
+		src--;
+	}
+
+	strcat(path, extension);
+}
+
+
+void
+DefaultPath(char *path, char *basepath)
+{
+	char temp[128];
+
+	if(path[0] == PATHSEPERATOR)
+		return;					// absolute path location
+	strcpy(temp, path);
+	strcpy(path, basepath);
+	strcat(path, temp);
+}
+
+
+void
+StripFilename(char *path)
+{
+	int length;
+
+	length = strlen(path) - 1;
+	while(length > 0 && path[length] != PATHSEPERATOR)
+		length--;
+	path[length] = 0;
+}
+
+void
+StripExtension(char *path)
+{
+	int length;
+
+	length = strlen(path) - 1;
+	while(length > 0 && path[length] != '.') {
+		length--;
+		if(path[length] == '/')
+			return;				// no extension
+	}
+	if(length)
+		path[length] = 0;
+}
+
+
+/*
+====================
+Extract file parts
+====================
+*/
+void
+ExtractFilePath(char *path, char *dest)
+{
+	char *src;
+
+	src = path + strlen(path) - 1;
+
+//
+// back up until a \ or the start
+//
+	while(src != path && *(src - 1) != PATHSEPERATOR)
+		src--;
+
+	memcpy(dest, path, src - path);
+	dest[src - path] = 0;
+}
+
+void
+ExtractFileBase(char *path, char *dest)
+{
+	char *src;
+
+	src = path + strlen(path) - 1;
+
+//
+// back up until a \ or the start
+//
+	while(src != path && *(src - 1) != PATHSEPERATOR)
+		src--;
+
+	while(*src && *src != '.') {
+		*dest++ = *src++;
+	}
+	*dest = 0;
+}
+
+void
+ExtractFileExtension(char *path, char *dest)
+{
+	char *src;
+
+	src = path + strlen(path) - 1;
+
+//
+// back up until a . or the start
+//
+	while(src != path && *(src - 1) != '.')
+		src--;
+	if(src == path) {
+		*dest = 0;				// no extension
+		return;
+	}
+
+	strcpy(dest, src);
+}
+
+
+/*
+==============
+ParseNum / ParseHex
+==============
+*/
+int
+ParseHex(char *hex)
+{
+	char *str;
+	int num;
+
+	num = 0;
+	str = hex;
+
+	while(*str) {
+		num <<= 4;
+		if(*str >= '0' && *str <= '9')
+			num += *str - '0';
+		else if(*str >= 'a' && *str <= 'f')
+			num += 10 + *str - 'a';
+		else if(*str >= 'A' && *str <= 'F')
+			num += 10 + *str - 'A';
+		else
+			Error("Bad hex number: %s", hex);
+		str++;
+	}
+
+	return num;
+}
+
+
+int
+ParseNum(char *str)
+{
+	if(str[0] == '$')
+		return ParseHex(str + 1);
+	if(str[0] == '0' && str[1] == 'x')
+		return ParseHex(str + 2);
+	return atol(str);
+}
+
+
+
+/*
+============================================================================
+
+					BYTE ORDER FUNCTIONS
+
+============================================================================
+*/
+
+#ifdef _SGI_SOURCE
+#   define	__BIG_ENDIAN__
+#endif
+
+#ifdef __BIG_ENDIAN__
+
+short
+LittleShort(short l)
+{
+	byte b1, b2;
+
+	b1 = l & 255;
+	b2 = (l >> 8) & 255;
+
+	return (b1 << 8) + b2;
+}
+
+short
+BigShort(short l)
+{
+	return l;
+}
+
+
+int
+LittleLong(int l)
+{
+	byte b1, b2, b3, b4;
+
+	b1 = l & 255;
+	b2 = (l >> 8) & 255;
+	b3 = (l >> 16) & 255;
+	b4 = (l >> 24) & 255;
+
+	return ((int)b1 << 24) + ((int)b2 << 16) + ((int)b3 << 8) + b4;
+}
+
+int
+BigLong(int l)
+{
+	return l;
+}
+
+
+float
+LittleFloat(float l)
+{
+	union {
+		byte b[4];
+		float f;
+	} in, out;
+
+	in.f = l;
+	out.b[0] = in.b[3];
+	out.b[1] = in.b[2];
+	out.b[2] = in.b[1];
+	out.b[3] = in.b[0];
+
+	return out.f;
+}
+
+float
+BigFloat(float l)
+{
+	return l;
+}
+
+
+#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
+
+
+//=======================================================
+
+
+// FIXME: byte swap?
+
+// this is a 16 bit, non-reflected CRC using the polynomial 0x1021
+// and the initial and final xor values shown below...  in other words, the
+// CCITT standard CRC used by XMODEM
+
+#define CRC_INIT_VALUE	0xffff
+#define CRC_XOR_VALUE	0x0000
+
+static unsigned short crctable[256] = {
+	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+	0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+	0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+	0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+	0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+	0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+	0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+	0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+	0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+	0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+	0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+	0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+	0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+	0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+	0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+	0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+	0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+	0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+	0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+	0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+	0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+	0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+	0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+	0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+	0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+	0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+	0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+	0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+	0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+	0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+	0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+	0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+};
+
+void
+CRC_Init(unsigned short *crcvalue)
+{
+	*crcvalue = CRC_INIT_VALUE;
+}
+
+void
+CRC_ProcessByte(unsigned short *crcvalue, byte data)
+{
+	*crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];
+}
+
+unsigned short
+CRC_Value(unsigned short crcvalue)
+{
+	return crcvalue ^ CRC_XOR_VALUE;
+}
+
+//=============================================================================
+
+/*
+============
+CreatePath
+============
+*/
+void
+CreatePath(char *path)
+{
+	char *ofs, c;
+
+	for(ofs = path + 1; *ofs; ofs++) {
+		c = *ofs;
+		if(c == '/' || c == '\\') {	// create the directory
+			*ofs = 0;
+			Q_mkdir(path);
+			*ofs = c;
+		}
+	}
+}
+
+
+/*
+============
+CopyFile
+
+  Used to archive source files
+============
+*/
+void
+CopyFile(char *from, char *to)
+{
+	void *buffer;
+	int length;
+
+	length = LoadFile(from, &buffer);
+	CreatePath(to);
+	SaveFile(to, buffer, length);
+	free(buffer);
+}
+/* <(stdio string stdlib errno ctype time stdarg unistd)^.h>
+ * need to be included before this file */
+typedef enum {false, true} qboolean;
+typedef unsigned char byte;
+
+// the dec offsetof macro doesn't work very well...
+#define myoffsetof(type,identifier) ((size_t)&((type *)0)->identifier)
+
+// set these before calling CheckParm
+extern int myargc;
+extern char **myargv;
+
+char *strupr (char *in);
+char *strlower (char *in);
+int Q_strncasecmp (char *s1, char *s2, int n);
+int Q_strcasecmp (char *s1, char *s2);
+void Q_getwd (char *out);
+
+int filelength (FILE *f);
+int	FileTime (char *path);
+
+void	Q_mkdir (char *path);
+
+extern	char		qdir[1024];
+extern	char		gamedir[1024];
+void SetQdirFromPath (char *path);
+char *ExpandPath (char *path);
+char *ExpandPathAndArchive (char *path);
+
+double I_FloatTime (void);
+
+void	Error (char *error, ...);
+int		CheckParm (char *check);
+
+FILE	*SafeOpenWrite (char *filename);
+FILE	*SafeOpenRead (char *filename);
+void	SafeRead (FILE *f, void *buffer, int count);
+void	SafeWrite (FILE *f, void *buffer, int count);
+
+int		LoadFile (char *filename, void **bufferptr);
+void	SaveFile (char *filename, void *buffer, int count);
+
+void 	DefaultExtension (char *path, char *extension);
+void 	DefaultPath (char *path, char *basepath);
+void 	StripFilename (char *path);
+void 	StripExtension (char *path);
+
+void 	ExtractFilePath (char *path, char *dest);
+void 	ExtractFileBase (char *path, char *dest);
+void	ExtractFileExtension (char *path, char *dest);
+
+int 	ParseNum (char *str);
+
+short	BigShort (short l);
+short	LittleShort (short l);
+int		BigLong (int l);
+int		LittleLong (int l);
+float	BigFloat (float l);
+float	LittleFloat (float l);
+
+char *COM_Parse (char *data);
+
+extern	char		com_token[1024];
+extern	qboolean	com_eof;
+
+char *copystring(char *s);
+
+void CRC_Init(unsigned short *crcvalue);
+void CRC_ProcessByte(unsigned short *crcvalue, byte data);
+unsigned short CRC_Value(unsigned short crcvalue);
+
+void	CreatePath (char *path);
+void CopyFile (char *from, char *to);
+
+extern	qboolean		archive;
+extern	char			archivedir[1024];
+// lbmlib.c
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <stdarg.h>
+#include "cmdlib.h"
+#include "lbmlib.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
+}
+
+/*
+=================
+=
+= 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 = malloc(768);
+			memset(cmapbuffer, 0, 768);
+			memcpy(cmapbuffer, LBM_P, chunklength);
+			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
+				//
+				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 = 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);
+}
+// lbmlib.h
+
+typedef unsigned char	UBYTE;
+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;
+	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);
+
+void WriteLBMfile (char *filename, byte *data, int width, int height
+	, byte *palette);
+// mathlib.c -- math primitives
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include "cmdlib.h"
+#include "mathlib.h"
+#include <math.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];
+}
+
+vec_t
+VectorNormalize(vec3_t v)
+{
+	int i;
+	double length;
+
+	length = 0;
+	for(i = 0; i < 3; i++)
+		length += v[i] * v[i];
+	length = sqrt(length);
+	if(length == 0)
+		return 0;
+
+	for(i = 0; i < 3; i++)
+		v[i] /= length;
+
+	return length;
+}
+
+void
+VectorInverse(vec3_t v)
+{
+	v[0] = -v[0];
+	v[1] = -v[1];
+	v[2] = -v[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;
+}
+/* <math.h> needs to be included before this file */
+#ifndef __MATHLIB__
+#define __MATHLIB__
+
+#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];}
+
+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);
+
+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 v);
+void VectorInverse (vec3_t v);
+void VectorScale (vec3_t v, vec_t scale, vec3_t out);
+
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <stdarg.h>
+#include <math.h>
+#include "cmdlib.h"
+#include "mathlib.h"
+#include "polylib.h"
+
+#define	BOGUS_RANGE	8192
+
+/*
+=============
+AllocWinding
+=============
+*/
+winding_t *
+AllocWinding(int points)
+{
+	winding_t *w;
+	int s;
+
+	s = sizeof(vec_t) * 3 * points + sizeof(int);
+	w = malloc(s);
+	memset(w, 0, s);
+	return 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);
+		VectorNormalize(v2);
+		if(DotProduct(v1, v2) < 0.999) {
+			VectorCopy(w->p[i], p[nump]);
+			nump++;
+		}
+	}
+
+	if(nump == w->numpoints)
+		return;
+
+	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(v1, v2, normal);
+	VectorNormalize(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;
+}
+
+/*
+=============
+WindingCenter
+=============
+*/
+void
+WindingCenter(winding_t * w, vec3_t center)
+{
+	int i;
+	vec3_t d1, d2, cross;
+	float scale;
+
+	VectorCopy(vec3_origin, center);
+	for(i = 0; i < w->numpoints; i++)
+		VectorAdd(w->p[i], center, center);