quakeforge/tools/qfbsp/source/readbsp.c

481 lines
13 KiB
C

/*
#FILENAME#
#DESCRIPTION#
Copyright (C) 2003 #AUTHOR#
Author: #AUTHOR#
Date: #DATE#
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static __attribute__ ((used)) const char rcsid[] =
"$Id$";
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include "QF/dstring.h"
#include "QF/qendian.h"
#include "QF/quakefs.h"
#include "QF/sys.h"
#include "QF/va.h"
#include "QF/wad.h"
#include "brush.h"
#include "bsp5.h"
#include "options.h"
#include "portals.h"
#include "readbsp.h"
#include "winding.h"
dmodel_t *models;
face_t *mfaces;
node_t *nodes;
node_t *leafs;
texinfo_t *texinfo;
dvertex_t *vertices;
dedge_t *edges;
int *surfedges;
unsigned short *marksurfaces;
static brushset_t bs;
static void
load_texinfo (void)
{
texinfo = bsp->texinfo;
}
static void
load_entities (void)
{
}
static void
load_clipnodes (void)
{
}
static void
load_surfedges (void)
{
surfedges = bsp->surfedges;
}
static void
load_edges (void)
{
edges = bsp->edges;
}
static void
load_planes (void)
{
dplane_t *p;
int i;
memset (planes, 0, sizeof (planes));
for (i = 0; i < bsp->numplanes; i++) {
p = bsp->planes + i;
VectorCopy (p->normal, planes[i].normal);
planes[i].dist = p->dist;
planes[i].type = p->type;
}
numbrushplanes = bsp->numplanes;
}
static void
load_marksurfaces (void)
{
marksurfaces = bsp->marksurfaces;
}
static void
load_faces (void)
{
dface_t *f;
int i, j;
winding_t *points;
mfaces = calloc (bsp->numfaces, sizeof (face_t));
for (i = 0; i < bsp->numfaces; i++) {
f = bsp->faces + i;
mfaces[i].planenum = f->planenum;
mfaces[i].planeside = f->side;
mfaces[i].texturenum = f->texinfo;
mfaces[i].points = NewWinding (f->numedges);
mfaces[i].edges = surfedges + f->firstedge;
points = mfaces[i].points;
points->numpoints = f->numedges;
for (j = 0; j < points->numpoints; j++) {
int e = mfaces[i].edges[j];
int v;
if (e < 0) {
v = edges[-e].v[1];
} else {
v = edges[e].v[0];
}
VectorCopy (vertices[v].point, points->points[j]);
}
}
}
static void
load_vertices (void)
{
vertices = bsp->vertexes;
}
static void
load_leafs (void)
{
dleaf_t *l;
int i, j;
leafs = calloc (bsp->numleafs, sizeof (node_t));
for (i = 0; i < bsp->numleafs; i++) {
l = bsp->leafs + i;
leafs[i].planenum = -1;
leafs[i].contents = l->contents;
VectorCopy (l->mins, leafs[i].mins);
VectorCopy (l->maxs, leafs[i].maxs);
leafs[i].markfaces = calloc (l->nummarksurfaces + 1,
sizeof (face_t *));
for (j = 0; j < l->nummarksurfaces; j++) {
unsigned short ms = l->firstmarksurface + j;
leafs[i].markfaces[j] = mfaces + marksurfaces[ms];
}
}
}
static void
load_nodes (void)
{
dnode_t *n;
face_t *f;
int i, j;
nodes = calloc (bsp->numnodes, sizeof (node_t));
for (i = 0; i < bsp->numnodes; i++) {
n = bsp->nodes + i;
VectorCopy (n->mins, nodes[i].mins);
VectorCopy (n->maxs, nodes[i].maxs);
nodes[i].planenum = n->planenum;
nodes[i].firstface = n->firstface;
nodes[i].numfaces = n->numfaces;
for (j = 0; j < 2; j++) {
if (n->children[j] < 0) {
nodes[i].children[j] = leafs - n->children[j] - 1;
} else {
nodes[i].children[j] = nodes + n->children[j];
}
}
if (nodes[i].numfaces) {
nodes[i].faces = mfaces + nodes[i].firstface;
for (j = 0, f = nodes[i].faces; j < n->numfaces - 1; j++, f++) {
f->next = f + 1;
}
}
}
}
static void
load_models (void)
{
}
static void
load_textures (void)
{
}
void
LoadBSP (void)
{
QFile *f;
f = Qopen (options.bspfile, "rbz");
if (!f)
Sys_Error ("couldn't open %s. %s", options.bspfile, strerror(errno));
bsp = LoadBSPFile (f, Qfilesize (f));
Qclose (f);
load_texinfo ();
load_entities ();
load_clipnodes ();
load_surfedges ();
load_edges ();
load_planes ();
load_marksurfaces ();
load_vertices ();
load_faces ();
load_leafs ();
load_nodes ();
load_models ();
load_textures ();
}
static char *
output_file (const char *ext)
{
char *name;
if (options.output_file) {
if (strcmp (options.output_file, "-") == 0)
return options.output_file;
name = malloc (strlen (options.output_file) + strlen (ext) + 1);
strcpy (name, options.output_file);
QFS_DefaultExtension (name, ext);
} else {
name = malloc (strlen (options.bspfile) + strlen (ext) + 1);
QFS_StripExtension (options.bspfile, name);
if (strcmp (QFS_FileExtension (options.bspfile), ".gz") == 0) {
QFS_StripExtension (name, name);
}
strcat (name, ext);
}
return name;
}
void
bsp2prt (void)
{
vec3_t ooo = {1, 1, 1};
options.portfile = output_file (".prt");
VectorSubtract (bsp->models[0].mins, ooo, bs.mins);
VectorAdd (bsp->models[0].maxs, ooo, bs.maxs);
brushset = &bs;
PortalizeWorld (nodes);
WritePortalfile (nodes);
}
static byte default_palette[] = {
0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x1F, 0x1F, 0x1F, 0x2F, 0x2F, 0x2F,
0x3F, 0x3F, 0x3F, 0x4B, 0x4B, 0x4B, 0x5B, 0x5B, 0x5B, 0x6B, 0x6B, 0x6B,
0x7B, 0x7B, 0x7B, 0x8B, 0x8B, 0x8B, 0x9B, 0x9B, 0x9B, 0xAB, 0xAB, 0xAB,
0xBB, 0xBB, 0xBB, 0xCB, 0xCB, 0xCB, 0xDB, 0xDB, 0xDB, 0xEB, 0xEB, 0xEB,
0x0F, 0x0B, 0x07, 0x17, 0x0F, 0x0B, 0x1F, 0x17, 0x0B, 0x27, 0x1B, 0x0F,
0x2F, 0x23, 0x13, 0x37, 0x2B, 0x17, 0x3F, 0x2F, 0x17, 0x4B, 0x37, 0x1B,
0x53, 0x3B, 0x1B, 0x5B, 0x43, 0x1F, 0x63, 0x4B, 0x1F, 0x6B, 0x53, 0x1F,
0x73, 0x57, 0x1F, 0x7B, 0x5F, 0x23, 0x83, 0x67, 0x23, 0x8F, 0x6F, 0x23,
0x0B, 0x0B, 0x0F, 0x13, 0x13, 0x1B, 0x1B, 0x1B, 0x27, 0x27, 0x27, 0x33,
0x2F, 0x2F, 0x3F, 0x37, 0x37, 0x4B, 0x3F, 0x3F, 0x57, 0x47, 0x47, 0x67,
0x4F, 0x4F, 0x73, 0x5B, 0x5B, 0x7F, 0x63, 0x63, 0x8B, 0x6B, 0x6B, 0x97,
0x73, 0x73, 0xA3, 0x7B, 0x7B, 0xAF, 0x83, 0x83, 0xBB, 0x8B, 0x8B, 0xCB,
0x00, 0x00, 0x00, 0x07, 0x07, 0x00, 0x0B, 0x0B, 0x00, 0x13, 0x13, 0x00,
0x1B, 0x1B, 0x00, 0x23, 0x23, 0x00, 0x2B, 0x2B, 0x07, 0x2F, 0x2F, 0x07,
0x37, 0x37, 0x07, 0x3F, 0x3F, 0x07, 0x47, 0x47, 0x07, 0x4B, 0x4B, 0x0B,
0x53, 0x53, 0x0B, 0x5B, 0x5B, 0x0B, 0x63, 0x63, 0x0B, 0x6B, 0x6B, 0x0F,
0x07, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x17, 0x00, 0x00, 0x1F, 0x00, 0x00,
0x27, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x37, 0x00, 0x00, 0x3F, 0x00, 0x00,
0x47, 0x00, 0x00, 0x4F, 0x00, 0x00, 0x57, 0x00, 0x00, 0x5F, 0x00, 0x00,
0x67, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x77, 0x00, 0x00, 0x7F, 0x00, 0x00,
0x13, 0x13, 0x00, 0x1B, 0x1B, 0x00, 0x23, 0x23, 0x00, 0x2F, 0x2B, 0x00,
0x37, 0x2F, 0x00, 0x43, 0x37, 0x00, 0x4B, 0x3B, 0x07, 0x57, 0x43, 0x07,
0x5F, 0x47, 0x07, 0x6B, 0x4B, 0x0B, 0x77, 0x53, 0x0F, 0x83, 0x57, 0x13,
0x8B, 0x5B, 0x13, 0x97, 0x5F, 0x1B, 0xA3, 0x63, 0x1F, 0xAF, 0x67, 0x23,
0x23, 0x13, 0x07, 0x2F, 0x17, 0x0B, 0x3B, 0x1F, 0x0F, 0x4B, 0x23, 0x13,
0x57, 0x2B, 0x17, 0x63, 0x2F, 0x1F, 0x73, 0x37, 0x23, 0x7F, 0x3B, 0x2B,
0x8F, 0x43, 0x33, 0x9F, 0x4F, 0x33, 0xAF, 0x63, 0x2F, 0xBF, 0x77, 0x2F,
0xCF, 0x8F, 0x2B, 0xDF, 0xAB, 0x27, 0xEF, 0xCB, 0x1F, 0xFF, 0xF3, 0x1B,
0x0B, 0x07, 0x00, 0x1B, 0x13, 0x00, 0x2B, 0x23, 0x0F, 0x37, 0x2B, 0x13,
0x47, 0x33, 0x1B, 0x53, 0x37, 0x23, 0x63, 0x3F, 0x2B, 0x6F, 0x47, 0x33,
0x7F, 0x53, 0x3F, 0x8B, 0x5F, 0x47, 0x9B, 0x6B, 0x53, 0xA7, 0x7B, 0x5F,
0xB7, 0x87, 0x6B, 0xC3, 0x93, 0x7B, 0xD3, 0xA3, 0x8B, 0xE3, 0xB3, 0x97,
0xAB, 0x8B, 0xA3, 0x9F, 0x7F, 0x97, 0x93, 0x73, 0x87, 0x8B, 0x67, 0x7B,
0x7F, 0x5B, 0x6F, 0x77, 0x53, 0x63, 0x6B, 0x4B, 0x57, 0x5F, 0x3F, 0x4B,
0x57, 0x37, 0x43, 0x4B, 0x2F, 0x37, 0x43, 0x27, 0x2F, 0x37, 0x1F, 0x23,
0x2B, 0x17, 0x1B, 0x23, 0x13, 0x13, 0x17, 0x0B, 0x0B, 0x0F, 0x07, 0x07,
0xBB, 0x73, 0x9F, 0xAF, 0x6B, 0x8F, 0xA3, 0x5F, 0x83, 0x97, 0x57, 0x77,
0x8B, 0x4F, 0x6B, 0x7F, 0x4B, 0x5F, 0x73, 0x43, 0x53, 0x6B, 0x3B, 0x4B,
0x5F, 0x33, 0x3F, 0x53, 0x2B, 0x37, 0x47, 0x23, 0x2B, 0x3B, 0x1F, 0x23,
0x2F, 0x17, 0x1B, 0x23, 0x13, 0x13, 0x17, 0x0B, 0x0B, 0x0F, 0x07, 0x07,
0xDB, 0xC3, 0xBB, 0xCB, 0xB3, 0xA7, 0xBF, 0xA3, 0x9B, 0xAF, 0x97, 0x8B,
0xA3, 0x87, 0x7B, 0x97, 0x7B, 0x6F, 0x87, 0x6F, 0x5F, 0x7B, 0x63, 0x53,
0x6B, 0x57, 0x47, 0x5F, 0x4B, 0x3B, 0x53, 0x3F, 0x33, 0x43, 0x33, 0x27,
0x37, 0x2B, 0x1F, 0x27, 0x1F, 0x17, 0x1B, 0x13, 0x0F, 0x0F, 0x0B, 0x07,
0x6F, 0x83, 0x7B, 0x67, 0x7B, 0x6F, 0x5F, 0x73, 0x67, 0x57, 0x6B, 0x5F,
0x4F, 0x63, 0x57, 0x47, 0x5B, 0x4F, 0x3F, 0x53, 0x47, 0x37, 0x4B, 0x3F,
0x2F, 0x43, 0x37, 0x2B, 0x3B, 0x2F, 0x23, 0x33, 0x27, 0x1F, 0x2B, 0x1F,
0x17, 0x23, 0x17, 0x0F, 0x1B, 0x13, 0x0B, 0x13, 0x0B, 0x07, 0x0B, 0x07,
0xFF, 0xF3, 0x1B, 0xEF, 0xDF, 0x17, 0xDB, 0xCB, 0x13, 0xCB, 0xB7, 0x0F,
0xBB, 0xA7, 0x0F, 0xAB, 0x97, 0x0B, 0x9B, 0x83, 0x07, 0x8B, 0x73, 0x07,
0x7B, 0x63, 0x07, 0x6B, 0x53, 0x00, 0x5B, 0x47, 0x00, 0x4B, 0x37, 0x00,
0x3B, 0x2B, 0x00, 0x2B, 0x1F, 0x00, 0x1B, 0x0F, 0x00, 0x0B, 0x07, 0x00,
0x00, 0x00, 0xFF, 0x0B, 0x0B, 0xEF, 0x13, 0x13, 0xDF, 0x1B, 0x1B, 0xCF,
0x23, 0x23, 0xBF, 0x2B, 0x2B, 0xAF, 0x2F, 0x2F, 0x9F, 0x2F, 0x2F, 0x8F,
0x2F, 0x2F, 0x7F, 0x2F, 0x2F, 0x6F, 0x2F, 0x2F, 0x5F, 0x2B, 0x2B, 0x4F,
0x23, 0x23, 0x3F, 0x1B, 0x1B, 0x2F, 0x13, 0x13, 0x1F, 0x0B, 0x0B, 0x0F,
0x2B, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x4B, 0x07, 0x00, 0x5F, 0x07, 0x00,
0x6F, 0x0F, 0x00, 0x7F, 0x17, 0x07, 0x93, 0x1F, 0x07, 0xA3, 0x27, 0x0B,
0xB7, 0x33, 0x0F, 0xC3, 0x4B, 0x1B, 0xCF, 0x63, 0x2B, 0xDB, 0x7F, 0x3B,
0xE3, 0x97, 0x4F, 0xE7, 0xAB, 0x5F, 0xEF, 0xBF, 0x77, 0xF7, 0xD3, 0x8B,
0xA7, 0x7B, 0x3B, 0xB7, 0x9B, 0x37, 0xC7, 0xC3, 0x37, 0xE7, 0xE3, 0x57,
0x7F, 0xBF, 0xFF, 0xAB, 0xE7, 0xFF, 0xD7, 0xFF, 0xFF, 0x67, 0x00, 0x00,
0x8B, 0x00, 0x00, 0xB3, 0x00, 0x00, 0xD7, 0x00, 0x00, 0xFF, 0x00, 0x00,
0xFF, 0xF3, 0x93, 0xFF, 0xF7, 0xC7, 0xFF, 0xFF, 0xFF, 0x9F, 0x5B, 0x53,
};
static const char *
unique_name (wad_t *wad, const char *name)
{
char uname[16];
int i = 0;
const char *tag;
if (!wad_find_lump (wad, name))
return name;
do {
strncpy (uname, name, 16);
uname[15] = 0;
tag = va ("~%x", i++);
if (strlen (uname) + strlen (tag) <= 15)
strcat (uname, tag);
else
strcpy (uname + 15 - strlen (tag), tag);
} while (wad_find_lump (wad, uname));
return va ("%s", uname); // just to make a safe returnable that doesn't
// need to be freed
}
void
extract_textures (void)
{
dmiptexlump_t *miptexlump = (dmiptexlump_t *) bsp->texdata;
miptex_t *miptex;
int i, mtsize, pixels;
char *wadfile;
wad_t *wad;
const char *uname;
wadfile = output_file (".wad");
wad = wad_create (wadfile);
wad_add_data (wad, "PALETTE", TYP_PALETTE, default_palette,
sizeof (default_palette));
for (i = 0; i < miptexlump->nummiptex; i++) {
if (miptexlump->dataofs[i] == -1)
continue;
miptex = (miptex_t *)(bsp->texdata + miptexlump->dataofs[i]);
pixels = miptex->width * miptex->height / 64 * 85;
mtsize = sizeof (miptex_t) + pixels;
uname = unique_name (wad, miptex->name);
#if 1
printf ("%3d %6d ", i, miptexlump->dataofs[i]);
printf ("%16.16s %16.16s %3dx%-3d %d %d %d %d %d %d\n",
miptex->name, uname, miptex->width,
miptex->height, miptex->offsets[0], miptex->offsets[1],
miptex->offsets[2], miptex->offsets[3], pixels, mtsize);
#endif
wad_add_data (wad, uname, TYP_MIPTEX, miptex, mtsize);
}
wad_close (wad);
}
void
extract_entities (void)
{
char *entfile;
int i;
QFile *ef;
entfile = output_file (".ent");
for (i = bsp->entdatasize; i > 0; i--)
if (bsp->entdata[i - 1])
break;
if (strcmp (entfile, "-") == 0)
ef = Qdopen (1, "wt");
else
ef = Qopen (entfile, "wt");
Qwrite (ef, bsp->entdata, i);
Qclose (ef);
}
void
extract_hull (void)
{
// hullfile = output_file (".c");
char *hullfile;
int i, j;
QFile *hf;
hullfile = output_file (".c");
if (strcmp (hullfile, "-") == 0)
hf = Qdopen (1, "wt");
else
hf = Qopen (hullfile, "wt");
printf ("%d\n", bsp->nummodels);
for (i = 0; i < bsp->nummodels; i++) {
dmodel_t *m = bsp->models + i;
printf ("mins: (%g, %g, %g)\n", m->mins[0], m->mins[1], m->mins[2]);
printf ("maxs: (%g, %g, %g)\n", m->maxs[0], m->maxs[1], m->maxs[2]);
printf ("origin: (%g, %g, %g)\n",
m->origin[0], m->origin[1], m->origin[2]);
for (j = 0; j < MAX_MAP_HULLS; j++)
printf ("headnodes[%d]: %d\n", j, m->headnode[j]);
printf ("visleafs: %d\n", m->visleafs);
printf ("firstface: %d\n", m->firstface);
printf ("numfaces: %d\n", m->numfaces);
printf ("\n");
}
Qprintf (hf, "dclipnode_t clipnodes[] = {\n");
for (i = 0; i < bsp->numnodes; i++) {
int c0, c1;
c0 = bsp->nodes[i].children[0];
c1 = bsp->nodes[i].children[1];
if (c0 < 0)
c0 = bsp->leafs[-1 - c0].contents;
if (c1 < 0)
c1 = bsp->leafs[-1 - c1].contents;
Qprintf (hf, "\t{%d, {%d, %d}},\t// %d\n", bsp->nodes[i].planenum,
c0, c1, i);
}
Qprintf (hf, "};\n");
Qprintf (hf, "mplane_t planes[] = {\n");
for (i = 0; i < bsp->numplanes; i++) {
Qprintf (hf, "\t{{%g, %g, %g}, %g, %d, 0, {0, 0}},\t// %d\n",
bsp->planes[i].normal[0], bsp->planes[i].normal[1],
bsp->planes[i].normal[2],
bsp->planes[i].dist, bsp->planes[i].type,
i);
}
Qprintf (hf, "};\n");
}