mirror of
https://github.com/id-Software/Quake-Tools.git
synced 2026-03-20 00:49:35 +01:00
The source release of the qutils.
This commit is contained in:
375
qutils/COMMON/BSPFILE.C
Normal file
375
qutils/COMMON/BSPFILE.C
Normal file
@@ -0,0 +1,375 @@
|
||||
|
||||
#include "cmdlib.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);
|
||||
}
|
||||
|
||||
|
||||
251
qutils/COMMON/BSPFILE.H
Normal file
251
qutils/COMMON/BSPFILE.H
Normal file
@@ -0,0 +1,251 @@
|
||||
|
||||
|
||||
// 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
|
||||
867
qutils/COMMON/CMDLIB.C
Normal file
867
qutils/COMMON/CMDLIB.C
Normal file
@@ -0,0 +1,867 @@
|
||||
// cmdlib.c
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <direct.h>
|
||||
#endif
|
||||
|
||||
#ifdef NeXT
|
||||
#include <libc.h>
|
||||
#endif
|
||||
|
||||
#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);
|
||||
}
|
||||
97
qutils/COMMON/CMDLIB.H
Normal file
97
qutils/COMMON/CMDLIB.H
Normal file
@@ -0,0 +1,97 @@
|
||||
// cmdlib.h
|
||||
|
||||
#ifndef __CMDLIB__
|
||||
#define __CMDLIB__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifndef __BYTEBOOL__
|
||||
#define __BYTEBOOL__
|
||||
typedef enum {false, true} qboolean;
|
||||
typedef unsigned char byte;
|
||||
#endif
|
||||
|
||||
// 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];
|
||||
|
||||
|
||||
#endif
|
||||
508
qutils/COMMON/LBMLIB.C
Normal file
508
qutils/COMMON/LBMLIB.C
Normal file
@@ -0,0 +1,508 @@
|
||||
// lbmlib.c
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
42
qutils/COMMON/LBMLIB.H
Normal file
42
qutils/COMMON/LBMLIB.H
Normal file
@@ -0,0 +1,42 @@
|
||||
// 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);
|
||||
|
||||
109
qutils/COMMON/MATHLIB.C
Normal file
109
qutils/COMMON/MATHLIB.C
Normal file
@@ -0,0 +1,109 @@
|
||||
// mathlib.c -- math primitives
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "mathlib.h"
|
||||
|
||||
vec3_t vec3_origin = {0,0,0};
|
||||
|
||||
|
||||
double VectorLength(vec3_t v)
|
||||
{
|
||||
int i;
|
||||
double length;
|
||||
|
||||
length = 0;
|
||||
for (i=0 ; i< 3 ; i++)
|
||||
length += v[i]*v[i];
|
||||
length = sqrt (length); // FIXME
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
qboolean VectorCompare (vec3_t v1, vec3_t v2)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
if (fabs(v1[i]-v2[i]) > EQUAL_EPSILON)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
vec_t Q_rint (vec_t in)
|
||||
{
|
||||
return floor (in + 0.5);
|
||||
}
|
||||
|
||||
void VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc)
|
||||
{
|
||||
vc[0] = va[0] + scale*vb[0];
|
||||
vc[1] = va[1] + scale*vb[1];
|
||||
vc[2] = va[2] + scale*vb[2];
|
||||
}
|
||||
|
||||
void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross)
|
||||
{
|
||||
cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
|
||||
cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
|
||||
cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
|
||||
}
|
||||
|
||||
vec_t _DotProduct (vec3_t v1, vec3_t v2)
|
||||
{
|
||||
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
|
||||
}
|
||||
|
||||
void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out)
|
||||
{
|
||||
out[0] = va[0]-vb[0];
|
||||
out[1] = va[1]-vb[1];
|
||||
out[2] = va[2]-vb[2];
|
||||
}
|
||||
|
||||
void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out)
|
||||
{
|
||||
out[0] = va[0]+vb[0];
|
||||
out[1] = va[1]+vb[1];
|
||||
out[2] = va[2]+vb[2];
|
||||
}
|
||||
|
||||
void _VectorCopy (vec3_t in, vec3_t out)
|
||||
{
|
||||
out[0] = in[0];
|
||||
out[1] = in[1];
|
||||
out[2] = in[2];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
48
qutils/COMMON/MATHLIB.H
Normal file
48
qutils/COMMON/MATHLIB.H
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifndef __MATHLIB__
|
||||
#define __MATHLIB__
|
||||
|
||||
// mathlib.h
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#ifdef DOUBLEVEC_T
|
||||
typedef double vec_t;
|
||||
#else
|
||||
typedef float vec_t;
|
||||
#endif
|
||||
typedef vec_t vec3_t[3];
|
||||
|
||||
#define SIDE_FRONT 0
|
||||
#define SIDE_ON 2
|
||||
#define SIDE_BACK 1
|
||||
#define SIDE_CROSS -2
|
||||
|
||||
#define Q_PI 3.14159265358979323846
|
||||
|
||||
extern vec3_t vec3_origin;
|
||||
|
||||
#define EQUAL_EPSILON 0.001
|
||||
|
||||
qboolean VectorCompare (vec3_t v1, vec3_t v2);
|
||||
|
||||
#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
|
||||
#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];}
|
||||
#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];}
|
||||
#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];}
|
||||
|
||||
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
|
||||
400
qutils/COMMON/POLYLIB.C
Normal file
400
qutils/COMMON/POLYLIB.C
Normal file
@@ -0,0 +1,400 @@
|
||||
|
||||
#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);
|
||||
|
||||
scale = 1.0/w->numpoints;
|
||||
VectorScale (center, scale, center);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
BaseWindingForPlane
|
||||
=================
|
||||
*/
|
||||
winding_t *BaseWindingForPlane (vec3_t normal, float dist)
|
||||
{
|
||||
int i, x;
|
||||
vec_t max, v;
|
||||
vec3_t org, vright, vup;
|
||||
winding_t *w;
|
||||
|
||||
// find the major axis
|
||||
|
||||
max = -BOGUS_RANGE;
|
||||
x = -1;
|
||||
for (i=0 ; i<3; i++)
|
||||
{
|
||||
v = fabs(normal[i]);
|
||||
if (v > max)
|
||||
{
|
||||
x = i;
|
||||
max = v;
|
||||
}
|
||||
}
|
||||
if (x==-1)
|
||||
Error ("BaseWindingForPlane: no axis found");
|
||||
|
||||
VectorCopy (vec3_origin, vup);
|
||||
switch (x)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
vup[2] = 1;
|
||||
break;
|
||||
case 2:
|
||||
vup[0] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
v = DotProduct (vup, normal);
|
||||
VectorMA (vup, -v, normal, vup);
|
||||
VectorNormalize (vup);
|
||||
|
||||
VectorScale (normal, dist, org);
|
||||
|
||||
CrossProduct (vup, normal, vright);
|
||||
|
||||
VectorScale (vup, 8192, vup);
|
||||
VectorScale (vright, 8192, vright);
|
||||
|
||||
// project a really big axis aligned box onto the plane
|
||||
w = AllocWinding (4);
|
||||
|
||||
VectorSubtract (org, vright, w->p[0]);
|
||||
VectorAdd (w->p[0], vup, w->p[0]);
|
||||
|
||||
VectorAdd (org, vright, w->p[1]);
|
||||
VectorAdd (w->p[1], vup, w->p[1]);
|
||||
|
||||
VectorAdd (org, vright, w->p[2]);
|
||||
VectorSubtract (w->p[2], vup, w->p[2]);
|
||||
|
||||
VectorSubtract (org, vright, w->p[3]);
|
||||
VectorSubtract (w->p[3], vup, w->p[3]);
|
||||
|
||||
w->numpoints = 4;
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
CopyWinding
|
||||
==================
|
||||
*/
|
||||
winding_t *CopyWinding (winding_t *w)
|
||||
{
|
||||
int size;
|
||||
winding_t *c;
|
||||
|
||||
size = (int)((winding_t *)0)->p[w->numpoints];
|
||||
c = malloc (size);
|
||||
memcpy (c, w, size);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
ClipWinding
|
||||
=============
|
||||
*/
|
||||
void ClipWinding (winding_t *in, vec3_t normal, vec_t dist,
|
||||
winding_t **front, winding_t **back)
|
||||
{
|
||||
vec_t dists[MAX_POINTS_ON_WINDING+4];
|
||||
int sides[MAX_POINTS_ON_WINDING+4];
|
||||
int counts[3];
|
||||
vec_t dot;
|
||||
int i, j;
|
||||
vec_t *p1, *p2;
|
||||
vec3_t mid;
|
||||
winding_t *f, *b;
|
||||
int maxpts;
|
||||
|
||||
counts[0] = counts[1] = counts[2] = 0;
|
||||
|
||||
// determine sides for each point
|
||||
for (i=0 ; i<in->numpoints ; i++)
|
||||
{
|
||||
dot = DotProduct (in->p[i], normal);
|
||||
dot -= dist;
|
||||
dists[i] = dot;
|
||||
if (dot > ON_EPSILON)
|
||||
sides[i] = SIDE_FRONT;
|
||||
else if (dot < -ON_EPSILON)
|
||||
sides[i] = SIDE_BACK;
|
||||
else
|
||||
{
|
||||
sides[i] = SIDE_ON;
|
||||
}
|
||||
counts[sides[i]]++;
|
||||
}
|
||||
sides[i] = sides[0];
|
||||
dists[i] = dists[0];
|
||||
|
||||
*front = *back = NULL;
|
||||
|
||||
if (!counts[0])
|
||||
{
|
||||
*back = CopyWinding (in);
|
||||
return;
|
||||
}
|
||||
if (!counts[1])
|
||||
{
|
||||
*front = CopyWinding (in);
|
||||
return;
|
||||
}
|
||||
|
||||
maxpts = in->numpoints+4; // can't use counts[0]+2 because
|
||||
// of fp grouping errors
|
||||
|
||||
*front = f = AllocWinding (maxpts);
|
||||
*back = b = AllocWinding (maxpts);
|
||||
|
||||
for (i=0 ; i<in->numpoints ; i++)
|
||||
{
|
||||
p1 = in->p[i];
|
||||
|
||||
if (sides[i] == SIDE_ON)
|
||||
{
|
||||
VectorCopy (p1, f->p[f->numpoints]);
|
||||
f->numpoints++;
|
||||
VectorCopy (p1, b->p[b->numpoints]);
|
||||
b->numpoints++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sides[i] == SIDE_FRONT)
|
||||
{
|
||||
VectorCopy (p1, f->p[f->numpoints]);
|
||||
f->numpoints++;
|
||||
}
|
||||
if (sides[i] == SIDE_BACK)
|
||||
{
|
||||
VectorCopy (p1, b->p[b->numpoints]);
|
||||
b->numpoints++;
|
||||
}
|
||||
|
||||
if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
|
||||
continue;
|
||||
|
||||
// generate a split point
|
||||
p2 = in->p[(i+1)%in->numpoints];
|
||||
|
||||
dot = dists[i] / (dists[i]-dists[i+1]);
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{ // avoid round off error when possible
|
||||
if (normal[j] == 1)
|
||||
mid[j] = dist;
|
||||
else if (normal[j] == -1)
|
||||
mid[j] = -dist;
|
||||
else
|
||||
mid[j] = p1[j] + dot*(p2[j]-p1[j]);
|
||||
}
|
||||
|
||||
VectorCopy (mid, f->p[f->numpoints]);
|
||||
f->numpoints++;
|
||||
VectorCopy (mid, b->p[b->numpoints]);
|
||||
b->numpoints++;
|
||||
}
|
||||
|
||||
if (f->numpoints > maxpts || b->numpoints > maxpts)
|
||||
Error ("ClipWinding: points exceeded estimate");
|
||||
if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)
|
||||
Error ("ClipWinding: MAX_POINTS_ON_WINDING");
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
ChopWinding
|
||||
|
||||
Returns the fragment of in that is on the front side
|
||||
of the cliping plane. The original is freed.
|
||||
=================
|
||||
*/
|
||||
winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist)
|
||||
{
|
||||
winding_t *f, *b;
|
||||
|
||||
ClipWinding (in, normal, dist, &f, &b);
|
||||
free (in);
|
||||
if (b)
|
||||
free (b);
|
||||
return f;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CheckWinding
|
||||
|
||||
=================
|
||||
*/
|
||||
void CheckWinding (winding_t *w)
|
||||
{
|
||||
int i, j;
|
||||
vec_t *p1, *p2;
|
||||
vec_t d, edgedist;
|
||||
vec3_t dir, edgenormal, facenormal;
|
||||
vec_t area;
|
||||
vec_t facedist;
|
||||
|
||||
if (w->numpoints < 3)
|
||||
Error ("CheckFace: %i points",w->numpoints);
|
||||
|
||||
area = WindingArea(w);
|
||||
if (area < 1)
|
||||
Error ("CheckFace: %f area", area);
|
||||
|
||||
WindingPlane (w, facenormal, &facedist);
|
||||
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
{
|
||||
p1 = w->p[i];
|
||||
|
||||
for (j=0 ; j<3 ; j++)
|
||||
if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE)
|
||||
Error ("CheckFace: BUGUS_RANGE: %f",p1[j]);
|
||||
|
||||
j = i+1 == w->numpoints ? 0 : i+1;
|
||||
|
||||
// check the point is on the face plane
|
||||
d = DotProduct (p1, facenormal) - facedist;
|
||||
if (d < -ON_EPSILON || d > ON_EPSILON)
|
||||
Error ("CheckFace: point off plane");
|
||||
|
||||
// check the edge isn't degenerate
|
||||
p2 = w->p[j];
|
||||
VectorSubtract (p2, p1, dir);
|
||||
|
||||
if (VectorLength (dir) < ON_EPSILON)
|
||||
Error ("CheckFace: degenerate edge");
|
||||
|
||||
CrossProduct (facenormal, dir, edgenormal);
|
||||
VectorNormalize (edgenormal);
|
||||
edgedist = DotProduct (p1, edgenormal);
|
||||
edgedist += ON_EPSILON;
|
||||
|
||||
// all other points must be on front side
|
||||
for (j=0 ; j<w->numpoints ; j++)
|
||||
{
|
||||
if (j == i)
|
||||
continue;
|
||||
d = DotProduct (w->p[j], edgenormal);
|
||||
if (d > edgedist)
|
||||
Error ("CheckFace: non-convex");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
22
qutils/COMMON/POLYLIB.H
Normal file
22
qutils/COMMON/POLYLIB.H
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int numpoints;
|
||||
vec3_t p[4]; // variable sized
|
||||
} winding_t;
|
||||
|
||||
#define MAX_POINTS_ON_WINDING 64
|
||||
|
||||
#define ON_EPSILON 0.1
|
||||
|
||||
winding_t *AllocWinding (int points);
|
||||
vec_t WindingArea (winding_t *w);
|
||||
void WindingCenter (winding_t *w, vec3_t center);
|
||||
void ClipWinding (winding_t *in, vec3_t normal, vec_t dist,
|
||||
winding_t **front, winding_t **back);
|
||||
winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist);
|
||||
winding_t *CopyWinding (winding_t *w);
|
||||
winding_t *BaseWindingForPlane (vec3_t normal, float dist);
|
||||
void CheckWinding (winding_t *w);
|
||||
void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist);
|
||||
void RemoveColinearPoints (winding_t *w);
|
||||
185
qutils/COMMON/SCRIPLIB.C
Normal file
185
qutils/COMMON/SCRIPLIB.C
Normal file
@@ -0,0 +1,185 @@
|
||||
// scriplib.c
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "scriplib.h"
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
PARSING STUFF
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
char token[MAXTOKEN];
|
||||
char *scriptbuffer,*script_p,*scriptend_p;
|
||||
int grabbed;
|
||||
int scriptline;
|
||||
qboolean endofscript;
|
||||
qboolean tokenready; // only true if UnGetToken was just called
|
||||
|
||||
/*
|
||||
==============
|
||||
=
|
||||
= LoadScriptFile
|
||||
=
|
||||
==============
|
||||
*/
|
||||
|
||||
void LoadScriptFile (char *filename)
|
||||
{
|
||||
int size;
|
||||
|
||||
size = LoadFile (filename, (void **)&scriptbuffer);
|
||||
|
||||
script_p = scriptbuffer;
|
||||
scriptend_p = script_p + size;
|
||||
scriptline = 1;
|
||||
endofscript = false;
|
||||
tokenready = false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
=
|
||||
= UnGetToken
|
||||
=
|
||||
= Signals that the current token was not used, and should be reported
|
||||
= for the next GetToken. Note that
|
||||
|
||||
GetToken (true);
|
||||
UnGetToken ();
|
||||
GetToken (false);
|
||||
|
||||
= could cross a line boundary.
|
||||
=
|
||||
==============
|
||||
*/
|
||||
|
||||
void UnGetToken (void)
|
||||
{
|
||||
tokenready = true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
GetToken
|
||||
==============
|
||||
*/
|
||||
qboolean GetToken (qboolean crossline)
|
||||
{
|
||||
char *token_p;
|
||||
|
||||
if (tokenready) // is a token allready waiting?
|
||||
{
|
||||
tokenready = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (script_p >= scriptend_p)
|
||||
{
|
||||
if (!crossline)
|
||||
Error ("Line %i is incomplete\n",scriptline);
|
||||
endofscript = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// skip space
|
||||
//
|
||||
skipspace:
|
||||
while (*script_p <= 32)
|
||||
{
|
||||
if (script_p >= scriptend_p)
|
||||
{
|
||||
if (!crossline)
|
||||
Error ("Line %i is incomplete\n",scriptline);
|
||||
endofscript = true;
|
||||
return true;
|
||||
}
|
||||
if (*script_p++ == '\n')
|
||||
{
|
||||
if (!crossline)
|
||||
Error ("Line %i is incomplete\n",scriptline);
|
||||
scriptline++;
|
||||
}
|
||||
}
|
||||
|
||||
if (script_p >= scriptend_p)
|
||||
{
|
||||
if (!crossline)
|
||||
Error ("Line %i is incomplete\n",scriptline);
|
||||
endofscript = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (*script_p == ';' || *script_p == '#') // semicolon is comment field
|
||||
{ // also make # a comment field
|
||||
if (!crossline)
|
||||
Error ("Line %i is incomplete\n",scriptline);
|
||||
while (*script_p++ != '\n')
|
||||
if (script_p >= scriptend_p)
|
||||
{
|
||||
endofscript = true;
|
||||
return false;
|
||||
}
|
||||
goto skipspace;
|
||||
}
|
||||
|
||||
//
|
||||
// copy token
|
||||
//
|
||||
token_p = token;
|
||||
|
||||
while ( *script_p > 32 && *script_p != ';')
|
||||
{
|
||||
*token_p++ = *script_p++;
|
||||
if (script_p == scriptend_p)
|
||||
break;
|
||||
if (token_p == &token[MAXTOKEN])
|
||||
Error ("Token too large on line %i\n",scriptline);
|
||||
}
|
||||
|
||||
*token_p = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
=
|
||||
= TokenAvailable
|
||||
=
|
||||
= Returns true if there is another token on the line
|
||||
=
|
||||
==============
|
||||
*/
|
||||
|
||||
qboolean TokenAvailable (void)
|
||||
{
|
||||
char *search_p;
|
||||
|
||||
search_p = script_p;
|
||||
|
||||
if (search_p >= scriptend_p)
|
||||
return false;
|
||||
|
||||
while ( *search_p <= 32)
|
||||
{
|
||||
if (*search_p == '\n')
|
||||
return false;
|
||||
search_p++;
|
||||
if (search_p == scriptend_p)
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
if (*search_p == ';')
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
21
qutils/COMMON/SCRIPLIB.H
Normal file
21
qutils/COMMON/SCRIPLIB.H
Normal file
@@ -0,0 +1,21 @@
|
||||
// scriplib.h
|
||||
|
||||
#ifndef __CMDLIB__
|
||||
#include "cmdlib.h"
|
||||
#endif
|
||||
|
||||
#define MAXTOKEN 128
|
||||
|
||||
extern char token[MAXTOKEN];
|
||||
extern char *scriptbuffer,*script_p,*scriptend_p;
|
||||
extern int grabbed;
|
||||
extern int scriptline;
|
||||
extern qboolean endofscript;
|
||||
|
||||
|
||||
void LoadScriptFile (char *filename);
|
||||
qboolean GetToken (qboolean crossline);
|
||||
void UnGetToken (void);
|
||||
qboolean TokenAvailable (void);
|
||||
|
||||
|
||||
239
qutils/COMMON/THREADS.C
Normal file
239
qutils/COMMON/THREADS.C
Normal file
@@ -0,0 +1,239 @@
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "threads.h"
|
||||
|
||||
#define MAX_THREADS 64
|
||||
|
||||
int dispatch;
|
||||
int workcount;
|
||||
int oldf;
|
||||
qboolean pacifier;
|
||||
|
||||
/*
|
||||
=============
|
||||
GetThreadWork
|
||||
|
||||
=============
|
||||
*/
|
||||
int GetThreadWork (void)
|
||||
{
|
||||
int r;
|
||||
int f;
|
||||
|
||||
ThreadLock ();
|
||||
|
||||
if (dispatch == workcount)
|
||||
{
|
||||
ThreadUnlock ();
|
||||
return -1;
|
||||
}
|
||||
|
||||
f = 10*dispatch / workcount;
|
||||
if (f != oldf)
|
||||
{
|
||||
oldf = f;
|
||||
if (pacifier)
|
||||
printf ("%i...", f);
|
||||
}
|
||||
|
||||
r = dispatch;
|
||||
dispatch++;
|
||||
ThreadUnlock ();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
===================================================================
|
||||
|
||||
WIN32
|
||||
|
||||
===================================================================
|
||||
*/
|
||||
#ifdef WIN32
|
||||
|
||||
#define USED
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
int numthreads = 1;
|
||||
CRITICAL_SECTION crit;
|
||||
|
||||
void ThreadLock (void)
|
||||
{
|
||||
EnterCriticalSection (&crit);
|
||||
}
|
||||
|
||||
void ThreadUnlock (void)
|
||||
{
|
||||
LeaveCriticalSection (&crit);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
RunThreadsOn
|
||||
=============
|
||||
*/
|
||||
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
|
||||
{
|
||||
int threadid[MAX_THREADS];
|
||||
HANDLE threadhandle[MAX_THREADS];
|
||||
int i;
|
||||
|
||||
dispatch = 0;
|
||||
workcount = workcnt;
|
||||
oldf = -1;
|
||||
pacifier = showpacifier;
|
||||
|
||||
//
|
||||
// run threads in parallel
|
||||
//
|
||||
InitializeCriticalSection (&crit);
|
||||
for (i=0 ; i<numthreads ; i++)
|
||||
{
|
||||
threadhandle[i] = CreateThread(
|
||||
NULL, // LPSECURITY_ATTRIBUTES lpsa,
|
||||
0, // DWORD cbStack,
|
||||
(LPTHREAD_START_ROUTINE)func, // LPTHREAD_START_ROUTINE lpStartAddr,
|
||||
(LPVOID)i, // LPVOID lpvThreadParm,
|
||||
0, // DWORD fdwCreate,
|
||||
&threadid[i]);
|
||||
}
|
||||
|
||||
for (i=0 ; i<numthreads ; i++)
|
||||
WaitForSingleObject (threadhandle[i], INFINITE);
|
||||
DeleteCriticalSection (&crit);
|
||||
if (pacifier)
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
===================================================================
|
||||
|
||||
OSF1
|
||||
|
||||
===================================================================
|
||||
*/
|
||||
|
||||
#ifdef __osf__
|
||||
#define USED
|
||||
|
||||
int numthreads = 4;
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
pthread_mutex_t *my_mutex;
|
||||
|
||||
void ThreadLock (void)
|
||||
{
|
||||
if (my_mutex)
|
||||
pthread_mutex_lock (my_mutex);
|
||||
}
|
||||
|
||||
void ThreadUnlock (void)
|
||||
{
|
||||
if (my_mutex)
|
||||
pthread_mutex_unlock (my_mutex);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
RunThreadsOn
|
||||
=============
|
||||
*/
|
||||
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
|
||||
{
|
||||
int i;
|
||||
pthread_t work_threads[MAX_THREADS];
|
||||
pthread_addr_t status;
|
||||
pthread_attr_t attrib;
|
||||
pthread_mutexattr_t mattrib;
|
||||
|
||||
dispatch = 0;
|
||||
workcount = workcnt;
|
||||
oldf = -1;
|
||||
pacifier = showpacifier;
|
||||
|
||||
if (!my_mutex)
|
||||
{
|
||||
my_mutex = malloc (sizeof(*my_mutex));
|
||||
if (pthread_mutexattr_create (&mattrib) == -1)
|
||||
Error ("pthread_mutex_attr_create failed");
|
||||
if (pthread_mutexattr_setkind_np (&mattrib, MUTEX_FAST_NP) == -1)
|
||||
Error ("pthread_mutexattr_setkind_np failed");
|
||||
if (pthread_mutex_init (my_mutex, mattrib) == -1)
|
||||
Error ("pthread_mutex_init failed");
|
||||
}
|
||||
|
||||
if (pthread_attr_create (&attrib) == -1)
|
||||
Error ("pthread_attr_create failed");
|
||||
if (pthread_attr_setstacksize (&attrib, 0x100000) == -1)
|
||||
Error ("pthread_attr_setstacksize failed");
|
||||
|
||||
for (i=0 ; i<numthreads ; i++)
|
||||
{
|
||||
if (pthread_create(&work_threads[i], attrib
|
||||
, (pthread_startroutine_t)func, (pthread_addr_t)i) == -1)
|
||||
Error ("pthread_create failed");
|
||||
}
|
||||
|
||||
for (i=0 ; i<numthreads ; i++)
|
||||
{
|
||||
if (pthread_join (work_threads[i], &status) == -1)
|
||||
Error ("pthread_join failed");
|
||||
}
|
||||
|
||||
if (pacifier)
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
=======================================================================
|
||||
|
||||
SINGLE THREAD
|
||||
|
||||
=======================================================================
|
||||
*/
|
||||
|
||||
#ifndef USED
|
||||
|
||||
int numthreads = 1;
|
||||
|
||||
void ThreadLock (void)
|
||||
{
|
||||
}
|
||||
|
||||
void ThreadUnlock (void)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
RunThreadsOn
|
||||
=============
|
||||
*/
|
||||
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
|
||||
{
|
||||
int i;
|
||||
|
||||
dispatch = 0;
|
||||
workcount = workcnt;
|
||||
oldf = -1;
|
||||
pacifier = showpacifier;
|
||||
|
||||
func(0);
|
||||
|
||||
if (pacifier)
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
8
qutils/COMMON/THREADS.H
Normal file
8
qutils/COMMON/THREADS.H
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
extern int numthreads;
|
||||
|
||||
int GetThreadWork (void);
|
||||
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int));
|
||||
void ThreadLock (void);
|
||||
void ThreadUnlock (void);
|
||||
|
||||
170
qutils/COMMON/TRILIB.C
Normal file
170
qutils/COMMON/TRILIB.C
Normal file
@@ -0,0 +1,170 @@
|
||||
//
|
||||
// trilib.c: library for loading triangles from an Alias triangle file
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include "cmdlib.h"
|
||||
#include "mathlib.h"
|
||||
#include "trilib.h"
|
||||
|
||||
// on disk representation of a face
|
||||
|
||||
|
||||
#define FLOAT_START 99999.0
|
||||
#define FLOAT_END -FLOAT_START
|
||||
#define MAGIC 123322
|
||||
|
||||
//#define NOISY 1
|
||||
|
||||
typedef struct {
|
||||
float v[3];
|
||||
} vector;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vector n; /* normal */
|
||||
vector p; /* point */
|
||||
vector c; /* color */
|
||||
float u; /* u */
|
||||
float v; /* v */
|
||||
} aliaspoint_t;
|
||||
|
||||
typedef struct {
|
||||
aliaspoint_t pt[3];
|
||||
} tf_triangle;
|
||||
|
||||
|
||||
void ByteSwapTri (tf_triangle *tri)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<sizeof(tf_triangle)/4 ; i++)
|
||||
{
|
||||
((int *)tri)[i] = BigLong (((int *)tri)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadTriangleList (char *filename, triangle_t **pptri, int *numtriangles)
|
||||
{
|
||||
FILE *input;
|
||||
float start;
|
||||
char name[256], tex[256];
|
||||
int i, count, magic;
|
||||
tf_triangle tri;
|
||||
triangle_t *ptri;
|
||||
int iLevel;
|
||||
int exitpattern;
|
||||
float t;
|
||||
|
||||
|
||||
t = -FLOAT_START;
|
||||
*((unsigned char *)&exitpattern + 0) = *((unsigned char *)&t + 3);
|
||||
*((unsigned char *)&exitpattern + 1) = *((unsigned char *)&t + 2);
|
||||
*((unsigned char *)&exitpattern + 2) = *((unsigned char *)&t + 1);
|
||||
*((unsigned char *)&exitpattern + 3) = *((unsigned char *)&t + 0);
|
||||
|
||||
if ((input = fopen(filename, "rb")) == 0) {
|
||||
fprintf(stderr,"reader: could not open file '%s'\n", filename);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
iLevel = 0;
|
||||
|
||||
fread(&magic, sizeof(int), 1, input);
|
||||
if (BigLong(magic) != MAGIC) {
|
||||
fprintf(stderr,"File is not a Alias object separated triangle file, magic number is wrong.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
ptri = malloc (MAXTRIANGLES * sizeof(triangle_t));
|
||||
|
||||
*pptri = ptri;
|
||||
|
||||
while (feof(input) == 0) {
|
||||
fread(&start, sizeof(float), 1, input);
|
||||
*(int *)&start = BigLong(*(int *)&start);
|
||||
if (*(int *)&start != exitpattern)
|
||||
{
|
||||
if (start == FLOAT_START) {
|
||||
/* Start of an object or group of objects. */
|
||||
i = -1;
|
||||
do {
|
||||
/* There are probably better ways to read a string from */
|
||||
/* a file, but this does allow you to do error checking */
|
||||
/* (which I'm not doing) on a per character basis. */
|
||||
++i;
|
||||
fread( &(name[i]), sizeof( char ), 1, input);
|
||||
} while( name[i] != '\0' );
|
||||
|
||||
// indent();
|
||||
// fprintf(stdout,"OBJECT START: %s\n",name);
|
||||
fread( &count, sizeof(int), 1, input);
|
||||
count = BigLong(count);
|
||||
++iLevel;
|
||||
if (count != 0) {
|
||||
// indent();
|
||||
|
||||
// fprintf(stdout,"NUMBER OF TRIANGLES: %d\n",count);
|
||||
|
||||
i = -1;
|
||||
do {
|
||||
++i;
|
||||
fread( &(tex[i]), sizeof( char ), 1, input);
|
||||
} while( tex[i] != '\0' );
|
||||
|
||||
// indent();
|
||||
// fprintf(stdout," Object texture name: '%s'\n",tex);
|
||||
}
|
||||
|
||||
/* Else (count == 0) this is the start of a group, and */
|
||||
/* no texture name is present. */
|
||||
}
|
||||
else if (start == FLOAT_END) {
|
||||
/* End of an object or group. Yes, the name should be */
|
||||
/* obvious from context, but it is in here just to be */
|
||||
/* safe and to provide a little extra information for */
|
||||
/* those who do not wish to write a recursive reader. */
|
||||
/* Mia culpa. */
|
||||
--iLevel;
|
||||
i = -1;
|
||||
do {
|
||||
++i;
|
||||
fread( &(name[i]), sizeof( char ), 1, input);
|
||||
} while( name[i] != '\0' );
|
||||
|
||||
// indent();
|
||||
// fprintf(stdout,"OBJECT END: %s\n",name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// read the triangles
|
||||
//
|
||||
for (i = 0; i < count; ++i) {
|
||||
int j;
|
||||
|
||||
fread( &tri, sizeof(tf_triangle), 1, input );
|
||||
ByteSwapTri (&tri);
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
int k;
|
||||
|
||||
for (k=0 ; k<3 ; k++)
|
||||
{
|
||||
ptri->verts[j][k] = tri.pt[j].p.v[k];
|
||||
}
|
||||
}
|
||||
|
||||
ptri++;
|
||||
|
||||
if ((ptri - *pptri) >= MAXTRIANGLES)
|
||||
Error ("Error: too many triangles; increase MAXTRIANGLES\n");
|
||||
}
|
||||
}
|
||||
|
||||
*numtriangles = ptri - *pptri;
|
||||
|
||||
fclose (input);
|
||||
}
|
||||
|
||||
11
qutils/COMMON/TRILIB.H
Normal file
11
qutils/COMMON/TRILIB.H
Normal file
@@ -0,0 +1,11 @@
|
||||
//
|
||||
// trilib.h: header file for loading triangles from an Alias triangle file
|
||||
//
|
||||
#define MAXTRIANGLES 2048
|
||||
|
||||
typedef struct {
|
||||
vec3_t verts[3];
|
||||
} triangle_t;
|
||||
|
||||
void LoadTriangleList (char *filename, triangle_t **pptri, int *numtriangles);
|
||||
|
||||
328
qutils/COMMON/WADLIB.C
Normal file
328
qutils/COMMON/WADLIB.C
Normal file
@@ -0,0 +1,328 @@
|
||||
// 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 "cmdlib.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 (char *filename)
|
||||
{
|
||||
lumpinfo_t *lump_p;
|
||||
unsigned i;
|
||||
int length;
|
||||
|
||||
//
|
||||
// open the file and add to directory
|
||||
//
|
||||
wadhandle = SafeOpenRead (filename);
|
||||
SafeRead (wadhandle, &header, sizeof(header));
|
||||
|
||||
if (strncmp(header.identification,"WAD2",4))
|
||||
Error ("Wad file %s doesn't have WAD2 id\n",filename);
|
||||
|
||||
header.numlumps = LittleLong(header.numlumps);
|
||||
header.infotableofs = LittleLong(header.infotableofs);
|
||||
|
||||
numlumps = header.numlumps;
|
||||
|
||||
length = numlumps*sizeof(lumpinfo_t);
|
||||
lumpinfo = 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 >= 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 (void)
|
||||
{
|
||||
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] = '2';
|
||||
|
||||
header.numlumps = wadlong(outlumps);
|
||||
header.infotableofs = wadlong(ofs);
|
||||
|
||||
fseek (outwad, 0, SEEK_SET);
|
||||
SafeWrite (outwad, &header, sizeof(header));
|
||||
fclose (outwad);
|
||||
}
|
||||
|
||||
|
||||
53
qutils/COMMON/WADLIB.H
Normal file
53
qutils/COMMON/WADLIB.H
Normal file
@@ -0,0 +1,53 @@
|
||||
// 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 (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 (void);
|
||||
|
||||
Reference in New Issue
Block a user