The Quake 2 tools as originally released under the GPL license.

This commit is contained in:
Travis Bradshaw
2012-01-31 15:22:13 -06:00
commit 707e849167
132 changed files with 52073 additions and 0 deletions

789
common/bspfile.c Normal file
View File

@@ -0,0 +1,789 @@
/*
===========================================================================
Copyright (C) 1997-2006 Id Software, Inc.
This file is part of Quake 2 Tools source code.
Quake 2 Tools source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake 2 Tools source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake 2 Tools source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "cmdlib.h"
#include "mathlib.h"
#include "bspfile.h"
#include "scriplib.h"
void GetLeafNums (void);
//=============================================================================
int nummodels;
dmodel_t dmodels[MAX_MAP_MODELS];
int visdatasize;
byte dvisdata[MAX_MAP_VISIBILITY];
dvis_t *dvis = (dvis_t *)dvisdata;
int lightdatasize;
byte dlightdata[MAX_MAP_LIGHTING];
int entdatasize;
char dentdata[MAX_MAP_ENTSTRING];
int numleafs;
dleaf_t dleafs[MAX_MAP_LEAFS];
int numplanes;
dplane_t dplanes[MAX_MAP_PLANES];
int numvertexes;
dvertex_t dvertexes[MAX_MAP_VERTS];
int numnodes;
dnode_t dnodes[MAX_MAP_NODES];
int numtexinfo;
texinfo_t texinfo[MAX_MAP_TEXINFO];
int numfaces;
dface_t dfaces[MAX_MAP_FACES];
int numedges;
dedge_t dedges[MAX_MAP_EDGES];
int numleaffaces;
unsigned short dleaffaces[MAX_MAP_LEAFFACES];
int numleafbrushes;
unsigned short dleafbrushes[MAX_MAP_LEAFBRUSHES];
int numsurfedges;
int dsurfedges[MAX_MAP_SURFEDGES];
int numbrushes;
dbrush_t dbrushes[MAX_MAP_BRUSHES];
int numbrushsides;
dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES];
int numareas;
darea_t dareas[MAX_MAP_AREAS];
int numareaportals;
dareaportal_t dareaportals[MAX_MAP_AREAPORTALS];
byte dpop[256];
/*
===============
CompressVis
===============
*/
int CompressVis (byte *vis, byte *dest)
{
int j;
int rep;
int visrow;
byte *dest_p;
dest_p = dest;
// visrow = (r_numvisleafs + 7)>>3;
visrow = (dvis->numclusters + 7)>>3;
for (j=0 ; j<visrow ; j++)
{
*dest_p++ = vis[j];
if (vis[j])
continue;
rep = 1;
for ( j++; j<visrow ; j++)
if (vis[j] || rep == 255)
break;
else
rep++;
*dest_p++ = rep;
j--;
}
return dest_p - dest;
}
/*
===================
DecompressVis
===================
*/
void DecompressVis (byte *in, byte *decompressed)
{
int c;
byte *out;
int row;
// row = (r_numvisleafs+7)>>3;
row = (dvis->numclusters+7)>>3;
out = decompressed;
do
{
if (*in)
{
*out++ = *in++;
continue;
}
c = in[1];
if (!c)
Error ("DecompressVis: 0 repeat");
in += 2;
while (c)
{
*out++ = 0;
c--;
}
} while (out - decompressed < row);
}
//=============================================================================
/*
=============
SwapBSPFile
Byte swaps all data in a bsp file.
=============
*/
void SwapBSPFile (qboolean todisk)
{
int i, j;
dmodel_t *d;
// models
for (i=0 ; i<nummodels ; i++)
{
d = &dmodels[i];
d->firstface = LittleLong (d->firstface);
d->numfaces = LittleLong (d->numfaces);
d->headnode = LittleLong (d->headnode);
for (j=0 ; j<3 ; j++)
{
d->mins[j] = LittleFloat(d->mins[j]);
d->maxs[j] = LittleFloat(d->maxs[j]);
d->origin[j] = LittleFloat(d->origin[j]);
}
}
//
// vertexes
//
for (i=0 ; i<numvertexes ; i++)
{
for (j=0 ; j<3 ; j++)
dvertexes[i].point[j] = LittleFloat (dvertexes[i].point[j]);
}
//
// planes
//
for (i=0 ; i<numplanes ; i++)
{
for (j=0 ; j<3 ; j++)
dplanes[i].normal[j] = LittleFloat (dplanes[i].normal[j]);
dplanes[i].dist = LittleFloat (dplanes[i].dist);
dplanes[i].type = LittleLong (dplanes[i].type);
}
//
// texinfos
//
for (i=0 ; i<numtexinfo ; i++)
{
for (j=0 ; j<8 ; j++)
texinfo[i].vecs[0][j] = LittleFloat (texinfo[i].vecs[0][j]);
texinfo[i].flags = LittleLong (texinfo[i].flags);
texinfo[i].value = LittleLong (texinfo[i].value);
texinfo[i].nexttexinfo = LittleLong (texinfo[i].nexttexinfo);
}
//
// faces
//
for (i=0 ; i<numfaces ; i++)
{
dfaces[i].texinfo = LittleShort (dfaces[i].texinfo);
dfaces[i].planenum = LittleShort (dfaces[i].planenum);
dfaces[i].side = LittleShort (dfaces[i].side);
dfaces[i].lightofs = LittleLong (dfaces[i].lightofs);
dfaces[i].firstedge = LittleLong (dfaces[i].firstedge);
dfaces[i].numedges = LittleShort (dfaces[i].numedges);
}
//
// nodes
//
for (i=0 ; i<numnodes ; i++)
{
dnodes[i].planenum = LittleLong (dnodes[i].planenum);
for (j=0 ; j<3 ; j++)
{
dnodes[i].mins[j] = LittleShort (dnodes[i].mins[j]);
dnodes[i].maxs[j] = LittleShort (dnodes[i].maxs[j]);
}
dnodes[i].children[0] = LittleLong (dnodes[i].children[0]);
dnodes[i].children[1] = LittleLong (dnodes[i].children[1]);
dnodes[i].firstface = LittleShort (dnodes[i].firstface);
dnodes[i].numfaces = LittleShort (dnodes[i].numfaces);
}
//
// leafs
//
for (i=0 ; i<numleafs ; i++)
{
dleafs[i].contents = LittleLong (dleafs[i].contents);
dleafs[i].cluster = LittleShort (dleafs[i].cluster);
dleafs[i].area = LittleShort (dleafs[i].area);
for (j=0 ; j<3 ; j++)
{
dleafs[i].mins[j] = LittleShort (dleafs[i].mins[j]);
dleafs[i].maxs[j] = LittleShort (dleafs[i].maxs[j]);
}
dleafs[i].firstleafface = LittleShort (dleafs[i].firstleafface);
dleafs[i].numleaffaces = LittleShort (dleafs[i].numleaffaces);
dleafs[i].firstleafbrush = LittleShort (dleafs[i].firstleafbrush);
dleafs[i].numleafbrushes = LittleShort (dleafs[i].numleafbrushes);
}
//
// leaffaces
//
for (i=0 ; i<numleaffaces ; i++)
dleaffaces[i] = LittleShort (dleaffaces[i]);
//
// leafbrushes
//
for (i=0 ; i<numleafbrushes ; i++)
dleafbrushes[i] = LittleShort (dleafbrushes[i]);
//
// surfedges
//
for (i=0 ; i<numsurfedges ; i++)
dsurfedges[i] = LittleLong (dsurfedges[i]);
//
// edges
//
for (i=0 ; i<numedges ; i++)
{
dedges[i].v[0] = LittleShort (dedges[i].v[0]);
dedges[i].v[1] = LittleShort (dedges[i].v[1]);
}
//
// brushes
//
for (i=0 ; i<numbrushes ; i++)
{
dbrushes[i].firstside = LittleLong (dbrushes[i].firstside);
dbrushes[i].numsides = LittleLong (dbrushes[i].numsides);
dbrushes[i].contents = LittleLong (dbrushes[i].contents);
}
//
// areas
//
for (i=0 ; i<numareas ; i++)
{
dareas[i].numareaportals = LittleLong (dareas[i].numareaportals);
dareas[i].firstareaportal = LittleLong (dareas[i].firstareaportal);
}
//
// areasportals
//
for (i=0 ; i<numareaportals ; i++)
{
dareaportals[i].portalnum = LittleLong (dareaportals[i].portalnum);
dareaportals[i].otherarea = LittleLong (dareaportals[i].otherarea);
}
//
// brushsides
//
for (i=0 ; i<numbrushsides ; i++)
{
dbrushsides[i].planenum = LittleShort (dbrushsides[i].planenum);
dbrushsides[i].texinfo = LittleShort (dbrushsides[i].texinfo);
}
//
// visibility
//
if (todisk)
j = dvis->numclusters;
else
j = LittleLong(dvis->numclusters);
dvis->numclusters = LittleLong (dvis->numclusters);
for (i=0 ; i<j ; i++)
{
dvis->bitofs[i][0] = LittleLong (dvis->bitofs[i][0]);
dvis->bitofs[i][1] = LittleLong (dvis->bitofs[i][1]);
}
}
dheader_t *header;
int CopyLump (int lump, void *dest, int size)
{
int length, ofs;
length = header->lumps[lump].filelen;
ofs = header->lumps[lump].fileofs;
if (length % size)
Error ("LoadBSPFile: odd lump size");
memcpy (dest, (byte *)header + ofs, length);
return length / size;
}
/*
=============
LoadBSPFile
=============
*/
void LoadBSPFile (char *filename)
{
int i;
//
// load the file header
//
LoadFile (filename, (void **)&header);
// swap the header
for (i=0 ; i< sizeof(dheader_t)/4 ; i++)
((int *)header)[i] = LittleLong ( ((int *)header)[i]);
if (header->ident != IDBSPHEADER)
Error ("%s is not a IBSP file", filename);
if (header->version != BSPVERSION)
Error ("%s is version %i, not %i", filename, header->version, BSPVERSION);
nummodels = CopyLump (LUMP_MODELS, dmodels, sizeof(dmodel_t));
numvertexes = CopyLump (LUMP_VERTEXES, dvertexes, sizeof(dvertex_t));
numplanes = CopyLump (LUMP_PLANES, dplanes, sizeof(dplane_t));
numleafs = CopyLump (LUMP_LEAFS, dleafs, sizeof(dleaf_t));
numnodes = CopyLump (LUMP_NODES, dnodes, sizeof(dnode_t));
numtexinfo = CopyLump (LUMP_TEXINFO, texinfo, sizeof(texinfo_t));
numfaces = CopyLump (LUMP_FACES, dfaces, sizeof(dface_t));
numleaffaces = CopyLump (LUMP_LEAFFACES, dleaffaces, sizeof(dleaffaces[0]));
numleafbrushes = CopyLump (LUMP_LEAFBRUSHES, dleafbrushes, sizeof(dleafbrushes[0]));
numsurfedges = CopyLump (LUMP_SURFEDGES, dsurfedges, sizeof(dsurfedges[0]));
numedges = CopyLump (LUMP_EDGES, dedges, sizeof(dedge_t));
numbrushes = CopyLump (LUMP_BRUSHES, dbrushes, sizeof(dbrush_t));
numbrushsides = CopyLump (LUMP_BRUSHSIDES, dbrushsides, sizeof(dbrushside_t));
numareas = CopyLump (LUMP_AREAS, dareas, sizeof(darea_t));
numareaportals = CopyLump (LUMP_AREAPORTALS, dareaportals, sizeof(dareaportal_t));
visdatasize = CopyLump (LUMP_VISIBILITY, dvisdata, 1);
lightdatasize = CopyLump (LUMP_LIGHTING, dlightdata, 1);
entdatasize = CopyLump (LUMP_ENTITIES, dentdata, 1);
CopyLump (LUMP_POP, dpop, 1);
free (header); // everything has been copied out
//
// swap everything
//
SwapBSPFile (false);
}
/*
=============
LoadBSPFileTexinfo
Only loads the texinfo lump, so qdata can scan for textures
=============
*/
void LoadBSPFileTexinfo (char *filename)
{
int i;
FILE *f;
int length, ofs;
header = malloc(sizeof(dheader_t));
f = fopen (filename, "rb");
fread (header, sizeof(dheader_t), 1, f);
// swap the header
for (i=0 ; i< sizeof(dheader_t)/4 ; i++)
((int *)header)[i] = LittleLong ( ((int *)header)[i]);
if (header->ident != IDBSPHEADER)
Error ("%s is not a IBSP file", filename);
if (header->version != BSPVERSION)
Error ("%s is version %i, not %i", filename, header->version, BSPVERSION);
length = header->lumps[LUMP_TEXINFO].filelen;
ofs = header->lumps[LUMP_TEXINFO].fileofs;
fseek (f, ofs, SEEK_SET);
fread (texinfo, length, 1, f);
fclose (f);
numtexinfo = length / sizeof(texinfo_t);
free (header); // everything has been copied out
SwapBSPFile (false);
}
//============================================================================
FILE *wadfile;
dheader_t outheader;
void AddLump (int lumpnum, void *data, int len)
{
lump_t *lump;
lump = &header->lumps[lumpnum];
lump->fileofs = LittleLong( ftell(wadfile) );
lump->filelen = LittleLong(len);
SafeWrite (wadfile, data, (len+3)&~3);
}
/*
=============
WriteBSPFile
Swaps the bsp file in place, so it should not be referenced again
=============
*/
void WriteBSPFile (char *filename)
{
header = &outheader;
memset (header, 0, sizeof(dheader_t));
SwapBSPFile (true);
header->ident = LittleLong (IDBSPHEADER);
header->version = LittleLong (BSPVERSION);
wadfile = SafeOpenWrite (filename);
SafeWrite (wadfile, header, sizeof(dheader_t)); // overwritten later
AddLump (LUMP_PLANES, dplanes, numplanes*sizeof(dplane_t));
AddLump (LUMP_LEAFS, dleafs, numleafs*sizeof(dleaf_t));
AddLump (LUMP_VERTEXES, dvertexes, numvertexes*sizeof(dvertex_t));
AddLump (LUMP_NODES, dnodes, numnodes*sizeof(dnode_t));
AddLump (LUMP_TEXINFO, texinfo, numtexinfo*sizeof(texinfo_t));
AddLump (LUMP_FACES, dfaces, numfaces*sizeof(dface_t));
AddLump (LUMP_BRUSHES, dbrushes, numbrushes*sizeof(dbrush_t));
AddLump (LUMP_BRUSHSIDES, dbrushsides, numbrushsides*sizeof(dbrushside_t));
AddLump (LUMP_LEAFFACES, dleaffaces, numleaffaces*sizeof(dleaffaces[0]));
AddLump (LUMP_LEAFBRUSHES, dleafbrushes, numleafbrushes*sizeof(dleafbrushes[0]));
AddLump (LUMP_SURFEDGES, dsurfedges, numsurfedges*sizeof(dsurfedges[0]));
AddLump (LUMP_EDGES, dedges, numedges*sizeof(dedge_t));
AddLump (LUMP_MODELS, dmodels, nummodels*sizeof(dmodel_t));
AddLump (LUMP_AREAS, dareas, numareas*sizeof(darea_t));
AddLump (LUMP_AREAPORTALS, dareaportals, numareaportals*sizeof(dareaportal_t));
AddLump (LUMP_LIGHTING, dlightdata, lightdatasize);
AddLump (LUMP_VISIBILITY, dvisdata, visdatasize);
AddLump (LUMP_ENTITIES, dentdata, entdatasize);
AddLump (LUMP_POP, dpop, sizeof(dpop));
fseek (wadfile, 0, SEEK_SET);
SafeWrite (wadfile, header, sizeof(dheader_t));
fclose (wadfile);
}
//============================================================================
/*
=============
PrintBSPFileSizes
Dumps info about current file
=============
*/
void PrintBSPFileSizes (void)
{
if (!num_entities)
ParseEntities ();
printf ("%5i models %7i\n"
,nummodels, (int)(nummodels*sizeof(dmodel_t)));
printf ("%5i brushes %7i\n"
,numbrushes, (int)(numbrushes*sizeof(dbrush_t)));
printf ("%5i brushsides %7i\n"
,numbrushsides, (int)(numbrushsides*sizeof(dbrushside_t)));
printf ("%5i planes %7i\n"
,numplanes, (int)(numplanes*sizeof(dplane_t)));
printf ("%5i texinfo %7i\n"
,numtexinfo, (int)(numtexinfo*sizeof(texinfo_t)));
printf ("%5i entdata %7i\n", num_entities, entdatasize);
printf ("\n");
printf ("%5i vertexes %7i\n"
,numvertexes, (int)(numvertexes*sizeof(dvertex_t)));
printf ("%5i nodes %7i\n"
,numnodes, (int)(numnodes*sizeof(dnode_t)));
printf ("%5i faces %7i\n"
,numfaces, (int)(numfaces*sizeof(dface_t)));
printf ("%5i leafs %7i\n"
,numleafs, (int)(numleafs*sizeof(dleaf_t)));
printf ("%5i leaffaces %7i\n"
,numleaffaces, (int)(numleaffaces*sizeof(dleaffaces[0])));
printf ("%5i leafbrushes %7i\n"
,numleafbrushes, (int)(numleafbrushes*sizeof(dleafbrushes[0])));
printf ("%5i surfedges %7i\n"
,numsurfedges, (int)(numsurfedges*sizeof(dsurfedges[0])));
printf ("%5i edges %7i\n"
,numedges, (int)(numedges*sizeof(dedge_t)));
printf (" lightdata %7i\n", lightdatasize);
printf (" visdata %7i\n", visdatasize);
}
//============================================
int num_entities;
entity_t entities[MAX_MAP_ENTITIES];
void StripTrailing (char *e)
{
char *s;
s = e + strlen(e)-1;
while (s >= e && *s <= 32)
{
*s = 0;
s--;
}
}
/*
=================
ParseEpair
=================
*/
epair_t *ParseEpair (void)
{
epair_t *e;
e = malloc (sizeof(epair_t));
memset (e, 0, sizeof(epair_t));
if (strlen(token) >= MAX_KEY-1)
Error ("ParseEpar: token too long");
e->key = copystring(token);
GetToken (false);
if (strlen(token) >= MAX_VALUE-1)
Error ("ParseEpar: token too long");
e->value = copystring(token);
// strip trailing spaces
StripTrailing (e->key);
StripTrailing (e->value);
return e;
}
/*
================
ParseEntity
================
*/
qboolean ParseEntity (void)
{
epair_t *e;
entity_t *mapent;
if (!GetToken (true))
return false;
if (strcmp (token, "{") )
Error ("ParseEntity: { not found");
if (num_entities == MAX_MAP_ENTITIES)
Error ("num_entities == MAX_MAP_ENTITIES");
mapent = &entities[num_entities];
num_entities++;
do
{
if (!GetToken (true))
Error ("ParseEntity: EOF without closing brace");
if (!strcmp (token, "}") )
break;
e = ParseEpair ();
e->next = mapent->epairs;
mapent->epairs = e;
} while (1);
return true;
}
/*
================
ParseEntities
Parses the dentdata string into entities
================
*/
void ParseEntities (void)
{
num_entities = 0;
ParseFromMemory (dentdata, entdatasize);
while (ParseEntity ())
{
}
}
/*
================
UnparseEntities
Generates the dentdata string from all the entities
================
*/
void UnparseEntities (void)
{
char *buf, *end;
epair_t *ep;
char line[2048];
int i;
char key[1024], value[1024];
buf = dentdata;
end = buf;
*end = 0;
for (i=0 ; i<num_entities ; i++)
{
ep = entities[i].epairs;
if (!ep)
continue; // ent got removed
strcat (end,"{\n");
end += 2;
for (ep = entities[i].epairs ; ep ; ep=ep->next)
{
strcpy (key, ep->key);
StripTrailing (key);
strcpy (value, ep->value);
StripTrailing (value);
sprintf (line, "\"%s\" \"%s\"\n", key, value);
strcat (end, line);
end += strlen(line);
}
strcat (end,"}\n");
end += 2;
if (end > buf + MAX_MAP_ENTSTRING)
Error ("Entity text too long");
}
entdatasize = end - buf + 1;
}
void PrintEntity (entity_t *ent)
{
epair_t *ep;
printf ("------- entity %p -------\n", ent);
for (ep=ent->epairs ; ep ; ep=ep->next)
{
printf ("%s = %s\n", ep->key, ep->value);
}
}
void SetKeyValue (entity_t *ent, char *key, char *value)
{
epair_t *ep;
for (ep=ent->epairs ; ep ; ep=ep->next)
if (!strcmp (ep->key, key) )
{
free (ep->value);
ep->value = copystring(value);
return;
}
ep = malloc (sizeof(*ep));
ep->next = ent->epairs;
ent->epairs = ep;
ep->key = copystring(key);
ep->value = copystring(value);
}
char *ValueForKey (entity_t *ent, char *key)
{
epair_t *ep;
for (ep=ent->epairs ; ep ; ep=ep->next)
if (!strcmp (ep->key, key) )
return ep->value;
return "";
}
vec_t FloatForKey (entity_t *ent, char *key)
{
char *k;
k = ValueForKey (ent, key);
return atof(k);
}
void GetVectorForKey (entity_t *ent, char *key, vec3_t vec)
{
char *k;
double v1, v2, v3;
k = ValueForKey (ent, key);
// scanf into doubles, then assign, so it is vec_t size independent
v1 = v2 = v3 = 0;
sscanf (k, "%lf %lf %lf", &v1, &v2, &v3);
vec[0] = v1;
vec[1] = v2;
vec[2] = v3;
}

