quakeforge/tools/qfbsp/source/qfbsp.c

836 lines
17 KiB
C
Raw Normal View History

2002-09-19 18:51:19 +00:00
/*
Copyright (C) 1996-1997 Id Software, Inc.
2002-09-19 18:51:19 +00:00
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.
2002-09-19 18:51:19 +00:00
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.
2002-09-19 18:51:19 +00:00
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
2002-09-19 18:51:19 +00:00
See file, 'COPYING', for details.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static __attribute__ ((used)) const char rcsid[] =
"$Id$";
2002-11-08 17:36:47 +00:00
#include <sys/types.h>
#ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#include <stdlib.h>
2003-08-11 17:11:44 +00:00
#include <errno.h>
#include "QF/quakefs.h"
#include "QF/sys.h"
#include "bsp5.h"
2002-09-20 21:48:34 +00:00
#include "options.h"
2002-09-20 21:48:34 +00:00
options_t options;
2002-09-20 21:48:34 +00:00
bsp_t *bsp;
2002-09-19 17:14:23 +00:00
brushset_t *brushset;
2002-09-23 16:27:17 +00:00
int c_activefaces, c_peakfaces;
int c_activesurfaces, c_peaksurfaces;
int c_activewindings, c_peakwindings;
int c_activeportals, c_peakportals;
2002-09-19 17:14:23 +00:00
int valid;
2002-09-19 17:14:23 +00:00
char *argv0; // changed after fork();
2002-09-19 17:14:23 +00:00
qboolean worldmodel;
2002-09-19 17:14:23 +00:00
int hullnum;
2002-09-23 16:27:17 +00:00
winding_t *
2002-09-19 17:14:23 +00:00
BaseWindingForPlane (plane_t *p)
{
2002-09-19 17:14:23 +00:00
int i, x;
vec_t max, v;
vec3_t org, vright, vup;
winding_t *w;
2002-09-23 16:27:17 +00:00
// find the major axis
max = -BOGUS_RANGE;
x = -1;
2002-09-19 17:14:23 +00:00
for (i = 0; i < 3; i++) {
v = fabs (p->normal[i]);
if (v > max) {
x = i;
max = v;
}
}
2002-09-19 17:14:23 +00:00
if (x == -1)
Sys_Error ("BaseWindingForPlane: no axis found");
2002-09-19 17:14:23 +00:00
VectorZero (vup);
2002-09-19 17:14:23 +00:00
switch (x) {
case 0:
case 1:
vup[2] = 1;
break;
case 2:
vup[0] = 1;
break;
}
v = DotProduct (vup, p->normal);
VectorMultSub (vup, v, p->normal, vup);
_VectorNormalize (vup);
2002-09-19 17:14:23 +00:00
VectorScale (p->normal, p->dist, org);
2002-09-19 17:14:23 +00:00
CrossProduct (vup, p->normal, vright);
2002-09-19 17:14:23 +00:00
VectorScale (vup, BOGUS_RANGE, vup);
VectorScale (vright, BOGUS_RANGE, vright);
2002-09-23 16:27:17 +00:00
// project a really big axis aligned box onto the plane
w = NewWinding (4);
2002-09-19 17:14:23 +00:00
VectorSubtract (org, vright, w->points[0]);
VectorAdd (w->points[0], vup, w->points[0]);
2002-09-19 17:14:23 +00:00
VectorAdd (org, vright, w->points[1]);
VectorAdd (w->points[1], vup, w->points[1]);
2002-09-19 17:14:23 +00:00
VectorAdd (org, vright, w->points[2]);
VectorSubtract (w->points[2], vup, w->points[2]);
2002-09-19 17:14:23 +00:00
VectorSubtract (org, vright, w->points[3]);
VectorSubtract (w->points[3], vup, w->points[3]);
2002-09-19 17:14:23 +00:00
w->numpoints = 4;
2002-09-19 17:14:23 +00:00
return w;
}
2002-09-23 16:27:17 +00:00
winding_t *
2002-09-19 18:51:19 +00:00
CopyWinding (winding_t *w)
{
2007-04-04 07:48:14 +00:00
size_t size;
2002-09-19 17:14:23 +00:00
winding_t *c;
2007-04-04 07:48:14 +00:00
size = (size_t) (uintptr_t) &((winding_t *) 0)->points[w->numpoints];
c = malloc (size);
memcpy (c, w, size);
return c;
}
2003-09-08 03:00:53 +00:00
winding_t *
CopyWindingReverse (winding_t *w)
{
2007-04-04 07:48:14 +00:00
int i;
size_t size;
2003-09-08 03:00:53 +00:00
winding_t *c;
2007-04-04 07:48:14 +00:00
size = (size_t) (uintptr_t) &((winding_t *) 0)->points[w->numpoints];
2003-09-08 03:00:53 +00:00
c = malloc (size);
c->numpoints = w->numpoints;
for (i = 0; i < w->numpoints; i++) {
// add points backwards
VectorCopy (w->points[w->numpoints - 1 - i], c->points[i]);
}
return c;
}
/*
2002-09-23 16:27:17 +00:00
ClipWinding
Clips the winding to the plane, returning the new winding on the positive
side.
Frees the input winding.
If keepon is true, an exactly on-plane winding will be saved, otherwise
it will be clipped away.
*/
2002-09-23 16:27:17 +00:00
winding_t *
2002-09-19 18:51:19 +00:00
ClipWinding (winding_t *in, plane_t *split, qboolean keepon)
{
2002-09-19 18:51:19 +00:00
int maxpts, i, j;
2003-09-08 03:25:01 +00:00
int *sides;
2002-09-19 17:14:23 +00:00
int counts[3];
vec_t dot;
2003-09-08 03:25:01 +00:00
vec_t *dists;
2002-09-19 17:14:23 +00:00
vec_t *p1, *p2;
vec3_t mid;
winding_t *neww;
counts[0] = counts[1] = counts[2] = 0;
2003-09-08 03:25:01 +00:00
sides = alloca ((in->numpoints + 1) * sizeof (int));
dists = alloca ((in->numpoints + 1) * sizeof (vec_t));
2002-09-23 16:27:17 +00:00
// determine sides for each point
2002-09-19 17:14:23 +00:00
for (i = 0; i < in->numpoints; i++) {
dot = DotProduct (in->points[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;
2002-09-19 17:14:23 +00:00
else {
sides[i] = SIDE_ON;
}
counts[sides[i]]++;
}
sides[i] = sides[0];
dists[i] = dists[0];
2002-09-19 17:14:23 +00:00
if (keepon && !counts[SIDE_FRONT] && !counts[SIDE_BACK])
return in;
2002-09-19 17:14:23 +00:00
if (!counts[SIDE_FRONT]) {
FreeWinding (in);
return NULL;
}
if (!counts[SIDE_BACK])
return in;
for (maxpts = 0, i = 0; i < in->numpoints; i++) {
if (!(sides[i] & 1))
maxpts++;
if ((sides[i] ^ 1) == sides[i + 1])
maxpts++;
}
neww = NewWinding (maxpts);
2002-09-19 17:14:23 +00:00
for (i = 0; i < in->numpoints; i++) {
p1 = in->points[i];
2002-09-19 17:14:23 +00:00
if (sides[i] == SIDE_ON) {
if (neww->numpoints == maxpts)
Sys_Error ("ClipWinding: points exceeded estimate");
VectorCopy (p1, neww->points[neww->numpoints]);
neww->numpoints++;
continue;
}
2002-09-19 17:14:23 +00:00
if (sides[i] == SIDE_FRONT) {
if (neww->numpoints == maxpts)
Sys_Error ("ClipWinding: points exceeded estimate");
VectorCopy (p1, neww->points[neww->numpoints]);
neww->numpoints++;
}
2002-09-19 17:14:23 +00:00
if (sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i])
continue;
2002-09-19 17:14:23 +00:00
if (neww->numpoints == maxpts)
Sys_Error ("ClipWinding: points exceeded estimate");
2002-09-19 17:14:23 +00:00
// generate a split point
p2 = in->points[(i + 1) % in->numpoints];
dot = dists[i] / (dists[i] - dists[i + 1]);
2002-09-19 18:51:19 +00:00
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
2002-09-19 17:14:23 +00:00
mid[j] = p1[j] + dot * (p2[j] - p1[j]);
}
2002-09-19 17:14:23 +00:00
VectorCopy (mid, neww->points[neww->numpoints]);
neww->numpoints++;
}
2002-09-19 17:14:23 +00:00
2002-09-23 16:27:17 +00:00
// free the original winding
FreeWinding (in);
2002-09-19 17:14:23 +00:00
return neww;
}
/*
2002-09-23 16:27:17 +00:00
DivideWinding
Divides a winding by a plane, producing one or two windings. The
original winding is not damaged or freed. If only on one side, the
returned winding will be the input winding. If on both sides, two
new windings will be created.
*/
2002-09-19 17:14:23 +00:00
void
2002-09-19 18:51:19 +00:00
DivideWinding (winding_t *in, plane_t *split, winding_t **front,
winding_t **back)
{
int i;
2002-09-19 17:14:23 +00:00
int counts[3];
2003-09-08 03:25:01 +00:00
plane_t plane;
2002-09-19 17:14:23 +00:00
vec_t dot;
2003-09-08 03:25:01 +00:00
winding_t *tmp;
2002-09-19 17:14:23 +00:00
counts[0] = counts[1] = counts[2] = 0;
2002-09-23 16:27:17 +00:00
// determine sides for each point
2002-09-19 17:14:23 +00:00
for (i = 0; i < in->numpoints; i++) {
2003-09-08 03:25:01 +00:00
dot = DotProduct (in->points[i], split->normal) - split->dist;
if (dot > ON_EPSILON)
2003-09-08 03:25:01 +00:00
counts[SIDE_FRONT]++;
else if (dot < -ON_EPSILON)
2003-09-08 03:25:01 +00:00
counts[SIDE_BACK]++;
}
2002-09-19 17:14:23 +00:00
*front = *back = NULL;
2003-09-08 03:25:01 +00:00
if (!counts[SIDE_FRONT]) {
*back = in;
return;
}
2003-09-08 03:25:01 +00:00
if (!counts[SIDE_BACK]) {
*front = in;
return;
}
2003-09-08 03:25:01 +00:00
tmp = CopyWinding (in);
*front = ClipWinding (tmp, split, 0);
2002-09-19 17:14:23 +00:00
2003-09-08 03:25:01 +00:00
plane.dist = -split->dist;
VectorNegate (split->normal, plane.normal);
2002-09-19 17:14:23 +00:00
2003-09-08 03:25:01 +00:00
tmp = CopyWinding (in);
*back = ClipWinding (tmp, &plane, 0);
}
2002-09-23 16:27:17 +00:00
winding_t *
2002-09-19 17:14:23 +00:00
NewWinding (int points)
{
2007-04-04 07:48:14 +00:00
size_t size;
2002-09-19 18:51:19 +00:00
winding_t *w;
2002-09-19 17:14:23 +00:00
2003-09-08 03:25:01 +00:00
if (points < 3)
Sys_Error ("NewWinding: %i points", points);
2002-09-19 17:14:23 +00:00
c_activewindings++;
if (c_activewindings > c_peakwindings)
c_peakwindings = c_activewindings;
2007-04-04 07:48:14 +00:00
size = (size_t) (uintptr_t) &((winding_t *) 0)->points[points];
w = malloc (size);
memset (w, 0, size);
2002-09-19 17:14:23 +00:00
return w;
}
2002-09-19 17:14:23 +00:00
void
2002-09-19 18:51:19 +00:00
FreeWinding (winding_t *w)
{
c_activewindings--;
free (w);
}
2002-09-23 16:27:17 +00:00
face_t *
2002-09-19 17:14:23 +00:00
AllocFace (void)
{
2002-09-19 17:14:23 +00:00
face_t *f;
c_activefaces++;
if (c_activefaces > c_peakfaces)
c_peakfaces = c_activefaces;
2002-09-19 17:14:23 +00:00
f = malloc (sizeof (face_t));
memset (f, 0, sizeof (face_t));
f->planenum = -1;
return f;
}
2002-09-19 17:14:23 +00:00
void
2002-09-19 18:51:19 +00:00
FreeFace (face_t *f)
{
c_activefaces--;
free (f);
}
2002-09-23 16:27:17 +00:00
surface_t *
2002-09-19 17:14:23 +00:00
AllocSurface (void)
{
2002-09-19 17:14:23 +00:00
surface_t *s;
s = malloc (sizeof (surface_t));
memset (s, 0, sizeof (surface_t));
c_activesurfaces++;
if (c_activesurfaces > c_peaksurfaces)
c_peaksurfaces = c_activesurfaces;
2002-09-19 17:14:23 +00:00
return s;
}
2002-09-19 17:14:23 +00:00
void
2002-09-19 18:51:19 +00:00
FreeSurface (surface_t *s)
{
c_activesurfaces--;
free (s);
}
2002-09-23 16:27:17 +00:00
portal_t *
2002-09-19 17:14:23 +00:00
AllocPortal (void)
{
2002-09-19 17:14:23 +00:00
portal_t *p;
c_activeportals++;
if (c_activeportals > c_peakportals)
c_peakportals = c_activeportals;
2002-09-19 17:14:23 +00:00
p = malloc (sizeof (portal_t));
memset (p, 0, sizeof (portal_t));
return p;
}
2002-09-19 17:14:23 +00:00
void
2002-09-19 18:51:19 +00:00
FreePortal (portal_t *p)
{
c_activeportals--;
free (p);
}
2002-09-23 16:27:17 +00:00
node_t *
2002-09-19 17:14:23 +00:00
AllocNode (void)
{
2002-09-19 17:14:23 +00:00
node_t *n;
n = malloc (sizeof (node_t));
memset (n, 0, sizeof (node_t));
return n;
}
2002-09-23 16:27:17 +00:00
brush_t *
2002-09-19 17:14:23 +00:00
AllocBrush (void)
{
2002-09-19 17:14:23 +00:00
brush_t *b;
b = malloc (sizeof (brush_t));
memset (b, 0, sizeof (brush_t));
return b;
}
static void
2002-09-19 17:14:23 +00:00
ProcessEntity (int entnum)
{
2002-09-19 18:51:19 +00:00
brushset_t *bs;
2002-09-19 17:14:23 +00:00
char mod[80];
2002-09-19 18:51:19 +00:00
entity_t *ent;
2002-09-19 17:14:23 +00:00
surface_t *surfs;
node_t *nodes;
ent = &entities[entnum];
if (!ent->brushes)
2002-09-19 17:14:23 +00:00
return; // non-bmodel entity
2002-09-19 17:14:23 +00:00
if (entnum > 0) {
worldmodel = false;
if (entnum == 1)
qprintf ("--- Internal Entities ---\n");
sprintf (mod, "*%i", bsp->nummodels);
2002-09-20 21:48:34 +00:00
if (options.verbosity)
PrintEntity (ent);
if (hullnum == 0)
printf ("MODEL: %s\n", mod);
SetKeyValue (ent, "model", mod);
2002-09-19 17:14:23 +00:00
} else
worldmodel = true;
2002-09-19 17:14:23 +00:00
2002-09-23 16:27:17 +00:00
// take the brush_ts and clip off all overlapping and contained faces,
// leaving a perfect skin of the model with no hidden faces
bs = Brush_LoadEntity (ent, hullnum);
2002-09-19 17:14:23 +00:00
if (!bs->brushes) {
PrintEntity (ent);
Sys_Error ("Entity with no valid brushes");
}
2002-09-19 17:14:23 +00:00
brushset = bs;
surfs = CSGFaces (bs);
2002-09-19 17:14:23 +00:00
if (hullnum != 0) {
nodes = SolidBSP (surfs, true);
2002-09-20 21:48:34 +00:00
if (entnum == 0 && !options.nofill) {
// assume non-world bmodels are simple
PortalizeWorld (nodes);
2002-09-19 17:14:23 +00:00
if (FillOutside (nodes)) {
surfs = GatherNodeFaces (nodes);
2002-09-19 18:51:19 +00:00
nodes = SolidBSP (surfs, false); // make a really good tree
}
FreeAllPortals (nodes);
}
WriteNodePlanes (nodes);
WriteClipNodes (nodes);
BumpModel (hullnum);
2002-09-19 17:14:23 +00:00
} else {
// SolidBSP generates a node tree
//
// if not the world, make a good tree first
// the world is just going to make a bad tree
// because the outside filling will force a regeneration later
nodes = SolidBSP (surfs, entnum == 0);
// build all the portals in the bsp tree
// some portals are solid polygons, and some are paths to other leafs
2002-09-20 21:48:34 +00:00
if (entnum == 0 && !options.nofill) {
// assume non-world bmodels are simple
PortalizeWorld (nodes);
2002-09-19 17:14:23 +00:00
if (FillOutside (nodes)) {
FreeAllPortals (nodes);
2002-09-19 17:14:23 +00:00
// get the remaining faces together into surfaces again
surfs = GatherNodeFaces (nodes);
2002-09-19 17:14:23 +00:00
// merge polygons
MergeAll (surfs);
2002-09-19 17:14:23 +00:00
// make a really good tree
nodes = SolidBSP (surfs, false);
2002-09-19 17:14:23 +00:00
// make the real portals for vis tracing
PortalizeWorldDetail (nodes);
2002-09-19 17:14:23 +00:00
// save portal file for vis tracing
WritePortalfile (nodes);
2002-09-19 17:14:23 +00:00
// fix tjunctions
tjunc (nodes);
}
FreeAllPortals (nodes);
}
WriteNodePlanes (nodes);
MakeFaceEdges (nodes);
WriteDrawNodes (nodes);
}
}
static void
2002-09-19 17:14:23 +00:00
UpdateEntLump (void)
{
2002-09-19 17:14:23 +00:00
int m, entnum;
char mod[80];
QFile *f;
2002-09-19 17:14:23 +00:00
m = 1;
2002-09-19 17:14:23 +00:00
for (entnum = 1; entnum < num_entities; entnum++) {
if (!entities[entnum].brushes)
continue;
sprintf (mod, "*%i", m);
SetKeyValue (&entities[entnum], "model", mod);
m++;
}
printf ("Updating entities lump...\n");
2002-09-20 21:48:34 +00:00
f = Qopen (options.bspfile, "rb");
2003-08-11 17:11:44 +00:00
if (!f)
Sys_Error ("couldn't open %s. %s", options.bspfile, strerror(errno));
bsp = LoadBSPFile (f, Qfilesize (f));
Qclose (f);
2002-09-19 17:14:23 +00:00
WriteEntitiesToString ();
2002-09-20 21:48:34 +00:00
f = Qopen (options.bspfile, "wb");
2003-08-11 17:11:44 +00:00
if (!f)
Sys_Error ("couldn't open %s. %s", options.bspfile, strerror(errno));
2002-09-19 17:14:23 +00:00
WriteBSPFile (bsp, f);
Qclose (f);
}
/*
2002-09-23 16:27:17 +00:00
WriteClipHull
2002-09-23 16:27:17 +00:00
Write the clipping hull out to a text file so the parent process can get it
*/
static void
2002-09-19 17:14:23 +00:00
WriteClipHull (void)
{
2002-09-19 18:51:19 +00:00
FILE *f;
2002-09-19 17:14:23 +00:00
dclipnode_t *d;
2002-09-19 18:51:19 +00:00
dplane_t *p;
int i;
2002-09-20 21:48:34 +00:00
options.hullfile[strlen (options.hullfile) - 1] = '0' + hullnum;
qprintf ("---- WriteClipHull ----\n");
2002-09-20 21:48:34 +00:00
qprintf ("Writing %s\n", options.hullfile);
2002-09-20 21:48:34 +00:00
f = fopen (options.hullfile, "w");
if (!f)
2002-09-20 21:48:34 +00:00
Sys_Error ("Couldn't open %s", options.hullfile);
fprintf (f, "%i\n", bsp->nummodels);
2002-09-19 17:14:23 +00:00
for (i = 0; i < bsp->nummodels; i++)
fprintf (f, "%i\n", bsp->models[i].headnode[hullnum]);
2002-09-19 17:14:23 +00:00
fprintf (f, "\n%i\n", bsp->numclipnodes);
2002-09-19 17:14:23 +00:00
for (i = 0; i < bsp->numclipnodes; i++) {
d = &bsp->clipnodes[i];
p = &bsp->planes[d->planenum];
// the node number is only written out for human readability
2002-09-19 17:14:23 +00:00
fprintf (f, "%5i : %f %f %f %f : %5i %5i\n", i, p->normal[0],
p->normal[1], p->normal[2], p->dist, d->children[0],
d->children[1]);
}
2002-09-19 17:14:23 +00:00
fclose (f);
}
/*
2002-09-23 16:27:17 +00:00
ReadClipHull
2002-09-23 16:27:17 +00:00
Read the files written out by the child processes
*/
static void
2002-09-19 17:14:23 +00:00
ReadClipHull (int hullnum)
{
2002-09-19 18:51:19 +00:00
FILE *f;
dclipnode_t d;
2002-09-19 18:51:19 +00:00
dplane_t p;
float f1, f2, f3, f4;
int firstclipnode, junk, c1, c2, i, j, n;
vec3_t norm;
2002-09-19 17:14:23 +00:00
2002-09-20 21:48:34 +00:00
options.hullfile[strlen (options.hullfile) - 1] = '0' + hullnum;
2002-09-20 21:48:34 +00:00
f = fopen (options.hullfile, "r");
if (!f)
2002-09-20 21:48:34 +00:00
Sys_Error ("Couldn't open %s", options.hullfile);
if (fscanf (f, "%d\n", &n) != 1)
2002-09-20 21:48:34 +00:00
Sys_Error ("Error parsing %s", options.hullfile);
if (n != bsp->nummodels)
2002-09-19 17:14:23 +00:00
Sys_Error ("ReadClipHull: hull had %i models, base had %i", n,
bsp->nummodels);
2002-09-19 17:14:23 +00:00
for (i = 0; i < n; i++) {
2007-01-06 21:31:03 +00:00
if (fscanf (f, "%d\n", &j) != 1)
Sys_Error ("Error parsing %s", options.hullfile);
bsp->models[i].headnode[hullnum] = bsp->numclipnodes + j;
}
2002-09-19 17:14:23 +00:00
2007-01-06 21:31:03 +00:00
if (fscanf (f, "\n%d\n", &n) != 1)
Sys_Error ("Error parsing %s", options.hullfile);
firstclipnode = bsp->numclipnodes;
2002-09-19 17:14:23 +00:00
for (i = 0; i < n; i++) {
if (bsp->numclipnodes == MAX_MAP_CLIPNODES)
Sys_Error ("ReadClipHull: MAX_MAP_CLIPNODES");
if (fscanf (f, "%d : %f %f %f %f : %d %d\n", &junk, &f1, &f2, &f3, &f4,
2002-09-19 18:51:19 +00:00
&c1, &c2) != 7)
2002-09-20 21:48:34 +00:00
Sys_Error ("Error parsing %s", options.hullfile);
2002-09-19 17:14:23 +00:00
p.normal[0] = f1;
p.normal[1] = f2;
p.normal[2] = f3;
p.dist = f4;
2002-09-19 17:14:23 +00:00
norm[0] = f1;
norm[1] = f2;
norm[2] = f3; // vec_t precision
p.type = PlaneTypeForNormal (norm);
2002-09-19 17:14:23 +00:00
d.children[0] = c1 >= 0 ? c1 + firstclipnode : c1;
d.children[1] = c2 >= 0 ? c2 + firstclipnode : c2;
d.planenum = FindFinalPlane (&p);
BSP_AddClipnode (bsp, &d);
}
2002-09-19 17:14:23 +00:00
}
static void
2002-09-19 17:14:23 +00:00
CreateSingleHull (void)
{
2002-09-19 17:14:23 +00:00
int entnum;
2002-09-23 16:27:17 +00:00
// for each entity in the map file that has geometry
2002-09-19 17:14:23 +00:00
for (entnum = 0; entnum < num_entities; entnum++) {
ProcessEntity (entnum);
2002-09-20 21:48:34 +00:00
if (options.verbosity < 2)
options.verbosity = 0; // don't print rest of entities
}
if (hullnum)
WriteClipHull ();
}
static void
2002-09-19 17:14:23 +00:00
CreateHulls (void)
{
2002-09-23 16:27:17 +00:00
// commanded to create a single hull only
2002-09-19 17:14:23 +00:00
if (hullnum) {
CreateSingleHull ();
exit (0);
}
2002-09-23 16:27:17 +00:00
// commanded to use the allready existing hulls 1 and 2
2002-09-20 21:48:34 +00:00
if (options.usehulls) {
CreateSingleHull ();
return;
}
2002-09-23 16:27:17 +00:00
// commanded to ignore the hulls altogether
2002-09-20 21:48:34 +00:00
if (options.noclip) {
CreateSingleHull ();
return;
}
2002-09-23 16:27:17 +00:00
// create all the hulls
#ifdef __alpha
printf ("forking hull processes...\n");
2002-09-23 16:27:17 +00:00
// fork a process for each clipping hull
fflush (stdout);
2002-09-19 17:14:23 +00:00
if (!fork ()) {
hullnum = 1;
2002-09-20 21:48:34 +00:00
options.verbosity = 0;
2002-11-10 02:50:42 +00:00
options.drawflag = false;
sprintf (argv0, "HUL%i", hullnum);
2002-09-19 17:14:23 +00:00
} else if (!fork ()) {
hullnum = 2;
2002-09-20 21:48:34 +00:00
options.verbosity = 0;
2002-11-10 02:50:42 +00:00
options.drawflag = false;
sprintf (argv0, "HUL%i", hullnum);
}
CreateSingleHull ();
if (hullnum)
exit (0);
2002-09-19 17:14:23 +00:00
2002-09-19 18:51:19 +00:00
wait (NULL); // wait for clip hull process to finish
wait (NULL); // wait for clip hull process to finish
#else
2002-09-23 16:27:17 +00:00
// create the hulls sequentially
printf ("building hulls sequentially...\n");
hullnum = 1;
CreateSingleHull ();
2002-09-19 17:14:23 +00:00
bsp->nummodels = 0;
bsp->numplanes = 0;
bsp->numclipnodes = 0;
hullnum = 2;
CreateSingleHull ();
2002-09-19 17:14:23 +00:00
bsp->nummodels = 0;
bsp->numplanes = 0;
bsp->numclipnodes = 0;
hullnum = 0;
CreateSingleHull ();
2002-09-19 17:14:23 +00:00
#endif
}
static void
ProcessFile (void)
{
bsp = BSP_New ();
if (options.extract) {
LoadBSP ();
if (options.portal)
bsp2prt ();
if (options.extract_textures)
extract_textures ();
if (options.extract_entities)
extract_entities ();
if (options.extract_hull)
extract_hull ();
return;
}
// load brushes and entities
LoadMapFile (options.mapfile);
2002-09-20 21:48:34 +00:00
if (options.onlyents) {
UpdateEntLump ();
return;
}
remove (options.bspfile);
if (!options.usehulls) {
options.hullfile[strlen (options.hullfile) - 1] = '1';
remove (options.hullfile);
options.hullfile[strlen (options.hullfile) - 1] = '2';
remove (options.hullfile);
}
remove (options.portfile);
remove (options.pointfile);
2002-09-23 16:27:17 +00:00
// init the tables to be shared by all models
BeginBSPFile ();
2002-09-23 16:27:17 +00:00
// the clipping hulls will be written out to text files by forked processes
CreateHulls ();
ReadClipHull (1);
ReadClipHull (2);
2002-09-19 17:14:23 +00:00
WriteEntitiesToString ();
FinishBSPFile ();
}
2002-09-19 17:14:23 +00:00
int
main (int argc, char **argv)
{
2002-09-19 18:51:19 +00:00
double start, end;
2002-09-19 17:14:23 +00:00
2002-09-25 17:48:43 +00:00
// let forked processes change name for ps status
this_program = argv0 = argv[0];
2002-09-23 16:27:17 +00:00
// check command line flags
2002-09-20 21:48:34 +00:00
DecodeArgs (argc, argv);
2002-09-19 18:51:19 +00:00
// XXX SetQdirFromPath (argv[i]);
2002-09-23 16:27:17 +00:00
// do it!
start = Sys_DoubleTime ();
ProcessFile ();
end = Sys_DoubleTime ();
2002-09-19 17:14:23 +00:00
printf ("%5.1f seconds elapsed\n", end - start);
return 0;
}
2003-05-07 07:18:36 +00:00
void
qprintf (const char *fmt, ...)
{
va_list argptr;
if (!options.verbosity)
return;
va_start (argptr, fmt);
vprintf (fmt, argptr);
va_end (argptr);
}