ericw-tools/common/bspfile.c

1568 lines
52 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>
static const char *
BSPVersionString(int32_t version)
{
static char buffers[2][20];
static int index;
char *buffer;
switch (version) {
case BSP2RMQVERSION:
return "BSP2rmq";
case BSP2VERSION:
return "BSP2";
default:
buffer = buffers[1 & ++index];
snprintf(buffer, sizeof(buffers[0]), "%d", version);
return buffer;
}
}
static qboolean
BSPVersionSupported(int32_t version)
{
switch (version) {
case BSPVERSION:
case BSP2VERSION:
case BSP2RMQVERSION:
return true;
default:
return false;
}
}
/*
* =========================================================================
* BSP BYTE SWAPPING
* =========================================================================
*/
typedef enum { TO_DISK, TO_CPU } swaptype_t;
static void
SwapBSPVertexes(int numvertexes, dvertex_t *verticies)
{
dvertex_t *vertex = verticies;
int i, j;
for (i = 0; i < numvertexes; i++, vertex++)
for (j = 0; j < 3; j++)
vertex->point[j] = LittleFloat(vertex->point[j]);
}
static void
SwapBSPPlanes(int numplanes, dplane_t *planes)
{
dplane_t *plane = planes;
int i, j;
for (i = 0; i < numplanes; i++, plane++) {
for (j = 0; j < 3; j++)
plane->normal[j] = LittleFloat(plane->normal[j]);
plane->dist = LittleFloat(plane->dist);
plane->type = LittleLong(plane->type);
}
}
static void
SwapBSPTexinfo(int numtexinfo, texinfo_t *texinfos)
{
texinfo_t *texinfo = texinfos;
int i, j;
for (i = 0; i < numtexinfo; i++, texinfo++) {
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);
}
}
static void
SwapBSP29Faces(int numfaces, bsp29_dface_t *faces)
{
bsp29_dface_t *face = faces;
int i;
for (i = 0; i < numfaces; i++, face++) {
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);
}
}
static void
SwapBSP2Faces(int numfaces, bsp2_dface_t *faces)
{
bsp2_dface_t *face = faces;
int i;
for (i = 0; i < numfaces; i++, face++) {
face->texinfo = LittleLong(face->texinfo);
face->planenum = LittleLong(face->planenum);
face->side = LittleLong(face->side);
face->lightofs = LittleLong(face->lightofs);
face->firstedge = LittleLong(face->firstedge);
face->numedges = LittleLong(face->numedges);
}
}
static void
SwapBSP29Nodes(int numnodes, bsp29_dnode_t *nodes)
{
bsp29_dnode_t *node = nodes;
int i, j;
/* nodes */
for (i = 0; i < numnodes; i++, node++) {
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);
}
}
static void
SwapBSP2rmqNodes(int numnodes, bsp2rmq_dnode_t *nodes)
{
bsp2rmq_dnode_t *node = nodes;
int i, j;
/* nodes */
for (i = 0; i < numnodes; i++, node++) {
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] = LittleLong(node->children[0]);
node->children[1] = LittleLong(node->children[1]);
node->firstface = LittleLong(node->firstface);
node->numfaces = LittleLong(node->numfaces);
}
}
static void
SwapBSP2Nodes(int numnodes, bsp2_dnode_t *nodes)
{
bsp2_dnode_t *node = nodes;
int i, j;
/* nodes */
for (i = 0; i < numnodes; i++, node++) {
node->planenum = LittleLong(node->planenum);
for (j = 0; j < 3; j++) {
node->mins[j] = LittleFloat(node->mins[j]);
node->maxs[j] = LittleFloat(node->maxs[j]);
}
node->children[0] = LittleLong(node->children[0]);
node->children[1] = LittleLong(node->children[1]);
node->firstface = LittleLong(node->firstface);
node->numfaces = LittleLong(node->numfaces);
}
}
static void
SwapBSP29Leafs(int numleafs, bsp29_dleaf_t *leafs)
{
bsp29_dleaf_t *leaf = leafs;
int i, j;
for (i = 0; i < numleafs; i++, leaf++) {
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);
}
}
static void
SwapBSP2rmqLeafs(int numleafs, bsp2rmq_dleaf_t *leafs)
{
bsp2rmq_dleaf_t *leaf = leafs;
int i, j;
for (i = 0; i < numleafs; i++, leaf++) {
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 = LittleLong(leaf->firstmarksurface);
leaf->nummarksurfaces = LittleLong(leaf->nummarksurfaces);
leaf->visofs = LittleLong(leaf->visofs);
}
}
static void
SwapBSP2Leafs(int numleafs, bsp2_dleaf_t *leafs)
{
bsp2_dleaf_t *leaf = leafs;
int i, j;
for (i = 0; i < numleafs; i++, leaf++) {
leaf->contents = LittleLong(leaf->contents);
for (j = 0; j < 3; j++) {
leaf->mins[j] = LittleFloat(leaf->mins[j]);
leaf->maxs[j] = LittleFloat(leaf->maxs[j]);
}
leaf->firstmarksurface = LittleLong(leaf->firstmarksurface);
leaf->nummarksurfaces = LittleLong(leaf->nummarksurfaces);
leaf->visofs = LittleLong(leaf->visofs);
}
}
static void
SwapBSP29Clipnodes(int numclipnodes, bsp29_dclipnode_t *clipnodes)
{
bsp29_dclipnode_t *clipnode = clipnodes;
int i;
for (i = 0; i < numclipnodes; i++, clipnode++) {
clipnode->planenum = LittleLong(clipnode->planenum);
clipnode->children[0] = LittleShort(clipnode->children[0]);
clipnode->children[1] = LittleShort(clipnode->children[1]);
}
}
static void
SwapBSP2Clipnodes(int numclipnodes, bsp2_dclipnode_t *clipnodes)
{
bsp2_dclipnode_t *clipnode = clipnodes;
int i;
for (i = 0; i < numclipnodes; i++, clipnode++) {
clipnode->planenum = LittleLong(clipnode->planenum);
clipnode->children[0] = LittleLong(clipnode->children[0]);
clipnode->children[1] = LittleLong(clipnode->children[1]);
}
}
static void
SwapBSP29Marksurfaces(int nummarksurfaces, uint16_t *dmarksurfaces)
{
uint16_t *marksurface = dmarksurfaces;
int i;
for (i = 0; i < nummarksurfaces; i++, marksurface++)
*marksurface = LittleShort(*marksurface);
}
static void
SwapBSP2Marksurfaces(int nummarksurfaces, uint32_t *dmarksurfaces)
{
uint32_t *marksurface = dmarksurfaces;
int i;
for (i = 0; i < nummarksurfaces; i++, marksurface++)
*marksurface = LittleLong(*marksurface);
}
static void
SwapBSPSurfedges(int numsurfedges, int32_t *dsurfedges)
{
int32_t *surfedge = dsurfedges;
int i;
for (i = 0; i < numsurfedges; i++, surfedge++)
*surfedge = LittleLong(*surfedge);
}
static void
SwapBSP29Edges(int numedges, bsp29_dedge_t *dedges)
{
bsp29_dedge_t *edge = dedges;
int i;
for (i = 0; i < numedges; i++, edge++) {
edge->v[0] = LittleShort(edge->v[0]);
edge->v[1] = LittleShort(edge->v[1]);
}
}
static void
SwapBSP2Edges(int numedges, bsp2_dedge_t *dedges)
{
bsp2_dedge_t *edge = dedges;
int i;
for (i = 0; i < numedges; i++, edge++) {
edge->v[0] = LittleLong(edge->v[0]);
edge->v[1] = LittleLong(edge->v[1]);
}
}
static void
SwapBSPModels(int nummodels, dmodel_t *dmodels)
{
dmodel_t *dmodel = dmodels;
int i, j;
for (i = 0; i < nummodels; i++, dmodel++) {
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]);
}
}
}
static void
SwapBSPMiptex(int texdatasize, dmiptexlump_t *header, const swaptype_t swap)
{
int i, count;
if (!texdatasize)
return;
count = header->nummiptex;
if (swap == TO_CPU)
count = LittleLong(count);
header->nummiptex = LittleLong(header->nummiptex);
for (i = 0; i < count; i++)
header->dataofs[i] = LittleLong(header->dataofs[i]);
}
/*
* =============
* SwapBSPFile
* Byte swaps all data in a bsp file.
* =============
*/
static void
SwapBSPFile(bspdata_t *bspdata, swaptype_t swap)
{
if (bspdata->version == BSPVERSION) {
bsp29_t *bsp = &bspdata->data.bsp29;
SwapBSPVertexes(bsp->numvertexes, bsp->dvertexes);
SwapBSPPlanes(bsp->numplanes, bsp->dplanes);
SwapBSPTexinfo(bsp->numtexinfo, bsp->texinfo);
SwapBSP29Faces(bsp->numfaces, bsp->dfaces);
SwapBSP29Nodes(bsp->numnodes, bsp->dnodes);
SwapBSP29Leafs(bsp->numleafs, bsp->dleafs);
SwapBSP29Clipnodes(bsp->numclipnodes, bsp->dclipnodes);
SwapBSPMiptex(bsp->texdatasize, bsp->dtexdata.header, swap);
SwapBSP29Marksurfaces(bsp->nummarksurfaces, bsp->dmarksurfaces);
SwapBSPSurfedges(bsp->numsurfedges, bsp->dsurfedges);
SwapBSP29Edges(bsp->numedges, bsp->dedges);
SwapBSPModels(bsp->nummodels, bsp->dmodels);
return;
}
if (bspdata->version == BSP2RMQVERSION) {
bsp2rmq_t *bsp = &bspdata->data.bsp2rmq;
SwapBSPVertexes(bsp->numvertexes, bsp->dvertexes);
SwapBSPPlanes(bsp->numplanes, bsp->dplanes);
SwapBSPTexinfo(bsp->numtexinfo, bsp->texinfo);
SwapBSP2Faces(bsp->numfaces, bsp->dfaces);
SwapBSP2rmqNodes(bsp->numnodes, bsp->dnodes);
SwapBSP2rmqLeafs(bsp->numleafs, bsp->dleafs);
SwapBSP2Clipnodes(bsp->numclipnodes, bsp->dclipnodes);
SwapBSPMiptex(bsp->texdatasize, bsp->dtexdata.header, swap);
SwapBSP2Marksurfaces(bsp->nummarksurfaces, bsp->dmarksurfaces);
SwapBSPSurfedges(bsp->numsurfedges, bsp->dsurfedges);
SwapBSP2Edges(bsp->numedges, bsp->dedges);
SwapBSPModels(bsp->nummodels, bsp->dmodels);
return;
}
if (bspdata->version == BSP2VERSION) {
bsp2_t *bsp = &bspdata->data.bsp2;
SwapBSPVertexes(bsp->numvertexes, bsp->dvertexes);
SwapBSPPlanes(bsp->numplanes, bsp->dplanes);
SwapBSPTexinfo(bsp->numtexinfo, bsp->texinfo);
SwapBSP2Faces(bsp->numfaces, bsp->dfaces);
SwapBSP2Nodes(bsp->numnodes, bsp->dnodes);
SwapBSP2Leafs(bsp->numleafs, bsp->dleafs);
SwapBSP2Clipnodes(bsp->numclipnodes, bsp->dclipnodes);
SwapBSPMiptex(bsp->texdatasize, bsp->dtexdata.header, swap);
SwapBSP2Marksurfaces(bsp->nummarksurfaces, bsp->dmarksurfaces);
SwapBSPSurfedges(bsp->numsurfedges, bsp->dsurfedges);
SwapBSP2Edges(bsp->numedges, bsp->dedges);
SwapBSPModels(bsp->nummodels, bsp->dmodels);
return;
}
Error("Unsupported BSP version: %d", bspdata->version);
}
/*
* =========================================================================
* BSP Format Conversion (ver. 29 <-> BSP2)
* =========================================================================
*/
static bsp2_dleaf_t *
BSP29to2_Leafs(const bsp29_t *bsp) {
const bsp29_dleaf_t *dleaf29 = bsp->dleafs;
bsp2_dleaf_t *newdata, *dleaf2;
int i, j;
newdata = dleaf2 = malloc(bsp->numleafs * sizeof(*dleaf2));
for (i = 0; i < bsp->numleafs; i++, dleaf29++, dleaf2++) {
dleaf2->contents = dleaf29->contents;
dleaf2->visofs = dleaf29->visofs;
for (j = 0; j < 3; j++) {
dleaf2->mins[j] = dleaf29->mins[j];
dleaf2->maxs[j] = dleaf29->maxs[j];
}
dleaf2->firstmarksurface = dleaf29->firstmarksurface;
dleaf2->nummarksurfaces = dleaf29->nummarksurfaces;
for (j = 0; j < NUM_AMBIENTS; j++)
dleaf2->ambient_level[j] = dleaf29->ambient_level[j];
}
free(bsp->dleafs);
return newdata;
}
static bsp29_dleaf_t *
BSP2to29_Leafs(const bsp2_t *bsp) {
const bsp2_dleaf_t *dleaf2 = bsp->dleafs;
bsp29_dleaf_t *newdata, *dleaf29;
int i, j;
newdata = dleaf29 = malloc(bsp->numleafs * sizeof(*dleaf29));
for (i = 0; i < bsp->numleafs; i++, dleaf2++, dleaf29++) {
dleaf29->contents = dleaf2->contents;
dleaf29->visofs = dleaf2->visofs;
for (j = 0; j < 3; j++) {
dleaf29->mins[j] = dleaf2->mins[j];
dleaf29->maxs[j] = dleaf2->maxs[j];
}
dleaf29->firstmarksurface = dleaf2->firstmarksurface;
dleaf29->nummarksurfaces = dleaf2->nummarksurfaces;
for (j = 0; j < NUM_AMBIENTS; j++)
dleaf29->ambient_level[j] = dleaf2->ambient_level[j];
}
free(bsp->dleafs);
return newdata;
}
static bsp2_dnode_t *
BSP29to2_Nodes(const bsp29_t *bsp) {
const bsp29_dnode_t *dnode29 = bsp->dnodes;
bsp2_dnode_t *newdata, *dnode2;
int i, j;
newdata = dnode2 = malloc(bsp->numnodes * sizeof(*dnode2));
for (i = 0; i < bsp->numnodes; i++, dnode29++, dnode2++) {
dnode2->planenum = dnode29->planenum;
dnode2->children[0] = dnode29->children[0];
dnode2->children[1] = dnode29->children[1];
for (j = 0; j < 3; j++) {
dnode2->mins[j] = dnode29->mins[j];
dnode2->maxs[j] = dnode29->maxs[j];
}
dnode2->firstface = dnode29->firstface;
dnode2->numfaces = dnode29->numfaces;
}
free(bsp->dnodes);
return newdata;
}
static bsp29_dnode_t *
BSP2to29_Nodes(const bsp2_t *bsp) {
const bsp2_dnode_t *dnode2 = bsp->dnodes;
bsp29_dnode_t *newdata, *dnode29;
int i, j;
newdata = dnode29 = malloc(bsp->numnodes * sizeof(*dnode29));
for (i = 0; i < bsp->numnodes; i++, dnode2++, dnode29++) {
dnode29->planenum = dnode2->planenum;
dnode29->children[0] = dnode2->children[0];
dnode29->children[1] = dnode2->children[1];
for (j = 0; j < 3; j++) {
dnode29->mins[j] = dnode2->mins[j];
dnode29->maxs[j] = dnode2->maxs[j];
}
dnode29->firstface = dnode2->firstface;
dnode29->numfaces = dnode2->numfaces;
}
free(bsp->dnodes);
return newdata;
}
static bsp2_dface_t *
BSP29to2_Faces(const bsp29_t *bsp) {
const bsp29_dface_t *dface29 = bsp->dfaces;
bsp2_dface_t *newdata, *dface2;
int i, j;
newdata = dface2 = malloc(bsp->numfaces * sizeof(*dface2));
for (i = 0; i < bsp->numfaces; i++, dface29++, dface2++) {
dface2->planenum = dface29->planenum;
dface2->side = dface29->side;
dface2->firstedge = dface29->firstedge;
dface2->numedges = dface29->numedges;
dface2->texinfo = dface29->texinfo;
for (j = 0; j < MAXLIGHTMAPS; j++)
dface2->styles[j] = dface29->styles[j];
dface2->lightofs = dface29->lightofs;
}
free(bsp->dfaces);
return newdata;
}
static bsp29_dface_t *
BSP2to29_Faces(const bsp2_t *bsp) {
const bsp2_dface_t *dface2 = bsp->dfaces;
bsp29_dface_t *newdata, *dface29;
int i, j;
newdata = dface29 = malloc(bsp->numfaces * sizeof(*dface29));
for (i = 0; i < bsp->numfaces; i++, dface2++, dface29++) {
dface29->planenum = dface2->planenum;
dface29->side = dface2->side;
dface29->firstedge = dface2->firstedge;
dface29->numedges = dface2->numedges;
dface29->texinfo = dface2->texinfo;
for (j = 0; j < MAXLIGHTMAPS; j++)
dface29->styles[j] = dface2->styles[j];
dface29->lightofs = dface2->lightofs;
}
free(bsp->dfaces);
return newdata;
}
static bsp2_dclipnode_t *
BSP29to2_Clipnodes(const bsp29_t *bsp) {
const bsp29_dclipnode_t *dclipnode29 = bsp->dclipnodes;
bsp2_dclipnode_t *newdata, *dclipnode2;
int i, j;
newdata = dclipnode2 = malloc(bsp->numclipnodes * sizeof(*dclipnode2));
for (i = 0; i < bsp->numclipnodes; i++, dclipnode29++, dclipnode2++) {
dclipnode2->planenum = dclipnode29->planenum;
for (j = 0; j < 2; j++) {
/* Slightly tricky since we support > 32k clipnodes */
int32_t child = (uint16_t)dclipnode29->children[j];
dclipnode2->children[j] = child > 0xfff0 ? child - 0x10000 : child;
}
}
free(bsp->dclipnodes);
return newdata;
}
static bsp29_dclipnode_t *
BSP2to29_Clipnodes(const bsp2_t *bsp) {
const bsp2_dclipnode_t *dclipnode2 = bsp->dclipnodes;
bsp29_dclipnode_t *newdata, *dclipnode29;
int i, j;
newdata = dclipnode29 = malloc(bsp->numclipnodes * sizeof(*dclipnode29));
for (i = 0; i < bsp->numclipnodes; i++, dclipnode2++, dclipnode29++) {
dclipnode29->planenum = dclipnode2->planenum;
for (j = 0; j < 2; j++) {
/* Slightly tricky since we support > 32k clipnodes */
int32_t child = dclipnode2->children[j];
dclipnode29->children[j] = child < 0 ? child + 0x10000 : child;
}
}
free(bsp->dclipnodes);
return newdata;
}
static bsp2_dedge_t *
BSP29to2_Edges(const bsp29_t *bsp)
{
const bsp29_dedge_t *dedge29 = bsp->dedges;
bsp2_dedge_t *newdata, *dedge2;
int i;
newdata = dedge2 = malloc(bsp->numedges * sizeof(*dedge2));
for (i = 0; i < bsp->numedges; i++, dedge29++, dedge2++) {
dedge2->v[0] = dedge29->v[0];
dedge2->v[1] = dedge29->v[1];
}
free(bsp->dedges);
return newdata;
}
static bsp29_dedge_t *
BSP2to29_Edges(const bsp2_t *bsp)
{
const bsp2_dedge_t *dedge2 = bsp->dedges;
bsp29_dedge_t *newdata, *dedge29;
int i;
newdata = dedge29 = malloc(bsp->numedges * sizeof(*dedge29));
for (i = 0; i < bsp->numedges; i++, dedge2++, dedge29++) {
dedge29->v[0] = dedge2->v[0];
dedge29->v[1] = dedge2->v[1];
}
free(bsp->dedges);
return newdata;
}
static uint32_t *
BSP29to2_Marksurfaces(const bsp29_t *bsp)
{
const uint16_t *dmarksurface29 = bsp->dmarksurfaces;
uint32_t *newdata, *dmarksurface2;
int i;
newdata = dmarksurface2 = malloc(bsp->nummarksurfaces * sizeof(*dmarksurface2));
for (i = 0; i < bsp->nummarksurfaces; i++, dmarksurface29++, dmarksurface2++)
*dmarksurface2 = *dmarksurface29;
free(bsp->dmarksurfaces);
return newdata;
}
static uint16_t *
BSP2to29_Marksurfaces(const bsp2_t *bsp)
{
const uint32_t *dmarksurface2 = bsp->dmarksurfaces;
uint16_t *newdata, *dmarksurface29;
int i;
newdata = dmarksurface29 = malloc(bsp->nummarksurfaces * sizeof(*dmarksurface29));
for (i = 0; i < bsp->nummarksurfaces; i++, dmarksurface2++, dmarksurface29++)
*dmarksurface29 = *dmarksurface2;
free(bsp->dmarksurfaces);
return newdata;
}
/*
* =========================================================================
* BSP Format Conversion (ver. BSP2rmq <-> BSP2)
* =========================================================================
*/
static bsp2_dleaf_t *
BSP2rmqto2_Leafs(const bsp2rmq_t *bsp) {
const bsp2rmq_dleaf_t *dleaf2rmq = bsp->dleafs;
bsp2_dleaf_t *newdata, *dleaf2;
int i, j;
newdata = dleaf2 = malloc(bsp->numleafs * sizeof(*dleaf2));
for (i = 0; i < bsp->numleafs; i++, dleaf2rmq++, dleaf2++) {
dleaf2->contents = dleaf2rmq->contents;
dleaf2->visofs = dleaf2rmq->visofs;
for (j = 0; j < 3; j++) {
dleaf2->mins[j] = dleaf2rmq->mins[j];
dleaf2->maxs[j] = dleaf2rmq->maxs[j];
}
dleaf2->firstmarksurface = dleaf2rmq->firstmarksurface;
dleaf2->nummarksurfaces = dleaf2rmq->nummarksurfaces;
for (j = 0; j < NUM_AMBIENTS; j++)
dleaf2->ambient_level[j] = dleaf2rmq->ambient_level[j];
}
free(bsp->dleafs);
return newdata;
}
static bsp2rmq_dleaf_t *
BSP2to2rmq_Leafs(const bsp2_t *bsp) {
const bsp2_dleaf_t *dleaf2 = bsp->dleafs;
bsp2rmq_dleaf_t *newdata, *dleaf2rmq;
int i, j;
newdata = dleaf2rmq = malloc(bsp->numleafs * sizeof(*dleaf2rmq));
for (i = 0; i < bsp->numleafs; i++, dleaf2++, dleaf2rmq++) {
dleaf2rmq->contents = dleaf2->contents;
dleaf2rmq->visofs = dleaf2->visofs;
for (j = 0; j < 3; j++) {
dleaf2rmq->mins[j] = dleaf2->mins[j];
dleaf2rmq->maxs[j] = dleaf2->maxs[j];
}
dleaf2rmq->firstmarksurface = dleaf2->firstmarksurface;
dleaf2rmq->nummarksurfaces = dleaf2->nummarksurfaces;
for (j = 0; j < NUM_AMBIENTS; j++)
dleaf2rmq->ambient_level[j] = dleaf2->ambient_level[j];
}
free(bsp->dleafs);
return newdata;
}
static bsp2_dnode_t *
BSP2rmqto2_Nodes(const bsp2rmq_t *bsp) {
const bsp2rmq_dnode_t *dnode2rmq = bsp->dnodes;
bsp2_dnode_t *newdata, *dnode2;
int i, j;
newdata = dnode2 = malloc(bsp->numnodes * sizeof(*dnode2));
for (i = 0; i < bsp->numnodes; i++, dnode2rmq++, dnode2++) {
dnode2->planenum = dnode2rmq->planenum;
dnode2->children[0] = dnode2rmq->children[0];
dnode2->children[1] = dnode2rmq->children[1];
for (j = 0; j < 3; j++) {
dnode2->mins[j] = dnode2rmq->mins[j];
dnode2->maxs[j] = dnode2rmq->maxs[j];
}
dnode2->firstface = dnode2rmq->firstface;
dnode2->numfaces = dnode2rmq->numfaces;
}
free(bsp->dnodes);
return newdata;
}
static bsp2rmq_dnode_t *
BSP2to2rmq_Nodes(const bsp2_t *bsp) {
const bsp2_dnode_t *dnode2 = bsp->dnodes;
bsp2rmq_dnode_t *newdata, *dnode2rmq;
int i, j;
newdata = dnode2rmq = malloc(bsp->numnodes * sizeof(*dnode2rmq));
for (i = 0; i < bsp->numnodes; i++, dnode2++, dnode2rmq++) {
dnode2rmq->planenum = dnode2->planenum;
dnode2rmq->children[0] = dnode2->children[0];
dnode2rmq->children[1] = dnode2->children[1];
for (j = 0; j < 3; j++) {
dnode2rmq->mins[j] = dnode2->mins[j];
dnode2rmq->maxs[j] = dnode2->maxs[j];
}
dnode2rmq->firstface = dnode2->firstface;
dnode2rmq->numfaces = dnode2->numfaces;
}
free(bsp->dnodes);
return newdata;
}
/*
* =========================================================================
* ConvertBSPFormat
* - BSP is assumed to be in CPU byte order already
* - No checks are done here (yet) for overflow of values when down-converting
* =========================================================================
*/
void
ConvertBSPFormat(int32_t version, bspdata_t *bspdata)
{
if (bspdata->version == version)
return;
if (bspdata->version == BSPVERSION && version == BSP2VERSION) {
bsp29_t *bsp29 = &bspdata->data.bsp29;
bsp2_t *bsp2 = &bspdata->data.bsp2;
bsp2->dleafs = BSP29to2_Leafs(bsp29);
bsp2->dnodes = BSP29to2_Nodes(bsp29);
bsp2->dfaces = BSP29to2_Faces(bsp29);
bsp2->dclipnodes = BSP29to2_Clipnodes(bsp29);
bsp2->dedges = BSP29to2_Edges(bsp29);
bsp2->dmarksurfaces = BSP29to2_Marksurfaces(bsp29);
/* Conversion complete! */
bspdata->version = BSP2VERSION;
return;
}
if (bspdata->version == BSP2RMQVERSION && version == BSP2VERSION) {
bsp2rmq_t *bsp2rmq = &bspdata->data.bsp2rmq;
bsp2_t *bsp2 = &bspdata->data.bsp2;
bsp2->dleafs = BSP2rmqto2_Leafs(bsp2rmq);
bsp2->dnodes = BSP2rmqto2_Nodes(bsp2rmq);
/* Conversion complete! */
bspdata->version = BSP2VERSION;
return;
}
if (bspdata->version == BSP2VERSION && version == BSPVERSION) {
bsp29_t *bsp29 = &bspdata->data.bsp29;
bsp2_t *bsp2 = &bspdata->data.bsp2;
bsp29->dleafs = BSP2to29_Leafs(bsp2);
bsp29->dnodes = BSP2to29_Nodes(bsp2);
bsp29->dfaces = BSP2to29_Faces(bsp2);
bsp29->dclipnodes = BSP2to29_Clipnodes(bsp2);
bsp29->dedges = BSP2to29_Edges(bsp2);
bsp29->dmarksurfaces = BSP2to29_Marksurfaces(bsp2);
/* Conversion complete! */
bspdata->version = BSPVERSION;
return;
}
if (bspdata->version == BSP2VERSION && version == BSP2RMQVERSION) {
bsp2rmq_t *bsp2rmq = &bspdata->data.bsp2rmq;
bsp2_t *bsp2 = &bspdata->data.bsp2;
bsp2rmq->dleafs = BSP2to2rmq_Leafs(bsp2);
bsp2rmq->dnodes = BSP2to2rmq_Nodes(bsp2);
/* Conversion complete! */
bspdata->version = BSP2RMQVERSION;
return;
}
if (bspdata->version == BSPVERSION && version == BSP2RMQVERSION) {
ConvertBSPFormat(BSP2VERSION, bspdata);
ConvertBSPFormat(BSP2RMQVERSION, bspdata);
return;
}
if (bspdata->version == BSP2RMQVERSION && version == BSPVERSION) {
ConvertBSPFormat(BSP2VERSION, bspdata);
ConvertBSPFormat(BSPVERSION, bspdata);
return;
}
Error("Don't know how to convert BSP version %s to %s",
BSPVersionString(bspdata->version), BSPVersionString(version));
}
static int
isHexen2(const dheader_t *header)
{
/*
the world should always have some face.
however, if the sizes are wrong then we're actually reading headnode[6]. hexen2 only used 5 hulls, so this should be 0 in hexen2, and not in quake.
*/
const dmodelq1_t *modelsq1 = (const dmodelq1_t*)((const byte *)header + header->lumps[LUMP_MODELS].fileofs);
return !modelsq1->numfaces;
}
/*
* =========================================================================
* ...
* =========================================================================
*/
const lumpspec_t lumpspec_bsp29[] = {
{ "entities", sizeof(char) },
{ "planes", sizeof(dplane_t) },
{ "texture", sizeof(byte) },
{ "vertexes", sizeof(dvertex_t) },
{ "visibility", sizeof(byte) },
{ "nodes", sizeof(bsp29_dnode_t) },
{ "texinfos", sizeof(texinfo_t) },
{ "faces", sizeof(bsp29_dface_t) },
{ "lighting", sizeof(byte) },
{ "clipnodes", sizeof(bsp29_dclipnode_t) },
{ "leafs", sizeof(bsp29_dleaf_t) },
{ "marksurfaces", sizeof(uint16_t) },
{ "edges", sizeof(bsp29_dedge_t) },
{ "surfedges", sizeof(int32_t) },
{ "models", sizeof(dmodel_t) },
};
const lumpspec_t lumpspec_bsp2rmq[] = {
{ "entities", sizeof(char) },
{ "planes", sizeof(dplane_t) },
{ "texture", sizeof(byte) },
{ "vertexes", sizeof(dvertex_t) },
{ "visibility", sizeof(byte) },
{ "nodes", sizeof(bsp2rmq_dnode_t) },
{ "texinfos", sizeof(texinfo_t) },
{ "faces", sizeof(bsp2_dface_t) },
{ "lighting", sizeof(byte) },
{ "clipnodes", sizeof(bsp2_dclipnode_t ) },
{ "leafs", sizeof(bsp2rmq_dleaf_t) },
{ "marksurfaces", sizeof(uint32_t) },
{ "edges", sizeof(bsp2_dedge_t) },
{ "surfedges", sizeof(int32_t) },
{ "models", sizeof(dmodel_t) },
};
const lumpspec_t lumpspec_bsp2[] = {
{ "entities", sizeof(char) },
{ "planes", sizeof(dplane_t) },
{ "texture", sizeof(byte) },
{ "vertexes", sizeof(dvertex_t) },
{ "visibility", sizeof(byte) },
{ "nodes", sizeof(bsp2_dnode_t) },
{ "texinfos", sizeof(texinfo_t) },
{ "faces", sizeof(bsp2_dface_t) },
{ "lighting", sizeof(byte) },
{ "clipnodes", sizeof(bsp2_dclipnode_t ) },
{ "leafs", sizeof(bsp2_dleaf_t) },
{ "marksurfaces", sizeof(uint32_t) },
{ "edges", sizeof(bsp2_dedge_t) },
{ "surfedges", sizeof(int32_t) },
{ "models", sizeof(dmodel_t) },
};
static int
CopyLump(const dheader_t *header, int lumpnum, void *destptr)
{
const lumpspec_t *lumpspec;
byte **bufferptr = destptr;
byte *buffer = *bufferptr;
int length;
int ofs;
switch (header->version) {
case BSPVERSION:
lumpspec = &lumpspec_bsp29[lumpnum];
break;
case BSP2RMQVERSION:
lumpspec = &lumpspec_bsp2rmq[lumpnum];
break;
case BSP2VERSION:
lumpspec = &lumpspec_bsp2[lumpnum];
break;
default:
Error("Unsupported BSP version: %d", header->version);
}
length = header->lumps[lumpnum].filelen;
ofs = header->lumps[lumpnum].fileofs;
if (buffer)
free(buffer);
if (lumpnum == LUMP_MODELS && !isHexen2(header))
{ /*convert in-place. no need to care about endian here.*/
const dmodelq1_t *in = (const dmodelq1_t*)((const byte *)header + ofs);
dmodel_t *out;
int i, j;
if (length % sizeof(dmodelq1_t))
Error("%s: odd %s lump size", __func__, lumpspec->name);
length /= sizeof(dmodelq1_t);
buffer = *bufferptr = malloc(length * sizeof(dmodel_t));
if (!buffer)
Error("%s: allocation of %i bytes failed.", __func__, length);
out = (dmodel_t*)buffer;
for (i = 0; i < length; i++)
{
for (j = 0; j < 3; j++)
{
out[i].mins[j] = in[i].mins[j];
out[i].maxs[j] = in[i].maxs[j];
out[i].origin[j] = in[i].origin[j];
}
for (j = 0; j < MAX_MAP_HULLS_Q1; j++)
out[i].headnode[j] = in[i].headnode[j];
for ( ; j < MAX_MAP_HULLS_H2; j++)
out[i].headnode[j] = 0;
out[i].visleafs = in[i].visleafs;
out[i].firstface = in[i].firstface;
out[i].numfaces = in[i].numfaces;
}
return length;
}
else
{
if (length % lumpspec->size)
Error("%s: odd %s lump size", __func__, lumpspec->name);
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 / lumpspec->size;
}
}
void BSPX_AddLump(bspdata_t *bspdata, const char *xname, const void *xdata, size_t xsize)
{
bspxentry_t *e;
bspxentry_t **link;
if (!xdata)
{
for (link = &bspdata->bspxentries; *link; )
{
e = *link;
if (!strcmp(e->lumpname, xname))
{
*link = e->next;
free(e);
break;
}
else
link = &(*link)->next;
}
return;
}
for (e = bspdata->bspxentries; e; e = e->next)
{
if (!strcmp(e->lumpname, xname))
break;
}
if (!e)
{
e = malloc(sizeof(*e));
memset(e, 0, sizeof(*e));
strncpy(e->lumpname, xname, sizeof(e->lumpname));
e->next = bspdata->bspxentries;
bspdata->bspxentries = e;
}
e->lumpdata = xdata;
e->lumpsize = xsize;
}
const void *BSPX_GetLump(bspdata_t *bspdata, const char *xname, size_t *xsize)
{
bspxentry_t *e;
for (e = bspdata->bspxentries; e; e = e->next)
{
if (!strcmp(e->lumpname, xname))
break;
}
if (e)
{
if (xsize)
*xsize = e->lumpsize;
return e->lumpdata;
}
else
{
if (xsize)
*xsize = 0;
return NULL;
}
}
/*
* =============
* LoadBSPFile
* =============
*/
void
LoadBSPFile(char *filename, bspdata_t *bspdata)
{
dheader_t *header;
int i;
uint32_t bspxofs, flen;
const bspx_header_t *bspx;
/* load the file header */
flen = LoadFilePak(filename, &header);
bspdata->bspxentries = NULL;
/* check the file version */
header->version = LittleLong(header->version);
logprint("BSP is version %s\n", BSPVersionString(header->version));
if (!BSPVersionSupported(header->version))
Error("Sorry, this bsp version is not supported.");
/* swap the lump headers */
for (i = 0; i < BSP_LUMPS; i++) {
header->lumps[i].fileofs = LittleLong(header->lumps[i].fileofs);
header->lumps[i].filelen = LittleLong(header->lumps[i].filelen);
}
if (isHexen2(header))
{
logprint("BSP appears to be from hexen2\n");
bspdata->hullcount = MAX_MAP_HULLS_H2;
}
else
bspdata->hullcount = MAX_MAP_HULLS_Q1;
/* copy the data */
if (header->version == BSPVERSION) {
bsp29_t *bsp = &bspdata->data.bsp29;
memset(bsp, 0, sizeof(*bsp));
bspdata->version = header->version;
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.base);
bsp->visdatasize = CopyLump(header, LUMP_VISIBILITY, &bsp->dvisdata);
bsp->lightdatasize = CopyLump(header, LUMP_LIGHTING, &bsp->dlightdata);
bsp->entdatasize = CopyLump(header, LUMP_ENTITIES, &bsp->dentdata);
}
if (header->version == BSP2RMQVERSION) {
bsp2rmq_t *bsp = &bspdata->data.bsp2rmq;
memset(bsp, 0, sizeof(*bsp));
bspdata->version = header->version;
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.base);
bsp->visdatasize = CopyLump(header, LUMP_VISIBILITY, &bsp->dvisdata);
bsp->lightdatasize = CopyLump(header, LUMP_LIGHTING, &bsp->dlightdata);
bsp->entdatasize = CopyLump(header, LUMP_ENTITIES, &bsp->dentdata);
}
if (header->version == BSP2VERSION) {
bsp2_t *bsp = &bspdata->data.bsp2;
memset(bsp, 0, sizeof(*bsp));
bspdata->version = header->version;
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.base);
bsp->visdatasize = CopyLump(header, LUMP_VISIBILITY, &bsp->dvisdata);
bsp->lightdatasize = CopyLump(header, LUMP_LIGHTING, &bsp->dlightdata);
bsp->entdatasize = CopyLump(header, LUMP_ENTITIES, &bsp->dentdata);
}
/*bspx header is positioned exactly+4align at the end of the last lump position (regardless of order)*/
for (i = 0, bspxofs = 0; i < BSP_LUMPS; i++)
{
if (bspxofs < header->lumps[i].fileofs + header->lumps[i].filelen)
bspxofs = header->lumps[i].fileofs + header->lumps[i].filelen;
}
bspxofs = (bspxofs+3) & ~3;
/*okay, so that's where it *should* be if it exists */
if (bspxofs + sizeof(*bspx) <= flen)
{
int xlumps;
const bspx_lump_t *xlump;
bspx = (const bspx_header_t*)((const byte*)header + bspxofs);
xlump = (const bspx_lump_t*)(bspx+1);
xlumps = LittleLong(bspx->numlumps);
if (!memcmp(&bspx->id,"BSPX",4) && xlumps >= 0 && bspxofs+sizeof(*bspx)+sizeof(*xlump)*xlumps <= flen)
{
/*header seems valid so far. just add the lumps as we normally would if we were generating them, ensuring that they get written out anew*/
while(xlumps --> 0)
{
uint32_t ofs = LittleLong(xlump[xlumps].fileofs);
uint32_t len = LittleLong(xlump[xlumps].filelen);
void *lumpdata = malloc(len);
memcpy(lumpdata, (const byte*)header + ofs, len);
BSPX_AddLump(bspdata, xlump[xlumps].lumpname, lumpdata, len);
}
}
else
{
if (!memcmp(&bspx->id,"BSPX",4))
printf("invalid bspx header\n");
}
}
/* everything has been copied out */
free(header);
/* swap everything */
SwapBSPFile(bspdata, TO_CPU);
}
/* ========================================================================= */
typedef struct {
dheader_t header;
FILE *file;
} bspfile_t;
static void
AddLump(bspfile_t *bspfile, int lumpnum, const void *data, int count)
{
lump_t *lump = &bspfile->header.lumps[lumpnum];
byte pad[4] = {0};
size_t size;
/* FIXME - bad API, needing to byte swap back and forth... */
switch (LittleLong(bspfile->header.version)) {
case BSPVERSION:
size = lumpspec_bsp29[lumpnum].size * count;
break;
case BSP2RMQVERSION:
size = lumpspec_bsp2rmq[lumpnum].size * count;
break;
case BSP2VERSION:
size = lumpspec_bsp2[lumpnum].size * count;
break;
default:
Error("Unsupported BSP version: %d",
LittleLong(bspfile->header.version));
}
lump->fileofs = LittleLong(ftell(bspfile->file));
lump->filelen = LittleLong(size);
SafeWrite(bspfile->file, data, size);
if (size % 4)
SafeWrite(bspfile->file, pad, 4 - (size % 4));
}
static void
AddModelsLump(bspfile_t *bspfile, bspdata_t *bspdata, const void *data, int count)
{
if (bspdata->hullcount == MAX_MAP_HULLS_Q1)
{ /*convert in-place. no need to care about endian here.*/
lump_t *lump = &bspfile->header.lumps[LUMP_MODELS];
const dmodel_t *in = data;
dmodelq1_t *out = malloc(count * sizeof(dmodelq1_t));
int i, j;
for (i = 0; i < count; i++)
{
for (j = 0; j < 3; j++)
{
out[i].mins[j] = in[i].mins[j];
out[i].maxs[j] = in[i].maxs[j];
out[i].origin[j] = in[i].origin[j];
}
for (j = 0; j < MAX_MAP_HULLS_Q1; j++)
out[i].headnode[j] = in[i].headnode[j];
out[i].visleafs = in[i].visleafs;
out[i].firstface = in[i].firstface;
out[i].numfaces = in[i].numfaces;
}
lump->fileofs = LittleLong(ftell(bspfile->file));
lump->filelen = LittleLong(sizeof(dmodelq1_t) * count);
SafeWrite(bspfile->file, out, lump->filelen);
free(out);
return;
}
else
AddLump(bspfile, LUMP_MODELS, data, count);
}
/*
* =============
* WriteBSPFile
* Swaps the bsp file in place, so it should not be referenced again
* =============
*/
void
WriteBSPFile(const char *filename, bspdata_t *bspdata)
{
bspfile_t bspfile;
memset(&bspfile.header, 0, sizeof(bspfile.header));
SwapBSPFile(bspdata, TO_DISK);
bspfile.header.version = LittleLong(bspdata->version);
logprint("Writing %s as BSP version %s\n", filename, BSPVersionString(bspdata->version));
bspfile.file = SafeOpenWrite(filename);
/* Save header space, updated after adding the lumps */
SafeWrite(bspfile.file, &bspfile.header, sizeof(bspfile.header));
if (bspdata->version == BSPVERSION) {
bsp29_t *bsp = &bspdata->data.bsp29;
AddLump(&bspfile, LUMP_PLANES, bsp->dplanes, bsp->numplanes);
AddLump(&bspfile, LUMP_LEAFS, bsp->dleafs, bsp->numleafs);
AddLump(&bspfile, LUMP_VERTEXES, bsp->dvertexes, bsp->numvertexes);
AddLump(&bspfile, LUMP_NODES, bsp->dnodes, bsp->numnodes);
AddLump(&bspfile, LUMP_TEXINFO, bsp->texinfo, bsp->numtexinfo);
AddLump(&bspfile, LUMP_FACES, bsp->dfaces, bsp->numfaces);
AddLump(&bspfile, LUMP_CLIPNODES, bsp->dclipnodes, bsp->numclipnodes);
AddLump(&bspfile, LUMP_MARKSURFACES, bsp->dmarksurfaces, bsp->nummarksurfaces);
AddLump(&bspfile, LUMP_SURFEDGES, bsp->dsurfedges, bsp->numsurfedges);
AddLump(&bspfile, LUMP_EDGES, bsp->dedges, bsp->numedges);
AddModelsLump(&bspfile, bspdata, bsp->dmodels, bsp->nummodels);
AddLump(&bspfile, LUMP_LIGHTING, bsp->dlightdata, bsp->lightdatasize);
AddLump(&bspfile, LUMP_VISIBILITY, bsp->dvisdata, bsp->visdatasize);
AddLump(&bspfile, LUMP_ENTITIES, bsp->dentdata, bsp->entdatasize);
AddLump(&bspfile, LUMP_TEXTURES, bsp->dtexdata.base, bsp->texdatasize);
}
if (bspdata->version == BSP2RMQVERSION) {
bsp2rmq_t *bsp = &bspdata->data.bsp2rmq;
AddLump(&bspfile, LUMP_PLANES, bsp->dplanes, bsp->numplanes);
AddLump(&bspfile, LUMP_LEAFS, bsp->dleafs, bsp->numleafs);
AddLump(&bspfile, LUMP_VERTEXES, bsp->dvertexes, bsp->numvertexes);
AddLump(&bspfile, LUMP_NODES, bsp->dnodes, bsp->numnodes);
AddLump(&bspfile, LUMP_TEXINFO, bsp->texinfo, bsp->numtexinfo);
AddLump(&bspfile, LUMP_FACES, bsp->dfaces, bsp->numfaces);
AddLump(&bspfile, LUMP_CLIPNODES, bsp->dclipnodes, bsp->numclipnodes);
AddLump(&bspfile, LUMP_MARKSURFACES, bsp->dmarksurfaces, bsp->nummarksurfaces);
AddLump(&bspfile, LUMP_SURFEDGES, bsp->dsurfedges, bsp->numsurfedges);
AddLump(&bspfile, LUMP_EDGES, bsp->dedges, bsp->numedges);
AddModelsLump(&bspfile, bspdata, bsp->dmodels, bsp->nummodels);
AddLump(&bspfile, LUMP_LIGHTING, bsp->dlightdata, bsp->lightdatasize);
AddLump(&bspfile, LUMP_VISIBILITY, bsp->dvisdata, bsp->visdatasize);
AddLump(&bspfile, LUMP_ENTITIES, bsp->dentdata, bsp->entdatasize);
AddLump(&bspfile, LUMP_TEXTURES, bsp->dtexdata.base, bsp->texdatasize);
}
if (bspdata->version == BSP2VERSION) {
bsp2_t *bsp = &bspdata->data.bsp2;
AddLump(&bspfile, LUMP_PLANES, bsp->dplanes, bsp->numplanes);
AddLump(&bspfile, LUMP_LEAFS, bsp->dleafs, bsp->numleafs);
AddLump(&bspfile, LUMP_VERTEXES, bsp->dvertexes, bsp->numvertexes);
AddLump(&bspfile, LUMP_NODES, bsp->dnodes, bsp->numnodes);
AddLump(&bspfile, LUMP_TEXINFO, bsp->texinfo, bsp->numtexinfo);
AddLump(&bspfile, LUMP_FACES, bsp->dfaces, bsp->numfaces);
AddLump(&bspfile, LUMP_CLIPNODES, bsp->dclipnodes, bsp->numclipnodes);
AddLump(&bspfile, LUMP_MARKSURFACES, bsp->dmarksurfaces, bsp->nummarksurfaces);
AddLump(&bspfile, LUMP_SURFEDGES, bsp->dsurfedges, bsp->numsurfedges);
AddLump(&bspfile, LUMP_EDGES, bsp->dedges, bsp->numedges);
AddModelsLump(&bspfile, bspdata, bsp->dmodels, bsp->nummodels);
AddLump(&bspfile, LUMP_LIGHTING, bsp->dlightdata, bsp->lightdatasize);
AddLump(&bspfile, LUMP_VISIBILITY, bsp->dvisdata, bsp->visdatasize);
AddLump(&bspfile, LUMP_ENTITIES, bsp->dentdata, bsp->entdatasize);
AddLump(&bspfile, LUMP_TEXTURES, bsp->dtexdata.base, bsp->texdatasize);
}
/*BSPX lumps are at a 4-byte alignment after the last of any official lump*/
if (bspdata->bspxentries)
{
bspx_header_t xheader;
bspxentry_t *x;
bspx_lump_t xlumps[64];
uint32_t l;
uint32_t bspxheader = ftell(bspfile.file);
if (bspxheader & 3)
Error("BSPX header is misaligned");
xheader.id[0] = 'B';
xheader.id[1] = 'S';
xheader.id[2] = 'P';
xheader.id[3] = 'X';
xheader.numlumps = 0;
for (x = bspdata->bspxentries; x; x = x->next)
xheader.numlumps++;
if (xheader.numlumps > sizeof(xlumps)/sizeof(xlumps[0])) /*eep*/
xheader.numlumps = sizeof(xlumps)/sizeof(xlumps[0]);
SafeWrite(bspfile.file, &xheader, sizeof(xheader));
SafeWrite(bspfile.file, xlumps, xheader.numlumps * sizeof(xlumps[0]));
for (x = bspdata->bspxentries, l = 0; x && l < xheader.numlumps; x = x->next, l++)
{
byte pad[4] = {0};
xlumps[l].filelen = LittleLong(x->lumpsize);
xlumps[l].fileofs = LittleLong(ftell(bspfile.file));
strncpy(xlumps[l].lumpname, x->lumpname, sizeof(xlumps[l].lumpname));
SafeWrite(bspfile.file, x->lumpdata, x->lumpsize);
if (x->lumpsize % 4)
SafeWrite(bspfile.file, pad, 4 - (x->lumpsize % 4));
}
fseek(bspfile.file, bspxheader, SEEK_SET);
SafeWrite(bspfile.file, &xheader, sizeof(xheader));
SafeWrite(bspfile.file, xlumps, xheader.numlumps * sizeof(xlumps[0]));
}
fseek(bspfile.file, 0, SEEK_SET);
SafeWrite(bspfile.file, &bspfile.header, sizeof(bspfile.header));
fclose(bspfile.file);
}
/* ========================================================================= */
static void
PrintLumpSize(const lumpspec_t *lumpspec, 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 *bspdata)
{
int numtextures = 0;
if (bspdata->version == BSPVERSION) {
const bsp29_t *bsp = &bspdata->data.bsp29;
const lumpspec_t *lumpspec = lumpspec_bsp29;
if (bsp->texdatasize)
numtextures = bsp->dtexdata.header->nummiptex;
logprint("%7i %-12s\n", bsp->nummodels, "models");
PrintLumpSize(lumpspec, LUMP_PLANES, bsp->numplanes);
PrintLumpSize(lumpspec, LUMP_VERTEXES, bsp->numvertexes);
PrintLumpSize(lumpspec, LUMP_NODES, bsp->numnodes);
PrintLumpSize(lumpspec, LUMP_TEXINFO, bsp->numtexinfo);
PrintLumpSize(lumpspec, LUMP_FACES, bsp->numfaces);
PrintLumpSize(lumpspec, LUMP_CLIPNODES, bsp->numclipnodes);
PrintLumpSize(lumpspec, LUMP_LEAFS, bsp->numleafs);
PrintLumpSize(lumpspec, LUMP_MARKSURFACES, bsp->nummarksurfaces);
PrintLumpSize(lumpspec, LUMP_EDGES, bsp->numedges);
PrintLumpSize(lumpspec, 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);
}
if (bspdata->version == BSP2RMQVERSION) {
const bsp2rmq_t *bsp = &bspdata->data.bsp2rmq;
const lumpspec_t *lumpspec = lumpspec_bsp2rmq;
if (bsp->texdatasize)
numtextures = bsp->dtexdata.header->nummiptex;
logprint("%7i %-12s\n", bsp->nummodels, "models");
PrintLumpSize(lumpspec, LUMP_PLANES, bsp->numplanes);
PrintLumpSize(lumpspec, LUMP_VERTEXES, bsp->numvertexes);
PrintLumpSize(lumpspec, LUMP_NODES, bsp->numnodes);
PrintLumpSize(lumpspec, LUMP_TEXINFO, bsp->numtexinfo);
PrintLumpSize(lumpspec, LUMP_FACES, bsp->numfaces);
PrintLumpSize(lumpspec, LUMP_CLIPNODES, bsp->numclipnodes);
PrintLumpSize(lumpspec, LUMP_LEAFS, bsp->numleafs);
PrintLumpSize(lumpspec, LUMP_MARKSURFACES, bsp->nummarksurfaces);
PrintLumpSize(lumpspec, LUMP_EDGES, bsp->numedges);
PrintLumpSize(lumpspec, 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);
}
if (bspdata->version == BSP2VERSION) {
const bsp2_t *bsp = &bspdata->data.bsp2;
const lumpspec_t *lumpspec = lumpspec_bsp2;
if (bsp->texdatasize)
numtextures = bsp->dtexdata.header->nummiptex;
logprint("%7i %-12s\n", bsp->nummodels, "models");
PrintLumpSize(lumpspec, LUMP_PLANES, bsp->numplanes);
PrintLumpSize(lumpspec, LUMP_VERTEXES, bsp->numvertexes);
PrintLumpSize(lumpspec, LUMP_NODES, bsp->numnodes);
PrintLumpSize(lumpspec, LUMP_TEXINFO, bsp->numtexinfo);
PrintLumpSize(lumpspec, LUMP_FACES, bsp->numfaces);
PrintLumpSize(lumpspec, LUMP_CLIPNODES, bsp->numclipnodes);
PrintLumpSize(lumpspec, LUMP_LEAFS, bsp->numleafs);
PrintLumpSize(lumpspec, LUMP_MARKSURFACES, bsp->nummarksurfaces);
PrintLumpSize(lumpspec, LUMP_EDGES, bsp->numedges);
PrintLumpSize(lumpspec, 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);
}
if (bspdata->bspxentries)
{
bspxentry_t *x;
for (x = bspdata->bspxentries; x; x = x->next) {
logprint("%7s %-12s %10i\n", "BSPX", x->lumpname, (int)x->lumpsize);
}
}
}