129
common/bspfile.h Normal file
View File

@@ -0,0 +1,129 @@
/*
===========================================================================
Copyright (C) 1997-2006 Id Software, Inc.
This file is part of Quake 2 Tools source code.
Quake 2 Tools source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake 2 Tools source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake 2 Tools source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "qfiles.h"
extern int nummodels;
extern dmodel_t dmodels[MAX_MAP_MODELS];
extern int visdatasize;
extern byte dvisdata[MAX_MAP_VISIBILITY];
extern dvis_t *dvis;
extern int lightdatasize;
extern byte dlightdata[MAX_MAP_LIGHTING];
extern int entdatasize;
extern char dentdata[MAX_MAP_ENTSTRING];
extern int numleafs;
extern dleaf_t dleafs[MAX_MAP_LEAFS];
extern int numplanes;
extern dplane_t dplanes[MAX_MAP_PLANES];
extern int numvertexes;
extern dvertex_t dvertexes[MAX_MAP_VERTS];
extern int numnodes;
extern dnode_t dnodes[MAX_MAP_NODES];
extern int numtexinfo;
extern texinfo_t texinfo[MAX_MAP_TEXINFO];
extern int numfaces;
extern dface_t dfaces[MAX_MAP_FACES];
extern int numedges;
extern dedge_t dedges[MAX_MAP_EDGES];
extern int numleaffaces;
extern unsigned short dleaffaces[MAX_MAP_LEAFFACES];
extern int numleafbrushes;
extern unsigned short dleafbrushes[MAX_MAP_LEAFBRUSHES];
extern int numsurfedges;
extern int dsurfedges[MAX_MAP_SURFEDGES];
extern int numareas;
extern darea_t dareas[MAX_MAP_AREAS];
extern int numareaportals;
extern dareaportal_t dareaportals[MAX_MAP_AREAPORTALS];
extern int numbrushes;
extern dbrush_t dbrushes[MAX_MAP_BRUSHES];
extern int numbrushsides;
extern dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES];
extern byte dpop[256];
void DecompressVis (byte *in, byte *decompressed);
int CompressVis (byte *vis, byte *dest);
void LoadBSPFile (char *filename);
void LoadBSPFileTexinfo (char *filename); // just for qdata
void WriteBSPFile (char *filename);
void PrintBSPFileSizes (void);
//===============
typedef struct epair_s
{
struct epair_s *next;
char *key;
char *value;
} epair_t;
typedef struct
{
vec3_t origin;
int firstbrush;
int numbrushes;
epair_t *epairs;
// only valid for func_areaportals
int areaportalnum;
int portalareas[2];
} entity_t;
extern int num_entities;
extern entity_t entities[MAX_MAP_ENTITIES];
void ParseEntities (void);
void UnparseEntities (void);
void SetKeyValue (entity_t *ent, char *key, char *value);
char *ValueForKey (entity_t *ent, char *key);
// will return "" if not present
vec_t FloatForKey (entity_t *ent, char *key);
void GetVectorForKey (entity_t *ent, char *key, vec3_t vec);
epair_t *ParseEpair (void);
void PrintEntity (entity_t *ent);

1055
common/cmdlib.c Normal file

File diff suppressed because it is too large Load Diff

145
common/cmdlib.h Normal file
View File

@@ -0,0 +1,145 @@
/*
===========================================================================
Copyright (C) 1997-2006 Id Software, Inc.
This file is part of Quake 2 Tools source code.
Quake 2 Tools source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake 2 Tools source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake 2 Tools source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// cmdlib.h
#ifndef __CMDLIB__
#define __CMDLIB__
#ifdef _WIN32
#pragma warning(disable : 4244) // MIPS
#pragma warning(disable : 4136) // X86
#pragma warning(disable : 4051) // ALPHA
#pragma warning(disable : 4018) // signed/unsigned mismatch
#pragma warning(disable : 4305) // truncate from double to float
#endif
#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 doesnt 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 Q_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 *ExpandArg (char *path); // from cmd line
char *ExpandPath (char *path); // from scripts
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);
int TryLoadFile (char *filename, void **bufferptr);
void SaveFile (char *filename, void *buffer, int count);
qboolean FileExists (char *filename);
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 QCopyFile (char *from, char *to);
extern qboolean archive;
extern char archivedir[1024];
extern qboolean verbose;
void qprintf (char *format, ...);
void ExpandWildcards (int *argc, char ***argv);
// for compression routines
typedef struct
{
byte *data;
int count;
} cblock_t;
#endif

301
common/l3dslib.c Normal file
View File

@@ -0,0 +1,301 @@
/*
===========================================================================
Copyright (C) 1997-2006 Id Software, Inc.
This file is part of Quake 2 Tools source code.
Quake 2 Tools source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake 2 Tools source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake 2 Tools source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// l3dslib.c: library for loading triangles from an Alias triangle file
//
#include <stdio.h>
#include "cmdlib.h"
#include "mathlib.h"
#include "trilib.h"
#include "l3dslib.h"
#define MAIN3DS 0x4D4D
#define EDIT3DS 0x3D3D // this is the start of the editor config
#define EDIT_OBJECT 0x4000
#define OBJ_TRIMESH 0x4100
#define TRI_VERTEXL 0x4110
#define TRI_FACEL1 0x4120
#define MAXVERTS 2000
typedef struct {
int v[4];
} tri;
float fverts[MAXVERTS][3];
tri tris[MAXTRIANGLES];
int bytesread, level, numtris, totaltris;
int vertsfound, trisfound;
triangle_t *ptri;
// Alias stores triangles as 3 explicit vertices in .tri files, so even though we
// start out with a vertex pool and vertex indices for triangles, we have to convert
// to raw, explicit triangles
void StoreAliasTriangles (void)
{
int i, j, k;
if ((totaltris + numtris) > MAXTRIANGLES)
Error ("Error: Too many triangles");
for (i=0; i<numtris ; i++)
{
for (j=0 ; j<3 ; j++)
{
for (k=0 ; k<3 ; k++)
{
ptri[i+totaltris].verts[j][k] = fverts[tris[i].v[j]][k];
}
}
}
totaltris += numtris;
numtris = 0;
vertsfound = 0;
trisfound = 0;
}
int ParseVertexL (FILE *input)
{
int i, j, startbytesread, numverts;
unsigned short tshort;
if (vertsfound)
Error ("Error: Multiple vertex chunks");
vertsfound = 1;
startbytesread = bytesread;
if (feof(input))
Error ("Error: unexpected end of file");
fread(&tshort, sizeof(tshort), 1, input);
bytesread += sizeof(tshort);
numverts = (int)tshort;
if (numverts > MAXVERTS)
Error ("Error: Too many vertices");
for (i=0 ; i<numverts ; i++)
{
for (j=0 ; j<3 ; j++)
{
if (feof(input))
Error ("Error: unexpected end of file");
fread(&fverts[i][j], sizeof(float), 1, input);
bytesread += sizeof(float);
}
}
if (vertsfound && trisfound)
StoreAliasTriangles ();
return bytesread - startbytesread;
}
int ParseFaceL1 (FILE *input)
{
int i, j, startbytesread;
unsigned short tshort;
if (trisfound)
Error ("Error: Multiple face chunks");
trisfound = 1;
startbytesread = bytesread;
if (feof(input))
Error ("Error: unexpected end of file");
fread(&tshort, sizeof(tshort), 1, input);
bytesread += sizeof(tshort);
numtris = (int)tshort;
if (numtris > MAXTRIANGLES)
Error ("Error: Too many triangles");
for (i=0 ; i<numtris ; i++)
{
for (j=0 ; j<4 ; j++)
{
if (feof(input))
Error ("Error: unexpected end of file");
fread(&tshort, sizeof(tshort), 1, input);
bytesread += sizeof(tshort);
tris[i].v[j] = (int)tshort;
}
}
if (vertsfound && trisfound)
StoreAliasTriangles ();
return bytesread - startbytesread;
}
int ParseChunk (FILE *input)
{
#define BLOCK_SIZE 4096
char temp[BLOCK_SIZE];
unsigned short type;
int i, length, w, t, retval;
level++;
retval = 0;
// chunk type
if (feof(input))
Error ("Error: unexpected end of file");
fread(&type, sizeof(type), 1, input);
bytesread += sizeof(type);
// chunk length
if (feof(input))
Error ("Error: unexpected end of file");
fread (&length, sizeof(length), 1, input);
bytesread += sizeof(length);
w = length - 6;
// process chunk if we care about it, otherwise skip it
switch (type)
{
case TRI_VERTEXL:
w -= ParseVertexL (input);
goto ParseSubchunk;
case TRI_FACEL1:
w -= ParseFaceL1 (input);
goto ParseSubchunk;
case EDIT_OBJECT:
// read the name
i = 0;
do
{
if (feof(input))
Error ("Error: unexpected end of file");
fread (&temp[i], 1, 1, input);
i++;
w--;
bytesread++;
} while (temp[i-1]);
case MAIN3DS:
case OBJ_TRIMESH:
case EDIT3DS:
// parse through subchunks
ParseSubchunk:
while (w > 0)
{
w -= ParseChunk (input);
}
retval = length;
goto Done;
default:
// skip other chunks
while (w > 0)
{
t = w;
if (t > BLOCK_SIZE)
t = BLOCK_SIZE;
if (feof(input))
Error ("Error: unexpected end of file");
fread (&temp, t, 1, input);
bytesread += t;
w -= t;
}
retval = length;
goto Done;
}
Done:
level--;
return retval;
}
void Load3DSTriangleList (char *filename, triangle_t **pptri, int *numtriangles)
{
FILE *input;
short int tshort;
bytesread = 0;
level = 0;
numtris = 0;
totaltris = 0;
vertsfound = 0;
trisfound = 0;
if ((input = fopen(filename, "rb")) == 0) {
fprintf(stderr,"reader: could not open file '%s'\n", filename);
exit(0);
}
fread(&tshort, sizeof(tshort), 1, input);
// should only be MAIN3DS, but some files seem to start with EDIT3DS, with
// no MAIN3DS
if ((tshort != MAIN3DS) && (tshort != EDIT3DS)) {
fprintf(stderr,"File is not a 3DS file.\n");
exit(0);
}
// back to top of file so we can parse the first chunk descriptor
fseek(input, 0, SEEK_SET);
ptri = malloc (MAXTRIANGLES * sizeof(triangle_t));
*pptri = ptri;
// parse through looking for the relevant chunk tree (MAIN3DS | EDIT3DS | EDIT_OBJECT |
// OBJ_TRIMESH | {TRI_VERTEXL, TRI_FACEL1}) and skipping other chunks
ParseChunk (input);
if (vertsfound || trisfound)
Error ("Incomplete triangle set");
*numtriangles = totaltris;
fclose (input);
}

27
common/l3dslib.h Normal file
View File

@@ -0,0 +1,27 @@
/*
===========================================================================
Copyright (C) 1997-2006 Id Software, Inc.
This file is part of Quake 2 Tools source code.
Quake 2 Tools source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake 2 Tools source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake 2 Tools source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// l3dslib.h: header file for loading triangles from a 3DS triangle file
//
void Load3DSTriangleList (char *filename, triangle_t **pptri, int *numtriangles);

824
common/lbmlib.c Normal file
View File

@@ -0,0 +1,824 @@
/*
===========================================================================
Copyright (C) 1997-2006 Id Software, Inc.
This file is part of Quake 2 Tools source code.
Quake 2 Tools source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake 2 Tools source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake 2 Tools source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// lbmlib.c
#include "cmdlib.h"
#include "lbmlib.h"
/*
============================================================================
LBM STUFF
============================================================================
*/
typedef unsigned char UBYTE;
//conflicts with windows typedef short WORD;
typedef unsigned short UWORD;
typedef long LONG;
typedef enum
{
ms_none,
ms_mask,
ms_transcolor,
ms_lasso
} mask_t;
typedef enum
{
cm_none,
cm_rle1
} compress_t;
typedef struct
{
UWORD w,h;
short x,y;
UBYTE nPlanes;
UBYTE masking;
UBYTE compression;
UBYTE pad1;
UWORD transparentColor;
UBYTE xAspect,yAspect;
short pageWidth,pageHeight;
} bmhd_t;
extern bmhd_t bmhd; // will be in native byte order
#define FORMID ('F'+('O'<<8)+((int)'R'<<16)+((int)'M'<<24))
#define ILBMID ('I'+('L'<<8)+((int)'B'<<16)+((int)'M'<<24))
#define PBMID ('P'+('B'<<8)+((int)'M'<<16)+((int)' '<<24))
#define BMHDID ('B'+('M'<<8)+((int)'H'<<16)+((int)'D'<<24))
#define BODYID ('B'+('O'<<8)+((int)'D'<<16)+((int)'Y'<<24))
#define CMAPID ('C'+('M'<<8)+((int)'A'<<16)+((int)'P'<<24))
bmhd_t bmhd;
int Align (int l)
{
if (l&1)
return l+1;
return l;
}
/*
================
LBMRLEdecompress
Source must be evenly aligned!
================
*/
byte *LBMRLEDecompress (byte *source,byte *unpacked, int bpwidth)
{
int count;
byte b,rept;
count = 0;
do
{
rept = *source++;
if (rept > 0x80)
{
rept = (rept^0xff)+2;
b = *source++;
memset(unpacked,b,rept);
unpacked += rept;
}
else if (rept < 0x80)
{
rept++;
memcpy(unpacked,source,rept);
unpacked += rept;
source += rept;
}
else
rept = 0; // rept of 0x80 is NOP
count += rept;
} while (count<bpwidth);
if (count>bpwidth)
Error ("Decompression exceeded width!\n");
return source;
}
/*
=================
LoadLBM
=================
*/
void LoadLBM (char *filename, byte **picture, byte **palette)
{
byte *LBMbuffer, *picbuffer, *cmapbuffer;
int y;
byte *LBM_P, *LBMEND_P;
byte *pic_p;
byte *body_p;
int formtype,formlength;
int chunktype,chunklength;
// qiet compiler warnings
picbuffer = NULL;
cmapbuffer = NULL;
//
// load the LBM
//
LoadFile (filename, (void **)&LBMbuffer);
//
// parse the LBM header
//
LBM_P = LBMbuffer;
if ( *(int *)LBMbuffer != LittleLong(FORMID) )
Error ("No FORM ID at start of file!\n");
LBM_P += 4;
formlength = BigLong( *(int *)LBM_P );
LBM_P += 4;
LBMEND_P = LBM_P + Align(formlength);
formtype = LittleLong(*(int *)LBM_P);
if (formtype != ILBMID && formtype != PBMID)
Error ("Unrecognized form type: %c%c%c%c\n", formtype&0xff
,(formtype>>8)&0xff,(formtype>>16)&0xff,(formtype>>24)&0xff);
LBM_P += 4;
//
// parse chunks
//
while (LBM_P < LBMEND_P)
{
chunktype = LBM_P[0] + (LBM_P[1]<<8) + (LBM_P[2]<<16) + (LBM_P[3]<<24);
LBM_P += 4;
chunklength = LBM_P[3] + (LBM_P[2]<<8) + (LBM_P[1]<<16) + (LBM_P[0]<<24);
LBM_P += 4;
switch ( chunktype )
{
case BMHDID:
memcpy (&bmhd,LBM_P,sizeof(bmhd));
bmhd.w = BigShort(bmhd.w);
bmhd.h = BigShort(bmhd.h);
bmhd.x = BigShort(bmhd.x);
bmhd.y = BigShort(bmhd.y);
bmhd.pageWidth = BigShort(bmhd.pageWidth);
bmhd.pageHeight = BigShort(bmhd.pageHeight);
break;
case CMAPID:
cmapbuffer = malloc (768);
memset (cmapbuffer, 0, 768);
memcpy (cmapbuffer, LBM_P, chunklength);
break;
case BODYID:
body_p = LBM_P;
pic_p = picbuffer = malloc (bmhd.w*bmhd.h);
if (formtype == PBMID)
{
//
// unpack PBM
//
for (y=0 ; y<bmhd.h ; y++, pic_p += bmhd.w)
{
if (bmhd.compression == cm_rle1)
body_p = LBMRLEDecompress ((byte *)body_p
, pic_p , bmhd.w);
else if (bmhd.compression == cm_none)
{
memcpy (pic_p,body_p,bmhd.w);
body_p += Align(bmhd.w);
}
}
}
else
{
//
// unpack ILBM
//
Error ("%s is an interlaced LBM, not packed", filename);
}
break;
}
LBM_P += Align(chunklength);
}
free (LBMbuffer);
*picture = picbuffer;
if (palette)
*palette = cmapbuffer;
}
/*
============================================================================
WRITE LBM
============================================================================
*/
/*
==============
WriteLBMfile
==============
*/
void WriteLBMfile (char *filename, byte *data,
int width, int height, byte *palette)
{
byte *lbm, *lbmptr;
int *formlength, *bmhdlength, *cmaplength, *bodylength;
int length;
bmhd_t basebmhd;
lbm = lbmptr = malloc (width*height+1000);
//
// start FORM
//
*lbmptr++ = 'F';
*lbmptr++ = 'O';
*lbmptr++ = 'R';
*lbmptr++ = 'M';
formlength = (int*)lbmptr;
lbmptr+=4; // leave space for length
*lbmptr++ = 'P';
*lbmptr++ = 'B';
*lbmptr++ = 'M';
*lbmptr++ = ' ';
//
// write BMHD
//
*lbmptr++ = 'B';
*lbmptr++ = 'M';
*lbmptr++ = 'H';
*lbmptr++ = 'D';
bmhdlength = (int *)lbmptr;
lbmptr+=4; // leave space for length
memset (&basebmhd,0,sizeof(basebmhd));
basebmhd.w = BigShort((short)width);
basebmhd.h = BigShort((short)height);
basebmhd.nPlanes = BigShort(8);
basebmhd.xAspect = BigShort(5);
basebmhd.yAspect = BigShort(6);
basebmhd.pageWidth = BigShort((short)width);
basebmhd.pageHeight = BigShort((short)height);
memcpy (lbmptr,&basebmhd,sizeof(basebmhd));
lbmptr += sizeof(basebmhd);
length = lbmptr-(byte *)bmhdlength-4;
*bmhdlength = BigLong(length);
if (length&1)
*lbmptr++ = 0; // pad chunk to even offset
//
// write CMAP
//
*lbmptr++ = 'C';
*lbmptr++ = 'M';
*lbmptr++ = 'A';
*lbmptr++ = 'P';
cmaplength = (int *)lbmptr;
lbmptr+=4; // leave space for length
memcpy (lbmptr,palette,768);
lbmptr += 768;
length = lbmptr-(byte *)cmaplength-4;
*cmaplength = BigLong(length);
if (length&1)
*lbmptr++ = 0; // pad chunk to even offset
//
// write BODY
//
*lbmptr++ = 'B';
*lbmptr++ = 'O';
*lbmptr++ = 'D';
*lbmptr++ = 'Y';
bodylength = (int *)lbmptr;
lbmptr+=4; // leave space for length
memcpy (lbmptr,data,width*height);
lbmptr += width*height;
length = lbmptr-(byte *)bodylength-4;
*bodylength = BigLong(length);
if (length&1)
*lbmptr++ = 0; // pad chunk to even offset
//
// done
//
length = lbmptr-(byte *)formlength-4;
*formlength = BigLong(length);
if (length&1)
*lbmptr++ = 0; // pad chunk to even offset
//
// write output file
//
SaveFile (filename, lbm, lbmptr-lbm);
free (lbm);
}
/*
============================================================================
LOAD PCX
============================================================================
*/
typedef struct
{
char manufacturer;
char version;
char encoding;
char bits_per_pixel;
unsigned short xmin,ymin,xmax,ymax;
unsigned short hres,vres;
unsigned char palette[48];
char reserved;
char color_planes;
unsigned short bytes_per_line;
unsigned short palette_type;
char filler[58];
unsigned char data; // unbounded
} pcx_t;
/*
==============
LoadPCX
==============
*/
void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height)
{
byte *raw;
pcx_t *pcx;
int x, y;
int len;
int dataByte, runLength;
byte *out, *pix;
//
// load the file
//
len = LoadFile (filename, (void **)&raw);
//
// parse the PCX file
//
pcx = (pcx_t *)raw;
raw = &pcx->data;
pcx->xmin = LittleShort(pcx->xmin);
pcx->ymin = LittleShort(pcx->ymin);
pcx->xmax = LittleShort(pcx->xmax);
pcx->ymax = LittleShort(pcx->ymax);
pcx->hres = LittleShort(pcx->hres);
pcx->vres = LittleShort(pcx->vres);
pcx->bytes_per_line = LittleShort(pcx->bytes_per_line);
pcx->palette_type = LittleShort(pcx->palette_type);
if (pcx->manufacturer != 0x0a
|| pcx->version != 5
|| pcx->encoding != 1
|| pcx->bits_per_pixel != 8
|| pcx->xmax >= 640
|| pcx->ymax >= 480)
Error ("Bad pcx file %s", filename);
if (palette)
{
*palette = malloc(768);
memcpy (*palette, (byte *)pcx + len - 768, 768);
}
if (width)
*width = pcx->xmax+1;
if (height)
*height = pcx->ymax+1;
if (!pic)
return;
out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
if (!out)
Error ("Skin_Cache: couldn't allocate");
*pic = out;
pix = out;
for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1)
{
for (x=0 ; x<=pcx->xmax ; )
{
dataByte = *raw++;
if((dataByte & 0xC0) == 0xC0)
{
runLength = dataByte & 0x3F;
dataByte = *raw++;
}
else
runLength = 1;
while(runLength-- > 0)
pix[x++] = dataByte;
}
}
if ( raw - (byte *)pcx > len)
Error ("PCX file %s was malformed", filename);
free (pcx);
}
/*
==============
WritePCXfile
==============
*/
void WritePCXfile (char *filename, byte *data,
int width, int height, byte *palette)
{
int i, j, length;
pcx_t *pcx;
byte *pack;
pcx = malloc (width*height*2+1000);
memset (pcx, 0, sizeof(*pcx));
pcx->manufacturer = 0x0a; // PCX id
pcx->version = 5; // 256 color
pcx->encoding = 1; // uncompressed
pcx->bits_per_pixel = 8; // 256 color
pcx->xmin = 0;
pcx->ymin = 0;
pcx->xmax = LittleShort((short)(width-1));
pcx->ymax = LittleShort((short)(height-1));
pcx->hres = LittleShort((short)width);
pcx->vres = LittleShort((short)height);
pcx->color_planes = 1; // chunky image
pcx->bytes_per_line = LittleShort((short)width);
pcx->palette_type = LittleShort(2); // not a grey scale
// pack the image
pack = &pcx->data;
for (i=0 ; i<height ; i++)
{
for (j=0 ; j<width ; j++)
{
if ( (*data & 0xc0) != 0xc0)
*pack++ = *data++;
else
{
*pack++ = 0xc1;
*pack++ = *data++;
}
}
}
// write the palette
*pack++ = 0x0c; // palette ID byte
for (i=0 ; i<768 ; i++)
*pack++ = *palette++;
// write output file
length = pack - (byte *)pcx;
SaveFile (filename, pcx, length);
free (pcx);
}
/*
============================================================================
LOAD IMAGE
============================================================================
*/
/*
==============
Load256Image
Will load either an lbm or pcx, depending on extension.
Any of the return pointers can be NULL if you don't want them.
==============
*/
void Load256Image (char *name, byte **pixels, byte **palette,
int *width, int *height)
{
char ext[128];
ExtractFileExtension (name, ext);
if (!Q_strcasecmp (ext, "lbm"))
{
LoadLBM (name, pixels, palette);
if (width)
*width = bmhd.w;
if (height)
*height = bmhd.h;
}
else if (!Q_strcasecmp (ext, "pcx"))
{
LoadPCX (name, pixels, palette, width, height);
}
else
Error ("%s doesn't have a known image extension", name);
}
/*
==============
Save256Image
Will save either an lbm or pcx, depending on extension.
==============
*/
void Save256Image (char *name, byte *pixels, byte *palette,
int width, int height)
{
char ext[128];
ExtractFileExtension (name, ext);
if (!Q_strcasecmp (ext, "lbm"))
{
WriteLBMfile (name, pixels, width, height, palette);
}
else if (!Q_strcasecmp (ext, "pcx"))
{
WritePCXfile (name, pixels, width, height, palette);
}
else
Error ("%s doesn't have a known image extension", name);
}
/*
============================================================================
TARGA IMAGE
============================================================================
*/
typedef struct _TargaHeader {
unsigned char id_length, colormap_type, image_type;
unsigned short colormap_index, colormap_length;
unsigned char colormap_size;
unsigned short x_origin, y_origin, width, height;
unsigned char pixel_size, attributes;
} TargaHeader;
int fgetLittleShort (FILE *f)
{
byte b1, b2;
b1 = fgetc(f);
b2 = fgetc(f);
return (short)(b1 + b2*256);
}
int fgetLittleLong (FILE *f)
{
byte b1, b2, b3, b4;
b1 = fgetc(f);
b2 = fgetc(f);
b3 = fgetc(f);
b4 = fgetc(f);
return b1 + (b2<<8) + (b3<<16) + (b4<<24);
}
/*
=============
LoadTGA
=============
*/
void LoadTGA (char *name, byte **pixels, int *width, int *height)
{
int columns, rows, numPixels;
byte *pixbuf;
int row, column;
FILE *fin;
byte *targa_rgba;
TargaHeader targa_header;
fin = fopen (name, "rb");
if (!fin)
Error ("Couldn't read %s", name);
targa_header.id_length = fgetc(fin);
targa_header.colormap_type = fgetc(fin);
targa_header.image_type = fgetc(fin);
targa_header.colormap_index = fgetLittleShort(fin);
targa_header.colormap_length = fgetLittleShort(fin);
targa_header.colormap_size = fgetc(fin);
targa_header.x_origin = fgetLittleShort(fin);
targa_header.y_origin = fgetLittleShort(fin);
targa_header.width = fgetLittleShort(fin);
targa_header.height = fgetLittleShort(fin);
targa_header.pixel_size = fgetc(fin);
targa_header.attributes = fgetc(fin);
if (targa_header.image_type!=2
&& targa_header.image_type!=10)
Error ("LoadTGA: Only type 2 and 10 targa RGB images supported\n");
if (targa_header.colormap_type !=0
|| (targa_header.pixel_size!=32 && targa_header.pixel_size!=24))
Error ("Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
columns = targa_header.width;
rows = targa_header.height;
numPixels = columns * rows;
if (width)
*width = columns;
if (height)
*height = rows;
targa_rgba = malloc(numPixels*4);
*pixels = targa_rgba;
if (targa_header.id_length != 0)
fseek(fin, targa_header.id_length, SEEK_CUR); // skip TARGA image comment
if (targa_header.image_type==2) { // Uncompressed, RGB images
for(row=rows-1; row>=0; row--) {
pixbuf = targa_rgba + row*columns*4;
for(column=0; column<columns; column++) {
unsigned char red,green,blue,alphabyte;
switch (targa_header.pixel_size) {
case 24:
blue = getc(fin);
green = getc(fin);
red = getc(fin);
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = 255;
break;
case 32:
blue = getc(fin);
green = getc(fin);
red = getc(fin);
alphabyte = getc(fin);
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = alphabyte;
break;
}
}
}
}
else if (targa_header.image_type==10) { // Runlength encoded RGB images
unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
for(row=rows-1; row>=0; row--) {
pixbuf = targa_rgba + row*columns*4;
for(column=0; column<columns; ) {
packetHeader=getc(fin);
packetSize = 1 + (packetHeader & 0x7f);
if (packetHeader & 0x80) { // run-length packet
switch (targa_header.pixel_size) {
case 24:
blue = getc(fin);
green = getc(fin);
red = getc(fin);
alphabyte = 255;
break;
case 32:
blue = getc(fin);
green = getc(fin);
red = getc(fin);
alphabyte = getc(fin);
break;
}
for(j=0;j<packetSize;j++) {
*pixbuf++=red;
*pixbuf++=green;
*pixbuf++=blue;
*pixbuf++=alphabyte;
column++;
if (column==columns) { // run spans across rows
column=0;
if (row>0)
row--;
else
goto breakOut;
pixbuf = targa_rgba + row*columns*4;
}
}
}
else { // non run-length packet
for(j=0;j<packetSize;j++) {
switch (targa_header.pixel_size) {
case 24:
blue = getc(fin);
green = getc(fin);
red = getc(fin);
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = 255;
break;
case 32:
blue = getc(fin);
green = getc(fin);
red = getc(fin);
alphabyte = getc(fin);
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = alphabyte;
break;
}
column++;
if (column==columns) { // pixel packet run spans across rows
column=0;
if (row>0)
row--;
else
goto breakOut;
pixbuf = targa_rgba + row*columns*4;
}
}
}
}
breakOut:;
}
}
fclose(fin);
}

40
common/lbmlib.h Normal file
View File

@@ -0,0 +1,40 @@
/*
===========================================================================
Copyright (C) 1997-2006 Id Software, Inc.
This file is part of Quake 2 Tools source code.
Quake 2 Tools source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake 2 Tools source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake 2 Tools source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// piclib.h
void LoadLBM (char *filename, byte **picture, byte **palette);
void WriteLBMfile (char *filename, byte *data, int width, int height
, byte *palette);
void LoadPCX (char *filename, byte **picture, byte **palette, int *width, int *height);
void WritePCXfile (char *filename, byte *data, int width, int height
, byte *palette);
// loads / saves either lbm or pcx, depending on extension
void Load256Image (char *name, byte **pixels, byte **palette,
int *width, int *height);
void Save256Image (char *name, byte *pixels, byte *palette,
int width, int height);
void LoadTGA (char *filename, byte **pixels, int *width, int *height);

174
common/mathlib.c Normal file
View File

@@ -0,0 +1,174 @@
/*
===========================================================================
Copyright (C) 1997-2006 Id Software, Inc.
This file is part of Quake 2 Tools source code.
Quake 2 Tools source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake 2 Tools source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake 2 Tools source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// mathlib.c -- math primitives
#include "cmdlib.h"
#include "mathlib.h"
vec3_t vec3_origin = {0,0,0};
double VectorLength(vec3_t v)
{
int i;
double length;
length = 0;
for (i=0 ; i< 3 ; i++)
length += v[i]*v[i];
length = sqrt (length); // FIXME
return length;
}
qboolean VectorCompare (vec3_t v1, vec3_t v2)
{
int i;
for (i=0 ; i<3 ; i++)
if (fabs(v1[i]-v2[i]) > EQUAL_EPSILON)
return false;
return true;
}
vec_t Q_rint (vec_t in)
{
return floor (in + 0.5);
}
void VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc)
{
vc[0] = va[0] + scale*vb[0];
vc[1] = va[1] + scale*vb[1];
vc[2] = va[2] + scale*vb[2];
}
void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross)
{
cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
}
vec_t _DotProduct (vec3_t v1, vec3_t v2)
{
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
}
void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out)
{
out[0] = va[0]-vb[0];
out[1] = va[1]-vb[1];
out[2] = va[2]-vb[2];
}
void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out)
{
out[0] = va[0]+vb[0];
out[1] = va[1]+vb[1];
out[2] = va[2]+vb[2];
}
void _VectorCopy (vec3_t in, vec3_t out)
{
out[0] = in[0];
out[1] = in[1];
out[2] = in[2];
}
void _VectorScale (vec3_t v, vec_t scale, vec3_t out)
{
out[0] = v[0] * scale;
out[1] = v[1] * scale;
out[2] = v[2] * scale;
}
vec_t VectorNormalize (vec3_t in, vec3_t out)
{
vec_t length, ilength;
length = sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]);
if (length == 0)
{
VectorClear (out);
return 0;
}
ilength = 1.0/length;
out[0] = in[0]*ilength;
out[1] = in[1]*ilength;
out[2] = in[2]*ilength;
return length;
}
vec_t ColorNormalize (vec3_t in, vec3_t out)
{
float max, scale;
max = in[0];
if (in[1] > max)
max = in[1];
if (in[2] > max)
max = in[2];
if (max == 0)
return 0;
scale = 1.0 / max;
VectorScale (in, scale, out);
return max;
}
void VectorInverse (vec3_t v)
{
v[0] = -v[0];
v[1] = -v[1];
v[2] = -v[2];
}
void ClearBounds (vec3_t mins, vec3_t maxs)
{
mins[0] = mins[1] = mins[2] = 99999;
maxs[0] = maxs[1] = maxs[2] = -99999;
}
void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs)
{
int i;
vec_t val;
for (i=0 ; i<3 ; i++)
{
val = v[i];
if (val < mins[i])
mins[i] = val;
if (val > maxs[i])
maxs[i] = val;
}
}

77
common/mathlib.h Normal file
View File

@@ -0,0 +1,77 @@
/*
===========================================================================
Copyright (C) 1997-2006 Id Software, Inc.
This file is part of Quake 2 Tools source code.
Quake 2 Tools source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake 2 Tools source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake 2 Tools source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#ifndef __MATHLIB__
#define __MATHLIB__
// mathlib.h
#include <math.h>
#ifdef DOUBLEVEC_T
typedef double vec_t;
#else
typedef float vec_t;
#endif
typedef vec_t vec3_t[3];
#define SIDE_FRONT 0
#define SIDE_ON 2
#define SIDE_BACK 1
#define SIDE_CROSS -2
#define Q_PI 3.14159265358979323846
extern vec3_t vec3_origin;
#define EQUAL_EPSILON 0.001
qboolean VectorCompare (vec3_t v1, vec3_t v2);
#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];}
#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];}
#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];}
#define VectorScale(a,b,c) {c[0]=b*a[0];c[1]=b*a[1];c[2]=b*a[2];}
#define VectorClear(x) {x[0] = x[1] = x[2] = 0;}
#define VectorNegate(x) {x[0]=-x[0];x[1]=-x[1];x[2]=-x[2];}
vec_t Q_rint (vec_t in);
vec_t _DotProduct (vec3_t v1, vec3_t v2);
void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out);
void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out);
void _VectorCopy (vec3_t in, vec3_t out);
void _VectorScale (vec3_t v, vec_t scale, vec3_t out);
double VectorLength(vec3_t v);
void VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc);
void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross);
vec_t VectorNormalize (vec3_t in, vec3_t out);
vec_t ColorNormalize (vec3_t in, vec3_t out);
void VectorInverse (vec3_t v);
void ClearBounds (vec3_t mins, vec3_t maxs);
void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs);
#endif

224
common/mdfour.c Normal file
View File

@@ -0,0 +1,224 @@
/*
mdfour.c
An implementation of MD4 designed for use in the samba SMB
authentication protocol
Copyright (C) 1997-1998 Andrew Tridgell
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
$Id: mdfour.c,v 1.1 2002/08/23 22:03:27 abster Exp $
*/
#include <string.h> /* XoXus: needed for memset call */
#include "mdfour.h"
/* NOTE: This code makes no attempt to be fast!
It assumes that a int is at least 32 bits long
*/
static struct mdfour *m;
#define F(X,Y,Z) (((X)&(Y)) | ((~(X))&(Z)))
#define G(X,Y,Z) (((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z)))
#define H(X,Y,Z) ((X)^(Y)^(Z))
#ifdef LARGE_INT32
#define lshift(x,s) ((((x)<<(s))&0xFFFFFFFF) | (((x)>>(32-(s)))&0xFFFFFFFF))
#else
#define lshift(x,s) (((x)<<(s)) | ((x)>>(32-(s))))
#endif
#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s)
#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + 0x5A827999,s)
#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + 0x6ED9EBA1,s)
/* this applies md4 to 64 byte chunks */
static void mdfour64(uint32 *M)
{
int j;
uint32 AA, BB, CC, DD;
uint32 X[16];
uint32 A,B,C,D;
for (j=0;j<16;j++)
X[j] = M[j];
A = m->A; B = m->B; C = m->C; D = m->D;
AA = A; BB = B; CC = C; DD = D;
ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7);
ROUND1(C,D,A,B, 2, 11); ROUND1(B,C,D,A, 3, 19);
ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7);
ROUND1(C,D,A,B, 6, 11); ROUND1(B,C,D,A, 7, 19);
ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7);
ROUND1(C,D,A,B, 10, 11); ROUND1(B,C,D,A, 11, 19);
ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7);
ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19);
ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5);
ROUND2(C,D,A,B, 8, 9); ROUND2(B,C,D,A, 12, 13);
ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5);
ROUND2(C,D,A,B, 9, 9); ROUND2(B,C,D,A, 13, 13);
ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5);
ROUND2(C,D,A,B, 10, 9); ROUND2(B,C,D,A, 14, 13);
ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5);
ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13);
ROUND3(A,B,C,D, 0, 3); ROUND3(D,A,B,C, 8, 9);
ROUND3(C,D,A,B, 4, 11); ROUND3(B,C,D,A, 12, 15);
ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9);
ROUND3(C,D,A,B, 6, 11); ROUND3(B,C,D,A, 14, 15);
ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9);
ROUND3(C,D,A,B, 5, 11); ROUND3(B,C,D,A, 13, 15);
ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9);
ROUND3(C,D,A,B, 7, 11); ROUND3(B,C,D,A, 15, 15);
A += AA; B += BB; C += CC; D += DD;
#ifdef LARGE_INT32
A &= 0xFFFFFFFF; B &= 0xFFFFFFFF;
C &= 0xFFFFFFFF; D &= 0xFFFFFFFF;
#endif
for (j=0;j<16;j++)
X[j] = 0;
m->A = A; m->B = B; m->C = C; m->D = D;
}
static void copy64(uint32 *M, unsigned char *in)
{
int i;
for (i=0;i<16;i++)
M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) |
(in[i*4+1]<<8) | (in[i*4+0]<<0);
}
static void copy4(unsigned char *out,uint32 x)
{
out[0] = x&0xFF;
out[1] = (x>>8)&0xFF;
out[2] = (x>>16)&0xFF;
out[3] = (x>>24)&0xFF;
}
void mdfour_begin(struct mdfour *md)
{
md->A = 0x67452301;
md->B = 0xefcdab89;
md->C = 0x98badcfe;
md->D = 0x10325476;
md->totalN = 0;
}
static void mdfour_tail(unsigned char *in, int n)
{
unsigned char buf[128];
uint32 M[16];
uint32 b;
m->totalN += n;
b = m->totalN * 8;
memset(buf, 0, 128);
if (n) memcpy(buf, in, n);
buf[n] = 0x80;
if (n <= 55) {
copy4(buf+56, b);
copy64(M, buf);
mdfour64(M);
} else {
copy4(buf+120, b);
copy64(M, buf);
mdfour64(M);
copy64(M, buf+64);
mdfour64(M);
}
}
void mdfour_update(struct mdfour *md, unsigned char *in, int n)
{
uint32 M[16];
if (n == 0) mdfour_tail(in, n);
m = md;
while (n >= 64) {
copy64(M, in);
mdfour64(M);
in += 64;
n -= 64;
m->totalN += 64;
}
mdfour_tail(in, n);
}
void mdfour_result(struct mdfour *md, unsigned char *out)
{
m = md;
copy4(out, m->A);
copy4(out+4, m->B);
copy4(out+8, m->C);
copy4(out+12, m->D);
}
void mdfour(unsigned char *out, unsigned char *in, int n)
{
struct mdfour md;
mdfour_begin(&md);
mdfour_update(&md, in, n);
mdfour_result(&md, out);
}
///////////////////////////////////////////////////////////////
// MD4-based checksum utility functions
//
// Copyright (C) 2000 Jeff Teunissen <d2deek@pmail.net>
//
// Author: Jeff Teunissen <d2deek@pmail.net>
// Date: 01 Jan 2000
unsigned Com_BlockChecksum (void *buffer, int length)
{
int digest[4];
unsigned val;
mdfour ( (unsigned char *) digest, (unsigned char *) buffer, length );
val = digest[0] ^ digest[1] ^ digest[2] ^ digest[3];
return val;
}
void Com_BlockFullChecksum (void *buffer, int len, unsigned char *outbuf)
{
mdfour ( outbuf, (unsigned char *) buffer, len );
}

