The source release of the qutils.

This commit is contained in:
Travis Bradshaw
2012-01-31 15:48:05 -06:00
commit 6df9737f9c
111 changed files with 23929 additions and 0 deletions

BIN
qutils/BIN/BSPINFO.EXE Normal file

Binary file not shown.

BIN
qutils/BIN/LIGHT.EXE Normal file

Binary file not shown.

BIN
qutils/BIN/MODELGEN.EXE Normal file

Binary file not shown.

BIN
qutils/BIN/QBSP.EXE Normal file

Binary file not shown.

BIN
qutils/BIN/QCC.EXE Normal file

Binary file not shown.

BIN
qutils/BIN/QFILES.EXE Normal file

Binary file not shown.

BIN
qutils/BIN/QLUMPY.EXE Normal file

Binary file not shown.

BIN
qutils/BIN/SPRGEN.EXE Normal file

Binary file not shown.

BIN
qutils/BIN/TEXMAKE.EXE Normal file

Binary file not shown.

BIN
qutils/BIN/VIS.EXE Normal file

Binary file not shown.

25
qutils/BSPINFO/BSPINFO.C Normal file
View File

@@ -0,0 +1,25 @@
#include "cmdlib.h"
#include "mathlib.h"
#include "bspfile.h"
void main (int argc, char **argv)
{
int i;
char source[1024];
if (argc == 1)
Error ("usage: bspinfo bspfile [bspfiles]");
for (i=1 ; i<argc ; i++)
{
printf ("---------------------\n");
strcpy (source, argv[i]);
DefaultExtension (source, ".bsp");
printf ("%s\n", source);
LoadBSPFile (source);
PrintBSPFileSizes ();
printf ("---------------------\n");
}
}

234
qutils/BSPINFO/BSPINFO.MAK Normal file
View File

@@ -0,0 +1,234 @@
# Microsoft Developer Studio Generated NMAKE File, Format Version 4.10
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
!IF "$(CFG)" == ""
CFG=bspinfo - Win32 Debug
!MESSAGE No configuration specified. Defaulting to bspinfo - Win32 Debug.
!ENDIF
!IF "$(CFG)" != "bspinfo - Win32 Release" && "$(CFG)" !=\
"bspinfo - Win32 Debug"
!MESSAGE Invalid configuration "$(CFG)" specified.
!MESSAGE You can specify a configuration when running NMAKE on this makefile
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "bspinfo.mak" CFG="bspinfo - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "bspinfo - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "bspinfo - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
!ERROR An invalid configuration is specified.
!ENDIF
!IF "$(OS)" == "Windows_NT"
NULL=
!ELSE
NULL=nul
!ENDIF
################################################################################
# Begin Project
# PROP Target_Last_Scanned "bspinfo - Win32 Debug"
RSC=rc.exe
CPP=cl.exe
!IF "$(CFG)" == "bspinfo - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
OUTDIR=.\Release
INTDIR=.\Release
ALL : "$(OUTDIR)\bspinfo.exe"
CLEAN :
-@erase "$(INTDIR)\bspfile.obj"
-@erase "$(INTDIR)\bspinfo.obj"
-@erase "$(INTDIR)\cmdlib.obj"
-@erase "$(OUTDIR)\bspinfo.exe"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
# ADD CPP /nologo /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
CPP_PROJ=/nologo /ML /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\
"_CONSOLE" /Fp"$(INTDIR)/bspinfo.pch" /YX /Fo"$(INTDIR)/" /c
CPP_OBJS=.\Release/
CPP_SBRS=.\.
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o"$(OUTDIR)/bspinfo.bsc"
BSC32_SBRS= \
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:console /incremental:no\
/pdb:"$(OUTDIR)/bspinfo.pdb" /machine:I386 /out:"$(OUTDIR)/bspinfo.exe"
LINK32_OBJS= \
"$(INTDIR)\bspfile.obj" \
"$(INTDIR)\bspinfo.obj" \
"$(INTDIR)\cmdlib.obj"
"$(OUTDIR)\bspinfo.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ELSEIF "$(CFG)" == "bspinfo - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
OUTDIR=.\Debug
INTDIR=.\Debug
ALL : "$(OUTDIR)\bspinfo.exe"
CLEAN :
-@erase "$(INTDIR)\bspfile.obj"
-@erase "$(INTDIR)\bspinfo.obj"
-@erase "$(INTDIR)\cmdlib.obj"
-@erase "$(INTDIR)\vc40.idb"
-@erase "$(INTDIR)\vc40.pdb"
-@erase "$(OUTDIR)\bspinfo.exe"
-@erase "$(OUTDIR)\bspinfo.ilk"
-@erase "$(OUTDIR)\bspinfo.pdb"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
# ADD CPP /nologo /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
CPP_PROJ=/nologo /MLd /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D\
"_CONSOLE" /Fp"$(INTDIR)/bspinfo.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
CPP_OBJS=.\Debug/
CPP_SBRS=.\.
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o"$(OUTDIR)/bspinfo.bsc"
BSC32_SBRS= \
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:console /incremental:yes\
/pdb:"$(OUTDIR)/bspinfo.pdb" /debug /machine:I386 /out:"$(OUTDIR)/bspinfo.exe"
LINK32_OBJS= \
"$(INTDIR)\bspfile.obj" \
"$(INTDIR)\bspinfo.obj" \
"$(INTDIR)\cmdlib.obj"
"$(OUTDIR)\bspinfo.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ENDIF
.c{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.c{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
################################################################################
# Begin Target
# Name "bspinfo - Win32 Release"
# Name "bspinfo - Win32 Debug"
!IF "$(CFG)" == "bspinfo - Win32 Release"
!ELSEIF "$(CFG)" == "bspinfo - Win32 Debug"
!ENDIF
################################################################################
# Begin Source File
SOURCE=.\bspinfo.c
DEP_CPP_BSPIN=\
"..\common\bspfile.h"\
"..\common\cmdlib.h"\
"..\common\mathlib.h"\
"$(INTDIR)\bspinfo.obj" : $(SOURCE) $(DEP_CPP_BSPIN) "$(INTDIR)"
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\cmdlib.c
DEP_CPP_CMDLI=\
"..\..\..\..\..\quake\utils2\common\cmdlib.h"\
{$(INCLUDE)}"\sys\stat.h"\
{$(INCLUDE)}"\sys\types.h"\
"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\bspfile.c
DEP_CPP_BSPFI=\
"..\..\..\..\..\quake\utils2\common\bspfile.h"\
"..\..\..\..\..\quake\utils2\common\cmdlib.h"\
"..\..\..\..\..\quake\utils2\common\mathlib.h"\
"$(INTDIR)\bspfile.obj" : $(SOURCE) $(DEP_CPP_BSPFI) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
# End Target
# End Project
################################################################################

BIN
qutils/BSPINFO/BSPINFO.MDP Normal file

Binary file not shown.

BIN
qutils/BSPINFO/BSPINFO.NCB Normal file

Binary file not shown.

375
qutils/COMMON/BSPFILE.C Normal file
View File

@@ -0,0 +1,375 @@
#include "cmdlib.h"
#include "mathlib.h"
#include "bspfile.h"
//=============================================================================
int nummodels;
dmodel_t dmodels[MAX_MAP_MODELS];
int visdatasize;
byte dvisdata[MAX_MAP_VISIBILITY];
int lightdatasize;
byte dlightdata[MAX_MAP_LIGHTING];
int texdatasize;
byte dtexdata[MAX_MAP_MIPTEX]; // (dmiptexlump_t)
int entdatasize;
char dentdata[MAX_MAP_ENTSTRING];
int numleafs;
dleaf_t dleafs[MAX_MAP_LEAFS];
int numplanes;
dplane_t dplanes[MAX_MAP_PLANES];
int numvertexes;
dvertex_t dvertexes[MAX_MAP_VERTS];
int numnodes;
dnode_t dnodes[MAX_MAP_NODES];
int numtexinfo;
texinfo_t texinfo[MAX_MAP_TEXINFO];
int numfaces;
dface_t dfaces[MAX_MAP_FACES];
int numclipnodes;
dclipnode_t dclipnodes[MAX_MAP_CLIPNODES];
int numedges;
dedge_t dedges[MAX_MAP_EDGES];
int nummarksurfaces;
unsigned short dmarksurfaces[MAX_MAP_MARKSURFACES];
int numsurfedges;
int dsurfedges[MAX_MAP_SURFEDGES];
//=============================================================================
/*
=============
SwapBSPFile
Byte swaps all data in a bsp file.
=============
*/
void SwapBSPFile (qboolean todisk)
{
int i, j, c;
dmodel_t *d;
dmiptexlump_t *mtl;
// models
for (i=0 ; i<nummodels ; i++)
{
d = &dmodels[i];
for (j=0 ; j<MAX_MAP_HULLS ; j++)
d->headnode[j] = LittleLong (d->headnode[j]);
d->visleafs = LittleLong (d->visleafs);
d->firstface = LittleLong (d->firstface);
d->numfaces = LittleLong (d->numfaces);
for (j=0 ; j<3 ; j++)
{
d->mins[j] = LittleFloat(d->mins[j]);
d->maxs[j] = LittleFloat(d->maxs[j]);
d->origin[j] = LittleFloat(d->origin[j]);
}
}
//
// vertexes
//
for (i=0 ; i<numvertexes ; i++)
{
for (j=0 ; j<3 ; j++)
dvertexes[i].point[j] = LittleFloat (dvertexes[i].point[j]);
}
//
// planes
//
for (i=0 ; i<numplanes ; i++)
{
for (j=0 ; j<3 ; j++)
dplanes[i].normal[j] = LittleFloat (dplanes[i].normal[j]);
dplanes[i].dist = LittleFloat (dplanes[i].dist);
dplanes[i].type = LittleLong (dplanes[i].type);
}
//
// texinfos
//
for (i=0 ; i<numtexinfo ; i++)
{
for (j=0 ; j<8 ; j++)
texinfo[i].vecs[0][j] = LittleFloat (texinfo[i].vecs[0][j]);
texinfo[i].miptex = LittleLong (texinfo[i].miptex);
texinfo[i].flags = LittleLong (texinfo[i].flags);
}
//
// faces
//
for (i=0 ; i<numfaces ; i++)
{
dfaces[i].texinfo = LittleShort (dfaces[i].texinfo);
dfaces[i].planenum = LittleShort (dfaces[i].planenum);
dfaces[i].side = LittleShort (dfaces[i].side);
dfaces[i].lightofs = LittleLong (dfaces[i].lightofs);
dfaces[i].firstedge = LittleLong (dfaces[i].firstedge);
dfaces[i].numedges = LittleShort (dfaces[i].numedges);
}
//
// nodes
//
for (i=0 ; i<numnodes ; i++)
{
dnodes[i].planenum = LittleLong (dnodes[i].planenum);
for (j=0 ; j<3 ; j++)
{
dnodes[i].mins[j] = LittleShort (dnodes[i].mins[j]);
dnodes[i].maxs[j] = LittleShort (dnodes[i].maxs[j]);
}
dnodes[i].children[0] = LittleShort (dnodes[i].children[0]);
dnodes[i].children[1] = LittleShort (dnodes[i].children[1]);
dnodes[i].firstface = LittleShort (dnodes[i].firstface);
dnodes[i].numfaces = LittleShort (dnodes[i].numfaces);
}
//
// leafs
//
for (i=0 ; i<numleafs ; i++)
{
dleafs[i].contents = LittleLong (dleafs[i].contents);
for (j=0 ; j<3 ; j++)
{
dleafs[i].mins[j] = LittleShort (dleafs[i].mins[j]);
dleafs[i].maxs[j] = LittleShort (dleafs[i].maxs[j]);
}
dleafs[i].firstmarksurface = LittleShort (dleafs[i].firstmarksurface);
dleafs[i].nummarksurfaces = LittleShort (dleafs[i].nummarksurfaces);
dleafs[i].visofs = LittleLong (dleafs[i].visofs);
}
//
// clipnodes
//
for (i=0 ; i<numclipnodes ; i++)
{
dclipnodes[i].planenum = LittleLong (dclipnodes[i].planenum);
dclipnodes[i].children[0] = LittleShort (dclipnodes[i].children[0]);
dclipnodes[i].children[1] = LittleShort (dclipnodes[i].children[1]);
}
//
// miptex
//
if (texdatasize)
{
mtl = (dmiptexlump_t *)dtexdata;
if (todisk)
c = mtl->nummiptex;
else
c = LittleLong(mtl->nummiptex);
mtl->nummiptex = LittleLong (mtl->nummiptex);
for (i=0 ; i<c ; i++)
mtl->dataofs[i] = LittleLong(mtl->dataofs[i]);
}
//
// marksurfaces
//
for (i=0 ; i<nummarksurfaces ; i++)
dmarksurfaces[i] = LittleShort (dmarksurfaces[i]);
//
// surfedges
//
for (i=0 ; i<numsurfedges ; i++)
dsurfedges[i] = LittleLong (dsurfedges[i]);
//
// edges
//
for (i=0 ; i<numedges ; i++)
{
dedges[i].v[0] = LittleShort (dedges[i].v[0]);
dedges[i].v[1] = LittleShort (dedges[i].v[1]);
}
}
dheader_t *header;
int CopyLump (int lump, void *dest, int size)
{
int length, ofs;
length = header->lumps[lump].filelen;
ofs = header->lumps[lump].fileofs;
if (length % size)
Error ("LoadBSPFile: odd lump size");
memcpy (dest, (byte *)header + ofs, length);
return length / size;
}
/*
=============
LoadBSPFile
=============
*/
void LoadBSPFile (char *filename)
{
int i;
//
// load the file header
//
LoadFile (filename, (void **)&header);
// swap the header
for (i=0 ; i< sizeof(dheader_t)/4 ; i++)
((int *)header)[i] = LittleLong ( ((int *)header)[i]);
if (header->version != BSPVERSION)
Error ("%s is version %i, not %i", filename, i, BSPVERSION);
nummodels = CopyLump (LUMP_MODELS, dmodels, sizeof(dmodel_t));
numvertexes = CopyLump (LUMP_VERTEXES, dvertexes, sizeof(dvertex_t));
numplanes = CopyLump (LUMP_PLANES, dplanes, sizeof(dplane_t));
numleafs = CopyLump (LUMP_LEAFS, dleafs, sizeof(dleaf_t));
numnodes = CopyLump (LUMP_NODES, dnodes, sizeof(dnode_t));
numtexinfo = CopyLump (LUMP_TEXINFO, texinfo, sizeof(texinfo_t));
numclipnodes = CopyLump (LUMP_CLIPNODES, dclipnodes, sizeof(dclipnode_t));
numfaces = CopyLump (LUMP_FACES, dfaces, sizeof(dface_t));
nummarksurfaces = CopyLump (LUMP_MARKSURFACES, dmarksurfaces, sizeof(dmarksurfaces[0]));
numsurfedges = CopyLump (LUMP_SURFEDGES, dsurfedges, sizeof(dsurfedges[0]));
numedges = CopyLump (LUMP_EDGES, dedges, sizeof(dedge_t));
texdatasize = CopyLump (LUMP_TEXTURES, dtexdata, 1);
visdatasize = CopyLump (LUMP_VISIBILITY, dvisdata, 1);
lightdatasize = CopyLump (LUMP_LIGHTING, dlightdata, 1);
entdatasize = CopyLump (LUMP_ENTITIES, dentdata, 1);
free (header); // everything has been copied out
//
// swap everything
//
SwapBSPFile (false);
}
//============================================================================
FILE *wadfile;
dheader_t outheader;
void AddLump (int lumpnum, void *data, int len)
{
lump_t *lump;
lump = &header->lumps[lumpnum];
lump->fileofs = LittleLong( ftell(wadfile) );
lump->filelen = LittleLong(len);
SafeWrite (wadfile, data, (len+3)&~3);
}
/*
=============
WriteBSPFile
Swaps the bsp file in place, so it should not be referenced again
=============
*/
void WriteBSPFile (char *filename)
{
header = &outheader;
memset (header, 0, sizeof(dheader_t));
SwapBSPFile (true);
header->version = LittleLong (BSPVERSION);
wadfile = SafeOpenWrite (filename);
SafeWrite (wadfile, header, sizeof(dheader_t)); // overwritten later
AddLump (LUMP_PLANES, dplanes, numplanes*sizeof(dplane_t));
AddLump (LUMP_LEAFS, dleafs, numleafs*sizeof(dleaf_t));
AddLump (LUMP_VERTEXES, dvertexes, numvertexes*sizeof(dvertex_t));
AddLump (LUMP_NODES, dnodes, numnodes*sizeof(dnode_t));
AddLump (LUMP_TEXINFO, texinfo, numtexinfo*sizeof(texinfo_t));
AddLump (LUMP_FACES, dfaces, numfaces*sizeof(dface_t));
AddLump (LUMP_CLIPNODES, dclipnodes, numclipnodes*sizeof(dclipnode_t));
AddLump (LUMP_MARKSURFACES, dmarksurfaces, nummarksurfaces*sizeof(dmarksurfaces[0]));
AddLump (LUMP_SURFEDGES, dsurfedges, numsurfedges*sizeof(dsurfedges[0]));
AddLump (LUMP_EDGES, dedges, numedges*sizeof(dedge_t));
AddLump (LUMP_MODELS, dmodels, nummodels*sizeof(dmodel_t));
AddLump (LUMP_LIGHTING, dlightdata, lightdatasize);
AddLump (LUMP_VISIBILITY, dvisdata, visdatasize);
AddLump (LUMP_ENTITIES, dentdata, entdatasize);
AddLump (LUMP_TEXTURES, dtexdata, texdatasize);
fseek (wadfile, 0, SEEK_SET);
SafeWrite (wadfile, header, sizeof(dheader_t));
fclose (wadfile);
}
//============================================================================
/*
=============
PrintBSPFileSizes
Dumps info about current file
=============
*/
void PrintBSPFileSizes (void)
{
printf ("%5i planes %6i\n"
,numplanes, (int)(numplanes*sizeof(dplane_t)));
printf ("%5i vertexes %6i\n"
,numvertexes, (int)(numvertexes*sizeof(dvertex_t)));
printf ("%5i nodes %6i\n"
,numnodes, (int)(numnodes*sizeof(dnode_t)));
printf ("%5i texinfo %6i\n"
,numtexinfo, (int)(numtexinfo*sizeof(texinfo_t)));
printf ("%5i faces %6i\n"
,numfaces, (int)(numfaces*sizeof(dface_t)));
printf ("%5i clipnodes %6i\n"
,numclipnodes, (int)(numclipnodes*sizeof(dclipnode_t)));
printf ("%5i leafs %6i\n"
,numleafs, (int)(numleafs*sizeof(dleaf_t)));
printf ("%5i marksurfaces %6i\n"
,nummarksurfaces, (int)(nummarksurfaces*sizeof(dmarksurfaces[0])));
printf ("%5i surfedges %6i\n"
,numsurfedges, (int)(numsurfedges*sizeof(dmarksurfaces[0])));
printf ("%5i edges %6i\n"
,numedges, (int)(numedges*sizeof(dedge_t)));
if (!texdatasize)
printf (" 0 textures 0\n");
else
printf ("%5i textures %6i\n",((dmiptexlump_t*)dtexdata)->nummiptex, texdatasize);
printf (" lightdata %6i\n", lightdatasize);
printf (" visdata %6i\n", visdatasize);
printf (" entdata %6i\n", entdatasize);
}

251
qutils/COMMON/BSPFILE.H Normal file
View File

@@ -0,0 +1,251 @@
// upper design bounds
#define MAX_MAP_HULLS 4
#define MAX_MAP_MODELS 256
#define MAX_MAP_BRUSHES 4096
#define MAX_MAP_ENTITIES 1024
#define MAX_MAP_ENTSTRING 65536
#define MAX_MAP_PLANES 8192
#define MAX_MAP_NODES 32767 // because negative shorts are contents
#define MAX_MAP_CLIPNODES 32767 //
#define MAX_MAP_LEAFS 32767 //
#define MAX_MAP_VERTS 65535
#define MAX_MAP_FACES 65535
#define MAX_MAP_MARKSURFACES 65535
#define MAX_MAP_TEXINFO 4096
#define MAX_MAP_EDGES 256000
#define MAX_MAP_SURFEDGES 512000
#define MAX_MAP_MIPTEX 0x200000
#define MAX_MAP_LIGHTING 0x100000
#define MAX_MAP_VISIBILITY 0x100000
// key / value pair sizes
#define MAX_KEY 32
#define MAX_VALUE 1024
//=============================================================================
#define BSPVERSION 29
typedef struct
{
int fileofs, filelen;
} lump_t;
#define LUMP_ENTITIES 0
#define LUMP_PLANES 1
#define LUMP_TEXTURES 2
#define LUMP_VERTEXES 3
#define LUMP_VISIBILITY 4
#define LUMP_NODES 5
#define LUMP_TEXINFO 6
#define LUMP_FACES 7
#define LUMP_LIGHTING 8
#define LUMP_CLIPNODES 9
#define LUMP_LEAFS 10
#define LUMP_MARKSURFACES 11
#define LUMP_EDGES 12
#define LUMP_SURFEDGES 13
#define LUMP_MODELS 14
#define HEADER_LUMPS 15
typedef struct
{
float mins[3], maxs[3];
float origin[3];
int headnode[MAX_MAP_HULLS];
int visleafs; // not including the solid leaf 0
int firstface, numfaces;
} dmodel_t;
typedef struct
{
int version;
lump_t lumps[HEADER_LUMPS];
} dheader_t;
typedef struct
{
int nummiptex;
int dataofs[4]; // [nummiptex]
} dmiptexlump_t;
#define MIPLEVELS 4
typedef struct miptex_s
{
char name[16];
unsigned width, height;
unsigned offsets[MIPLEVELS]; // four mip maps stored
} miptex_t;
typedef struct
{
float point[3];
} dvertex_t;
// 0-2 are axial planes
#define PLANE_X 0
#define PLANE_Y 1
#define PLANE_Z 2
// 3-5 are non-axial planes snapped to the nearest
#define PLANE_ANYX 3
#define PLANE_ANYY 4
#define PLANE_ANYZ 5
typedef struct
{
float normal[3];
float dist;
int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
} dplane_t;
#define CONTENTS_EMPTY -1
#define CONTENTS_SOLID -2
#define CONTENTS_WATER -3
#define CONTENTS_SLIME -4
#define CONTENTS_LAVA -5
#define CONTENTS_SKY -6
// !!! if this is changed, it must be changed in asm_i386.h too !!!
typedef struct
{
int planenum;
short children[2]; // negative numbers are -(leafs+1), not nodes
short mins[3]; // for sphere culling
short maxs[3];
unsigned short firstface;
unsigned short numfaces; // counting both sides
} dnode_t;
typedef struct
{
int planenum;
short children[2]; // negative numbers are contents
} dclipnode_t;
typedef struct texinfo_s
{
float vecs[2][4]; // [s/t][xyz offset]
int miptex;
int flags;
} texinfo_t;
#define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision
// note that edge 0 is never used, because negative edge nums are used for
// counterclockwise use of the edge in a face
typedef struct
{
unsigned short v[2]; // vertex numbers
} dedge_t;
#define MAXLIGHTMAPS 4
typedef struct
{
short planenum;
short side;
int firstedge; // we must support > 64k edges
short numedges;
short texinfo;
// lighting info
byte styles[MAXLIGHTMAPS];
int lightofs; // start of [numstyles*surfsize] samples
} dface_t;
#define AMBIENT_WATER 0
#define AMBIENT_SKY 1
#define AMBIENT_SLIME 2
#define AMBIENT_LAVA 3
#define NUM_AMBIENTS 4 // automatic ambient sounds
// leaf 0 is the generic CONTENTS_SOLID leaf, used for all solid areas
// all other leafs need visibility info
typedef struct
{
int contents;
int visofs; // -1 = no visibility info
short mins[3]; // for frustum culling
short maxs[3];
unsigned short firstmarksurface;
unsigned short nummarksurfaces;
byte ambient_level[NUM_AMBIENTS];
} dleaf_t;
//============================================================================
#ifndef QUAKE_GAME
// the utilities get to be lazy and just use large static arrays
extern int nummodels;
extern dmodel_t dmodels[MAX_MAP_MODELS];
extern int visdatasize;
extern byte dvisdata[MAX_MAP_VISIBILITY];
extern int lightdatasize;
extern byte dlightdata[MAX_MAP_LIGHTING];
extern int texdatasize;
extern byte dtexdata[MAX_MAP_MIPTEX]; // (dmiptexlump_t)
extern int entdatasize;
extern char dentdata[MAX_MAP_ENTSTRING];
extern int numleafs;
extern dleaf_t dleafs[MAX_MAP_LEAFS];
extern int numplanes;
extern dplane_t dplanes[MAX_MAP_PLANES];
extern int numvertexes;
extern dvertex_t dvertexes[MAX_MAP_VERTS];
extern int numnodes;
extern dnode_t dnodes[MAX_MAP_NODES];
extern int numtexinfo;
extern texinfo_t texinfo[MAX_MAP_TEXINFO];
extern int numfaces;
extern dface_t dfaces[MAX_MAP_FACES];
extern int numclipnodes;
extern dclipnode_t dclipnodes[MAX_MAP_CLIPNODES];
extern int numedges;
extern dedge_t dedges[MAX_MAP_EDGES];
extern int nummarksurfaces;
extern unsigned short dmarksurfaces[MAX_MAP_MARKSURFACES];
extern int numsurfedges;
extern int dsurfedges[MAX_MAP_SURFEDGES];
void LoadBSPFile (char *filename);
void WriteBSPFile (char *filename);
void PrintBSPFileSizes (void);
#endif

867
qutils/COMMON/CMDLIB.C Normal file
View File

@@ -0,0 +1,867 @@
// cmdlib.c
#include "cmdlib.h"
#include <sys/types.h>
#include <sys/stat.h>
#ifdef WIN32
#include <direct.h>
#endif
#ifdef NeXT
#include <libc.h>
#endif
#define PATHSEPERATOR '/'
// set these before calling CheckParm
int myargc;
char **myargv;
char com_token[1024];
qboolean com_eof;
qboolean archive;
char archivedir[1024];
/*
=================
Error
For abnormal program terminations
=================
*/
void Error (char *error, ...)
{
va_list argptr;
printf ("************ ERROR ************\n");
va_start (argptr,error);
vprintf (error,argptr);
va_end (argptr);
printf ("\n");
exit (1);
}
/*
qdir will hold the path up to the quake directory, including the slash
f:\quake\
/raid/quake/
gamedir will hold qdir + the game directory (id1, id2, etc)
*/
char qdir[1024];
char gamedir[1024];
void SetQdirFromPath (char *path)
{
char temp[1024];
char *c;
if (!(path[0] == '/' || path[0] == '\\' || path[1] == ':'))
{ // path is partial
Q_getwd (temp);
strcat (temp, path);
path = temp;
}
// search for "quake" in path
for (c=path ; *c ; c++)
if (!Q_strncasecmp (c, "quake", 5))
{
strncpy (qdir, path, c+6-path);
printf ("qdir: %s\n", qdir);
c += 6;
while (*c)
{
if (*c == '/' || *c == '\\')
{
strncpy (gamedir, path, c+1-path);
printf ("gamedir: %s\n", gamedir);
return;
}
c++;
}
Error ("No gamedir in %s", path);
return;
}
Error ("SeetQdirFromPath: no 'quake' in %s", path);
}
char *ExpandPath (char *path)
{
static char full[1024];
if (!qdir)
Error ("ExpandPath called without qdir set");
if (path[0] == '/' || path[0] == '\\' || path[1] == ':')
return path;
sprintf (full, "%s%s", qdir, path);
return full;
}
char *ExpandPathAndArchive (char *path)
{
char *expanded;
char archivename[1024];
expanded = ExpandPath (path);
if (archive)
{
sprintf (archivename, "%s/%s", archivedir, path);
CopyFile (expanded, archivename);
}
return expanded;
}
char *copystring(char *s)
{
char *b;
b = malloc(strlen(s)+1);
strcpy (b, s);
return b;
}
/*
================
I_FloatTime
================
*/
double I_FloatTime (void)
{
time_t t;
time (&t);
return t;
#if 0
// more precise, less portable
struct timeval tp;
struct timezone tzp;
static int secbase;
gettimeofday(&tp, &tzp);
if (!secbase)
{
secbase = tp.tv_sec;
return tp.tv_usec/1000000.0;
}
return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0;
#endif
}
void Q_getwd (char *out)
{
#ifdef WIN32
_getcwd (out, 256);
strcat (out, "\\");
#else
getwd (out);
#endif
}
void Q_mkdir (char *path)
{
#ifdef WIN32
if (_mkdir (path) != -1)
return;
#else
if (mkdir (path, 0777) != -1)
return;
#endif
if (errno != EEXIST)
Error ("mkdir %s: %s",path, strerror(errno));
}
/*
============
FileTime
returns -1 if not present
============
*/
int FileTime (char *path)
{
struct stat buf;
if (stat (path,&buf) == -1)
return -1;
return buf.st_mtime;
}
/*
==============
COM_Parse
Parse a token out of a string
==============
*/
char *COM_Parse (char *data)
{
int c;
int len;
len = 0;
com_token[0] = 0;
if (!data)
return NULL;
// skip whitespace
skipwhite:
while ( (c = *data) <= ' ')
{
if (c == 0)
{
com_eof = true;
return NULL; // end of file;
}
data++;
}
// skip // comments
if (c=='/' && data[1] == '/')
{
while (*data && *data != '\n')
data++;
goto skipwhite;
}
// handle quoted strings specially
if (c == '\"')
{
data++;
do
{
c = *data++;
if (c=='\"')
{
com_token[len] = 0;
return data;
}
com_token[len] = c;
len++;
} while (1);
}
// parse single characters
if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
{
com_token[len] = c;
len++;
com_token[len] = 0;
return data+1;
}
// parse a regular word
do
{
com_token[len] = c;
data++;
len++;
c = *data;
if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
break;
} while (c>32);
com_token[len] = 0;
return data;
}
int Q_strncasecmp (char *s1, char *s2, int n)
{
int c1, c2;
while (1)
{
c1 = *s1++;
c2 = *s2++;
if (!n--)
return 0; // strings are equal until end point
if (c1 != c2)
{
if (c1 >= 'a' && c1 <= 'z')
c1 -= ('a' - 'A');
if (c2 >= 'a' && c2 <= 'z')
c2 -= ('a' - 'A');
if (c1 != c2)
return -1; // strings not equal
}
if (!c1)
return 0; // strings are equal
}
return -1;
}
int Q_strcasecmp (char *s1, char *s2)
{
return Q_strncasecmp (s1, s2, 99999);
}
char *strupr (char *start)
{
char *in;
in = start;
while (*in)
{
*in = toupper(*in);
in++;
}
return start;
}
char *strlower (char *start)
{
char *in;
in = start;
while (*in)
{
*in = tolower(*in);
in++;
}
return start;
}
/*
=============================================================================
MISC FUNCTIONS
=============================================================================
*/
/*
=================
CheckParm
Checks for the given parameter in the program's command line arguments
Returns the argument number (1 to argc-1) or 0 if not present
=================
*/
int CheckParm (char *check)
{
int i;
for (i = 1;i<myargc;i++)
{
if ( !Q_strcasecmp(check, myargv[i]) )
return i;
}
return 0;
}
/*
================
filelength
================
*/
int filelength (FILE *f)
{
int pos;
int end;
pos = ftell (f);
fseek (f, 0, SEEK_END);
end = ftell (f);
fseek (f, pos, SEEK_SET);
return end;
}
FILE *SafeOpenWrite (char *filename)
{
FILE *f;
f = fopen(filename, "wb");
if (!f)
Error ("Error opening %s: %s",filename,strerror(errno));
return f;
}
FILE *SafeOpenRead (char *filename)
{
FILE *f;
f = fopen(filename, "rb");
if (!f)
Error ("Error opening %s: %s",filename,strerror(errno));
return f;
}
void SafeRead (FILE *f, void *buffer, int count)
{
if ( fread (buffer, 1, count, f) != (size_t)count)
Error ("File read failure");
}
void SafeWrite (FILE *f, void *buffer, int count)
{
if (fwrite (buffer, 1, count, f) != (size_t)count)
Error ("File read failure");
}
/*
==============
LoadFile
==============
*/
int LoadFile (char *filename, void **bufferptr)
{
FILE *f;
int length;
void *buffer;
f = SafeOpenRead (filename);
length = filelength (f);
buffer = malloc (length+1);
((char *)buffer)[length] = 0;
SafeRead (f, buffer, length);
fclose (f);
*bufferptr = buffer;
return length;
}
/*
==============
SaveFile
==============
*/
void SaveFile (char *filename, void *buffer, int count)
{
FILE *f;
f = SafeOpenWrite (filename);
SafeWrite (f, buffer, count);
fclose (f);
}
void DefaultExtension (char *path, char *extension)
{
char *src;
//
// if path doesn't have a .EXT, append extension
// (extension should include the .)
//
src = path + strlen(path) - 1;
while (*src != PATHSEPERATOR && src != path)
{
if (*src == '.')
return; // it has an extension
src--;
}
strcat (path, extension);
}
void DefaultPath (char *path, char *basepath)
{
char temp[128];
if (path[0] == PATHSEPERATOR)
return; // absolute path location
strcpy (temp,path);
strcpy (path,basepath);
strcat (path,temp);
}
void StripFilename (char *path)
{
int length;
length = strlen(path)-1;
while (length > 0 && path[length] != PATHSEPERATOR)
length--;
path[length] = 0;
}
void StripExtension (char *path)
{
int length;
length = strlen(path)-1;
while (length > 0 && path[length] != '.')
{
length--;
if (path[length] == '/')
return; // no extension
}
if (length)
path[length] = 0;
}
/*
====================
Extract file parts
====================
*/
void ExtractFilePath (char *path, char *dest)
{
char *src;
src = path + strlen(path) - 1;
//
// back up until a \ or the start
//
while (src != path && *(src-1) != PATHSEPERATOR)
src--;
memcpy (dest, path, src-path);
dest[src-path] = 0;
}
void ExtractFileBase (char *path, char *dest)
{
char *src;
src = path + strlen(path) - 1;
//
// back up until a \ or the start
//
while (src != path && *(src-1) != PATHSEPERATOR)
src--;
while (*src && *src != '.')
{
*dest++ = *src++;
}
*dest = 0;
}
void ExtractFileExtension (char *path, char *dest)
{
char *src;
src = path + strlen(path) - 1;
//
// back up until a . or the start
//
while (src != path && *(src-1) != '.')
src--;
if (src == path)
{
*dest = 0; // no extension
return;
}
strcpy (dest,src);
}
/*
==============
ParseNum / ParseHex
==============
*/
int ParseHex (char *hex)
{
char *str;
int num;
num = 0;
str = hex;
while (*str)
{
num <<= 4;
if (*str >= '0' && *str <= '9')
num += *str-'0';
else if (*str >= 'a' && *str <= 'f')
num += 10 + *str-'a';
else if (*str >= 'A' && *str <= 'F')
num += 10 + *str-'A';
else
Error ("Bad hex number: %s",hex);
str++;
}
return num;
}
int ParseNum (char *str)
{
if (str[0] == '$')
return ParseHex (str+1);
if (str[0] == '0' && str[1] == 'x')
return ParseHex (str+2);
return atol (str);
}
/*
============================================================================
BYTE ORDER FUNCTIONS
============================================================================
*/
#ifdef _SGI_SOURCE
#define __BIG_ENDIAN__
#endif
#ifdef __BIG_ENDIAN__
short LittleShort (short l)
{
byte b1,b2;
b1 = l&255;
b2 = (l>>8)&255;
return (b1<<8) + b2;
}
short BigShort (short l)
{
return l;
}
int LittleLong (int l)
{
byte b1,b2,b3,b4;
b1 = l&255;
b2 = (l>>8)&255;
b3 = (l>>16)&255;
b4 = (l>>24)&255;
return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
}
int BigLong (int l)
{
return l;
}
float LittleFloat (float l)
{
union {byte b[4]; float f;} in, out;
in.f = l;
out.b[0] = in.b[3];
out.b[1] = in.b[2];
out.b[2] = in.b[1];
out.b[3] = in.b[0];
return out.f;
}
float BigFloat (float l)
{
return l;
}
#else
short BigShort (short l)
{
byte b1,b2;
b1 = l&255;
b2 = (l>>8)&255;
return (b1<<8) + b2;
}
short LittleShort (short l)
{
return l;
}
int BigLong (int l)
{
byte b1,b2,b3,b4;
b1 = l&255;
b2 = (l>>8)&255;
b3 = (l>>16)&255;
b4 = (l>>24)&255;
return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
}
int LittleLong (int l)
{
return l;
}
float BigFloat (float l)
{
union {byte b[4]; float f;} in, out;
in.f = l;
out.b[0] = in.b[3];
out.b[1] = in.b[2];
out.b[2] = in.b[1];
out.b[3] = in.b[0];
return out.f;
}
float LittleFloat (float l)
{
return l;
}
#endif
//=======================================================
// FIXME: byte swap?
// this is a 16 bit, non-reflected CRC using the polynomial 0x1021
// and the initial and final xor values shown below... in other words, the
// CCITT standard CRC used by XMODEM
#define CRC_INIT_VALUE 0xffff
#define CRC_XOR_VALUE 0x0000
static unsigned short crctable[256] =
{
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};
void CRC_Init(unsigned short *crcvalue)
{
*crcvalue = CRC_INIT_VALUE;
}
void CRC_ProcessByte(unsigned short *crcvalue, byte data)
{
*crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];
}
unsigned short CRC_Value(unsigned short crcvalue)
{
return crcvalue ^ CRC_XOR_VALUE;
}
//=============================================================================
/*
============
CreatePath
============
*/
void CreatePath (char *path)
{
char *ofs, c;
for (ofs = path+1 ; *ofs ; ofs++)
{
c = *ofs;
if (c == '/' || c == '\\')
{ // create the directory
*ofs = 0;
Q_mkdir (path);
*ofs = c;
}
}
}
/*
============
CopyFile
Used to archive source files
============
*/
void CopyFile (char *from, char *to)
{
void *buffer;
int length;
length = LoadFile (from, &buffer);
CreatePath (to);
SaveFile (to, buffer, length);
free (buffer);
}

97
qutils/COMMON/CMDLIB.H Normal file
View File

@@ -0,0 +1,97 @@
// cmdlib.h
#ifndef __CMDLIB__
#define __CMDLIB__
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <time.h>
#include <stdarg.h>
#ifndef __BYTEBOOL__
#define __BYTEBOOL__
typedef enum {false, true} qboolean;
typedef unsigned char byte;
#endif
// the dec offsetof macro doesn't work very well...
#define myoffsetof(type,identifier) ((size_t)&((type *)0)->identifier)
// set these before calling CheckParm
extern int myargc;
extern char **myargv;
char *strupr (char *in);
char *strlower (char *in);
int Q_strncasecmp (char *s1, char *s2, int n);
int Q_strcasecmp (char *s1, char *s2);
void Q_getwd (char *out);
int filelength (FILE *f);
int FileTime (char *path);
void Q_mkdir (char *path);
extern char qdir[1024];
extern char gamedir[1024];
void SetQdirFromPath (char *path);
char *ExpandPath (char *path);
char *ExpandPathAndArchive (char *path);
double I_FloatTime (void);
void Error (char *error, ...);
int CheckParm (char *check);
FILE *SafeOpenWrite (char *filename);
FILE *SafeOpenRead (char *filename);
void SafeRead (FILE *f, void *buffer, int count);
void SafeWrite (FILE *f, void *buffer, int count);
int LoadFile (char *filename, void **bufferptr);
void SaveFile (char *filename, void *buffer, int count);
void DefaultExtension (char *path, char *extension);
void DefaultPath (char *path, char *basepath);
void StripFilename (char *path);
void StripExtension (char *path);
void ExtractFilePath (char *path, char *dest);
void ExtractFileBase (char *path, char *dest);
void ExtractFileExtension (char *path, char *dest);
int ParseNum (char *str);
short BigShort (short l);
short LittleShort (short l);
int BigLong (int l);
int LittleLong (int l);
float BigFloat (float l);
float LittleFloat (float l);
char *COM_Parse (char *data);
extern char com_token[1024];
extern qboolean com_eof;
char *copystring(char *s);
void CRC_Init(unsigned short *crcvalue);
void CRC_ProcessByte(unsigned short *crcvalue, byte data);
unsigned short CRC_Value(unsigned short crcvalue);
void CreatePath (char *path);
void CopyFile (char *from, char *to);
extern qboolean archive;
extern char archivedir[1024];
#endif

508
qutils/COMMON/LBMLIB.C Normal file
View File

@@ -0,0 +1,508 @@
// lbmlib.c
#include "cmdlib.h"
#include "lbmlib.h"
/*
============================================================================
LBM STUFF
============================================================================
*/
#define FORMID ('F'+('O'<<8)+((int)'R'<<16)+((int)'M'<<24))
#define ILBMID ('I'+('L'<<8)+((int)'B'<<16)+((int)'M'<<24))
#define PBMID ('P'+('B'<<8)+((int)'M'<<16)+((int)' '<<24))
#define BMHDID ('B'+('M'<<8)+((int)'H'<<16)+((int)'D'<<24))
#define BODYID ('B'+('O'<<8)+((int)'D'<<16)+((int)'Y'<<24))
#define CMAPID ('C'+('M'<<8)+((int)'A'<<16)+((int)'P'<<24))
bmhd_t bmhd;
int Align (int l)
{
if (l&1)
return l+1;
return l;
}
/*
================
=
= LBMRLEdecompress
=
= Source must be evenly aligned!
=
================
*/
byte *LBMRLEDecompress (byte *source,byte *unpacked, int bpwidth)
{
int count;
byte b,rept;
count = 0;
do
{
rept = *source++;
if (rept > 0x80)
{
rept = (rept^0xff)+2;
b = *source++;
memset(unpacked,b,rept);
unpacked += rept;
}
else if (rept < 0x80)
{
rept++;
memcpy(unpacked,source,rept);
unpacked += rept;
source += rept;
}
else
rept = 0; // rept of 0x80 is NOP
count += rept;
} while (count<bpwidth);
if (count>bpwidth)
Error ("Decompression exceeded width!\n");
return source;
}
#define BPLANESIZE 128
byte bitplanes[9][BPLANESIZE]; // max size 1024 by 9 bit planes
/*
=================
=
= MungeBitPlanes8
=
= This destroys the bit plane data!
=
=================
*/
void MungeBitPlanes8 (int width, byte *dest)
{
*dest=width; // shut up the compiler warning
Error ("MungeBitPlanes8 not rewritten!");
#if 0
asm les di,[dest]
asm mov si,-1
asm mov cx,[width]
mungebyte:
asm inc si
asm mov dx,8
mungebit:
asm shl [BYTE PTR bitplanes + BPLANESIZE*7 +si],1
asm rcl al,1
asm shl [BYTE PTR bitplanes + BPLANESIZE*6 +si],1
asm rcl al,1
asm shl [BYTE PTR bitplanes + BPLANESIZE*5 +si],1
asm rcl al,1
asm shl [BYTE PTR bitplanes + BPLANESIZE*4 +si],1
asm rcl al,1
asm shl [BYTE PTR bitplanes + BPLANESIZE*3 +si],1
asm rcl al,1
asm shl [BYTE PTR bitplanes + BPLANESIZE*2 +si],1
asm rcl al,1
asm shl [BYTE PTR bitplanes + BPLANESIZE*1 +si],1
asm rcl al,1
asm shl [BYTE PTR bitplanes + BPLANESIZE*0 +si],1
asm rcl al,1
asm stosb
asm dec cx
asm jz done
asm dec dx
asm jnz mungebit
asm jmp mungebyte
done:
#endif
}
void MungeBitPlanes4 (int width, byte *dest)
{
*dest=width; // shut up the compiler warning
Error ("MungeBitPlanes4 not rewritten!");
#if 0
asm les di,[dest]
asm mov si,-1
asm mov cx,[width]
mungebyte:
asm inc si
asm mov dx,8
mungebit:
asm xor al,al
asm shl [BYTE PTR bitplanes + BPLANESIZE*3 +si],1
asm rcl al,1
asm shl [BYTE PTR bitplanes + BPLANESIZE*2 +si],1
asm rcl al,1
asm shl [BYTE PTR bitplanes + BPLANESIZE*1 +si],1
asm rcl al,1
asm shl [BYTE PTR bitplanes + BPLANESIZE*0 +si],1
asm rcl al,1
asm stosb
asm dec cx
asm jz done
asm dec dx
asm jnz mungebit
asm jmp mungebyte
done:
#endif
}
void MungeBitPlanes2 (int width, byte *dest)
{
*dest=width; // shut up the compiler warning
Error ("MungeBitPlanes2 not rewritten!");
#if 0
asm les di,[dest]
asm mov si,-1
asm mov cx,[width]
mungebyte:
asm inc si
asm mov dx,8
mungebit:
asm xor al,al
asm shl [BYTE PTR bitplanes + BPLANESIZE*1 +si],1
asm rcl al,1
asm shl [BYTE PTR bitplanes + BPLANESIZE*0 +si],1
asm rcl al,1
asm stosb
asm dec cx
asm jz done
asm dec dx
asm jnz mungebit
asm jmp mungebyte
done:
#endif
}
void MungeBitPlanes1 (int width, byte *dest)
{
*dest=width; // shut up the compiler warning
Error ("MungeBitPlanes1 not rewritten!");
#if 0
asm les di,[dest]
asm mov si,-1
asm mov cx,[width]
mungebyte:
asm inc si
asm mov dx,8
mungebit:
asm xor al,al
asm shl [BYTE PTR bitplanes + BPLANESIZE*0 +si],1
asm rcl al,1
asm stosb
asm dec cx
asm jz done
asm dec dx
asm jnz mungebit
asm jmp mungebyte
done:
#endif
}
/*
=================
=
= LoadLBM
=
=================
*/
void LoadLBM (char *filename, byte **picture, byte **palette)
{
byte *LBMbuffer, *picbuffer, *cmapbuffer;
int y,p,planes;
byte *LBM_P, *LBMEND_P;
byte *pic_p;
byte *body_p;
unsigned rowsize;
int formtype,formlength;
int chunktype,chunklength;
void (*mungecall) (int, byte *);
// qiet compiler warnings
picbuffer = NULL;
cmapbuffer = NULL;
mungecall = NULL;
//
// load the LBM
//
LoadFile (filename, (void **)&LBMbuffer);
//
// parse the LBM header
//
LBM_P = LBMbuffer;
if ( *(int *)LBMbuffer != LittleLong(FORMID) )
Error ("No FORM ID at start of file!\n");
LBM_P += 4;
formlength = BigLong( *(int *)LBM_P );
LBM_P += 4;
LBMEND_P = LBM_P + Align(formlength);
formtype = LittleLong(*(int *)LBM_P);
if (formtype != ILBMID && formtype != PBMID)
Error ("Unrecognized form type: %c%c%c%c\n", formtype&0xff
,(formtype>>8)&0xff,(formtype>>16)&0xff,(formtype>>24)&0xff);
LBM_P += 4;
//
// parse chunks
//
while (LBM_P < LBMEND_P)
{
chunktype = LBM_P[0] + (LBM_P[1]<<8) + (LBM_P[2]<<16) + (LBM_P[3]<<24);
LBM_P += 4;
chunklength = LBM_P[3] + (LBM_P[2]<<8) + (LBM_P[1]<<16) + (LBM_P[0]<<24);
LBM_P += 4;
switch ( chunktype )
{
case BMHDID:
memcpy (&bmhd,LBM_P,sizeof(bmhd));
bmhd.w = BigShort(bmhd.w);
bmhd.h = BigShort(bmhd.h);
bmhd.x = BigShort(bmhd.x);
bmhd.y = BigShort(bmhd.y);
bmhd.pageWidth = BigShort(bmhd.pageWidth);
bmhd.pageHeight = BigShort(bmhd.pageHeight);
break;
case CMAPID:
cmapbuffer = malloc (768);
memset (cmapbuffer, 0, 768);
memcpy (cmapbuffer, LBM_P, chunklength);
break;
case BODYID:
body_p = LBM_P;
pic_p = picbuffer = malloc (bmhd.w*bmhd.h);
if (formtype == PBMID)
{
//
// unpack PBM
//
for (y=0 ; y<bmhd.h ; y++, pic_p += bmhd.w)
{
if (bmhd.compression == cm_rle1)
body_p = LBMRLEDecompress ((byte *)body_p
, pic_p , bmhd.w);
else if (bmhd.compression == cm_none)
{
memcpy (pic_p,body_p,bmhd.w);
body_p += Align(bmhd.w);
}
}
}
else
{
//
// unpack ILBM
//
planes = bmhd.nPlanes;
if (bmhd.masking == ms_mask)
planes++;
rowsize = (bmhd.w+15)/16 * 2;
switch (bmhd.nPlanes)
{
case 1:
mungecall = MungeBitPlanes1;
break;
case 2:
mungecall = MungeBitPlanes2;
break;
case 4:
mungecall = MungeBitPlanes4;
break;
case 8:
mungecall = MungeBitPlanes8;
break;
default:
Error ("Can't munge %i bit planes!\n",bmhd.nPlanes);
}
for (y=0 ; y<bmhd.h ; y++, pic_p += bmhd.w)
{
for (p=0 ; p<planes ; p++)
if (bmhd.compression == cm_rle1)
body_p = LBMRLEDecompress ((byte *)body_p
, bitplanes[p] , rowsize);
else if (bmhd.compression == cm_none)
{
memcpy (bitplanes[p],body_p,rowsize);
body_p += rowsize;
}
mungecall (bmhd.w , pic_p);
}
}
break;
}
LBM_P += Align(chunklength);
}
free (LBMbuffer);
*picture = picbuffer;
*palette = cmapbuffer;
}
/*
============================================================================
WRITE LBM
============================================================================
*/
/*
==============
=
= WriteLBMfile
=
==============
*/
void WriteLBMfile (char *filename, byte *data, int width, int height, byte *palette)
{
byte *lbm, *lbmptr;
int *formlength, *bmhdlength, *cmaplength, *bodylength;
int length;
bmhd_t basebmhd;
lbm = lbmptr = malloc (width*height+1000);
//
// start FORM
//
*lbmptr++ = 'F';
*lbmptr++ = 'O';
*lbmptr++ = 'R';
*lbmptr++ = 'M';
formlength = (int*)lbmptr;
lbmptr+=4; // leave space for length
*lbmptr++ = 'P';
*lbmptr++ = 'B';
*lbmptr++ = 'M';
*lbmptr++ = ' ';
//
// write BMHD
//
*lbmptr++ = 'B';
*lbmptr++ = 'M';
*lbmptr++ = 'H';
*lbmptr++ = 'D';
bmhdlength = (int *)lbmptr;
lbmptr+=4; // leave space for length
memset (&basebmhd,0,sizeof(basebmhd));
basebmhd.w = BigShort((short)width);
basebmhd.h = BigShort((short)height);
basebmhd.nPlanes = BigShort(8);
basebmhd.xAspect = BigShort(5);
basebmhd.yAspect = BigShort(6);
basebmhd.pageWidth = BigShort((short)width);
basebmhd.pageHeight = BigShort((short)height);
memcpy (lbmptr,&basebmhd,sizeof(basebmhd));
lbmptr += sizeof(basebmhd);
length = lbmptr-(byte *)bmhdlength-4;
*bmhdlength = BigLong(length);
if (length&1)
*lbmptr++ = 0; // pad chunk to even offset
//
// write CMAP
//
*lbmptr++ = 'C';
*lbmptr++ = 'M';
*lbmptr++ = 'A';
*lbmptr++ = 'P';
cmaplength = (int *)lbmptr;
lbmptr+=4; // leave space for length
memcpy (lbmptr,palette,768);
lbmptr += 768;
length = lbmptr-(byte *)cmaplength-4;
*cmaplength = BigLong(length);
if (length&1)
*lbmptr++ = 0; // pad chunk to even offset
//
// write BODY
//
*lbmptr++ = 'B';
*lbmptr++ = 'O';
*lbmptr++ = 'D';
*lbmptr++ = 'Y';
bodylength = (int *)lbmptr;
lbmptr+=4; // leave space for length
memcpy (lbmptr,data,width*height);
lbmptr += width*height;
length = lbmptr-(byte *)bodylength-4;
*bodylength = BigLong(length);
if (length&1)
*lbmptr++ = 0; // pad chunk to even offset
//
// done
//
length = lbmptr-(byte *)formlength-4;
*formlength = BigLong(length);
if (length&1)
*lbmptr++ = 0; // pad chunk to even offset
//
// write output file
//
SaveFile (filename, lbm, lbmptr-lbm);
free (lbm);
}

42
qutils/COMMON/LBMLIB.H Normal file
View File

@@ -0,0 +1,42 @@
// lbmlib.h
typedef unsigned char UBYTE;
typedef short WORD;
typedef unsigned short UWORD;
typedef long LONG;
typedef enum
{
ms_none,
ms_mask,
ms_transcolor,
ms_lasso
} mask_t;
typedef enum
{
cm_none,
cm_rle1
} compress_t;
typedef struct
{
UWORD w,h;
WORD x,y;
UBYTE nPlanes;
UBYTE masking;
UBYTE compression;
UBYTE pad1;
UWORD transparentColor;
UBYTE xAspect,yAspect;
WORD pageWidth,pageHeight;
} bmhd_t;
extern bmhd_t bmhd; // will be in native byte order
void LoadLBM (char *filename, byte **picture, byte **palette);
void WriteLBMfile (char *filename, byte *data, int width, int height
, byte *palette);

109
qutils/COMMON/MATHLIB.C Normal file
View File

@@ -0,0 +1,109 @@
// mathlib.c -- math primitives
#include "cmdlib.h"
#include "mathlib.h"
vec3_t vec3_origin = {0,0,0};
double VectorLength(vec3_t v)
{
int i;
double length;
length = 0;
for (i=0 ; i< 3 ; i++)
length += v[i]*v[i];
length = sqrt (length); // FIXME
return length;
}
qboolean VectorCompare (vec3_t v1, vec3_t v2)
{
int i;
for (i=0 ; i<3 ; i++)
if (fabs(v1[i]-v2[i]) > EQUAL_EPSILON)
return false;
return true;
}
vec_t Q_rint (vec_t in)
{
return floor (in + 0.5);
}
void VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc)
{
vc[0] = va[0] + scale*vb[0];
vc[1] = va[1] + scale*vb[1];
vc[2] = va[2] + scale*vb[2];
}
void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross)
{
cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
}
vec_t _DotProduct (vec3_t v1, vec3_t v2)
{
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
}
void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out)
{
out[0] = va[0]-vb[0];
out[1] = va[1]-vb[1];
out[2] = va[2]-vb[2];
}
void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out)
{
out[0] = va[0]+vb[0];
out[1] = va[1]+vb[1];
out[2] = va[2]+vb[2];
}
void _VectorCopy (vec3_t in, vec3_t out)
{
out[0] = in[0];
out[1] = in[1];
out[2] = in[2];
}
vec_t VectorNormalize (vec3_t v)
{
int i;
double length;
length = 0;
for (i=0 ; i< 3 ; i++)
length += v[i]*v[i];
length = sqrt (length);
if (length == 0)
return 0;
for (i=0 ; i< 3 ; i++)
v[i] /= length;
return length;
}
void VectorInverse (vec3_t v)
{
v[0] = -v[0];
v[1] = -v[1];
v[2] = -v[2];
}
void VectorScale (vec3_t v, vec_t scale, vec3_t out)
{
out[0] = v[0] * scale;
out[1] = v[1] * scale;
out[2] = v[2] * scale;
}

48
qutils/COMMON/MATHLIB.H Normal file
View File

@@ -0,0 +1,48 @@
#ifndef __MATHLIB__
#define __MATHLIB__
// mathlib.h
#include <math.h>
#ifdef DOUBLEVEC_T
typedef double vec_t;
#else
typedef float vec_t;
#endif
typedef vec_t vec3_t[3];
#define SIDE_FRONT 0
#define SIDE_ON 2
#define SIDE_BACK 1
#define SIDE_CROSS -2
#define Q_PI 3.14159265358979323846
extern vec3_t vec3_origin;
#define EQUAL_EPSILON 0.001
qboolean VectorCompare (vec3_t v1, vec3_t v2);
#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];}
#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];}
#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];}
vec_t Q_rint (vec_t in);
vec_t _DotProduct (vec3_t v1, vec3_t v2);
void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out);
void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out);
void _VectorCopy (vec3_t in, vec3_t out);
double VectorLength(vec3_t v);
void VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc);
void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross);
vec_t VectorNormalize (vec3_t v);
void VectorInverse (vec3_t v);
void VectorScale (vec3_t v, vec_t scale, vec3_t out);
#endif

400
qutils/COMMON/POLYLIB.C Normal file
View File

@@ -0,0 +1,400 @@
#include "cmdlib.h"
#include "mathlib.h"
#include "polylib.h"
#define BOGUS_RANGE 8192
/*
=============
AllocWinding
=============
*/
winding_t *AllocWinding (int points)
{
winding_t *w;
int s;
s = sizeof(vec_t)*3*points + sizeof(int);
w = malloc (s);
memset (w, 0, s);
return w;
}
/*
============
RemoveColinearPoints
============
*/
int c_removed;
void RemoveColinearPoints (winding_t *w)
{
int i, j, k;
vec3_t v1, v2;
int nump;
vec3_t p[MAX_POINTS_ON_WINDING];
nump = 0;
for (i=0 ; i<w->numpoints ; i++)
{
j = (i+1)%w->numpoints;
k = (i+w->numpoints-1)%w->numpoints;
VectorSubtract (w->p[j], w->p[i], v1);
VectorSubtract (w->p[i], w->p[k], v2);
VectorNormalize(v1);
VectorNormalize(v2);
if (DotProduct(v1, v2) < 0.999)
{
VectorCopy (w->p[i], p[nump]);
nump++;
}
}
if (nump == w->numpoints)
return;
c_removed += w->numpoints - nump;
w->numpoints = nump;
memcpy (w->p, p, nump*sizeof(p[0]));
}
/*
============
WindingPlane
============
*/
void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist)
{
vec3_t v1, v2;
VectorSubtract (w->p[1], w->p[0], v1);
VectorSubtract (w->p[2], w->p[0], v2);
CrossProduct (v1, v2, normal);
VectorNormalize (normal);
*dist = DotProduct (w->p[0], normal);
}
/*
=============
WindingArea
=============
*/
vec_t WindingArea (winding_t *w)
{
int i;
vec3_t d1, d2, cross;
vec_t total;
total = 0;
for (i=2 ; i<w->numpoints ; i++)
{
VectorSubtract (w->p[i-1], w->p[0], d1);
VectorSubtract (w->p[i], w->p[0], d2);
CrossProduct (d1, d2, cross);
total += 0.5 * VectorLength ( cross );
}
return total;
}
/*
=============
WindingCenter
=============
*/
void WindingCenter (winding_t *w, vec3_t center)
{
int i;
vec3_t d1, d2, cross;
float scale;
VectorCopy (vec3_origin, center);
for (i=0 ; i<w->numpoints ; i++)
VectorAdd (w->p[i], center, center);
scale = 1.0/w->numpoints;
VectorScale (center, scale, center);
}
/*
=================
BaseWindingForPlane
=================
*/
winding_t *BaseWindingForPlane (vec3_t normal, float dist)
{
int i, x;
vec_t max, v;
vec3_t org, vright, vup;
winding_t *w;
// find the major axis
max = -BOGUS_RANGE;
x = -1;
for (i=0 ; i<3; i++)
{
v = fabs(normal[i]);
if (v > max)
{
x = i;
max = v;
}
}
if (x==-1)
Error ("BaseWindingForPlane: no axis found");
VectorCopy (vec3_origin, vup);
switch (x)
{
case 0:
case 1:
vup[2] = 1;
break;
case 2:
vup[0] = 1;
break;
}
v = DotProduct (vup, normal);
VectorMA (vup, -v, normal, vup);
VectorNormalize (vup);
VectorScale (normal, dist, org);
CrossProduct (vup, normal, vright);
VectorScale (vup, 8192, vup);
VectorScale (vright, 8192, vright);
// project a really big axis aligned box onto the plane
w = AllocWinding (4);
VectorSubtract (org, vright, w->p[0]);
VectorAdd (w->p[0], vup, w->p[0]);
VectorAdd (org, vright, w->p[1]);
VectorAdd (w->p[1], vup, w->p[1]);
VectorAdd (org, vright, w->p[2]);
VectorSubtract (w->p[2], vup, w->p[2]);
VectorSubtract (org, vright, w->p[3]);
VectorSubtract (w->p[3], vup, w->p[3]);
w->numpoints = 4;
return w;
}
/*
==================
CopyWinding
==================
*/
winding_t *CopyWinding (winding_t *w)
{
int size;
winding_t *c;
size = (int)((winding_t *)0)->p[w->numpoints];
c = malloc (size);
memcpy (c, w, size);
return c;
}
/*
=============
ClipWinding
=============
*/
void ClipWinding (winding_t *in, vec3_t normal, vec_t dist,
winding_t **front, winding_t **back)
{
vec_t dists[MAX_POINTS_ON_WINDING+4];
int sides[MAX_POINTS_ON_WINDING+4];
int counts[3];
vec_t dot;
int i, j;
vec_t *p1, *p2;
vec3_t mid;
winding_t *f, *b;
int maxpts;
counts[0] = counts[1] = counts[2] = 0;
// determine sides for each point
for (i=0 ; i<in->numpoints ; i++)
{
dot = DotProduct (in->p[i], normal);
dot -= dist;
dists[i] = dot;
if (dot > ON_EPSILON)
sides[i] = SIDE_FRONT;
else if (dot < -ON_EPSILON)
sides[i] = SIDE_BACK;
else
{
sides[i] = SIDE_ON;
}
counts[sides[i]]++;
}
sides[i] = sides[0];
dists[i] = dists[0];
*front = *back = NULL;
if (!counts[0])
{
*back = CopyWinding (in);
return;
}
if (!counts[1])
{
*front = CopyWinding (in);
return;
}
maxpts = in->numpoints+4; // can't use counts[0]+2 because
// of fp grouping errors
*front = f = AllocWinding (maxpts);
*back = b = AllocWinding (maxpts);
for (i=0 ; i<in->numpoints ; i++)
{
p1 = in->p[i];
if (sides[i] == SIDE_ON)
{
VectorCopy (p1, f->p[f->numpoints]);
f->numpoints++;
VectorCopy (p1, b->p[b->numpoints]);
b->numpoints++;
continue;
}
if (sides[i] == SIDE_FRONT)
{
VectorCopy (p1, f->p[f->numpoints]);
f->numpoints++;
}
if (sides[i] == SIDE_BACK)
{
VectorCopy (p1, b->p[b->numpoints]);
b->numpoints++;
}
if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
continue;
// generate a split point
p2 = in->p[(i+1)%in->numpoints];
dot = dists[i] / (dists[i]-dists[i+1]);
for (j=0 ; j<3 ; j++)
{ // avoid round off error when possible
if (normal[j] == 1)
mid[j] = dist;
else if (normal[j] == -1)
mid[j] = -dist;
else
mid[j] = p1[j] + dot*(p2[j]-p1[j]);
}
VectorCopy (mid, f->p[f->numpoints]);
f->numpoints++;
VectorCopy (mid, b->p[b->numpoints]);
b->numpoints++;
}
if (f->numpoints > maxpts || b->numpoints > maxpts)
Error ("ClipWinding: points exceeded estimate");
if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)
Error ("ClipWinding: MAX_POINTS_ON_WINDING");
}
/*
=================
ChopWinding
Returns the fragment of in that is on the front side
of the cliping plane. The original is freed.
=================
*/
winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist)
{
winding_t *f, *b;
ClipWinding (in, normal, dist, &f, &b);
free (in);
if (b)
free (b);
return f;
}
/*
=================
CheckWinding
=================
*/
void CheckWinding (winding_t *w)
{
int i, j;
vec_t *p1, *p2;
vec_t d, edgedist;
vec3_t dir, edgenormal, facenormal;
vec_t area;
vec_t facedist;
if (w->numpoints < 3)
Error ("CheckFace: %i points",w->numpoints);
area = WindingArea(w);
if (area < 1)
Error ("CheckFace: %f area", area);
WindingPlane (w, facenormal, &facedist);
for (i=0 ; i<w->numpoints ; i++)
{
p1 = w->p[i];
for (j=0 ; j<3 ; j++)
if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE)
Error ("CheckFace: BUGUS_RANGE: %f",p1[j]);
j = i+1 == w->numpoints ? 0 : i+1;
// check the point is on the face plane
d = DotProduct (p1, facenormal) - facedist;
if (d < -ON_EPSILON || d > ON_EPSILON)
Error ("CheckFace: point off plane");
// check the edge isn't degenerate
p2 = w->p[j];
VectorSubtract (p2, p1, dir);
if (VectorLength (dir) < ON_EPSILON)
Error ("CheckFace: degenerate edge");
CrossProduct (facenormal, dir, edgenormal);
VectorNormalize (edgenormal);
edgedist = DotProduct (p1, edgenormal);
edgedist += ON_EPSILON;
// all other points must be on front side
for (j=0 ; j<w->numpoints ; j++)
{
if (j == i)
continue;
d = DotProduct (w->p[j], edgenormal);
if (d > edgedist)
Error ("CheckFace: non-convex");
}
}
}

22
qutils/COMMON/POLYLIB.H Normal file
View File

@@ -0,0 +1,22 @@
typedef struct
{
int numpoints;
vec3_t p[4]; // variable sized
} winding_t;
#define MAX_POINTS_ON_WINDING 64
#define ON_EPSILON 0.1
winding_t *AllocWinding (int points);
vec_t WindingArea (winding_t *w);
void WindingCenter (winding_t *w, vec3_t center);
void ClipWinding (winding_t *in, vec3_t normal, vec_t dist,
winding_t **front, winding_t **back);
winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist);
winding_t *CopyWinding (winding_t *w);
winding_t *BaseWindingForPlane (vec3_t normal, float dist);
void CheckWinding (winding_t *w);
void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist);
void RemoveColinearPoints (winding_t *w);

185
qutils/COMMON/SCRIPLIB.C Normal file
View File

@@ -0,0 +1,185 @@
// scriplib.c
#include "cmdlib.h"
#include "scriplib.h"
/*
=============================================================================
PARSING STUFF
=============================================================================
*/
char token[MAXTOKEN];
char *scriptbuffer,*script_p,*scriptend_p;
int grabbed;
int scriptline;
qboolean endofscript;
qboolean tokenready; // only true if UnGetToken was just called
/*
==============
=
= LoadScriptFile
=
==============
*/
void LoadScriptFile (char *filename)
{
int size;
size = LoadFile (filename, (void **)&scriptbuffer);
script_p = scriptbuffer;
scriptend_p = script_p + size;
scriptline = 1;
endofscript = false;
tokenready = false;
}
/*
==============
=
= UnGetToken
=
= Signals that the current token was not used, and should be reported
= for the next GetToken. Note that
GetToken (true);
UnGetToken ();
GetToken (false);
= could cross a line boundary.
=
==============
*/
void UnGetToken (void)
{
tokenready = true;
}
/*
==============
GetToken
==============
*/
qboolean GetToken (qboolean crossline)
{
char *token_p;
if (tokenready) // is a token allready waiting?
{
tokenready = false;
return true;
}
if (script_p >= scriptend_p)
{
if (!crossline)
Error ("Line %i is incomplete\n",scriptline);
endofscript = true;
return false;
}
//
// skip space
//
skipspace:
while (*script_p <= 32)
{
if (script_p >= scriptend_p)
{
if (!crossline)
Error ("Line %i is incomplete\n",scriptline);
endofscript = true;
return true;
}
if (*script_p++ == '\n')
{
if (!crossline)
Error ("Line %i is incomplete\n",scriptline);
scriptline++;
}
}
if (script_p >= scriptend_p)
{
if (!crossline)
Error ("Line %i is incomplete\n",scriptline);
endofscript = true;
return true;
}
if (*script_p == ';' || *script_p == '#') // semicolon is comment field
{ // also make # a comment field
if (!crossline)
Error ("Line %i is incomplete\n",scriptline);
while (*script_p++ != '\n')
if (script_p >= scriptend_p)
{
endofscript = true;
return false;
}
goto skipspace;
}
//
// copy token
//
token_p = token;
while ( *script_p > 32 && *script_p != ';')
{
*token_p++ = *script_p++;
if (script_p == scriptend_p)
break;
if (token_p == &token[MAXTOKEN])
Error ("Token too large on line %i\n",scriptline);
}
*token_p = 0;
return true;
}
/*
==============
=
= TokenAvailable
=
= Returns true if there is another token on the line
=
==============
*/
qboolean TokenAvailable (void)
{
char *search_p;
search_p = script_p;
if (search_p >= scriptend_p)
return false;
while ( *search_p <= 32)
{
if (*search_p == '\n')
return false;
search_p++;
if (search_p == scriptend_p)
return false;
}
if (*search_p == ';')
return false;
return true;
}

21
qutils/COMMON/SCRIPLIB.H Normal file
View File

@@ -0,0 +1,21 @@
// scriplib.h
#ifndef __CMDLIB__
#include "cmdlib.h"
#endif
#define MAXTOKEN 128
extern char token[MAXTOKEN];
extern char *scriptbuffer,*script_p,*scriptend_p;
extern int grabbed;
extern int scriptline;
extern qboolean endofscript;
void LoadScriptFile (char *filename);
qboolean GetToken (qboolean crossline);
void UnGetToken (void);
qboolean TokenAvailable (void);

239
qutils/COMMON/THREADS.C Normal file
View File

@@ -0,0 +1,239 @@
#include "cmdlib.h"
#include "threads.h"
#define MAX_THREADS 64
int dispatch;
int workcount;
int oldf;
qboolean pacifier;
/*
=============
GetThreadWork
=============
*/
int GetThreadWork (void)
{
int r;
int f;
ThreadLock ();
if (dispatch == workcount)
{
ThreadUnlock ();
return -1;
}
f = 10*dispatch / workcount;
if (f != oldf)
{
oldf = f;
if (pacifier)
printf ("%i...", f);
}
r = dispatch;
dispatch++;
ThreadUnlock ();
return r;
}
/*
===================================================================
WIN32
===================================================================
*/
#ifdef WIN32
#define USED
#include <windows.h>
int numthreads = 1;
CRITICAL_SECTION crit;
void ThreadLock (void)
{
EnterCriticalSection (&crit);
}
void ThreadUnlock (void)
{
LeaveCriticalSection (&crit);
}
/*
=============
RunThreadsOn
=============
*/
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
{
int threadid[MAX_THREADS];
HANDLE threadhandle[MAX_THREADS];
int i;
dispatch = 0;
workcount = workcnt;
oldf = -1;
pacifier = showpacifier;
//
// run threads in parallel
//
InitializeCriticalSection (&crit);
for (i=0 ; i<numthreads ; i++)
{
threadhandle[i] = CreateThread(
NULL, // LPSECURITY_ATTRIBUTES lpsa,
0, // DWORD cbStack,
(LPTHREAD_START_ROUTINE)func, // LPTHREAD_START_ROUTINE lpStartAddr,
(LPVOID)i, // LPVOID lpvThreadParm,
0, // DWORD fdwCreate,
&threadid[i]);
}
for (i=0 ; i<numthreads ; i++)
WaitForSingleObject (threadhandle[i], INFINITE);
DeleteCriticalSection (&crit);
if (pacifier)
printf ("\n");
}
#endif
/*
===================================================================
OSF1
===================================================================
*/
#ifdef __osf__
#define USED
int numthreads = 4;
#include <pthread.h>
pthread_mutex_t *my_mutex;
void ThreadLock (void)
{
if (my_mutex)
pthread_mutex_lock (my_mutex);
}
void ThreadUnlock (void)
{
if (my_mutex)
pthread_mutex_unlock (my_mutex);
}
/*
=============
RunThreadsOn
=============
*/
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
{
int i;
pthread_t work_threads[MAX_THREADS];
pthread_addr_t status;
pthread_attr_t attrib;
pthread_mutexattr_t mattrib;
dispatch = 0;
workcount = workcnt;
oldf = -1;
pacifier = showpacifier;
if (!my_mutex)
{
my_mutex = malloc (sizeof(*my_mutex));
if (pthread_mutexattr_create (&mattrib) == -1)
Error ("pthread_mutex_attr_create failed");
if (pthread_mutexattr_setkind_np (&mattrib, MUTEX_FAST_NP) == -1)
Error ("pthread_mutexattr_setkind_np failed");
if (pthread_mutex_init (my_mutex, mattrib) == -1)
Error ("pthread_mutex_init failed");
}
if (pthread_attr_create (&attrib) == -1)
Error ("pthread_attr_create failed");
if (pthread_attr_setstacksize (&attrib, 0x100000) == -1)
Error ("pthread_attr_setstacksize failed");
for (i=0 ; i<numthreads ; i++)
{
if (pthread_create(&work_threads[i], attrib
, (pthread_startroutine_t)func, (pthread_addr_t)i) == -1)
Error ("pthread_create failed");
}
for (i=0 ; i<numthreads ; i++)
{
if (pthread_join (work_threads[i], &status) == -1)
Error ("pthread_join failed");
}
if (pacifier)
printf ("\n");
}
#endif
/*
=======================================================================
SINGLE THREAD
=======================================================================
*/
#ifndef USED
int numthreads = 1;
void ThreadLock (void)
{
}
void ThreadUnlock (void)
{
}
/*
=============
RunThreadsOn
=============
*/
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
{
int i;
dispatch = 0;
workcount = workcnt;
oldf = -1;
pacifier = showpacifier;
func(0);
if (pacifier)
printf ("\n");
}
#endif

8
qutils/COMMON/THREADS.H Normal file
View File

@@ -0,0 +1,8 @@
extern int numthreads;
int GetThreadWork (void);
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int));
void ThreadLock (void);
void ThreadUnlock (void);

170
qutils/COMMON/TRILIB.C Normal file
View File

@@ -0,0 +1,170 @@
//
// trilib.c: library for loading triangles from an Alias triangle file
//
#include <stdio.h>
#include "cmdlib.h"
#include "mathlib.h"
#include "trilib.h"
// on disk representation of a face
#define FLOAT_START 99999.0
#define FLOAT_END -FLOAT_START
#define MAGIC 123322
//#define NOISY 1
typedef struct {
float v[3];
} vector;
typedef struct
{
vector n; /* normal */
vector p; /* point */
vector c; /* color */
float u; /* u */
float v; /* v */
} aliaspoint_t;
typedef struct {
aliaspoint_t pt[3];
} tf_triangle;
void ByteSwapTri (tf_triangle *tri)
{
int i;
for (i=0 ; i<sizeof(tf_triangle)/4 ; i++)
{
((int *)tri)[i] = BigLong (((int *)tri)[i]);
}
}
void LoadTriangleList (char *filename, triangle_t **pptri, int *numtriangles)
{
FILE *input;
float start;
char name[256], tex[256];
int i, count, magic;
tf_triangle tri;
triangle_t *ptri;
int iLevel;
int exitpattern;
float t;
t = -FLOAT_START;
*((unsigned char *)&exitpattern + 0) = *((unsigned char *)&t + 3);
*((unsigned char *)&exitpattern + 1) = *((unsigned char *)&t + 2);
*((unsigned char *)&exitpattern + 2) = *((unsigned char *)&t + 1);
*((unsigned char *)&exitpattern + 3) = *((unsigned char *)&t + 0);
if ((input = fopen(filename, "rb")) == 0) {
fprintf(stderr,"reader: could not open file '%s'\n", filename);
exit(0);
}
iLevel = 0;
fread(&magic, sizeof(int), 1, input);
if (BigLong(magic) != MAGIC) {
fprintf(stderr,"File is not a Alias object separated triangle file, magic number is wrong.\n");
exit(0);
}
ptri = malloc (MAXTRIANGLES * sizeof(triangle_t));
*pptri = ptri;
while (feof(input) == 0) {
fread(&start, sizeof(float), 1, input);
*(int *)&start = BigLong(*(int *)&start);
if (*(int *)&start != exitpattern)
{
if (start == FLOAT_START) {
/* Start of an object or group of objects. */
i = -1;
do {
/* There are probably better ways to read a string from */
/* a file, but this does allow you to do error checking */
/* (which I'm not doing) on a per character basis. */
++i;
fread( &(name[i]), sizeof( char ), 1, input);
} while( name[i] != '\0' );
// indent();
// fprintf(stdout,"OBJECT START: %s\n",name);
fread( &count, sizeof(int), 1, input);
count = BigLong(count);
++iLevel;
if (count != 0) {
// indent();
// fprintf(stdout,"NUMBER OF TRIANGLES: %d\n",count);
i = -1;
do {
++i;
fread( &(tex[i]), sizeof( char ), 1, input);
} while( tex[i] != '\0' );
// indent();
// fprintf(stdout," Object texture name: '%s'\n",tex);
}
/* Else (count == 0) this is the start of a group, and */
/* no texture name is present. */
}
else if (start == FLOAT_END) {
/* End of an object or group. Yes, the name should be */
/* obvious from context, but it is in here just to be */
/* safe and to provide a little extra information for */
/* those who do not wish to write a recursive reader. */
/* Mia culpa. */
--iLevel;
i = -1;
do {
++i;
fread( &(name[i]), sizeof( char ), 1, input);
} while( name[i] != '\0' );
// indent();
// fprintf(stdout,"OBJECT END: %s\n",name);
continue;
}
}
//
// read the triangles
//
for (i = 0; i < count; ++i) {
int j;
fread( &tri, sizeof(tf_triangle), 1, input );
ByteSwapTri (&tri);
for (j=0 ; j<3 ; j++)
{
int k;
for (k=0 ; k<3 ; k++)
{
ptri->verts[j][k] = tri.pt[j].p.v[k];
}
}
ptri++;
if ((ptri - *pptri) >= MAXTRIANGLES)
Error ("Error: too many triangles; increase MAXTRIANGLES\n");
}
}
*numtriangles = ptri - *pptri;
fclose (input);
}

11
qutils/COMMON/TRILIB.H Normal file
View File

@@ -0,0 +1,11 @@
//
// trilib.h: header file for loading triangles from an Alias triangle file
//
#define MAXTRIANGLES 2048
typedef struct {
vec3_t verts[3];
} triangle_t;
void LoadTriangleList (char *filename, triangle_t **pptri, int *numtriangles);

328
qutils/COMMON/WADLIB.C Normal file
View File

@@ -0,0 +1,328 @@
// wad2lib.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
//#include <sys/file.h>
#include <stdarg.h>
#ifdef NeXT
#include <libc.h>
#endif
#include "cmdlib.h"
#include "wadlib.h"
/*
============================================================================
WAD READING
============================================================================
*/
lumpinfo_t *lumpinfo; // location of each lump on disk
int numlumps;
wadinfo_t header;
FILE *wadhandle;
/*
====================
W_OpenWad
====================
*/
void W_OpenWad (char *filename)
{
lumpinfo_t *lump_p;
unsigned i;
int length;
//
// open the file and add to directory
//
wadhandle = SafeOpenRead (filename);
SafeRead (wadhandle, &header, sizeof(header));
if (strncmp(header.identification,"WAD2",4))
Error ("Wad file %s doesn't have WAD2 id\n",filename);
header.numlumps = LittleLong(header.numlumps);
header.infotableofs = LittleLong(header.infotableofs);
numlumps = header.numlumps;
length = numlumps*sizeof(lumpinfo_t);
lumpinfo = malloc (length);
lump_p = lumpinfo;
fseek (wadhandle, header.infotableofs, SEEK_SET);
SafeRead (wadhandle, lumpinfo, length);
//
// Fill in lumpinfo
//
for (i=0 ; i<numlumps ; i++,lump_p++)
{
lump_p->filepos = LittleLong(lump_p->filepos);
lump_p->size = LittleLong(lump_p->size);
}
}
void CleanupName (char *in, char *out)
{
int i;
for (i=0 ; i<sizeof( ((lumpinfo_t *)0)->name ) ; i++ )
{
if (!in[i])
break;
out[i] = toupper(in[i]);
}
for ( ; i<sizeof( ((lumpinfo_t *)0)->name ); i++ )
out[i] = 0;
}
/*
====================
W_CheckNumForName
Returns -1 if name not found
====================
*/
int W_CheckNumForName (char *name)
{
char cleanname[16];
int v1,v2, v3, v4;
int i;
lumpinfo_t *lump_p;
CleanupName (name, cleanname);
// make the name into four integers for easy compares
v1 = *(int *)cleanname;
v2 = *(int *)&cleanname[4];
v3 = *(int *)&cleanname[8];
v4 = *(int *)&cleanname[12];
// find it
lump_p = lumpinfo;
for (i=0 ; i<numlumps ; i++, lump_p++)
{
if ( *(int *)lump_p->name == v1
&& *(int *)&lump_p->name[4] == v2
&& *(int *)&lump_p->name[8] == v3
&& *(int *)&lump_p->name[12] == v4)
return i;
}
return -1;
}
/*
====================
W_GetNumForName
Calls W_CheckNumForName, but bombs out if not found
====================
*/
int W_GetNumForName (char *name)
{
int i;
i = W_CheckNumForName (name);
if (i != -1)
return i;
Error ("W_GetNumForName: %s not found!",name);
return -1;
}
/*
====================
W_LumpLength
Returns the buffer size needed to load the given lump
====================
*/
int W_LumpLength (int lump)
{
if (lump >= numlumps)
Error ("W_LumpLength: %i >= numlumps",lump);
return lumpinfo[lump].size;
}
/*
====================
W_ReadLumpNum
Loads the lump into the given buffer, which must be >= W_LumpLength()
====================
*/
void W_ReadLumpNum (int lump, void *dest)
{
lumpinfo_t *l;
if (lump >= numlumps)
Error ("W_ReadLump: %i >= numlumps",lump);
l = lumpinfo+lump;
fseek (wadhandle, l->filepos, SEEK_SET);
SafeRead (wadhandle, dest, l->size);
}
/*
====================
W_LoadLumpNum
====================
*/
void *W_LoadLumpNum (int lump)
{
void *buf;
if ((unsigned)lump >= numlumps)
Error ("W_CacheLumpNum: %i >= numlumps",lump);
buf = malloc (W_LumpLength (lump));
W_ReadLumpNum (lump, buf);
return buf;
}
/*
====================
W_LoadLumpName
====================
*/
void *W_LoadLumpName (char *name)
{
return W_LoadLumpNum (W_GetNumForName(name));
}
/*
===============================================================================
WAD CREATION
===============================================================================
*/
FILE *outwad;
lumpinfo_t outinfo[4096];
int outlumps;
short (*wadshort) (short l);
int (*wadlong) (int l);
/*
===============
NewWad
===============
*/
void NewWad (char *pathname, qboolean bigendien)
{
outwad = SafeOpenWrite (pathname);
fseek (outwad, sizeof(wadinfo_t), SEEK_SET);
memset (outinfo, 0, sizeof(outinfo));
if (bigendien)
{
wadshort = BigShort;
wadlong = BigLong;
}
else
{
wadshort = LittleShort;
wadlong = LittleLong;
}
outlumps = 0;
}
/*
===============
AddLump
===============
*/
void AddLump (char *name, void *buffer, int length, int type, int compress)
{
lumpinfo_t *info;
int ofs;
info = &outinfo[outlumps];
outlumps++;
memset (info,0,sizeof(info));
strcpy (info->name, name);
strupr (info->name);
ofs = ftell(outwad);
info->filepos = wadlong(ofs);
info->size = info->disksize = wadlong(length);
info->type = type;
info->compression = compress;
// FIXME: do compression
SafeWrite (outwad, buffer, length);
}
/*
===============
WriteWad
===============
*/
void WriteWad (void)
{
wadinfo_t header;
int ofs;
// write the lumpingo
ofs = ftell(outwad);
SafeWrite (outwad, outinfo, outlumps*sizeof(lumpinfo_t) );
// write the header
// a program will be able to tell the ednieness of a wad by the id
header.identification[0] = 'W';
header.identification[1] = 'A';
header.identification[2] = 'D';
header.identification[3] = '2';
header.numlumps = wadlong(outlumps);
header.infotableofs = wadlong(ofs);
fseek (outwad, 0, SEEK_SET);
SafeWrite (outwad, &header, sizeof(header));
fclose (outwad);
}

53
qutils/COMMON/WADLIB.H Normal file
View File

@@ -0,0 +1,53 @@
// wadlib.h
//
// wad reading
//
#define CMP_NONE 0
#define CMP_LZSS 1
#define TYP_NONE 0
#define TYP_LABEL 1
#define TYP_LUMPY 64 // 64 + grab command number
typedef struct
{
char identification[4]; // should be WAD2 or 2DAW
int numlumps;
int infotableofs;
} wadinfo_t;
typedef struct
{
int filepos;
int disksize;
int size; // uncompressed
char type;
char compression;
char pad1, pad2;
char name[16]; // must be null terminated
} lumpinfo_t;
extern lumpinfo_t *lumpinfo; // location of each lump on disk
extern int numlumps;
extern wadinfo_t header;
void W_OpenWad (char *filename);
int W_CheckNumForName (char *name);
int W_GetNumForName (char *name);
int W_LumpLength (int lump);
void W_ReadLumpNum (int lump, void *dest);
void *W_LoadLumpNum (int lump);
void *W_LoadLumpName (char *name);
void CleanupName (char *in, char *out);
//
// wad creation
//
void NewWad (char *pathname, qboolean bigendien);
void AddLump (char *name, void *buffer, int length, int type, int compress);
void WriteWad (void);

43
qutils/INSTALL.BAT Normal file
View File

@@ -0,0 +1,43 @@
cd qlumpy
nmake /f "qlumpy.mak" CFG="qlumpy - Win32 Release"
copy release\qlumpy.exe \quake\bin_nt
cd ..\texmake
nmake /f "texmake.mak" CFG="texmake - Win32 Release"
copy release\texmake.exe \quake\bin_nt
cd ..\modelgen
nmake /f "modelgen.mak" CFG="modelgen - Win32 Release"
copy release\modelgen.exe \quake\bin_nt
cd ..\sprgen
nmake /f "sprgen.mak" CFG="sprgen - Win32 Release"
copy release\sprgen.exe \quake\bin_nt
cd ..\qbsp
nmake /f "qbsp.mak" CFG="qbsp - Win32 Release"
copy release\qbsp.exe \quake\bin_nt
cd ..\light
nmake /f "light.mak" CFG="light - Win32 Release"
copy release\light.exe \quake\bin_nt
cd ..\vis
nmake /f "vis.mak" CFG="vis - Win32 Release"
copy release\vis.exe \quake\bin_nt
cd ..\bspinfo
nmake /f "bspinfo.mak" CFG="bspinfo - Win32 Release"
copy release\bspinfo.exe \quake\bin_nt
cd ..\qcc
nmake /f "qcc.mak" CFG="qcc - Win32 Release"
copy release\qcc.exe \quake\bin_nt
cd ..\qfiles
nmake /f "qfiles.mak" CFG="qfiles - Win32 Release"
copy release\qfiles.exe \quake\bin_nt
cd ..

278
qutils/LIGHT/ENTITIES.C Normal file
View File

@@ -0,0 +1,278 @@
// entities.c
#include "light.h"
entity_t entities[MAX_MAP_ENTITIES];
int num_entities;
/*
==============================================================================
ENTITY FILE PARSING
If a light has a targetname, generate a unique style in the 32-63 range
==============================================================================
*/
int numlighttargets;
char lighttargets[32][64];
int LightStyleForTargetname (char *targetname, qboolean alloc)
{
int i;
for (i=0 ; i<numlighttargets ; i++)
if (!strcmp (lighttargets[i], targetname))
return 32 + i;
if (!alloc)
return -1;
strcpy (lighttargets[i], targetname);
numlighttargets++;
return numlighttargets-1 + 32;
}
/*
==================
MatchTargets
==================
*/
void MatchTargets (void)
{
int i,j;
for (i=0 ; i<num_entities ; i++)
{
if (!entities[i].target[0])
continue;
for (j=0 ; j<num_entities ; j++)
if (!strcmp(entities[j].targetname, entities[i].target))
{
entities[i].targetent = &entities[j];
break;
}
if (j==num_entities)
{
printf ("WARNING: entity at (%i,%i,%i) (%s) has unmatched target\n", (int)entities[i].origin[0], (int)entities[i].origin[1], (int)entities[i].origin[2], entities[i].classname);
continue;
}
// set the style on the source ent for switchable lights
if (entities[j].style)
{
char s[16];
entities[i].style = entities[j].style;
sprintf (s,"%i", entities[i].style);
SetKeyValue (&entities[i], "style", s);
}
}
}
/*
==================
LoadEntities
==================
*/
void LoadEntities (void)
{
char *data;
entity_t *entity;
char key[64];
epair_t *epair;
double vec[3];
int i;
data = dentdata;
//
// start parsing
//
num_entities = 0;
// go through all the entities
while (1)
{
// parse the opening brace
data = COM_Parse (data);
if (!data)
break;
if (com_token[0] != '{')
Error ("LoadEntities: found %s when expecting {",com_token);
if (num_entities == MAX_MAP_ENTITIES)
Error ("LoadEntities: MAX_MAP_ENTITIES");
entity = &entities[num_entities];
num_entities++;
// go through all the keys in this entity
while (1)
{
int c;
// parse key
data = COM_Parse (data);
if (!data)
Error ("LoadEntities: EOF without closing brace");
if (!strcmp(com_token,"}"))
break;
strcpy (key, com_token);
// parse value
data = COM_Parse (data);
if (!data)
Error ("LoadEntities: EOF without closing brace");
c = com_token[0];
if (c == '}')
Error ("LoadEntities: closing brace without data");
epair = malloc (sizeof(epair_t));
memset (epair, 0, sizeof(epair));
strcpy (epair->key, key);
strcpy (epair->value, com_token);
epair->next = entity->epairs;
entity->epairs = epair;
if (!strcmp(key, "classname"))
strcpy (entity->classname, com_token);
else if (!strcmp(key, "target"))
strcpy (entity->target, com_token);
else if (!strcmp(key, "targetname"))
strcpy (entity->targetname, com_token);
else if (!strcmp(key, "origin"))
{
// scan into doubles, then assign
// which makes it vec_t size independent
if (sscanf(com_token, "%lf %lf %lf",
&vec[0], &vec[1], &vec[2]) != 3)
Error ("LoadEntities: not 3 values for origin");
for (i=0 ; i<3 ; i++)
entity->origin[i] = vec[i];
}
else if (!strncmp(key, "light", 5) || !strcmp (key, "_light") )
{
entity->light = atof(com_token);
}
else if (!strcmp(key, "style"))
{
entity->style = atof(com_token);
if ((unsigned)entity->style > 254)
Error ("Bad light style %i (must be 0-254)", entity->style);
}
else if (!strcmp(key, "angle"))
{
entity->angle = atof(com_token);
}
}
// all fields have been parsed
if (!strncmp (entity->classname, "light", 5) && !entity->light)
entity->light = DEFAULTLIGHTLEVEL;
if (!strcmp (entity->classname, "light"))
{
if (entity->targetname[0] && !entity->style)
{
char s[16];
entity->style = LightStyleForTargetname (entity->targetname, true);
sprintf (s,"%i", entity->style);
SetKeyValue (entity, "style", s);
}
}
}
printf ("%d entities read\n", num_entities);
MatchTargets ();
}
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 "";
}
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) )
{
strcpy (ep->value, value);
return;
}
ep = malloc (sizeof(*ep));
ep->next = ent->epairs;
ent->epairs = ep;
strcpy (ep->key, key);
strcpy (ep->value, value);
}
float 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;
k = ValueForKey (ent, key);
sscanf (k, "%lf %lf %lf", &vec[0], &vec[1], &vec[2]);
}
/*
================
WriteEntitiesToString
================
*/
void WriteEntitiesToString (void)
{
char *buf, *end;
epair_t *ep;
char line[128];
int i;
buf = dentdata;
end = buf;
*end = 0;
printf ("%i switchable light styles\n", numlighttargets);
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)
{
sprintf (line, "\"%s\" \"%s\"\n", ep->key, ep->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;
}

33
qutils/LIGHT/ENTITIES.H Normal file
View File

@@ -0,0 +1,33 @@
#define DEFAULTLIGHTLEVEL 300
typedef struct epair_s
{
struct epair_s *next;
char key[MAX_KEY];
char value[MAX_VALUE];
} epair_t;
typedef struct entity_s
{
char classname[64];
vec3_t origin;
float angle;
int light;
int style;
char target[32];
char targetname[32];
struct epair_s *epairs;
struct entity_s *targetent;
} entity_t;
extern entity_t entities[MAX_MAP_ENTITIES];
extern int num_entities;
char *ValueForKey (entity_t *ent, char *key);
void SetKeyValue (entity_t *ent, char *key, char *value);
float FloatForKey (entity_t *ent, char *key);
void GetVectorForKey (entity_t *ent, char *key, vec3_t vec);
void LoadEntities (void);
void WriteEntitiesToString (void);

146
qutils/LIGHT/LIGHT.C Normal file
View File

@@ -0,0 +1,146 @@
// lighting.c
#include "light.h"
/*
NOTES
-----
*/
float scaledist = 1.0;
float scalecos = 0.5;
float rangescale = 0.5;
byte *filebase, *file_p, *file_end;
dmodel_t *bspmodel;
int bspfileface; // next surface to dispatch
vec3_t bsp_origin;
qboolean extrasamples;
float minlights[MAX_MAP_FACES];
byte *GetFileSpace (int size)
{
byte *buf;
LOCK;
file_p = (byte *)(((long)file_p + 3)&~3);
buf = file_p;
file_p += size;
UNLOCK;
if (file_p > file_end)
Error ("GetFileSpace: overrun");
return buf;
}
void LightThread (void *junk)
{
int i;
while (1)
{
LOCK;
i = bspfileface++;
UNLOCK;
if (i >= numfaces)
return;
LightFace (i);
}
}
/*
=============
LightWorld
=============
*/
void LightWorld (void)
{
filebase = file_p = dlightdata;
file_end = filebase + MAX_MAP_LIGHTING;
RunThreadsOn (LightThread);
lightdatasize = file_p - filebase;
printf ("lightdatasize: %i\n", lightdatasize);
}
/*
========
main
light modelfile
========
*/
int main (int argc, char **argv)
{
int i;
double start, end;
char source[1024];
printf ("----- LightFaces ----\n");
for (i=1 ; i<argc ; i++)
{
if (!strcmp(argv[i],"-threads"))
{
numthreads = atoi (argv[i+1]);
i++;
}
else if (!strcmp(argv[i],"-extra"))
{
extrasamples = true;
printf ("extra sampling enabled\n");
}
else if (!strcmp(argv[i],"-dist"))
{
scaledist = atof (argv[i+1]);
i++;
}
else if (!strcmp(argv[i],"-range"))
{
rangescale = atof (argv[i+1]);
i++;
}
else if (argv[i][0] == '-')
Error ("Unknown option \"%s\"", argv[i]);
else
break;
}
if (i != argc - 1)
Error ("usage: light [-threads num] [-extra] bspfile");
InitThreads ();
start = I_FloatTime ();
strcpy (source, argv[i]);
StripExtension (source);
DefaultExtension (source, ".bsp");
LoadBSPFile (source);
LoadEntities ();
MakeTnodes (&dmodels[0]);
LightWorld ();
WriteEntitiesToString ();
WriteBSPFile (source);
end = I_FloatTime ();
printf ("%5.1f seconds elapsed\n", end-start);
return 0;
}

38
qutils/LIGHT/LIGHT.H Normal file
View File

@@ -0,0 +1,38 @@
#include "cmdlib.h"
#include "mathlib.h"
#include "bspfile.h"
#include "entities.h"
#include "threads.h"
#define ON_EPSILON 0.1
#define MAXLIGHTS 1024
void LoadNodes (char *file);
qboolean TestLine (vec3_t start, vec3_t stop);
void LightFace (int surfnum);
void LightLeaf (dleaf_t *leaf);
void MakeTnodes (dmodel_t *bm);
extern float scaledist;
extern float scalecos;
extern float rangescale;
extern int c_culldistplane, c_proper;
byte *GetFileSpace (int size);
extern byte *filebase;
extern vec3_t bsp_origin;
extern vec3_t bsp_xvector;
extern vec3_t bsp_yvector;
void TransformSample (vec3_t in, vec3_t out);
void RotateSample (vec3_t in, vec3_t out);
extern qboolean extrasamples;
extern float minlights[MAX_MAP_FACES];

407
qutils/LIGHT/LIGHT.MAK Normal file
View File

@@ -0,0 +1,407 @@
# Microsoft Developer Studio Generated NMAKE File, Format Version 4.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
!IF "$(CFG)" == ""
CFG=light - Win32 Debug
!MESSAGE No configuration specified. Defaulting to light - Win32 Debug.
!ENDIF
!IF "$(CFG)" != "light - Win32 Release" && "$(CFG)" != "light - Win32 Debug"
!MESSAGE Invalid configuration "$(CFG)" specified.
!MESSAGE You can specify a configuration when running NMAKE on this makefile
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "light.mak" CFG="light - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "light - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "light - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
!ERROR An invalid configuration is specified.
!ENDIF
!IF "$(OS)" == "Windows_NT"
NULL=
!ELSE
NULL=nul
!ENDIF
################################################################################
# Begin Project
# PROP Target_Last_Scanned "light - Win32 Debug"
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "light - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
OUTDIR=.\Release
INTDIR=.\Release
ALL : "$(OUTDIR)\light.exe"
CLEAN :
-@erase ".\Release\light.exe"
-@erase ".\Release\trilib.obj"
-@erase ".\Release\threads.obj"
-@erase ".\Release\mathlib.obj"
-@erase ".\Release\light.obj"
-@erase ".\Release\entities.obj"
-@erase ".\Release\bspfile.obj"
-@erase ".\Release\ltface.obj"
-@erase ".\Release\cmdlib.obj"
-@erase ".\Release\trace.obj"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
# ADD CPP /nologo /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
CPP_PROJ=/nologo /ML /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\
"_CONSOLE" /Fp"$(INTDIR)/light.pch" /YX /Fo"$(INTDIR)/" /c
CPP_OBJS=.\Release/
CPP_SBRS=
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o"$(OUTDIR)/light.bsc"
BSC32_SBRS=
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:console /incremental:no\
/pdb:"$(OUTDIR)/light.pdb" /machine:I386 /out:"$(OUTDIR)/light.exe"
LINK32_OBJS= \
".\Release\trilib.obj" \
".\Release\threads.obj" \
".\Release\mathlib.obj" \
".\Release\light.obj" \
".\Release\entities.obj" \
".\Release\bspfile.obj" \
".\Release\ltface.obj" \
".\Release\cmdlib.obj" \
".\Release\trace.obj"
"$(OUTDIR)\light.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ELSEIF "$(CFG)" == "light - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
OUTDIR=.\Debug
INTDIR=.\Debug
ALL : "$(OUTDIR)\light.exe"
CLEAN :
-@erase ".\Debug\vc40.pdb"
-@erase ".\Debug\vc40.idb"
-@erase ".\Debug\light.exe"
-@erase ".\Debug\threads.obj"
-@erase ".\Debug\trilib.obj"
-@erase ".\Debug\bspfile.obj"
-@erase ".\Debug\light.obj"
-@erase ".\Debug\trace.obj"
-@erase ".\Debug\entities.obj"
-@erase ".\Debug\mathlib.obj"
-@erase ".\Debug\ltface.obj"
-@erase ".\Debug\cmdlib.obj"
-@erase ".\Debug\light.ilk"
-@erase ".\Debug\light.pdb"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
# ADD CPP /nologo /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
CPP_PROJ=/nologo /MLd /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D\
"_CONSOLE" /Fp"$(INTDIR)/light.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
CPP_OBJS=.\Debug/
CPP_SBRS=
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o"$(OUTDIR)/light.bsc"
BSC32_SBRS=
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:console /incremental:yes\
/pdb:"$(OUTDIR)/light.pdb" /debug /machine:I386 /out:"$(OUTDIR)/light.exe"
LINK32_OBJS= \
".\Debug\threads.obj" \
".\Debug\trilib.obj" \
".\Debug\bspfile.obj" \
".\Debug\light.obj" \
".\Debug\trace.obj" \
".\Debug\entities.obj" \
".\Debug\mathlib.obj" \
".\Debug\ltface.obj" \
".\Debug\cmdlib.obj"
"$(OUTDIR)\light.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ENDIF
.c{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.c{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
################################################################################
# Begin Target
# Name "light - Win32 Release"
# Name "light - Win32 Debug"
!IF "$(CFG)" == "light - Win32 Release"
!ELSEIF "$(CFG)" == "light - Win32 Debug"
!ENDIF
################################################################################
# Begin Source File
SOURCE=.\trace.c
!IF "$(CFG)" == "light - Win32 Release"
DEP_CPP_TRACE=\
".\light.h"\
"$(INTDIR)\trace.obj" : $(SOURCE) $(DEP_CPP_TRACE) "$(INTDIR)"
!ELSEIF "$(CFG)" == "light - Win32 Debug"
DEP_CPP_TRACE=\
".\light.h"\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
".\..\common\bspfile.h"\
".\entities.h"\
".\threads.h"\
"$(INTDIR)\trace.obj" : $(SOURCE) $(DEP_CPP_TRACE) "$(INTDIR)"
!ENDIF
# End Source File
################################################################################
# Begin Source File
SOURCE=.\threads.c
DEP_CPP_THREA=\
".\..\common\cmdlib.h"\
".\threads.h"\
"$(INTDIR)\threads.obj" : $(SOURCE) $(DEP_CPP_THREA) "$(INTDIR)"
# End Source File
################################################################################
# Begin Source File
SOURCE=.\ltface.c
!IF "$(CFG)" == "light - Win32 Release"
DEP_CPP_LTFAC=\
".\light.h"\
"$(INTDIR)\ltface.obj" : $(SOURCE) $(DEP_CPP_LTFAC) "$(INTDIR)"
!ELSEIF "$(CFG)" == "light - Win32 Debug"
DEP_CPP_LTFAC=\
".\light.h"\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
".\..\common\bspfile.h"\
".\entities.h"\
".\threads.h"\
"$(INTDIR)\ltface.obj" : $(SOURCE) $(DEP_CPP_LTFAC) "$(INTDIR)"
!ENDIF
# End Source File
################################################################################
# Begin Source File
SOURCE=.\light.c
!IF "$(CFG)" == "light - Win32 Release"
DEP_CPP_LIGHT=\
".\light.h"\
"$(INTDIR)\light.obj" : $(SOURCE) $(DEP_CPP_LIGHT) "$(INTDIR)"
!ELSEIF "$(CFG)" == "light - Win32 Debug"
DEP_CPP_LIGHT=\
".\light.h"\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
".\..\common\bspfile.h"\
".\entities.h"\
".\threads.h"\
"$(INTDIR)\light.obj" : $(SOURCE) $(DEP_CPP_LIGHT) "$(INTDIR)"
!ENDIF
# End Source File
################################################################################
# Begin Source File
SOURCE=.\entities.c
!IF "$(CFG)" == "light - Win32 Release"
DEP_CPP_ENTIT=\
".\light.h"\
"$(INTDIR)\entities.obj" : $(SOURCE) $(DEP_CPP_ENTIT) "$(INTDIR)"
!ELSEIF "$(CFG)" == "light - Win32 Debug"
DEP_CPP_ENTIT=\
".\light.h"\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
".\..\common\bspfile.h"\
".\entities.h"\
".\threads.h"\
"$(INTDIR)\entities.obj" : $(SOURCE) $(DEP_CPP_ENTIT) "$(INTDIR)"
!ENDIF
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\trilib.c
DEP_CPP_TRILI=\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
".\..\common\trilib.h"\
"$(INTDIR)\trilib.obj" : $(SOURCE) $(DEP_CPP_TRILI) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\mathlib.c
DEP_CPP_MATHL=\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
"$(INTDIR)\mathlib.obj" : $(SOURCE) $(DEP_CPP_MATHL) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\cmdlib.c
DEP_CPP_CMDLI=\
".\..\common\cmdlib.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
{$(INCLUDE)}"\sys\STAT.H"\
"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\bspfile.c
DEP_CPP_BSPFI=\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
".\..\common\bspfile.h"\
"$(INTDIR)\bspfile.obj" : $(SOURCE) $(DEP_CPP_BSPFI) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
# End Target
# End Project
################################################################################

BIN
qutils/LIGHT/LIGHT.MDP Normal file

Binary file not shown.

BIN
qutils/LIGHT/LIGHT.NCB Normal file

Binary file not shown.

588
qutils/LIGHT/LTFACE.C Normal file
View File

@@ -0,0 +1,588 @@
#include "light.h"
/*
============
CastRay
Returns the distance between the points, or -1 if blocked
=============
*/
vec_t CastRay (vec3_t p1, vec3_t p2)
{
int i;
vec_t t;
qboolean trace;
trace = TestLine (p1, p2);
if (!trace)
return -1; // ray was blocked
t = 0;
for (i=0 ; i< 3 ; i++)
t += (p2[i]-p1[i]) * (p2[i]-p1[i]);
if (t == 0)
t = 1; // don't blow up...
return sqrt(t);
}
/*
===============================================================================
SAMPLE POINT DETERMINATION
void SetupBlock (dface_t *f) Returns with surfpt[] set
This is a little tricky because the lightmap covers more area than the face.
If done in the straightforward fashion, some of the
sample points will be inside walls or on the other side of walls, causing
false shadows and light bleeds.
To solve this, I only consider a sample point valid if a line can be drawn
between it and the exact midpoint of the face. If invalid, it is adjusted
towards the center until it is valid.
(this doesn't completely work)
===============================================================================
*/
#define SINGLEMAP (18*18*4)
typedef struct
{
vec_t lightmaps[MAXLIGHTMAPS][SINGLEMAP];
int numlightstyles;
vec_t *light;
vec_t facedist;
vec3_t facenormal;
int numsurfpt;
vec3_t surfpt[SINGLEMAP];
vec3_t texorg;
vec3_t worldtotex[2]; // s = (world - texorg) . worldtotex[0]
vec3_t textoworld[2]; // world = texorg + s * textoworld[0]
vec_t exactmins[2], exactmaxs[2];
int texmins[2], texsize[2];
int lightstyles[256];
int surfnum;
dface_t *face;
} lightinfo_t;
/*
================
CalcFaceVectors
Fills in texorg, worldtotex. and textoworld
================
*/
void CalcFaceVectors (lightinfo_t *l)
{
texinfo_t *tex;
int i, j;
vec3_t texnormal;
float distscale;
vec_t dist, len;
tex = &texinfo[l->face->texinfo];
// convert from float to vec_t
for (i=0 ; i<2 ; i++)
for (j=0 ; j<3 ; j++)
l->worldtotex[i][j] = tex->vecs[i][j];
// calculate a normal to the texture axis. points can be moved along this
// without changing their S/T
texnormal[0] = tex->vecs[1][1]*tex->vecs[0][2]
- tex->vecs[1][2]*tex->vecs[0][1];
texnormal[1] = tex->vecs[1][2]*tex->vecs[0][0]
- tex->vecs[1][0]*tex->vecs[0][2];
texnormal[2] = tex->vecs[1][0]*tex->vecs[0][1]
- tex->vecs[1][1]*tex->vecs[0][0];
VectorNormalize (texnormal);
// flip it towards plane normal
distscale = DotProduct (texnormal, l->facenormal);
if (!distscale)
Error ("Texture axis perpendicular to face");
if (distscale < 0)
{
distscale = -distscale;
VectorSubtract (vec3_origin, texnormal, texnormal);
}
// distscale is the ratio of the distance along the texture normal to
// the distance along the plane normal
distscale = 1/distscale;
for (i=0 ; i<2 ; i++)
{
len = VectorLength (l->worldtotex[i]);
dist = DotProduct (l->worldtotex[i], l->facenormal);
dist *= distscale;
VectorMA (l->worldtotex[i], -dist, texnormal, l->textoworld[i]);
VectorScale (l->textoworld[i], (1/len)*(1/len), l->textoworld[i]);
}
// calculate texorg on the texture plane
for (i=0 ; i<3 ; i++)
l->texorg[i] = -tex->vecs[0][3]* l->textoworld[0][i] - tex->vecs[1][3] * l->textoworld[1][i];
// project back to the face plane
dist = DotProduct (l->texorg, l->facenormal) - l->facedist - 1;
dist *= distscale;
VectorMA (l->texorg, -dist, texnormal, l->texorg);
}
/*
================
CalcFaceExtents
Fills in s->texmins[] and s->texsize[]
also sets exactmins[] and exactmaxs[]
================
*/
void CalcFaceExtents (lightinfo_t *l)
{
dface_t *s;
vec_t mins[2], maxs[2], val;
int i,j, e;
dvertex_t *v;
texinfo_t *tex;
s = l->face;
mins[0] = mins[1] = 999999;
maxs[0] = maxs[1] = -99999;
tex = &texinfo[s->texinfo];
for (i=0 ; i<s->numedges ; i++)
{
e = dsurfedges[s->firstedge+i];
if (e >= 0)
v = dvertexes + dedges[e].v[0];
else
v = dvertexes + dedges[-e].v[1];
for (j=0 ; j<2 ; j++)
{
val = v->point[0] * tex->vecs[j][0] +
v->point[1] * tex->vecs[j][1] +
v->point[2] * tex->vecs[j][2] +
tex->vecs[j][3];
if (val < mins[j])
mins[j] = val;
if (val > maxs[j])
maxs[j] = val;
}
}
for (i=0 ; i<2 ; i++)
{
l->exactmins[i] = mins[i];
l->exactmaxs[i] = maxs[i];
mins[i] = floor(mins[i]/16);
maxs[i] = ceil(maxs[i]/16);
l->texmins[i] = mins[i];
l->texsize[i] = maxs[i] - mins[i];
if (l->texsize[i] > 17)
Error ("Bad surface extents");
}
}
/*
=================
CalcPoints
For each texture aligned grid point, back project onto the plane
to get the world xyz value of the sample point
=================
*/
int c_bad;
void CalcPoints (lightinfo_t *l)
{
int i;
int s, t, j;
int w, h, step;
vec_t starts, startt, us, ut;
vec_t *surf;
vec_t mids, midt;
vec3_t facemid, move;
//
// fill in surforg
// the points are biased towards the center of the surface
// to help avoid edge cases just inside walls
//
surf = l->surfpt[0];
mids = (l->exactmaxs[0] + l->exactmins[0])/2;
midt = (l->exactmaxs[1] + l->exactmins[1])/2;
for (j=0 ; j<3 ; j++)
facemid[j] = l->texorg[j] + l->textoworld[0][j]*mids + l->textoworld[1][j]*midt;
if (extrasamples)
{ // extra filtering
h = (l->texsize[1]+1)*2;
w = (l->texsize[0]+1)*2;
starts = (l->texmins[0]-0.5)*16;
startt = (l->texmins[1]-0.5)*16;
step = 8;
}
else
{
h = l->texsize[1]+1;
w = l->texsize[0]+1;
starts = l->texmins[0]*16;
startt = l->texmins[1]*16;
step = 16;
}
l->numsurfpt = w * h;
for (t=0 ; t<h ; t++)
{
for (s=0 ; s<w ; s++, surf+=3)
{
us = starts + s*step;
ut = startt + t*step;
// if a line can be traced from surf to facemid, the point is good
for (i=0 ; i<6 ; i++)
{
// calculate texture point
for (j=0 ; j<3 ; j++)
surf[j] = l->texorg[j] + l->textoworld[0][j]*us
+ l->textoworld[1][j]*ut;
if (CastRay (facemid, surf) != -1)
break; // got it
if (i & 1)
{
if (us > mids)
{
us -= 8;
if (us < mids)
us = mids;
}
else
{
us += 8;
if (us > mids)
us = mids;
}
}
else
{
if (ut > midt)
{
ut -= 8;
if (ut < midt)
ut = midt;
}
else
{
ut += 8;
if (ut > midt)
ut = midt;
}
}
// move surf 8 pixels towards the center
VectorSubtract (facemid, surf, move);
VectorNormalize (move);
VectorMA (surf, 8, move, surf);
}
if (i == 2)
c_bad++;
}
}
}
/*
===============================================================================
FACE LIGHTING
===============================================================================
*/
int c_culldistplane, c_proper;
/*
================
SingleLightFace
================
*/
void SingleLightFace (entity_t *light, lightinfo_t *l)
{
vec_t dist;
vec3_t incoming;
vec_t angle;
vec_t add;
vec_t *surf;
qboolean hit;
int mapnum;
int size;
int c, i;
vec3_t rel;
vec3_t spotvec;
vec_t falloff;
vec_t *lightsamp;
VectorSubtract (light->origin, bsp_origin, rel);
dist = scaledist * (DotProduct (rel, l->facenormal) - l->facedist);
// don't bother with lights behind the surface
if (dist <= 0)
return;
// don't bother with light too far away
if (dist > light->light)
{
c_culldistplane++;
return;
}
if (light->targetent)
{
VectorSubtract (light->targetent->origin, light->origin, spotvec);
VectorNormalize (spotvec);
if (!light->angle)
falloff = -cos(20*Q_PI/180);
else
falloff = -cos(light->angle/2*Q_PI/180);
}
else
falloff = 0; // shut up compiler warnings
mapnum = 0;
for (mapnum=0 ; mapnum<l->numlightstyles ; mapnum++)
if (l->lightstyles[mapnum] == light->style)
break;
lightsamp = l->lightmaps[mapnum];
if (mapnum == l->numlightstyles)
{ // init a new light map
if (mapnum == MAXLIGHTMAPS)
{
printf ("WARNING: Too many light styles on a face\n");
return;
}
size = (l->texsize[1]+1)*(l->texsize[0]+1);
for (i=0 ; i<size ; i++)
lightsamp[i] = 0;
}
//
// check it for real
//
hit = false;
c_proper++;
surf = l->surfpt[0];
for (c=0 ; c<l->numsurfpt ; c++, surf+=3)
{
dist = CastRay(light->origin, surf)*scaledist;
if (dist < 0)
continue; // light doesn't reach
VectorSubtract (light->origin, surf, incoming);
VectorNormalize (incoming);
angle = DotProduct (incoming, l->facenormal);
if (light->targetent)
{ // spotlight cutoff
if (DotProduct (spotvec, incoming) > falloff)
continue;
}
angle = (1.0-scalecos) + scalecos*angle;
add = light->light - dist;
add *= angle;
if (add < 0)
continue;
lightsamp[c] += add;
if (lightsamp[c] > 1) // ignore real tiny lights
hit = true;
}
if (mapnum == l->numlightstyles && hit)
{
l->lightstyles[mapnum] = light->style;
l->numlightstyles++; // the style has some real data now
}
}
/*
============
FixMinlight
============
*/
void FixMinlight (lightinfo_t *l)
{
int i, j;
float minlight;
minlight = minlights[l->surfnum];
// if minlight is set, there must be a style 0 light map
if (!minlight)
return;
for (i=0 ; i< l->numlightstyles ; i++)
{
if (l->lightstyles[i] == 0)
break;
}
if (i == l->numlightstyles)
{
if (l->numlightstyles == MAXLIGHTMAPS)
return; // oh well..
for (j=0 ; j<l->numsurfpt ; j++)
l->lightmaps[i][j] = minlight;
l->lightstyles[i] = 0;
l->numlightstyles++;
}
else
{
for (j=0 ; j<l->numsurfpt ; j++)
if ( l->lightmaps[i][j] < minlight)
l->lightmaps[i][j] = minlight;
}
}
/*
============
LightFace
============
*/
void LightFace (int surfnum)
{
dface_t *f;
lightinfo_t l;
int s, t;
int i,j,c;
vec_t total;
int size;
int lightmapwidth, lightmapsize;
byte *out;
vec_t *light;
int w, h;
f = dfaces + surfnum;
//
// some surfaces don't need lightmaps
//
f->lightofs = -1;
for (j=0 ; j<MAXLIGHTMAPS ; j++)
f->styles[j] = 255;
if ( texinfo[f->texinfo].flags & TEX_SPECIAL)
{ // non-lit texture
return;
}
memset (&l, 0, sizeof(l));
l.surfnum = surfnum;
l.face = f;
//
// rotate plane
//
VectorCopy (dplanes[f->planenum].normal, l.facenormal);
l.facedist = dplanes[f->planenum].dist;
if (f->side)
{
VectorSubtract (vec3_origin, l.facenormal, l.facenormal);
l.facedist = -l.facedist;
}
CalcFaceVectors (&l);
CalcFaceExtents (&l);
CalcPoints (&l);
lightmapwidth = l.texsize[0]+1;
size = lightmapwidth*(l.texsize[1]+1);
if (size > SINGLEMAP)
Error ("Bad lightmap size");
for (i=0 ; i<MAXLIGHTMAPS ; i++)
l.lightstyles[i] = 255;
//
// cast all lights
//
l.numlightstyles = 0;
for (i=0 ; i<num_entities ; i++)
{
if (entities[i].light)
SingleLightFace (&entities[i], &l);
}
FixMinlight (&l);
if (!l.numlightstyles)
{ // no light hitting it
return;
}
//
// save out the values
//
for (i=0 ; i <MAXLIGHTMAPS ; i++)
f->styles[i] = l.lightstyles[i];
lightmapsize = size*l.numlightstyles;
out = GetFileSpace (lightmapsize);
f->lightofs = out - filebase;
// extra filtering
h = (l.texsize[1]+1)*2;
w = (l.texsize[0]+1)*2;
for (i=0 ; i< l.numlightstyles ; i++)
{
if (l.lightstyles[i] == 0xff)
Error ("Wrote empty lightmap");
light = l.lightmaps[i];
c = 0;
for (t=0 ; t<=l.texsize[1] ; t++)
for (s=0 ; s<=l.texsize[0] ; s++, c++)
{
if (extrasamples)
{ // filtered sample
total = light[t*2*w+s*2] + light[t*2*w+s*2+1]
+ light[(t*2+1)*w+s*2] + light[(t*2+1)*w+s*2+1];
total *= 0.25;
}
else
total = light[c];
total *= rangescale; // scale before clamping
if (total > 255)
total = 255;
if (total < 0)
Error ("light < 0");
*out++ = total;
}
}
}

66
qutils/LIGHT/THREADS.C Normal file
View File

@@ -0,0 +1,66 @@
#include "cmdlib.h"
#include "threads.h"
#ifdef __alpha
int numthreads = 4;
pthread_mutex_t *my_mutex;
#else
int numthreads = 1;
#endif
void InitThreads (void)
{
#ifdef __alpha
pthread_mutexattr_t mattrib;
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");
#endif
}
/*
===============
RunThreadsOn
===============
*/
void RunThreadsOn ( threadfunc_t func )
{
#ifdef __alpha
pthread_t work_threads[256];
pthread_addr_t status;
pthread_attr_t attrib;
int i;
if (numthreads == 1)
{
func (NULL);
return;
}
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");
}
#else
func (NULL);
#endif
}

17
qutils/LIGHT/THREADS.H Normal file
View File

@@ -0,0 +1,17 @@
#ifdef __alpha
#include <pthread.h>
extern pthread_mutex_t *my_mutex;
#define LOCK pthread_mutex_lock (my_mutex)
#define UNLOCK pthread_mutex_unlock (my_mutex)
#else
#define LOCK
#define UNLOCK
#endif
extern int numthreads;
typedef void (threadfunc_t) (void *);
void InitThreads (void);
void RunThreadsOn ( threadfunc_t func );

197
qutils/LIGHT/TRACE.C Normal file
View File

@@ -0,0 +1,197 @@
// trace.c
#include "light.h"
typedef struct tnode_s
{
int type;
vec3_t normal;
float dist;
int children[2];
int pad;
} tnode_t;
tnode_t *tnodes, *tnode_p;
/*
==============
MakeTnode
Converts the disk node structure into the efficient tracing structure
==============
*/
void MakeTnode (int nodenum)
{
tnode_t *t;
dplane_t *plane;
int i;
dnode_t *node;
t = tnode_p++;
node = dnodes + nodenum;
plane = dplanes + node->planenum;
t->type = plane->type;
VectorCopy (plane->normal, t->normal);
t->dist = plane->dist;
for (i=0 ; i<2 ; i++)
{
if (node->children[i] < 0)
t->children[i] = dleafs[-node->children[i] - 1].contents;
else
{
t->children[i] = tnode_p - tnodes;
MakeTnode (node->children[i]);
}
}
}
/*
=============
MakeTnodes
Loads the node structure out of a .bsp file to be used for light occlusion
=============
*/
void MakeTnodes (dmodel_t *bm)
{
tnode_p = tnodes = malloc(numnodes * sizeof(tnode_t));
MakeTnode (0);
}
/*
==============================================================================
LINE TRACING
The major lighting operation is a point to point visibility test, performed
by recursive subdivision of the line by the BSP tree.
==============================================================================
*/
typedef struct
{
vec3_t backpt;
int side;
int node;
} tracestack_t;
/*
==============
TestLine
==============
*/
qboolean TestLine (vec3_t start, vec3_t stop)
{
int node;
float front, back;
tracestack_t *tstack_p;
int side;
float frontx,fronty, frontz, backx, backy, backz;
tracestack_t tracestack[64];
tnode_t *tnode;
frontx = start[0];
fronty = start[1];
frontz = start[2];
backx = stop[0];
backy = stop[1];
backz = stop[2];
tstack_p = tracestack;
node = 0;
while (1)
{
while (node < 0 && node != CONTENTS_SOLID)
{
// pop up the stack for a back side
tstack_p--;
if (tstack_p < tracestack)
return true;
node = tstack_p->node;
// set the hit point for this plane
frontx = backx;
fronty = backy;
frontz = backz;
// go down the back side
backx = tstack_p->backpt[0];
backy = tstack_p->backpt[1];
backz = tstack_p->backpt[2];
node = tnodes[tstack_p->node].children[!tstack_p->side];
}
if (node == CONTENTS_SOLID)
return false; // DONE!
tnode = &tnodes[node];
switch (tnode->type)
{
case PLANE_X:
front = frontx - tnode->dist;
back = backx - tnode->dist;
break;
case PLANE_Y:
front = fronty - tnode->dist;
back = backy - tnode->dist;
break;
case PLANE_Z:
front = frontz - tnode->dist;
back = backz - tnode->dist;
break;
default:
front = (frontx*tnode->normal[0] + fronty*tnode->normal[1] + frontz*tnode->normal[2]) - tnode->dist;
back = (backx*tnode->normal[0] + backy*tnode->normal[1] + backz*tnode->normal[2]) - tnode->dist;
break;
}
if (front > -ON_EPSILON && back > -ON_EPSILON)
// if (front > 0 && back > 0)
{
node = tnode->children[0];
continue;
}
if (front < ON_EPSILON && back < ON_EPSILON)
// if (front <= 0 && back <= 0)
{
node = tnode->children[1];
continue;
}
side = front < 0;
front = front / (front-back);
tstack_p->node = node;
tstack_p->side = side;
tstack_p->backpt[0] = backx;
tstack_p->backpt[1] = backy;
tstack_p->backpt[2] = backz;
tstack_p++;
backx = frontx + front*(backx-frontx);
backy = fronty + front*(backy-fronty);
backz = frontz + front*(backz-frontz);
node = tnode->children[side];
}
}

162
qutils/MODELGEN/ANORMS.H Normal file
View File

@@ -0,0 +1,162 @@
{-0.525731, 0.000000, 0.850651},
{-0.442863, 0.238856, 0.864188},
{-0.295242, 0.000000, 0.955423},
{-0.309017, 0.500000, 0.809017},
{-0.162460, 0.262866, 0.951056},
{0.000000, 0.000000, 1.000000},
{0.000000, 0.850651, 0.525731},
{-0.147621, 0.716567, 0.681718},
{0.147621, 0.716567, 0.681718},
{0.000000, 0.525731, 0.850651},
{0.309017, 0.500000, 0.809017},
{0.525731, 0.000000, 0.850651},
{0.295242, 0.000000, 0.955423},
{0.442863, 0.238856, 0.864188},
{0.162460, 0.262866, 0.951056},
{-0.681718, 0.147621, 0.716567},
{-0.809017, 0.309017, 0.500000},
{-0.587785, 0.425325, 0.688191},
{-0.850651, 0.525731, 0.000000},
{-0.864188, 0.442863, 0.238856},
{-0.716567, 0.681718, 0.147621},
{-0.688191, 0.587785, 0.425325},
{-0.500000, 0.809017, 0.309017},
{-0.238856, 0.864188, 0.442863},
{-0.425325, 0.688191, 0.587785},
{-0.716567, 0.681718, -0.147621},
{-0.500000, 0.809017, -0.309017},
{-0.525731, 0.850651, 0.000000},
{0.000000, 0.850651, -0.525731},
{-0.238856, 0.864188, -0.442863},
{0.000000, 0.955423, -0.295242},
{-0.262866, 0.951056, -0.162460},
{0.000000, 1.000000, 0.000000},
{0.000000, 0.955423, 0.295242},
{-0.262866, 0.951056, 0.162460},
{0.238856, 0.864188, 0.442863},
{0.262866, 0.951056, 0.162460},
{0.500000, 0.809017, 0.309017},
{0.238856, 0.864188, -0.442863},
{0.262866, 0.951056, -0.162460},
{0.500000, 0.809017, -0.309017},
{0.850651, 0.525731, 0.000000},
{0.716567, 0.681718, 0.147621},
{0.716567, 0.681718, -0.147621},
{0.525731, 0.850651, 0.000000},
{0.425325, 0.688191, 0.587785},
{0.864188, 0.442863, 0.238856},
{0.688191, 0.587785, 0.425325},
{0.809017, 0.309017, 0.500000},
{0.681718, 0.147621, 0.716567},
{0.587785, 0.425325, 0.688191},
{0.955423, 0.295242, 0.000000},
{1.000000, 0.000000, 0.000000},
{0.951056, 0.162460, 0.262866},
{0.850651, -0.525731, 0.000000},
{0.955423, -0.295242, 0.000000},
{0.864188, -0.442863, 0.238856},
{0.951056, -0.162460, 0.262866},
{0.809017, -0.309017, 0.500000},
{0.681718, -0.147621, 0.716567},
{0.850651, 0.000000, 0.525731},
{0.864188, 0.442863, -0.238856},
{0.809017, 0.309017, -0.500000},
{0.951056, 0.162460, -0.262866},
{0.525731, 0.000000, -0.850651},
{0.681718, 0.147621, -0.716567},
{0.681718, -0.147621, -0.716567},
{0.850651, 0.000000, -0.525731},
{0.809017, -0.309017, -0.500000},
{0.864188, -0.442863, -0.238856},
{0.951056, -0.162460, -0.262866},
{0.147621, 0.716567, -0.681718},
{0.309017, 0.500000, -0.809017},
{0.425325, 0.688191, -0.587785},
{0.442863, 0.238856, -0.864188},
{0.587785, 0.425325, -0.688191},
{0.688191, 0.587785, -0.425325},
{-0.147621, 0.716567, -0.681718},
{-0.309017, 0.500000, -0.809017},
{0.000000, 0.525731, -0.850651},
{-0.525731, 0.000000, -0.850651},
{-0.442863, 0.238856, -0.864188},
{-0.295242, 0.000000, -0.955423},
{-0.162460, 0.262866, -0.951056},
{0.000000, 0.000000, -1.000000},
{0.295242, 0.000000, -0.955423},
{0.162460, 0.262866, -0.951056},
{-0.442863, -0.238856, -0.864188},
{-0.309017, -0.500000, -0.809017},
{-0.162460, -0.262866, -0.951056},
{0.000000, -0.850651, -0.525731},
{-0.147621, -0.716567, -0.681718},
{0.147621, -0.716567, -0.681718},
{0.000000, -0.525731, -0.850651},
{0.309017, -0.500000, -0.809017},
{0.442863, -0.238856, -0.864188},
{0.162460, -0.262866, -0.951056},
{0.238856, -0.864188, -0.442863},
{0.500000, -0.809017, -0.309017},
{0.425325, -0.688191, -0.587785},
{0.716567, -0.681718, -0.147621},
{0.688191, -0.587785, -0.425325},
{0.587785, -0.425325, -0.688191},
{0.000000, -0.955423, -0.295242},
{0.000000, -1.000000, 0.000000},
{0.262866, -0.951056, -0.162460},
{0.000000, -0.850651, 0.525731},
{0.000000, -0.955423, 0.295242},
{0.238856, -0.864188, 0.442863},
{0.262866, -0.951056, 0.162460},
{0.500000, -0.809017, 0.309017},
{0.716567, -0.681718, 0.147621},
{0.525731, -0.850651, 0.000000},
{-0.238856, -0.864188, -0.442863},
{-0.500000, -0.809017, -0.309017},
{-0.262866, -0.951056, -0.162460},
{-0.850651, -0.525731, 0.000000},
{-0.716567, -0.681718, -0.147621},
{-0.716567, -0.681718, 0.147621},
{-0.525731, -0.850651, 0.000000},
{-0.500000, -0.809017, 0.309017},
{-0.238856, -0.864188, 0.442863},
{-0.262866, -0.951056, 0.162460},
{-0.864188, -0.442863, 0.238856},
{-0.809017, -0.309017, 0.500000},
{-0.688191, -0.587785, 0.425325},
{-0.681718, -0.147621, 0.716567},
{-0.442863, -0.238856, 0.864188},
{-0.587785, -0.425325, 0.688191},
{-0.309017, -0.500000, 0.809017},
{-0.147621, -0.716567, 0.681718},
{-0.425325, -0.688191, 0.587785},
{-0.162460, -0.262866, 0.951056},
{0.442863, -0.238856, 0.864188},
{0.162460, -0.262866, 0.951056},
{0.309017, -0.500000, 0.809017},
{0.147621, -0.716567, 0.681718},
{0.000000, -0.525731, 0.850651},
{0.425325, -0.688191, 0.587785},
{0.587785, -0.425325, 0.688191},
{0.688191, -0.587785, 0.425325},
{-0.955423, 0.295242, 0.000000},
{-0.951056, 0.162460, 0.262866},
{-1.000000, 0.000000, 0.000000},
{-0.850651, 0.000000, 0.525731},
{-0.955423, -0.295242, 0.000000},
{-0.951056, -0.162460, 0.262866},
{-0.864188, 0.442863, -0.238856},
{-0.951056, 0.162460, -0.262866},
{-0.809017, 0.309017, -0.500000},
{-0.864188, -0.442863, -0.238856},
{-0.951056, -0.162460, -0.262866},
{-0.809017, -0.309017, -0.500000},
{-0.681718, 0.147621, -0.716567},
{-0.681718, -0.147621, -0.716567},
{-0.850651, 0.000000, -0.525731},
{-0.688191, 0.587785, -0.425325},
{-0.587785, 0.425325, -0.688191},
{-0.425325, 0.688191, -0.587785},
{-0.425325, -0.688191, -0.587785},
{-0.587785, -0.425325, -0.688191},
{-0.688191, -0.587785, -0.425325},

1212
qutils/MODELGEN/MODELGEN.C Normal file

File diff suppressed because it is too large Load Diff

113
qutils/MODELGEN/MODELGEN.H Normal file
View File

@@ -0,0 +1,113 @@
//
// modelgen.h: header file for model generation program
//
// *********************************************************
// * This file must be identical in the modelgen directory *
// * and in the Quake directory, because it's used to *
// * pass data from one to the other via model files. *
// *********************************************************
#ifdef INCLUDELIBS
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "cmdlib.h"
#include "scriplib.h"
#include "mathlib.h"
#include "trilib.h"
#include "lbmlib.h"
#endif
#define ALIAS_VERSION 6
#define ALIAS_ONSEAM 0x0020
// must match definition in spritegn.h
#ifndef SYNCTYPE_T
#define SYNCTYPE_T
typedef enum {ST_SYNC=0, ST_RAND } synctype_t;
#endif
typedef enum { ALIAS_SINGLE=0, ALIAS_GROUP } aliasframetype_t;
typedef enum { ALIAS_SKIN_SINGLE=0, ALIAS_SKIN_GROUP } aliasskintype_t;
typedef struct {
int ident;
int version;
vec3_t scale;
vec3_t scale_origin;
float boundingradius;
vec3_t eyeposition;
int numskins;
int skinwidth;
int skinheight;
int numverts;
int numtris;
int numframes;
synctype_t synctype;
int flags;
float size;
} mdl_t;
// TODO: could be shorts
typedef struct {
int onseam;
int s;
int t;
} stvert_t;
typedef struct dtriangle_s {
int facesfront;
int vertindex[3];
} dtriangle_t;
#define DT_FACES_FRONT 0x0010
typedef struct {
byte v[3];
byte lightnormalindex;
} trivertx_t;
typedef struct {
trivertx_t bboxmin; // lightnormal isn't used
trivertx_t bboxmax; // lightnormal isn't used
char name[16]; // frame name from grabbing
} daliasframe_t;
typedef struct {
int numframes;
trivertx_t bboxmin; // lightnormal isn't used
trivertx_t bboxmax; // lightnormal isn't used
} daliasgroup_t;
typedef struct {
int numskins;
} daliasskingroup_t;
typedef struct {
float interval;
} daliasinterval_t;
typedef struct {
float interval;
} daliasskininterval_t;
typedef struct {
aliasframetype_t type;
} daliasframetype_t;
typedef struct {
aliasskintype_t type;
} daliasskintype_t;
#define IDPOLYHEADER (('O'<<24)+('P'<<16)+('D'<<8)+'I')
// little-endian "IDPO"

View File

@@ -0,0 +1,294 @@
# Microsoft Developer Studio Generated NMAKE File, Format Version 4.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
!IF "$(CFG)" == ""
CFG=modelgen - Win32 Debug
!MESSAGE No configuration specified. Defaulting to modelgen - Win32 Debug.
!ENDIF
!IF "$(CFG)" != "modelgen - Win32 Release" && "$(CFG)" !=\
"modelgen - Win32 Debug"
!MESSAGE Invalid configuration "$(CFG)" specified.
!MESSAGE You can specify a configuration when running NMAKE on this makefile
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "modelgen.mak" CFG="modelgen - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "modelgen - Win32 Release" (based on\
"Win32 (x86) Console Application")
!MESSAGE "modelgen - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
!ERROR An invalid configuration is specified.
!ENDIF
!IF "$(OS)" == "Windows_NT"
NULL=
!ELSE
NULL=nul
!ENDIF
################################################################################
# Begin Project
# PROP Target_Last_Scanned "modelgen - Win32 Debug"
RSC=rc.exe
CPP=cl.exe
!IF "$(CFG)" == "modelgen - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
OUTDIR=.\Release
INTDIR=.\Release
ALL : "$(OUTDIR)\modelgen.exe"
CLEAN :
-@erase ".\Release\modelgen.exe"
-@erase ".\Release\mathlib.obj"
-@erase ".\Release\cmdlib.obj"
-@erase ".\Release\lbmlib.obj"
-@erase ".\Release\trilib.obj"
-@erase ".\Release\scriplib.obj"
-@erase ".\Release\modelgen.obj"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
# ADD CPP /nologo /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
CPP_PROJ=/nologo /ML /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\
"_CONSOLE" /Fp"$(INTDIR)/modelgen.pch" /YX /Fo"$(INTDIR)/" /c
CPP_OBJS=.\Release/
CPP_SBRS=
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o"$(OUTDIR)/modelgen.bsc"
BSC32_SBRS=
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:console /incremental:no\
/pdb:"$(OUTDIR)/modelgen.pdb" /machine:I386 /out:"$(OUTDIR)/modelgen.exe"
LINK32_OBJS= \
"$(INTDIR)/mathlib.obj" \
"$(INTDIR)/cmdlib.obj" \
"$(INTDIR)/lbmlib.obj" \
"$(INTDIR)/trilib.obj" \
"$(INTDIR)/scriplib.obj" \
"$(INTDIR)/modelgen.obj"
"$(OUTDIR)\modelgen.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ELSEIF "$(CFG)" == "modelgen - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
OUTDIR=.\Debug
INTDIR=.\Debug
ALL : "$(OUTDIR)\modelgen.exe"
CLEAN :
-@erase ".\Debug\vc40.pdb"
-@erase ".\Debug\vc40.idb"
-@erase ".\Debug\modelgen.exe"
-@erase ".\Debug\trilib.obj"
-@erase ".\Debug\mathlib.obj"
-@erase ".\Debug\lbmlib.obj"
-@erase ".\Debug\modelgen.obj"
-@erase ".\Debug\scriplib.obj"
-@erase ".\Debug\cmdlib.obj"
-@erase ".\Debug\modelgen.ilk"
-@erase ".\Debug\modelgen.pdb"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
# ADD CPP /nologo /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
CPP_PROJ=/nologo /MLd /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D\
"_CONSOLE" /Fp"$(INTDIR)/modelgen.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
CPP_OBJS=.\Debug/
CPP_SBRS=
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o"$(OUTDIR)/modelgen.bsc"
BSC32_SBRS=
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:console /incremental:yes\
/pdb:"$(OUTDIR)/modelgen.pdb" /debug /machine:I386\
/out:"$(OUTDIR)/modelgen.exe"
LINK32_OBJS= \
"$(INTDIR)/trilib.obj" \
"$(INTDIR)/mathlib.obj" \
"$(INTDIR)/lbmlib.obj" \
"$(INTDIR)/modelgen.obj" \
"$(INTDIR)/scriplib.obj" \
"$(INTDIR)/cmdlib.obj"
"$(OUTDIR)\modelgen.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ENDIF
.c{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.c{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
################################################################################
# Begin Target
# Name "modelgen - Win32 Release"
# Name "modelgen - Win32 Debug"
!IF "$(CFG)" == "modelgen - Win32 Release"
!ELSEIF "$(CFG)" == "modelgen - Win32 Debug"
!ENDIF
################################################################################
# Begin Source File
SOURCE=.\modelgen.c
DEP_CPP_MODEL=\
{$(INCLUDE)}"\sys\STAT.H"\
".\modelgen.h"\
".\anorms.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
".\..\common\cmdlib.h"\
".\..\common\scriplib.h"\
".\..\common\mathlib.h"\
".\..\common\trilib.h"\
".\..\common\lbmlib.h"\
"$(INTDIR)\modelgen.obj" : $(SOURCE) $(DEP_CPP_MODEL) "$(INTDIR)"
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\cmdlib.c
DEP_CPP_CMDLI=\
".\..\common\cmdlib.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
{$(INCLUDE)}"\sys\STAT.H"\
"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\trilib.c
DEP_CPP_TRILI=\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
".\..\common\trilib.h"\
"$(INTDIR)\trilib.obj" : $(SOURCE) $(DEP_CPP_TRILI) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\scriplib.c
DEP_CPP_SCRIP=\
".\..\common\cmdlib.h"\
".\..\common\scriplib.h"\
"$(INTDIR)\scriplib.obj" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\mathlib.c
DEP_CPP_MATHL=\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
"$(INTDIR)\mathlib.obj" : $(SOURCE) $(DEP_CPP_MATHL) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\lbmlib.c
DEP_CPP_LBMLI=\
".\..\common\cmdlib.h"\
".\..\common\lbmlib.h"\
"$(INTDIR)\lbmlib.obj" : $(SOURCE) $(DEP_CPP_LBMLI) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
# End Target
# End Project
################################################################################

Binary file not shown.

Binary file not shown.

870
qutils/QBSP/BRUSH.C Normal file
View File

@@ -0,0 +1,870 @@
// brush.c
#include "bsp5.h"
int numbrushplanes;
plane_t planes[MAX_MAP_PLANES];
int numbrushfaces;
mface_t faces[128]; // beveled clipping hull can generate many extra
/*
=================
CheckFace
Note: this will not catch 0 area polygons
=================
*/
void CheckFace (face_t *f)
{
int i, j;
vec_t *p1, *p2;
vec_t d, edgedist;
vec3_t dir, edgenormal, facenormal;
if (f->numpoints < 3)
Error ("CheckFace: %i points",f->numpoints);
VectorCopy (planes[f->planenum].normal, facenormal);
if (f->planeside)
{
VectorSubtract (vec3_origin, facenormal, facenormal);
}
for (i=0 ; i<f->numpoints ; i++)
{
p1 = f->pts[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 == f->numpoints ? 0 : i+1;
// check the point is on the face plane
d = DotProduct (p1, planes[f->planenum].normal) - planes[f->planenum].dist;
if (d < -ON_EPSILON || d > ON_EPSILON)
Error ("CheckFace: point off plane");
// check the edge isn't degenerate
p2 = f->pts[j];
VectorSubtract (p2, p1, dir);
if (VectorLength (dir) < ON_EPSILON)
Error ("CheckFace: degenerate edge");
CrossProduct (facenormal, dir, edgenormal);
VectorNormalize (edgenormal);
edgedist = DotProduct (p1, edgenormal);
edgedist += ON_EPSILON;
// all other points must be on front side
for (j=0 ; j<f->numpoints ; j++)
{
if (j == i)
continue;
d = DotProduct (f->pts[j], edgenormal);
if (d > edgedist)
Error ("CheckFace: non-convex");
}
}
}
//===========================================================================
/*
=================
ClearBounds
=================
*/
void ClearBounds (brushset_t *bs)
{
int i, j;
for (j=0 ; j<NUM_HULLS ; j++)
for (i=0 ; i<3 ; i++)
{
bs->mins[i] = 99999;
bs->maxs[i] = -99999;
}
}
/*
=================
AddToBounds
=================
*/
void AddToBounds (brushset_t *bs, vec3_t v)
{
int i;
for (i=0 ; i<3 ; i++)
{
if (v[i] < bs->mins[i])
bs->mins[i] = v[i];
if (v[i] > bs->maxs[i])
bs->maxs[i] = v[i];
}
}
//===========================================================================
int PlaneTypeForNormal (vec3_t normal)
{
float ax, ay, az;
// NOTE: should these have an epsilon around 1.0?
if (normal[0] == 1.0)
return PLANE_X;
if (normal[1] == 1.0)
return PLANE_Y;
if (normal[2] == 1.0)
return PLANE_Z;
if (normal[0] == -1.0 ||
normal[1] == -1.0 ||
normal[2] == -1.0)
Error ("PlaneTypeForNormal: not a canonical vector");
ax = fabs(normal[0]);
ay = fabs(normal[1]);
az = fabs(normal[2]);
if (ax >= ay && ax >= az)
return PLANE_ANYX;
if (ay >= ax && ay >= az)
return PLANE_ANYY;
return PLANE_ANYZ;
}
#define DISTEPSILON 0.01
#define ANGLEEPSILON 0.00001
void NormalizePlane (plane_t *dp)
{
vec_t ax, ay, az;
if (dp->normal[0] == -1.0)
{
dp->normal[0] = 1.0;
dp->dist = -dp->dist;
}
if (dp->normal[1] == -1.0)
{
dp->normal[1] = 1.0;
dp->dist = -dp->dist;
}
if (dp->normal[2] == -1.0)
{
dp->normal[2] = 1.0;
dp->dist = -dp->dist;
}
if (dp->normal[0] == 1.0)
{
dp->type = PLANE_X;
return;
}
if (dp->normal[1] == 1.0)
{
dp->type = PLANE_Y;
return;
}
if (dp->normal[2] == 1.0)
{
dp->type = PLANE_Z;
return;
}
ax = fabs(dp->normal[0]);
ay = fabs(dp->normal[1]);
az = fabs(dp->normal[2]);
if (ax >= ay && ax >= az)
dp->type = PLANE_ANYX;
else if (ay >= ax && ay >= az)
dp->type = PLANE_ANYY;
else
dp->type = PLANE_ANYZ;
if (dp->normal[dp->type-PLANE_ANYX] < 0)
{
VectorSubtract (vec3_origin, dp->normal, dp->normal);
dp->dist = -dp->dist;
}
}
/*
===============
FindPlane
Returns a global plane number and the side that will be the front
===============
*/
int FindPlane (plane_t *dplane, int *side)
{
int i;
plane_t *dp, pl;
vec_t dot;
dot = VectorLength(dplane->normal);
if (dot < 1.0 - ANGLEEPSILON || dot > 1.0 + ANGLEEPSILON)
Error ("FindPlane: normalization error");
pl = *dplane;
NormalizePlane (&pl);
if (DotProduct(pl.normal, dplane->normal) > 0)
*side = 0;
else
*side = 1;
dp = planes;
for (i=0 ; i<numbrushplanes;i++, dp++)
{
dot = DotProduct (dp->normal, pl.normal);
if (dot > 1.0 - ANGLEEPSILON
&& fabs(dp->dist - pl.dist) < DISTEPSILON )
{ // regular match
return i;
}
}
if (numbrushplanes == MAX_MAP_PLANES)
Error ("numbrushplanes == MAX_MAP_PLANES");
planes[numbrushplanes] = pl;
numbrushplanes++;
return numbrushplanes-1;
}
/*
===============
FindPlane_old
Returns a global plane number and the side that will be the front
===============
*/
int FindPlane_old (plane_t *dplane, int *side)
{
int i;
plane_t *dp;
vec_t dot, ax, ay, az;
dot = VectorLength(dplane->normal);
if (dot < 1.0 - ANGLEEPSILON || dot > 1.0 + ANGLEEPSILON)
Error ("FindPlane: normalization error");
dp = planes;
for (i=0 ; i<numbrushplanes;i++, dp++)
{
dot = DotProduct (dplane->normal, dp->normal);
if (dot > 1.0 - ANGLEEPSILON
&& fabs(dplane->dist - dp->dist) < DISTEPSILON )
{ // regular match
*side = 0;
return i;
}
if (dot < -1.0+ANGLEEPSILON
&& fabs(dplane->dist + dp->dist) < DISTEPSILON )
{ // inverse of vector
*side = 1;
return i;
}
}
// allocate a new plane, flipping normal to a consistant direction
// if needed
*dp = *dplane;
if (numbrushplanes == MAX_MAP_PLANES)
Error ("numbrushplanes == MAX_MAP_PLANES");
numbrushplanes++;
*side = 0;
// NOTE: should these have an epsilon around 1.0?
if (dplane->normal[0] == 1.0)
dp->type = PLANE_X;
else if (dplane->normal[1] == 1.0)
dp->type = PLANE_Y;
else if (dplane->normal[2] == 1.0)
dp->type = PLANE_Z;
else if (dplane->normal[0] == -1.0)
{
dp->type = PLANE_X;
dp->normal[0] = 1.0;
dp->dist = -dp->dist;
*side = 1;
}
else if (dplane->normal[1] == -1.0)
{
dp->type = PLANE_Y;
dp->normal[1] = 1.0;
dp->dist = -dp->dist;
*side = 1;
}
else if (dplane->normal[2] == -1.0)
{
dp->type = PLANE_Z;
dp->normal[2] = 1.0;
dp->dist = -dp->dist;
*side = 1;
}
else
{
ax = fabs(dplane->normal[0]);
ay = fabs(dplane->normal[1]);
az = fabs(dplane->normal[2]);
if (ax >= ay && ax >= az)
dp->type = PLANE_ANYX;
else if (ay >= ax && ay >= az)
dp->type = PLANE_ANYY;
else
dp->type = PLANE_ANYZ;
if (dplane->normal[dp->type-PLANE_ANYX] < 0)
{
VectorSubtract (vec3_origin, dp->normal, dp->normal);
dp->dist = -dp->dist;
*side = 1;
}
}
return i;
}
/*
=============================================================================
TURN BRUSHES INTO GROUPS OF FACES
=============================================================================
*/
vec3_t brush_mins, brush_maxs;
face_t *brush_faces;
/*
=================
CreateBrushFaces
=================
*/
#define ZERO_EPSILON 0.001
void CreateBrushFaces (void)
{
int i,j, k;
vec_t r;
face_t *f;
winding_t *w;
plane_t plane;
mface_t *mf;
brush_mins[0] = brush_mins[1] = brush_mins[2] = 99999;
brush_maxs[0] = brush_maxs[1] = brush_maxs[2] = -99999;
brush_faces = NULL;
for (i=0 ; i<numbrushfaces ; i++)
{
mf = &faces[i];
w = BaseWindingForPlane (&mf->plane);
for (j=0 ; j<numbrushfaces && w ; j++)
{
if (j == i)
continue;
// flip the plane, because we want to keep the back side
VectorSubtract (vec3_origin,faces[j].plane.normal, plane.normal);
plane.dist = -faces[j].plane.dist;
w = ClipWinding (w, &plane, false);
}
if (!w)
continue; // overcontrained plane
// this face is a keeper
f = AllocFace ();
f->numpoints = w->numpoints;
if (f->numpoints > MAXEDGES)
Error ("f->numpoints > MAXEDGES");
for (j=0 ; j<w->numpoints ; j++)
{
for (k=0 ; k<3 ; k++)
{
r = Q_rint (w->points[j][k]);
if ( fabs(w->points[j][k] - r) < ZERO_EPSILON)
f->pts[j][k] = r;
else
f->pts[j][k] = w->points[j][k];
if (f->pts[j][k] < brush_mins[k])
brush_mins[k] = f->pts[j][k];
if (f->pts[j][k] > brush_maxs[k])
brush_maxs[k] = f->pts[j][k];
}
}
FreeWinding (w);
f->texturenum = mf->texinfo;
f->planenum = FindPlane (&mf->plane, &f->planeside);
f->next = brush_faces;
brush_faces = f;
CheckFace (f);
}
}
/*
==============================================================================
BEVELED CLIPPING HULL GENERATION
This is done by brute force, and could easily get a lot faster if anyone cares.
==============================================================================
*/
vec3_t hull_size[3][2] = {
{ {0, 0, 0}, {0, 0, 0} },
{ {-16,-16,-32}, {16,16,24} },
{ {-32,-32,-64}, {32,32,24} }
};
#define MAX_HULL_POINTS 32
#define MAX_HULL_EDGES 64
int num_hull_points;
vec3_t hull_points[MAX_HULL_POINTS];
vec3_t hull_corners[MAX_HULL_POINTS*8];
int num_hull_edges;
int hull_edges[MAX_HULL_EDGES][2];
/*
============
AddBrushPlane
=============
*/
void AddBrushPlane (plane_t *plane)
{
int i;
plane_t *pl;
float l;
if (numbrushfaces == MAX_FACES)
Error ("AddBrushPlane: numbrushfaces == MAX_FACES");
l = VectorLength (plane->normal);
if (l < 0.999 || l > 1.001)
Error ("AddBrushPlane: bad normal");
for (i=0 ; i<numbrushfaces ; i++)
{
pl = &faces[i].plane;
if (VectorCompare (pl->normal, plane->normal)
&& fabs(pl->dist - plane->dist) < ON_EPSILON )
return;
}
faces[i].plane = *plane;
faces[i].texinfo = faces[0].texinfo;
numbrushfaces++;
}
/*
============
TestAddPlane
Adds the given plane to the brush description if all of the original brush
vertexes can be put on the front side
=============
*/
void TestAddPlane (plane_t *plane)
{
int i, c;
vec_t d;
vec_t *corner;
plane_t flip;
vec3_t inv;
int counts[3];
plane_t *pl;
// see if the plane has allready been added
for (i=0 ; i<numbrushfaces ; i++)
{
pl = &faces[i].plane;
if (VectorCompare (plane->normal, pl->normal) && fabs(plane->dist - pl->dist) < ON_EPSILON)
return;
VectorSubtract (vec3_origin, plane->normal, inv);
if (VectorCompare (inv, pl->normal) && fabs(plane->dist + pl->dist) < ON_EPSILON)
return;
}
// check all the corner points
counts[0] = counts[1] = counts[2] = 0;
c = num_hull_points * 8;
corner = hull_corners[0];
for (i=0 ; i<c ; i++, corner += 3)
{
d = DotProduct (corner, plane->normal) - plane->dist;
if (d < -ON_EPSILON)
{
if (counts[0])
return;
counts[1]++;
}
else if (d > ON_EPSILON)
{
if (counts[1])
return;
counts[0]++;
}
else
counts[2]++;
}
// the plane is a seperator
if (counts[0])
{
VectorSubtract (vec3_origin, plane->normal, flip.normal);
flip.dist = -plane->dist;
plane = &flip;
}
AddBrushPlane (plane);
}
/*
============
AddHullPoint
Doesn't add if duplicated
=============
*/
int AddHullPoint (vec3_t p, int hullnum)
{
int i;
vec_t *c;
int x,y,z;
for (i=0 ; i<num_hull_points ; i++)
if (VectorCompare (p, hull_points[i]))
return i;
VectorCopy (p, hull_points[num_hull_points]);
c = hull_corners[i*8];
for (x=0 ; x<2 ; x++)
for (y=0 ; y<2 ; y++)
for (z=0; z<2 ; z++)
{
c[0] = p[0] + hull_size[hullnum][x][0];
c[1] = p[1] + hull_size[hullnum][y][1];
c[2] = p[2] + hull_size[hullnum][z][2];
c += 3;
}
if (num_hull_points == MAX_HULL_POINTS)
Error ("MAX_HULL_POINTS");
num_hull_points++;
return i;
}
/*
============
AddHullEdge
Creates all of the hull planes around the given edge, if not done allready
=============
*/
void AddHullEdge (vec3_t p1, vec3_t p2, int hullnum)
{
int pt1, pt2;
int i;
int a, b, c, d, e;
vec3_t edgevec, planeorg, planevec;
plane_t plane;
vec_t l;
pt1 = AddHullPoint (p1, hullnum);
pt2 = AddHullPoint (p2, hullnum);
for (i=0 ; i<num_hull_edges ; i++)
if ( (hull_edges[i][0] == pt1 && hull_edges[i][1] == pt2)
|| (hull_edges[i][0] == pt2 && hull_edges[i][1] == pt1) )
return; // allread added
if (num_hull_edges == MAX_HULL_EDGES)
Error ("MAX_HULL_EDGES");
hull_edges[i][0] = pt1;
hull_edges[i][1] = pt2;
num_hull_edges++;
VectorSubtract (p1, p2, edgevec);
VectorNormalize (edgevec);
for (a=0 ; a<3 ; a++)
{
b = (a+1)%3;
c = (a+2)%3;
for (d=0 ; d<=1 ; d++)
for (e=0 ; e<=1 ; e++)
{
VectorCopy (p1, planeorg);
planeorg[b] += hull_size[hullnum][d][b];
planeorg[c] += hull_size[hullnum][e][c];
VectorCopy (vec3_origin, planevec);
planevec[a] = 1;
CrossProduct (planevec, edgevec, plane.normal);
l = VectorLength (plane.normal);
if (l < 1-ANGLEEPSILON || l > 1+ANGLEEPSILON)
continue;
plane.dist = DotProduct (planeorg, plane.normal);
TestAddPlane (&plane);
}
}
}
/*
============
ExpandBrush
=============
*/
void ExpandBrush (int hullnum)
{
int i, x, s;
vec3_t corner;
face_t *f;
plane_t plane, *p;
num_hull_points = 0;
num_hull_edges = 0;
// create all the hull points
for (f=brush_faces ; f ; f=f->next)
for (i=0 ; i<f->numpoints ; i++)
AddHullPoint (f->pts[i], hullnum);
// expand all of the planes
for (i=0 ; i<numbrushfaces ; i++)
{
p = &faces[i].plane;
VectorCopy (vec3_origin, corner);
for (x=0 ; x<3 ; x++)
{
if (p->normal[x] > 0)
corner[x] = hull_size[hullnum][1][x];
else if (p->normal[x] < 0)
corner[x] = hull_size[hullnum][0][x];
}
p->dist += DotProduct (corner, p->normal);
}
// add any axis planes not contained in the brush to bevel off corners
for (x=0 ; x<3 ; x++)
for (s=-1 ; s<=1 ; s+=2)
{
// add the plane
VectorCopy (vec3_origin, plane.normal);
plane.normal[x] = s;
if (s == -1)
plane.dist = -brush_mins[x] + -hull_size[hullnum][0][x];
else
plane.dist = brush_maxs[x] + hull_size[hullnum][1][x];
AddBrushPlane (&plane);
}
// add all of the edge bevels
for (f=brush_faces ; f ; f=f->next)
for (i=0 ; i<f->numpoints ; i++)
AddHullEdge (f->pts[i], f->pts[(i+1)%f->numpoints], hullnum);
}
//============================================================================
/*
===============
LoadBrush
Converts a mapbrush to a bsp brush
===============
*/
brush_t *LoadBrush (mbrush_t *mb, int hullnum)
{
brush_t *b;
int contents;
char *name;
mface_t *f;
//
// check texture name for attributes
//
name = miptex[texinfo[mb->faces->texinfo].miptex];
if (!Q_strcasecmp(name, "clip") && hullnum == 0)
return NULL; // "clip" brushes don't show up in the draw hull
if (name[0] == '*' && worldmodel) // entities never use water merging
{
if (!Q_strncasecmp(name+1,"lava",4))
contents = CONTENTS_LAVA;
else if (!Q_strncasecmp(name+1,"slime",5))
contents = CONTENTS_SLIME;
else
contents = CONTENTS_WATER;
}
else if (!Q_strncasecmp (name, "sky",3) && worldmodel && hullnum == 0)
contents = CONTENTS_SKY;
else
contents = CONTENTS_SOLID;
if (hullnum && contents != CONTENTS_SOLID && contents != CONTENTS_SKY)
return NULL; // water brushes don't show up in clipping hulls
// no seperate textures on clip hull
//
// create the faces
//
brush_faces = NULL;
numbrushfaces = 0;
for (f=mb->faces ; f ; f=f->next)
{
faces[numbrushfaces] = *f;
if (hullnum)
faces[numbrushfaces].texinfo = 0;
numbrushfaces++;
}
CreateBrushFaces ();
if (!brush_faces)
{
printf ("WARNING: couldn't create brush faces\n");
return NULL;
}
if (hullnum)
{
ExpandBrush (hullnum);
CreateBrushFaces ();
}
//
// create the brush
//
b = AllocBrush ();
b->contents = contents;
b->faces = brush_faces;
VectorCopy (brush_mins, b->mins);
VectorCopy (brush_maxs, b->maxs);
return b;
}
//=============================================================================
/*
============
Brush_DrawAll
============
*/
void Brush_DrawAll (brushset_t *bs)
{
brush_t *b;
face_t *f;
for (b=bs->brushes ; b ; b=b->next)
for (f=b->faces ; f ; f=f->next)
Draw_DrawFace (f);
}
/*
============
Brush_LoadEntity
============
*/
brushset_t *Brush_LoadEntity (entity_t *ent, int hullnum)
{
brush_t *b, *next, *water, *other;
mbrush_t *mbr;
int numbrushes;
brushset_t *bset;
bset = malloc (sizeof(brushset_t));
memset (bset, 0, sizeof(brushset_t));
ClearBounds (bset);
numbrushes = 0;
other = water = NULL;
qprintf ("--- Brush_LoadEntity ---\n");
for (mbr = ent->brushes ; mbr ; mbr=mbr->next)
{
b = LoadBrush (mbr, hullnum);
if (!b)
continue;
numbrushes++;
if (b->contents != CONTENTS_SOLID)
{
b->next = water;
water = b;
}
else
{
b->next = other;
other = b;
}
AddToBounds (bset, b->mins);
AddToBounds (bset, b->maxs);
}
// add all of the water textures at the start
for (b=water ; b ; b=next)
{
next = b->next;
b->next = other;
other = b;
}
bset->brushes = other;
brushset = bset;
Brush_DrawAll (bset);
qprintf ("%i brushes read\n",numbrushes);
return bset;
}

297
qutils/QBSP/BSP5.H Normal file
View File

@@ -0,0 +1,297 @@
// bsp5.h
#include "cmdlib.h"
#include "mathlib.h"
#include "bspfile.h"
typedef struct
{
vec3_t normal;
vec_t dist;
int type;
} plane_t;
#include "map.h"
#define MAX_THREADS 4
#define ON_EPSILON 0.05
#define BOGUS_RANGE 18000
// the exact bounding box of the brushes is expanded some for the headnode
// volume. is this still needed?
#define SIDESPACE 24
//============================================================================
typedef struct
{
int numpoints;
vec3_t points[8]; // variable sized
} winding_t;
#define MAX_POINTS_ON_WINDING 64
winding_t *BaseWindingForPlane (plane_t *p);
void CheckWinding (winding_t *w);
winding_t *NewWinding (int points);
void FreeWinding (winding_t *w);
winding_t *CopyWinding (winding_t *w);
winding_t *ClipWinding (winding_t *in, plane_t *split, qboolean keepon);
void DivideWinding (winding_t *in, plane_t *split, winding_t **front, winding_t **back);
//============================================================================
#define MAXEDGES 32
#define MAXPOINTS 28 // don't let a base face get past this
// because it can be split more later
typedef struct visfacet_s
{
struct visfacet_s *next;
int planenum;
int planeside; // which side is the front of the face
int texturenum;
int contents[2]; // 0 = front side
struct visfacet_s *original; // face on node
int outputnumber; // only valid for original faces after
// write surfaces
int numpoints;
vec3_t pts[MAXEDGES]; // FIXME: change to use winding_t
int edges[MAXEDGES];
} face_t;
typedef struct surface_s
{
struct surface_s *next;
struct surface_s *original; // before BSP cuts it up
int planenum;
int outputplanenum; // only valid after WriteSurfacePlanes
vec3_t mins, maxs;
qboolean onnode; // true if surface has already been used
// as a splitting node
face_t *faces; // links to all the faces on either side of the surf
} surface_t;
//
// there is a node_t structure for every node and leaf in the bsp tree
//
#define PLANENUM_LEAF -1
typedef struct node_s
{
vec3_t mins,maxs; // bounding volume, not just points inside
// information for decision nodes
int planenum; // -1 = leaf node
int outputplanenum; // only valid after WriteNodePlanes
int firstface; // decision node only
int numfaces; // decision node only
struct node_s *children[2]; // only valid for decision nodes
face_t *faces; // decision nodes only, list for both sides
// information for leafs
int contents; // leaf nodes (0 for decision nodes)
face_t **markfaces; // leaf nodes only, point to node faces
struct portal_s *portals;
int visleafnum; // -1 = solid
int valid; // for flood filling
int occupied; // light number in leaf for outside filling
} node_t;
//=============================================================================
// brush.c
#define NUM_HULLS 2 // normal and +16
#define NUM_CONTENTS 2 // solid and water
typedef struct brush_s
{
struct brush_s *next;
vec3_t mins, maxs;
face_t *faces;
int contents;
} brush_t;
typedef struct
{
vec3_t mins, maxs;
brush_t *brushes; // NULL terminated list
} brushset_t;
extern int numbrushplanes;
extern plane_t planes[MAX_MAP_PLANES];
brushset_t *Brush_LoadEntity (entity_t *ent, int hullnum);
int PlaneTypeForNormal (vec3_t normal);
int FindPlane (plane_t *dplane, int *side);
//=============================================================================
// csg4.c
// build surfaces is also used by GatherNodeFaces
extern face_t *validfaces[MAX_MAP_PLANES];
surface_t *BuildSurfaces (void);
face_t *NewFaceFromFace (face_t *in);
surface_t *CSGFaces (brushset_t *bs);
void SplitFace (face_t *in, plane_t *split, face_t **front, face_t **back);
//=============================================================================
// solidbsp.c
void DivideFacet (face_t *in, plane_t *split, face_t **front, face_t **back);
void CalcSurfaceInfo (surface_t *surf);
void SubdivideFace (face_t *f, face_t **prevptr);
node_t *SolidBSP (surface_t *surfhead, qboolean midsplit);
//=============================================================================
// merge.c
void MergePlaneFaces (surface_t *plane);
face_t *MergeFaceToList (face_t *face, face_t *list);
face_t *FreeMergeListScraps (face_t *merged);
void MergeAll (surface_t *surfhead);
//=============================================================================
// surfaces.c
extern int c_cornerverts;
extern int c_tryedges;
extern face_t *edgefaces[MAX_MAP_EDGES][2];
extern int firstmodeledge;
extern int firstmodelface;
void SubdivideFaces (surface_t *surfhead);
surface_t *GatherNodeFaces (node_t *headnode);
void MakeFaceEdges (node_t *headnode);
//=============================================================================
// portals.c
typedef struct portal_s
{
int planenum;
node_t *nodes[2]; // [0] = front side of planenum
struct portal_s *next[2];
winding_t *winding;
} portal_t;
extern node_t outside_node; // portals outside the world face this
void PortalizeWorld (node_t *headnode);
void WritePortalfile (node_t *headnode);
void FreeAllPortals (node_t *node);
//=============================================================================
// region.c
void GrowNodeRegions (node_t *headnode);
//=============================================================================
// tjunc.c
void tjunc (node_t *headnode);
//=============================================================================
// writebsp.c
void WriteNodePlanes (node_t *headnode);
void WriteClipNodes (node_t *headnode);
void WriteDrawNodes (node_t *headnode);
void BumpModel (int hullnum);
int FindFinalPlane (dplane_t *p);
void BeginBSPFile (void);
void FinishBSPFile (void);
//=============================================================================
// draw.c
void Draw_ClearBounds (void);
void Draw_AddToBounds (vec3_t v);
void Draw_DrawFace (face_t *f);
void Draw_ClearWindow (void);
void Draw_SetRed (void);
void Draw_SetGrey (void);
void Draw_SetBlack (void);
void DrawPoint (vec3_t v);
void Draw_SetColor (int c);
void SetColor (int c);
void DrawPortal (portal_t *p);
void DrawLeaf (node_t *l, int color);
void DrawBrush (brush_t *b);
void DrawWinding (winding_t *w);
void DrawTri (vec3_t p1, vec3_t p2, vec3_t p3);
//=============================================================================
// outside.c
qboolean FillOutside (node_t *node);
//=============================================================================
extern qboolean drawflag;
extern qboolean nofill;
extern qboolean notjunc;
extern qboolean noclip;
extern qboolean verbose;
extern int subdivide_size;
extern int hullnum;
extern brushset_t *brushset;
void qprintf (char *fmt, ...); // only prints if verbose
extern int valid;
extern char portfilename[1024];
extern char bspfilename[1024];
extern char pointfilename[1024];
extern qboolean worldmodel;
// misc functions
face_t *AllocFace (void);
void FreeFace (face_t *f);
struct portal_s *AllocPortal (void);
void FreePortal (struct portal_s *p);
surface_t *AllocSurface (void);
void FreeSurface (surface_t *s);
node_t *AllocNode (void);
struct brush_s *AllocBrush (void);
//=============================================================================

464
qutils/QBSP/CSG4.C Normal file
View File

@@ -0,0 +1,464 @@
// csg4.c
#include "bsp5.h"
/*
NOTES
-----
Brushes that touch still need to be split at the cut point to make a tjunction
*/
face_t *validfaces[MAX_MAP_PLANES];
face_t *inside, *outside;
int brushfaces;
int csgfaces;
int csgmergefaces;
void DrawList (face_t *list)
{
for ( ; list ; list=list->next)
Draw_DrawFace (list);
}
/*
==================
NewFaceFromFace
Duplicates the non point information of a face, used by SplitFace and
MergeFace.
==================
*/
face_t *NewFaceFromFace (face_t *in)
{
face_t *newf;
newf = AllocFace ();
newf->planenum = in->planenum;
newf->texturenum = in->texturenum;
newf->planeside = in->planeside;
newf->original = in->original;
newf->contents[0] = in->contents[0];
newf->contents[1] = in->contents[1];
return newf;
}
/*
==================
SplitFace
==================
*/
void SplitFace (face_t *in, plane_t *split, face_t **front, face_t **back)
{
vec_t dists[MAXEDGES+1];
int sides[MAXEDGES+1];
int counts[3];
vec_t dot;
int i, j;
face_t *newf, *new2;
vec_t *p1, *p2;
vec3_t mid;
if (in->numpoints < 0)
Error ("SplitFace: freed face");
counts[0] = counts[1] = counts[2] = 0;
// determine sides for each point
for (i=0 ; i<in->numpoints ; i++)
{
dot = DotProduct (in->pts[i], split->normal);
dot -= split->dist;
dists[i] = dot;
if (dot > ON_EPSILON)
sides[i] = SIDE_FRONT;
else if (dot < -ON_EPSILON)
sides[i] = SIDE_BACK;
else
sides[i] = SIDE_ON;
counts[sides[i]]++;
}
sides[i] = sides[0];
dists[i] = dists[0];
if (!counts[0])
{
*front = NULL;
*back = in;
return;
}
if (!counts[1])
{
*front = in;
*back = NULL;
return;
}
*back = newf = NewFaceFromFace (in);
*front = new2 = NewFaceFromFace (in);
// distribute the points and generate splits
for (i=0 ; i<in->numpoints ; i++)
{
if (newf->numpoints > MAXEDGES || new2->numpoints > MAXEDGES)
Error ("SplitFace: numpoints > MAXEDGES");
p1 = in->pts[i];
if (sides[i] == SIDE_ON)
{
VectorCopy (p1, newf->pts[newf->numpoints]);
newf->numpoints++;
VectorCopy (p1, new2->pts[new2->numpoints]);
new2->numpoints++;
continue;
}
if (sides[i] == SIDE_FRONT)
{
VectorCopy (p1, new2->pts[new2->numpoints]);
new2->numpoints++;
}
else
{
VectorCopy (p1, newf->pts[newf->numpoints]);
newf->numpoints++;
}
if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
continue;
// generate a split point
p2 = in->pts[(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 (split->normal[j] == 1)
mid[j] = split->dist;
else if (split->normal[j] == -1)
mid[j] = -split->dist;
else
mid[j] = p1[j] + dot*(p2[j]-p1[j]);
}
VectorCopy (mid, newf->pts[newf->numpoints]);
newf->numpoints++;
VectorCopy (mid, new2->pts[new2->numpoints]);
new2->numpoints++;
}
if (newf->numpoints > MAXEDGES || new2->numpoints > MAXEDGES)
Error ("SplitFace: numpoints > MAXEDGES");
#if 0
CheckFace (newf);
CheckFace (new2);
#endif
// free the original face now that is is represented by the fragments
FreeFace (in);
}
/*
=================
ClipInside
Clips all of the faces in the inside list, possibly moving them to the
outside list or spliting it into a piece in each list.
Faces exactly on the plane will stay inside unless overdrawn by later brush
frontside is the side of the plane that holds the outside list
=================
*/
void ClipInside (int splitplane, int frontside, qboolean precedence)
{
face_t *f, *next;
face_t *frags[2];
face_t *insidelist;
plane_t *split;
split = &planes[splitplane];
insidelist = NULL;
for (f=inside ; f ; f=next)
{
next = f->next;
if (f->planenum == splitplane)
{ // exactly on, handle special
if ( frontside != f->planeside || precedence )
{ // allways clip off opposite faceing
frags[frontside] = NULL;
frags[!frontside] = f;
}
else
{ // leave it on the outside
frags[frontside] = f;
frags[!frontside] = NULL;
}
}
else
{ // proper split
SplitFace (f, split, &frags[0], &frags[1]);
}
if (frags[frontside])
{
frags[frontside]->next = outside;
outside = frags[frontside];
}
if (frags[!frontside])
{
frags[!frontside]->next = insidelist;
insidelist = frags[!frontside];
}
}
inside = insidelist;
}
/*
==================
SaveOutside
Saves all of the faces in the outside list to the bsp plane list
==================
*/
void SaveOutside (qboolean mirror)
{
face_t *f , *next, *newf;
int i;
int planenum;
for (f=outside ; f ; f=next)
{
next = f->next;
csgfaces++;
Draw_DrawFace (f);
planenum = f->planenum;
if (mirror)
{
newf = NewFaceFromFace (f);
newf->numpoints = f->numpoints;
newf->planeside = f->planeside ^ 1; // reverse side
newf->contents[0] = f->contents[1];
newf->contents[1] = f->contents[0];
for (i=0 ; i<f->numpoints ; i++) // add points backwards
{
VectorCopy (f->pts[f->numpoints-1-i], newf->pts[i]);
}
}
else
newf = NULL;
validfaces[planenum] = MergeFaceToList(f, validfaces[planenum]);
if (newf)
validfaces[planenum] = MergeFaceToList(newf, validfaces[planenum]);
validfaces[planenum] = FreeMergeListScraps (validfaces[planenum]);
}
}
/*
==================
FreeInside
Free all the faces that got clipped out
==================
*/
void FreeInside (int contents)
{
face_t *f, *next;
for (f=inside ; f ; f=next)
{
next = f->next;
if (contents != CONTENTS_SOLID)
{
f->contents[0] = contents;
f->next = outside;
outside = f;
}
else
FreeFace (f);
}
}
//==========================================================================
/*
==================
BuildSurfaces
Returns a chain of all the external surfaces with one or more visible
faces.
==================
*/
surface_t *BuildSurfaces (void)
{
face_t **f;
face_t *count;
int i;
surface_t *s;
surface_t *surfhead;
surfhead = NULL;
f = validfaces;
for (i=0 ; i<numbrushplanes ; i++, f++)
{
if (!*f)
continue; // nothing left on this plane
// create a new surface to hold the faces on this plane
s = AllocSurface ();
s->planenum = i;
s->next = surfhead;
surfhead = s;
s->faces = *f;
for (count = s->faces ; count ; count=count->next)
csgmergefaces++;
CalcSurfaceInfo (s); // bounding box and flags
}
return surfhead;
}
//==========================================================================
/*
==================
CopyFacesToOutside
==================
*/
void CopyFacesToOutside (brush_t *b)
{
face_t *f, *newf;
outside = NULL;
for (f=b->faces ; f ; f=f->next)
{
brushfaces++;
#if 0
{
int i;
for (i=0 ; i<f->numpoints ; i++)
printf ("(%f,%f,%f) ",f->pts[i][0], f->pts[i][1], f->pts[i][2]);
printf ("\n");
}
#endif
newf = AllocFace ();
*newf = *f;
newf->next = outside;
newf->contents[0] = CONTENTS_EMPTY;
newf->contents[1] = b->contents;
outside = newf;
}
}
/*
==================
CSGFaces
Returns a list of surfaces containing aall of the faces
==================
*/
surface_t *CSGFaces (brushset_t *bs)
{
brush_t *b1, *b2;
int i;
qboolean overwrite;
face_t *f;
surface_t *surfhead;
qprintf ("---- CSGFaces ----\n");
memset (validfaces, 0, sizeof(validfaces));
csgfaces = brushfaces = csgmergefaces = 0;
Draw_ClearWindow ();
//
// do the solid faces
//
for (b1=bs->brushes ; b1 ; b1 = b1->next)
{
// set outside to a copy of the brush's faces
CopyFacesToOutside (b1);
overwrite = false;
for (b2=bs->brushes ; b2 ; b2 = b2->next)
{
// see if b2 needs to clip a chunk out of b1
if (b1==b2)
{
overwrite = true; // later brushes now overwrite
continue;
}
// check bounding box first
for (i=0 ; i<3 ; i++)
if (b1->mins[i] > b2->maxs[i] || b1->maxs[i] < b2->mins[i])
break;
if (i<3)
continue;
// divide faces by the planes of the new brush
inside = outside;
outside = NULL;
for (f=b2->faces ; f ; f=f->next)
ClipInside (f->planenum, f->planeside, overwrite);
// these faces are continued in another brush, so get rid of them
if (b1->contents == CONTENTS_SOLID && b2->contents <= CONTENTS_WATER)
FreeInside (b2->contents);
else
FreeInside (CONTENTS_SOLID);
}
// all of the faces left in outside are real surface faces
if (b1->contents != CONTENTS_SOLID)
SaveOutside (true); // mirror faces for inside view
else
SaveOutside (false);
}
#if 0
if (!csgfaces)
Error ("No faces");
#endif
surfhead = BuildSurfaces ();
qprintf ("%5i brushfaces\n", brushfaces);
qprintf ("%5i csgfaces\n", csgfaces);
qprintf ("%5i mergedfaces\n", csgmergefaces);
return surfhead;
}

65
qutils/QBSP/MAKEFILE Normal file
View File

@@ -0,0 +1,65 @@
EXES = qbsp light vis bspinfo entmap visx
NTEXES = qbsp.exe light.exe vis.exe bspinfo.exe entmap.exe visx.exe
#==============================================================================
EXT= .o
all: $(EXES)
clean:
rm *.o *.obj $(EXES) $(NTEXES)
next:
make "CFLAGS = -g -Wall -I.."
nextinstall:
make "CFLAGS = -O4 -g -Wall -I.. -arch i386 -arch hppa"
cp $(EXES) /LocalApps
alpha:
make "CFLAGS = -g -I.." "LDFLAGS = -lm"
alphainstall:
make "CFLAGS = -O4 -I.." "LDFLAGS = -lm"
cp $(EXES) /LocalApps
nt:
nmake /nologo "CFLAGS = -nologo -Zi -DWIN32 -I.." "LDFLAGS = " "EXT = .obj"
ntinstall:
nmake /nologo "CFLAGS = -nologo -Ox -G5 -DWIN32 -I.." "LDFLAGS = " "EXT = .obj"
cp $(NTEXES) f:\nt\id
#==============================================================================
QBSPFILES = region$(EXT) map$(EXT) brush$(EXT) cmdlib$(EXT) csg4$(EXT) surfaces$(EXT) mathlib$(EXT)\
merge$(EXT) outside$(EXT) portals$(EXT) qbsp$(EXT) solidbsp$(EXT) tjunc$(EXT)\
writebsp$(EXT) bspfile$(EXT) nodraw$(EXT)
qbsp : $(QBSPFILES)
$(CC) $(CFLAGS) -o qbsp $(QBSPFILES)
light : threads$(EXT) bspfile$(EXT) cmdlib$(EXT) light$(EXT) ltface$(EXT) mathlib$(EXT) trace$(EXT) entities$(EXT)
$(CC) $(CFLAGS) -o light threads$(EXT) bspfile$(EXT) cmdlib$(EXT) light$(EXT) ltface$(EXT) mathlib$(EXT) trace$(EXT) entities$(EXT)
vis : vis$(EXT) flow$(EXT) cmdlib$(EXT) mathlib$(EXT) bspfile$(EXT) soundpvs$(EXT)
$(CC) $(CFLAGS) -o vis vis$(EXT) flow$(EXT) cmdlib$(EXT) mathlib$(EXT) bspfile$(EXT) soundpvs$(EXT)
visx : visx$(EXT) flowx$(EXT) cmdlib$(EXT) mathlib$(EXT) bspfile$(EXT) soundpvs$(EXT)
$(CC) $(CFLAGS) -o visx visx$(EXT) flowx$(EXT) cmdlib$(EXT) mathlib$(EXT) bspfile$(EXT) soundpvs$(EXT)
bspinfo : bspinfo$(EXT) bspfile$(EXT) cmdlib$(EXT)
$(CC) $(CFLAGS) -o bspinfo bspinfo$(EXT) bspfile$(EXT) cmdlib$(EXT)
entmap : entmap$(EXT) cmdlib$(EXT)
$(CC) $(CFLAGS) -o entmap entmap$(EXT) cmdlib$(EXT)
cmdlib$(EXT) : ../cmdlib.c
$(CC) $(CFLAGS) -c -o cmdlib$(EXT) ../cmdlib.c
mathlib$(EXT) : ../mathlib.c
$(CC) $(CFLAGS) -c -o mathlib$(EXT) ../mathlib.c

579
qutils/QBSP/MAP.C Normal file
View File

@@ -0,0 +1,579 @@
// map.c
#include "bsp5.h"
int nummapbrushes;
mbrush_t mapbrushes[MAX_MAP_BRUSHES];
int num_entities;
entity_t entities[MAX_MAP_ENTITIES];
int nummiptex;
char miptex[MAX_MAP_TEXINFO][16];
//============================================================================
/*
===============
FindMiptex
===============
*/
int FindMiptex (char *name)
{
int i;
for (i=0 ; i<nummiptex ; i++)
{
if (!strcmp (name, miptex[i]))
return i;
}
if (nummiptex == MAX_MAP_TEXINFO)
Error ("nummiptex == MAX_MAP_TEXINFO");
strcpy (miptex[i], name);
nummiptex++;
return i;
}
/*
===============
FindTexinfo
Returns a global texinfo number
===============
*/
int FindTexinfo (texinfo_t *t)
{
int i, j;
texinfo_t *tex;
// set the special flag
if (miptex[t->miptex][0] == '*'
|| !Q_strncasecmp (miptex[t->miptex], "sky",3) )
t->flags |= TEX_SPECIAL;
tex = texinfo;
for (i=0 ; i<numtexinfo;i++, tex++)
{
if (t->miptex != tex->miptex)
continue;
if (t->flags != tex->flags)
continue;
for (j=0 ; j<8 ; j++)
if (t->vecs[0][j] != tex->vecs[0][j])
break;
if (j != 8)
continue;
return i;
}
// allocate a new texture
if (numtexinfo == MAX_MAP_TEXINFO)
Error ("numtexinfo == MAX_MAP_TEXINFO");
texinfo[i] = *t;
numtexinfo++;
return i;
}
//============================================================================
#define MAXTOKEN 128
char token[MAXTOKEN];
qboolean unget;
char *script_p;
int scriptline;
void StartTokenParsing (char *data)
{
scriptline = 1;
script_p = data;
unget = false;
}
qboolean GetToken (qboolean crossline)
{
char *token_p;
if (unget) // is a token allready waiting?
return true;
//
// skip space
//
skipspace:
while (*script_p <= 32)
{
if (!*script_p)
{
if (!crossline)
Error ("Line %i is incomplete",scriptline);
return false;
}
if (*script_p++ == '\n')
{
if (!crossline)
Error ("Line %i is incomplete",scriptline);
scriptline++;
}
}
if (script_p[0] == '/' && script_p[1] == '/') // comment field
{
if (!crossline)
Error ("Line %i is incomplete\n",scriptline);
while (*script_p++ != '\n')
if (!*script_p)
{
if (!crossline)
Error ("Line %i is incomplete",scriptline);
return false;
}
goto skipspace;
}
//
// copy token
//
token_p = token;
if (*script_p == '"')
{
script_p++;
while ( *script_p != '"' )
{
if (!*script_p)
Error ("EOF inside quoted token");
*token_p++ = *script_p++;
if (token_p > &token[MAXTOKEN-1])
Error ("Token too large on line %i",scriptline);
}
script_p++;
}
else while ( *script_p > 32 )
{
*token_p++ = *script_p++;
if (token_p > &token[MAXTOKEN-1])
Error ("Token too large on line %i",scriptline);
}
*token_p = 0;
return true;
}
void UngetToken ()
{
unget = true;
}
//============================================================================
entity_t *mapent;
/*
=================
ParseEpair
=================
*/
void ParseEpair (void)
{
epair_t *e;
e = malloc (sizeof(epair_t));
memset (e, 0, sizeof(epair_t));
e->next = mapent->epairs;
mapent->epairs = e;
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);
}
//============================================================================
/*
==================
textureAxisFromPlane
==================
*/
vec3_t baseaxis[18] =
{
{0,0,1}, {1,0,0}, {0,-1,0}, // floor
{0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
{1,0,0}, {0,1,0}, {0,0,-1}, // west wall
{-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
{0,1,0}, {1,0,0}, {0,0,-1}, // south wall
{0,-1,0}, {1,0,0}, {0,0,-1} // north wall
};
void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv)
{
int bestaxis;
float dot,best;
int i;
best = 0;
bestaxis = 0;
for (i=0 ; i<6 ; i++)
{
dot = DotProduct (pln->normal, baseaxis[i*3]);
if (dot > best)
{
best = dot;
bestaxis = i;
}
}
VectorCopy (baseaxis[bestaxis*3+1], xv);
VectorCopy (baseaxis[bestaxis*3+2], yv);
}
//=============================================================================
/*
=================
ParseBrush
=================
*/
void ParseBrush (void)
{
mbrush_t *b;
mface_t *f, *f2;
vec3_t planepts[3];
vec3_t t1, t2, t3;
int i,j;
texinfo_t tx;
vec_t d;
float shift[2], rotate, scale[2];
b = &mapbrushes[nummapbrushes];
nummapbrushes++;
b->next = mapent->brushes;
mapent->brushes = b;
do
{
if (!GetToken (true))
break;
if (!strcmp (token, "}") )
break;
// read the three point plane definition
for (i=0 ; i<3 ; i++)
{
if (i != 0)
GetToken (true);
if (strcmp (token, "(") )
Error ("parsing brush");
for (j=0 ; j<3 ; j++)
{
GetToken (false);
planepts[i][j] = atoi(token);
}
GetToken (false);
if (strcmp (token, ")") )
Error ("parsing brush");
}
// read the texturedef
memset (&tx, 0, sizeof(tx));
GetToken (false);
tx.miptex = FindMiptex (token);
GetToken (false);
shift[0] = atoi(token);
GetToken (false);
shift[1] = atoi(token);
GetToken (false);
rotate = atoi(token);
GetToken (false);
scale[0] = atof(token);
GetToken (false);
scale[1] = atof(token);
// if the three points are all on a previous plane, it is a
// duplicate plane
for (f2 = b->faces ; f2 ; f2=f2->next)
{
for (i=0 ; i<3 ; i++)
{
d = DotProduct(planepts[i],f2->plane.normal) - f2->plane.dist;
if (d < -ON_EPSILON || d > ON_EPSILON)
break;
}
if (i==3)
break;
}
if (f2)
{
printf ("WARNING: brush with duplicate plane\n");
continue;
}
f = malloc(sizeof(mface_t));
f->next = b->faces;
b->faces = f;
// convert to a vector / dist plane
for (j=0 ; j<3 ; j++)
{
t1[j] = planepts[0][j] - planepts[1][j];
t2[j] = planepts[2][j] - planepts[1][j];
t3[j] = planepts[1][j];
}
CrossProduct(t1,t2, f->plane.normal);
if (VectorCompare (f->plane.normal, vec3_origin))
{
printf ("WARNING: brush plane with no normal\n");
b->faces = f->next;
free (f);
break;
}
VectorNormalize (f->plane.normal);
f->plane.dist = DotProduct (t3, f->plane.normal);
//
// fake proper texture vectors from QuakeEd style
//
{
vec3_t vecs[2];
int sv, tv;
float ang, sinv, cosv;
float ns, nt;
TextureAxisFromPlane(&f->plane, vecs[0], vecs[1]);
if (!scale[0])
scale[0] = 1;
if (!scale[1])
scale[1] = 1;
// rotate axis
if (rotate == 0)
{ sinv = 0 ; cosv = 1; }
else if (rotate == 90)
{ sinv = 1 ; cosv = 0; }
else if (rotate == 180)
{ sinv = 0 ; cosv = -1; }
else if (rotate == 270)
{ sinv = -1 ; cosv = 0; }
else
{
ang = rotate / 180 * Q_PI;
sinv = sin(ang);
cosv = cos(ang);
}
if (vecs[0][0])
sv = 0;
else if (vecs[0][1])
sv = 1;
else
sv = 2;
if (vecs[1][0])
tv = 0;
else if (vecs[1][1])
tv = 1;
else
tv = 2;
for (i=0 ; i<2 ; i++)
{
ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
vecs[i][sv] = ns;
vecs[i][tv] = nt;
}
for (i=0 ; i<2 ; i++)
for (j=0 ; j<3 ; j++)
tx.vecs[i][j] = vecs[i][j] / scale[i];
tx.vecs[0][3] = shift[0];
tx.vecs[1][3] = shift[1];
}
// unique the texinfo
f->texinfo = FindTexinfo (&tx);
} while (1);
}
/*
================
ParseEntity
================
*/
qboolean ParseEntity (void)
{
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;
if (!strcmp (token, "{") )
ParseBrush ();
else
ParseEpair ();
} while (1);
GetVectorForKey (mapent, "origin", mapent->origin);
return true;
}
/*
================
LoadMapFile
================
*/
void LoadMapFile (char *filename)
{
char *buf;
LoadFile (filename, (void **)&buf);
StartTokenParsing (buf);
num_entities = 0;
while (ParseEntity ())
{
}
free (buf);
qprintf ("--- LoadMapFile ---\n");
qprintf ("%s\n", filename);
qprintf ("%5i brushes\n", nummapbrushes);
qprintf ("%5i entities\n", num_entities);
qprintf ("%5i miptex\n", nummiptex);
qprintf ("%5i texinfo\n", numtexinfo);
}
void PrintEntity (entity_t *ent)
{
epair_t *ep;
for (ep=ent->epairs ; ep ; ep=ep->next)
printf ("%20s : %s\n", ep->key, ep->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 "";
}
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);
}
float 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);
v1 = v2 = v3 = 0;
// scanf into doubles, then assign, so it is vec_t size independent
sscanf (k, "%lf %lf %lf", &v1, &v2, &v3);
vec[0] = v1;
vec[1] = v2;
vec[2] = v3;
}
void WriteEntitiesToString (void)
{
char *buf, *end;
epair_t *ep;
char line[128];
int i;
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)
{
sprintf (line, "\"%s\" \"%s\"\n", ep->key, ep->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;
}

50
qutils/QBSP/MAP.H Normal file
View File

@@ -0,0 +1,50 @@
#define MAX_FACES 16
typedef struct mface_s
{
struct mface_s *next;
plane_t plane;
int texinfo;
} mface_t;
typedef struct mbrush_s
{
struct mbrush_s *next;
mface_t *faces;
} mbrush_t;
typedef struct epair_s
{
struct epair_s *next;
char *key;
char *value;
} epair_t;
typedef struct
{
vec3_t origin;
mbrush_t *brushes;
epair_t *epairs;
} entity_t;
extern int nummapbrushes;
extern mbrush_t mapbrushes[MAX_MAP_BRUSHES];
extern int num_entities;
extern entity_t entities[MAX_MAP_ENTITIES];
extern int nummiptex;
extern char miptex[MAX_MAP_TEXINFO][16];
void LoadMapFile (char *filename);
int FindMiptex (char *name);
void PrintEntity (entity_t *ent);
char *ValueForKey (entity_t *ent, char *key);
void SetKeyValue (entity_t *ent, char *key, char *value);
float FloatForKey (entity_t *ent, char *key);
void GetVectorForKey (entity_t *ent, char *key, vec3_t vec);
void WriteEntitiesToString (void);

277
qutils/QBSP/MERGE.C Normal file
View File

@@ -0,0 +1,277 @@
// merge.c
#include "bsp5.h"
#define CONTINUOUS_EPSILON 0.001
/*
================
CheckColinear
================
*/
void CheckColinear (face_t *f)
{
int i, j;
vec3_t v1, v2;
for (i=0 ; i<f->numpoints ;i++)
{
// skip the point if the vector from the previous point is the same
// as the vector to the next point
j = (i - 1 < 0) ? f->numpoints - 1 : i - 1;
VectorSubtract (f->pts[i], f->pts[j], v1);
VectorNormalize (v1);
j = (i + 1 == f->numpoints) ? 0 : i + 1;
VectorSubtract (f->pts[j], f->pts[i], v2);
VectorNormalize (v2);
if (VectorCompare (v1, v2))
Error ("Colinear edge");
}
}
/*
=============
TryMerge
If two polygons share a common edge and the edges that meet at the
common points are both inside the other polygons, merge them
Returns NULL if the faces couldn't be merged, or the new face.
The originals will NOT be freed.
=============
*/
face_t *TryMerge (face_t *f1, face_t *f2)
{
vec_t *p1, *p2, *p3, *p4, *back;
face_t *newf;
int i, j, k, l;
vec3_t normal, delta, planenormal;
vec_t dot;
plane_t *plane;
qboolean keep1, keep2;
if (f1->numpoints == -1 || f2->numpoints == -1)
return NULL;
if (f1->planeside != f2->planeside)
return NULL;
if (f1->texturenum != f2->texturenum)
return NULL;
if (f1->contents[0] != f2->contents[0])
return NULL;
if (f1->contents[1] != f2->contents[1])
return NULL;
//
// find a common edge
//
p1 = p2 = NULL; // stop compiler warning
j = 0; //
for (i=0 ; i<f1->numpoints ; i++)
{
p1 = f1->pts[i];
p2 = f1->pts[(i+1)%f1->numpoints];
for (j=0 ; j<f2->numpoints ; j++)
{
p3 = f2->pts[j];
p4 = f2->pts[(j+1)%f2->numpoints];
for (k=0 ; k<3 ; k++)
{
if (fabs(p1[k] - p4[k]) > EQUAL_EPSILON)
break;
if (fabs(p2[k] - p3[k]) > EQUAL_EPSILON)
break;
}
if (k==3)
break;
}
if (j < f2->numpoints)
break;
}
if (i == f1->numpoints)
return NULL; // no matching edges
//
// check slope of connected lines
// if the slopes are colinear, the point can be removed
//
plane = &planes[f1->planenum];
VectorCopy (plane->normal, planenormal);
if (f1->planeside)
VectorSubtract (vec3_origin, planenormal, planenormal);
back = f1->pts[(i+f1->numpoints-1)%f1->numpoints];
VectorSubtract (p1, back, delta);
CrossProduct (planenormal, delta, normal);
VectorNormalize (normal);
back = f2->pts[(j+2)%f2->numpoints];
VectorSubtract (back, p1, delta);
dot = DotProduct (delta, normal);
if (dot > CONTINUOUS_EPSILON)
return NULL; // not a convex polygon
keep1 = dot < -CONTINUOUS_EPSILON;
back = f1->pts[(i+2)%f1->numpoints];
VectorSubtract (back, p2, delta);
CrossProduct (planenormal, delta, normal);
VectorNormalize (normal);
back = f2->pts[(j+f2->numpoints-1)%f2->numpoints];
VectorSubtract (back, p2, delta);
dot = DotProduct (delta, normal);
if (dot > CONTINUOUS_EPSILON)
return NULL; // not a convex polygon
keep2 = dot < -CONTINUOUS_EPSILON;
//
// build the new polygon
//
if (f1->numpoints + f2->numpoints > MAXEDGES)
{
// Error ("TryMerge: too many edges!");
return NULL;
}
newf = NewFaceFromFace (f1);
// copy first polygon
for (k=(i+1)%f1->numpoints ; k != i ; k=(k+1)%f1->numpoints)
{
if (k==(i+1)%f1->numpoints && !keep2)
continue;
VectorCopy (f1->pts[k], newf->pts[newf->numpoints]);
newf->numpoints++;
}
// copy second polygon
for (l= (j+1)%f2->numpoints ; l != j ; l=(l+1)%f2->numpoints)
{
if (l==(j+1)%f2->numpoints && !keep1)
continue;
VectorCopy (f2->pts[l], newf->pts[newf->numpoints]);
newf->numpoints++;
}
return newf;
}
/*
===============
MergeFaceToList
===============
*/
qboolean mergedebug;
face_t *MergeFaceToList (face_t *face, face_t *list)
{
face_t *newf, *f;
for (f=list ; f ; f=f->next)
{
//CheckColinear (f);
if (mergedebug)
{
Draw_ClearWindow ();
Draw_DrawFace (face);
Draw_DrawFace (f);
Draw_SetBlack ();
}
newf = TryMerge (face, f);
if (!newf)
continue;
FreeFace (face);
f->numpoints = -1; // merged out
return MergeFaceToList (newf, list);
}
// didn't merge, so add at start
face->next = list;
return face;
}
/*
===============
FreeMergeListScraps
===============
*/
face_t *FreeMergeListScraps (face_t *merged)
{
face_t *head, *next;
head = NULL;
for ( ; merged ; merged = next)
{
next = merged->next;
if (merged->numpoints == -1)
FreeFace (merged);
else
{
merged->next = head;
head = merged;
}
}
return head;
}
/*
===============
MergePlaneFaces
===============
*/
void MergePlaneFaces (surface_t *plane)
{
face_t *f1, *next;
face_t *merged;
merged = NULL;
for (f1 = plane->faces ; f1 ; f1 = next)
{
next = f1->next;
merged = MergeFaceToList (f1, merged);
}
// chain all of the non-empty faces to the plane
plane->faces = FreeMergeListScraps (merged);
}
/*
============
MergeAll
============
*/
void MergeAll (surface_t *surfhead)
{
surface_t *surf;
int mergefaces;
face_t *f;
printf ("---- MergeAll ----\n");
mergefaces = 0;
for (surf = surfhead ; surf ; surf=surf->next)
{
MergePlaneFaces (surf);
Draw_ClearWindow ();
for (f=surf->faces ; f ; f=f->next)
{
Draw_DrawFace (f);
mergefaces++;
}
}
printf ("%i mergefaces\n", mergefaces);
}

54
qutils/QBSP/NODRAW.C Normal file
View File

@@ -0,0 +1,54 @@
#include "bsp5.h"
void Draw_ClearBounds (void)
{
}
void Draw_AddToBounds (vec3_t v)
{
}
void Draw_DrawFace (face_t *f)
{
}
void Draw_ClearWindow (void)
{
}
void Draw_SetRed (void)
{
}
void Draw_SetGrey (void)
{
}
void Draw_SetBlack (void)
{
}
void DrawPoint (vec3_t v)
{
}
void DrawLeaf (node_t *l, int color)
{
}
void DrawBrush (brush_t *b)
{
}
void DrawWinding (winding_t *w)
{
}
void DrawTri (vec3_t p1, vec3_t p2, vec3_t p3)
{
}
void DrawPortal (portal_t *portal)
{
}

252
qutils/QBSP/OUTSIDE.C Normal file
View File

@@ -0,0 +1,252 @@
#include "bsp5.h"
int outleafs;
/*
===========
PointInLeaf
===========
*/
node_t *PointInLeaf (node_t *node, vec3_t point)
{
vec_t d;
if (node->contents)
return node;
d = DotProduct (planes[node->planenum].normal, point) - planes[node->planenum]. dist;
if (d > 0)
return PointInLeaf (node->children[0], point);
return PointInLeaf (node->children[1], point);
}
/*
===========
PlaceOccupant
===========
*/
qboolean PlaceOccupant (int num, vec3_t point, node_t *headnode)
{
node_t *n;
n = PointInLeaf (headnode, point);
if (n->contents == CONTENTS_SOLID)
return false;
n->occupied = num;
return true;
}
/*
==============
MarkLeakTrail
==============
*/
portal_t *prevleaknode;
FILE *leakfile;
void MarkLeakTrail (portal_t *n2)
{
int i, j;
vec3_t p1, p2, dir;
float len;
portal_t *n1;
if (hullnum)
return;
n1 = prevleaknode;
prevleaknode = n2;
if (!n1)
return;
VectorCopy (n2->winding->points[0], p1);
for (i=1 ; i< n2->winding->numpoints ; i++)
{
for (j=0 ; j<3 ; j++)
p1[j] = (p1[j] + n2->winding->points[i][j]) / 2;
}
VectorCopy (n1->winding->points[0], p2);
for (i=1 ; i< n1->winding->numpoints ; i++)
{
for (j=0 ; j<3 ; j++)
p2[j] = (p2[j] + n1->winding->points[i][j]) / 2;
}
VectorSubtract (p2, p1, dir);
len = VectorLength (dir);
VectorNormalize (dir);
while (len > 2)
{
fprintf (leakfile,"%f %f %f\n", p1[0], p1[1], p1[2]);
for (i=0 ; i<3 ; i++)
p1[i] += dir[i]*2;
len -= 2;
}
}
/*
==================
RecursiveFillOutside
If fill is false, just check, don't fill
Returns true if an occupied leaf is reached
==================
*/
int hit_occupied;
int backdraw;
qboolean RecursiveFillOutside (node_t *l, qboolean fill)
{
portal_t *p;
int s;
if (l->contents == CONTENTS_SOLID || l->contents == CONTENTS_SKY)
return false;
if (l->valid == valid)
return false;
if (l->occupied)
return true;
l->valid = valid;
// fill it and it's neighbors
if (fill)
l->contents = CONTENTS_SOLID;
outleafs++;
for (p=l->portals ; p ; )
{
s = (p->nodes[0] == l);
if (RecursiveFillOutside (p->nodes[s], fill) )
{ // leaked, so stop filling
if (backdraw-- > 0)
{
MarkLeakTrail (p);
DrawLeaf (l, 2);
}
return true;
}
p = p->next[!s];
}
return false;
}
/*
==================
ClearOutFaces
==================
*/
void ClearOutFaces (node_t *node)
{
face_t **fp;
if (node->planenum != -1)
{
ClearOutFaces (node->children[0]);
ClearOutFaces (node->children[1]);
return;
}
if (node->contents != CONTENTS_SOLID)
return;
for (fp=node->markfaces ; *fp ; fp++)
{
// mark all the original faces that are removed
(*fp)->numpoints = 0;
}
node->faces = NULL;
}
//=============================================================================
/*
===========
FillOutside
===========
*/
qboolean FillOutside (node_t *node)
{
int s;
vec_t *v;
int i;
qboolean inside;
qprintf ("----- FillOutside ----\n");
if (nofill)
{
printf ("skipped\n");
return false;
}
inside = false;
for (i=1 ; i<num_entities ; i++)
{
if (!VectorCompare(entities[i].origin, vec3_origin))
{
if (PlaceOccupant (i, entities[i].origin, node))
inside = true;
}
}
if (!inside)
{
printf ("Hullnum %i: No entities in empty space -- no filling performed\n", hullnum);
return false;
}
s = !(outside_node.portals->nodes[1] == &outside_node);
// first check to see if an occupied leaf is hit
outleafs = 0;
valid++;
prevleaknode = NULL;
if (!hullnum)
{
leakfile = fopen (pointfilename, "w");
if (!leakfile)
Error ("Couldn't open %s\n", pointfilename);
}
if (RecursiveFillOutside (outside_node.portals->nodes[s], false))
{
v = entities[hit_occupied].origin;
qprintf ("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
qprintf ("reached occupant at: (%4.0f,%4.0f,%4.0f)\n"
, v[0], v[1], v[2]);
qprintf ("no filling performed\n");
if (!hullnum)
fclose (leakfile);
qprintf ("leak file written to %s\n", pointfilename);
qprintf ("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
return false;
}
if (!hullnum)
fclose (leakfile);
// now go back and fill things in
valid++;
RecursiveFillOutside (outside_node.portals->nodes[s], true);
// remove faces from filled in leafs
ClearOutFaces (node);
qprintf ("%4i outleafs\n", outleafs);
return true;
}

576
qutils/QBSP/PORTALS.C Normal file
View File

@@ -0,0 +1,576 @@
#include "bsp5.h"
node_t outside_node; // portals outside the world face this
//=============================================================================
/*
=============
AddPortalToNodes
=============
*/
void AddPortalToNodes (portal_t *p, node_t *front, node_t *back)
{
if (p->nodes[0] || p->nodes[1])
Error ("AddPortalToNode: allready included");
p->nodes[0] = front;
p->next[0] = front->portals;
front->portals = p;
p->nodes[1] = back;
p->next[1] = back->portals;
back->portals = p;
}
/*
=============
RemovePortalFromNode
=============
*/
void RemovePortalFromNode (portal_t *portal, node_t *l)
{
portal_t **pp, *t;
// remove reference to the current portal
pp = &l->portals;
while (1)
{
t = *pp;
if (!t)
Error ("RemovePortalFromNode: portal not in leaf");
if ( t == portal )
break;
if (t->nodes[0] == l)
pp = &t->next[0];
else if (t->nodes[1] == l)
pp = &t->next[1];
else
Error ("RemovePortalFromNode: portal not bounding leaf");
}
if (portal->nodes[0] == l)
{
*pp = portal->next[0];
portal->nodes[0] = NULL;
}
else if (portal->nodes[1] == l)
{
*pp = portal->next[1];
portal->nodes[1] = NULL;
}
}
//============================================================================
void PrintPortal (portal_t *p)
{
int i;
winding_t *w;
w = p->winding;
for (i=0 ; i<w->numpoints ; i++)
printf ("(%5.0f,%5.0f,%5.0f)\n",w->points[i][0]
, w->points[i][1], w->points[i][2]);
}
/*
================
MakeHeadnodePortals
The created portals will face the global outside_node
================
*/
void MakeHeadnodePortals (node_t *node)
{
vec3_t bounds[2];
int i, j, n;
portal_t *p, *portals[6];
plane_t bplanes[6], *pl;
int side;
Draw_ClearWindow ();
// pad with some space so there will never be null volume leafs
for (i=0 ; i<3 ; i++)
{
bounds[0][i] = brushset->mins[i] - SIDESPACE;
bounds[1][i] = brushset->maxs[i] + SIDESPACE;
}
outside_node.contents = CONTENTS_SOLID;
outside_node.portals = NULL;
for (i=0 ; i<3 ; i++)
for (j=0 ; j<2 ; j++)
{
n = j*3 + i;
p = AllocPortal ();
portals[n] = p;
pl = &bplanes[n];
memset (pl, 0, sizeof(*pl));
if (j)
{
pl->normal[i] = -1;
pl->dist = -bounds[j][i];
}
else
{
pl->normal[i] = 1;
pl->dist = bounds[j][i];
}
p->planenum = FindPlane (pl, &side);
p->winding = BaseWindingForPlane (pl);
if (side)
AddPortalToNodes (p, &outside_node, node);
else
AddPortalToNodes (p, node, &outside_node);
}
// clip the basewindings by all the other planes
for (i=0 ; i<6 ; i++)
{
for (j=0 ; j<6 ; j++)
{
if (j == i)
continue;
portals[i]->winding = ClipWinding (portals[i]->winding, &bplanes[j], true);
}
}
}
//============================================================================
void CheckWindingInNode (winding_t *w, node_t *node)
{
int i, j;
for (i=0 ; i<w->numpoints ; i++)
{
for (j=0 ; j<3 ; j++)
if (w->points[i][j] < node->mins[j] - 1
|| w->points[i][j] > node->maxs[j] + 1)
{
printf ("WARNING: CheckWindingInNode: outside\n");
return;
}
}
}
void CheckWindingArea (winding_t *w)
{
int i;
float total, add;
vec3_t v1, v2, cross;
total = 0;
for (i=1 ; i<w->numpoints ; i++)
{
VectorSubtract (w->points[i], w->points[0], v1);
VectorSubtract (w->points[i+1], w->points[0], v2);
CrossProduct (v1, v2, cross);
add = VectorLength (cross);
total += add*0.5;
}
if (total < 16)
printf ("WARNING: winding area %f\n", total);
}
void PlaneFromWinding (winding_t *w, plane_t *plane)
{
vec3_t v1, v2;
// calc plane
VectorSubtract (w->points[2], w->points[1], v1);
VectorSubtract (w->points[0], w->points[1], v2);
CrossProduct (v2, v1, plane->normal);
VectorNormalize (plane->normal);
plane->dist = DotProduct (w->points[0], plane->normal);
}
void CheckLeafPortalConsistancy (node_t *node)
{
int side, side2;
portal_t *p, *p2;
plane_t plane, plane2;
int i;
winding_t *w;
float dist;
side = side2 = 0; // quiet compiler warning
for (p = node->portals ; p ; p = p->next[side])
{
if (p->nodes[0] == node)
side = 0;
else if (p->nodes[1] == node)
side = 1;
else
Error ("CutNodePortals_r: mislinked portal");
CheckWindingInNode (p->winding, node);
CheckWindingArea (p->winding);
// check that the side orders are correct
plane = planes[p->planenum];
PlaneFromWinding (p->winding, &plane2);
for (p2 = node->portals ; p2 ; p2 = p2->next[side2])
{
if (p2->nodes[0] == node)
side2 = 0;
else if (p2->nodes[1] == node)
side2 = 1;
else
Error ("CutNodePortals_r: mislinked portal");
w = p2->winding;
for (i=0 ; i<w->numpoints ; i++)
{
dist = DotProduct (w->points[i], plane.normal) - plane.dist;
if ( (side == 0 && dist < -1) || (side == 1 && dist > 1) )
{
printf ("WARNING: portal siding direction is wrong\n");
return;
}
}
}
}
}
/*
================
CutNodePortals_r
================
*/
void CutNodePortals_r (node_t *node)
{
plane_t *plane, clipplane;
node_t *f, *b, *other_node;
portal_t *p, *new_portal, *next_portal;
winding_t *w, *frontwinding, *backwinding;
int side;
// CheckLeafPortalConsistancy (node);
//
// seperate the portals on node into it's children
//
if (node->contents)
{
return; // at a leaf, no more dividing
}
plane = &planes[node->planenum];
f = node->children[0];
b = node->children[1];
//
// create the new portal by taking the full plane winding for the cutting plane
// and clipping it by all of the planes from the other portals
//
new_portal = AllocPortal ();
new_portal->planenum = node->planenum;
w = BaseWindingForPlane (&planes[node->planenum]);
side = 0; // shut up compiler warning
for (p = node->portals ; p ; p = p->next[side])
{
clipplane = planes[p->planenum];
if (p->nodes[0] == node)
side = 0;
else if (p->nodes[1] == node)
{
clipplane.dist = -clipplane.dist;
VectorSubtract (vec3_origin, clipplane.normal, clipplane.normal);
side = 1;
}
else
Error ("CutNodePortals_r: mislinked portal");
w = ClipWinding (w, &clipplane, true);
if (!w)
{
printf ("WARNING: CutNodePortals_r:new portal was clipped away\n");
break;
}
}
if (w)
{
// if the plane was not clipped on all sides, there was an error
new_portal->winding = w;
AddPortalToNodes (new_portal, f, b);
}
//
// partition the portals
//
for (p = node->portals ; p ; p = next_portal)
{
if (p->nodes[0] == node)
side = 0;
else if (p->nodes[1] == node)
side = 1;
else
Error ("CutNodePortals_r: mislinked portal");
next_portal = p->next[side];
other_node = p->nodes[!side];
RemovePortalFromNode (p, p->nodes[0]);
RemovePortalFromNode (p, p->nodes[1]);
//
// cut the portal into two portals, one on each side of the cut plane
//
DivideWinding (p->winding, plane, &frontwinding, &backwinding);
if (!frontwinding)
{
if (side == 0)
AddPortalToNodes (p, b, other_node);
else
AddPortalToNodes (p, other_node, b);
continue;
}
if (!backwinding)
{
if (side == 0)
AddPortalToNodes (p, f, other_node);
else
AddPortalToNodes (p, other_node, f);
continue;
}
// the winding is split
new_portal = AllocPortal ();
*new_portal = *p;
new_portal->winding = backwinding;
FreeWinding (p->winding);
p->winding = frontwinding;
if (side == 0)
{
AddPortalToNodes (p, f, other_node);
AddPortalToNodes (new_portal, b, other_node);
}
else
{
AddPortalToNodes (p, other_node, f);
AddPortalToNodes (new_portal, other_node, b);
}
}
DrawLeaf (f,1);
DrawLeaf (b,2);
CutNodePortals_r (f);
CutNodePortals_r (b);
}
/*
==================
PortalizeWorld
Builds the exact polyhedrons for the nodes and leafs
==================
*/
void PortalizeWorld (node_t *headnode)
{
qprintf ("----- portalize ----\n");
MakeHeadnodePortals (headnode);
CutNodePortals_r (headnode);
}
/*
==================
FreeAllPortals
==================
*/
void FreeAllPortals (node_t *node)
{
portal_t *p, *nextp;
if (!node->contents)
{
FreeAllPortals (node->children[0]);
FreeAllPortals (node->children[1]);
}
for (p=node->portals ; p ; p=nextp)
{
if (p->nodes[0] == node)
nextp = p->next[0];
else
nextp = p->next[1];
RemovePortalFromNode (p, p->nodes[0]);
RemovePortalFromNode (p, p->nodes[1]);
FreeWinding (p->winding);
FreePortal (p);
}
}
/*
==============================================================================
PORTAL FILE GENERATION
==============================================================================
*/
#define PORTALFILE "PRT1"
FILE *pf;
int num_visleafs; // leafs the player can be in
int num_visportals;
void WriteFloat (FILE *f, vec_t v)
{
if ( fabs(v - Q_rint(v)) < 0.001 )
fprintf (f,"%i ",(int)Q_rint(v));
else
fprintf (f,"%f ",v);
}
void WritePortalFile_r (node_t *node)
{
int i;
portal_t *p;
winding_t *w;
plane_t *pl, plane2;
if (!node->contents)
{
WritePortalFile_r (node->children[0]);
WritePortalFile_r (node->children[1]);
return;
}
if (node->contents == CONTENTS_SOLID)
return;
for (p = node->portals ; p ; )
{
w = p->winding;
if (w && p->nodes[0] == node
&& p->nodes[0]->contents == p->nodes[1]->contents)
{
// write out to the file
// sometimes planes get turned around when they are very near
// the changeover point between different axis. interpret the
// plane the same way vis will, and flip the side orders if needed
pl = &planes[p->planenum];
PlaneFromWinding (w, &plane2);
if ( DotProduct (pl->normal, plane2.normal) < 0.99 )
{ // backwards...
fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[1]->visleafnum, p->nodes[0]->visleafnum);
}
else
fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[0]->visleafnum, p->nodes[1]->visleafnum);
for (i=0 ; i<w->numpoints ; i++)
{
fprintf (pf,"(");
WriteFloat (pf, w->points[i][0]);
WriteFloat (pf, w->points[i][1]);
WriteFloat (pf, w->points[i][2]);
fprintf (pf,") ");
}
fprintf (pf,"\n");
}
if (p->nodes[0] == node)
p = p->next[0];
else
p = p->next[1];
}
}
/*
================
NumberLeafs_r
================
*/
void NumberLeafs_r (node_t *node)
{
portal_t *p;
if (!node->contents)
{ // decision node
node->visleafnum = -99;
NumberLeafs_r (node->children[0]);
NumberLeafs_r (node->children[1]);
return;
}
Draw_ClearWindow ();
DrawLeaf (node, 1);
if (node->contents == CONTENTS_SOLID)
{ // solid block, viewpoint never inside
node->visleafnum = -1;
return;
}
node->visleafnum = num_visleafs++;
for (p = node->portals ; p ; )
{
if (p->nodes[0] == node) // only write out from first leaf
{
if (p->nodes[0]->contents == p->nodes[1]->contents)
num_visportals++;
p = p->next[0];
}
else
p = p->next[1];
}
}
/*
================
WritePortalfile
================
*/
void WritePortalfile (node_t *headnode)
{
// set the visleafnum field in every leaf and count the total number of portals
num_visleafs = 0;
num_visportals = 0;
NumberLeafs_r (headnode);
// write the file
printf ("writing %s\n", portfilename);
pf = fopen (portfilename, "w");
if (!pf)
Error ("Error opening %s", portfilename);
fprintf (pf, "%s\n", PORTALFILE);
fprintf (pf, "%i\n", num_visleafs);
fprintf (pf, "%i\n", num_visportals);
WritePortalFile_r (headnode);
fclose (pf);
}

1030
qutils/QBSP/QBSP.C Normal file

File diff suppressed because it is too large Load Diff

527
qutils/QBSP/QBSP.MAK Normal file
View File

@@ -0,0 +1,527 @@
# Microsoft Developer Studio Generated NMAKE File, Format Version 4.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
!IF "$(CFG)" == ""
CFG=qbsp - Win32 Debug
!MESSAGE No configuration specified. Defaulting to qbsp - Win32 Debug.
!ENDIF
!IF "$(CFG)" != "qbsp - Win32 Release" && "$(CFG)" != "qbsp - Win32 Debug"
!MESSAGE Invalid configuration "$(CFG)" specified.
!MESSAGE You can specify a configuration when running NMAKE on this makefile
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "qbsp.mak" CFG="qbsp - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "qbsp - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "qbsp - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
!ERROR An invalid configuration is specified.
!ENDIF
!IF "$(OS)" == "Windows_NT"
NULL=
!ELSE
NULL=nul
!ENDIF
################################################################################
# Begin Project
# PROP Target_Last_Scanned "qbsp - Win32 Debug"
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "qbsp - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
OUTDIR=.\Release
INTDIR=.\Release
ALL : "$(OUTDIR)\qbsp.exe"
CLEAN :
-@erase ".\Release\qbsp.exe"
-@erase ".\Release\mathlib.obj"
-@erase ".\Release\solidbsp.obj"
-@erase ".\Release\portals.obj"
-@erase ".\Release\surfaces.obj"
-@erase ".\Release\nodraw.obj"
-@erase ".\Release\cmdlib.obj"
-@erase ".\Release\csg4.obj"
-@erase ".\Release\brush.obj"
-@erase ".\Release\merge.obj"
-@erase ".\Release\map.obj"
-@erase ".\Release\region.obj"
-@erase ".\Release\bspfile.obj"
-@erase ".\Release\writebsp.obj"
-@erase ".\Release\outside.obj"
-@erase ".\Release\qbsp.obj"
-@erase ".\Release\tjunc.obj"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
# ADD CPP /nologo /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
CPP_PROJ=/nologo /ML /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\
"_CONSOLE" /Fp"$(INTDIR)/qbsp.pch" /YX /Fo"$(INTDIR)/" /c
CPP_OBJS=.\Release/
CPP_SBRS=
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o"$(OUTDIR)/qbsp.bsc"
BSC32_SBRS=
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:console /incremental:no\
/pdb:"$(OUTDIR)/qbsp.pdb" /machine:I386 /out:"$(OUTDIR)/qbsp.exe"
LINK32_OBJS= \
".\Release\mathlib.obj" \
".\Release\solidbsp.obj" \
".\Release\portals.obj" \
".\Release\surfaces.obj" \
".\Release\nodraw.obj" \
".\Release\cmdlib.obj" \
".\Release\csg4.obj" \
".\Release\brush.obj" \
".\Release\merge.obj" \
".\Release\map.obj" \
".\Release\region.obj" \
".\Release\bspfile.obj" \
".\Release\writebsp.obj" \
".\Release\outside.obj" \
".\Release\qbsp.obj" \
".\Release\tjunc.obj"
"$(OUTDIR)\qbsp.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ELSEIF "$(CFG)" == "qbsp - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
OUTDIR=.\Debug
INTDIR=.\Debug
ALL : "$(OUTDIR)\qbsp.exe"
CLEAN :
-@erase ".\Debug\vc40.pdb"
-@erase ".\Debug\vc40.idb"
-@erase ".\Debug\qbsp.exe"
-@erase ".\Debug\region.obj"
-@erase ".\Debug\mathlib.obj"
-@erase ".\Debug\csg4.obj"
-@erase ".\Debug\portals.obj"
-@erase ".\Debug\surfaces.obj"
-@erase ".\Debug\tjunc.obj"
-@erase ".\Debug\nodraw.obj"
-@erase ".\Debug\outside.obj"
-@erase ".\Debug\map.obj"
-@erase ".\Debug\bspfile.obj"
-@erase ".\Debug\solidbsp.obj"
-@erase ".\Debug\brush.obj"
-@erase ".\Debug\merge.obj"
-@erase ".\Debug\qbsp.obj"
-@erase ".\Debug\cmdlib.obj"
-@erase ".\Debug\writebsp.obj"
-@erase ".\Debug\qbsp.ilk"
-@erase ".\Debug\qbsp.pdb"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
# ADD CPP /nologo /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
CPP_PROJ=/nologo /MLd /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D\
"_CONSOLE" /Fp"$(INTDIR)/qbsp.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
CPP_OBJS=.\Debug/
CPP_SBRS=
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o"$(OUTDIR)/qbsp.bsc"
BSC32_SBRS=
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:console /incremental:yes\
/pdb:"$(OUTDIR)/qbsp.pdb" /debug /machine:I386 /out:"$(OUTDIR)/qbsp.exe"
LINK32_OBJS= \
".\Debug\region.obj" \
".\Debug\mathlib.obj" \
".\Debug\csg4.obj" \
".\Debug\portals.obj" \
".\Debug\surfaces.obj" \
".\Debug\tjunc.obj" \
".\Debug\nodraw.obj" \
".\Debug\outside.obj" \
".\Debug\map.obj" \
".\Debug\bspfile.obj" \
".\Debug\solidbsp.obj" \
".\Debug\brush.obj" \
".\Debug\merge.obj" \
".\Debug\qbsp.obj" \
".\Debug\cmdlib.obj" \
".\Debug\writebsp.obj"
"$(OUTDIR)\qbsp.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ENDIF
.c{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.c{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
################################################################################
# Begin Target
# Name "qbsp - Win32 Release"
# Name "qbsp - Win32 Debug"
!IF "$(CFG)" == "qbsp - Win32 Release"
!ELSEIF "$(CFG)" == "qbsp - Win32 Debug"
!ENDIF
################################################################################
# Begin Source File
SOURCE=.\writebsp.c
DEP_CPP_WRITE=\
".\bsp5.h"\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
".\..\common\bspfile.h"\
".\map.h"\
"$(INTDIR)\writebsp.obj" : $(SOURCE) $(DEP_CPP_WRITE) "$(INTDIR)"
# End Source File
################################################################################
# Begin Source File
SOURCE=.\tjunc.c
DEP_CPP_TJUNC=\
".\bsp5.h"\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
".\..\common\bspfile.h"\
".\map.h"\
"$(INTDIR)\tjunc.obj" : $(SOURCE) $(DEP_CPP_TJUNC) "$(INTDIR)"
# End Source File
################################################################################
# Begin Source File
SOURCE=.\surfaces.c
DEP_CPP_SURFA=\
".\bsp5.h"\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
".\..\common\bspfile.h"\
".\map.h"\
"$(INTDIR)\surfaces.obj" : $(SOURCE) $(DEP_CPP_SURFA) "$(INTDIR)"
# End Source File
################################################################################
# Begin Source File
SOURCE=.\solidbsp.c
DEP_CPP_SOLID=\
".\bsp5.h"\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
".\..\common\bspfile.h"\
".\map.h"\
"$(INTDIR)\solidbsp.obj" : $(SOURCE) $(DEP_CPP_SOLID) "$(INTDIR)"
# End Source File
################################################################################
# Begin Source File
SOURCE=.\region.c
DEP_CPP_REGIO=\
".\bsp5.h"\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
".\..\common\bspfile.h"\
".\map.h"\
"$(INTDIR)\region.obj" : $(SOURCE) $(DEP_CPP_REGIO) "$(INTDIR)"
# End Source File
################################################################################
# Begin Source File
SOURCE=.\qbsp.c
DEP_CPP_QBSP_=\
".\bsp5.h"\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
".\..\common\bspfile.h"\
".\map.h"\
"$(INTDIR)\qbsp.obj" : $(SOURCE) $(DEP_CPP_QBSP_) "$(INTDIR)"
# End Source File
################################################################################
# Begin Source File
SOURCE=.\portals.c
DEP_CPP_PORTA=\
".\bsp5.h"\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
".\..\common\bspfile.h"\
".\map.h"\
"$(INTDIR)\portals.obj" : $(SOURCE) $(DEP_CPP_PORTA) "$(INTDIR)"
# End Source File
################################################################################
# Begin Source File
SOURCE=.\outside.c
DEP_CPP_OUTSI=\
".\bsp5.h"\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
".\..\common\bspfile.h"\
".\map.h"\
"$(INTDIR)\outside.obj" : $(SOURCE) $(DEP_CPP_OUTSI) "$(INTDIR)"
# End Source File
################################################################################
# Begin Source File
SOURCE=.\nodraw.c
DEP_CPP_NODRA=\
".\bsp5.h"\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
".\..\common\bspfile.h"\
".\map.h"\
"$(INTDIR)\nodraw.obj" : $(SOURCE) $(DEP_CPP_NODRA) "$(INTDIR)"
# End Source File
################################################################################
# Begin Source File
SOURCE=.\merge.c
DEP_CPP_MERGE=\
".\bsp5.h"\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
".\..\common\bspfile.h"\
".\map.h"\
"$(INTDIR)\merge.obj" : $(SOURCE) $(DEP_CPP_MERGE) "$(INTDIR)"
# End Source File
################################################################################
# Begin Source File
SOURCE=.\map.c
DEP_CPP_MAP_C=\
".\bsp5.h"\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
".\..\common\bspfile.h"\
".\map.h"\
"$(INTDIR)\map.obj" : $(SOURCE) $(DEP_CPP_MAP_C) "$(INTDIR)"
# End Source File
################################################################################
# Begin Source File
SOURCE=.\csg4.c
DEP_CPP_CSG4_=\
".\bsp5.h"\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
".\..\common\bspfile.h"\
".\map.h"\
"$(INTDIR)\csg4.obj" : $(SOURCE) $(DEP_CPP_CSG4_) "$(INTDIR)"
# End Source File
################################################################################
# Begin Source File
SOURCE=.\brush.c
DEP_CPP_BRUSH=\
".\bsp5.h"\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
".\..\common\bspfile.h"\
".\map.h"\
"$(INTDIR)\brush.obj" : $(SOURCE) $(DEP_CPP_BRUSH) "$(INTDIR)"
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\bspfile.c
DEP_CPP_BSPFI=\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
".\..\common\bspfile.h"\
"$(INTDIR)\bspfile.obj" : $(SOURCE) $(DEP_CPP_BSPFI) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\cmdlib.c
DEP_CPP_CMDLI=\
".\..\common\cmdlib.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
{$(INCLUDE)}"\sys\STAT.H"\
"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\mathlib.c
DEP_CPP_MATHL=\
".\..\common\cmdlib.h"\
".\..\common\mathlib.h"\
"$(INTDIR)\mathlib.obj" : $(SOURCE) $(DEP_CPP_MATHL) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\mathlib.h
!IF "$(CFG)" == "qbsp - Win32 Release"
!ELSEIF "$(CFG)" == "qbsp - Win32 Debug"
!ENDIF
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\cmdlib.h
!IF "$(CFG)" == "qbsp - Win32 Release"
!ELSEIF "$(CFG)" == "qbsp - Win32 Debug"
!ENDIF
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\bspfile.h
!IF "$(CFG)" == "qbsp - Win32 Release"
!ELSEIF "$(CFG)" == "qbsp - Win32 Debug"
!ENDIF
# End Source File
# End Target
# End Project
################################################################################

BIN
qutils/QBSP/QBSP.MDP Normal file

Binary file not shown.

BIN
qutils/QBSP/QBSP.NCB Normal file

Binary file not shown.

511
qutils/QBSP/REGION.C Normal file
View File

@@ -0,0 +1,511 @@
// region.h
#include "bsp5.h"
/*
input
-----
vertexes
edges
faces
output
------
smaller set of vertexes
smaller set of edges
regions
? triangulated regions
face to region mapping numbers
*/
#define MAX_EDGES_IN_REGION 32
int firstedge;
vec3_t region_mins, region_maxs;
void AddPointToRegion (vec3_t p)
{
int i;
for (i=0 ; i<3 ; i++)
{
if (p[i] < region_mins[i])
region_mins[i] = p[i];
if (p[i] > region_maxs[i])
region_maxs[i] = p[i];
}
}
void ClearRegionSize (void)
{
region_mins[0] = region_mins[1] = region_mins[2] = 9999;
region_maxs[0] = region_maxs[1] = region_maxs[2] = -9999;
}
void AddFaceToRegionSize (face_t *f)
{
int i;
for (i=0 ; i<f->numpoints ; i++)
AddPointToRegion (f->pts[i]);
}
/*
==============
CanJoinFaces
==============
*/
qboolean CanJoinFaces (face_t *f, face_t *f2)
{
vec3_t oldmins, oldmaxs;
int i;
if (f2->planenum != f->planenum
|| f2->planeside != f->planeside
|| f2->texturenum != f->texturenum)
return false;
if (f2->outputnumber != -1)
return false;
if (f2->contents[0] != f->contents[0])
{ // does this ever happen? theyy shouldn't share.
printf ("CanJoinFaces: edge with different contents");
return false;
}
// check size constraints
if ( ! (texinfo[f->texturenum].flags & TEX_SPECIAL) )
{
VectorCopy (region_mins, oldmins);
VectorCopy (region_maxs, oldmaxs);
AddFaceToRegionSize (f2);
for (i=0 ; i<3 ; i++)
{
if (region_maxs[i] - region_mins[i] > 240)
{
VectorCopy (oldmins, region_mins);
VectorCopy (oldmaxs, region_maxs);
return false;
}
}
}
else
{
if (numsurfedges - firstedge + f2->numpoints > MAX_EDGES_IN_REGION)
return false; // a huge water or sky polygon
}
// check edge count constraints
return true;
}
/*
==============
RecursiveGrowRegion
==============
*/
void RecursiveGrowRegion (dface_t *r, face_t *f)
{
int e;
face_t *f2;
int i;
if (f->outputnumber == numfaces)
return;
if (f->outputnumber != -1)
Error ("RecursiveGrowRegion: region collision");
f->outputnumber = numfaces;
// add edges
for (i=0 ; i<f->numpoints ; i++)
{
e = f->edges[i];
if (!edgefaces[abs(e)][0])
continue; // edge has allready been removed
if (e > 0)
f2 = edgefaces[e][1];
else
f2 = edgefaces[-e][0];
if (f2 && f2->outputnumber == numfaces)
{
edgefaces[abs(e)][0] = NULL;
edgefaces[abs(e)][1] = NULL;
continue; // allready merged
}
if (f2 && CanJoinFaces (f, f2))
{ // remove the edge and merge the faces
edgefaces[abs(e)][0] = NULL;
edgefaces[abs(e)][1] = NULL;
RecursiveGrowRegion (r, f2);
}
else
{
// emit a surfedge
if (numsurfedges == MAX_MAP_SURFEDGES)
Error ("numsurfedges == MAX_MAP_SURFEDGES");
dsurfedges[numsurfedges] = e;
numsurfedges++;
}
}
}
void PrintDface (int f)
{ // for debugging
dface_t *df;
dedge_t *e;
int i, n;
df = &dfaces[f];
for (i=0 ; i<df->numedges ; i++)
{
n = dsurfedges[df->firstedge+i];
e = &dedges[abs(n)];
if (n < 0)
printf ("%5i = %5i : %5i\n", n, e->v[1], e->v[0]);
else
printf ("%5i = %5i : %5i\n", n, e->v[0], e->v[1]);
}
}
void FindVertexUse (int v)
{ // for debugging
int i, j, n;
dface_t *df;
dedge_t *e;
for (i=firstmodelface ; i<numfaces ; i++)
{
df = &dfaces[i];
for (j=0 ; j<df->numedges ; j++)
{
n = dsurfedges[df->firstedge+j];
e = &dedges[abs(n)];
if (e->v[0] == v || e->v[1] == v)
{
printf ("on face %i\n", i);
break;
}
}
}
}
void FindEdgeUse (int v)
{ // for debugging
int i, j, n;
dface_t *df;
for (i=firstmodelface ; i<numfaces ; i++)
{
df = &dfaces[i];
for (j=0 ; j<df->numedges ; j++)
{
n = dsurfedges[df->firstedge+j];
if (n == v || -n == v)
{
printf ("on face %i\n", i);
break;
}
}
}
}
/*
================
HealEdges
Extends e1 so that it goes all the way to e2, and removes all references
to e2
================
*/
int edgemapping[MAX_MAP_EDGES];
void HealEdges (int e1, int e2)
{
int i, j, n, saved;
dface_t *df;
dedge_t *ed, *ed2;
vec3_t v1, v2;
dface_t *found[2];
int foundj[2];
return;
e1 = edgemapping[e1];
e2 = edgemapping[e2];
// extend e1 to e2
ed = &dedges[e1];
ed2 = &dedges[e2];
VectorSubtract (dvertexes[ed->v[1]].point, dvertexes[ed->v[0]].point, v1);
VectorNormalize (v1);
if (ed->v[0] == ed2->v[0])
ed->v[0] = ed2->v[1];
else if (ed->v[0] == ed2->v[1])
ed->v[0] = ed2->v[0];
else if (ed->v[1] == ed2->v[0])
ed->v[1] = ed2->v[1];
else if (ed->v[1] == ed2->v[1])
ed->v[1] = ed2->v[0];
else
Error ("HealEdges: edges don't meet");
VectorSubtract (dvertexes[ed->v[1]].point, dvertexes[ed->v[0]].point, v2);
VectorNormalize (v2);
if (!VectorCompare (v1, v2))
Error ("HealEdges: edges not colinear");
edgemapping[e2] = e1;
saved = 0;
// remove all uses of e2
for (i=firstmodelface ; i<numfaces ; i++)
{
df = &dfaces[i];
for (j=0 ; j<df->numedges ; j++)
{
n = dsurfedges[df->firstedge+j];
if (n == e2 || n == -e2)
{
found[saved] = df;
foundj[saved] = j;
saved++;
break;
}
}
}
if (saved != 2)
printf ("WARNING: didn't find both faces for a saved edge\n");
else
{
for (i=0 ; i<2 ; i++)
{ // remove this edge
df = found[i];
j = foundj[i];
for (j++ ; j<df->numedges ; j++)
dsurfedges[df->firstedge+j-1] =
dsurfedges[df->firstedge+j];
dsurfedges[df->firstedge+j-1] = 0;
df->numedges--;
}
edgefaces[e2][0] = edgefaces[e2][1] = NULL;
}
}
typedef struct
{
int numedges;
int edges[2];
} checkpoint_t;
checkpoint_t checkpoints[MAX_MAP_VERTS];
/*
==============
RemoveColinearEdges
==============
*/
void RemoveColinearEdges (void)
{
int i,j, v;
int c0, c1, c2, c3;
checkpoint_t *cp;
// no edges remapped yet
for (i=0 ; i<numedges ; i++)
edgemapping[i] = i;
// find vertexes that only have two edges
memset (checkpoints, 0, sizeof(checkpoints));
for (i=firstmodeledge ; i<numedges ; i++)
{
if (!edgefaces[i][0])
continue; // removed
for (j=0 ; j<2 ; j++)
{
v = dedges[i].v[j];
cp = &checkpoints[v];
if (cp->numedges<2)
cp->edges[cp->numedges] = i;
cp->numedges++;
}
}
// if a vertex only has two edges and they are colinear, it can be removed
c0 = c1 = c2 = c3 = 0;
for (i=0 ; i<numvertexes ; i++)
{
cp = &checkpoints[i];
switch (cp->numedges)
{
case 0:
c0++;
break;
case 1:
c1++;
break;
case 2:
c2++;
HealEdges (cp->edges[0], cp->edges[1]);
break;
default:
c3++;
break;
}
}
// qprintf ("%5i c0\n", c0);
// qprintf ("%5i c1\n", c1);
// qprintf ("%5i c2\n", c2);
// qprintf ("%5i c3+\n", c3);
qprintf ("%5i deges removed by tjunction healing\n", c2);
}
/*
==============
CountRealNumbers
==============
*/
void CountRealNumbers (void)
{
int i;
int c;
qprintf ("%5i regions\n", numfaces-firstmodelface);
c = 0;
for (i=firstmodelface ; i<numfaces ; i++)
c += dfaces[i].numedges;
qprintf ("%5i real marksurfaces\n", c);
c = 0;
for (i=firstmodeledge ; i<numedges ; i++)
if (edgefaces[i][0])
c++; // not removed
qprintf ("%5i real edges\n", c);
}
//=============================================================================
/*
==============
GrowNodeRegion_r
==============
*/
void GrowNodeRegion_r (node_t *node)
{
dface_t *r;
face_t *f;
int i;
if (node->planenum == PLANENUM_LEAF)
return;
node->firstface = numfaces;
for (f=node->faces ; f ; f=f->next)
{
// if (f->outputnumber != -1)
// continue; // allready grown into an earlier region
// emit a region
if (numfaces == MAX_MAP_FACES)
Error ("MAX_MAP_FACES");
f->outputnumber = numfaces;
r = &dfaces[numfaces];
r->planenum = node->outputplanenum;
r->side = f->planeside;
r->texinfo = f->texturenum;
for (i=0 ; i<MAXLIGHTMAPS ; i++)
r->styles[i] = 255;
r->lightofs = -1;
// add the face and mergable neighbors to it
#if 0
ClearRegionSize ();
AddFaceToRegionSize (f);
RecursiveGrowRegion (r, f);
#endif
r->firstedge = firstedge = numsurfedges;
for (i=0 ; i<f->numpoints ; i++)
{
if (numsurfedges == MAX_MAP_SURFEDGES)
Error ("numsurfedges == MAX_MAP_SURFEDGES");
dsurfedges[numsurfedges] = f->edges[i];
numsurfedges++;
}
r->numedges = numsurfedges - r->firstedge;
numfaces++;
}
node->numfaces = numfaces - node->firstface;
GrowNodeRegion_r (node->children[0]);
GrowNodeRegion_r (node->children[1]);
}
/*
==============
GrowNodeRegions
==============
*/
void GrowNodeRegions (node_t *headnode)
{
qprintf ("---- GrowRegions ----\n");
GrowNodeRegion_r (headnode);
//RemoveColinearEdges ();
CountRealNumbers ();
}
/*
===============================================================================
Turn the faces on a plane into optimal non-convex regions
The edges may still be split later as a result of tjunctions
typedef struct
{
vec3_t dir;
vec3_t origin;
vec3_t p[2];
}
for all faces
for all edges
for all edges so far
if overlap
split
===============================================================================
*/

754
qutils/QBSP/SOLIDBSP.C Normal file
View File

@@ -0,0 +1,754 @@
// solidbsp.c
#include "bsp5.h"
int leaffaces;
int nodefaces;
int splitnodes;
int c_solid, c_empty, c_water;
qboolean usemidsplit;
//============================================================================
/*
==================
FaceSide
For BSP hueristic
==================
*/
int FaceSide (face_t *in, plane_t *split)
{
int frontcount, backcount;
vec_t dot;
int i;
vec_t *p;
frontcount = backcount = 0;
// axial planes are fast
if (split->type < 3)
for (i=0, p = in->pts[0]+split->type ; i<in->numpoints ; i++, p+=3)
{
if (*p > split->dist + ON_EPSILON)
{
if (backcount)
return SIDE_ON;
frontcount = 1;
}
else if (*p < split->dist - ON_EPSILON)
{
if (frontcount)
return SIDE_ON;
backcount = 1;
}
}
else
// sloping planes take longer
for (i=0, p = in->pts[0] ; i<in->numpoints ; i++, p+=3)
{
dot = DotProduct (p, split->normal);
dot -= split->dist;
if (dot > ON_EPSILON)
{
if (backcount)
return SIDE_ON;
frontcount = 1;
}
else if (dot < -ON_EPSILON)
{
if (frontcount)
return SIDE_ON;
backcount = 1;
}
}
if (!frontcount)
return SIDE_BACK;
if (!backcount)
return SIDE_FRONT;
return SIDE_ON;
}
/*
==================
ChooseMidPlaneFromList
The clipping hull BSP doesn't worry about avoiding splits
==================
*/
surface_t *ChooseMidPlaneFromList (surface_t *surfaces, vec3_t mins, vec3_t maxs)
{
int j,l;
surface_t *p, *bestsurface;
vec_t bestvalue, value, dist;
plane_t *plane;
//
// pick the plane that splits the least
//
bestvalue = 6*8192*8192;
bestsurface = NULL;
for (p=surfaces ; p ; p=p->next)
{
if (p->onnode)
continue;
plane = &planes[p->planenum];
// check for axis aligned surfaces
l = plane->type;
if (l > PLANE_Z)
continue;
//
// calculate the split metric along axis l, smaller values are better
//
value = 0;
dist = plane->dist * plane->normal[l];
for (j=0 ; j<3 ; j++)
{
if (j == l)
{
value += (maxs[l]-dist)*(maxs[l]-dist);
value += (dist-mins[l])*(dist-mins[l]);
}
else
value += 2*(maxs[j]-mins[j])*(maxs[j]-mins[j]);
}
if (value > bestvalue)
continue;
//
// currently the best!
//
bestvalue = value;
bestsurface = p;
}
if (!bestsurface)
{
for (p=surfaces ; p ; p=p->next)
if (!p->onnode)
return p; // first valid surface
Error ("ChooseMidPlaneFromList: no valid planes");
}
return bestsurface;
}
/*
==================
ChoosePlaneFromList
The real BSP hueristic
==================
*/
surface_t *ChoosePlaneFromList (surface_t *surfaces, vec3_t mins, vec3_t maxs, qboolean usefloors)
{
int j,k,l;
surface_t *p, *p2, *bestsurface;
vec_t bestvalue, bestdistribution, value, dist;
plane_t *plane;
face_t *f;
//
// pick the plane that splits the least
//
bestvalue = 99999;
bestsurface = NULL;
bestdistribution = 9e30;
for (p=surfaces ; p ; p=p->next)
{
if (p->onnode)
continue;
plane = &planes[p->planenum];
k = 0;
if (!usefloors && plane->normal[2] == 1)
continue;
for (p2=surfaces ; p2 ; p2=p2->next)
{
if (p2 == p)
continue;
if (p2->onnode)
continue;
for (f=p2->faces ; f ; f=f->next)
{
if (FaceSide (f, plane) == SIDE_ON)
{
k++;
if (k >= bestvalue)
break;
}
}
if (k > bestvalue)
break;
}
if (k > bestvalue)
continue;
// if equal numbers, axial planes win, then decide on spatial subdivision
if (k < bestvalue || (k == bestvalue && plane->type < PLANE_ANYX) )
{
// check for axis aligned surfaces
l = plane->type;
if (l <= PLANE_Z)
{ // axial aligned
//
// calculate the split metric along axis l
//
value = 0;
for (j=0 ; j<3 ; j++)
{
if (j == l)
{
dist = plane->dist * plane->normal[l];
value += (maxs[l]-dist)*(maxs[l]-dist);
value += (dist-mins[l])*(dist-mins[l]);
}
else
value += 2*(maxs[j]-mins[j])*(maxs[j]-mins[j]);
}
if (value > bestdistribution && k == bestvalue)
continue;
bestdistribution = value;
}
//
// currently the best!
//
bestvalue = k;
bestsurface = p;
}
}
return bestsurface;
}
/*
==================
SelectPartition
Selects a surface from a linked list of surfaces to split the group on
returns NULL if the surface list can not be divided any more (a leaf)
==================
*/
surface_t *SelectPartition (surface_t *surfaces)
{
int i,j;
vec3_t mins, maxs;
surface_t *p, *bestsurface;
//
// count onnode surfaces
//
i = 0;
bestsurface = NULL;
for (p=surfaces ; p ; p=p->next)
if (!p->onnode)
{
i++;
bestsurface = p;
}
if (i==0)
return NULL;
if (i==1)
return bestsurface; // this is a final split
//
// calculate a bounding box of the entire surfaceset
//
for (i=0 ; i<3 ; i++)
{
mins[i] = 99999;
maxs[i] = -99999;
}
for (p=surfaces ; p ; p=p->next)
for (j=0 ; j<3 ; j++)
{
if (p->mins[j] < mins[j])
mins[j] = p->mins[j];
if (p->maxs[j] > maxs[j])
maxs[j] = p->maxs[j];
}
if (usemidsplit) // do fast way for clipping hull
return ChooseMidPlaneFromList (surfaces, mins, maxs);
// do slow way to save poly splits for drawing hull
#if 0
bestsurface = ChoosePlaneFromList (surfaces, mins, maxs, false);
if (bestsurface)
return bestsurface;
#endif
return ChoosePlaneFromList (surfaces, mins, maxs, true);
}
//============================================================================
/*
=================
CalcSurfaceInfo
Calculates the bounding box
=================
*/
void CalcSurfaceInfo (surface_t *surf)
{
int i,j;
face_t *f;
if (!surf->faces)
Error ("CalcSurfaceInfo: surface without a face");
//
// calculate a bounding box
//
for (i=0 ; i<3 ; i++)
{
surf->mins[i] = 99999;
surf->maxs[i] = -99999;
}
for (f=surf->faces ; f ; f=f->next)
{
if (f->contents[0] >= 0 || f->contents[1] >= 0)
Error ("Bad contents");
for (i=0 ; i<f->numpoints ; i++)
for (j=0 ; j<3 ; j++)
{
if (f->pts[i][j] < surf->mins[j])
surf->mins[j] = f->pts[i][j];
if (f->pts[i][j] > surf->maxs[j])
surf->maxs[j] = f->pts[i][j];
}
}
}
/*
==================
DividePlane
==================
*/
void DividePlane (surface_t *in, plane_t *split, surface_t **front, surface_t **back)
{
face_t *facet, *next;
face_t *frontlist, *backlist;
face_t *frontfrag, *backfrag;
surface_t *news;
plane_t *inplane;
inplane = &planes[in->planenum];
// parallel case is easy
if (VectorCompare (inplane->normal, split->normal))
{
// check for exactly on node
if (inplane->dist == split->dist)
{ // divide the facets to the front and back sides
news = AllocSurface ();
*news = *in;
facet=in->faces;
in->faces = NULL;
news->faces = NULL;
in->onnode = news->onnode = true;
for ( ; facet ; facet=next)
{
next = facet->next;
if (facet->planeside == 1)
{
facet->next = news->faces;
news->faces = facet;
}
else
{
facet->next = in->faces;
in->faces = facet;
}
}
if (in->faces)
*front = in;
else
*front = NULL;
if (news->faces)
*back = news;
else
*back = NULL;
return;
}
if (inplane->dist > split->dist)
{
*front = in;
*back = NULL;
}
else
{
*front = NULL;
*back = in;
}
return;
}
// do a real split. may still end up entirely on one side
// OPTIMIZE: use bounding box for fast test
frontlist = NULL;
backlist = NULL;
for (facet = in->faces ; facet ; facet = next)
{
next = facet->next;
SplitFace (facet, split, &frontfrag, &backfrag);
if (frontfrag)
{
frontfrag->next = frontlist;
frontlist = frontfrag;
}
if (backfrag)
{
backfrag->next = backlist;
backlist = backfrag;
}
}
// if nothing actually got split, just move the in plane
if (frontlist == NULL)
{
*front = NULL;
*back = in;
in->faces = backlist;
return;
}
if (backlist == NULL)
{
*front = in;
*back = NULL;
in->faces = frontlist;
return;
}
// stuff got split, so allocate one new plane and reuse in
news = AllocSurface ();
*news = *in;
news->faces = backlist;
*back = news;
in->faces = frontlist;
*front = in;
// recalc bboxes and flags
CalcSurfaceInfo (news);
CalcSurfaceInfo (in);
}
/*
==================
DivideNodeBounds
==================
*/
void DivideNodeBounds (node_t *node, plane_t *split)
{
VectorCopy (node->mins, node->children[0]->mins);
VectorCopy (node->mins, node->children[1]->mins);
VectorCopy (node->maxs, node->children[0]->maxs);
VectorCopy (node->maxs, node->children[1]->maxs);
// OPTIMIZE: sloping cuts can give a better bbox than this...
if (split->type > 2)
return;
node->children[0]->mins[split->type] =
node->children[1]->maxs[split->type] = split->dist;
}
/*
==================
LinkConvexFaces
Determines the contents of the leaf and creates the final list of
original faces that have some fragment inside this leaf
==================
*/
void LinkConvexFaces (surface_t *planelist, node_t *leafnode)
{
face_t *f, *next;
surface_t *surf, *pnext;
int i, count;
leafnode->faces = NULL;
leafnode->contents = 0;
leafnode->planenum = -1;
count = 0;
for ( surf = planelist ; surf ; surf = surf->next)
{
for (f = surf->faces ; f ; f=f->next)
{
count++;
if (!leafnode->contents)
leafnode->contents = f->contents[0];
else if (leafnode->contents != f->contents[0])
Error ("Mixed face contents in leafnode");
}
}
if (!leafnode->contents)
leafnode->contents = CONTENTS_SOLID;
switch (leafnode->contents)
{
case CONTENTS_EMPTY:
c_empty++;
break;
case CONTENTS_SOLID:
c_solid++;
break;
case CONTENTS_WATER:
case CONTENTS_SLIME:
case CONTENTS_LAVA:
case CONTENTS_SKY:
c_water++;
break;
default:
Error ("LinkConvexFaces: bad contents number");
}
//
// write the list of faces, and free the originals
//
leaffaces += count;
leafnode->markfaces = malloc(sizeof(face_t *)*(count+1));
i = 0;
for ( surf = planelist ; surf ; surf = pnext)
{
pnext = surf->next;
for (f = surf->faces ; f ; f=next)
{
next = f->next;
leafnode->markfaces[i] = f->original;
i++;
FreeFace (f);
}
FreeSurface (surf);
}
leafnode->markfaces[i] = NULL; // sentinal
}
/*
==================
LinkNodeFaces
Returns a duplicated list of all faces on surface
==================
*/
face_t *LinkNodeFaces (surface_t *surface)
{
face_t *f, *new, **prevptr;
face_t *list;
list = NULL;
// subdivide
prevptr = &surface->faces;
while (1)
{
f = *prevptr;
if (!f)
break;
SubdivideFace (f, prevptr);
f = *prevptr;
prevptr = &f->next;
}
// copy
for (f=surface->faces ; f ; f=f->next)
{
nodefaces++;
new = AllocFace ();
*new = *f;
f->original = new;
new->next = list;
list = new;
}
return list;
}
/*
==================
PartitionSurfaces
==================
*/
void PartitionSurfaces (surface_t *surfaces, node_t *node)
{
surface_t *split, *p, *next;
surface_t *frontlist, *backlist;
surface_t *frontfrag, *backfrag;
plane_t *splitplane;
split = SelectPartition (surfaces);
if (!split)
{ // this is a leaf node
node->planenum = PLANENUM_LEAF;
LinkConvexFaces (surfaces, node);
return;
}
splitnodes++;
node->faces = LinkNodeFaces (split);
node->children[0] = AllocNode ();
node->children[1] = AllocNode ();
node->planenum = split->planenum;
splitplane = &planes[split->planenum];
DivideNodeBounds (node, splitplane);
//
// multiple surfaces, so split all the polysurfaces into front and back lists
//
frontlist = NULL;
backlist = NULL;
for (p=surfaces ; p ; p=next)
{
next = p->next;
DividePlane (p, splitplane, &frontfrag, &backfrag);
if (frontfrag && backfrag)
{
// the plane was split, which may expose oportunities to merge
// adjacent faces into a single face
// MergePlaneFaces (frontfrag);
// MergePlaneFaces (backfrag);
}
if (frontfrag)
{
if (!frontfrag->faces)
Error ("surface with no faces");
frontfrag->next = frontlist;
frontlist = frontfrag;
}
if (backfrag)
{
if (!backfrag->faces)
Error ("surface with no faces");
backfrag->next = backlist;
backlist = backfrag;
}
}
PartitionSurfaces (frontlist, node->children[0]);
PartitionSurfaces (backlist, node->children[1]);
}
/*
==================
DrawSurface
==================
*/
void DrawSurface (surface_t *surf)
{
face_t *f;
for (f=surf->faces ; f ; f=f->next)
Draw_DrawFace (f);
}
/*
==================
DrawSurfaceList
==================
*/
void DrawSurfaceList (surface_t *surf)
{
Draw_ClearWindow ();
while (surf)
{
DrawSurface (surf);
surf = surf->next;
}
}
/*
==================
SolidBSP
==================
*/
node_t *SolidBSP (surface_t *surfhead, qboolean midsplit)
{
int i;
node_t *headnode;
qprintf ("----- SolidBSP -----\n");
headnode = AllocNode ();
usemidsplit = midsplit;
//
// calculate a bounding box for the entire model
//
for (i=0 ; i<3 ; i++)
{
headnode->mins[i] = brushset->mins[i] - SIDESPACE;
headnode->maxs[i] = brushset->maxs[i] + SIDESPACE;
}
//
// recursively partition everything
//
Draw_ClearWindow ();
splitnodes = 0;
leaffaces = 0;
nodefaces = 0;
c_solid = c_empty = c_water = 0;
PartitionSurfaces (surfhead, headnode);
qprintf ("%5i split nodes\n", splitnodes);
qprintf ("%5i solid leafs\n", c_solid);
qprintf ("%5i empty leafs\n", c_empty);
qprintf ("%5i water leafs\n", c_water);
qprintf ("%5i leaffaces\n",leaffaces);
qprintf ("%5i nodefaces\n", nodefaces);
return headnode;
}

512
qutils/QBSP/SURFACES.C Normal file
View File

@@ -0,0 +1,512 @@
// divide.h
#include "bsp5.h"
surface_t newcopy_t;
/*
a surface has all of the faces that could be drawn on a given plane
the outside filling stage can remove some of them so a better bsp can be generated
*/
int subdivides;
/*
===============
SubdivideFace
If the face is >256 in either texture direction, carve a valid sized
piece off and insert the remainder in the next link
===============
*/
void SubdivideFace (face_t *f, face_t **prevptr)
{
float mins, maxs;
vec_t v;
int axis, i;
plane_t plane;
face_t *front, *back, *next;
texinfo_t *tex;
// special (non-surface cached) faces don't need subdivision
tex = &texinfo[f->texturenum];
if ( tex->flags & TEX_SPECIAL)
return;
for (axis = 0 ; axis < 2 ; axis++)
{
while (1)
{
mins = 9999;
maxs = -9999;
for (i=0 ; i<f->numpoints ; i++)
{
v = DotProduct (f->pts[i], tex->vecs[axis]);
if (v < mins)
mins = v;
if (v > maxs)
maxs = v;
}
if (maxs - mins <= subdivide_size)
break;
// split it
subdivides++;
VectorCopy (tex->vecs[axis], plane.normal);
v = VectorLength (plane.normal);
VectorNormalize (plane.normal);
plane.dist = (mins + subdivide_size - 16)/v;
next = f->next;
SplitFace (f, &plane, &front, &back);
if (!front || !back)
Error ("SubdivideFace: didn't split the polygon");
*prevptr = back;
back->next = front;
front->next = next;
f = back;
}
}
}
/*
================
SubdivideFaces
================
*/
void SubdivideFaces (surface_t *surfhead)
{
surface_t *surf;
face_t *f , **prevptr;
qprintf ("--- SubdivideFaces ---\n");
subdivides = 0;
for (surf = surfhead ; surf ; surf=surf->next)
{
prevptr = &surf->faces;
while (1)
{
f = *prevptr;
if (!f)
break;
SubdivideFace (f, prevptr);
f = *prevptr;
prevptr = &f->next;
}
}
qprintf ("%i faces added by subdivision\n", subdivides);
}
/*
=============================================================================
GatherNodeFaces
Frees the current node tree and returns a new chain of the surfaces that
have inside faces.
=============================================================================
*/
void GatherNodeFaces_r (node_t *node)
{
face_t *f, *next;
if (node->planenum != PLANENUM_LEAF)
{
//
// decision node
//
for (f=node->faces ; f ; f=next)
{
next = f->next;
if (!f->numpoints)
{ // face was removed outside
FreeFace (f);
}
else
{
f->next = validfaces[f->planenum];
validfaces[f->planenum] = f;
}
}
GatherNodeFaces_r (node->children[0]);
GatherNodeFaces_r (node->children[1]);
free (node);
}
else
{
//
// leaf node
//
free (node);
}
}
/*
================
GatherNodeFaces
================
*/
surface_t *GatherNodeFaces (node_t *headnode)
{
memset (validfaces, 0, sizeof(validfaces));
GatherNodeFaces_r (headnode);
return BuildSurfaces ();
}
//===========================================================================
typedef struct hashvert_s
{
struct hashvert_s *next;
vec3_t point;
int num;
int numplanes; // for corner determination
int planenums[2];
int numedges;
} hashvert_t;
#define POINT_EPSILON 0.01
int c_cornerverts;
hashvert_t hvertex[MAX_MAP_VERTS];
hashvert_t *hvert_p;
face_t *edgefaces[MAX_MAP_EDGES][2];
int firstmodeledge = 1;
int firstmodelface;
//============================================================================
#define NUM_HASH 4096
hashvert_t *hashverts[NUM_HASH];
static vec3_t hash_min, hash_scale;
static void InitHash (void)
{
vec3_t size;
vec_t volume;
vec_t scale;
int newsize[2];
int i;
memset (hashverts, 0, sizeof(hashverts));
for (i=0 ; i<3 ; i++)
{
hash_min[i] = -8000;
size[i] = 16000;
}
volume = size[0]*size[1];
scale = sqrt(volume / NUM_HASH);
newsize[0] = size[0] / scale;
newsize[1] = size[1] / scale;
hash_scale[0] = newsize[0] / size[0];
hash_scale[1] = newsize[1] / size[1];
hash_scale[2] = newsize[1];
hvert_p = hvertex;
}
static unsigned HashVec (vec3_t vec)
{
unsigned h;
h = hash_scale[0] * (vec[0] - hash_min[0]) * hash_scale[2]
+ hash_scale[1] * (vec[1] - hash_min[1]);
if ( h >= NUM_HASH)
return NUM_HASH - 1;
return h;
}
/*
=============
GetVertex
=============
*/
int GetVertex (vec3_t in, int planenum)
{
int h;
int i;
hashvert_t *hv;
vec3_t vert;
for (i=0 ; i<3 ; i++)
{
if ( fabs(in[i] - Q_rint(in[i])) < 0.001)
vert[i] = Q_rint(in[i]);
else
vert[i] = in[i];
}
h = HashVec (vert);
for (hv=hashverts[h] ; hv ; hv=hv->next)
{
if ( fabs(hv->point[0]-vert[0])<POINT_EPSILON
&& fabs(hv->point[1]-vert[1])<POINT_EPSILON
&& fabs(hv->point[2]-vert[2])<POINT_EPSILON )
{
hv->numedges++;
if (hv->numplanes == 3)
return hv->num; // allready known to be a corner
for (i=0 ; i<hv->numplanes ; i++)
if (hv->planenums[i] == planenum)
return hv->num; // allready know this plane
if (hv->numplanes == 2)
c_cornerverts++;
else
hv->planenums[hv->numplanes] = planenum;
hv->numplanes++;
return hv->num;
}
}
hv = hvert_p;
hv->numedges = 1;
hv->numplanes = 1;
hv->planenums[0] = planenum;
hv->next = hashverts[h];
hashverts[h] = hv;
VectorCopy (vert, hv->point);
hv->num = numvertexes;
if (hv->num==MAX_MAP_VERTS)
Error ("GetVertex: MAX_MAP_VERTS");
hvert_p++;
// emit a vertex
if (numvertexes == MAX_MAP_VERTS)
Error ("numvertexes == MAX_MAP_VERTS");
dvertexes[numvertexes].point[0] = vert[0];
dvertexes[numvertexes].point[1] = vert[1];
dvertexes[numvertexes].point[2] = vert[2];
numvertexes++;
return hv->num;
}
//===========================================================================
/*
==================
GetEdge
Don't allow four way edges
==================
*/
int c_tryedges;
int GetEdge (vec3_t p1, vec3_t p2, face_t *f)
{
int v1, v2;
dedge_t *edge;
int i;
if (!f->contents[0])
Error ("GetEdge: 0 contents");
c_tryedges++;
v1 = GetVertex (p1, f->planenum);
v2 = GetVertex (p2, f->planenum);
for (i=firstmodeledge ; i < numedges ; i++)
{
edge = &dedges[i];
if (v1 == edge->v[1] && v2 == edge->v[0]
&& !edgefaces[i][1]
&& edgefaces[i][0]->contents[0] == f->contents[0])
{
edgefaces[i][1] = f;
return -i;
}
}
// emit an edge
if (numedges == MAX_MAP_EDGES)
Error ("numedges == MAX_MAP_EDGES");
edge = &dedges[numedges];
numedges++;
edge->v[0] = v1;
edge->v[1] = v2;
edgefaces[i][0] = f;
return i;
}
/*
==================
FindFaceEdges
==================
*/
void FindFaceEdges (face_t *face)
{
int i;
face->outputnumber = -1;
if (face->numpoints > MAXEDGES)
Error ("WriteFace: %i points", face->numpoints);
for (i=0; i<face->numpoints ; i++)
face->edges[i] = GetEdge
(face->pts[i], face->pts[(i+1)%face->numpoints], face);
}
/*
=============
CheckVertexes
// debugging
=============
*/
void CheckVertexes (void)
{
int cb, c0, c1, c2, c3;
hashvert_t *hv;
cb = c0 = c1 = c2 = c3 = 0;
for (hv=hvertex ; hv!=hvert_p ; hv++)
{
if (hv->numedges < 0 || hv->numedges & 1)
cb++;
else if (!hv->numedges)
c0++;
else if (hv->numedges == 2)
c1++;
else if (hv->numedges == 4)
c2++;
else
c3++;
}
qprintf ("%5i bad edge points\n", cb);
qprintf ("%5i 0 edge points\n", c0);
qprintf ("%5i 2 edge points\n", c1);
qprintf ("%5i 4 edge points\n", c2);
qprintf ("%5i 6+ edge points\n", c3);
}
/*
=============
CheckEdges
// debugging
=============
*/
void CheckEdges (void)
{
dedge_t *edge;
int i;
dvertex_t *d1, *d2;
face_t *f1, *f2;
int c_nonconvex;
int c_multitexture;
c_nonconvex = c_multitexture = 0;
// CheckVertexes ();
for (i=1 ; i < numedges ; i++)
{
edge = &dedges[i];
if (!edgefaces[i][1])
{
d1 = &dvertexes[edge->v[0]];
d2 = &dvertexes[edge->v[1]];
qprintf ("unshared edge at: (%8.2f, %8.2f, %8.2f) (%8.2f, %8.2f, %8.2f)\n",d1->point[0], d1->point[1], d1->point[2], d2->point[0], d2->point[1], d2->point[2]);
}
else
{
f1 = edgefaces[i][0];
f2 = edgefaces[i][1];
if (f1->planeside != f2->planeside)
continue;
if (f1->planenum != f2->planenum)
continue;
// on the same plane, might be discardable
if (f1->texturenum == f2->texturenum)
{
hvertex[edge->v[0]].numedges-=2;
hvertex[edge->v[1]].numedges-=2;
c_nonconvex++;
}
else
c_multitexture++;
}
}
// qprintf ("%5i edges\n", i);
// qprintf ("%5i c_nonconvex\n", c_nonconvex);
// qprintf ("%5i c_multitexture\n", c_multitexture);
// CheckVertexes ();
}
/*
================
MakeFaceEdges_r
================
*/
void MakeFaceEdges_r (node_t *node)
{
face_t *f;
if (node->planenum == PLANENUM_LEAF)
return;
for (f=node->faces ; f ; f=f->next)
FindFaceEdges (f);
MakeFaceEdges_r (node->children[0]);
MakeFaceEdges_r (node->children[1]);
}
/*
================
MakeFaceEdges
================
*/
void MakeFaceEdges (node_t *headnode)
{
qprintf ("----- MakeFaceEdges -----\n");
InitHash ();
c_tryedges = 0;
c_cornerverts = 0;
MakeFaceEdges_r (headnode);
// CheckEdges ();
GrowNodeRegions (headnode);
firstmodeledge = numedges;
firstmodelface = numfaces;
}

506
qutils/QBSP/TJUNC.C Normal file
View File

@@ -0,0 +1,506 @@
// tjunc.c
#include "bsp5.h"
typedef struct wvert_s
{
vec_t t;
struct wvert_s *prev, *next;
} wvert_t;
typedef struct wedge_s
{
struct wedge_s *next;
vec3_t dir;
vec3_t origin;
wvert_t head;
} wedge_t;
int numwedges, numwverts;
int tjuncs;
int tjuncfaces;
#define MAXWVERTS 0x20000
#define MAXWEDGES 0x10000
wvert_t wverts[MAXWVERTS];
wedge_t wedges[MAXWEDGES];
void PrintFace (face_t *f)
{
int i;
for (i=0 ; i<f->numpoints ; i++)
printf ("(%5.2f, %5.2f, %5.2f)\n", f->pts[i][0], f->pts[i][1], f->pts[i][2]);
}
//============================================================================
#define NUM_HASH 1024
wedge_t *wedge_hash[NUM_HASH];
static vec3_t hash_min, hash_scale;
static void InitHash (vec3_t mins, vec3_t maxs)
{
vec3_t size;
vec_t volume;
vec_t scale;
int newsize[2];
VectorCopy (mins, hash_min);
VectorSubtract (maxs, mins, size);
memset (wedge_hash, 0, sizeof(wedge_hash));
volume = size[0]*size[1];
scale = sqrt(volume / NUM_HASH);
newsize[0] = size[0] / scale;
newsize[1] = size[1] / scale;
hash_scale[0] = newsize[0] / size[0];
hash_scale[1] = newsize[1] / size[1];
hash_scale[2] = newsize[1];
}
static unsigned HashVec (vec3_t vec)
{
unsigned h;
h = hash_scale[0] * (vec[0] - hash_min[0]) * hash_scale[2]
+ hash_scale[1] * (vec[1] - hash_min[1]);
if ( h >= NUM_HASH)
return NUM_HASH - 1;
return h;
}
//============================================================================
void CanonicalVector (vec3_t vec)
{
VectorNormalize (vec);
if (vec[0] > EQUAL_EPSILON)
return;
else if (vec[0] < -EQUAL_EPSILON)
{
VectorSubtract (vec3_origin, vec, vec);
return;
}
else
vec[0] = 0;
if (vec[1] > EQUAL_EPSILON)
return;
else if (vec[1] < -EQUAL_EPSILON)
{
VectorSubtract (vec3_origin, vec, vec);
return;
}
else
vec[1] = 0;
if (vec[2] > EQUAL_EPSILON)
return;
else if (vec[2] < -EQUAL_EPSILON)
{
VectorSubtract (vec3_origin, vec, vec);
return;
}
else
vec[2] = 0;
Error ("CanonicalVector: degenerate");
}
wedge_t *FindEdge (vec3_t p1, vec3_t p2, vec_t *t1, vec_t *t2)
{
vec3_t origin;
vec3_t dir;
wedge_t *w;
vec_t temp;
int h;
VectorSubtract (p2, p1, dir);
CanonicalVector (dir);
*t1 = DotProduct (p1, dir);
*t2 = DotProduct (p2, dir);
VectorMA (p1, -*t1, dir, origin);
if (*t1 > *t2)
{
temp = *t1;
*t1 = *t2;
*t2 = temp;
}
h = HashVec (origin);
for (w = wedge_hash[h] ; w ; w=w->next)
{
temp = w->origin[0] - origin[0];
if (temp < -EQUAL_EPSILON || temp > EQUAL_EPSILON)
continue;
temp = w->origin[1] - origin[1];
if (temp < -EQUAL_EPSILON || temp > EQUAL_EPSILON)
continue;
temp = w->origin[2] - origin[2];
if (temp < -EQUAL_EPSILON || temp > EQUAL_EPSILON)
continue;
temp = w->dir[0] - dir[0];
if (temp < -EQUAL_EPSILON || temp > EQUAL_EPSILON)
continue;
temp = w->dir[1] - dir[1];
if (temp < -EQUAL_EPSILON || temp > EQUAL_EPSILON)
continue;
temp = w->dir[2] - dir[2];
if (temp < -EQUAL_EPSILON || temp > EQUAL_EPSILON)
continue;
return w;
}
if (numwedges == MAXWEDGES)
Error ("FindEdge: numwedges == MAXWEDGES");
w = &wedges[numwedges];
numwedges++;
w->next = wedge_hash[h];
wedge_hash[h] = w;
VectorCopy (origin, w->origin);
VectorCopy (dir, w->dir);
w->head.next = w->head.prev = &w->head;
w->head.t = 99999;
return w;
}
/*
===============
AddVert
===============
*/
#define T_EPSILON 0.01
void AddVert (wedge_t *w, vec_t t)
{
wvert_t *v, *newv;
v = w->head.next;
do
{
if (fabs(v->t - t) < T_EPSILON)
return;
if (v->t > t)
break;
v = v->next;
} while (1);
// insert a new wvert before v
if (numwverts == MAXWVERTS)
Error ("AddVert: numwverts == MAXWVERTS");
newv = &wverts[numwverts];
numwverts++;
newv->t = t;
newv->next = v;
newv->prev = v->prev;
v->prev->next = newv;
v->prev = newv;
}
/*
===============
AddEdge
===============
*/
void AddEdge (vec3_t p1, vec3_t p2)
{
wedge_t *w;
vec_t t1, t2;
w = FindEdge(p1, p2, &t1, &t2);
AddVert (w, t1);
AddVert (w, t2);
}
/*
===============
AddFaceEdges
===============
*/
void AddFaceEdges (face_t *f)
{
int i, j;
for (i=0 ; i < f->numpoints ; i++)
{
j = (i+1)%f->numpoints;
AddEdge (f->pts[i], f->pts[j]);
}
}
//============================================================================
// a specially allocated face that can hold hundreds of edges if needed
byte superfacebuf[8192];
face_t *superface = (face_t *)superfacebuf;
void FixFaceEdges (face_t *f);
face_t *newlist;
void SplitFaceForTjunc (face_t *f, face_t *original)
{
int i;
face_t *new, *chain;
vec3_t dir, test;
vec_t v;
int firstcorner, lastcorner;
chain = NULL;
do
{
if (f->numpoints <= MAXPOINTS)
{ // the face is now small enough without more cutting
// so copy it back to the original
*original = *f;
original->original = chain;
original->next = newlist;
newlist = original;
return;
}
tjuncfaces++;
restart:
// find the last corner
VectorSubtract (f->pts[f->numpoints-1], f->pts[0], dir);
VectorNormalize (dir);
for (lastcorner=f->numpoints-1 ; lastcorner > 0 ; lastcorner--)
{
VectorSubtract (f->pts[lastcorner-1], f->pts[lastcorner], test);
VectorNormalize (test);
v = DotProduct (test, dir);
if (v < 0.9999 || v > 1.00001)
{
break;
}
}
// find the first corner
VectorSubtract (f->pts[1], f->pts[0], dir);
VectorNormalize (dir);
for (firstcorner=1 ; firstcorner < f->numpoints-1 ; firstcorner++)
{
VectorSubtract (f->pts[firstcorner+1], f->pts[firstcorner], test);
VectorNormalize (test);
v = DotProduct (test, dir);
if (v < 0.9999 || v > 1.00001)
{
break;
}
}
if (firstcorner+2 >= MAXPOINTS)
{
// rotate the point winding
VectorCopy (f->pts[0], test);
for (i=1 ; i<f->numpoints ; i++)
{
VectorCopy (f->pts[i], f->pts[i-1]);
}
VectorCopy (test, f->pts[f->numpoints-1]);
goto restart;
}
// cut off as big a piece as possible, less than MAXPOINTS, and not
// past lastcorner
new = NewFaceFromFace (f);
if (f->original)
Error ("SplitFaceForTjunc: f->original");
new->original = chain;
chain = new;
new->next = newlist;
newlist = new;
if (f->numpoints - firstcorner <= MAXPOINTS)
new->numpoints = firstcorner+2;
else if (lastcorner+2 < MAXPOINTS &&
f->numpoints - lastcorner <= MAXPOINTS)
new->numpoints = lastcorner+2;
else
new->numpoints = MAXPOINTS;
for (i=0 ; i<new->numpoints ; i++)
{
VectorCopy (f->pts[i], new->pts[i]);
}
for (i=new->numpoints-1 ; i<f->numpoints ; i++)
{
VectorCopy (f->pts[i], f->pts[i-(new->numpoints-2)]);
}
f->numpoints -= (new->numpoints-2);
} while (1);
}
/*
===============
FixFaceEdges
===============
*/
void FixFaceEdges (face_t *f)
{
int i, j, k;
wedge_t *w;
wvert_t *v;
vec_t t1, t2;
*superface = *f;
restart:
for (i=0 ; i < superface->numpoints ; i++)
{
j = (i+1)%superface->numpoints;
w = FindEdge (superface->pts[i], superface->pts[j], &t1, &t2);
for (v=w->head.next ; v->t < t1 + T_EPSILON ; v = v->next)
{
}
if (v->t < t2-T_EPSILON)
{
tjuncs++;
// insert a new vertex here
for (k = superface->numpoints ; k> j ; k--)
{
VectorCopy (superface->pts[k-1], superface->pts[k]);
}
VectorMA (w->origin, v->t, w->dir, superface->pts[j]);
superface->numpoints++;
goto restart;
}
}
if (superface->numpoints <= MAXPOINTS)
{
*f = *superface;
f->next = newlist;
newlist = f;
return;
}
// the face needs to be split into multiple faces because of too many edges
SplitFaceForTjunc (superface, f);
}
//============================================================================
void tjunc_find_r (node_t *node)
{
face_t *f;
if (node->planenum == PLANENUM_LEAF)
return;
for (f=node->faces ; f ; f=f->next)
AddFaceEdges (f);
tjunc_find_r (node->children[0]);
tjunc_find_r (node->children[1]);
}
void tjunc_fix_r (node_t *node)
{
face_t *f, *next;
if (node->planenum == PLANENUM_LEAF)
return;
newlist = NULL;
for (f=node->faces ; f ; f=next)
{
next = f->next;
FixFaceEdges (f);
}
node->faces = newlist;
tjunc_fix_r (node->children[0]);
tjunc_fix_r (node->children[1]);
}
/*
===========
tjunc
===========
*/
void tjunc (node_t *headnode)
{
vec3_t maxs, mins;
int i;
qprintf ("---- tjunc ----\n");
if (notjunc)
return;
//
// identify all points on common edges
//
// origin points won't allways be inside the map, so extend the hash area
for (i=0 ; i<3 ; i++)
{
if ( fabs(brushset->maxs[i]) > fabs(brushset->mins[i]) )
maxs[i] = fabs(brushset->maxs[i]);
else
maxs[i] = fabs(brushset->mins[i]);
}
VectorSubtract (vec3_origin, maxs, mins);
InitHash (mins, maxs);
numwedges = numwverts = 0;
tjunc_find_r (headnode);
qprintf ("%i world edges %i edge points\n", numwedges, numwverts);
//
// add extra vertexes on edges where needed
//
tjuncs = tjuncfaces = 0;
tjunc_fix_r (headnode);
qprintf ("%i edges added by tjunctions\n", tjuncs);
qprintf ("%i faces added by tjunctions\n", tjuncfaces);
}

523
qutils/QBSP/WRITEBSP.C Normal file
View File

@@ -0,0 +1,523 @@
#include "bsp5.h"
int headclipnode;
int firstface;
//===========================================================================
/*
==================
FindFinalPlane
Used to find plane index numbers for clip nodes read from child processes
==================
*/
int FindFinalPlane (dplane_t *p)
{
int i;
dplane_t *dplane;
for (i=0, dplane = dplanes ; i<numplanes ; i++, dplane++)
{
if (p->type != dplane->type)
continue;
if (p->dist != dplane->dist)
continue;
if (p->normal[0] != dplane->normal[0])
continue;
if (p->normal[1] != dplane->normal[1])
continue;
if (p->normal[2] != dplane->normal[2])
continue;
return i;
}
//
// new plane
//
if (numplanes == MAX_MAP_PLANES)
Error ("numplanes == MAX_MAP_PLANES");
dplane = &dplanes[numplanes];
*dplane = *p;
numplanes++;
return numplanes - 1;
}
int planemapping[MAX_MAP_PLANES];
void WriteNodePlanes_r (node_t *node)
{
plane_t *plane;
dplane_t *dplane;
if (node->planenum == -1)
return;
if (planemapping[node->planenum] == -1)
{ // a new plane
planemapping[node->planenum] = numplanes;
if (numplanes == MAX_MAP_PLANES)
Error ("numplanes == MAX_MAP_PLANES");
plane = &planes[node->planenum];
dplane = &dplanes[numplanes];
dplane->normal[0] = plane->normal[0];
dplane->normal[1] = plane->normal[1];
dplane->normal[2] = plane->normal[2];
dplane->dist = plane->dist;
dplane->type = plane->type;
numplanes++;
}
node->outputplanenum = planemapping[node->planenum];
WriteNodePlanes_r (node->children[0]);
WriteNodePlanes_r (node->children[1]);
}
/*
==================
WriteNodePlanes
==================
*/
void WriteNodePlanes (node_t *nodes)
{
memset (planemapping,-1, sizeof(planemapping));
WriteNodePlanes_r (nodes);
}
//===========================================================================
/*
==================
WriteClipNodes_r
==================
*/
int WriteClipNodes_r (node_t *node)
{
int i, c;
dclipnode_t *cn;
int num;
// FIXME: free more stuff?
if (node->planenum == -1)
{
num = node->contents;
free (node);
return num;
}
// emit a clipnode
c = numclipnodes;
cn = &dclipnodes[numclipnodes];
numclipnodes++;
cn->planenum = node->outputplanenum;
for (i=0 ; i<2 ; i++)
cn->children[i] = WriteClipNodes_r(node->children[i]);
free (node);
return c;
}
/*
==================
WriteClipNodes
Called after the clipping hull is completed. Generates a disk format
representation and frees the original memory.
==================
*/
void WriteClipNodes (node_t *nodes)
{
headclipnode = numclipnodes;
WriteClipNodes_r (nodes);
}
//===========================================================================
/*
==================
WriteLeaf
==================
*/
void WriteLeaf (node_t *node)
{
face_t **fp, *f;
dleaf_t *leaf_p;
// emit a leaf
leaf_p = &dleafs[numleafs];
numleafs++;
leaf_p->contents = node->contents;
//
// write bounding box info
//
VectorCopy (node->mins, leaf_p->mins);
VectorCopy (node->maxs, leaf_p->maxs);
leaf_p->visofs = -1; // no vis info yet
//
// write the marksurfaces
//
leaf_p->firstmarksurface = nummarksurfaces;
for (fp=node->markfaces ; *fp ; fp++)
{
// emit a marksurface
if (nummarksurfaces == MAX_MAP_MARKSURFACES)
Error ("nummarksurfaces == MAX_MAP_MARKSURFACES");
f = *fp;
do
{
dmarksurfaces[nummarksurfaces] = f->outputnumber;
nummarksurfaces++;
f=f->original; // grab tjunction split faces
} while (f);
}
leaf_p->nummarksurfaces = nummarksurfaces - leaf_p->firstmarksurface;
}
/*
==================
WriteDrawNodes_r
==================
*/
void WriteDrawNodes_r (node_t *node)
{
dnode_t *n;
int i;
// emit a node
if (numnodes == MAX_MAP_NODES)
Error ("numnodes == MAX_MAP_NODES");
n = &dnodes[numnodes];
numnodes++;
VectorCopy (node->mins, n->mins);
VectorCopy (node->maxs, n->maxs);
n->planenum = node->outputplanenum;
n->firstface = node->firstface;
n->numfaces = node->numfaces;
//
// recursively output the other nodes
//
for (i=0 ; i<2 ; i++)
{
if (node->children[i]->planenum == -1)
{
if (node->children[i]->contents == CONTENTS_SOLID)
n->children[i] = -1;
else
{
n->children[i] = -(numleafs + 1);
WriteLeaf (node->children[i]);
}
}
else
{
n->children[i] = numnodes;
WriteDrawNodes_r (node->children[i]);
}
}
}
/*
==================
WriteDrawNodes
==================
*/
void WriteDrawNodes (node_t *headnode)
{
int i;
int start;
dmodel_t *bm;
#if 0
if (headnode->contents < 0)
Error ("FinishBSPModel: empty model");
#endif
// emit a model
if (nummodels == MAX_MAP_MODELS)
Error ("nummodels == MAX_MAP_MODELS");
bm = &dmodels[nummodels];
nummodels++;
bm->headnode[0] = numnodes;
bm->firstface = firstface;
bm->numfaces = numfaces - firstface;
firstface = numfaces;
start = numleafs;
if (headnode->contents < 0)
WriteLeaf (headnode);
else
WriteDrawNodes_r (headnode);
bm->visleafs = numleafs - start;
for (i=0 ; i<3 ; i++)
{
bm->mins[i] = headnode->mins[i] + SIDESPACE + 1; // remove the padding
bm->maxs[i] = headnode->maxs[i] - SIDESPACE - 1;
}
// FIXME: are all the children decendant of padded nodes?
}
/*
==================
BumpModel
Used by the clipping hull processes that only need to store headclipnode
==================
*/
void BumpModel (int hullnum)
{
dmodel_t *bm;
// emit a model
if (nummodels == MAX_MAP_MODELS)
Error ("nummodels == MAX_MAP_MODELS");
bm = &dmodels[nummodels];
nummodels++;
bm->headnode[hullnum] = headclipnode;
}
//=============================================================================
typedef struct
{
char identification[4]; // should be WAD2
int numlumps;
int infotableofs;
} wadinfo_t;
typedef struct
{
int filepos;
int disksize;
int size; // uncompressed
char type;
char compression;
char pad1, pad2;
char name[16]; // must be null terminated
} lumpinfo_t;
FILE *texfile;
wadinfo_t wadinfo;
lumpinfo_t *lumpinfo;
void CleanupName (char *in, char *out)
{
int i;
for (i=0 ; i< 16 ; i++ )
{
if (!in[i])
break;
out[i] = toupper(in[i]);
}
for ( ; i< 16 ; i++ )
out[i] = 0;
}
/*
=================
TEX_InitFromWad
=================
*/
void TEX_InitFromWad (char *path)
{
int i;
texfile = SafeOpenRead (path);
SafeRead (texfile, &wadinfo, sizeof(wadinfo));
if (strncmp (wadinfo.identification, "WAD2", 4))
Error ("TEX_InitFromWad: %s isn't a wadfile",path);
wadinfo.numlumps = LittleLong(wadinfo.numlumps);
wadinfo.infotableofs = LittleLong(wadinfo.infotableofs);
fseek (texfile, wadinfo.infotableofs, SEEK_SET);
lumpinfo = malloc(wadinfo.numlumps*sizeof(lumpinfo_t));
SafeRead (texfile, lumpinfo, wadinfo.numlumps*sizeof(lumpinfo_t));
for (i=0 ; i<wadinfo.numlumps ; i++)
{
CleanupName (lumpinfo[i].name, lumpinfo[i].name);
lumpinfo[i].filepos = LittleLong(lumpinfo[i].filepos);
lumpinfo[i].disksize = LittleLong(lumpinfo[i].disksize);
}
}
/*
==================
LoadLump
==================
*/
int LoadLump (char *name, byte *dest)
{
int i;
char cname[16];
CleanupName (name, cname);
for (i=0 ; i<wadinfo.numlumps ; i++)
{
if (!strcmp(cname, lumpinfo[i].name))
{
fseek (texfile, lumpinfo[i].filepos, SEEK_SET);
SafeRead (texfile, dest, lumpinfo[i].disksize);
return lumpinfo[i].disksize;
}
}
printf ("WARNING: texture %s not found\n", name);
return 0;
}
/*
==================
AddAnimatingTextures
==================
*/
void AddAnimatingTextures (void)
{
int base;
int i, j, k;
char name[32];
base = nummiptex;
for (i=0 ; i<base ; i++)
{
if (miptex[i][0] != '+')
continue;
strcpy (name, miptex[i]);
for (j=0 ; j<20 ; j++)
{
if (j < 10)
name[1] = '0'+j;
else
name[1] = 'A'+j-10; // alternate animation
// see if this name exists in the wadfile
for (k=0 ; k<wadinfo.numlumps ; k++)
if (!strcmp(name, lumpinfo[k].name))
{
FindMiptex (name); // add to the miptex list
break;
}
}
}
printf ("added %i texture frames\n", nummiptex - base);
}
/*
==================
WriteMiptex
==================
*/
void WriteMiptex (void)
{
int i, len;
byte *data;
dmiptexlump_t *l;
char *path;
char fullpath[1024];
path = ValueForKey (&entities[0], "_wad");
if (!path || !path[0])
{
path = ValueForKey (&entities[0], "wad");
if (!path || !path[0])
{
printf ("WARNING: no wadfile specified\n");
texdatasize = 0;
return;
}
}
sprintf (fullpath, "%s/%s", gamedir, path);
TEX_InitFromWad (fullpath);
AddAnimatingTextures ();
l = (dmiptexlump_t *)dtexdata;
data = (byte *)&l->dataofs[nummiptex];
l->nummiptex = nummiptex;
for (i=0 ; i<nummiptex ; i++)
{
l->dataofs[i] = data - (byte *)l;
len = LoadLump (miptex[i], data);
if (data + len - dtexdata >= MAX_MAP_MIPTEX)
Error ("Textures exceeded MAX_MAP_MIPTEX");
if (!len)
l->dataofs[i] = -1; // didn't find the texture
data += len;
}
texdatasize = data - dtexdata;
}
//===========================================================================
/*
==================
BeginBSPFile
==================
*/
void BeginBSPFile (void)
{
// edge 0 is not used, because 0 can't be negated
numedges = 1;
// leaf 0 is common solid with no faces
numleafs = 1;
dleafs[0].contents = CONTENTS_SOLID;
firstface = 0;
}
/*
==================
FinishBSPFile
==================
*/
void FinishBSPFile (void)
{
printf ("--- FinishBSPFile ---\n");
printf ("WriteBSPFile: %s\n", bspfilename);
WriteMiptex ();
PrintBSPFileSizes ();
WriteBSPFile (bspfilename);
}

42
qutils/QCC/MAKEFILE Normal file
View File

@@ -0,0 +1,42 @@
EXES = qcc
NTEXES = qcc.exe
#==============================================================================
EXT= .o
all: $(EXES)
clean:
rm *.o *.obj $(EXES) $(NTEXES)
next:
make "CFLAGS = -g -Wall -I.."
nextinstall:
make "CFLAGS = -O4 -g -Wall -I.. -arch i386 -arch hppa"
cp $(EXES) /LocalApps
alpha:
make "CFLAGS = -g -I.." "LDFLAGS = -lm"
alphainstall:
make "CFLAGS = -O4 -I.." "LDFLAGS = -lm"
cp $(EXES) /LocalApps
nt:
nmake /nologo "CFLAGS = -nologo -Zi -DWIN32 -I.." "LDFLAGS = " "EXT = .obj"
ntinstall:
nmake /nologo "CFLAGS = -nologo -Ox -G5 -DWIN32 -I.." "LDFLAGS = " "EXT = .obj"
cp $(NTEXES) f:\nt\id
#==============================================================================
QCCFILES = qcc$(EXT) pr_lex$(EXT) pr_comp$(EXT) cmdlib$(EXT)
qcc : $(QCCFILES)
$(CC) $(CFLAGS) -o qcc $(QCCFILES)
cmdlib$(EXT) : ../cmdlib.c
$(CC) $(CFLAGS) -c -o cmdlib$(EXT) ../cmdlib.c

936
qutils/QCC/PR_COMP.C Normal file
View File

@@ -0,0 +1,936 @@
#include "qcc.h"
pr_info_t pr;
def_t *pr_global_defs[MAX_REGS]; // to find def for a global variable
int pr_edict_size;
//========================================
def_t *pr_scope; // the function being parsed, or NULL
qboolean pr_dumpasm;
string_t s_file; // filename for function definition
int locals_end; // for tracking local variables vs temps
jmp_buf pr_parse_abort; // longjump with this on parse error
void PR_ParseDefs (void);
//========================================
opcode_t pr_opcodes[] =
{
{"<DONE>", "DONE", -1, false, &def_entity, &def_field, &def_void},
{"*", "MUL_F", 2, false, &def_float, &def_float, &def_float},
{"*", "MUL_V", 2, false, &def_vector, &def_vector, &def_float},
{"*", "MUL_FV", 2, false, &def_float, &def_vector, &def_vector},
{"*", "MUL_VF", 2, false, &def_vector, &def_float, &def_vector},
{"/", "DIV", 2, false, &def_float, &def_float, &def_float},
{"+", "ADD_F", 3, false, &def_float, &def_float, &def_float},
{"+", "ADD_V", 3, false, &def_vector, &def_vector, &def_vector},
{"-", "SUB_F", 3, false, &def_float, &def_float, &def_float},
{"-", "SUB_V", 3, false, &def_vector, &def_vector, &def_vector},
{"==", "EQ_F", 4, false, &def_float, &def_float, &def_float},
{"==", "EQ_V", 4, false, &def_vector, &def_vector, &def_float},
{"==", "EQ_S", 4, false, &def_string, &def_string, &def_float},
{"==", "EQ_E", 4, false, &def_entity, &def_entity, &def_float},
{"==", "EQ_FNC", 4, false, &def_function, &def_function, &def_float},
{"!=", "NE_F", 4, false, &def_float, &def_float, &def_float},
{"!=", "NE_V", 4, false, &def_vector, &def_vector, &def_float},
{"!=", "NE_S", 4, false, &def_string, &def_string, &def_float},
{"!=", "NE_E", 4, false, &def_entity, &def_entity, &def_float},
{"!=", "NE_FNC", 4, false, &def_function, &def_function, &def_float},
{"<=", "LE", 4, false, &def_float, &def_float, &def_float},
{">=", "GE", 4, false, &def_float, &def_float, &def_float},
{"<", "LT", 4, false, &def_float, &def_float, &def_float},
{">", "GT", 4, false, &def_float, &def_float, &def_float},
{".", "INDIRECT", 1, false, &def_entity, &def_field, &def_float},
{".", "INDIRECT", 1, false, &def_entity, &def_field, &def_vector},
{".", "INDIRECT", 1, false, &def_entity, &def_field, &def_string},
{".", "INDIRECT", 1, false, &def_entity, &def_field, &def_entity},
{".", "INDIRECT", 1, false, &def_entity, &def_field, &def_field},
{".", "INDIRECT", 1, false, &def_entity, &def_field, &def_function},
{".", "ADDRESS", 1, false, &def_entity, &def_field, &def_pointer},
{"=", "STORE_F", 5, true, &def_float, &def_float, &def_float},
{"=", "STORE_V", 5, true, &def_vector, &def_vector, &def_vector},
{"=", "STORE_S", 5, true, &def_string, &def_string, &def_string},
{"=", "STORE_ENT", 5, true, &def_entity, &def_entity, &def_entity},
{"=", "STORE_FLD", 5, true, &def_field, &def_field, &def_field},
{"=", "STORE_FNC", 5, true, &def_function, &def_function, &def_function},
{"=", "STOREP_F", 5, true, &def_pointer, &def_float, &def_float},
{"=", "STOREP_V", 5, true, &def_pointer, &def_vector, &def_vector},
{"=", "STOREP_S", 5, true, &def_pointer, &def_string, &def_string},
{"=", "STOREP_ENT", 5, true, &def_pointer, &def_entity, &def_entity},
{"=", "STOREP_FLD", 5, true, &def_pointer, &def_field, &def_field},
{"=", "STOREP_FNC", 5, true, &def_pointer, &def_function, &def_function},
{"<RETURN>", "RETURN", -1, false, &def_void, &def_void, &def_void},
{"!", "NOT_F", -1, false, &def_float, &def_void, &def_float},
{"!", "NOT_V", -1, false, &def_vector, &def_void, &def_float},
{"!", "NOT_S", -1, false, &def_vector, &def_void, &def_float},
{"!", "NOT_ENT", -1, false, &def_entity, &def_void, &def_float},
{"!", "NOT_FNC", -1, false, &def_function, &def_void, &def_float},
{"<IF>", "IF", -1, false, &def_float, &def_float, &def_void},
{"<IFNOT>", "IFNOT", -1, false, &def_float, &def_float, &def_void},
// calls returns REG_RETURN
{"<CALL0>", "CALL0", -1, false, &def_function, &def_void, &def_void},
{"<CALL1>", "CALL1", -1, false, &def_function, &def_void, &def_void},
{"<CALL2>", "CALL2", -1, false, &def_function, &def_void, &def_void},
{"<CALL3>", "CALL3", -1, false, &def_function, &def_void, &def_void},
{"<CALL4>", "CALL4", -1, false, &def_function, &def_void, &def_void},
{"<CALL5>", "CALL5", -1, false, &def_function, &def_void, &def_void},
{"<CALL6>", "CALL6", -1, false, &def_function, &def_void, &def_void},
{"<CALL7>", "CALL7", -1, false, &def_function, &def_void, &def_void},
{"<CALL8>", "CALL8", -1, false, &def_function, &def_void, &def_void},
{"<STATE>", "STATE", -1, false, &def_float, &def_float, &def_void},
{"<GOTO>", "GOTO", -1, false, &def_float, &def_void, &def_void},
{"&&", "AND", 6, false, &def_float, &def_float, &def_float},
{"||", "OR", 6, false, &def_float, &def_float, &def_float},
{"&", "BITAND", 2, false, &def_float, &def_float, &def_float},
{"|", "BITOR", 2, false, &def_float, &def_float, &def_float},
{NULL}
};
#define TOP_PRIORITY 6
#define NOT_PRIORITY 4
def_t *PR_Expression (int priority);
def_t junkdef;
//===========================================================================
/*
============
PR_Statement
Emits a primitive statement, returning the var it places it's value in
============
*/
def_t *PR_Statement ( opcode_t *op, def_t *var_a, def_t *var_b)
{
dstatement_t *statement;
def_t *var_c;
statement = &statements[numstatements];
numstatements++;
statement_linenums[statement-statements] = pr_source_line;
statement->op = op - pr_opcodes;
statement->a = var_a ? var_a->ofs : 0;
statement->b = var_b ? var_b->ofs : 0;
if (op->type_c == &def_void || op->right_associative)
{
var_c = NULL;
statement->c = 0; // ifs, gotos, and assignments
// don't need vars allocated
}
else
{ // allocate result space
var_c = malloc (sizeof(def_t));
memset (var_c, 0, sizeof(def_t));
var_c->ofs = numpr_globals;
var_c->type = op->type_c->type;
statement->c = numpr_globals;
numpr_globals += type_size[op->type_c->type->type];
}
if (op->right_associative)
return var_a;
return var_c;
}
/*
============
PR_ParseImmediate
Looks for a preexisting constant
============
*/
def_t *PR_ParseImmediate (void)
{
def_t *cn;
// check for a constant with the same value
for (cn=pr.def_head.next ; cn ; cn=cn->next)
{
if (!cn->initialized)
continue;
if (cn->type != pr_immediate_type)
continue;
if (pr_immediate_type == &type_string)
{
if (!strcmp(G_STRING(cn->ofs), pr_immediate_string) )
{
PR_Lex ();
return cn;
}
}
else if (pr_immediate_type == &type_float)
{
if ( G_FLOAT(cn->ofs) == pr_immediate._float )
{
PR_Lex ();
return cn;
}
}
else if (pr_immediate_type == &type_vector)
{
if ( ( G_FLOAT(cn->ofs) == pr_immediate.vector[0] )
&& ( G_FLOAT(cn->ofs+1) == pr_immediate.vector[1] )
&& ( G_FLOAT(cn->ofs+2) == pr_immediate.vector[2] ) )
{
PR_Lex ();
return cn;
}
}
else
PR_ParseError ("weird immediate type");
}
// allocate a new one
cn = malloc (sizeof(def_t));
cn->next = NULL;
pr.def_tail->next = cn;
pr.def_tail = cn;
cn->search_next = pr.search;
pr.search = cn;
cn->type = pr_immediate_type;
cn->name = "IMMEDIATE";
cn->initialized = 1;
cn->scope = NULL; // always share immediates
// copy the immediate to the global area
cn->ofs = numpr_globals;
pr_global_defs[cn->ofs] = cn;
numpr_globals += type_size[pr_immediate_type->type];
if (pr_immediate_type == &type_string)
pr_immediate.string = CopyString (pr_immediate_string);
memcpy (pr_globals + cn->ofs, &pr_immediate, 4*type_size[pr_immediate_type->type]);
PR_Lex ();
return cn;
}
void PrecacheSound (def_t *e, int ch)
{
char *n;
int i;
if (!e->ofs)
return;
n = G_STRING(e->ofs);
for (i=0 ; i<numsounds ; i++)
if (!strcmp(n, precache_sounds[i]))
return;
if (numsounds == MAX_SOUNDS)
Error ("PrecacheSound: numsounds == MAX_SOUNDS");
strcpy (precache_sounds[i], n);
if (ch >= '1' && ch <= '9')
precache_sounds_block[i] = ch - '0';
else
precache_sounds_block[i] = 1;
numsounds++;
}
void PrecacheModel (def_t *e, int ch)
{
char *n;
int i;
if (!e->ofs)
return;
n = G_STRING(e->ofs);
for (i=0 ; i<nummodels ; i++)
if (!strcmp(n, precache_models[i]))
return;
if (numsounds == MAX_SOUNDS)
Error ("PrecacheModels: numsounds == MAX_SOUNDS");
strcpy (precache_models[i], n);
if (ch >= '1' && ch <= '9')
precache_models_block[i] = ch - '0';
else
precache_models_block[i] = 1;
nummodels++;
}
void PrecacheFile (def_t *e, int ch)
{
char *n;
int i;
if (!e->ofs)
return;
n = G_STRING(e->ofs);
for (i=0 ; i<numfiles ; i++)
if (!strcmp(n, precache_files[i]))
return;
if (numfiles == MAX_FILES)
Error ("PrecacheFile: numfiles == MAX_FILES");
strcpy (precache_files[i], n);
if (ch >= '1' && ch <= '9')
precache_files_block[i] = ch - '0';
else
precache_files_block[i] = 1;
numfiles++;
}
/*
============
PR_ParseFunctionCall
============
*/
def_t *PR_ParseFunctionCall (def_t *func)
{
def_t *e;
int arg;
type_t *t;
t = func->type;
if (t->type != ev_function)
PR_ParseError ("not a function");
// copy the arguments to the global parameter variables
arg = 0;
if (!PR_Check(")"))
{
do
{
if (t->num_parms != -1 && arg >= t->num_parms)
PR_ParseError ("too many parameters");
e = PR_Expression (TOP_PRIORITY);
if (arg == 0 && func->name)
{
// save information for model and sound caching
if (!strncmp(func->name,"precache_sound", 14))
PrecacheSound (e, func->name[14]);
else if (!strncmp(func->name,"precache_model", 14))
PrecacheModel (e, func->name[14]);
else if (!strncmp(func->name,"precache_file", 13))
PrecacheFile (e, func->name[13]);
}
if (t->num_parms != -1 && ( e->type != t->parm_types[arg] ) )
PR_ParseError ("type mismatch on parm %i", arg);
// a vector copy will copy everything
def_parms[arg].type = t->parm_types[arg];
PR_Statement (&pr_opcodes[OP_STORE_V], e, &def_parms[arg]);
arg++;
} while (PR_Check (","));
if (t->num_parms != -1 && arg != t->num_parms)
PR_ParseError ("too few parameters");
PR_Expect (")");
}
if (arg >8)
PR_ParseError ("More than eight parameters");
PR_Statement (&pr_opcodes[OP_CALL0+arg], func, 0);
def_ret.type = t->aux_type;
return &def_ret;
}
/*
============
PR_ParseValue
Returns the global ofs for the current token
============
*/
def_t *PR_ParseValue (void)
{
def_t *d;
char *name;
// if the token is an immediate, allocate a constant for it
if (pr_token_type == tt_immediate)
return PR_ParseImmediate ();
name = PR_ParseName ();
// look through the defs
d = PR_GetDef (NULL, name, pr_scope, false);
if (!d)
PR_ParseError ("Unknown value \"%s\"", name);
return d;
}
/*
============
PR_Term
============
*/
def_t *PR_Term (void)
{
def_t *e, *e2;
etype_t t;
if (PR_Check ("!"))
{
e = PR_Expression (NOT_PRIORITY);
t = e->type->type;
if (t == ev_float)
e2 = PR_Statement (&pr_opcodes[OP_NOT_F], e, 0);
else if (t == ev_string)
e2 = PR_Statement (&pr_opcodes[OP_NOT_S], e, 0);
else if (t == ev_entity)
e2 = PR_Statement (&pr_opcodes[OP_NOT_ENT], e, 0);
else if (t == ev_vector)
e2 = PR_Statement (&pr_opcodes[OP_NOT_V], e, 0);
else if (t == ev_function)
e2 = PR_Statement (&pr_opcodes[OP_NOT_FNC], e, 0);
else
{
e2 = NULL; // shut up compiler warning;
PR_ParseError ("type mismatch for !");
}
return e2;
}
if (PR_Check ("("))
{
e = PR_Expression (TOP_PRIORITY);
PR_Expect (")");
return e;
}
return PR_ParseValue ();
}
/*
==============
PR_Expression
==============
*/
def_t *PR_Expression (int priority)
{
opcode_t *op, *oldop;
def_t *e, *e2;
etype_t type_a, type_b, type_c;
if (priority == 0)
return PR_Term ();
e = PR_Expression (priority-1);
while (1)
{
if (priority == 1 && PR_Check ("(") )
return PR_ParseFunctionCall (e);
for (op=pr_opcodes ; op->name ; op++)
{
if (op->priority != priority)
continue;
if (!PR_Check (op->name))
continue;
if ( op->right_associative )
{
// if last statement is an indirect, change it to an address of
if ( (unsigned)(statements[numstatements-1].op - OP_LOAD_F) < 6 )
{
statements[numstatements-1].op = OP_ADDRESS;
def_pointer.type->aux_type = e->type;
e->type = def_pointer.type;
}
e2 = PR_Expression (priority);
}
else
e2 = PR_Expression (priority-1);
// type check
type_a = e->type->type;
type_b = e2->type->type;
if (op->name[0] == '.')// field access gets type from field
{
if (e2->type->aux_type)
type_c = e2->type->aux_type->type;
else
type_c = -1; // not a field
}
else
type_c = ev_void;
oldop = op;
while (type_a != op->type_a->type->type
|| type_b != op->type_b->type->type
|| (type_c != ev_void && type_c != op->type_c->type->type) )
{
op++;
if (!op->name || strcmp (op->name , oldop->name))
PR_ParseError ("type mismatch for %s", oldop->name);
}
if (type_a == ev_pointer && type_b != e->type->aux_type->type)
PR_ParseError ("type mismatch for %s", op->name);
if (op->right_associative)
e = PR_Statement (op, e2, e);
else
e = PR_Statement (op, e, e2);
if (type_c != ev_void) // field access gets type from field
e->type = e2->type->aux_type;
break;
}
if (!op->name)
break; // next token isn't at this priority level
}
return e;
}
/*
============
PR_ParseStatement
============
*/
void PR_ParseStatement (void)
{
def_t *e;
dstatement_t *patch1, *patch2;
if (PR_Check ("{"))
{
do
{
PR_ParseStatement ();
} while (!PR_Check ("}"));
return;
}
if (PR_Check("return"))
{
if (PR_Check (";"))
{
PR_Statement (&pr_opcodes[OP_RETURN], 0, 0);
return;
}
e = PR_Expression (TOP_PRIORITY);
PR_Expect (";");
PR_Statement (&pr_opcodes[OP_RETURN], e, 0);
return;
}
if (PR_Check("while"))
{
PR_Expect ("(");
patch2 = &statements[numstatements];
e = PR_Expression (TOP_PRIORITY);
PR_Expect (")");
patch1 = &statements[numstatements];
PR_Statement (&pr_opcodes[OP_IFNOT], e, 0);
PR_ParseStatement ();
junkdef.ofs = patch2 - &statements[numstatements];
PR_Statement (&pr_opcodes[OP_GOTO], &junkdef, 0);
patch1->b = &statements[numstatements] - patch1;
return;
}
if (PR_Check("do"))
{
patch1 = &statements[numstatements];
PR_ParseStatement ();
PR_Expect ("while");
PR_Expect ("(");
e = PR_Expression (TOP_PRIORITY);
PR_Expect (")");
PR_Expect (";");
junkdef.ofs = patch1 - &statements[numstatements];
PR_Statement (&pr_opcodes[OP_IF], e, &junkdef);
return;
}
if (PR_Check("local"))
{
PR_ParseDefs ();
locals_end = numpr_globals;
return;
}
if (PR_Check("if"))
{
PR_Expect ("(");
e = PR_Expression (TOP_PRIORITY);
PR_Expect (")");
patch1 = &statements[numstatements];
PR_Statement (&pr_opcodes[OP_IFNOT], e, 0);
PR_ParseStatement ();
if (PR_Check ("else"))
{
patch2 = &statements[numstatements];
PR_Statement (&pr_opcodes[OP_GOTO], 0, 0);
patch1->b = &statements[numstatements] - patch1;
PR_ParseStatement ();
patch2->a = &statements[numstatements] - patch2;
}
else
patch1->b = &statements[numstatements] - patch1;
return;
}
PR_Expression (TOP_PRIORITY);
PR_Expect (";");
}
/*
==============
PR_ParseState
States are special functions made for convenience. They automatically
set frame, nextthink (implicitly), and think (allowing forward definitions).
// void() name = [framenum, nextthink] {code}
// expands to:
// function void name ()
// {
// self.frame=framenum;
// self.nextthink = time + 0.1;
// self.think = nextthink
// <code>
// };
==============
*/
void PR_ParseState (void)
{
char *name;
def_t *s1, *def;
if (pr_token_type != tt_immediate || pr_immediate_type != &type_float)
PR_ParseError ("state frame must be a number");
s1 = PR_ParseImmediate ();
PR_Expect (",");
name = PR_ParseName ();
def = PR_GetDef (&type_function, name,0, true);
PR_Expect ("]");
PR_Statement (&pr_opcodes[OP_STATE], s1, def);
}
/*
============
PR_ParseImmediateStatements
Parse a function body
============
*/
function_t *PR_ParseImmediateStatements (type_t *type)
{
int i;
function_t *f;
def_t *defs[MAX_PARMS];
f = malloc (sizeof(function_t));
//
// check for builtin function definition #1, #2, etc
//
if (PR_Check ("#"))
{
if (pr_token_type != tt_immediate
|| pr_immediate_type != &type_float
|| pr_immediate._float != (int)pr_immediate._float)
PR_ParseError ("Bad builtin immediate");
f->builtin = (int)pr_immediate._float;
PR_Lex ();
return f;
}
f->builtin = 0;
//
// define the parms
//
for (i=0 ; i<type->num_parms ; i++)
{
defs[i] = PR_GetDef (type->parm_types[i], pr_parm_names[i], pr_scope, true);
f->parm_ofs[i] = defs[i]->ofs;
if (i > 0 && f->parm_ofs[i] < f->parm_ofs[i-1])
Error ("bad parm order");
}
f->code = numstatements;
//
// check for a state opcode
//
if (PR_Check ("["))
PR_ParseState ();
//
// parse regular statements
//
PR_Expect ("{");
while (!PR_Check("}"))
PR_ParseStatement ();
// emit an end of statements opcode
PR_Statement (pr_opcodes, 0,0);
return f;
}
/*
============
PR_GetDef
If type is NULL, it will match any type
If allocate is true, a new def will be allocated if it can't be found
============
*/
def_t *PR_GetDef (type_t *type, char *name, def_t *scope, qboolean allocate)
{
def_t *def, **old;
char element[MAX_NAME];
// see if the name is already in use
old = &pr.search;
for (def = *old ; def ; old=&def->search_next,def = *old)
if (!strcmp(def->name,name) )
{
if ( def->scope && def->scope != scope)
continue; // in a different function
if (type && def->type != type)
PR_ParseError ("Type mismatch on redeclaration of %s",name);
// move to head of list to find fast next time
*old = def->search_next;
def->search_next = pr.search;
pr.search = def;
return def;
}
if (!allocate)
return NULL;
// allocate a new def
def = malloc (sizeof(def_t));
memset (def, 0, sizeof(*def));
def->next = NULL;
pr.def_tail->next = def;
pr.def_tail = def;
def->search_next = pr.search;
pr.search = def;
def->name = malloc (strlen(name)+1);
strcpy (def->name, name);
def->type = type;
def->scope = scope;
def->ofs = numpr_globals;
pr_global_defs[numpr_globals] = def;
//
// make automatic defs for the vectors elements
// .origin can be accessed as .origin_x, .origin_y, and .origin_z
//
if (type->type == ev_vector)
{
sprintf (element, "%s_x",name);
PR_GetDef (&type_float, element, scope, true);
sprintf (element, "%s_y",name);
PR_GetDef (&type_float, element, scope, true);
sprintf (element, "%s_z",name);
PR_GetDef (&type_float, element, scope, true);
}
else
numpr_globals += type_size[type->type];
if (type->type == ev_field)
{
*(int *)&pr_globals[def->ofs] = pr.size_fields;
if (type->aux_type->type == ev_vector)
{
sprintf (element, "%s_x",name);
PR_GetDef (&type_floatfield, element, scope, true);
sprintf (element, "%s_y",name);
PR_GetDef (&type_floatfield, element, scope, true);
sprintf (element, "%s_z",name);
PR_GetDef (&type_floatfield, element, scope, true);
}
else
pr.size_fields += type_size[type->aux_type->type];
}
// if (pr_dumpasm)
// PR_PrintOfs (def->ofs);
return def;
}
/*
================
PR_ParseDefs
Called at the outer layer and when a local statement is hit
================
*/
void PR_ParseDefs (void)
{
char *name;
type_t *type;
def_t *def;
function_t *f;
dfunction_t *df;
int i;
int locals_start;
type = PR_ParseType ();
if (pr_scope && (type->type == ev_field || type->type == ev_function) )
PR_ParseError ("Fields and functions must be global");
do
{
name = PR_ParseName ();
def = PR_GetDef (type, name, pr_scope, true);
// check for an initialization
if ( PR_Check ("=") )
{
if (def->initialized)
PR_ParseError ("%s redeclared", name);
if (type->type == ev_function)
{
locals_start = locals_end = numpr_globals;
pr_scope = def;
f = PR_ParseImmediateStatements (type);
pr_scope = NULL;
def->initialized = 1;
G_FUNCTION(def->ofs) = numfunctions;
f->def = def;
// if (pr_dumpasm)
// PR_PrintFunction (def);
// fill in the dfunction
df = &functions[numfunctions];
numfunctions++;
if (f->builtin)
df->first_statement = -f->builtin;
else
df->first_statement = f->code;
df->s_name = CopyString (f->def->name);
df->s_file = s_file;
df->numparms = f->def->type->num_parms;
df->locals = locals_end - locals_start;
df->parm_start = locals_start;
for (i=0 ; i<df->numparms ; i++)
df->parm_size[i] = type_size[f->def->type->parm_types[i]->type];
continue;
}
else if (pr_immediate_type != type)
PR_ParseError ("wrong immediate type for %s", name);
def->initialized = 1;
memcpy (pr_globals + def->ofs, &pr_immediate, 4*type_size[pr_immediate_type->type]);
PR_Lex ();
}
} while (PR_Check (","));
PR_Expect (";");
}
/*
============
PR_CompileFile
compiles the 0 terminated text, adding defintions to the pr structure
============
*/
qboolean PR_CompileFile (char *string, char *filename)
{
if (!pr.memory)
Error ("PR_CompileFile: Didn't clear");
PR_ClearGrabMacros (); // clear the frame macros
pr_file_p = string;
s_file = CopyString (filename);
pr_source_line = 0;
PR_NewLine ();
PR_Lex (); // read first token
while (pr_token_type != tt_eof)
{
if (setjmp(pr_parse_abort))
{
if (++pr_error_count > MAX_ERRORS)
return false;
PR_SkipToSemicolon ();
if (pr_token_type == tt_eof)
return false;
}
pr_scope = NULL; // outside all functions
PR_ParseDefs ();
}
return (pr_error_count == 0);
}

161
qutils/QCC/PR_COMP.H Normal file
View File

@@ -0,0 +1,161 @@
// this file is shared by quake and qcc
typedef int func_t;
typedef int string_t;
typedef enum {ev_void, ev_string, ev_float, ev_vector, ev_entity, ev_field, ev_function, ev_pointer} etype_t;
#define OFS_NULL 0
#define OFS_RETURN 1
#define OFS_PARM0 4 // leave 3 ofs for each parm to hold vectors
#define OFS_PARM1 7
#define OFS_PARM2 10
#define OFS_PARM3 13
#define OFS_PARM4 16
#define OFS_PARM5 19
#define OFS_PARM6 22
#define OFS_PARM7 25
#define RESERVED_OFS 28
enum {
OP_DONE,
OP_MUL_F,
OP_MUL_V,
OP_MUL_FV,
OP_MUL_VF,
OP_DIV_F,
OP_ADD_F,
OP_ADD_V,
OP_SUB_F,
OP_SUB_V,
OP_EQ_F,
OP_EQ_V,
OP_EQ_S,
OP_EQ_E,
OP_EQ_FNC,
OP_NE_F,
OP_NE_V,
OP_NE_S,
OP_NE_E,
OP_NE_FNC,
OP_LE,
OP_GE,
OP_LT,
OP_GT,
OP_LOAD_F,
OP_LOAD_V,
OP_LOAD_S,
OP_LOAD_ENT,
OP_LOAD_FLD,
OP_LOAD_FNC,
OP_ADDRESS,
OP_STORE_F,
OP_STORE_V,
OP_STORE_S,
OP_STORE_ENT,
OP_STORE_FLD,
OP_STORE_FNC,
OP_STOREP_F,
OP_STOREP_V,
OP_STOREP_S,
OP_STOREP_ENT,
OP_STOREP_FLD,
OP_STOREP_FNC,
OP_RETURN,
OP_NOT_F,
OP_NOT_V,
OP_NOT_S,
OP_NOT_ENT,
OP_NOT_FNC,
OP_IF,
OP_IFNOT,
OP_CALL0,
OP_CALL1,
OP_CALL2,
OP_CALL3,
OP_CALL4,
OP_CALL5,
OP_CALL6,
OP_CALL7,
OP_CALL8,
OP_STATE,
OP_GOTO,
OP_AND,
OP_OR,
OP_BITAND,
OP_BITOR
};
typedef struct statement_s
{
unsigned short op;
short a,b,c;
} dstatement_t;
typedef struct
{
unsigned short type; // if DEF_SAVEGLOBGAL bit is set
// the variable needs to be saved in savegames
unsigned short ofs;
int s_name;
} ddef_t;
#define DEF_SAVEGLOBGAL (1<<15)
#define MAX_PARMS 8
typedef struct
{
int first_statement; // negative numbers are builtins
int parm_start;
int locals; // total ints of parms + locals
int profile; // runtime
int s_name;
int s_file; // source file defined in
int numparms;
byte parm_size[MAX_PARMS];
} dfunction_t;
#define PROG_VERSION 6
typedef struct
{
int version;
int crc; // check of header file
int ofs_statements;
int numstatements; // statement 0 is an error
int ofs_globaldefs;
int numglobaldefs;
int ofs_fielddefs;
int numfielddefs;
int ofs_functions;
int numfunctions; // function 0 is an empty
int ofs_strings;
int numstrings; // first string is a null string
int ofs_globals;
int numglobals;
int entityfields;
} dprograms_t;

677
qutils/QCC/PR_LEX.C Normal file
View File

@@ -0,0 +1,677 @@
#include "qcc.h"
int pr_source_line;
char *pr_file_p;
char *pr_line_start; // start of current source line
int pr_bracelevel;
char pr_token[2048];
token_type_t pr_token_type;
type_t *pr_immediate_type;
eval_t pr_immediate;
char pr_immediate_string[2048];
int pr_error_count;
char *pr_punctuation[] =
// longer symbols must be before a shorter partial match
{"&&", "||", "<=", ">=","==", "!=", ";", ",", "!", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", ".", "<", ">" , "#" , "&" , "|" , NULL};
// simple types. function types are dynamically allocated
type_t type_void = {ev_void, &def_void};
type_t type_string = {ev_string, &def_string};
type_t type_float = {ev_float, &def_float};
type_t type_vector = {ev_vector, &def_vector};
type_t type_entity = {ev_entity, &def_entity};
type_t type_field = {ev_field, &def_field};
type_t type_function = {ev_function, &def_function,NULL,&type_void};
// type_function is a void() function used for state defs
type_t type_pointer = {ev_pointer, &def_pointer};
type_t type_floatfield = {ev_field, &def_field, NULL, &type_float};
int type_size[8] = {1,1,1,3,1,1,1,1};
def_t def_void = {&type_void, "temp"};
def_t def_string = {&type_string, "temp"};
def_t def_float = {&type_float, "temp"};
def_t def_vector = {&type_vector, "temp"};
def_t def_entity = {&type_entity, "temp"};
def_t def_field = {&type_field, "temp"};
def_t def_function = {&type_function, "temp"};
def_t def_pointer = {&type_pointer, "temp"};
def_t def_ret, def_parms[MAX_PARMS];
def_t *def_for_type[8] = {&def_void, &def_string, &def_float, &def_vector, &def_entity, &def_field, &def_function, &def_pointer};
void PR_LexWhitespace (void);
/*
==============
PR_PrintNextLine
==============
*/
void PR_PrintNextLine (void)
{
char *t;
printf ("%3i:",pr_source_line);
for (t=pr_line_start ; *t && *t != '\n' ; t++)
printf ("%c",*t);
printf ("\n");
}
/*
==============
PR_NewLine
Call at start of file and when *pr_file_p == '\n'
==============
*/
void PR_NewLine (void)
{
qboolean m;
if (*pr_file_p == '\n')
{
pr_file_p++;
m = true;
}
else
m = false;
pr_source_line++;
pr_line_start = pr_file_p;
// if (pr_dumpasm)
// PR_PrintNextLine ();
if (m)
pr_file_p--;
}
/*
==============
PR_LexString
Parses a quoted string
==============
*/
void PR_LexString (void)
{
int c;
int len;
len = 0;
pr_file_p++;
do
{
c = *pr_file_p++;
if (!c)
PR_ParseError ("EOF inside quote");
if (c=='\n')
PR_ParseError ("newline inside quote");
if (c=='\\')
{ // escape char
c = *pr_file_p++;
if (!c)
PR_ParseError ("EOF inside quote");
if (c == 'n')
c = '\n';
else if (c == '"')
c = '"';
else
PR_ParseError ("Unknown escape char");
}
else if (c=='\"')
{
pr_token[len] = 0;
pr_token_type = tt_immediate;
pr_immediate_type = &type_string;
strcpy (pr_immediate_string, pr_token);
return;
}
pr_token[len] = c;
len++;
} while (1);
}
/*
==============
PR_LexNumber
==============
*/
float PR_LexNumber (void)
{
int c;
int len;
len = 0;
c = *pr_file_p;
do
{
pr_token[len] = c;
len++;
pr_file_p++;
c = *pr_file_p;
} while ((c >= '0' && c<= '9') || c == '.');
pr_token[len] = 0;
return atof (pr_token);
}
/*
==============
PR_LexVector
Parses a single quoted vector
==============
*/
void PR_LexVector (void)
{
int i;
pr_file_p++;
pr_token_type = tt_immediate;
pr_immediate_type = &type_vector;
for (i=0 ; i<3 ; i++)
{
pr_immediate.vector[i] = PR_LexNumber ();
PR_LexWhitespace ();
}
if (*pr_file_p != '\'')
PR_ParseError ("Bad vector");
pr_file_p++;
}
/*
==============
PR_LexName
Parses an identifier
==============
*/
void PR_LexName (void)
{
int c;
int len;
len = 0;
c = *pr_file_p;
do
{
pr_token[len] = c;
len++;
pr_file_p++;
c = *pr_file_p;
} while ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
|| (c >= '0' && c <= '9'));
pr_token[len] = 0;
pr_token_type = tt_name;
}
/*
==============
PR_LexPunctuation
==============
*/
void PR_LexPunctuation (void)
{
int i;
int len;
char *p;
pr_token_type = tt_punct;
for (i=0 ; (p = pr_punctuation[i]) != NULL ; i++)
{
len = strlen(p);
if (!strncmp(p, pr_file_p, len) )
{
strcpy (pr_token, p);
if (p[0] == '{')
pr_bracelevel++;
else if (p[0] == '}')
pr_bracelevel--;
pr_file_p += len;
return;
}
}
PR_ParseError ("Unknown punctuation");
}
/*
==============
PR_LexWhitespace
==============
*/
void PR_LexWhitespace (void)
{
int c;
while (1)
{
// skip whitespace
while ( (c = *pr_file_p) <= ' ')
{
if (c=='\n')
PR_NewLine ();
if (c == 0)
return; // end of file
pr_file_p++;
}
// skip // comments
if (c=='/' && pr_file_p[1] == '/')
{
while (*pr_file_p && *pr_file_p != '\n')
pr_file_p++;
PR_NewLine();
pr_file_p++;
continue;
}
// skip /* */ comments
if (c=='/' && pr_file_p[1] == '*')
{
do
{
pr_file_p++;
if (pr_file_p[0]=='\n')
PR_NewLine();
if (pr_file_p[1] == 0)
return;
} while (pr_file_p[-1] != '*' || pr_file_p[0] != '/');
pr_file_p++;
continue;
}
break; // a real character has been found
}
}
//============================================================================
#define MAX_FRAMES 256
char pr_framemacros[MAX_FRAMES][16];
int pr_nummacros;
void PR_ClearGrabMacros (void)
{
pr_nummacros = 0;
}
void PR_FindMacro (void)
{
int i;
for (i=0 ; i<pr_nummacros ; i++)
if (!strcmp (pr_token, pr_framemacros[i]))
{
sprintf (pr_token,"%d", i);
pr_token_type = tt_immediate;
pr_immediate_type = &type_float;
pr_immediate._float = i;
return;
}
PR_ParseError ("Unknown frame macro $%s", pr_token);
}
// just parses text, returning false if an eol is reached
qboolean PR_SimpleGetToken (void)
{
int c;
int i;
// skip whitespace
while ( (c = *pr_file_p) <= ' ')
{
if (c=='\n' || c == 0)
return false;
pr_file_p++;
}
i = 0;
while ( (c = *pr_file_p) > ' ' && c != ',' && c != ';')
{
pr_token[i] = c;
i++;
pr_file_p++;
}
pr_token[i] = 0;
return true;
}
void PR_ParseFrame (void)
{
while (PR_SimpleGetToken ())
{
strcpy (pr_framemacros[pr_nummacros], pr_token);
pr_nummacros++;
}
}
/*
==============
PR_LexGrab
Deals with counting sequence numbers and replacing frame macros
==============
*/
void PR_LexGrab (void)
{
pr_file_p++; // skip the $
if (!PR_SimpleGetToken ())
PR_ParseError ("hanging $");
// check for $frame
if (!strcmp (pr_token, "frame"))
{
PR_ParseFrame ();
PR_Lex ();
}
// ignore other known $commands
else if (!strcmp (pr_token, "cd")
|| !strcmp (pr_token, "origin")
|| !strcmp (pr_token, "base")
|| !strcmp (pr_token, "flags")
|| !strcmp (pr_token, "scale")
|| !strcmp (pr_token, "skin") )
{ // skip to end of line
while (PR_SimpleGetToken ())
;
PR_Lex ();
}
// look for a frame name macro
else
PR_FindMacro ();
}
//============================================================================
/*
==============
PR_Lex
Sets pr_token, pr_token_type, and possibly pr_immediate and pr_immediate_type
==============
*/
void PR_Lex (void)
{
int c;
pr_token[0] = 0;
if (!pr_file_p)
{
pr_token_type = tt_eof;
return;
}
PR_LexWhitespace ();
c = *pr_file_p;
if (!c)
{
pr_token_type = tt_eof;
return;
}
// handle quoted strings as a unit
if (c == '\"')
{
PR_LexString ();
return;
}
// handle quoted vectors as a unit
if (c == '\'')
{
PR_LexVector ();
return;
}
// if the first character is a valid identifier, parse until a non-id
// character is reached
if ( (c >= '0' && c <= '9') || ( c=='-' && pr_file_p[1]>='0' && pr_file_p[1] <='9') )
{
pr_token_type = tt_immediate;
pr_immediate_type = &type_float;
pr_immediate._float = PR_LexNumber ();
return;
}
if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' )
{
PR_LexName ();
return;
}
if (c == '$')
{
PR_LexGrab ();
return;
}
// parse symbol strings until a non-symbol is found
PR_LexPunctuation ();
}
//=============================================================================
/*
============
PR_ParseError
Aborts the current file load
============
*/
void PR_ParseError (char *error, ...)
{
va_list argptr;
char string[1024];
va_start (argptr,error);
vsprintf (string,error,argptr);
va_end (argptr);
printf ("%s:%i:%s\n", strings + s_file, pr_source_line, string);
longjmp (pr_parse_abort, 1);
}
/*
=============
PR_Expect
Issues an error if the current token isn't equal to string
Gets the next token
=============
*/
void PR_Expect (char *string)
{
if (strcmp (string, pr_token))
PR_ParseError ("expected %s, found %s",string, pr_token);
PR_Lex ();
}
/*
=============
PR_Check
Returns true and gets the next token if the current token equals string
Returns false and does nothing otherwise
=============
*/
qboolean PR_Check (char *string)
{
if (strcmp (string, pr_token))
return false;
PR_Lex ();
return true;
}
/*
============
PR_ParseName
Checks to see if the current token is a valid name
============
*/
char *PR_ParseName (void)
{
static char ident[MAX_NAME];
if (pr_token_type != tt_name)
PR_ParseError ("not a name");
if (strlen(pr_token) >= MAX_NAME-1)
PR_ParseError ("name too long");
strcpy (ident, pr_token);
PR_Lex ();
return ident;
}
/*
============
PR_FindType
Returns a preexisting complex type that matches the parm, or allocates
a new one and copies it out.
============
*/
type_t *PR_FindType (type_t *type)
{
def_t *def;
type_t *check;
int i;
for (check = pr.types ; check ; check = check->next)
{
if (check->type != type->type
|| check->aux_type != type->aux_type
|| check->num_parms != type->num_parms)
continue;
for (i=0 ; i< type->num_parms ; i++)
if (check->parm_types[i] != type->parm_types[i])
break;
if (i == type->num_parms)
return check;
}
// allocate a new one
check = malloc (sizeof (*check));
*check = *type;
check->next = pr.types;
pr.types = check;
// allocate a generic def for the type, so fields can reference it
def = malloc (sizeof(def_t));
def->name = "COMPLEX TYPE";
def->type = check;
check->def = def;
return check;
}
/*
============
PR_SkipToSemicolon
For error recovery, also pops out of nested braces
============
*/
void PR_SkipToSemicolon (void)
{
do
{
if (!pr_bracelevel && PR_Check (";"))
return;
PR_Lex ();
} while (pr_token[0]); // eof will return a null token
}
/*
============
PR_ParseType
Parses a variable type, including field and functions types
============
*/
char pr_parm_names[MAX_PARMS][MAX_NAME];
type_t *PR_ParseType (void)
{
type_t new;
type_t *type;
char *name;
if (PR_Check ("."))
{
memset (&new, 0, sizeof(new));
new.type = ev_field;
new.aux_type = PR_ParseType ();
return PR_FindType (&new);
}
if (!strcmp (pr_token, "float") )
type = &type_float;
else if (!strcmp (pr_token, "vector") )
type = &type_vector;
else if (!strcmp (pr_token, "float") )
type = &type_float;
else if (!strcmp (pr_token, "entity") )
type = &type_entity;
else if (!strcmp (pr_token, "string") )
type = &type_string;
else if (!strcmp (pr_token, "void") )
type = &type_void;
else
{
PR_ParseError ("\"%s\" is not a type", pr_token);
type = &type_float; // shut up compiler warning
}
PR_Lex ();
if (!PR_Check ("("))
return type;
// function type
memset (&new, 0, sizeof(new));
new.type = ev_function;
new.aux_type = type; // return type
new.num_parms = 0;
if (!PR_Check (")"))
{
if (PR_Check ("..."))
new.num_parms = -1; // variable args
else
do
{
type = PR_ParseType ();
name = PR_ParseName ();
strcpy (pr_parm_names[new.num_parms], name);
new.parm_types[new.num_parms] = type;
new.num_parms++;
} while (PR_Check (","));
PR_Expect (")");
}
return PR_FindType (&new);
}

BIN
qutils/QCC/QCC Normal file

Binary file not shown.

808
qutils/QCC/QCC.C Normal file
View File

@@ -0,0 +1,808 @@
#include "qcc.h"
char sourcedir[1024];
char destfile[1024];
float pr_globals[MAX_REGS];
int numpr_globals;
char strings[MAX_STRINGS];
int strofs;
dstatement_t statements[MAX_STATEMENTS];
int numstatements;
int statement_linenums[MAX_STATEMENTS];
dfunction_t functions[MAX_FUNCTIONS];
int numfunctions;
ddef_t globals[MAX_GLOBALS];
int numglobaldefs;
ddef_t fields[MAX_FIELDS];
int numfielddefs;
char precache_sounds[MAX_SOUNDS][MAX_DATA_PATH];
int precache_sounds_block[MAX_SOUNDS];
int numsounds;
char precache_models[MAX_MODELS][MAX_DATA_PATH];
int precache_models_block[MAX_SOUNDS];
int nummodels;
char precache_files[MAX_FILES][MAX_DATA_PATH];
int precache_files_block[MAX_SOUNDS];
int numfiles;
/*
============
WriteFiles
Generates files.dat, which contains all of the
data files actually used by the game, to be
processed by qfiles.exe
============
*/
void WriteFiles (void)
{
FILE *f;
int i;
char filename[1024];
sprintf (filename, "%sfiles.dat", sourcedir);
f = fopen (filename, "w");
if (!f)
Error ("Couldn't open %s", filename);
fprintf (f, "%i\n", numsounds);
for (i=0 ; i<numsounds ; i++)
fprintf (f, "%i %s\n", precache_sounds_block[i],
precache_sounds[i]);
fprintf (f, "%i\n", nummodels);
for (i=0 ; i<nummodels ; i++)
fprintf (f, "%i %s\n", precache_models_block[i],
precache_models[i]);
fprintf (f, "%i\n", numfiles);
for (i=0 ; i<numfiles ; i++)
fprintf (f, "%i %s\n", precache_files_block[i],
precache_files[i]);
fclose (f);
}
// CopyString returns an offset from the string heap
int CopyString (char *str)
{
int old;
old = strofs;
strcpy (strings+strofs, str);
strofs += strlen(str)+1;
return old;
}
void PrintStrings (void)
{
int i, l, j;
for (i=0 ; i<strofs ; i += l)
{
l = strlen(strings+i) + 1;
printf ("%5i : ",i);
for (j=0 ; j<l ; j++)
{
if (strings[i+j] == '\n')
{
putchar ('\\');
putchar ('n');
}
else
putchar (strings[i+j]);
}
printf ("\n");
}
}
void PrintFunctions (void)
{
int i,j;
dfunction_t *d;
for (i=0 ; i<numfunctions ; i++)
{
d = &functions[i];
printf ("%s : %s : %i %i (", strings + d->s_file, strings + d->s_name, d->first_statement, d->parm_start);
for (j=0 ; j<d->numparms ; j++)
printf ("%i ",d->parm_size[j]);
printf (")\n");
}
}
void PrintFields (void)
{
int i;
ddef_t *d;
for (i=0 ; i<numfielddefs ; i++)
{
d = &fields[i];
printf ("%5i : (%i) %s\n", d->ofs, d->type, strings + d->s_name);
}
}
void PrintGlobals (void)
{
int i;
ddef_t *d;
for (i=0 ; i<numglobaldefs ; i++)
{
d = &globals[i];
printf ("%5i : (%i) %s\n", d->ofs, d->type, strings + d->s_name);
}
}
void InitData (void)
{
int i;
numstatements = 1;
strofs = 1;
numfunctions = 1;
numglobaldefs = 1;
numfielddefs = 1;
def_ret.ofs = OFS_RETURN;
for (i=0 ; i<MAX_PARMS ; i++)
def_parms[i].ofs = OFS_PARM0 + 3*i;
}
void WriteData (int crc)
{
def_t *def;
ddef_t *dd;
dprograms_t progs;
FILE *h;
int i;
for (def = pr.def_head.next ; def ; def = def->next)
{
if (def->type->type == ev_function)
{
// df = &functions[numfunctions];
// numfunctions++;
}
else if (def->type->type == ev_field)
{
dd = &fields[numfielddefs];
numfielddefs++;
dd->type = def->type->aux_type->type;
dd->s_name = CopyString (def->name);
dd->ofs = G_INT(def->ofs);
}
dd = &globals[numglobaldefs];
numglobaldefs++;
dd->type = def->type->type;
if ( !def->initialized
&& def->type->type != ev_function
&& def->type->type != ev_field
&& def->scope == NULL)
dd->type |= DEF_SAVEGLOBGAL;
dd->s_name = CopyString (def->name);
dd->ofs = def->ofs;
}
//PrintStrings ();
//PrintFunctions ();
//PrintFields ();
//PrintGlobals ();
strofs = (strofs+3)&~3;
printf ("%6i strofs\n", strofs);
printf ("%6i numstatements\n", numstatements);
printf ("%6i numfunctions\n", numfunctions);
printf ("%6i numglobaldefs\n", numglobaldefs);
printf ("%6i numfielddefs\n", numfielddefs);
printf ("%6i numpr_globals\n", numpr_globals);
h = SafeOpenWrite (destfile);
SafeWrite (h, &progs, sizeof(progs));
progs.ofs_strings = ftell (h);
progs.numstrings = strofs;
SafeWrite (h, strings, strofs);
progs.ofs_statements = ftell (h);
progs.numstatements = numstatements;
for (i=0 ; i<numstatements ; i++)
{
statements[i].op = LittleShort(statements[i].op);
statements[i].a = LittleShort(statements[i].a);
statements[i].b = LittleShort(statements[i].b);
statements[i].c = LittleShort(statements[i].c);
}
SafeWrite (h, statements, numstatements*sizeof(dstatement_t));
progs.ofs_functions = ftell (h);
progs.numfunctions = numfunctions;
for (i=0 ; i<numfunctions ; i++)
{
functions[i].first_statement = LittleLong (functions[i].first_statement);
functions[i].parm_start = LittleLong (functions[i].parm_start);
functions[i].s_name = LittleLong (functions[i].s_name);
functions[i].s_file = LittleLong (functions[i].s_file);
functions[i].numparms = LittleLong (functions[i].numparms);
functions[i].locals = LittleLong (functions[i].locals);
}
SafeWrite (h, functions, numfunctions*sizeof(dfunction_t));
progs.ofs_globaldefs = ftell (h);
progs.numglobaldefs = numglobaldefs;
for (i=0 ; i<numglobaldefs ; i++)
{
globals[i].type = LittleShort (globals[i].type);
globals[i].ofs = LittleShort (globals[i].ofs);
globals[i].s_name = LittleLong (globals[i].s_name);
}
SafeWrite (h, globals, numglobaldefs*sizeof(ddef_t));
progs.ofs_fielddefs = ftell (h);
progs.numfielddefs = numfielddefs;
for (i=0 ; i<numfielddefs ; i++)
{
fields[i].type = LittleShort (fields[i].type);
fields[i].ofs = LittleShort (fields[i].ofs);
fields[i].s_name = LittleLong (fields[i].s_name);
}
SafeWrite (h, fields, numfielddefs*sizeof(ddef_t));
progs.ofs_globals = ftell (h);
progs.numglobals = numpr_globals;
for (i=0 ; i<numpr_globals ; i++)
((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]);
SafeWrite (h, pr_globals, numpr_globals*4);
printf ("%6i TOTAL SIZE\n", (int)ftell (h));
progs.entityfields = pr.size_fields;
progs.version = PROG_VERSION;
progs.crc = crc;
// byte swap the header and write it out
for (i=0 ; i<sizeof(progs)/4 ; i++)
((int *)&progs)[i] = LittleLong ( ((int *)&progs)[i] );
fseek (h, 0, SEEK_SET);
SafeWrite (h, &progs, sizeof(progs));
fclose (h);
}
/*
===============
PR_String
Returns a string suitable for printing (no newlines, max 60 chars length)
===============
*/
char *PR_String (char *string)
{
static char buf[80];
char *s;
s = buf;
*s++ = '"';
while (string && *string)
{
if (s == buf + sizeof(buf) - 2)
break;
if (*string == '\n')
{
*s++ = '\\';
*s++ = 'n';
}
else if (*string == '"')
{
*s++ = '\\';
*s++ = '"';
}
else
*s++ = *string;
string++;
if (s - buf > 60)
{
*s++ = '.';
*s++ = '.';
*s++ = '.';
break;
}
}
*s++ = '"';
*s++ = 0;
return buf;
}
def_t *PR_DefForFieldOfs (gofs_t ofs)
{
def_t *d;
for (d=pr.def_head.next ; d ; d=d->next)
{
if (d->type->type != ev_field)
continue;
if (*((int *)&pr_globals[d->ofs]) == ofs)
return d;
}
Error ("PR_DefForFieldOfs: couldn't find %i",ofs);
return NULL;
}
/*
============
PR_ValueString
Returns a string describing *data in a type specific manner
=============
*/
char *PR_ValueString (etype_t type, void *val)
{
static char line[256];
def_t *def;
dfunction_t *f;
switch (type)
{
case ev_string:
sprintf (line, "%s", PR_String(strings + *(int *)val));
break;
case ev_entity:
sprintf (line, "entity %i", *(int *)val);
break;
case ev_function:
f = functions + *(int *)val;
if (!f)
sprintf (line, "undefined function");
else
sprintf (line, "%s()", strings + f->s_name);
break;
case ev_field:
def = PR_DefForFieldOfs ( *(int *)val );
sprintf (line, ".%s", def->name);
break;
case ev_void:
sprintf (line, "void");
break;
case ev_float:
sprintf (line, "%5.1f", *(float *)val);
break;
case ev_vector:
sprintf (line, "'%5.1f %5.1f %5.1f'", ((float *)val)[0], ((float *)val)[1], ((float *)val)[2]);
break;
case ev_pointer:
sprintf (line, "pointer");
break;
default:
sprintf (line, "bad type %i", type);
break;
}
return line;
}
/*
============
PR_GlobalString
Returns a string with a description and the contents of a global,
padded to 20 field width
============
*/
char *PR_GlobalStringNoContents (gofs_t ofs)
{
int i;
def_t *def;
void *val;
static char line[128];
val = (void *)&pr_globals[ofs];
def = pr_global_defs[ofs];
if (!def)
// Error ("PR_GlobalString: no def for %i", ofs);
sprintf (line,"%i(???)", ofs);
else
sprintf (line,"%i(%s)", ofs, def->name);
i = strlen(line);
for ( ; i<16 ; i++)
strcat (line," ");
strcat (line," ");
return line;
}
char *PR_GlobalString (gofs_t ofs)
{
char *s;
int i;
def_t *def;
void *val;
static char line[128];
val = (void *)&pr_globals[ofs];
def = pr_global_defs[ofs];
if (!def)
return PR_GlobalStringNoContents(ofs);
if (def->initialized && def->type->type != ev_function)
{
s = PR_ValueString (def->type->type, &pr_globals[ofs]);
sprintf (line,"%i(%s)", ofs, s);
}
else
sprintf (line,"%i(%s)", ofs, def->name);
i = strlen(line);
for ( ; i<16 ; i++)
strcat (line," ");
strcat (line," ");
return line;
}
/*
============
PR_PrintOfs
============
*/
void PR_PrintOfs (gofs_t ofs)
{
printf ("%s\n",PR_GlobalString(ofs));
}
/*
=================
PR_PrintStatement
=================
*/
void PR_PrintStatement (dstatement_t *s)
{
int i;
printf ("%4i : %4i : %s ", (int)(s - statements), statement_linenums[s-statements], pr_opcodes[s->op].opname);
i = strlen(pr_opcodes[s->op].opname);
for ( ; i<10 ; i++)
printf (" ");
if (s->op == OP_IF || s->op == OP_IFNOT)
printf ("%sbranch %i",PR_GlobalString(s->a),s->b);
else if (s->op == OP_GOTO)
{
printf ("branch %i",s->a);
}
else if ( (unsigned)(s->op - OP_STORE_F) < 6)
{
printf ("%s",PR_GlobalString(s->a));
printf ("%s", PR_GlobalStringNoContents(s->b));
}
else
{
if (s->a)
printf ("%s",PR_GlobalString(s->a));
if (s->b)
printf ("%s",PR_GlobalString(s->b));
if (s->c)
printf ("%s", PR_GlobalStringNoContents(s->c));
}
printf ("\n");
}
/*
============
PR_PrintDefs
============
*/
void PR_PrintDefs (void)
{
def_t *d;
for (d=pr.def_head.next ; d ; d=d->next)
PR_PrintOfs (d->ofs);
}
/*
==============
PR_BeginCompilation
called before compiling a batch of files, clears the pr struct
==============
*/
void PR_BeginCompilation (void *memory, int memsize)
{
int i;
pr.memory = memory;
pr.max_memory = memsize;
numpr_globals = RESERVED_OFS;
pr.def_tail = &pr.def_head;
for (i=0 ; i<RESERVED_OFS ; i++)
pr_global_defs[i] = &def_void;
// link the function type in so state forward declarations match proper type
pr.types = &type_function;
type_function.next = NULL;
pr_error_count = 0;
}
/*
==============
PR_FinishCompilation
called after all files are compiled to check for errors
Returns false if errors were detected.
==============
*/
qboolean PR_FinishCompilation (void)
{
def_t *d;
qboolean errors;
errors = false;
// check to make sure all functions prototyped have code
for (d=pr.def_head.next ; d ; d=d->next)
{
if (d->type->type == ev_function && !d->scope)// function parms are ok
{
// f = G_FUNCTION(d->ofs);
// if (!f || (!f->code && !f->builtin) )
if (!d->initialized)
{
printf ("function %s was not defined\n",d->name);
errors = true;
}
}
}
return !errors;
}
//=============================================================================
/*
============
PR_WriteProgdefs
Writes the global and entity structures out
Returns a crc of the header, to be stored in the progs file for comparison
at load time.
============
*/
int PR_WriteProgdefs (char *filename)
{
def_t *d;
FILE *f;
unsigned short crc;
int c;
printf ("writing %s\n", filename);
f = fopen (filename, "w");
// print global vars until the first field is defined
fprintf (f,"\n/* file generated by qcc, do not modify */\n\ntypedef struct\n{\tint\tpad[%i];\n", RESERVED_OFS);
for (d=pr.def_head.next ; d ; d=d->next)
{
if (!strcmp (d->name, "end_sys_globals"))
break;
switch (d->type->type)
{
case ev_float:
fprintf (f, "\tfloat\t%s;\n",d->name);
break;
case ev_vector:
fprintf (f, "\tvec3_t\t%s;\n",d->name);
d=d->next->next->next; // skip the elements
break;
case ev_string:
fprintf (f,"\tstring_t\t%s;\n",d->name);
break;
case ev_function:
fprintf (f,"\tfunc_t\t%s;\n",d->name);
break;
case ev_entity:
fprintf (f,"\tint\t%s;\n",d->name);
break;
default:
fprintf (f,"\tint\t%s;\n",d->name);
break;
}
}
fprintf (f,"} globalvars_t;\n\n");
// print all fields
fprintf (f,"typedef struct\n{\n");
for (d=pr.def_head.next ; d ; d=d->next)
{
if (!strcmp (d->name, "end_sys_fields"))
break;
if (d->type->type != ev_field)
continue;
switch (d->type->aux_type->type)
{
case ev_float:
fprintf (f,"\tfloat\t%s;\n",d->name);
break;
case ev_vector:
fprintf (f,"\tvec3_t\t%s;\n",d->name);
d=d->next->next->next; // skip the elements
break;
case ev_string:
fprintf (f,"\tstring_t\t%s;\n",d->name);
break;
case ev_function:
fprintf (f,"\tfunc_t\t%s;\n",d->name);
break;
case ev_entity:
fprintf (f,"\tint\t%s;\n",d->name);
break;
default:
fprintf (f,"\tint\t%s;\n",d->name);
break;
}
}
fprintf (f,"} entvars_t;\n\n");
fclose (f);
// do a crc of the file
CRC_Init (&crc);
f = fopen (filename, "r+");
while ((c = fgetc(f)) != EOF)
CRC_ProcessByte (&crc, (byte)c);
fprintf (f,"#define PROGHEADER_CRC %i\n", crc);
fclose (f);
return crc;
}
void PrintFunction (char *name)
{
int i;
dstatement_t *ds;
dfunction_t *df;
for (i=0 ; i<numfunctions ; i++)
if (!strcmp (name, strings + functions[i].s_name))
break;
if (i==numfunctions)
Error ("No function names \"%s\"", name);
df = functions + i;
printf ("Statements for %s:\n", name);
ds = statements + df->first_statement;
while (1)
{
PR_PrintStatement (ds);
if (!ds->op)
break;
ds++;
}
}
//============================================================================
/*
============
main
============
*/
void main (int argc, char **argv)
{
char *src;
char *src2;
char filename[1024];
int p, crc;
double start, stop;
start = I_FloatTime ();
myargc = argc;
myargv = argv;
if ( CheckParm ("-?") || CheckParm ("-help"))
{
printf ("qcc looks for progs.src in the current directory.\n");
printf ("to look in a different directory: qcc -src <directory>\n");
printf ("to build a clean data tree: qcc -copy <srcdir> <destdir>\n");
printf ("to build a clean pak file: qcc -pak <srcdir> <packfile>\n");
printf ("to bsp all bmodels: qcc -bspmodels <gamedir>\n");
return;
}
p = CheckParm ("-src");
if (p && p < argc-1 )
{
strcpy (sourcedir, argv[p+1]);
strcat (sourcedir, "/");
printf ("Source directory: %s\n", sourcedir);
}
else
strcpy (sourcedir, "");
InitData ();
sprintf (filename, "%sprogs.src", sourcedir);
LoadFile (filename, (void *)&src);
src = COM_Parse (src);
if (!src)
Error ("No destination filename. qcc -help for info.\n");
strcpy (destfile, com_token);
printf ("outputfile: %s\n", destfile);
pr_dumpasm = false;
PR_BeginCompilation (malloc (0x100000), 0x100000);
// compile all the files
do
{
src = COM_Parse(src);
if (!src)
break;
sprintf (filename, "%s%s", sourcedir, com_token);
printf ("compiling %s\n", filename);
LoadFile (filename, (void *)&src2);
if (!PR_CompileFile (src2, filename) )
exit (1);
} while (1);
if (!PR_FinishCompilation ())
Error ("compilation errors");
p = CheckParm ("-asm");
if (p)
{
for (p++ ; p<argc ; p++)
{
if (argv[p][0] == '-')
break;
PrintFunction (argv[p]);
}
}
// write progdefs.h
crc = PR_WriteProgdefs ("progdefs.h");
// write data file
WriteData (crc);
// write files.dat
WriteFiles ();
stop = I_FloatTime ();
printf ("%i seconds elapsed.\n", (int)(stop-start));
}

436
qutils/QCC/QCC.H Normal file
View File

@@ -0,0 +1,436 @@
#include "cmdlib.h"
#include <stdio.h>
#include <setjmp.h>
#include "pr_comp.h"
/*
TODO:
"stopped at 10 errors"
other pointer types for models and clients?
compact string heap?
allways initialize all variables to something safe
the def->type->type arrangement is really silly.
return type checking
parm count type checking
immediate overflow checking
pass the first two parms in call->b and call->c
*/
/*
comments
--------
// comments discard text until the end of line
/ * * / comments discard all enclosed text (spaced out on this line because this documentation is in a regular C comment block, and typing them in normally causes a parse error)
code structure
--------------
A definition is:
<type> <name> [ = <immediate>] {, <name> [ = <immediate>] };
types
-----
simple types: void, float, vector, string, or entity
float width, height;
string name;
entity self, other;
vector types:
vector org; // also creates org_x, org_y, and org_z float defs
A function type is specified as: simpletype ( type name {,type name} )
The names are ignored except when the function is initialized.
void() think;
entity() FindTarget;
void(vector destination, float speed, void() callback) SUB_CalcMove;
void(...) dprint; // variable argument builtin
A field type is specified as: .type
.vector origin;
.string netname;
.void() think, touch, use;
names
-----
Names are a maximum of 64 characters, must begin with A-Z,a-z, or _, and can continue with those characters or 0-9.
There are two levels of scoping: global, and function. The parameter list of a function and any vars declared inside a function with the "local" statement are only visible within that function,
immediates
----------
Float immediates must begin with 0-9 or minus sign. .5 is illegal.
A parsing ambiguity is present with negative constants. "a-5" will be parsed as "a", then "-5", causing an error. Seperate the - from the digits with a space "a - 5" to get the proper behavior.
12
1.6
0.5
-100
Vector immediates are three float immediates enclosed in single quotes.
'0 0 0'
'20.5 -10 0.00001'
String immediates are characters enclosed in double quotes. The string cannot contain explicit newlines, but the escape character \n can embed one. The \" escape can be used to include a quote in the string.
"maps/jrwiz1.bsp"
"sound/nin/pain.wav"
"ouch!\n"
Code immediates are statements enclosed in {} braces.
statement:
{ <multiple statements> }
<expression>;
local <type> <name> [ = <immediate>] {, <name> [ = <immediate>] };
return <expression>;
if ( <expression> ) <statement> [ else <statement> ];
while ( <expression> ) <statement>;
do <statement> while ( <expression> );
<function name> ( <function parms> );
expression:
combiations of names and these operators with standard C precedence:
"&&", "||", "<=", ">=","==", "!=", "!", "*", "/", "-", "+", "=", ".", "<", ">", "&", "|"
Parenthesis can be used to alter order of operation.
The & and | operations perform integral bit ops on floats
A built in function immediate is a number sign followed by an integer.
#1
#12
compilation
-----------
Source files are processed sequentially without dumping any state, so if a defs file is the first one processed, the definitions will be available to all other files.
The language is strongly typed and there are no casts.
Anything that is initialized is assumed to be constant, and will have immediates folded into it. If you change the value, your program will malfunction. All uninitialized globals will be saved to savegame files.
Functions cannot have more than eight parameters.
Error recovery during compilation is minimal. It will skip to the next global definition, so you will never see more than one error at a time in a given function. All compilation aborts after ten error messages.
Names can be defined multiple times until they are defined with an initialization, allowing functions to be prototyped before their definition.
void() MyFunction; // the prototype
void() MyFunction = // the initialization
{
dprint ("we're here\n");
};
entities and fields
-------------------
execution
---------
Code execution is initiated by C code in quake from two main places: the timed think routines for periodic control, and the touch function when two objects impact each other.
There are three global variables that are set before beginning code execution:
entity world; // the server's world object, which holds all global
// state for the server, like the deathmatch flags
// and the body ques.
entity self; // the entity the function is executing for
entity other; // the other object in an impact, not used for thinks
float time; // the current game time. Note that because the
// entities in the world are simulated sequentially,
// time is NOT strictly increasing. An impact late
// in one entity's time slice may set time higher
// than the think function of the next entity.
// The difference is limited to 0.1 seconds.
Execution is also caused by a few uncommon events, like the addition of a new client to an existing server.
There is a runnaway counter that stops a program if 100000 statements are executed, assuming it is in an infinite loop.
It is acceptable to change the system set global variables. This is usually done to pose as another entity by changing self and calling a function.
The interpretation is fairly efficient, but it is still over an order of magnitude slower than compiled C code. All time consuming operations should be made into built in functions.
A profile counter is kept for each function, and incremented for each interpreted instruction inside that function. The "profile" console command in Quake will dump out the top 10 functions, then clear all the counters. The "profile all" command will dump sorted stats for every function that has been executed.
afunc ( 4, bfunc(1,2,3));
will fail because there is a shared parameter marshaling area, which will cause the 1 from bfunc to overwrite the 4 allready placed in parm0. When a function is called, it copies the parms from the globals into it's privately scoped variables, so there is no collision when calling another function.
total = factorial(3) + factorial(4);
Will fail because the return value from functions is held in a single global area. If this really gets on your nerves, tell me and I can work around it at a slight performance and space penalty by allocating a new register for the function call and copying it out.
built in functions
------------------
void(string text) dprint;
Prints the string to the server console.
void(entity client, string text) cprint;
Prints a message to a specific client.
void(string text) bprint;
Broadcast prints a message to all clients on the current server.
entity() spawn;
Returns a totally empty entity. You can manually set everything up, or just set the origin and call one of the existing entity setup functions.
entity(entity start, .string field, string match) find;
Searches the server entity list beginning at start, looking for an entity that has entity.field = match. To start at the beginning of the list, pass world. World is returned when the end of the list is reached.
<FIXME: define all the other functions...>
gotchas
-------
The && and || operators DO NOT EARLY OUT like C!
Don't confuse single quoted vectors with double quoted strings
The function declaration syntax takes a little getting used to.
Don't forget the ; after the trailing brace of a function initialization.
Don't forget the "local" before defining local variables.
There are no ++ / -- operators, or operate/assign operators.
*/
//=============================================================================
// offsets are allways multiplied by 4 before using
typedef int gofs_t; // offset in global data block
typedef struct function_s function_t;
#define MAX_PARMS 8
typedef struct type_s
{
etype_t type;
struct def_s *def; // a def that points to this type
struct type_s *next;
// function types are more complex
struct type_s *aux_type; // return type or field type
int num_parms; // -1 = variable args
struct type_s *parm_types[MAX_PARMS]; // only [num_parms] allocated
} type_t;
typedef struct def_s
{
type_t *type;
char *name;
struct def_s *next;
struct def_s *search_next; // for finding faster
gofs_t ofs;
struct def_s *scope; // function the var was defined in, or NULL
int initialized; // 1 when a declaration included "= immediate"
} def_t;
//============================================================================
// pr_loc.h -- program local defs
#define MAX_ERRORS 10
#define MAX_NAME 64 // chars long
#define MAX_REGS 16384
//=============================================================================
typedef union eval_s
{
string_t string;
float _float;
float vector[3];
func_t function;
int _int;
union eval_s *ptr;
} eval_t;
extern int type_size[8];
extern def_t *def_for_type[8];
extern type_t type_void, type_string, type_float, type_vector, type_entity, type_field, type_function, type_pointer, type_floatfield;
extern def_t def_void, def_string, def_float, def_vector, def_entity, def_field, def_function, def_pointer;
struct function_s
{
int builtin; // if non 0, call an internal function
int code; // first statement
char *file; // source file with definition
int file_line;
struct def_s *def;
int parm_ofs[MAX_PARMS]; // allways contiguous, right?
};
//
// output generated by prog parsing
//
typedef struct
{
char *memory;
int max_memory;
int current_memory;
type_t *types;
def_t def_head; // unused head of linked list
def_t *def_tail; // add new defs after this and move it
def_t *search; // search chain through defs
int size_fields;
} pr_info_t;
extern pr_info_t pr;
typedef struct
{
char *name;
char *opname;
float priority;
qboolean right_associative;
def_t *type_a, *type_b, *type_c;
} opcode_t;
//============================================================================
extern opcode_t pr_opcodes[99]; // sized by initialization
extern qboolean pr_dumpasm;
extern def_t *pr_global_defs[MAX_REGS]; // to find def for a global variable
typedef enum {
tt_eof, // end of file reached
tt_name, // an alphanumeric name token
tt_punct, // code punctuation
tt_immediate, // string, float, vector
} token_type_t;
extern char pr_token[2048];
extern token_type_t pr_token_type;
extern type_t *pr_immediate_type;
extern eval_t pr_immediate;
void PR_PrintStatement (dstatement_t *s);
void PR_Lex (void);
// reads the next token into pr_token and classifies its type
type_t *PR_ParseType (void);
char *PR_ParseName (void);
qboolean PR_Check (char *string);
void PR_Expect (char *string);
void PR_ParseError (char *error, ...);
extern jmp_buf pr_parse_abort; // longjump with this on parse error
extern int pr_source_line;
extern char *pr_file_p;
void *PR_Malloc (int size);
#define OFS_NULL 0
#define OFS_RETURN 1
#define OFS_PARM0 4 // leave 3 ofs for each parm to hold vectors
#define OFS_PARM1 7
#define OFS_PARM2 10
#define OFS_PARM3 13
#define OFS_PARM4 16
#define RESERVED_OFS 28
extern def_t *pr_scope;
extern int pr_error_count;
void PR_NewLine (void);
def_t *PR_GetDef (type_t *type, char *name, def_t *scope, qboolean allocate);
void PR_PrintDefs (void);
void PR_SkipToSemicolon (void);
extern char pr_parm_names[MAX_PARMS][MAX_NAME];
extern qboolean pr_trace;
#define G_FLOAT(o) (pr_globals[o])
#define G_INT(o) (*(int *)&pr_globals[o])
#define G_VECTOR(o) (&pr_globals[o])
#define G_STRING(o) (strings + *(string_t *)&pr_globals[o])
#define G_FUNCTION(o) (*(func_t *)&pr_globals[o])
char *PR_ValueString (etype_t type, void *val);
void PR_ClearGrabMacros (void);
qboolean PR_CompileFile (char *string, char *filename);
extern qboolean pr_dumpasm;
extern string_t s_file; // filename for function definition
extern def_t def_ret, def_parms[MAX_PARMS];
//=============================================================================
#define MAX_STRINGS 500000
#define MAX_GLOBALS 16384
#define MAX_FIELDS 1024
#define MAX_STATEMENTS 65536
#define MAX_FUNCTIONS 8192
#define MAX_SOUNDS 1024
#define MAX_MODELS 1024
#define MAX_FILES 1024
#define MAX_DATA_PATH 64
extern char strings[MAX_STRINGS];
extern int strofs;
extern dstatement_t statements[MAX_STATEMENTS];
extern int numstatements;
extern int statement_linenums[MAX_STATEMENTS];
extern dfunction_t functions[MAX_FUNCTIONS];
extern int numfunctions;
extern float pr_globals[MAX_REGS];
extern int numpr_globals;
extern char pr_immediate_string[2048];
extern char precache_sounds[MAX_SOUNDS][MAX_DATA_PATH];
extern int precache_sounds_block[MAX_SOUNDS];
extern int numsounds;
extern char precache_models[MAX_MODELS][MAX_DATA_PATH];
extern int precache_models_block[MAX_SOUNDS];
extern int nummodels;
extern char precache_files[MAX_FILES][MAX_DATA_PATH];
extern int precache_files_block[MAX_SOUNDS];
extern int numfiles;
int CopyString (char *str);

249
qutils/QCC/QCC.MAK Normal file
View File

@@ -0,0 +1,249 @@
# Microsoft Developer Studio Generated NMAKE File, Format Version 4.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
!IF "$(CFG)" == ""
CFG=qcc - Win32 Debug
!MESSAGE No configuration specified. Defaulting to qcc - Win32 Debug.
!ENDIF
!IF "$(CFG)" != "qcc - Win32 Release" && "$(CFG)" != "qcc - Win32 Debug"
!MESSAGE Invalid configuration "$(CFG)" specified.
!MESSAGE You can specify a configuration when running NMAKE on this makefile
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "qcc.mak" CFG="qcc - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "qcc - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "qcc - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
!ERROR An invalid configuration is specified.
!ENDIF
!IF "$(OS)" == "Windows_NT"
NULL=
!ELSE
NULL=nul
!ENDIF
################################################################################
# Begin Project
# PROP Target_Last_Scanned "qcc - Win32 Debug"
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "qcc - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
OUTDIR=.\Release
INTDIR=.\Release
ALL : "$(OUTDIR)\qcc.exe"
CLEAN :
-@erase ".\Release\qcc.exe"
-@erase ".\Release\qcc.obj"
-@erase ".\Release\pr_comp.obj"
-@erase ".\Release\pr_lex.obj"
-@erase ".\Release\cmdlib.obj"
-@erase ".\Release\vc40.pdb"
-@erase ".\Release\qcc.map"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
# ADD CPP /nologo /GX /Zi /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
CPP_PROJ=/nologo /ML /GX /Zi /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\
"_CONSOLE" /Fp"$(INTDIR)/qcc.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
CPP_OBJS=.\Release/
CPP_SBRS=
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o"$(OUTDIR)/qcc.bsc"
BSC32_SBRS=
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /profile /map /machine:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:console /profile /map:"$(INTDIR)/qcc.map"\
/machine:I386 /out:"$(OUTDIR)/qcc.exe"
LINK32_OBJS= \
"$(INTDIR)/qcc.obj" \
"$(INTDIR)/pr_comp.obj" \
"$(INTDIR)/pr_lex.obj" \
"$(INTDIR)/cmdlib.obj"
"$(OUTDIR)\qcc.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ELSEIF "$(CFG)" == "qcc - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
OUTDIR=.\Debug
INTDIR=.\Debug
ALL : "$(OUTDIR)\qcc.exe"
CLEAN :
-@erase ".\Debug\vc40.pdb"
-@erase ".\Debug\vc40.idb"
-@erase ".\Debug\qcc.exe"
-@erase ".\Debug\pr_lex.obj"
-@erase ".\Debug\qcc.obj"
-@erase ".\Debug\cmdlib.obj"
-@erase ".\Debug\pr_comp.obj"
-@erase ".\Debug\qcc.map"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
# ADD CPP /nologo /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
CPP_PROJ=/nologo /MLd /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D\
"_CONSOLE" /Fp"$(INTDIR)/qcc.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
CPP_OBJS=.\Debug/
CPP_SBRS=
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o"$(OUTDIR)/qcc.bsc"
BSC32_SBRS=
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /profile /map /debug /machine:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:console /profile /map:"$(INTDIR)/qcc.map"\
/debug /machine:I386 /out:"$(OUTDIR)/qcc.exe"
LINK32_OBJS= \
"$(INTDIR)/pr_lex.obj" \
"$(INTDIR)/qcc.obj" \
"$(INTDIR)/cmdlib.obj" \
"$(INTDIR)/pr_comp.obj"
"$(OUTDIR)\qcc.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ENDIF
.c{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.c{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
################################################################################
# Begin Target
# Name "qcc - Win32 Release"
# Name "qcc - Win32 Debug"
!IF "$(CFG)" == "qcc - Win32 Release"
!ELSEIF "$(CFG)" == "qcc - Win32 Debug"
!ENDIF
################################################################################
# Begin Source File
SOURCE=.\pr_comp.c
DEP_CPP_PR_CO=\
".\qcc.h"\
".\..\common\cmdlib.h"\
".\pr_comp.h"\
"$(INTDIR)\pr_comp.obj" : $(SOURCE) $(DEP_CPP_PR_CO) "$(INTDIR)"
# End Source File
################################################################################
# Begin Source File
SOURCE=.\qcc.c
DEP_CPP_QCC_C=\
".\qcc.h"\
".\..\common\cmdlib.h"\
".\pr_comp.h"\
"$(INTDIR)\qcc.obj" : $(SOURCE) $(DEP_CPP_QCC_C) "$(INTDIR)"
# End Source File
################################################################################
# Begin Source File
SOURCE=.\pr_lex.c
DEP_CPP_PR_LE=\
".\qcc.h"\
".\..\common\cmdlib.h"\
".\pr_comp.h"\
"$(INTDIR)\pr_lex.obj" : $(SOURCE) $(DEP_CPP_PR_LE) "$(INTDIR)"
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\cmdlib.c
DEP_CPP_CMDLI=\
".\..\common\cmdlib.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
{$(INCLUDE)}"\sys\STAT.H"\
"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
# End Target
# End Project
################################################################################

BIN
qutils/QCC/QCC.MDP Normal file

Binary file not shown.

BIN
qutils/QCC/QCC.NCB Normal file

Binary file not shown.

BIN
qutils/QCC/QCC.PDB Normal file

Binary file not shown.

BIN
qutils/QCC/VC40.PDB Normal file

Binary file not shown.

251
qutils/QFILES/QFILES.C Normal file
View File

@@ -0,0 +1,251 @@
#include "cmdlib.h"
#define MAX_SOUNDS 1024
#define MAX_MODELS 1024
#define MAX_FILES 1024
#define MAX_DATA_PATH 64
char precache_sounds[MAX_SOUNDS][MAX_DATA_PATH];
int precache_sounds_block[MAX_SOUNDS];
int numsounds;
char precache_models[MAX_MODELS][MAX_DATA_PATH];
int precache_models_block[MAX_SOUNDS];
int nummodels;
char precache_files[MAX_FILES][MAX_DATA_PATH];
int precache_files_block[MAX_SOUNDS];
int numfiles;
typedef struct
{
char name[56];
int filepos, filelen;
} packfile_t;
typedef struct
{
char id[4];
int dirofs;
int dirlen;
} packheader_t;
packfile_t pfiles[4096], *pf;
FILE *packhandle;
int packbytes;
/*
===========
PackFile
Copy a file into the pak file
===========
*/
void PackFile (char *src, char *name)
{
FILE *in;
int remaining, count;
char buf[4096];
if ( (byte *)pf - (byte *)pfiles > sizeof(pfiles) )
Error ("Too many files in pak file");
in = SafeOpenRead (src);
remaining = filelength (in);
pf->filepos = LittleLong (ftell (packhandle));
pf->filelen = LittleLong (remaining);
strcpy (pf->name, name);
printf ("%64s : %7i\n", pf->name, remaining);
packbytes += remaining;
while (remaining)
{
if (remaining < sizeof(buf))
count = remaining;
else
count = sizeof(buf);
SafeRead (in, buf, count);
SafeWrite (packhandle, buf, count);
remaining -= count;
}
fclose (in);
pf++;
}
/*
===========
CopyQFiles
===========
*/
void CopyQFiles (int blocknum)
{
int i, p;
char srcfile[1024];
char destfile[1024];
char name[1024];
packheader_t header;
int dirlen;
unsigned short crc;
// create a pak file
pf = pfiles;
sprintf (destfile, "%spak%i.pak", gamedir, blocknum);
packhandle = SafeOpenWrite (destfile);
SafeWrite (packhandle, &header, sizeof(header));
blocknum++;
for (i=0 ; i<numsounds ; i++)
{
if (precache_sounds_block[i] != blocknum)
continue;
sprintf (name, "sound/%s", precache_sounds[i]);
sprintf (srcfile,"%s%s",gamedir, name);
PackFile (srcfile, name);
}
for (i=0 ; i<nummodels ; i++)
{
if (precache_models_block[i] != blocknum)
continue;
sprintf (srcfile,"%s%s",gamedir, precache_models[i]);
PackFile (srcfile, precache_models[i]);
}
for (i=0 ; i<numfiles ; i++)
{
if (precache_files_block[i] != blocknum)
continue;
sprintf (srcfile,"%s%s",gamedir, precache_files[i]);
PackFile (srcfile, precache_files[i]);
}
header.id[0] = 'P';
header.id[1] = 'A';
header.id[2] = 'C';
header.id[3] = 'K';
dirlen = (byte *)pf - (byte *)pfiles;
header.dirofs = LittleLong(ftell (packhandle));
header.dirlen = LittleLong(dirlen);
SafeWrite (packhandle, pfiles, dirlen);
fseek (packhandle, 0, SEEK_SET);
SafeWrite (packhandle, &header, sizeof(header));
fclose (packhandle);
// do a crc of the file
CRC_Init (&crc);
for (i=0 ; i<dirlen ; i++)
CRC_ProcessByte (&crc, ((byte *)pfiles)[i]);
i = pf - pfiles;
printf ("%i files packed in %i bytes (%i crc)\n",i, packbytes, crc);
}
/*
=================
BspModels
Runs qbsp and light on all of the models with a .bsp extension
=================
*/
void BspModels (void)
{
int p;
int i;
char *m;
char cmd[1024];
char name[256];
for (i=0 ; i<nummodels ; i++)
{
m = precache_models[i];
if (strcmp(m+strlen(m)-4, ".bsp"))
continue;
strcpy (name, m);
name[strlen(m)-4] = 0;
sprintf (cmd, "qbsp %s%s",gamedir, name);
system (cmd);
sprintf (cmd, "light -extra %s%s", gamedir, name);
system (cmd);
}
}
/*
=============
ReadFiles
=============
*/
int ReadFiles (void)
{
FILE *f;
int i;
f = SafeOpenRead ("files.dat");
fscanf (f, "%i\n", &numsounds);
for (i=0 ; i<numsounds ; i++)
fscanf (f, "%i %s\n", &precache_sounds_block[i],
precache_sounds[i]);
fscanf (f, "%i\n", &nummodels);
for (i=0 ; i<nummodels ; i++)
fscanf (f, "%i %s\n", &precache_models_block[i],
precache_models[i]);
fscanf (f, "%i\n", &numfiles);
for (i=0 ; i<numfiles ; i++)
fscanf (f, "%i %s\n", &precache_files_block[i],
precache_files[i]);
fclose (f);
printf ("%3i sounds\n", numsounds);
printf ("%3i models\n", nummodels);
printf ("%3i files\n", numfiles);
}
/*
=============
main
=============
*/
int main (int argc, char **argv)
{
if (argc == 1)
{
printf ("qfiles -pak <0 / 1> : build a .pak file\n");
printf ("qfiles -bspmodels : regenerates all brush models\n");
exit (1);
}
SetQdirFromPath ("");
ReadFiles ();
if (!strcmp (argv[1], "-pak"))
{
CopyQFiles (atoi(argv[2]));
}
else if (!strcmp (argv[1], "-bspmodels"))
{
BspModels ();
}
else
Error ("unknown command: %s", argv[1]);
return 0;
}

221
qutils/QFILES/QFILES.MAK Normal file
View File

@@ -0,0 +1,221 @@
# Microsoft Developer Studio Generated NMAKE File, Format Version 4.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
!IF "$(CFG)" == ""
CFG=qfiles - Win32 Debug
!MESSAGE No configuration specified. Defaulting to qfiles - Win32 Debug.
!ENDIF
!IF "$(CFG)" != "qfiles - Win32 Release" && "$(CFG)" != "qfiles - Win32 Debug"
!MESSAGE Invalid configuration "$(CFG)" specified.
!MESSAGE You can specify a configuration when running NMAKE on this makefile
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "qfiles.mak" CFG="qfiles - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "qfiles - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "qfiles - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
!ERROR An invalid configuration is specified.
!ENDIF
!IF "$(OS)" == "Windows_NT"
NULL=
!ELSE
NULL=nul
!ENDIF
################################################################################
# Begin Project
RSC=rc.exe
CPP=cl.exe
!IF "$(CFG)" == "qfiles - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
OUTDIR=.\Release
INTDIR=.\Release
ALL : "$(OUTDIR)\qfiles.exe"
CLEAN :
-@erase ".\Release\qfiles.exe"
-@erase ".\Release\qfiles.obj"
-@erase ".\Release\cmdlib.obj"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
# ADD CPP /nologo /W1 /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
CPP_PROJ=/nologo /ML /W1 /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\
"_CONSOLE" /Fp"$(INTDIR)/qfiles.pch" /YX /Fo"$(INTDIR)/" /c
CPP_OBJS=.\Release/
CPP_SBRS=
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o"$(OUTDIR)/qfiles.bsc"
BSC32_SBRS=
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:console /incremental:no\
/pdb:"$(OUTDIR)/qfiles.pdb" /machine:I386 /out:"$(OUTDIR)/qfiles.exe"
LINK32_OBJS= \
"$(INTDIR)/qfiles.obj" \
"$(INTDIR)/cmdlib.obj"
"$(OUTDIR)\qfiles.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ELSEIF "$(CFG)" == "qfiles - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
OUTDIR=.\Debug
INTDIR=.\Debug
ALL : "$(OUTDIR)\qfiles.exe"
CLEAN :
-@erase ".\Debug\qfiles.exe"
-@erase ".\Debug\qfiles.obj"
-@erase ".\Debug\cmdlib.obj"
-@erase ".\Debug\qfiles.ilk"
-@erase ".\Debug\qfiles.pdb"
-@erase ".\Debug\vc40.pdb"
-@erase ".\Debug\vc40.idb"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
# ADD CPP /nologo /W1 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
CPP_PROJ=/nologo /MLd /W1 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG"\
/D "_CONSOLE" /Fp"$(INTDIR)/qfiles.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
CPP_OBJS=.\Debug/
CPP_SBRS=
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o"$(OUTDIR)/qfiles.bsc"
BSC32_SBRS=
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:console /incremental:yes\
/pdb:"$(OUTDIR)/qfiles.pdb" /debug /machine:I386 /out:"$(OUTDIR)/qfiles.exe"
LINK32_OBJS= \
"$(INTDIR)/qfiles.obj" \
"$(INTDIR)/cmdlib.obj"
"$(OUTDIR)\qfiles.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ENDIF
.c{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.c{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
################################################################################
# Begin Target
# Name "qfiles - Win32 Release"
# Name "qfiles - Win32 Debug"
!IF "$(CFG)" == "qfiles - Win32 Release"
!ELSEIF "$(CFG)" == "qfiles - Win32 Debug"
!ENDIF
################################################################################
# Begin Source File
SOURCE=.\qfiles.c
DEP_CPP_QFILE=\
".\..\common\cmdlib.h"\
"$(INTDIR)\qfiles.obj" : $(SOURCE) $(DEP_CPP_QFILE) "$(INTDIR)"
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\cmdlib.c
DEP_CPP_CMDLI=\
".\..\common\cmdlib.h"\
{$(INCLUDE)}"\sys\types.h"\
{$(INCLUDE)}"\sys\stat.h"\
"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\cmdlib.h
!IF "$(CFG)" == "qfiles - Win32 Release"
!ELSEIF "$(CFG)" == "qfiles - Win32 Debug"
!ENDIF
# End Source File
# End Target
# End Project
################################################################################

BIN
qutils/QFILES/QFILES.MDP Normal file

Binary file not shown.

BIN
qutils/QFILES/QFILES.NCB Normal file

Binary file not shown.

301
qutils/QLUMPY/QLUMPY.C Normal file
View File

@@ -0,0 +1,301 @@
#define VERSION "2.0"
#include "qlumpy.h"
#define MAXLUMP 0x50000 // biggest possible lump
byte *byteimage, *lbmpalette;
int byteimagewidth, byteimageheight;
char basepath[1024];
char lumpname[16];
char destfile[1024];
byte *lumpbuffer, *lump_p;
qboolean savesingle;
qboolean outputcreated;
/*
=============================================================================
MAIN
=============================================================================
*/
void GrabRaw (void);
void GrabPalette (void);
void GrabPic (void);
void GrabMip (void);
void GrabColormap (void);
void GrabColormap2 (void);
typedef struct
{
char *name;
void (*function) (void);
} command_t;
command_t commands[] =
{
{"palette",GrabPalette},
{"colormap",GrabColormap},
{"qpic",GrabPic},
{"miptex",GrabMip},
{"raw",GrabRaw},
{"colormap2",GrabColormap2},
{NULL,NULL} // list terminator
};
/*
==============
LoadScreen
==============
*/
void LoadScreen (char *name)
{
char *expanded;
expanded = ExpandPathAndArchive (name);
printf ("grabbing from %s...\n",expanded);
LoadLBM (expanded, &byteimage, &lbmpalette);
byteimagewidth = bmhd.w;
byteimageheight = bmhd.h;
}
/*
================
CreateOutput
================
*/
void CreateOutput (void)
{
outputcreated = true;
//
// create the output wadfile file
//
NewWad (destfile, false); // create a new wadfile
}
/*
===============
WriteLump
===============
*/
void WriteLump (int type, int compression)
{
int size;
if (!outputcreated)
CreateOutput ();
//
// dword align the size
//
while ((int)lump_p&3)
*lump_p++ = 0;
size = lump_p - lumpbuffer;
if (size > MAXLUMP)
Error ("Lump size exceeded %d, memory corrupted!",MAXLUMP);
//
// write the grabbed lump to the wadfile
//
AddLump (lumpname,lumpbuffer,size,type, compression);
}
/*
===========
WriteFile
Save as a seperate file instead of as a wadfile lump
===========
*/
void WriteFile (void)
{
char filename[1024];
char *exp;
sprintf (filename,"%s/%s.lmp", destfile, lumpname);
exp = ExpandPath(filename);
printf ("saved %s\n", exp);
SaveFile (exp, lumpbuffer, lump_p-lumpbuffer);
}
/*
================
ParseScript
================
*/
void ParseScript (void)
{
int cmd;
int size;
do
{
//
// get a command / lump name
//
GetToken (true);
if (endofscript)
break;
if (!Q_strcasecmp (token,"$LOAD"))
{
GetToken (false);
LoadScreen (token);
continue;
}
if (!Q_strcasecmp (token,"$DEST"))
{
GetToken (false);
strcpy (destfile, ExpandPath(token));
continue;
}
if (!Q_strcasecmp (token,"$SINGLEDEST"))
{
GetToken (false);
strcpy (destfile, token);
savesingle = true;
continue;
}
//
// new lump
//
if (strlen(token) >= sizeof(lumpname) )
Error ("\"%s\" is too long to be a lump name",token);
memset (lumpname,0,sizeof(lumpname));
strcpy (lumpname, token);
for (size=0 ; size<sizeof(lumpname) ; size++)
lumpname[size] = tolower(lumpname[size]);
//
// get the grab command
//
lump_p = lumpbuffer;
GetToken (false);
//
// call a routine to grab some data and put it in lumpbuffer
// with lump_p pointing after the last byte to be saved
//
for (cmd=0 ; commands[cmd].name ; cmd++)
if ( !Q_strcasecmp(token,commands[cmd].name) )
{
commands[cmd].function ();
break;
}
if ( !commands[cmd].name )
Error ("Unrecognized token '%s' at line %i",token,scriptline);
grabbed++;
if (savesingle)
WriteFile ();
else
WriteLump (TYP_LUMPY+cmd, 0);
} while (script_p < scriptend_p);
}
/*
=================
ProcessLumpyScript
Loads a script file, then grabs everything from it
=================
*/
void ProcessLumpyScript (char *basename)
{
char script[256];
printf ("qlumpy script: %s\n",basename);
//
// create default destination directory
//
strcpy (destfile, ExpandPath(basename));
StripExtension (destfile);
strcat (destfile,".wad"); // unless the script overrides, save in cwd
//
// save in a wadfile by default
//
savesingle = false;
grabbed = 0;
outputcreated = false;
//
// read in the script file
//
strcpy (script, basename);
DefaultExtension (script, ".ls");
LoadScriptFile (script);
strcpy (basepath, basename);
ParseScript (); // execute load / grab commands
if (!savesingle)
{
WriteWad (); // write out the wad directory
printf ("%i lumps grabbed in a wad file\n",grabbed);
}
else
printf ("%i lumps written seperately\n",grabbed);
}
/*
==============================
main
==============================
*/
int main (int argc, char **argv)
{
int i;
printf ("\nqlumpy "VERSION" by John Carmack, copyright (c) 1994 Id Software\n");
if (argc == 1)
Error ("qlumpy [-archive directory] scriptfile [scriptfile ...]");
lumpbuffer = malloc (MAXLUMP);
if (!strcmp(argv[1], "-archive"))
{
archive = true;
strcpy (archivedir, argv[2]);
printf ("Archiving source to: %s\n", archivedir);
i = 3;
}
else
i = 1;
for ( ; i<argc ; i++)
{
SetQdirFromPath (argv[i]);
ProcessLumpyScript (argv[i]);
}
return 0;
}

16
qutils/QLUMPY/QLUMPY.H Normal file
View File

@@ -0,0 +1,16 @@
#include "cmdlib.h"
#include "scriplib.h"
#include "lbmlib.h"
#include "wadlib.h"
extern byte *byteimage, *lbmpalette;
extern int byteimagewidth, byteimageheight;
#define SCRN(x,y) (*(byteimage+(y)*byteimagewidth+x))
extern byte *lump_p;
extern byte *lumpbuffer;
extern char lumpname[];

324
qutils/QLUMPY/QLUMPY.MAK Normal file
View File

@@ -0,0 +1,324 @@
# Microsoft Developer Studio Generated NMAKE File, Format Version 4.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
!IF "$(CFG)" == ""
CFG=qlumpy - Win32 Debug
!MESSAGE No configuration specified. Defaulting to qlumpy - Win32 Debug.
!ENDIF
!IF "$(CFG)" != "qlumpy - Win32 Release" && "$(CFG)" != "qlumpy - Win32 Debug"
!MESSAGE Invalid configuration "$(CFG)" specified.
!MESSAGE You can specify a configuration when running NMAKE on this makefile
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "qlumpy.mak" CFG="qlumpy - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "qlumpy - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "qlumpy - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
!ERROR An invalid configuration is specified.
!ENDIF
!IF "$(OS)" == "Windows_NT"
NULL=
!ELSE
NULL=nul
!ENDIF
################################################################################
# Begin Project
# PROP Target_Last_Scanned "qlumpy - Win32 Debug"
RSC=rc.exe
CPP=cl.exe
!IF "$(CFG)" == "qlumpy - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
OUTDIR=.\Release
INTDIR=.\Release
ALL : "$(OUTDIR)\qlumpy.exe"
CLEAN :
-@erase ".\Release\qlumpy.exe"
-@erase ".\Release\quakegrb.obj"
-@erase ".\Release\qlumpy.obj"
-@erase ".\Release\wadlib.obj"
-@erase ".\Release\scriplib.obj"
-@erase ".\Release\cmdlib.obj"
-@erase ".\Release\lbmlib.obj"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
# ADD CPP /nologo /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
CPP_PROJ=/nologo /ML /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\
"_CONSOLE" /Fp"$(INTDIR)/qlumpy.pch" /YX /Fo"$(INTDIR)/" /c
CPP_OBJS=.\Release/
CPP_SBRS=
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o"$(OUTDIR)/qlumpy.bsc"
BSC32_SBRS=
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:console /incremental:no\
/pdb:"$(OUTDIR)/qlumpy.pdb" /machine:I386 /out:"$(OUTDIR)/qlumpy.exe"
LINK32_OBJS= \
".\Release\quakegrb.obj" \
".\Release\qlumpy.obj" \
".\Release\wadlib.obj" \
".\Release\scriplib.obj" \
".\Release\cmdlib.obj" \
".\Release\lbmlib.obj"
"$(OUTDIR)\qlumpy.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ELSEIF "$(CFG)" == "qlumpy - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
OUTDIR=.\Debug
INTDIR=.\Debug
ALL : "$(OUTDIR)\qlumpy.exe"
CLEAN :
-@erase ".\Debug\vc40.pdb"
-@erase ".\Debug\vc40.idb"
-@erase ".\Debug\qlumpy.exe"
-@erase ".\Debug\lbmlib.obj"
-@erase ".\Debug\scriplib.obj"
-@erase ".\Debug\cmdlib.obj"
-@erase ".\Debug\qlumpy.obj"
-@erase ".\Debug\quakegrb.obj"
-@erase ".\Debug\wadlib.obj"
-@erase ".\Debug\qlumpy.ilk"
-@erase ".\Debug\qlumpy.pdb"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
# ADD CPP /nologo /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
CPP_PROJ=/nologo /MLd /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D\
"_CONSOLE" /Fp"$(INTDIR)/qlumpy.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
CPP_OBJS=.\Debug/
CPP_SBRS=
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o"$(OUTDIR)/qlumpy.bsc"
BSC32_SBRS=
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:console /incremental:yes\
/pdb:"$(OUTDIR)/qlumpy.pdb" /debug /machine:I386 /out:"$(OUTDIR)/qlumpy.exe"
LINK32_OBJS= \
".\Debug\lbmlib.obj" \
".\Debug\scriplib.obj" \
".\Debug\cmdlib.obj" \
".\Debug\qlumpy.obj" \
".\Debug\quakegrb.obj" \
".\Debug\wadlib.obj"
"$(OUTDIR)\qlumpy.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ENDIF
.c{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.c{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
################################################################################
# Begin Target
# Name "qlumpy - Win32 Release"
# Name "qlumpy - Win32 Debug"
!IF "$(CFG)" == "qlumpy - Win32 Release"
!ELSEIF "$(CFG)" == "qlumpy - Win32 Debug"
!ENDIF
################################################################################
# Begin Source File
SOURCE=.\quakegrb.c
!IF "$(CFG)" == "qlumpy - Win32 Release"
DEP_CPP_QUAKE=\
".\qlumpy.h"\
".\..\common\cmdlib.h"\
".\..\common\scriplib.h"\
".\..\common\lbmlib.h"\
".\..\common\wadlib.h"\
"$(INTDIR)\quakegrb.obj" : $(SOURCE) $(DEP_CPP_QUAKE) "$(INTDIR)"
!ELSEIF "$(CFG)" == "qlumpy - Win32 Debug"
DEP_CPP_QUAKE=\
".\qlumpy.h"\
".\..\common\cmdlib.h"\
".\..\common\scriplib.h"\
".\..\common\lbmlib.h"\
"$(INTDIR)\quakegrb.obj" : $(SOURCE) $(DEP_CPP_QUAKE) "$(INTDIR)"
!ENDIF
# End Source File
################################################################################
# Begin Source File
SOURCE=.\qlumpy.c
!IF "$(CFG)" == "qlumpy - Win32 Release"
DEP_CPP_QLUMP=\
".\qlumpy.h"\
".\..\common\cmdlib.h"\
".\..\common\scriplib.h"\
".\..\common\lbmlib.h"\
".\..\common\wadlib.h"\
"$(INTDIR)\qlumpy.obj" : $(SOURCE) $(DEP_CPP_QLUMP) "$(INTDIR)"
!ELSEIF "$(CFG)" == "qlumpy - Win32 Debug"
DEP_CPP_QLUMP=\
".\qlumpy.h"\
".\..\common\cmdlib.h"\
".\..\common\scriplib.h"\
".\..\common\lbmlib.h"\
"$(INTDIR)\qlumpy.obj" : $(SOURCE) $(DEP_CPP_QLUMP) "$(INTDIR)"
!ENDIF
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\cmdlib.c
DEP_CPP_CMDLI=\
".\..\common\cmdlib.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
{$(INCLUDE)}"\sys\STAT.H"\
"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\scriplib.c
DEP_CPP_SCRIP=\
".\..\common\cmdlib.h"\
".\..\common\scriplib.h"\
"$(INTDIR)\scriplib.obj" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\wadlib.c
DEP_CPP_WADLI=\
{$(INCLUDE)}"\sys\TYPES.H"\
{$(INCLUDE)}"\sys\STAT.H"\
".\..\common\cmdlib.h"\
".\..\common\wadlib.h"\
"$(INTDIR)\wadlib.obj" : $(SOURCE) $(DEP_CPP_WADLI) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\lbmlib.c
DEP_CPP_LBMLI=\
".\..\common\cmdlib.h"\
".\..\common\lbmlib.h"\
"$(INTDIR)\lbmlib.obj" : $(SOURCE) $(DEP_CPP_LBMLI) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
# End Target
# End Project
################################################################################

BIN
qutils/QLUMPY/QLUMPY.MDP Normal file

Binary file not shown.

BIN
qutils/QLUMPY/QLUMPY.NCB Normal file

Binary file not shown.

523
qutils/QLUMPY/QUAKEGRB.C Normal file
View File

@@ -0,0 +1,523 @@
#include "qlumpy.h"
typedef struct
{
short ofs, length;
} row_t;
typedef struct
{
int width, height;
int widthbits, heightbits;
unsigned char data[4];
} qtex_t;
typedef struct
{
int width, height;
byte data[4]; // variably sized
} qpic_t;
#define SCRN(x,y) (*(byteimage+(y)*byteimagewidth+x))
/*
==============
GrabRaw
filename RAW x y width height
==============
*/
void GrabRaw (void)
{
int x,y,xl,yl,xh,yh,w,h;
byte *screen_p;
int linedelta;
GetToken (false);
xl = atoi (token);
GetToken (false);
yl = atoi (token);
GetToken (false);
w = atoi (token);
GetToken (false);
h = atoi (token);
xh = xl+w;
yh = yl+h;
screen_p = byteimage + yl*byteimagewidth + xl;
linedelta = byteimagewidth - w;
for (y=yl ; y<yh ; y++)
{
for (x=xl ; x<xh ; x++)
{
*lump_p++ = *screen_p;
*screen_p++ = 0;
}
screen_p += linedelta;
}
}
/*
==============
GrabPalette
filename PALETTE [startcolor endcolor]
==============
*/
void GrabPalette (void)
{
int start,end,length;
if (TokenAvailable())
{
GetToken (false);
start = atoi (token);
GetToken (false);
end = atoi (token);
}
else
{
start = 0;
end = 255;
}
length = 3*(end-start+1);
memcpy (lump_p, lbmpalette+start*3, length);
lump_p += length;
}
/*
==============
GrabPic
filename qpic x y width height
==============
*/
void GrabPic (void)
{
int x,y,xl,yl,xh,yh;
int width;
byte transcolor;
qpic_t *header;
GetToken (false);
xl = atoi (token);
GetToken (false);
yl = atoi (token);
GetToken (false);
xh = xl-1+atoi (token);
GetToken (false);
yh = yl-1+atoi (token);
if (xh<xl || yh<yl || xl < 0 || yl<0 || xh>319 || yh>199)
Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,xh,yh);
transcolor = 255;
//
// fill in header
//
header = (qpic_t *)lump_p;
width = xh-xl+1;
header->width = LittleLong(width);
header->height = LittleLong(yh-yl+1);
//
// start grabbing posts
//
lump_p = (byte *)header->data;
for (y=yl ; y<= yh ; y++)
for (x=xl ; x<=xh ; x++)
*lump_p++ = SCRN(x,y);
}
/*
=============================================================================
COLORMAP GRABBING
=============================================================================
*/
/*
===============
BestColor
===============
*/
byte BestColor (int r, int g, int b, int start, int stop)
{
int i;
int dr, dg, db;
int bestdistortion, distortion;
int bestcolor;
byte *pal;
//
// let any color go to 0 as a last resort
//
bestdistortion = ( (int)r*r + (int)g*g + (int)b*b )*2;
bestcolor = 0;
pal = lbmpalette + start*3;
for (i=start ; i<= stop ; i++)
{
dr = r - (int)pal[0];
dg = g - (int)pal[1];
db = b - (int)pal[2];
pal += 3;
distortion = dr*dr + dg*dg + db*db;
if (distortion < bestdistortion)
{
if (!distortion)
return i; // perfect match
bestdistortion = distortion;
bestcolor = i;
}
}
return bestcolor;
}
/*
==============
GrabColormap
filename COLORMAP levels fullbrights
the first map is an identiy 0-255
the final map is all black except for the fullbrights
the remaining maps are evenly spread
fullbright colors start at the top of the palette.
==============
*/
void GrabColormap (void)
{
int levels, brights;
int l, c;
float frac, red, green, blue;
GetToken (false);
levels = atoi (token);
GetToken (false);
brights = atoi (token);
// identity lump
for (l=0 ; l<256 ; l++)
*lump_p++ = l;
// shaded levels
for (l=1;l<levels;l++)
{
frac = 1.0 - (float)l/(levels-1);
for (c=0 ; c<256-brights ; c++)
{
red = lbmpalette[c*3];
green = lbmpalette[c*3+1];
blue = lbmpalette[c*3+2];
red = (int)(red*frac+0.5);
green = (int)(green*frac+0.5);
blue = (int)(blue*frac+0.5);
//
// note: 254 instead of 255 because 255 is the transparent color, and we
// don't want anything remapping to that
//
*lump_p++ = BestColor(red,green,blue, 0, 254);
}
for ( ; c<256 ; c++)
*lump_p++ = c;
}
*lump_p++ = brights;
}
/*
==============
GrabColormap2
experimental -- not used by quake
filename COLORMAP2 range levels fullbrights
fullbright colors start at the top of the palette.
Range can be greater than 1 to allow overbright color tables.
the first map is all 0
the last (levels-1) map is at range
==============
*/
void GrabColormap2 (void)
{
int levels, brights;
int l, c;
float frac, red, green, blue;
float range;
GetToken (false);
range = atof (token);
GetToken (false);
levels = atoi (token);
GetToken (false);
brights = atoi (token);
// shaded levels
for (l=0;l<levels;l++)
{
frac = range - range*(float)l/(levels-1);
for (c=0 ; c<256-brights ; c++)
{
red = lbmpalette[c*3];
green = lbmpalette[c*3+1];
blue = lbmpalette[c*3+2];
red = (int)(red*frac+0.5);
green = (int)(green*frac+0.5);
blue = (int)(blue*frac+0.5);
//
// note: 254 instead of 255 because 255 is the transparent color, and we
// don't want anything remapping to that
//
*lump_p++ = BestColor(red,green,blue, 0, 254);
}
// fullbrights allways stay the same
for ( ; c<256 ; c++)
*lump_p++ = c;
}
*lump_p++ = brights;
}
/*
=============================================================================
MIPTEX GRABBING
=============================================================================
*/
typedef struct
{
char name[16];
unsigned width, height;
unsigned offsets[4]; // four mip maps stored
} miptex_t;
byte pixdata[256];
int d_red, d_green, d_blue;
/*
=============
AveragePixels
=============
*/
byte AveragePixels (int count)
{
int r,g,b;
int i;
int vis;
int pix;
int dr, dg, db;
int bestdistortion, distortion;
int bestcolor;
byte *pal;
int fullbright;
int e;
vis = 0;
r = g = b = 0;
fullbright = 0;
for (i=0 ; i<count ; i++)
{
pix = pixdata[i];
if (pix == 255)
fullbright = 2;
else if (pix >= 240)
{
return pix;
if (!fullbright)
{
fullbright = true;
r = 0;
g = 0;
b = 0;
}
}
else
{
if (fullbright)
continue;
}
r += lbmpalette[pix*3];
g += lbmpalette[pix*3+1];
b += lbmpalette[pix*3+2];
vis++;
}
if (fullbright == 2)
return 255;
r /= vis;
g /= vis;
b /= vis;
if (!fullbright)
{
r += d_red;
g += d_green;
b += d_blue;
}
//
// find the best color
//
bestdistortion = r*r + g*g + b*b;
bestcolor = 0;
if (fullbright)
{
i = 240;
e = 255;
}
else
{
i = 0;
e = 240;
}
for ( ; i< e ; i++)
{
pix = i; //pixdata[i];
pal = lbmpalette + pix*3;
dr = r - (int)pal[0];
dg = g - (int)pal[1];
db = b - (int)pal[2];
distortion = dr*dr + dg*dg + db*db;
if (distortion < bestdistortion)
{
if (!distortion)
{
d_red = d_green = d_blue = 0; // no distortion yet
return pix; // perfect match
}
bestdistortion = distortion;
bestcolor = pix;
}
}
if (!fullbright)
{ // error diffusion
pal = lbmpalette + bestcolor*3;
d_red = r - (int)pal[0];
d_green = g - (int)pal[1];
d_blue = b - (int)pal[2];
}
return bestcolor;
}
/*
==============
GrabMip
filename MIP x y width height
must be multiples of sixteen
==============
*/
void GrabMip (void)
{
int x,y,xl,yl,xh,yh,w,h;
byte *screen_p, *source;
int linedelta;
miptex_t *qtex;
int miplevel, mipstep;
int xx, yy, pix;
int count;
GetToken (false);
xl = atoi (token);
GetToken (false);
yl = atoi (token);
GetToken (false);
w = atoi (token);
GetToken (false);
h = atoi (token);
if ( (w & 15) || (h & 15) )
Error ("line %i: miptex sizes must be multiples of 16", scriptline);
xh = xl+w;
yh = yl+h;
qtex = (miptex_t *)lump_p;
qtex->width = LittleLong(w);
qtex->height = LittleLong(h);
strcpy (qtex->name, lumpname);
lump_p = (byte *)&qtex->offsets[4];
screen_p = byteimage + yl*byteimagewidth + xl;
linedelta = byteimagewidth - w;
source = lump_p;
qtex->offsets[0] = LittleLong(lump_p - (byte *)qtex);
for (y=yl ; y<yh ; y++)
{
for (x=xl ; x<xh ; x++)
{
pix = *screen_p;
*screen_p++ = 0;
if (pix == 255)
pix = 0;
*lump_p++ = pix;
}
screen_p += linedelta;
}
//
// subsample for greater mip levels
//
d_red = d_green = d_blue = 0; // no distortion yet
for (miplevel = 1 ; miplevel<4 ; miplevel++)
{
qtex->offsets[miplevel] = LittleLong(lump_p - (byte *)qtex);
mipstep = 1<<miplevel;
for (y=0 ; y<h ; y+=mipstep)
{
for (x = 0 ; x<w ; x+= mipstep)
{
count = 0;
for (yy=0 ; yy<mipstep ; yy++)
for (xx=0 ; xx<mipstep ; xx++)
{
pixdata[count] = source[ (y+yy)*w + x + xx ];
count++;
}
*lump_p++ = AveragePixels (count);
}
}
}
}

148
qutils/README.TXT Normal file
View File

@@ -0,0 +1,148 @@
This is the readme from our most recent licensed developer CD. Not all of it is applicable to this source upload, because the map editor, source data, and game source code have not been made freely available (gotta have some reason to charge lots of $$$ for it...), but it is the best documentation I have.
-- John Carmack
Quake Development CD 9/4/96
---------------------------
Included is all of the source data and utilities necessary to generate all of the data distributed with quake, and the main executable itself. You can modify the data in place, or copy the data you wish to modify to an addon directory and work from there.
The win-32 tools have not been extensively tested yet, because we still do most of our work on unix.
Completely building Quake code and data:
---------------------------------------
This process can take quite some time on a slow machine. I am omiting the steps to rebuild all the maps, otherwise it would take all day (literally).
Install VC++ and MASM. You don't need MASM if you are going to use DJGPP to compile the dos version instead of using the windows version.
Copy the contents of the quake development cd to /quake on any drive. The directory MUST be called "quake", because that string is searched for by the utilities to provide compatability between unix directories mounted inside a tree, and windows directories mounted on a drive letter. You can move it off of root, but it will require changes in a few batch files.
Add drive:\quake\bin_nt to your path.
cd \quake\utils
install // compiles all of the utilities and copies them to \quake\bin_nt
cd \quake\id1\gfx
foreach %i in (*.ls) do qlumpy %i // regrab all 2d graphics
// gfx.ls : graphics that are statically loaded: the small font, status bar stuff, etc
// cached.ls : graphics that are dynamically cached: menus, console background, etc
// the other .ls files are texture paletes for map editing
cd \quake\id1\progs
sprgen sprites.qc // regrab the sprites used in the 3d world (all three of them)
foreach %i in (*.qc) do modelgen %i // regrab all 3d models
// many of the .qc files do not actually specify a model, but
// running them through modelgen is harmless
qcc // rebuild progs.dat and files.dat
qfiles -bspmodels // reads files.dat and runs qbsp and light on all external
// brush models (health boxes, ammo boxes, etc)
qfiles -pak 0 // builds \quake\id1\pak0.pak
qfiles -pak 1 // builds \quake\id1\pak1.pak
// note that you should not leave the pak files in your development directory, because
// you won't be able to override any of the contents. If you are doing your work
// in an add-on directory, it isn't a problem, and the pak files will load faster
// than the discrete files.
cd \quake\code
mw // a batch file that compiles the windows version of quake
q +map newmap // a batch file that runs "quake -basedir \quake +map newmap"
the bsp tools
-------------
The bsp tools are usually run straight from the map editor, but they can also be called from the command line.
cd \quake\id1\maps
qbsp dm1 // processes dm1.map into dm1.bsp
light dm1 // generates lightmaps for dm1.bsp. If you run "light -extra dm1", it will make smoother shadow
// edges by oversampling.
vis dm1 // generates a potentially visible set (PVS) structure for dm1.bsp. This will only work if
// the map is leak-free. You can run "vis -fast dm1" to generate a rough PVS without
// spending very much time.
bspinfo newmap // dumps the stats on newmap
QuakeEd
-------
You are not expected to be able to figure out how to use QuakeEd from the (nonexistant) documentation we have. You get one full day with one of our map designers for tutoring.
If you want to try it out anyway:
cd \quake\id1 // the directory that contains the quake.qe3 project file
qe3 // see quakeed.txt for a box-room walkthrough
QuakeEd is still undergoing development. The version included in bin_nt is a newer version than the source included in utils. I don't have the current source here right now.
Expect new versions over the next few weeks.
The main source code:
--------------------
You can use the djgpp compiler (http://www.delorie.com) to rebuild quake for dos. We used a cross-compiler built for our Digital Unix alpha system that works very rapidly, but the dos hosted compiler is quite slow.
Our reccomended procedure is to forget about dos and just work with the windows version for code changes.
Currently at id we compile for three different platforms: NEXTSTEP, dos, and windows. The code also compiles for linux, but that is not part of our regular process. The C code is totally portable, but the assembly code was writen for GAS, which was unfreindly for windows development. Michael wrote a GAS to MASM translator to allow the assembly code to compile under windows. We still consider
the GAS code (.s) to be the master, and derive the masm (.asm) code from it inside the makefile. If you are never going to touch
the assembly code (we don't reccoment you do), or you are willing to take full responsibility for it, you can throw out the .s files
and just use the .asm.
The direct-sound driver is not very good right now. You may want to run with "-nosound".
The utilities source:
--------------------
Each utility has a seperate directory of code with a VC++ project file. They all share several code files in the "common" directory. The NT versions of these utilities have not been very extensively tested, as we still use DEC Unix for most of our work (soon to change). The two source files you are most likely to change are: common/lbmlib.c to load a more common graphics format, like pcx, and common/trilib.c to load a 3D format other than Alias object seperated triangles.
qe3 : The map editor. Designed for use on open GL accelerated systems such as intergraph or glint-TX based systems, but it will still run on the basic NT software version. REQUIRES A 3-BUTTON MOUSE!
qbsp / light / vis : these utilities are called directly from the map editor to process .map files into .bsp files. They can be executed by hand if desired.
bspinfo : a command line utility that will dump the count and size statistics on a .bsp file.
qlumpy : the 2-D graphics grabber. Grabs graphics off of .lbm pictures. Used for grabbing the 2d graphics used by quake (status bar stuff, fonts, etc), and also used for grabbing the textures to be viewed in qe3 and extracted by qbsp. Qlumpy script files have the default extension ".ls" (LumpyScript).
qcc : the Quake-C compiler. Reads "progs.src", then compiles all of the files listed there. Generates "progs.dat" for use by quake at runtime, "progdefs.h" for use at compile time, and "files.dat" to be used as input for qfiles.exe.
qfiles : Builds pak files based on the contents of "files.dat" writen out by qcc. It can also regenerate all of the .bsp models used in a project, which is required if any changes to the file format have been made.
sprgen : the sprite model grabber. Grabs 2d graphics and creates a .spr file.
modelgen : the 3-D model grabber. Combines skin graphics with 3d frames to produce a .mdl file. The commands are parsed out of .qc files that can also be read by qcc, so a single source can both generate and use the data.
texmake : creates 2d wireframe outlines of a 3d model that can be drawn on to give a texture to a model. This is only done once per model, or when the base frame changes.
Example:
cd \quake\id1\models\torch
texmake base // reads base.tri and creates the graphic base.lbm
copy base.lbm skin.lbm // never work on the base skin, it might get overwritten
cd \quake\id1\progs
modelgen torch.qc // creates torch.mdl out of files in \quake\id1\models\torch
Continuing development work at id:
------------------------------
winquake : work is still being done on the direct-X drivers for quake.
qe3 : the NT editor does not yet have full functionality for texture positioning and entity connecting.
qrad : a radiosity replacement for light.exe. Instead of placing light entities, certain textures automatically become light emiters. The light bounces off of surfaces, so a single light panel can light all sides of a room.
qcsg / qbsp / qwrite : qbsp.exe is being broken up into multiple programs to reduce memory usage and provide a better means for experimentation. It should get faster, as well.
visx : a faster replacement for vis.

526
qutils/SPRGEN/SPRGEN.C Normal file
View File

@@ -0,0 +1,526 @@
//
// spritegen.c: generates a .spr file from a series of .lbm frame files.
// Result is stored in /raid/quake/id1/sprites/<scriptname>.spr.
//
#define INCLUDELIBS
#ifdef NeXT
#include <libc.h>
#endif
#include "spritegn.h"
#define MAX_BUFFER_SIZE 0x100000
#define MAX_FRAMES 1000
dsprite_t sprite;
byte *byteimage, *lbmpalette;
int byteimagewidth, byteimageheight;
byte *lumpbuffer, *plump;
char spritedir[1024];
char spriteoutname[1024];
int framesmaxs[2];
int framecount;
typedef struct {
spriteframetype_t type; // single frame or group of frames
void *pdata; // either a dspriteframe_t or group info
float interval; // only used for frames in groups
int numgroupframes; // only used by group headers
} spritepackage_t;
spritepackage_t frames[MAX_FRAMES];
void FinishSprite (void);
void Cmd_Spritename (void);
/*
============
WriteFrame
============
*/
void WriteFrame (FILE *spriteouthandle, int framenum)
{
dspriteframe_t *pframe;
dspriteframe_t frametemp;
pframe = (dspriteframe_t *)frames[framenum].pdata;
frametemp.origin[0] = LittleLong (pframe->origin[0]);
frametemp.origin[1] = LittleLong (pframe->origin[1]);
frametemp.width = LittleLong (pframe->width);
frametemp.height = LittleLong (pframe->height);
SafeWrite (spriteouthandle, &frametemp, sizeof (frametemp));
SafeWrite (spriteouthandle,
(byte *)(pframe + 1),
pframe->height * pframe->width);
}
/*
============
WriteSprite
============
*/
void WriteSprite (FILE *spriteouthandle)
{
int i, groupframe, curframe;
dsprite_t spritetemp;
sprite.boundingradius = sqrt (((framesmaxs[0] >> 1) *
(framesmaxs[0] >> 1)) +
((framesmaxs[1] >> 1) *
(framesmaxs[1] >> 1)));
//
// write out the sprite header
//
spritetemp.type = LittleLong (sprite.type);
spritetemp.boundingradius = LittleFloat (sprite.boundingradius);
spritetemp.width = LittleLong (framesmaxs[0]);
spritetemp.height = LittleLong (framesmaxs[1]);
spritetemp.numframes = LittleLong (sprite.numframes);
spritetemp.beamlength = LittleFloat (sprite.beamlength);
spritetemp.synctype = LittleFloat (sprite.synctype);
spritetemp.version = LittleLong (SPRITE_VERSION);
spritetemp.ident = LittleLong (IDSPRITEHEADER);
SafeWrite (spriteouthandle, &spritetemp, sizeof(spritetemp));
//
// write out the frames
//
curframe = 0;
for (i=0 ; i<sprite.numframes ; i++)
{
SafeWrite (spriteouthandle, &frames[curframe].type,
sizeof(frames[curframe].type));
if (frames[curframe].type == SPR_SINGLE)
{
//
// single (non-grouped) frame
//
WriteFrame (spriteouthandle, curframe);
curframe++;
}
else
{
int j, numframes;
dspritegroup_t dsgroup;
float totinterval;
groupframe = curframe;
curframe++;
numframes = frames[groupframe].numgroupframes;
//
// set and write the group header
//
dsgroup.numframes = LittleLong (numframes);
SafeWrite (spriteouthandle, &dsgroup, sizeof(dsgroup));
//
// write the interval array
//
totinterval = 0.0;
for (j=0 ; j<numframes ; j++)
{
dspriteinterval_t temp;
totinterval += frames[groupframe+1+j].interval;
temp.interval = LittleFloat (totinterval);
SafeWrite (spriteouthandle, &temp, sizeof(temp));
}
for (j=0 ; j<numframes ; j++)
{
WriteFrame (spriteouthandle, curframe);
curframe++;
}
}
}
}
/*
============
ExecCommand
============
*/
int cmdsrun;
void ExecCommand (char *cmd, ...)
{
int ret;
char cmdline[1024];
va_list argptr;
cmdsrun++;
va_start (argptr, cmd);
vsprintf (cmdline,cmd,argptr);
va_end (argptr);
// printf ("=============================================================\n");
// printf ("spritegen: %s\n",cmdline);
fflush (stdout);
ret = system (cmdline);
// printf ("=============================================================\n");
if (ret)
Error ("spritegen: exiting due to error");
}
/*
==============
LoadScreen
==============
*/
void LoadScreen (char *name)
{
printf ("grabbing from %s...\n",name);
LoadLBM (name, &byteimage, &lbmpalette);
byteimagewidth = bmhd.w;
byteimageheight = bmhd.h;
}
/*
===============
Cmd_Type
===============
*/
void Cmd_Type (void)
{
GetToken (false);
if (!strcmp (token, "vp_parallel_upright"))
sprite.type = SPR_VP_PARALLEL_UPRIGHT;
else if (!strcmp (token, "facing_upright"))
sprite.type = SPR_FACING_UPRIGHT;
else if (!strcmp (token, "vp_parallel"))
sprite.type = SPR_VP_PARALLEL;
else if (!strcmp (token, "oriented"))
sprite.type = SPR_ORIENTED;
else if (!strcmp (token, "vp_parallel_oriented"))
sprite.type = SPR_VP_PARALLEL_ORIENTED;
else
Error ("Bad sprite type\n");
}
/*
===============
Cmd_Beamlength
===============
*/
void Cmd_Beamlength ()
{
GetToken (false);
sprite.beamlength = atof (token);
}
/*
===============
Cmd_Load
===============
*/
void Cmd_Load (void)
{
GetToken (false);
LoadScreen (ExpandPathAndArchive(token));
}
/*
===============
Cmd_Frame
===============
*/
void Cmd_Frame ()
{
int x,y,xl,yl,xh,yh,w,h;
byte *screen_p, *source;
int linedelta;
dspriteframe_t *pframe;
int pix;
GetToken (false);
xl = atoi (token);
GetToken (false);
yl = atoi (token);
GetToken (false);
w = atoi (token);
GetToken (false);
h = atoi (token);
if ((xl & 0x07) || (yl & 0x07) || (w & 0x07) || (h & 0x07))
Error ("Sprite dimensions not multiples of 8\n");
if ((w > 255) || (h > 255))
Error ("Sprite has a dimension longer than 255");
xh = xl+w;
yh = yl+h;
pframe = (dspriteframe_t *)plump;
frames[framecount].pdata = pframe;
frames[framecount].type = SPR_SINGLE;
if (TokenAvailable ())
{
GetToken (false);
frames[framecount].interval = atof (token);
if (frames[framecount].interval <= 0.0)
Error ("Non-positive interval");
}
else
{
frames[framecount].interval = 0.1;
}
if (TokenAvailable ())
{
GetToken (false);
pframe->origin[0] = -atoi (token);
GetToken (false);
pframe->origin[1] = atoi (token);
}
else
{
pframe->origin[0] = -(w >> 1);
pframe->origin[1] = h >> 1;
}
pframe->width = w;
pframe->height = h;
if (w > framesmaxs[0])
framesmaxs[0] = w;
if (h > framesmaxs[1])
framesmaxs[1] = h;
plump = (byte *)(pframe + 1);
screen_p = byteimage + yl*byteimagewidth + xl;
linedelta = byteimagewidth - w;
source = plump;
for (y=yl ; y<yh ; y++)
{
for (x=xl ; x<xh ; x++)
{
pix = *screen_p;
*screen_p++ = 0;
// if (pix == 255)
// pix = 0;
*plump++ = pix;
}
screen_p += linedelta;
}
framecount++;
if (framecount >= MAX_FRAMES)
Error ("Too many frames; increase MAX_FRAMES\n");
}
/*
===============
Cmd_GroupStart
===============
*/
void Cmd_GroupStart (void)
{
int groupframe;
groupframe = framecount++;
frames[groupframe].type = SPR_GROUP;
frames[groupframe].numgroupframes = 0;
while (1)
{
GetToken (true);
if (endofscript)
Error ("End of file during group");
if (!strcmp (token, "$frame"))
{
Cmd_Frame ();
frames[groupframe].numgroupframes++;
}
else if (!strcmp (token, "$load"))
{
Cmd_Load ();
}
else if (!strcmp (token, "$groupend"))
{
break;
}
else
{
Error ("$frame, $load, or $groupend expected\n");
}
}
if (frames[groupframe].numgroupframes == 0)
Error ("Empty group\n");
}
/*
===============
ParseScript
===============
*/
void ParseScript (void)
{
while (1)
{
GetToken (true);
if (endofscript)
break;
if (!strcmp (token, "$load"))
{
Cmd_Load ();
}
if (!strcmp (token, "$spritename"))
{
Cmd_Spritename ();
}
else if (!strcmp (token, "$type"))
{
Cmd_Type ();
}
else if (!strcmp (token, "$beamlength"))
{
Cmd_Beamlength ();
}
else if (!strcmp (token, "$sync"))
{
sprite.synctype = ST_SYNC;
}
else if (!strcmp (token, "$frame"))
{
Cmd_Frame ();
sprite.numframes++;
}
else if (!strcmp (token, "$load"))
{
Cmd_Load ();
}
else if (!strcmp (token, "$groupstart"))
{
Cmd_GroupStart ();
sprite.numframes++;
}
}
}
/*
==============
Cmd_Spritename
==============
*/
void Cmd_Spritename (void)
{
if (sprite.numframes)
FinishSprite ();
GetToken (false);
sprintf (spriteoutname, "%s%s.spr", spritedir, token);
memset (&sprite, 0, sizeof(sprite));
framecount = 0;
framesmaxs[0] = -9999999;
framesmaxs[1] = -9999999;
lumpbuffer = malloc (MAX_BUFFER_SIZE * 2); // *2 for padding
if (!lumpbuffer)
Error ("Couldn't get buffer memory");
plump = lumpbuffer;
sprite.synctype = ST_RAND; // default
}
/*
==============
FinishSprite
==============
*/
void FinishSprite (void)
{
FILE *spriteouthandle;
if (sprite.numframes == 0)
Error ("no frames\n");
if (!strlen(spriteoutname))
Error ("Didn't name sprite file");
if ((plump - lumpbuffer) > MAX_BUFFER_SIZE)
Error ("Sprite package too big; increase MAX_BUFFER_SIZE");
spriteouthandle = SafeOpenWrite (spriteoutname);
printf ("saving in %s\n", spriteoutname);
WriteSprite (spriteouthandle);
fclose (spriteouthandle);
printf ("spritegen: successful\n");
printf ("%d frame(s)\n", sprite.numframes);
printf ("%d ungrouped frame(s), including group headers\n", framecount);
spriteoutname[0] = 0; // clear for a new sprite
}
/*
==============
main
==============
*/
int main (int argc, char **argv)
{
int i;
if (argc != 2 && argc != 4)
Error ("usage: spritegen [-archive directory] file.qc");
if (!strcmp(argv[1], "-archive"))
{
archive = true;
strcpy (archivedir, argv[2]);
printf ("Archiving source to: %s\n", archivedir);
i = 3;
}
else
i = 1;
SetQdirFromPath (argv[i]);
ExtractFilePath (argv[i], spritedir); // chop the filename
//
// load the script
//
LoadScriptFile (argv[i]);
ParseScript ();
FinishSprite ();
return 0;
}

300
qutils/SPRGEN/SPRGEN.MAK Normal file
View File

@@ -0,0 +1,300 @@
# Microsoft Developer Studio Generated NMAKE File, Format Version 4.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
!IF "$(CFG)" == ""
CFG=sprgen - Win32 Debug
!MESSAGE No configuration specified. Defaulting to sprgen - Win32 Debug.
!ENDIF
!IF "$(CFG)" != "sprgen - Win32 Release" && "$(CFG)" != "sprgen - Win32 Debug"
!MESSAGE Invalid configuration "$(CFG)" specified.
!MESSAGE You can specify a configuration when running NMAKE on this makefile
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "sprgen.mak" CFG="sprgen - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "sprgen - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "sprgen - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
!ERROR An invalid configuration is specified.
!ENDIF
!IF "$(OS)" == "Windows_NT"
NULL=
!ELSE
NULL=nul
!ENDIF
################################################################################
# Begin Project
# PROP Target_Last_Scanned "sprgen - Win32 Debug"
RSC=rc.exe
CPP=cl.exe
!IF "$(CFG)" == "sprgen - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
OUTDIR=.\Release
INTDIR=.\Release
ALL : "$(OUTDIR)\sprgen.exe"
CLEAN :
-@erase ".\Release\sprgen.exe"
-@erase ".\Release\scriplib.obj"
-@erase ".\Release\sprgen.obj"
-@erase ".\Release\cmdlib.obj"
-@erase ".\Release\lbmlib.obj"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
# ADD CPP /nologo /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
CPP_PROJ=/nologo /ML /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\
"_CONSOLE" /Fp"$(INTDIR)/sprgen.pch" /YX /Fo"$(INTDIR)/" /c
CPP_OBJS=.\Release/
CPP_SBRS=
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o"$(OUTDIR)/sprgen.bsc"
BSC32_SBRS=
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:console /incremental:no\
/pdb:"$(OUTDIR)/sprgen.pdb" /machine:I386 /out:"$(OUTDIR)/sprgen.exe"
LINK32_OBJS= \
".\Release\scriplib.obj" \
".\Release\sprgen.obj" \
".\Release\cmdlib.obj" \
".\Release\lbmlib.obj"
"$(OUTDIR)\sprgen.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ELSEIF "$(CFG)" == "sprgen - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
OUTDIR=.\Debug
INTDIR=.\Debug
ALL : "$(OUTDIR)\sprgen.exe"
CLEAN :
-@erase ".\Debug\vc40.pdb"
-@erase ".\Debug\vc40.idb"
-@erase ".\Debug\sprgen.exe"
-@erase ".\Debug\cmdlib.obj"
-@erase ".\Debug\scriplib.obj"
-@erase ".\Debug\lbmlib.obj"
-@erase ".\Debug\sprgen.obj"
-@erase ".\Debug\sprgen.ilk"
-@erase ".\Debug\sprgen.pdb"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
# ADD CPP /nologo /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
CPP_PROJ=/nologo /MLd /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D\
"_CONSOLE" /Fp"$(INTDIR)/sprgen.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
CPP_OBJS=.\Debug/
CPP_SBRS=
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o"$(OUTDIR)/sprgen.bsc"
BSC32_SBRS=
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:console /incremental:yes\
/pdb:"$(OUTDIR)/sprgen.pdb" /debug /machine:I386 /out:"$(OUTDIR)/sprgen.exe"
LINK32_OBJS= \
".\Debug\cmdlib.obj" \
".\Debug\scriplib.obj" \
".\Debug\lbmlib.obj" \
".\Debug\sprgen.obj"
"$(OUTDIR)\sprgen.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ENDIF
.c{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.c{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_SBRS)}.sbr:
$(CPP) $(CPP_PROJ) $<
################################################################################
# Begin Target
# Name "sprgen - Win32 Release"
# Name "sprgen - Win32 Debug"
!IF "$(CFG)" == "sprgen - Win32 Release"
!ELSEIF "$(CFG)" == "sprgen - Win32 Debug"
!ENDIF
################################################################################
# Begin Source File
SOURCE=.\sprgen.c
!IF "$(CFG)" == "sprgen - Win32 Release"
DEP_CPP_SPRGE=\
".\spritegn.h"\
".\..\common\cmdlib.h"\
".\..\common\scriplib.h"\
".\..\common\lbmlib.h"\
"$(INTDIR)\sprgen.obj" : $(SOURCE) $(DEP_CPP_SPRGE) "$(INTDIR)"
!ELSEIF "$(CFG)" == "sprgen - Win32 Debug"
DEP_CPP_SPRGE=\
".\spritegn.h"\
".\..\common\cmdlib.h"\
"$(INTDIR)\sprgen.obj" : $(SOURCE) $(DEP_CPP_SPRGE) "$(INTDIR)"
!ENDIF
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\cmdlib.c
DEP_CPP_CMDLI=\
".\..\common\cmdlib.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
{$(INCLUDE)}"\sys\STAT.H"\
"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\scriplib.c
DEP_CPP_SCRIP=\
".\..\common\cmdlib.h"\
".\..\common\scriplib.h"\
"$(INTDIR)\scriplib.obj" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\lbmlib.c
DEP_CPP_LBMLI=\
".\..\common\cmdlib.h"\
".\..\common\lbmlib.h"\
"$(INTDIR)\lbmlib.obj" : $(SOURCE) $(DEP_CPP_LBMLI) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\scriplib.h
!IF "$(CFG)" == "sprgen - Win32 Release"
!ELSEIF "$(CFG)" == "sprgen - Win32 Debug"
!ENDIF
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\lbmlib.h
!IF "$(CFG)" == "sprgen - Win32 Release"
!ELSEIF "$(CFG)" == "sprgen - Win32 Debug"
!ENDIF
# End Source File
################################################################################
# Begin Source File
SOURCE=\quake\utils2\common\cmdlib.h
!IF "$(CFG)" == "sprgen - Win32 Release"
!ELSEIF "$(CFG)" == "sprgen - Win32 Debug"
!ENDIF
# End Source File
# End Target
# End Project
################################################################################

BIN
qutils/SPRGEN/SPRGEN.MDP Normal file

Binary file not shown.

BIN
qutils/SPRGEN/SPRGEN.NCB Normal file

Binary file not shown.

88
qutils/SPRGEN/SPRITEGN.H Normal file
View File

@@ -0,0 +1,88 @@
//
// spritegn.h: header file for sprite generation program
//
// **********************************************************
// * This file must be identical in the spritegen directory *
// * and in the Quake directory, because it's used to *
// * pass data from one to the other via .spr files. *
// **********************************************************
//-------------------------------------------------------
// This program generates .spr sprite package files.
// The format of the files is as follows:
//
// dsprite_t file header structure
// <repeat dsprite_t.numframes times>
// <if spritegroup, repeat dspritegroup_t.numframes times>
// dspriteframe_t frame header structure
// sprite bitmap
// <else (single sprite frame)>
// dspriteframe_t frame header structure
// sprite bitmap
// <endrepeat>
//-------------------------------------------------------
#ifdef INCLUDELIBS
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "cmdlib.h"
#include "scriplib.h"
#include "lbmlib.h"
#endif
#define SPRITE_VERSION 1
// must match definition in modelgen.h
#ifndef SYNCTYPE_T
#define SYNCTYPE_T
typedef enum {ST_SYNC=0, ST_RAND } synctype_t;
#endif
// TODO: shorten these?
typedef struct {
int ident;
int version;
int type;
float boundingradius;
int width;
int height;
int numframes;
float beamlength;
synctype_t synctype;
} dsprite_t;
#define SPR_VP_PARALLEL_UPRIGHT 0
#define SPR_FACING_UPRIGHT 1
#define SPR_VP_PARALLEL 2
#define SPR_ORIENTED 3
#define SPR_VP_PARALLEL_ORIENTED 4
typedef struct {
int origin[2];
int width;
int height;
} dspriteframe_t;
typedef struct {
int numframes;
} dspritegroup_t;
typedef struct {
float interval;
} dspriteinterval_t;
typedef enum { SPR_SINGLE=0, SPR_GROUP } spriteframetype_t;
typedef struct {
spriteframetype_t type;
} dspriteframetype_t;
#define IDSPRITEHEADER (('P'<<24)+('S'<<16)+('D'<<8)+'I')
// little-endian "IDSP"

BIN
qutils/SPRGEN/S_BUBBLE.SPR Normal file

Binary file not shown.

BIN
qutils/SPRGEN/S_EXPLOD.SPR Normal file

Binary file not shown.

BIN
qutils/SPRGEN/S_LIGHT.SPR Normal file

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More