/* 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 #include #include /* ========================================================================= */ 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); }