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 on only one side, the
2002-09-23 16:27:17 +00:00
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 written out only 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)
{
// commanded to create only a single hull
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);
}