54
common/mdfour.h Normal file
View File

@@ -0,0 +1,54 @@
/*
mdfour.h
an implementation of MD4 designed for use in the SMB authentication
protocol
Copyright (C) Andrew Tridgell 1997-1998
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifndef _MDFOUR_H
#define _MDFOUR_H
#ifndef int32
#define int32 int
#endif
#if SIZEOF_INT > 4
#define LARGE_INT32
#endif
#ifndef uint32
#define uint32 unsigned int32
#endif
struct mdfour {
uint32 A, B, C, D;
uint32 totalN;
};
void mdfour_begin(struct mdfour *md); // old: MD4Init
void mdfour_update(struct mdfour *md, unsigned char *in, int n); //old: MD4Update
void mdfour_result(struct mdfour *md, unsigned char *out); // old: MD4Final
void mdfour(unsigned char *out, unsigned char *in, int n);
#endif // _MDFOUR_H

642
common/polylib.c Normal file
View File

@@ -0,0 +1,642 @@
/*
===========================================================================
Copyright (C) 1997-2006 Id Software, Inc.
This file is part of Quake 2 Tools source code.
Quake 2 Tools source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake 2 Tools source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake 2 Tools source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "cmdlib.h"
#include "mathlib.h"
#include "polylib.h"
extern int numthreads;
// counters are only bumped when running single threaded,
// because they are an awefull coherence problem
int c_active_windings;
int c_peak_windings;
int c_winding_allocs;
int c_winding_points;
#define BOGUS_RANGE 8192
void pw(winding_t *w)
{
int i;
for (i=0 ; i<w->numpoints ; i++)
printf ("(%5.1f, %5.1f, %5.1f)\n",w->p[i][0], w->p[i][1],w->p[i][2]);
}
/*
=============
AllocWinding
=============
*/
winding_t *AllocWinding (int points)
{
winding_t *w;
int s;
if (numthreads == 1)
{
c_winding_allocs++;
c_winding_points += points;
c_active_windings++;
if (c_active_windings > c_peak_windings)
c_peak_windings = c_active_windings;
}
s = sizeof(vec_t)*3*points + sizeof(int);
w = malloc (s);
memset (w, 0, s);
return w;
}
void FreeWinding (winding_t *w)
{
if (*(unsigned *)w == 0xdeaddead)
Error ("FreeWinding: freed a freed winding");
*(unsigned *)w = 0xdeaddead;
if (numthreads == 1)
c_active_windings--;
free (w);
}
/*
============
RemoveColinearPoints
============
*/
int c_removed;
void RemoveColinearPoints (winding_t *w)
{
int i, j, k;
vec3_t v1, v2;
int nump;
vec3_t p[MAX_POINTS_ON_WINDING];
nump = 0;
for (i=0 ; i<w->numpoints ; i++)
{
j = (i+1)%w->numpoints;
k = (i+w->numpoints-1)%w->numpoints;
VectorSubtract (w->p[j], w->p[i], v1);
VectorSubtract (w->p[i], w->p[k], v2);
VectorNormalize(v1,v1);
VectorNormalize(v2,v2);
if (DotProduct(v1, v2) < 0.999)
{
VectorCopy (w->p[i], p[nump]);
nump++;
}
}
if (nump == w->numpoints)
return;
if (numthreads == 1)
c_removed += w->numpoints - nump;
w->numpoints = nump;
memcpy (w->p, p, nump*sizeof(p[0]));
}
/*
============
WindingPlane
============
*/
void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist)
{
vec3_t v1, v2;
VectorSubtract (w->p[1], w->p[0], v1);
VectorSubtract (w->p[2], w->p[0], v2);
CrossProduct (v2, v1, normal);
VectorNormalize (normal, normal);
*dist = DotProduct (w->p[0], normal);
}
/*
=============
WindingArea
=============
*/
vec_t WindingArea (winding_t *w)
{
int i;
vec3_t d1, d2, cross;
vec_t total;
total = 0;
for (i=2 ; i<w->numpoints ; i++)
{
VectorSubtract (w->p[i-1], w->p[0], d1);
VectorSubtract (w->p[i], w->p[0], d2);
CrossProduct (d1, d2, cross);
total += 0.5 * VectorLength ( cross );
}
return total;
}
void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs)
{
vec_t v;
int i,j;
mins[0] = mins[1] = mins[2] = 99999;
maxs[0] = maxs[1] = maxs[2] = -99999;
for (i=0 ; i<w->numpoints ; i++)
{
for (j=0 ; j<3 ; j++)
{
v = w->p[i][j];
if (v < mins[j])
mins[j] = v;
if (v > maxs[j])
maxs[j] = v;
}
}
}
/*
=============
WindingCenter
=============
*/
void WindingCenter (winding_t *w, vec3_t center)
{
int i;
float scale;
VectorCopy (vec3_origin, center);
for (i=0 ; i<w->numpoints ; i++)
VectorAdd (w->p[i], center, center);
scale = 1.0/w->numpoints;
VectorScale (center, scale, center);
}
/*
=================
BaseWindingForPlane
=================
*/
winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist)
{
int i, x;
vec_t max, v;
vec3_t org, vright, vup;
winding_t *w;
// find the major axis
max = -BOGUS_RANGE;
x = -1;
for (i=0 ; i<3; i++)
{
v = fabs(normal[i]);
if (v > max)
{
x = i;
max = v;
}
}
if (x==-1)
Error ("BaseWindingForPlane: no axis found");
VectorCopy (vec3_origin, vup);
switch (x)
{
case 0:
case 1:
vup[2] = 1;
break;
case 2:
vup[0] = 1;
break;
}
v = DotProduct (vup, normal);
VectorMA (vup, -v, normal, vup);
VectorNormalize (vup, vup);
VectorScale (normal, dist, org);
CrossProduct (vup, normal, vright);
VectorScale (vup, 8192, vup);
VectorScale (vright, 8192, vright);
// project a really big axis aligned box onto the plane
w = AllocWinding (4);
VectorSubtract (org, vright, w->p[0]);
VectorAdd (w->p[0], vup, w->p[0]);
VectorAdd (org, vright, w->p[1]);
VectorAdd (w->p[1], vup, w->p[1]);
VectorAdd (org, vright, w->p[2]);
VectorSubtract (w->p[2], vup, w->p[2]);
VectorSubtract (org, vright, w->p[3]);
VectorSubtract (w->p[3], vup, w->p[3]);
w->numpoints = 4;
return w;
}
/*
==================
CopyWinding
==================
*/
winding_t *CopyWinding (winding_t *w)
{
int size;
winding_t *c;
c = AllocWinding (w->numpoints);
size = (int)((winding_t *)0)->p[w->numpoints];
memcpy (c, w, size);
return c;
}
/*
==================
ReverseWinding
==================
*/
winding_t *ReverseWinding (winding_t *w)
{
int i;
winding_t *c;
c = AllocWinding (w->numpoints);
for (i=0 ; i<w->numpoints ; i++)
{
VectorCopy (w->p[w->numpoints-1-i], c->p[i]);
}
c->numpoints = w->numpoints;
return c;
}
/*
=============
ClipWindingEpsilon
=============
*/
void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist,
vec_t epsilon, winding_t **front, winding_t **back)
{
vec_t dists[MAX_POINTS_ON_WINDING+4];
int sides[MAX_POINTS_ON_WINDING+4];
int counts[3];
static vec_t dot; // VC 4.2 optimizer bug if not static
int i, j;
vec_t *p1, *p2;
vec3_t mid;
winding_t *f, *b;
int maxpts;
counts[0] = counts[1] = counts[2] = 0;
// determine sides for each point
for (i=0 ; i<in->numpoints ; i++)
{
dot = DotProduct (in->p[i], normal);
dot -= dist;
dists[i] = dot;
if (dot > epsilon)
sides[i] = SIDE_FRONT;
else if (dot < -epsilon)
sides[i] = SIDE_BACK;
else
{
sides[i] = SIDE_ON;
}
counts[sides[i]]++;
}
sides[i] = sides[0];
dists[i] = dists[0];
*front = *back = NULL;
if (!counts[0])
{
*back = CopyWinding (in);
return;
}
if (!counts[1])
{
*front = CopyWinding (in);
return;
}
maxpts = in->numpoints+4; // cant use counts[0]+2 because
// of fp grouping errors
*front = f = AllocWinding (maxpts);
*back = b = AllocWinding (maxpts);
for (i=0 ; i<in->numpoints ; i++)
{
p1 = in->p[i];
if (sides[i] == SIDE_ON)
{
VectorCopy (p1, f->p[f->numpoints]);
f->numpoints++;
VectorCopy (p1, b->p[b->numpoints]);
b->numpoints++;
continue;
}
if (sides[i] == SIDE_FRONT)
{
VectorCopy (p1, f->p[f->numpoints]);
f->numpoints++;
}
if (sides[i] == SIDE_BACK)
{
VectorCopy (p1, b->p[b->numpoints]);
b->numpoints++;
}
if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
continue;
// generate a split point
p2 = in->p[(i+1)%in->numpoints];
dot = dists[i] / (dists[i]-dists[i+1]);
for (j=0 ; j<3 ; j++)
{ // avoid round off error when possible
if (normal[j] == 1)
mid[j] = dist;
else if (normal[j] == -1)
mid[j] = -dist;
else
mid[j] = p1[j] + dot*(p2[j]-p1[j]);
}
VectorCopy (mid, f->p[f->numpoints]);
f->numpoints++;
VectorCopy (mid, b->p[b->numpoints]);
b->numpoints++;
}
if (f->numpoints > maxpts || b->numpoints > maxpts)
Error ("ClipWinding: points exceeded estimate");
if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)
Error ("ClipWinding: MAX_POINTS_ON_WINDING");
}
/*
=============
ChopWindingInPlace
=============
*/
void ChopWindingInPlace (winding_t **inout, vec3_t normal, vec_t dist, vec_t epsilon)
{
winding_t *in;
vec_t dists[MAX_POINTS_ON_WINDING+4];
int sides[MAX_POINTS_ON_WINDING+4];
int counts[3];
static vec_t dot; // VC 4.2 optimizer bug if not static
int i, j;
vec_t *p1, *p2;
vec3_t mid;
winding_t *f;
int maxpts;
in = *inout;
counts[0] = counts[1] = counts[2] = 0;
// determine sides for each point
for (i=0 ; i<in->numpoints ; i++)
{
dot = DotProduct (in->p[i], normal);
dot -= dist;
dists[i] = dot;
if (dot > epsilon)
sides[i] = SIDE_FRONT;
else if (dot < -epsilon)
sides[i] = SIDE_BACK;
else
{
sides[i] = SIDE_ON;
}
counts[sides[i]]++;
}
sides[i] = sides[0];
dists[i] = dists[0];
if (!counts[0])
{
FreeWinding (in);
*inout = NULL;
return;
}
if (!counts[1])
return; // inout stays the same
maxpts = in->numpoints+4; // cant use counts[0]+2 because
// of fp grouping errors
f = AllocWinding (maxpts);
for (i=0 ; i<in->numpoints ; i++)
{
p1 = in->p[i];
if (sides[i] == SIDE_ON)
{
VectorCopy (p1, f->p[f->numpoints]);
f->numpoints++;
continue;
}
if (sides[i] == SIDE_FRONT)
{
VectorCopy (p1, f->p[f->numpoints]);
f->numpoints++;
}
if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
continue;
// generate a split point
p2 = in->p[(i+1)%in->numpoints];
dot = dists[i] / (dists[i]-dists[i+1]);
for (j=0 ; j<3 ; j++)
{ // avoid round off error when possible
if (normal[j] == 1)
mid[j] = dist;
else if (normal[j] == -1)
mid[j] = -dist;
else
mid[j] = p1[j] + dot*(p2[j]-p1[j]);
}
VectorCopy (mid, f->p[f->numpoints]);
f->numpoints++;
}
if (f->numpoints > maxpts)
Error ("ClipWinding: points exceeded estimate");
if (f->numpoints > MAX_POINTS_ON_WINDING)
Error ("ClipWinding: MAX_POINTS_ON_WINDING");
FreeWinding (in);
*inout = f;
}
/*
=================
ChopWinding
Returns the fragment of in that is on the front side
of the cliping plane. The original is freed.
=================
*/
winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist)
{
winding_t *f, *b;
ClipWindingEpsilon (in, normal, dist, ON_EPSILON, &f, &b);
FreeWinding (in);
if (b)
FreeWinding (b);
return f;
}
/*
=================
CheckWinding
=================
*/
void CheckWinding (winding_t *w)
{
int i, j;
vec_t *p1, *p2;
vec_t d, edgedist;
vec3_t dir, edgenormal, facenormal;
vec_t area;
vec_t facedist;
if (w->numpoints < 3)
Error ("CheckWinding: %i points",w->numpoints);
area = WindingArea(w);
if (area < 1)
Error ("CheckWinding: %f area", area);
WindingPlane (w, facenormal, &facedist);
for (i=0 ; i<w->numpoints ; i++)
{
p1 = w->p[i];
for (j=0 ; j<3 ; j++)
if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE)
Error ("CheckFace: BUGUS_RANGE: %f",p1[j]);
j = i+1 == w->numpoints ? 0 : i+1;
// check the point is on the face plane
d = DotProduct (p1, facenormal) - facedist;
if (d < -ON_EPSILON || d > ON_EPSILON)
Error ("CheckWinding: point off plane");
// check the edge isnt degenerate
p2 = w->p[j];
VectorSubtract (p2, p1, dir);
if (VectorLength (dir) < ON_EPSILON)
Error ("CheckWinding: degenerate edge");
CrossProduct (facenormal, dir, edgenormal);
VectorNormalize (edgenormal, edgenormal);
edgedist = DotProduct (p1, edgenormal);
edgedist += ON_EPSILON;
// all other points must be on front side
for (j=0 ; j<w->numpoints ; j++)
{
if (j == i)
continue;
d = DotProduct (w->p[j], edgenormal);
if (d > edgedist)
Error ("CheckWinding: non-convex");
}
}
}
/*
============
WindingOnPlaneSide
============
*/
int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist)
{
qboolean front, back;
int i;
vec_t d;
front = false;
back = false;
for (i=0 ; i<w->numpoints ; i++)
{
d = DotProduct (w->p[i], normal) - dist;
if (d < -ON_EPSILON)
{
if (front)
return SIDE_CROSS;
back = true;
continue;
}
if (d > ON_EPSILON)
{
if (back)
return SIDE_CROSS;
front = true;
continue;
}
}
if (back)
return SIDE_BACK;
if (front)
return SIDE_FRONT;
return SIDE_ON;
}

