1030 lines
18 KiB
C
1030 lines
18 KiB
C
// bsp5.c
|
|
|
|
#include "bsp5.h"
|
|
|
|
//
|
|
// command line flags
|
|
//
|
|
qboolean drawflag;
|
|
qboolean nofill;
|
|
qboolean notjunc;
|
|
qboolean noclip;
|
|
qboolean onlyents;
|
|
qboolean verbose = true;
|
|
qboolean allverbose;
|
|
qboolean usehulls;
|
|
|
|
int subdivide_size = 240;
|
|
|
|
brushset_t *brushset;
|
|
|
|
int valid;
|
|
|
|
char bspfilename[1024];
|
|
char pointfilename[1024];
|
|
char portfilename[1024];
|
|
char hullfilename[1024];
|
|
|
|
char *argv0; // changed after fork();
|
|
|
|
qboolean worldmodel;
|
|
|
|
int hullnum;
|
|
|
|
//===========================================================================
|
|
|
|
void qprintf (char *fmt, ...)
|
|
{
|
|
va_list argptr;
|
|
|
|
if (!verbose)
|
|
return;
|
|
|
|
va_start (argptr, fmt);
|
|
vprintf (fmt,argptr);
|
|
va_end (argptr);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
basewindingforplane
|
|
=================
|
|
*/
|
|
winding_t *basewindingforplane (plane_t *p)
|
|
{
|
|
int i, x;
|
|
vec_t max, v;
|
|
vec3_t org, vright, vup;
|
|
winding_t *w;
|
|
|
|
// find the major axis
|
|
|
|
max = -bogus_range;
|
|
x = -1;
|
|
for (i=0 ; i<3; i++)
|
|
{
|
|
v = fabs(p->normal[i]);
|
|
if (v > max)
|
|
{
|
|
x = i;
|
|
max = v;
|
|
}
|
|
}
|
|
if (x==-1)
|
|
error ("basewindingforplane: no axis found");
|
|
|
|
vectorcopy (vec3_origin, vup);
|
|
switch (x)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
vup[2] = 1;
|
|
break;
|
|
case 2:
|
|
vup[0] = 1;
|
|
break;
|
|
}
|
|
|
|
v = dotproduct (vup, p->normal);
|
|
vectorma (vup, -v, p->normal, vup);
|
|
vectornormalize (vup);
|
|
|
|
vectorscale (p->normal, p->dist, org);
|
|
|
|
crossproduct (vup, p->normal, vright);
|
|
|
|
vectorscale (vup, 8192, vup);
|
|
vectorscale (vright, 8192, vright);
|
|
|
|
// project a really big axis aligned box onto the plane
|
|
w = newwinding (4);
|
|
|
|
vectorsubtract (org, vright, w->points[0]);
|
|
vectoradd (w->points[0], vup, w->points[0]);
|
|
|
|
vectoradd (org, vright, w->points[1]);
|
|
vectoradd (w->points[1], vup, w->points[1]);
|
|
|
|
vectoradd (org, vright, w->points[2]);
|
|
vectorsubtract (w->points[2], vup, w->points[2]);
|
|
|
|
vectorsubtract (org, vright, w->points[3]);
|
|
vectorsubtract (w->points[3], vup, w->points[3]);
|
|
|
|
w->numpoints = 4;
|
|
|
|
return w;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
==================
|
|
copywinding
|
|
==================
|
|
*/
|
|
winding_t *copywinding (winding_t *w)
|
|
{
|
|
int size;
|
|
winding_t *c;
|
|
|
|
size = (int)((winding_t *)0)->points[w->numpoints];
|
|
c = malloc (size);
|
|
memcpy (c, w, size);
|
|
return c;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
==================
|
|
checkwinding
|
|
|
|
check for possible errors
|
|
==================
|
|
*/
|
|
void checkwinding (winding_t *w)
|
|
{
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
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.
|
|
==================
|
|
*/
|
|
winding_t *clipwinding (winding_t *in, plane_t *split, qboolean keepon)
|
|
{
|
|
vec_t dists[max_points_on_winding];
|
|
int sides[max_points_on_winding];
|
|
int counts[3];
|
|
vec_t dot;
|
|
int i, j;
|
|
vec_t *p1, *p2;
|
|
vec3_t mid;
|
|
winding_t *neww;
|
|
int maxpts;
|
|
|
|
counts[0] = counts[1] = counts[2] = 0;
|
|
|
|
// determine sides for each point
|
|
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;
|
|
else
|
|
{
|
|
sides[i] = side_on;
|
|
}
|
|
counts[sides[i]]++;
|
|
}
|
|
sides[i] = sides[0];
|
|
dists[i] = dists[0];
|
|
|
|
if (keepon && !counts[0] && !counts[1])
|
|
return in;
|
|
|
|
if (!counts[0])
|
|
{
|
|
freewinding (in);
|
|
return null;
|
|
}
|
|
if (!counts[1])
|
|
return in;
|
|
|
|
maxpts = in->numpoints+4; // can't use counts[0]+2 because
|
|
// of fp grouping errors
|
|
neww = newwinding (maxpts);
|
|
|
|
for (i=0 ; i<in->numpoints ; i++)
|
|
{
|
|
p1 = in->points[i];
|
|
|
|
if (sides[i] == side_on)
|
|
{
|
|
vectorcopy (p1, neww->points[neww->numpoints]);
|
|
neww->numpoints++;
|
|
continue;
|
|
}
|
|
|
|
if (sides[i] == side_front)
|
|
{
|
|
vectorcopy (p1, neww->points[neww->numpoints]);
|
|
neww->numpoints++;
|
|
}
|
|
|
|
if (sides[i+1] == side_on || sides[i+1] == sides[i])
|
|
continue;
|
|
|
|
// generate a split point
|
|
p2 = in->points[(i+1)%in->numpoints];
|
|
|
|
dot = dists[i] / (dists[i]-dists[i+1]);
|
|
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
|
|
mid[j] = p1[j] + dot*(p2[j]-p1[j]);
|
|
}
|
|
|
|
vectorcopy (mid, neww->points[neww->numpoints]);
|
|
neww->numpoints++;
|
|
}
|
|
|
|
if (neww->numpoints > maxpts)
|
|
error ("clipwinding: points exceeded estimate");
|
|
|
|
// free the original winding
|
|
freewinding (in);
|
|
|
|
return neww;
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
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.
|
|
==================
|
|
*/
|
|
void dividewinding (winding_t *in, plane_t *split, winding_t **front, winding_t **back)
|
|
{
|
|
vec_t dists[max_points_on_winding];
|
|
int sides[max_points_on_winding];
|
|
int counts[3];
|
|
vec_t dot;
|
|
int i, j;
|
|
vec_t *p1, *p2;
|
|
vec3_t mid;
|
|
winding_t *f, *b;
|
|
int maxpts;
|
|
|
|
counts[0] = counts[1] = counts[2] = 0;
|
|
|
|
// determine sides for each point
|
|
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;
|
|
else
|
|
{
|
|
sides[i] = side_on;
|
|
}
|
|
counts[sides[i]]++;
|
|
}
|
|
sides[i] = sides[0];
|
|
dists[i] = dists[0];
|
|
|
|
*front = *back = null;
|
|
|
|
if (!counts[0])
|
|
{
|
|
*back = in;
|
|
return;
|
|
}
|
|
if (!counts[1])
|
|
{
|
|
*front = in;
|
|
return;
|
|
}
|
|
|
|
maxpts = in->numpoints+4; // can't use counts[0]+2 because
|
|
// of fp grouping errors
|
|
|
|
*front = f = newwinding (maxpts);
|
|
*back = b = newwinding (maxpts);
|
|
|
|
for (i=0 ; i<in->numpoints ; i++)
|
|
{
|
|
p1 = in->points[i];
|
|
|
|
if (sides[i] == side_on)
|
|
{
|
|
vectorcopy (p1, f->points[f->numpoints]);
|
|
f->numpoints++;
|
|
vectorcopy (p1, b->points[b->numpoints]);
|
|
b->numpoints++;
|
|
continue;
|
|
}
|
|
|
|
if (sides[i] == side_front)
|
|
{
|
|
vectorcopy (p1, f->points[f->numpoints]);
|
|
f->numpoints++;
|
|
}
|
|
if (sides[i] == side_back)
|
|
{
|
|
vectorcopy (p1, b->points[b->numpoints]);
|
|
b->numpoints++;
|
|
}
|
|
|
|
if (sides[i+1] == side_on || sides[i+1] == sides[i])
|
|
continue;
|
|
|
|
// generate a split point
|
|
p2 = in->points[(i+1)%in->numpoints];
|
|
|
|
dot = dists[i] / (dists[i]-dists[i+1]);
|
|
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
|
|
mid[j] = p1[j] + dot*(p2[j]-p1[j]);
|
|
}
|
|
|
|
vectorcopy (mid, f->points[f->numpoints]);
|
|
f->numpoints++;
|
|
vectorcopy (mid, b->points[b->numpoints]);
|
|
b->numpoints++;
|
|
}
|
|
|
|
if (f->numpoints > maxpts || b->numpoints > maxpts)
|
|
error ("clipwinding: points exceeded estimate");
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
|
|
int c_activefaces, c_peakfaces;
|
|
int c_activesurfaces, c_peaksurfaces;
|
|
int c_activewindings, c_peakwindings;
|
|
int c_activeportals, c_peakportals;
|
|
|
|
void printmemory (void)
|
|
{
|
|
printf ("faces : %6i (%6i)\n", c_activefaces, c_peakfaces);
|
|
printf ("surfaces: %6i (%6i)\n", c_activesurfaces, c_peaksurfaces);
|
|
printf ("windings: %6i (%6i)\n", c_activewindings, c_peakwindings);
|
|
printf ("portals : %6i (%6i)\n", c_activeportals, c_peakportals);
|
|
}
|
|
|
|
/*
|
|
==================
|
|
newwinding
|
|
==================
|
|
*/
|
|
winding_t *newwinding (int points)
|
|
{
|
|
winding_t *w;
|
|
int size;
|
|
|
|
if (points > max_points_on_winding)
|
|
error ("newwinding: %i points", points);
|
|
|
|
c_activewindings++;
|
|
if (c_activewindings > c_peakwindings)
|
|
c_peakwindings = c_activewindings;
|
|
|
|
size = (int)((winding_t *)0)->points[points];
|
|
w = malloc (size);
|
|
memset (w, 0, size);
|
|
|
|
return w;
|
|
}
|
|
|
|
|
|
void freewinding (winding_t *w)
|
|
{
|
|
c_activewindings--;
|
|
free (w);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
===========
|
|
allocface
|
|
===========
|
|
*/
|
|
face_t *allocface (void)
|
|
{
|
|
face_t *f;
|
|
|
|
c_activefaces++;
|
|
if (c_activefaces > c_peakfaces)
|
|
c_peakfaces = c_activefaces;
|
|
|
|
f = malloc (sizeof(face_t));
|
|
memset (f, 0, sizeof(face_t));
|
|
f->planenum = -1;
|
|
|
|
return f;
|
|
}
|
|
|
|
|
|
void freeface (face_t *f)
|
|
{
|
|
c_activefaces--;
|
|
// memset (f,0xff,sizeof(face_t));
|
|
free (f);
|
|
}
|
|
|
|
|
|
/*
|
|
===========
|
|
allocsurface
|
|
===========
|
|
*/
|
|
surface_t *allocsurface (void)
|
|
{
|
|
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;
|
|
|
|
return s;
|
|
}
|
|
|
|
void freesurface (surface_t *s)
|
|
{
|
|
c_activesurfaces--;
|
|
free (s);
|
|
}
|
|
|
|
/*
|
|
===========
|
|
allocportal
|
|
===========
|
|
*/
|
|
portal_t *allocportal (void)
|
|
{
|
|
portal_t *p;
|
|
|
|
c_activeportals++;
|
|
if (c_activeportals > c_peakportals)
|
|
c_peakportals = c_activeportals;
|
|
|
|
p = malloc (sizeof(portal_t));
|
|
memset (p, 0, sizeof(portal_t));
|
|
|
|
return p;
|
|
}
|
|
|
|
void freeportal (portal_t *p)
|
|
{
|
|
c_activeportals--;
|
|
free (p);
|
|
}
|
|
|
|
|
|
/*
|
|
===========
|
|
allocnode
|
|
===========
|
|
*/
|
|
node_t *allocnode (void)
|
|
{
|
|
node_t *n;
|
|
|
|
n = malloc (sizeof(node_t));
|
|
memset (n, 0, sizeof(node_t));
|
|
|
|
return n;
|
|
}
|
|
|
|
/*
|
|
===========
|
|
allocbrush
|
|
===========
|
|
*/
|
|
brush_t *allocbrush (void)
|
|
{
|
|
brush_t *b;
|
|
|
|
b = malloc (sizeof(brush_t));
|
|
memset (b, 0, sizeof(brush_t));
|
|
|
|
return b;
|
|
}
|
|
|
|
//===========================================================================
|
|
|
|
/*
|
|
===============
|
|
processentity
|
|
===============
|
|
*/
|
|
void processentity (int entnum)
|
|
{
|
|
entity_t *ent;
|
|
char mod[80];
|
|
surface_t *surfs;
|
|
node_t *nodes;
|
|
brushset_t *bs;
|
|
|
|
|
|
ent = &entities[entnum];
|
|
if (!ent->brushes)
|
|
return; // non-bmodel entity
|
|
|
|
if (entnum > 0)
|
|
{
|
|
worldmodel = false;
|
|
if (entnum == 1)
|
|
qprintf ("--- internal entities ---\n");
|
|
sprintf (mod, "*%i", nummodels);
|
|
if (verbose)
|
|
printentity (ent);
|
|
|
|
if (hullnum == 0)
|
|
printf ("model: %s\n", mod);
|
|
setkeyvalue (ent, "model", mod);
|
|
}
|
|
else
|
|
worldmodel = true;
|
|
|
|
|
|
//
|
|
// 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);
|
|
|
|
if (!bs->brushes)
|
|
{
|
|
printentity (ent);
|
|
error ("entity with no valid brushes");
|
|
}
|
|
|
|
brushset = bs;
|
|
surfs = csgfaces (bs);
|
|
|
|
if (hullnum != 0)
|
|
{
|
|
nodes = solidbsp (surfs, true);
|
|
if (entnum == 0 && !nofill) // assume non-world bmodels are simple
|
|
{
|
|
portalizeworld (nodes);
|
|
if (filloutside (nodes))
|
|
{
|
|
surfs = gathernodefaces (nodes);
|
|
nodes = solidbsp (surfs, false); // make a really good tree
|
|
}
|
|
freeallportals (nodes);
|
|
}
|
|
writenodeplanes (nodes);
|
|
writeclipnodes (nodes);
|
|
bumpmodel (hullnum);
|
|
}
|
|
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
|
|
//
|
|
if (entnum == 0 && !nofill) // assume non-world bmodels are simple
|
|
{
|
|
portalizeworld (nodes);
|
|
|
|
if (filloutside (nodes))
|
|
{
|
|
freeallportals (nodes);
|
|
|
|
// get the remaining faces together into surfaces again
|
|
surfs = gathernodefaces (nodes);
|
|
|
|
// merge polygons
|
|
mergeall (surfs);
|
|
|
|
// make a really good tree
|
|
nodes = solidbsp (surfs, false);
|
|
|
|
// make the real portals for vis tracing
|
|
portalizeworld (nodes);
|
|
|
|
// save portal file for vis tracing
|
|
writeportalfile (nodes);
|
|
|
|
// fix tjunctions
|
|
tjunc (nodes);
|
|
}
|
|
freeallportals (nodes);
|
|
}
|
|
|
|
writenodeplanes (nodes);
|
|
makefaceedges (nodes);
|
|
writedrawnodes (nodes);
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
updateentlump
|
|
|
|
=================
|
|
*/
|
|
void updateentlump (void)
|
|
{
|
|
int m, entnum;
|
|
char mod[80];
|
|
|
|
m = 1;
|
|
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");
|
|
loadbspfile (bspfilename);
|
|
writeentitiestostring();
|
|
writebspfile (bspfilename);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
writecliphull
|
|
|
|
write the clipping hull out to a text file so the parent process can get it
|
|
=================
|
|
*/
|
|
void writecliphull (void)
|
|
{
|
|
file *f;
|
|
int i;
|
|
dplane_t *p;
|
|
dclipnode_t *d;
|
|
|
|
hullfilename[strlen(hullfilename)-1] = '0' + hullnum;
|
|
|
|
qprintf ("---- writecliphull ----\n");
|
|
qprintf ("writing %s\n", hullfilename);
|
|
|
|
f = fopen (hullfilename, "w");
|
|
if (!f)
|
|
error ("couldn't open %s", hullfilename);
|
|
|
|
fprintf (f, "%i\n", nummodels);
|
|
|
|
for (i=0 ; i<nummodels ; i++)
|
|
fprintf (f, "%i\n", dmodels[i].headnode[hullnum]);
|
|
|
|
fprintf (f, "\n%i\n", numclipnodes);
|
|
|
|
for (i=0 ; i<numclipnodes ; i++)
|
|
{
|
|
d = &dclipnodes[i];
|
|
p = &dplanes[d->planenum];
|
|
// the node number is only written out for human readability
|
|
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]);
|
|
}
|
|
|
|
fclose (f);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
readcliphull
|
|
|
|
read the files written out by the child processes
|
|
=================
|
|
*/
|
|
void readcliphull (int hullnum)
|
|
{
|
|
file *f;
|
|
int i, j, n;
|
|
int firstclipnode;
|
|
dplane_t p;
|
|
dclipnode_t *d;
|
|
int c1, c2;
|
|
float f1, f2, f3, f4;
|
|
int junk;
|
|
vec3_t norm;
|
|
|
|
hullfilename[strlen(hullfilename)-1] = '0' + hullnum;
|
|
|
|
f = fopen (hullfilename, "r");
|
|
if (!f)
|
|
error ("couldn't open %s", hullfilename);
|
|
|
|
if (fscanf (f,"%i\n", &n) != 1)
|
|
error ("error parsing %s", hullfilename);
|
|
|
|
if (n != nummodels)
|
|
error ("readcliphull: hull had %i models, base had %i", n, nummodels);
|
|
|
|
for (i=0 ; i<n ; i++)
|
|
{
|
|
fscanf (f, "%i\n", &j);
|
|
dmodels[i].headnode[hullnum] = numclipnodes + j;
|
|
}
|
|
|
|
|
|
fscanf (f,"\n%i\n", &n);
|
|
firstclipnode = numclipnodes;
|
|
|
|
for (i=0 ; i<n ; i++)
|
|
{
|
|
if (numclipnodes == max_map_clipnodes)
|
|
error ("readcliphull: max_map_clipnodes");
|
|
d = &dclipnodes[numclipnodes];
|
|
numclipnodes++;
|
|
if (fscanf (f,"%i : %f %f %f %f : %i %i\n", &junk, &f1, &f2, &f3, &f4, &c1, &c2) != 7)
|
|
error ("error parsing %s", hullfilename);
|
|
|
|
|
|
p.normal[0] = f1;
|
|
p.normal[1] = f2;
|
|
p.normal[2] = f3;
|
|
p.dist = f4;
|
|
|
|
norm[0] = f1; norm[1] = f2; norm[2] = f3; // vec_t precision
|
|
p.type = planetypefornormal (norm);
|
|
|
|
d->children[0] = c1 >= 0 ? c1 + firstclipnode : c1;
|
|
d->children[1] = c2 >= 0 ? c2 + firstclipnode : c2;
|
|
d->planenum = findfinalplane (&p);
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
=================
|
|
createsinglehull
|
|
|
|
=================
|
|
*/
|
|
void createsinglehull (void)
|
|
{
|
|
int entnum;
|
|
|
|
// for each entity in the map file that has geometry
|
|
for (entnum = 0 ; entnum < num_entities ; entnum++)
|
|
{
|
|
processentity (entnum);
|
|
if (!allverbose)
|
|
verbose = false; // don't print rest of entities
|
|
}
|
|
|
|
if (hullnum)
|
|
writecliphull ();
|
|
}
|
|
|
|
/*
|
|
=================
|
|
createhulls
|
|
|
|
=================
|
|
*/
|
|
void createhulls (void)
|
|
{
|
|
// commanded to create a single hull only
|
|
if (hullnum)
|
|
{
|
|
createsinglehull ();
|
|
exit (0);
|
|
}
|
|
|
|
// commanded to use the allready existing hulls 1 and 2
|
|
if (usehulls)
|
|
{
|
|
createsinglehull ();
|
|
return;
|
|
}
|
|
|
|
// commanded to ignore the hulls altogether
|
|
if (noclip)
|
|
{
|
|
createsinglehull ();
|
|
return;
|
|
}
|
|
|
|
|
|
// create all the hulls
|
|
|
|
#ifdef __alpha
|
|
printf ("forking hull processes...\n");
|
|
// fork a process for each clipping hull
|
|
fflush (stdout);
|
|
if (!fork ())
|
|
{
|
|
hullnum = 1;
|
|
verbose = false;
|
|
drawflag = false;
|
|
sprintf (argv0, "hul%i", hullnum);
|
|
}
|
|
else if (!fork ())
|
|
{
|
|
hullnum = 2;
|
|
verbose = false;
|
|
drawflag = false;
|
|
sprintf (argv0, "hul%i", hullnum);
|
|
}
|
|
createsinglehull ();
|
|
|
|
if (hullnum)
|
|
exit (0);
|
|
|
|
wait (null); // wait for clip hull process to finish
|
|
wait (null); // wait for clip hull process to finish
|
|
|
|
#else
|
|
// create the hulls sequentially
|
|
printf ("building hulls sequentially...\n");
|
|
|
|
hullnum = 1;
|
|
createsinglehull ();
|
|
|
|
nummodels = 0;
|
|
numplanes = 0;
|
|
numclipnodes = 0;
|
|
hullnum = 2;
|
|
createsinglehull ();
|
|
|
|
nummodels = 0;
|
|
numplanes = 0;
|
|
numclipnodes = 0;
|
|
hullnum = 0;
|
|
createsinglehull ();
|
|
#endif
|
|
|
|
}
|
|
|
|
/*
|
|
=================
|
|
processfile
|
|
|
|
=================
|
|
*/
|
|
void processfile (char *sourcebase, char *bspfilename1)
|
|
{
|
|
// create filenames
|
|
strcpy (bspfilename, bspfilename1);
|
|
stripextension (bspfilename);
|
|
strcat (bspfilename, ".bsp");
|
|
|
|
strcpy (hullfilename, bspfilename1);
|
|
stripextension (hullfilename);
|
|
strcat (hullfilename, ".h0");
|
|
|
|
strcpy (portfilename, bspfilename1);
|
|
stripextension (portfilename);
|
|
strcat (portfilename, ".prt");
|
|
|
|
strcpy (pointfilename, bspfilename1);
|
|
stripextension (pointfilename);
|
|
strcat (pointfilename, ".pts");
|
|
|
|
if (!onlyents)
|
|
{
|
|
remove (bspfilename);
|
|
if (!usehulls)
|
|
{
|
|
hullfilename[strlen(hullfilename)-1] = '1';
|
|
remove (hullfilename);
|
|
hullfilename[strlen(hullfilename)-1] = '2';
|
|
remove (hullfilename);
|
|
}
|
|
remove (portfilename);
|
|
remove (pointfilename);
|
|
}
|
|
|
|
// load brushes and entities
|
|
loadmapfile (sourcebase);
|
|
if (onlyents)
|
|
{
|
|
updateentlump ();
|
|
return;
|
|
}
|
|
|
|
// init the tables to be shared by all models
|
|
beginbspfile ();
|
|
|
|
// the clipping hulls will be written out to text files by forked processes
|
|
createhulls ();
|
|
|
|
readcliphull (1);
|
|
readcliphull (2);
|
|
|
|
writeentitiestostring();
|
|
finishbspfile ();
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
main
|
|
|
|
==================
|
|
*/
|
|
int main (int argc, char **argv)
|
|
{
|
|
int i;
|
|
double start, end;
|
|
char sourcename[1024];
|
|
char destname[1024];
|
|
|
|
// malloc_debug (15);
|
|
|
|
//
|
|
// check command line flags
|
|
//
|
|
for (i=1 ; i<argc ; i++)
|
|
{
|
|
if (argv[i][0] != '-')
|
|
break;
|
|
else if (!strcmp (argv[i],"-draw"))
|
|
drawflag = true;
|
|
else if (!strcmp (argv[i],"-notjunc"))
|
|
notjunc = true;
|
|
else if (!strcmp (argv[i],"-nofill"))
|
|
nofill = true;
|
|
else if (!strcmp (argv[i],"-noclip"))
|
|
noclip = true;
|
|
else if (!strcmp (argv[i],"-onlyents"))
|
|
onlyents = true;
|
|
else if (!strcmp (argv[i],"-verbose"))
|
|
allverbose = true;
|
|
else if (!strcmp (argv[i],"-usehulls"))
|
|
usehulls = true; // don't fork -- use the existing files
|
|
else if (!strcmp (argv[i],"-hullnum"))
|
|
{
|
|
hullnum = atoi(argv[i+1]);
|
|
i++;
|
|
}
|
|
else if (!strcmp (argv[i],"-subdivide"))
|
|
{
|
|
subdivide_size = atoi(argv[i+1]);
|
|
i++;
|
|
}
|
|
else
|
|
error ("qbsp: unknown option '%s'", argv[i]);
|
|
}
|
|
|
|
if (i != argc - 2 && i != argc - 1)
|
|
error ("usage: qbsp [options] sourcefile [destfile]\noptions: -nojunc -nofill -threads[124] -draw -onlyents -verbose -proj <projectpath>");
|
|
|
|
setqdirfrompath (argv[i]);
|
|
|
|
//
|
|
// let forked processes change name for ps status
|
|
//
|
|
argv0 = argv[0];
|
|
|
|
|
|
//
|
|
// create destination name if not specified
|
|
//
|
|
strcpy (sourcename, argv[i]);
|
|
defaultextension (sourcename, ".map");
|
|
|
|
if (i != argc - 2)
|
|
{
|
|
strcpy (destname, argv[i]);
|
|
stripextension (destname);
|
|
strcat (destname, ".bsp");
|
|
printf ("outputfile: %s\n", destname);
|
|
}
|
|
else
|
|
strcpy (destname, argv[i+1]);
|
|
|
|
//
|
|
// do it!
|
|
//
|
|
start = i_floattime ();
|
|
processfile (sourcename, destname);
|
|
end = i_floattime ();
|
|
printf ("%5.1f seconds elapsed\n", end-start);
|
|
|
|
return 0;
|
|
}
|