#include "qbsp.h"
void SplitBrush2(bspbrush_t *brush, int32_t planenum,
bspbrush_t **front, bspbrush_t **back) {
SplitBrush(brush, planenum, front, back);
#if 0#endif
}
bspbrush_t *SubtractBrush(bspbrush_t *a, bspbrush_t *b) {
int32_t i;
bspbrush_t *front, *back;
bspbrush_t *out, *in;
in = a;
out = NULL;
for (i = 0; i < b->numsides && in; i++) {
SplitBrush2(in, b->sides[i].planenum, &front, &back);
if (in != a)
FreeBrush(in);
if (front) {
front->next = out;
out = front;
}
in = back;
}
if (in)
FreeBrush(in);
else {
FreeBrushList(out);
return a;
}
return out;
}
bspbrush_t *IntersectBrush(bspbrush_t *a, bspbrush_t *b) {
int32_t i;
bspbrush_t *front, *back;
bspbrush_t *in;
in = a;
for (i = 0; i < b->numsides && in; i++) {
SplitBrush2(in, b->sides[i].planenum, &front, &back);
if (in != a)
FreeBrush(in);
if (front)
FreeBrush(front);
in = back;
}
if (in == a)
return NULL;
in->next = NULL;
return in;
}
qboolean BrushesDisjoint(bspbrush_t *a, bspbrush_t *b) {
int32_t i, j;
for (i = 0; i < 3; i++)
if (a->mins[i] >= b->maxs[i] || a->maxs[i] <= b->mins[i])
return true;
for (i = 0; i < a->numsides; i++) {
for (j = 0; j < b->numsides; j++) {
if (a->sides[i].planenum ==
(b->sides[j].planenum ^ 1))
return true; }
}
return false; }
int32_t IntersectionContents(int32_t c1, int32_t c2) {
int32_t out;
out = c1 | c2;
if (out & CONTENTS_SOLID)
out = CONTENTS_SOLID;
return out;
}
int32_t minplanenums[3];
int32_t maxplanenums[3];
bspbrush_t *ClipBrushToBox(bspbrush_t *brush, vec3_t clipmins, vec3_t clipmaxs) {
int32_t i, j;
bspbrush_t *front, *back;
int32_t p;
for (j = 0; j < 2; j++) {
if (brush->maxs[j] > clipmaxs[j]) {
SplitBrush(brush, maxplanenums[j], &front, &back);
FreeBrush(brush); if (front)
FreeBrush(front);
brush = back;
if (!brush)
return NULL;
}
if (brush->mins[j] < clipmins[j]) {
SplitBrush(brush, minplanenums[j], &front, &back);
FreeBrush(brush); if (back)
FreeBrush(back);
brush = front;
if (!brush)
return NULL;
}
}
for (i = 0; i < brush->numsides; i++) {
p = brush->sides[i].planenum & ~1;
if (p == maxplanenums[0] || p == maxplanenums[1] || p == minplanenums[0] || p == minplanenums[1]) {
brush->sides[i].texinfo = TEXINFO_NODE;
brush->sides[i].visible = false;
}
}
return brush;
}
bspbrush_t *MakeBspBrushList(int32_t startbrush, int32_t endbrush,
vec3_t clipmins, vec3_t clipmaxs) {
mapbrush_t *mb;
bspbrush_t *brushlist, *newbrush;
int32_t i, j;
int32_t c_faces;
int32_t c_brushes;
int32_t numsides;
int32_t vis;
vec3_t normal;
vec_t dist;
for (i = 0; i < 2; i++) {
VectorClear(normal);
normal[i] = 1;
dist = clipmaxs[i];
maxplanenums[i] = FindFloatPlane(normal, dist, 0);
dist = clipmins[i];
minplanenums[i] = FindFloatPlane(normal, dist, 0);
}
brushlist = NULL;
c_faces = 0;
c_brushes = 0;
for (i = startbrush; i < endbrush; i++) {
mb = &mapbrushes[i];
numsides = mb->numsides;
if (!numsides)
continue;
vis = 0;
for (j = 0; j < numsides; j++)
if (mb->original_sides[j].visible && mb->original_sides[j].winding)
vis++;
#if 0#endif
for (j = 0; j < 3; j++)
if (mb->mins[j] >= clipmaxs[j] || mb->maxs[j] <= clipmins[j])
break;
if (j != 3)
continue;
newbrush = AllocBrush(mb->numsides);
newbrush->original = mb;
newbrush->numsides = mb->numsides;
memcpy(newbrush->sides, mb->original_sides, numsides * sizeof(side_t));
for (j = 0; j < numsides; j++) {
if (newbrush->sides[j].winding)
newbrush->sides[j].winding = CopyWinding(newbrush->sides[j].winding);
if (newbrush->sides[j].surf & SURF_HINT)
newbrush->sides[j].visible = true; }
VectorCopy(mb->mins, newbrush->mins);
VectorCopy(mb->maxs, newbrush->maxs);
newbrush = ClipBrushToBox(newbrush, clipmins, clipmaxs);
if (!newbrush)
continue;
c_faces += vis;
c_brushes++;
newbrush->next = brushlist;
brushlist = newbrush;
}
return brushlist;
}
bspbrush_t *AddBrushListToTail(bspbrush_t *list, bspbrush_t *tail) {
bspbrush_t *walk, *next;
for (walk = list; walk; walk = next) {
next = walk->next;
walk->next = NULL;
tail->next = walk;
tail = walk;
}
return tail;
}
bspbrush_t *CullList(bspbrush_t *list, bspbrush_t *skip1) {
bspbrush_t *newlist;
bspbrush_t *next;
newlist = NULL;
for (; list; list = next) {
next = list->next;
if (list == skip1) {
FreeBrush(list);
continue;
}
list->next = newlist;
newlist = list;
}
return newlist;
}
void WriteBrushMap(char *name, bspbrush_t *list) {
FILE *f;
side_t *s;
int32_t i;
winding_t *w;
if (use_qbsp)
printf("\ntexinfo count: %i of %i maximum\n", numtexinfo, MAX_MAP_TEXINFO_QBSP);
else
printf("\ntexinfo count: %i of %i maximum\n", numtexinfo, MAX_MAP_TEXINFO);
if (use_qbsp)
printf("brushsides count: %i of %i maximum\n", nummapbrushsides, MAX_MAP_BRUSHSIDES_QBSP);
else
printf("brushsides count: %i of %i maximum\n", nummapbrushsides, MAX_MAP_BRUSHSIDES);
printf("writing %s\n", name);
f = fopen(name, "wb");
if (!f)
Error("Can't write %s\b", name);
fprintf(f, "{\n\"classname\" \"worldspawn\"\n");
for (; list; list = list->next) {
fprintf(f, "{\n");
for (i = 0, s = list->sides; i < list->numsides; i++, s++) {
w = BaseWindingForPlane(mapplanes[s->planenum].normal, mapplanes[s->planenum].dist);
fprintf(f, "( %i %i %i ) ", (int32_t)w->p[0][0], (int32_t)w->p[0][1], (int32_t)w->p[0][2]);
fprintf(f, "( %i %i %i ) ", (int32_t)w->p[1][0], (int32_t)w->p[1][1], (int32_t)w->p[1][2]);
fprintf(f, "( %i %i %i ) ", (int32_t)w->p[2][0], (int32_t)w->p[2][1], (int32_t)w->p[2][2]);
fprintf(f, "%s 0 0 0 1 1\n", texinfo[s->texinfo].texture);
FreeWinding(w);
}
fprintf(f, "}\n");
}
fprintf(f, "}\n");
fclose(f);
}
qboolean BrushGE(bspbrush_t *b1, bspbrush_t *b2) {
if ((b1->original->contents & CONTENTS_DETAIL) && !(b2->original->contents & CONTENTS_DETAIL))
return false;
if (b1->original->contents & CONTENTS_SOLID)
return true;
return false;
}
bspbrush_t *ChopBrushes(bspbrush_t *head) {
bspbrush_t *b1, *b2, *next;
bspbrush_t *tail;
bspbrush_t *keep;
bspbrush_t *sub, *sub2;
int32_t c1, c2;
qprintf("---- ChopBrushes ----\n");
qprintf("original brushes: %i\n", CountBrushList(head));
keep = NULL;
newlist:
if (!head)
return NULL;
for (tail = head; tail->next; tail = tail->next)
;
for (b1 = head; b1; b1 = next) {
next = b1->next;
for (b2 = b1->next; b2; b2 = b2->next) {
if (BrushesDisjoint(b1, b2))
continue;
sub = NULL;
sub2 = NULL;
c1 = BOGUS_RANGE;
c2 = BOGUS_RANGE;
if (BrushGE(b2, b1)) {
sub = SubtractBrush(b1, b2);
if (sub == b1)
continue; if (!sub) {
head = CullList(b1, b1);
goto newlist;
}
c1 = CountBrushList(sub);
}
if (BrushGE(b1, b2)) {
sub2 = SubtractBrush(b2, b1);
if (sub2 == b2)
continue; if (!sub2) {
FreeBrushList(sub);
head = CullList(b1, b2);
goto newlist;
}
c2 = CountBrushList(sub2);
}
if (!sub && !sub2)
continue;
if (c1 > 1 && c2 > 1) {
if (sub2)
FreeBrushList(sub2);
if (sub)
FreeBrushList(sub);
continue;
}
if (c1 < c2) {
if (sub2)
FreeBrushList(sub2);
tail = AddBrushListToTail(sub, tail);
head = CullList(b1, b1);
goto newlist;
} else {
if (sub)
FreeBrushList(sub);
tail = AddBrushListToTail(sub2, tail);
head = CullList(b1, b2);
goto newlist;
}
}
if (!b2) {
b1->next = keep;
keep = b1;
}
}
qprintf("output brushes: %i\n", CountBrushList(keep));
return keep;
}
bspbrush_t *InitialBrushList(bspbrush_t *list) {
bspbrush_t *b;
bspbrush_t *out, *newb;
int32_t i;
out = NULL;
for (b = list; b; b = b->next) {
#if 0#endif
newb = CopyBrush(b);
newb->next = out;
out = newb;
for (i = 0; i < b->numsides; i++) {
newb->sides[i].original = &b->sides[i];
b->sides[i].visible = false;
}
}
return out;
}
bspbrush_t *OptimizedBrushList(bspbrush_t *list) {
bspbrush_t *b;
bspbrush_t *out, *newb;
int32_t i;
out = NULL;
for (b = list; b; b = b->next) {
for (i = 0; i < b->numsides; i++)
if (b->sides[i].visible)
break;
if (i == b->numsides)
continue;
newb = CopyBrush(b);
newb->next = out;
out = newb;
}
return out;
}