55
common/polylib.h Normal file
View File

@@ -0,0 +1,55 @@
/*
===========================================================================
Copyright (C) 1997-2006 Id Software, Inc.
This file is part of Quake 2 Tools source code.
Quake 2 Tools source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake 2 Tools source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake 2 Tools source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
typedef struct
{
int numpoints;
vec3_t p[4]; // variable sized
} winding_t;
#define MAX_POINTS_ON_WINDING 64
// you can define on_epsilon in the makefile as tighter
#ifndef ON_EPSILON
#define ON_EPSILON 0.1
#endif
winding_t *AllocWinding (int points);
vec_t WindingArea (winding_t *w);
void WindingCenter (winding_t *w, vec3_t center);
void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist,
vec_t epsilon, winding_t **front, winding_t **back);
winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist);
winding_t *CopyWinding (winding_t *w);
winding_t *ReverseWinding (winding_t *w);
winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist);
void CheckWinding (winding_t *w);
void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist);
void RemoveColinearPoints (winding_t *w);
int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist);
void FreeWinding (winding_t *w);
void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs);
void ChopWindingInPlace (winding_t **w, vec3_t normal, vec_t dist, vec_t epsilon);
// frees the original if clipped
void pw(winding_t *w);

486
common/qfiles.h Normal file
View File

@@ -0,0 +1,486 @@
/*
===========================================================================
Copyright (C) 1997-2006 Id Software, Inc.
This file is part of Quake 2 Tools source code.
Quake 2 Tools source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake 2 Tools source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake 2 Tools source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// qfiles.h: quake file formats
// This file must be identical in the quake and utils directories
//
/*
========================================================================
The .pak files are just a linear collapse of a directory tree
========================================================================
*/
#define IDPAKHEADER (('K'<<24)+('C'<<16)+('A'<<8)+'P')
typedef struct
{
char name[56];
int filepos, filelen;
} dpackfile_t;
typedef struct
{
int ident; // == IDPAKHEADER
int dirofs;
int dirlen;
} dpackheader_t;
#define MAX_FILES_IN_PACK 4096
/*
========================================================================
PCX files are used for as many images as possible
========================================================================
*/
typedef struct
{
char manufacturer;
char version;
char encoding;
char bits_per_pixel;
unsigned short xmin,ymin,xmax,ymax;
unsigned short hres,vres;
unsigned char palette[48];
char reserved;
char color_planes;
unsigned short bytes_per_line;
unsigned short palette_type;
char filler[58];
unsigned char data; // unbounded
} pcx_t;
/*
========================================================================
.MD2 triangle model file format
========================================================================
*/
#define IDALIASHEADER (('2'<<24)+('P'<<16)+('D'<<8)+'I')
#define ALIAS_VERSION 8
#define MAX_TRIANGLES 4096
#define MAX_VERTS 2048
#define MAX_FRAMES 512
#define MAX_MD2SKINS 32
#define MAX_SKINNAME 64
typedef struct
{
short s;
short t;
} dstvert_t;
typedef struct
{
short index_xyz[3];
short index_st[3];
} dtriangle_t;
typedef struct
{
byte v[3]; // scaled byte to fit in frame mins/maxs
byte lightnormalindex;
} dtrivertx_t;
#define DTRIVERTX_V0 0
#define DTRIVERTX_V1 1
#define DTRIVERTX_V2 2
#define DTRIVERTX_LNI 3
#define DTRIVERTX_SIZE 4
typedef struct
{
float scale[3]; // multiply byte verts by this
float translate[3]; // then add this
char name[16]; // frame name from grabbing
dtrivertx_t verts[1]; // variable sized
} daliasframe_t;
// the glcmd format:
// a positive integer starts a tristrip command, followed by that many
// vertex structures.
// a negative integer starts a trifan command, followed by -x vertexes
// a zero indicates the end of the command list.
// a vertex consists of a floating point s, a floating point t,
// and an integer vertex index.
typedef struct
{
int ident;
int version;
int skinwidth;
int skinheight;
int framesize; // byte size of each frame
int num_skins;
int num_xyz;
int num_st; // greater than num_xyz for seams
int num_tris;
int num_glcmds; // dwords in strip/fan command list
int num_frames;
int ofs_skins; // each skin is a MAX_SKINNAME string
int ofs_st; // byte offset from start for stverts
int ofs_tris; // offset for dtriangles
int ofs_frames; // offset for first frame
int ofs_glcmds;
int ofs_end; // end of file
} dmdl_t;
/*
========================================================================
.SP2 sprite file format
========================================================================
*/
#define IDSPRITEHEADER (('2'<<24)+('S'<<16)+('D'<<8)+'I')
// little-endian "IDS2"
#define SPRITE_VERSION 2
typedef struct
{
int width, height;
int origin_x, origin_y; // raster coordinates inside pic
char name[MAX_SKINNAME]; // name of pcx file
} dsprframe_t;
typedef struct {
int ident;
int version;
int numframes;
dsprframe_t frames[1]; // variable sized
} dsprite_t;
/*
==============================================================================
.WAL texture file format
==============================================================================
*/
#define MIPLEVELS 4
typedef struct miptex_s
{
char name[32];
unsigned width, height;
unsigned offsets[MIPLEVELS]; // four mip maps stored
char animname[32]; // next frame in animation chain
int flags;
int contents;
int value;
} miptex_t;
/*
==============================================================================
.BSP file format
==============================================================================
*/
#define IDBSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I')
// little-endian "IBSP"
#define BSPVERSION 38
// upper design bounds
// leaffaces, leafbrushes, planes, and verts are still bounded by
// 16 bit short limits
#define MAX_MAP_MODELS 1024
#define MAX_MAP_BRUSHES 8192
#define MAX_MAP_ENTITIES 2048
#define MAX_MAP_ENTSTRING 0x40000
#define MAX_MAP_TEXINFO 8192
#define MAX_MAP_AREAS 256
#define MAX_MAP_AREAPORTALS 1024
#define MAX_MAP_PLANES 65536
#define MAX_MAP_NODES 65536
#define MAX_MAP_BRUSHSIDES 65536
#define MAX_MAP_LEAFS 65536
#define MAX_MAP_VERTS 65536
#define MAX_MAP_FACES 65536
#define MAX_MAP_LEAFFACES 65536
#define MAX_MAP_LEAFBRUSHES 65536
#define MAX_MAP_PORTALS 65536
#define MAX_MAP_EDGES 128000
#define MAX_MAP_SURFEDGES 256000
#define MAX_MAP_LIGHTING 0x200000
#define MAX_MAP_VISIBILITY 0x100000
// key / value pair sizes
#define MAX_KEY 32
#define MAX_VALUE 1024
//=============================================================================
typedef struct
{
int fileofs, filelen;
} lump_t;
#define LUMP_ENTITIES 0
#define LUMP_PLANES 1
#define LUMP_VERTEXES 2
#define LUMP_VISIBILITY 3
#define LUMP_NODES 4
#define LUMP_TEXINFO 5
#define LUMP_FACES 6
#define LUMP_LIGHTING 7
#define LUMP_LEAFS 8
#define LUMP_LEAFFACES 9
#define LUMP_LEAFBRUSHES 10
#define LUMP_EDGES 11
#define LUMP_SURFEDGES 12
#define LUMP_MODELS 13
#define LUMP_BRUSHES 14
#define LUMP_BRUSHSIDES 15
#define LUMP_POP 16
#define LUMP_AREAS 17
#define LUMP_AREAPORTALS 18
#define HEADER_LUMPS 19
typedef struct
{
int ident;
int version;
lump_t lumps[HEADER_LUMPS];
} dheader_t;
typedef struct
{
float mins[3], maxs[3];
float origin[3]; // for sounds or lights
int headnode;
int firstface, numfaces; // submodels just draw faces
// without walking the bsp tree
} dmodel_t;
typedef struct
{
float point[3];
} dvertex_t;
// 0-2 are axial planes
#define PLANE_X 0
#define PLANE_Y 1
#define PLANE_Z 2
// 3-5 are non-axial planes snapped to the nearest
#define PLANE_ANYX 3
#define PLANE_ANYY 4
#define PLANE_ANYZ 5
// planes (x&~1) and (x&~1)+1 are allways opposites
typedef struct
{
float normal[3];
float dist;
int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
} dplane_t;
// contents flags are seperate bits
// a given brush can contribute multiple content bits
// multiple brushes can be in a single leaf
// these definitions also need to be in q_shared.h!
// lower bits are stronger, and will eat weaker brushes completely
#define CONTENTS_SOLID 1 // an eye is never valid in a solid
#define CONTENTS_WINDOW 2 // translucent, but not watery
#define CONTENTS_AUX 4
#define CONTENTS_LAVA 8
#define CONTENTS_SLIME 16
#define CONTENTS_WATER 32
#define CONTENTS_MIST 64
#define LAST_VISIBLE_CONTENTS 64
// remaining contents are non-visible, and don't eat brushes
#define CONTENTS_AREAPORTAL 0x8000
#define CONTENTS_PLAYERCLIP 0x10000
#define CONTENTS_MONSTERCLIP 0x20000
// currents can be added to any other contents, and may be mixed
#define CONTENTS_CURRENT_0 0x40000
#define CONTENTS_CURRENT_90 0x80000
#define CONTENTS_CURRENT_180 0x100000
#define CONTENTS_CURRENT_270 0x200000
#define CONTENTS_CURRENT_UP 0x400000
#define CONTENTS_CURRENT_DOWN 0x800000
#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity
#define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game
#define CONTENTS_DEADMONSTER 0x4000000
#define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs
#define CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans
#define CONTENTS_LADDER 0x20000000
#define SURF_LIGHT 0x1 // value will hold the light strength
#define SURF_SLICK 0x2 // effects game physics
#define SURF_SKY 0x4 // don't draw, but add to skybox
#define SURF_WARP 0x8 // turbulent water warp
#define SURF_TRANS33 0x10
#define SURF_TRANS66 0x20
#define SURF_FLOWING 0x40 // scroll towards angle
#define SURF_NODRAW 0x80 // don't bother referencing the texture
#define SURF_HINT 0x100 // make a primary bsp splitter
#define SURF_SKIP 0x200 // completely ignore, allowing non-closed brushes
typedef struct
{
int planenum;
int children[2]; // negative numbers are -(leafs+1), not nodes
short mins[3]; // for frustom culling
short maxs[3];
unsigned short firstface;
unsigned short numfaces; // counting both sides
} dnode_t;
typedef struct texinfo_s
{
float vecs[2][4]; // [s/t][xyz offset]
int flags; // miptex flags + overrides
int value; // light emission, etc
char texture[32]; // texture name (textures/*.wal)
int nexttexinfo; // for animations, -1 = end of chain
} texinfo_t;
// note that edge 0 is never used, because negative edge nums are used for
// counterclockwise use of the edge in a face
typedef struct
{
unsigned short v[2]; // vertex numbers
} dedge_t;
#define MAXLIGHTMAPS 4
typedef struct
{
unsigned short planenum;
short side;
int firstedge; // we must support > 64k edges
short numedges;
short texinfo;
// lighting info
byte styles[MAXLIGHTMAPS];
int lightofs; // start of [numstyles*surfsize] samples
} dface_t;
typedef struct
{
int contents; // OR of all brushes (not needed?)
short cluster;
short area;
short mins[3]; // for frustum culling
short maxs[3];
unsigned short firstleafface;
unsigned short numleaffaces;
unsigned short firstleafbrush;
unsigned short numleafbrushes;
} dleaf_t;
typedef struct
{
unsigned short planenum; // facing out of the leaf
short texinfo;
} dbrushside_t;
typedef struct
{
int firstside;
int numsides;
int contents;
} dbrush_t;
#define ANGLE_UP -1
#define ANGLE_DOWN -2
// the visibility lump consists of a header with a count, then
// byte offsets for the PVS and PHS of each cluster, then the raw
// compressed bit vectors
#define DVIS_PVS 0
#define DVIS_PHS 1
typedef struct
{
int numclusters;
int bitofs[8][2]; // bitofs[numclusters][2]
} dvis_t;
// each area has a list of portals that lead into other areas
// when portals are closed, other areas may not be visible or
// hearable even if the vis info says that it should be
typedef struct
{
int portalnum;
int otherarea;
} dareaportal_t;
typedef struct
{
int numareaportals;
int firstareaportal;
} darea_t;

