514 lines
15 KiB
C
514 lines
15 KiB
C
/* Copyright (C) 1996-1997 Id Software, Inc.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
See file, 'COPYING', for details.
|
|
*/
|
|
|
|
#include <common/cmdlib.h>
|
|
#include <common/mathlib.h>
|
|
#include <common/bspfile.h>
|
|
|
|
/* ========================================================================= */
|
|
|
|
int nummodels;
|
|
dmodel_t *dmodels;
|
|
|
|
int visdatasize;
|
|
byte *dvisdata;
|
|
|
|
int lightdatasize;
|
|
byte *dlightdata;
|
|
|
|
int texdatasize;
|
|
byte *dtexdata; /* (dmiptexlump_t) */
|
|
|
|
int entdatasize;
|
|
char *dentdata;
|
|
|
|
int numleafs;
|
|
dleaf_t *dleafs;
|
|
|
|
int numplanes;
|
|
dplane_t *dplanes;
|
|
|
|
int numvertexes;
|
|
dvertex_t *dvertexes;
|
|
|
|
int numnodes;
|
|
dnode_t *dnodes;
|
|
|
|
int numtexinfo;
|
|
texinfo_t *texinfo;
|
|
|
|
int numfaces;
|
|
dface_t *dfaces;
|
|
|
|
int numclipnodes;
|
|
dclipnode_t *dclipnodes;
|
|
|
|
int numedges;
|
|
dedge_t *dedges;
|
|
|
|
int nummarksurfaces;
|
|
unsigned short *dmarksurfaces;
|
|
|
|
int numsurfedges;
|
|
int *dsurfedges;
|
|
|
|
/* Transitional helper functions */
|
|
void
|
|
GetBSPGlobals(bspdata_t *bspdata)
|
|
{
|
|
bspdata->nummodels = nummodels;
|
|
bspdata->dmodels = dmodels;
|
|
|
|
bspdata->visdatasize = visdatasize;
|
|
bspdata->dvisdata = dvisdata;
|
|
|
|
bspdata->lightdatasize = lightdatasize;
|
|
bspdata->dlightdata = dlightdata;
|
|
|
|
bspdata->texdatasize = texdatasize;
|
|
bspdata->dtexdata = dtexdata;
|
|
|
|
bspdata->entdatasize = entdatasize;
|
|
bspdata->dentdata = dentdata;
|
|
|
|
bspdata->numleafs = numleafs;
|
|
bspdata->dleafs = dleafs;
|
|
|
|
bspdata->numplanes = numplanes;
|
|
bspdata->dplanes = dplanes;
|
|
|
|
bspdata->numvertexes = numvertexes;
|
|
bspdata->dvertexes = dvertexes;
|
|
|
|
bspdata->numnodes = numnodes;
|
|
bspdata->dnodes = dnodes;
|
|
|
|
bspdata->numtexinfo = numtexinfo;
|
|
bspdata->texinfo = texinfo;
|
|
|
|
bspdata->numfaces = numfaces;
|
|
bspdata->dfaces = dfaces;
|
|
|
|
bspdata->numclipnodes = numclipnodes;
|
|
bspdata->dclipnodes = dclipnodes;
|
|
|
|
bspdata->numedges = numedges;
|
|
bspdata->dedges = dedges;
|
|
|
|
bspdata->nummarksurfaces = nummarksurfaces;
|
|
bspdata->dmarksurfaces = dmarksurfaces;
|
|
|
|
bspdata->numsurfedges = numsurfedges;
|
|
bspdata->dsurfedges = dsurfedges;
|
|
}
|
|
|
|
void
|
|
SetBSPGlobals(const bspdata_t *bspdata)
|
|
{
|
|
nummodels = bspdata->nummodels;
|
|
dmodels = bspdata->dmodels;
|
|
|
|
visdatasize = bspdata->visdatasize;
|
|
dvisdata = bspdata->dvisdata;
|
|
|
|
lightdatasize = bspdata->lightdatasize;
|
|
dlightdata = bspdata->dlightdata;
|
|
|
|
texdatasize = bspdata->texdatasize;
|
|
dtexdata = bspdata->dtexdata;
|
|
|
|
entdatasize = bspdata->entdatasize;
|
|
dentdata = bspdata->dentdata;
|
|
|
|
numleafs = bspdata->numleafs;
|
|
dleafs = bspdata->dleafs;
|
|
|
|
numplanes = bspdata->numplanes;
|
|
dplanes = bspdata->dplanes;
|
|
|
|
numvertexes = bspdata->numvertexes;
|
|
dvertexes = bspdata->dvertexes;
|
|
|
|
numnodes = bspdata->numnodes;
|
|
dnodes = bspdata->dnodes;
|
|
|
|
numtexinfo = bspdata->numtexinfo;
|
|
texinfo = bspdata->texinfo;
|
|
|
|
numfaces = bspdata->numfaces;
|
|
dfaces = bspdata->dfaces;
|
|
|
|
numclipnodes = bspdata->numclipnodes;
|
|
dclipnodes = bspdata->dclipnodes;
|
|
|
|
numedges = bspdata->numedges;
|
|
dedges = bspdata->dedges;
|
|
|
|
nummarksurfaces = bspdata->nummarksurfaces;
|
|
dmarksurfaces = bspdata->dmarksurfaces;
|
|
|
|
numsurfedges = bspdata->numsurfedges;
|
|
dsurfedges = bspdata->dsurfedges;
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
|
|
typedef enum { TO_DISK, TO_CPU } swaptype_t;
|
|
|
|
/*
|
|
* =============
|
|
* SwapBSPFile
|
|
* Byte swaps all data in a bsp file.
|
|
* =============
|
|
*/
|
|
void
|
|
SwapBSPFile(bspdata_t *bspdata, swaptype_t swap)
|
|
{
|
|
int i, j;
|
|
|
|
/* vertexes */
|
|
for (i = 0; i < bspdata->numvertexes; i++) {
|
|
dvertex_t *vertex = &bspdata->dvertexes[i];
|
|
for (j = 0; j < 3; j++)
|
|
vertex->point[j] = LittleFloat(vertex->point[j]);
|
|
}
|
|
|
|
/* planes */
|
|
for (i = 0; i < bspdata->numplanes; i++) {
|
|
dplane_t *plane = &bspdata->dplanes[i];
|
|
for (j = 0; j < 3; j++)
|
|
plane->normal[j] = LittleFloat(plane->normal[j]);
|
|
plane->dist = LittleFloat(plane->dist);
|
|
plane->type = LittleLong(plane->type);
|
|
}
|
|
|
|
/* texinfos */
|
|
for (i = 0; i < bspdata->numtexinfo; i++) {
|
|
texinfo_t *texinfo = &bspdata->texinfo[i];
|
|
for (j = 0; j < 4; j++) {
|
|
texinfo->vecs[0][j] = LittleFloat(texinfo->vecs[0][j]);
|
|
texinfo->vecs[1][j] = LittleFloat(texinfo->vecs[1][j]);
|
|
}
|
|
texinfo->miptex = LittleLong(texinfo->miptex);
|
|
texinfo->flags = LittleLong(texinfo->flags);
|
|
}
|
|
|
|
/* faces */
|
|
for (i = 0; i < bspdata->numfaces; i++) {
|
|
dface_t *face = &bspdata->dfaces[i];
|
|
face->texinfo = LittleShort(face->texinfo);
|
|
face->planenum = LittleShort(face->planenum);
|
|
face->side = LittleShort(face->side);
|
|
face->lightofs = LittleLong(face->lightofs);
|
|
face->firstedge = LittleLong(face->firstedge);
|
|
face->numedges = LittleShort(face->numedges);
|
|
}
|
|
|
|
/* nodes */
|
|
for (i = 0; i < bspdata->numnodes; i++) {
|
|
dnode_t *node = &bspdata->dnodes[i];
|
|
node->planenum = LittleLong(node->planenum);
|
|
for (j = 0; j < 3; j++) {
|
|
node->mins[j] = LittleShort(node->mins[j]);
|
|
node->maxs[j] = LittleShort(node->maxs[j]);
|
|
}
|
|
node->children[0] = LittleShort(node->children[0]);
|
|
node->children[1] = LittleShort(node->children[1]);
|
|
node->firstface = LittleShort(node->firstface);
|
|
node->numfaces = LittleShort(node->numfaces);
|
|
}
|
|
|
|
/* leafs */
|
|
for (i = 0; i < bspdata->numleafs; i++) {
|
|
dleaf_t *leaf = &bspdata->dleafs[i];
|
|
leaf->contents = LittleLong(leaf->contents);
|
|
for (j = 0; j < 3; j++) {
|
|
leaf->mins[j] = LittleShort(leaf->mins[j]);
|
|
leaf->maxs[j] = LittleShort(leaf->maxs[j]);
|
|
}
|
|
leaf->firstmarksurface = LittleShort(leaf->firstmarksurface);
|
|
leaf->nummarksurfaces = LittleShort(leaf->nummarksurfaces);
|
|
leaf->visofs = LittleLong(leaf->visofs);
|
|
}
|
|
|
|
/* clipnodes */
|
|
for (i = 0; i < bspdata->numclipnodes; i++) {
|
|
dclipnode_t *clipnode = &bspdata->dclipnodes[i];
|
|
clipnode->planenum = LittleLong(clipnode->planenum);
|
|
clipnode->children[0] = LittleShort(clipnode->children[0]);
|
|
clipnode->children[1] = LittleShort(clipnode->children[1]);
|
|
}
|
|
|
|
/* miptex */
|
|
if (bspdata->texdatasize) {
|
|
dmiptexlump_t *lump = (dmiptexlump_t *)bspdata->dtexdata;
|
|
int count = lump->nummiptex;
|
|
if (swap == TO_CPU)
|
|
count = LittleLong(count);
|
|
|
|
lump->nummiptex = LittleLong(lump->nummiptex);
|
|
for (i = 0; i < count; i++)
|
|
lump->dataofs[i] = LittleLong(lump->dataofs[i]);
|
|
}
|
|
|
|
/* marksurfaces */
|
|
for (i = 0; i < bspdata->nummarksurfaces; i++) {
|
|
unsigned short *marksurface = &bspdata->dmarksurfaces[i];
|
|
*marksurface = LittleShort(*marksurface);
|
|
}
|
|
|
|
/* surfedges */
|
|
for (i = 0; i < bspdata->numsurfedges; i++) {
|
|
int *surfedge = &bspdata->dsurfedges[i];
|
|
*surfedge = LittleLong(*surfedge);
|
|
}
|
|
|
|
/* edges */
|
|
for (i = 0; i < bspdata->numedges; i++) {
|
|
dedge_t *edge = &bspdata->dedges[i];
|
|
edge->v[0] = LittleShort(edge->v[0]);
|
|
edge->v[1] = LittleShort(edge->v[1]);
|
|
}
|
|
|
|
/* models */
|
|
for (i = 0; i < bspdata->nummodels; i++) {
|
|
dmodel_t *dmodel = &bspdata->dmodels[i];
|
|
for (j = 0; j < MAX_MAP_HULLS; j++)
|
|
dmodel->headnode[j] = LittleLong(dmodel->headnode[j]);
|
|
dmodel->visleafs = LittleLong(dmodel->visleafs);
|
|
dmodel->firstface = LittleLong(dmodel->firstface);
|
|
dmodel->numfaces = LittleLong(dmodel->numfaces);
|
|
for (j = 0; j < 3; j++) {
|
|
dmodel->mins[j] = LittleFloat(dmodel->mins[j]);
|
|
dmodel->maxs[j] = LittleFloat(dmodel->maxs[j]);
|
|
dmodel->origin[j] = LittleFloat(dmodel->origin[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
const lumpspec_t lumpspec[] = {
|
|
{ "entities", sizeof(char) },
|
|
{ "planes", sizeof(dplane_t) },
|
|
{ "texture", sizeof(byte) },
|
|
{ "vertexes", sizeof(dvertex_t) },
|
|
{ "visibility", sizeof(byte) },
|
|
{ "nodes", sizeof(dnode_t) },
|
|
{ "texinfos", sizeof(texinfo_t) },
|
|
{ "faces", sizeof(dface_t) },
|
|
{ "lighting", sizeof(byte) },
|
|
{ "clipnodes", sizeof(dclipnode_t) },
|
|
{ "leafs", sizeof(dleaf_t) },
|
|
{ "marksurfaces", sizeof(unsigned short) },
|
|
{ "edges", sizeof(dedge_t) },
|
|
{ "surfedges", sizeof(int) },
|
|
{ "models", sizeof(dmodel_t) },
|
|
};
|
|
|
|
static int
|
|
CopyLump(const dheader_t *header, int lumpnum, void *destptr)
|
|
{
|
|
const size_t size = lumpspec[lumpnum].size;
|
|
byte **bufferptr = destptr;
|
|
byte *buffer = *bufferptr;
|
|
int length;
|
|
int ofs;
|
|
|
|
length = header->lumps[lumpnum].filelen;
|
|
ofs = header->lumps[lumpnum].fileofs;
|
|
|
|
if (length % size)
|
|
Error("%s: odd %s lump size", __func__, lumpspec[lumpnum].name);
|
|
|
|
if (buffer)
|
|
free(buffer);
|
|
|
|
buffer = *bufferptr = malloc(length + 1);
|
|
if (!buffer)
|
|
Error("%s: allocation of %i bytes failed.", __func__, length);
|
|
|
|
memcpy(buffer, (const byte *)header + ofs, length);
|
|
buffer[length] = 0; /* In case of corrupt entity lump */
|
|
|
|
return length / size;
|
|
}
|
|
|
|
/*
|
|
* =============
|
|
* LoadBSPFile
|
|
* =============
|
|
*/
|
|
int
|
|
LoadBSPFile(const char *filename)
|
|
{
|
|
bspdata_t bsp;
|
|
dheader_t *header;
|
|
int i, version;
|
|
|
|
/* load the file header */
|
|
LoadFile(filename, &header);
|
|
|
|
/* check the file version */
|
|
version = header->version = LittleLong(header->version);
|
|
logprint("BSP is version %i\n", header->version);
|
|
if (header->version != 29)
|
|
Error("Sorry, only bsp version 29 supported.");
|
|
|
|
/* swap the lump headers */
|
|
for (i = 0; i < HEADER_LUMPS; i++) {
|
|
header->lumps[i].fileofs = LittleLong(header->lumps[i].fileofs);
|
|
header->lumps[i].filelen = LittleLong(header->lumps[i].filelen);
|
|
}
|
|
|
|
/* copy the data */
|
|
memset(&bsp, 0, sizeof(bsp));
|
|
bsp.nummodels = CopyLump(header, LUMP_MODELS, &bsp.dmodels);
|
|
bsp.numvertexes = CopyLump(header, LUMP_VERTEXES, &bsp.dvertexes);
|
|
bsp.numplanes = CopyLump(header, LUMP_PLANES, &bsp.dplanes);
|
|
bsp.numleafs = CopyLump(header, LUMP_LEAFS, &bsp.dleafs);
|
|
bsp.numnodes = CopyLump(header, LUMP_NODES, &bsp.dnodes);
|
|
bsp.numtexinfo = CopyLump(header, LUMP_TEXINFO, &bsp.texinfo);
|
|
bsp.numclipnodes = CopyLump(header, LUMP_CLIPNODES, &bsp.dclipnodes);
|
|
bsp.numfaces = CopyLump(header, LUMP_FACES, &bsp.dfaces);
|
|
bsp.nummarksurfaces = CopyLump(header, LUMP_MARKSURFACES, &bsp.dmarksurfaces);
|
|
bsp.numsurfedges = CopyLump(header, LUMP_SURFEDGES, &bsp.dsurfedges);
|
|
bsp.numedges = CopyLump(header, LUMP_EDGES, &bsp.dedges);
|
|
|
|
bsp.texdatasize = CopyLump(header, LUMP_TEXTURES, &bsp.dtexdata);
|
|
bsp.visdatasize = CopyLump(header, LUMP_VISIBILITY, &bsp.dvisdata);
|
|
bsp.lightdatasize = CopyLump(header, LUMP_LIGHTING, &bsp.dlightdata);
|
|
bsp.entdatasize = CopyLump(header, LUMP_ENTITIES, &bsp.dentdata);
|
|
|
|
/* everything has been copied out */
|
|
free(header);
|
|
|
|
/* swap everything */
|
|
SwapBSPFile(&bsp, TO_CPU);
|
|
|
|
/* Set the bsp globals for compatibility */
|
|
SetBSPGlobals(&bsp);
|
|
|
|
/* Return the version */
|
|
return version;
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
|
|
static void
|
|
AddLump(FILE *wadfile, dheader_t *header, int lumpnum,
|
|
const void *data, int count)
|
|
{
|
|
const size_t size = lumpspec[lumpnum].size * count;
|
|
lump_t *lump = &header->lumps[lumpnum];
|
|
byte pad[4] = {0};
|
|
|
|
lump->fileofs = LittleLong(ftell(wadfile));
|
|
lump->filelen = LittleLong(size);
|
|
SafeWrite(wadfile, data, (size + 3) & ~3);
|
|
if (size % 4)
|
|
SafeWrite(wadfile, pad, size % 4);
|
|
}
|
|
|
|
/*
|
|
* =============
|
|
* WriteBSPFile
|
|
* Swaps the bsp file in place, so it should not be referenced again
|
|
* =============
|
|
*/
|
|
void
|
|
WriteBSPFile(const char *filename, int version)
|
|
{
|
|
bspdata_t bspdata;
|
|
dheader_t header;
|
|
FILE *wadfile;
|
|
|
|
memset(&header, 0, sizeof(header));
|
|
|
|
GetBSPGlobals(&bspdata);
|
|
SwapBSPFile(&bspdata, TO_DISK);
|
|
|
|
header.version = LittleLong(version);
|
|
logprint("Writing BSP version %i\n", header.version);
|
|
wadfile = SafeOpenWrite(filename);
|
|
|
|
/* Save header space, updated after adding the lumps */
|
|
SafeWrite(wadfile, &header, sizeof(header));
|
|
|
|
AddLump(wadfile, &header, LUMP_PLANES, dplanes, numplanes);
|
|
AddLump(wadfile, &header, LUMP_LEAFS, dleafs, numleafs);
|
|
AddLump(wadfile, &header, LUMP_VERTEXES, dvertexes, numvertexes);
|
|
AddLump(wadfile, &header, LUMP_NODES, dnodes, numnodes);
|
|
AddLump(wadfile, &header, LUMP_TEXINFO, texinfo, numtexinfo);
|
|
AddLump(wadfile, &header, LUMP_FACES, dfaces, numfaces);
|
|
AddLump(wadfile, &header, LUMP_CLIPNODES, dclipnodes, numclipnodes);
|
|
AddLump(wadfile, &header, LUMP_MARKSURFACES, dmarksurfaces, nummarksurfaces);
|
|
AddLump(wadfile, &header, LUMP_SURFEDGES, dsurfedges, numsurfedges);
|
|
AddLump(wadfile, &header, LUMP_EDGES, dedges, numedges);
|
|
AddLump(wadfile, &header, LUMP_MODELS, dmodels, nummodels);
|
|
|
|
AddLump(wadfile, &header, LUMP_LIGHTING, dlightdata, lightdatasize);
|
|
AddLump(wadfile, &header, LUMP_VISIBILITY, dvisdata, visdatasize);
|
|
AddLump(wadfile, &header, LUMP_ENTITIES, dentdata, entdatasize);
|
|
AddLump(wadfile, &header, LUMP_TEXTURES, dtexdata, texdatasize);
|
|
|
|
fseek(wadfile, 0, SEEK_SET);
|
|
SafeWrite(wadfile, &header, sizeof(header));
|
|
|
|
fclose(wadfile);
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
|
|
static void
|
|
PrintLumpSize(int lumptype, int count)
|
|
{
|
|
const lumpspec_t *lump = &lumpspec[lumptype];
|
|
logprint("%7i %-12s %10i\n", count, lump->name, count * (int)lump->size);
|
|
}
|
|
|
|
/*
|
|
* =============
|
|
* PrintBSPFileSizes
|
|
* Dumps info about the bsp data
|
|
* =============
|
|
*/
|
|
void
|
|
PrintBSPFileSizes(const bspdata_t *bsp)
|
|
{
|
|
int numtextures = 0;
|
|
|
|
if (bsp->texdatasize)
|
|
numtextures = ((const dmiptexlump_t *)bsp->dtexdata)->nummiptex;
|
|
|
|
PrintLumpSize(LUMP_PLANES, bsp->numplanes);
|
|
PrintLumpSize(LUMP_VERTEXES, bsp->numvertexes);
|
|
PrintLumpSize(LUMP_NODES, bsp->numnodes);
|
|
PrintLumpSize(LUMP_TEXINFO, bsp->numtexinfo);
|
|
PrintLumpSize(LUMP_FACES, bsp->numfaces);
|
|
PrintLumpSize(LUMP_CLIPNODES, bsp->numclipnodes);
|
|
PrintLumpSize(LUMP_LEAFS, bsp->numleafs);
|
|
PrintLumpSize(LUMP_MARKSURFACES, bsp->nummarksurfaces);
|
|
PrintLumpSize(LUMP_EDGES, bsp->numedges);
|
|
PrintLumpSize(LUMP_SURFEDGES, bsp->numsurfedges);
|
|
|
|
logprint("%7i %-12s %10i\n", numtextures, "textures", bsp->texdatasize);
|
|
logprint("%7s %-12s %10i\n", "", "lightdata", bsp->lightdatasize);
|
|
logprint("%7s %-12s %10i\n", "", "visdata", bsp->visdatasize);
|
|
logprint("%7s %-12s %10i\n", "", "entdata", bsp->entdatasize);
|
|
}
|