quakeforge/tools/qfbsp/source/csg4.c

374 lines
7.8 KiB
C
Raw Permalink 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__ ((unused)) const char rcsid[] =
"$Id$";
#ifdef HAVE_STRING_H
# include "string.h"
#endif
#include "QF/sys.h"
#include "bsp5.h"
/*
2002-09-23 16:27:17 +00:00
NOTES
2002-09-23 16:27:17 +00:00
Brushes that touch still need to be split at the cut point to make a
tjunction
*/
2002-09-19 17:14:23 +00:00
face_t *validfaces[MAX_MAP_PLANES];
face_t *inside, *outside;
int brushfaces;
int csgfaces;
int csgmergefaces;
2002-09-19 18:51:19 +00:00
/*
2002-09-23 16:27:17 +00:00
NewFaceFromFace
2002-09-23 16:27:17 +00:00
Duplicates the non point information of a face, used by SplitFace and
MergeFace.
*/
2002-09-19 17:14:23 +00:00
face_t *
2002-09-19 18:51:19 +00:00
NewFaceFromFace (face_t *in)
{
2002-09-19 17:14:23 +00:00
face_t *newf;
newf = AllocFace ();
newf->planenum = in->planenum;
2002-09-19 17:14:23 +00:00
newf->texturenum = in->texturenum;
newf->planeside = in->planeside;
newf->original = in->original;
newf->contents[0] = in->contents[0];
newf->contents[1] = in->contents[1];
newf->detail = in->detail;
2002-09-19 17:14:23 +00:00
return newf;
}
2002-09-19 17:14:23 +00:00
void
2002-09-19 18:51:19 +00:00
SplitFace (face_t *in, plane_t *split, face_t **front, face_t **back)
{
2003-09-08 03:00:53 +00:00
int i;
2002-09-19 17:14:23 +00:00
int counts[3];
2003-09-08 03:00:53 +00:00
plane_t plane;
2002-09-19 17:14:23 +00:00
vec_t dot;
2003-09-08 03:00:53 +00:00
winding_t *tmp;
2002-09-19 17:14:23 +00:00
2003-09-08 03:00:53 +00:00
if (in->points->numpoints < 0)
Sys_Error ("SplitFace: freed face");
counts[0] = counts[1] = counts[2] = 0;
2002-09-23 16:27:17 +00:00
// determine sides for each point
2003-09-08 03:00:53 +00:00
for (i = 0; i < in->points->numpoints; i++) {
dot = DotProduct (in->points->points[i], split->normal) - split->dist;
if (dot > ON_EPSILON)
2003-09-08 03:00:53 +00:00
counts[SIDE_FRONT]++;
else if (dot < -ON_EPSILON)
2003-09-08 03:00:53 +00:00
counts[SIDE_BACK]++;
}
2002-09-19 17:14:23 +00:00
2003-09-08 03:00:53 +00:00
if (!counts[SIDE_FRONT]) {
*front = NULL;
*back = in;
return;
}
2003-09-08 03:00:53 +00:00
if (!counts[SIDE_BACK]) {
*front = in;
*back = NULL;
return;
}
2002-09-19 17:14:23 +00:00
2003-09-08 03:00:53 +00:00
*back = NewFaceFromFace (in);
*front = NewFaceFromFace (in);
2002-09-19 17:14:23 +00:00
2003-09-08 03:00:53 +00:00
tmp = CopyWinding (in->points);
(*front)->points = ClipWinding (tmp, split, 0);
2003-09-08 03:00:53 +00:00
plane.dist = -split->dist;
VectorNegate (split->normal, plane.normal);
(*back)->points = ClipWinding (in->points, &plane, 0);
2003-09-08 03:00:53 +00:00
in->points = 0; // freed by ClipWinding
FreeFace (in);
}
/*
2002-09-23 16:27:17 +00:00
ClipInside
2002-09-23 16:27:17 +00:00
Clips all of the faces in the inside list, possibly moving them to the
outside list or spliting it into a piece in each list.
2002-09-23 16:27:17 +00:00
Faces exactly on the plane will stay inside unless overdrawn by later brush
2002-09-23 16:27:17 +00:00
frontside is the side of the plane that holds the outside list
*/
static void
2002-09-19 17:14:23 +00:00
ClipInside (int splitplane, int frontside, qboolean precedence)
{
2002-09-19 18:51:19 +00:00
face_t *insidelist, *next, *f;
2002-09-19 17:14:23 +00:00
face_t *frags[2];
plane_t *split;
split = &planes[splitplane];
2002-09-19 17:14:23 +00:00
insidelist = NULL;
2002-09-19 17:14:23 +00:00
for (f = inside; f; f = next) {
next = f->next;
2002-09-19 17:14:23 +00:00
if (f->planenum == splitplane) { // exactly on, handle special
2002-09-19 18:51:19 +00:00
if (frontside != f->planeside || precedence) { // always clip off
// opposite faceing
frags[frontside] = NULL;
frags[!frontside] = f;
2002-09-19 17:14:23 +00:00
} else { // leave it on the outside
frags[frontside] = f;
frags[!frontside] = NULL;
}
2002-09-19 17:14:23 +00:00
} else { // proper split
SplitFace (f, split, &frags[0], &frags[1]);
}
2002-09-19 17:14:23 +00:00
if (frags[frontside]) {
frags[frontside]->next = outside;
outside = frags[frontside];
}
2002-09-19 17:14:23 +00:00
if (frags[!frontside]) {
frags[!frontside]->next = insidelist;
insidelist = frags[!frontside];
}
}
2002-09-19 17:14:23 +00:00
inside = insidelist;
}
/*
2002-09-23 16:27:17 +00:00
SaveOutside
2002-09-23 16:27:17 +00:00
Saves all of the faces in the outside list to the bsp plane list
*/
static void
2002-09-19 17:14:23 +00:00
SaveOutside (qboolean mirror)
{
2002-09-19 17:14:23 +00:00
face_t *f, *next, *newf;
2003-09-08 03:00:53 +00:00
int planenum;
2002-09-19 17:14:23 +00:00
for (f = outside; f; f = next) {
next = f->next;
csgfaces++;
Draw_DrawFace (f);
planenum = f->planenum;
2002-09-19 17:14:23 +00:00
if (mirror) {
newf = NewFaceFromFace (f);
2002-09-19 17:14:23 +00:00
2003-09-08 03:00:53 +00:00
newf->points = CopyWindingReverse (f->points);
newf->planeside = f->planeside ^ 1; // reverse side
newf->contents[0] = f->contents[1];
newf->contents[1] = f->contents[0];
2002-09-19 17:14:23 +00:00
2002-09-19 18:51:19 +00:00
validfaces[planenum] = MergeFaceToList (newf,
validfaces[planenum]);
}
validfaces[planenum] = MergeFaceToList (f, validfaces[planenum]);
validfaces[planenum] = FreeMergeListScraps (validfaces[planenum]);
}
}
/*
2002-09-23 16:27:17 +00:00
FreeInside
2002-09-23 16:27:17 +00:00
Free all the faces that got clipped out
*/
static void
2002-09-19 17:14:23 +00:00
FreeInside (int contents)
{
2002-09-19 18:51:19 +00:00
face_t *next, *f;
2002-09-19 17:14:23 +00:00
for (f = inside; f; f = next) {
next = f->next;
2002-09-19 17:14:23 +00:00
if (contents != CONTENTS_SOLID) {
f->contents[0] = contents;
f->next = outside;
outside = f;
2002-09-19 17:14:23 +00:00
} else
FreeFace (f);
}
}
/*
2002-09-23 16:27:17 +00:00
BuildSurfaces
2002-09-23 16:27:17 +00:00
Returns a chain of all the external surfaces with one or more visible
faces.
*/
2002-09-19 17:14:23 +00:00
surface_t *
BuildSurfaces (void)
{
2002-09-19 17:14:23 +00:00
face_t *count;
2002-09-19 18:51:19 +00:00
face_t **f;
2002-09-19 17:14:23 +00:00
int i;
2002-09-19 18:51:19 +00:00
surface_t *surfhead, *s;
2002-09-19 17:14:23 +00:00
surfhead = NULL;
2002-09-19 17:14:23 +00:00
f = validfaces;
2002-09-19 17:14:23 +00:00
for (i = 0; i < numbrushplanes; i++, f++) {
if (!*f)
2002-09-19 17:14:23 +00:00
continue; // nothing left on this plane
2002-09-23 16:27:17 +00:00
// create a new surface to hold the faces on this plane
s = AllocSurface ();
s->planenum = i;
s->next = surfhead;
surfhead = s;
s->faces = *f;
for (count = s->faces; count; count = count->next) {
csgmergefaces++;
if (count->detail)
s->has_detail = 1;
else
s->has_struct = 1;
}
2002-09-19 17:14:23 +00:00
CalcSurfaceInfo (s); // bounding box and flags
}
return surfhead;
}
static void
2002-09-19 18:51:19 +00:00
CopyFacesToOutside (brush_t *b)
{
2002-09-19 18:51:19 +00:00
face_t *newf, *f;
2002-09-19 17:14:23 +00:00
outside = NULL;
2002-09-19 17:14:23 +00:00
for (f = b->faces; f; f = f->next) {
if (f->texturenum == TEX_SKIP)
continue;
brushfaces++;
newf = AllocFace ();
*newf = *f;
2003-09-08 03:00:53 +00:00
newf->points = CopyWinding (f->points);
newf->next = outside;
newf->contents[0] = CONTENTS_EMPTY;
newf->contents[1] = b->contents;
outside = newf;
}
}
/*
2002-09-23 16:27:17 +00:00
CSGFaces
2002-09-23 16:27:17 +00:00
Returns a list of surfaces containing aall of the faces
*/
2002-09-19 17:14:23 +00:00
surface_t *
2002-09-19 18:51:19 +00:00
CSGFaces (brushset_t *bs)
{
2002-09-19 17:14:23 +00:00
brush_t *b1, *b2;
2002-09-19 18:51:19 +00:00
face_t *f;
2002-09-19 17:14:23 +00:00
int i;
qboolean overwrite;
surface_t *surfhead;
qprintf ("---- CSGFaces ----\n");
2002-09-19 17:14:23 +00:00
memset (validfaces, 0, sizeof (validfaces));
csgfaces = brushfaces = csgmergefaces = 0;
2002-09-19 17:14:23 +00:00
Draw_ClearWindow ();
2002-09-19 17:14:23 +00:00
2002-09-23 16:27:17 +00:00
// do the solid faces
2002-09-19 17:14:23 +00:00
for (b1 = bs->brushes; b1; b1 = b1->next) {
// set outside to a copy of the brush's faces
CopyFacesToOutside (b1);
2002-09-19 17:14:23 +00:00
if (b1->faces->texturenum < 0) {
// Don't split HINT and SKIP brushes.
SaveOutside (false);
continue;
}
overwrite = false;
2002-09-19 17:14:23 +00:00
for (b2 = bs->brushes; b2; b2 = b2->next) {
if (b2->faces->texturenum < 0)
continue;
2002-09-19 17:14:23 +00:00
// see if b2 needs to clip a chunk out of b1
if (b1 == b2) {
overwrite = true; // later brushes now overwrite
continue;
}
2002-09-19 17:14:23 +00:00
// check bounding box first
for (i = 0; i < 3; i++)
if (b1->mins[i] > b2->maxs[i] || b1->maxs[i] < b2->mins[i])
break;
2002-09-19 17:14:23 +00:00
if (i < 3)
continue;
2002-09-19 17:14:23 +00:00
// divide faces by the planes of the new brush
inside = outside;
outside = NULL;
2002-09-19 17:14:23 +00:00
for (f = b2->faces; f; f = f->next)
ClipInside (f->planenum, f->planeside, overwrite);
2002-09-19 17:14:23 +00:00
// these faces are continued in another brush, so get rid of them
if (b1->contents == CONTENTS_SOLID
&& b2->contents <= CONTENTS_WATER)
FreeInside (b2->contents);
else
FreeInside (CONTENTS_SOLID);
}
2002-09-19 17:14:23 +00:00
// all of the faces left in outside are real surface faces
if (b1->contents != CONTENTS_SOLID)
2002-09-19 17:14:23 +00:00
SaveOutside (true); // mirror faces for inside view
else
SaveOutside (false);
}
#if 0
if (!csgfaces)
Sys_Error ("No faces");
#endif
surfhead = BuildSurfaces ();
2002-09-19 17:14:23 +00:00
qprintf ("%5i brushfaces\n", brushfaces);
qprintf ("%5i csgfaces\n", csgfaces);
qprintf ("%5i mergedfaces\n", csgmergefaces);
2002-09-19 17:14:23 +00:00
return surfhead;
}