297
common/scriplib.c Normal file
View File

@@ -0,0 +1,297 @@
/*
===========================================================================
Copyright (C) 1997-2006 Id Software, Inc.
This file is part of Quake 2 Tools source code.
Quake 2 Tools source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake 2 Tools source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake 2 Tools source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// scriplib.c
#include "cmdlib.h"
#include "scriplib.h"
/*
=============================================================================
PARSING STUFF
=============================================================================
*/
typedef struct
{
char filename[1024];
char *buffer,*script_p,*end_p;
int line;
} script_t;
#define MAX_INCLUDES 8
script_t scriptstack[MAX_INCLUDES];
script_t *script;
int scriptline;
char token[MAXTOKEN];
qboolean endofscript;
qboolean tokenready; // only true if UnGetToken was just called
/*
==============
AddScriptToStack
==============
*/
void AddScriptToStack (char *filename)
{
int size;
script++;
if (script == &scriptstack[MAX_INCLUDES])
Error ("script file exceeded MAX_INCLUDES");
strcpy (script->filename, ExpandPath (filename) );
size = LoadFile (script->filename, (void **)&script->buffer);
printf ("entering %s\n", script->filename);
script->line = 1;
script->script_p = script->buffer;
script->end_p = script->buffer + size;
}
/*
==============
LoadScriptFile
==============
*/
void LoadScriptFile (char *filename)
{
script = scriptstack;
AddScriptToStack (filename);
endofscript = false;
tokenready = false;
}
/*
==============
ParseFromMemory
==============
*/
void ParseFromMemory (char *buffer, int size)
{
script = scriptstack;
script++;
if (script == &scriptstack[MAX_INCLUDES])
Error ("script file exceeded MAX_INCLUDES");
strcpy (script->filename, "memory buffer" );
script->buffer = buffer;
script->line = 1;
script->script_p = script->buffer;
script->end_p = script->buffer + size;
endofscript = false;
tokenready = false;
}
/*
==============
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;
}
qboolean EndOfScript (qboolean crossline)
{
if (!crossline)
Error ("Line %i is incomplete\n",scriptline);
if (!strcmp (script->filename, "memory buffer"))
{
endofscript = true;
return false;
}
free (script->buffer);
if (script == scriptstack+1)
{
endofscript = true;
return false;
}
script--;
scriptline = script->line;
printf ("returning to %s\n", script->filename);
return GetToken (crossline);
}
/*
==============
GetToken
==============
*/
qboolean GetToken (qboolean crossline)
{
char *token_p;
if (tokenready) // is a token allready waiting?
{
tokenready = false;
return true;
}
if (script->script_p >= script->end_p)
return EndOfScript (crossline);
//
// skip space
//
skipspace:
while (*script->script_p <= 32)
{
if (script->script_p >= script->end_p)
return EndOfScript (crossline);
if (*script->script_p++ == '\n')
{
if (!crossline)
Error ("Line %i is incomplete\n",scriptline);
scriptline = script->line++;
}
}
if (script->script_p >= script->end_p)
return EndOfScript (crossline);
// ; # // comments
if (*script->script_p == ';' || *script->script_p == '#'
|| ( script->script_p[0] == '/' && script->script_p[1] == '/') )
{
if (!crossline)
Error ("Line %i is incomplete\n",scriptline);
while (*script->script_p++ != '\n')
if (script->script_p >= script->end_p)
return EndOfScript (crossline);
goto skipspace;
}
// /* */ comments
if (script->script_p[0] == '/' && script->script_p[1] == '*')
{
if (!crossline)
Error ("Line %i is incomplete\n",scriptline);
script->script_p+=2;
while (script->script_p[0] != '*' && script->script_p[1] != '/')
{
script->script_p++;
if (script->script_p >= script->end_p)
return EndOfScript (crossline);
}
script->script_p += 2;
goto skipspace;
}
//
// copy token
//
token_p = token;
if (*script->script_p == '"')
{
// quoted token
script->script_p++;
while (*script->script_p != '"')
{
*token_p++ = *script->script_p++;
if (script->script_p == script->end_p)
break;
if (token_p == &token[MAXTOKEN])
Error ("Token too large on line %i\n",scriptline);
}
script->script_p++;
}
else // regular token
while ( *script->script_p > 32 && *script->script_p != ';')
{
*token_p++ = *script->script_p++;
if (script->script_p == script->end_p)
break;
if (token_p == &token[MAXTOKEN])
Error ("Token too large on line %i\n",scriptline);
}
*token_p = 0;
if (!strcmp (token, "$include"))
{
GetToken (false);
AddScriptToStack (token);
return GetToken (crossline);
}
return true;
}
/*
==============
TokenAvailable
Returns true if there is another token on the line
==============
*/
qboolean TokenAvailable (void)
{
char *search_p;
search_p = script->script_p;
if (search_p >= script->end_p)
return false;
while ( *search_p <= 32)
{
if (*search_p == '\n')
return false;
search_p++;
if (search_p == script->end_p)
return false;
}
if (*search_p == ';')
return false;
return true;
}

45
common/scriplib.h Normal file
View File

@@ -0,0 +1,45 @@
/*
===========================================================================
Copyright (C) 1997-2006 Id Software, Inc.
This file is part of Quake 2 Tools source code.
Quake 2 Tools source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake 2 Tools source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake 2 Tools source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// scriplib.h
#ifndef __CMDLIB__
#include "cmdlib.h"
#endif
#define MAXTOKEN 1024
extern char token[MAXTOKEN];
extern char *scriptbuffer,*script_p,*scriptend_p;
extern int grabbed;
extern int scriptline;
extern qboolean endofscript;
void LoadScriptFile (char *filename);
void ParseFromMemory (char *buffer, int size);
qboolean GetToken (qboolean crossline);
void UnGetToken (void);
qboolean TokenAvailable (void);

448
common/threads.c Normal file
View File

@@ -0,0 +1,448 @@
/*
===========================================================================
Copyright (C) 1997-2006 Id Software, Inc.
This file is part of Quake 2 Tools source code.
Quake 2 Tools source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake 2 Tools source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake 2 Tools source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "cmdlib.h"
#include "threads.h"
#define MAX_THREADS 64
int dispatch;
int workcount;
int oldf;
qboolean pacifier;
qboolean threaded;
/*
=============
GetThreadWork
=============
*/
int GetThreadWork (void)
{
int r;
int f;
ThreadLock ();
if (dispatch == workcount)
{
ThreadUnlock ();
return -1;
}
f = 10*dispatch / workcount;
if (f != oldf)
{
oldf = f;
if (pacifier)
printf ("%i...", f);
}
r = dispatch;
dispatch++;
ThreadUnlock ();
return r;
}
void (*workfunction) (int);
void ThreadWorkerFunction (int threadnum)
{
int work;
while (1)
{
work = GetThreadWork ();
if (work == -1)
break;
//printf ("thread %i, work %i\n", threadnum, work);
workfunction(work);
}
}
void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, void(*func)(int))
{
if (numthreads == -1)
ThreadSetDefault ();
workfunction = func;
RunThreadsOn (workcnt, showpacifier, ThreadWorkerFunction);
}
/*
===================================================================
WIN32
===================================================================
*/
#ifdef WIN32
#define USED
#include <windows.h>
int numthreads = -1;
CRITICAL_SECTION crit;
static int enter;
void ThreadSetDefault (void)
{
SYSTEM_INFO info;
if (numthreads == -1) // not set manually
{
GetSystemInfo (&info);
numthreads = info.dwNumberOfProcessors;
if (numthreads < 1 || numthreads > 32)
numthreads = 1;
}
qprintf ("%i threads\n", numthreads);
}
void ThreadLock (void)
{
if (!threaded)
return;
EnterCriticalSection (&crit);
if (enter)
Error ("Recursive ThreadLock\n");
enter = 1;
}
void ThreadUnlock (void)
{
if (!threaded)
return;
if (!enter)
Error ("ThreadUnlock without lock\n");
enter = 0;
LeaveCriticalSection (&crit);
}
/*
=============
RunThreadsOn
=============
*/
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
{
int threadid[MAX_THREADS];
HANDLE threadhandle[MAX_THREADS];
int i;
int start, end;
start = I_FloatTime ();
dispatch = 0;
workcount = workcnt;
oldf = -1;
pacifier = showpacifier;
threaded = true;
//
// run threads in parallel
//
InitializeCriticalSection (&crit);
if (numthreads == 1)
{ // use same thread
func (0);
}
else
{
for (i=0 ; i<numthreads ; i++)
{
threadhandle[i] = CreateThread(
NULL, // LPSECURITY_ATTRIBUTES lpsa,
0, // DWORD cbStack,
(LPTHREAD_START_ROUTINE)func, // LPTHREAD_START_ROUTINE lpStartAddr,
(LPVOID)i, // LPVOID lpvThreadParm,
0, // DWORD fdwCreate,
&threadid[i]);
}
for (i=0 ; i<numthreads ; i++)
WaitForSingleObject (threadhandle[i], INFINITE);
}
DeleteCriticalSection (&crit);
threaded = false;
end = I_FloatTime ();
if (pacifier)
printf (" (%i)\n", end-start);
}
#endif
/*
===================================================================
OSF1
===================================================================
*/
#ifdef __osf__
#define USED
int numthreads = 4;
void ThreadSetDefault (void)
{
if (numthreads == -1) // not set manually
{
numthreads = 4;
}
}
#include <pthread.h>
pthread_mutex_t *my_mutex;
void ThreadLock (void)
{
if (my_mutex)
pthread_mutex_lock (my_mutex);
}
void ThreadUnlock (void)
{
if (my_mutex)
pthread_mutex_unlock (my_mutex);
}
/*
=============
RunThreadsOn
=============
*/
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
{
int i;
pthread_t work_threads[MAX_THREADS];
pthread_addr_t status;
pthread_attr_t attrib;
pthread_mutexattr_t mattrib;
int start, end;
start = I_FloatTime ();
dispatch = 0;
workcount = workcnt;
oldf = -1;
pacifier = showpacifier;
threaded = true;
if (pacifier)
setbuf (stdout, NULL);
if (!my_mutex)
{
my_mutex = malloc (sizeof(*my_mutex));
if (pthread_mutexattr_create (&mattrib) == -1)
Error ("pthread_mutex_attr_create failed");
if (pthread_mutexattr_setkind_np (&mattrib, MUTEX_FAST_NP) == -1)
Error ("pthread_mutexattr_setkind_np failed");
if (pthread_mutex_init (my_mutex, mattrib) == -1)
Error ("pthread_mutex_init failed");
}
if (pthread_attr_create (&attrib) == -1)
Error ("pthread_attr_create failed");
if (pthread_attr_setstacksize (&attrib, 0x100000) == -1)
Error ("pthread_attr_setstacksize failed");
for (i=0 ; i<numthreads ; i++)
{
if (pthread_create(&work_threads[i], attrib
, (pthread_startroutine_t)func, (pthread_addr_t)i) == -1)
Error ("pthread_create failed");
}
for (i=0 ; i<numthreads ; i++)
{
if (pthread_join (work_threads[i], &status) == -1)
Error ("pthread_join failed");
}
threaded = false;
end = I_FloatTime ();
if (pacifier)
printf (" (%i)\n", end-start);
}
#endif
/*
===================================================================
IRIX
===================================================================
*/
#ifdef _MIPS_ISA
#define USED
#include <task.h>
#include <abi_mutex.h>
#include <sys/types.h>
#include <sys/prctl.h>
int numthreads = -1;
abilock_t lck;
void ThreadSetDefault (void)
{
if (numthreads == -1)
numthreads = prctl(PR_MAXPPROCS);
printf ("%i threads\n", numthreads);
//@@
usconfig (CONF_INITUSERS, numthreads);
}
void ThreadLock (void)
{
spin_lock (&lck);
}
void ThreadUnlock (void)
{
release_lock (&lck);
}
/*
=============
RunThreadsOn
=============
*/
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
{
int i;
int pid[MAX_THREADS];
int start, end;
start = I_FloatTime ();
dispatch = 0;
workcount = workcnt;
oldf = -1;
pacifier = showpacifier;
threaded = true;
if (pacifier)
setbuf (stdout, NULL);
init_lock (&lck);
for (i=0 ; i<numthreads-1 ; i++)
{
pid[i] = sprocsp ( (void (*)(void *, size_t))func, PR_SALL, (void *)i
, NULL, 0x100000);
// pid[i] = sprocsp ( (void (*)(void *, size_t))func, PR_SALL, (void *)i
// , NULL, 0x80000);
if (pid[i] == -1)
{
perror ("sproc");
Error ("sproc failed");
}
}
func(i);
for (i=0 ; i<numthreads-1 ; i++)
wait (NULL);
threaded = false;
end = I_FloatTime ();
if (pacifier)
printf (" (%i)\n", end-start);
}
#endif
/*
=======================================================================
SINGLE THREAD
=======================================================================
*/
#ifndef USED
int numthreads = 1;
void ThreadSetDefault (void)
{
numthreads = 1;
}
void ThreadLock (void)
{
}
void ThreadUnlock (void)
{
}
/*
=============
RunThreadsOn
=============
*/
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
{
int i;
int start, end;
dispatch = 0;
workcount = workcnt;
oldf = -1;
pacifier = showpacifier;
start = I_FloatTime ();
#ifdef NeXT
if (pacifier)
setbuf (stdout, NULL);
#endif
func(0);
end = I_FloatTime ();
if (pacifier)
printf (" (%i)\n", end-start);
}
#endif

31
common/threads.h Normal file
View File

@@ -0,0 +1,31 @@
/*
===========================================================================
Copyright (C) 1997-2006 Id Software, Inc.
This file is part of Quake 2 Tools source code.
Quake 2 Tools source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake 2 Tools source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake 2 Tools source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
extern int numthreads;
void ThreadSetDefault (void);
int GetThreadWork (void);
void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, void(*func)(int));
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int));
void ThreadLock (void);
void ThreadUnlock (void);

187
common/trilib.c Normal file
View File

@@ -0,0 +1,187 @@
/*
===========================================================================
Copyright (C) 1997-2006 Id Software, Inc.
This file is part of Quake 2 Tools source code.
Quake 2 Tools source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake 2 Tools source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake 2 Tools source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// 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)
Error ("reader: could not open file '%s'", filename);
iLevel = 0;
fread(&magic, sizeof(int), 1, input);
if (BigLong(magic) != MAGIC)
Error ("%s is not a Alias object separated triangle file, magic number is wrong.", filename);
ptri = malloc (MAXTRIANGLES * sizeof(triangle_t));
*pptri = ptri;
while (feof(input) == 0) {
if (fread(&start, sizeof(float), 1, input) < 1)
break;
*(int *)&start = BigLong(*(int *)&start);
if (*(int *)&start != exitpattern)
{
if (start == FLOAT_START) {
/* Start of an object or group of objects. */
i = -1;
do {
/* There are probably better ways to read a string from */
/* a file, but this does allow you to do error checking */
/* (which I'm not doing) on a per character basis. */
++i;
fread( &(name[i]), sizeof( char ), 1, input);
} while( name[i] != '\0' );
// indent();
// fprintf(stdout,"OBJECT START: %s\n",name);
fread( &count, sizeof(int), 1, input);
count = BigLong(count);
++iLevel;
if (count != 0) {
// indent();
// fprintf(stdout,"NUMBER OF TRIANGLES: %d\n",count);
i = -1;
do {
++i;
fread( &(tex[i]), sizeof( char ), 1, input);
} while( tex[i] != '\0' );
// indent();
// fprintf(stdout," Object texture name: '%s'\n",tex);
}
/* Else (count == 0) this is the start of a group, and */
/* no texture name is present. */
}
else if (start == FLOAT_END) {
/* End of an object or group. Yes, the name should be */
/* obvious from context, but it is in here just to be */
/* safe and to provide a little extra information for */
/* those who do not wish to write a recursive reader. */
/* Mia culpa. */
--iLevel;
i = -1;
do {
++i;
fread( &(name[i]), sizeof( char ), 1, input);
} while( name[i] != '\0' );
// indent();
// fprintf(stdout,"OBJECT END: %s\n",name);
continue;
}
}
//
// read the triangles
//
for (i = 0; i < count; ++i) {
int j;
fread( &tri, sizeof(tf_triangle), 1, input );
ByteSwapTri (&tri);
for (j=0 ; j<3 ; j++)
{
int k;
for (k=0 ; k<3 ; k++)
{
ptri->verts[j][k] = tri.pt[j].p.v[k];
}
}
ptri++;
if ((ptri - *pptri) >= MAXTRIANGLES)
Error ("Error: too many triangles; increase MAXTRIANGLES\n");
}
}
*numtriangles = ptri - *pptri;
fclose (input);
}

33
common/trilib.h Normal file
View File

@@ -0,0 +1,33 @@
/*
===========================================================================
Copyright (C) 1997-2006 Id Software, Inc.
This file is part of Quake 2 Tools source code.
Quake 2 Tools source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake 2 Tools source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake 2 Tools source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// 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);