00001
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048 #include "bsp.h"
00049
00055 static bspbrush_t *SubtractBrush (bspbrush_t *a, const bspbrush_t *b)
00056 {
00057
00058 int i;
00059 bspbrush_t *front, *back, *out;
00060 bspbrush_t *in;
00061
00062 in = a;
00063 out = NULL;
00064 for (i = 0; i < b->numsides && in; i++) {
00065 SplitBrush(in, b->sides[i].planenum, &front, &back);
00066 if (in != a)
00067 FreeBrush(in);
00068 if (front) {
00069 front->next = out;
00070 out = front;
00071 }
00072 in = back;
00073 }
00074 if (in)
00075 FreeBrush(in);
00076 else {
00077 FreeBrushList(out);
00078 return a;
00079 }
00080 return out;
00081 }
00082
00087 static qboolean BrushesDisjoint (bspbrush_t *a, bspbrush_t *b)
00088 {
00089 int i, j;
00090
00091
00092 for (i = 0; i < 3; i++)
00093 if (a->mins[i] >= b->maxs[i] || a->maxs[i] <= b->mins[i])
00094 return qtrue;
00095
00096
00097 for (i = 0; i < a->numsides; i++) {
00098 for (j = 0; j < b->numsides; j++) {
00099 if (a->sides[i].planenum == (b->sides[j].planenum ^ 1))
00100 return qtrue;
00101 }
00102 }
00103
00104 return qfalse;
00105 }
00106
00107 static int minplanenums[2];
00108 static int maxplanenums[2];
00109
00113 static bspbrush_t *ClipBrushToBox (bspbrush_t *brush, vec3_t clipmins, vec3_t clipmaxs)
00114 {
00115 int i, j, p;
00116 bspbrush_t *front, *back;
00117
00118 for (j = 0; j < 2; j++) {
00119 if (brush->maxs[j] > clipmaxs[j]) {
00120 SplitBrush(brush, maxplanenums[j], &front, &back);
00121 FreeBrush(brush);
00122 if (front)
00123 FreeBrush(front);
00124 brush = back;
00125 if (!brush)
00126 return NULL;
00127 }
00128 if (brush->mins[j] < clipmins[j]) {
00129 SplitBrush(brush, minplanenums[j], &front, &back);
00130 FreeBrush(brush);
00131 if (back)
00132 FreeBrush(back);
00133 brush = front;
00134 if (!brush)
00135 return NULL;
00136 }
00137 }
00138
00139
00140 for (i = 0; i < brush->numsides; i++) {
00141 p = brush->sides[i].planenum & ~1;
00142 if (p == maxplanenums[0] || p == maxplanenums[1]
00143 || p == minplanenums[0] || p == minplanenums[1]) {
00144 brush->sides[i].texinfo = TEXINFO_NODE;
00145 brush->sides[i].visible = qfalse;
00146 }
00147 }
00148 return brush;
00149 }
00150
00158 static qboolean IsInLevel (const int contents, const int level)
00159 {
00160
00161 switch (level) {
00162 case LEVEL_LIGHTCLIP:
00163 if (contents & CONTENTS_LIGHTCLIP)
00164 return qtrue;
00165 else
00166 return qfalse;
00167 case LEVEL_WEAPONCLIP:
00168 if (contents & CONTENTS_WEAPONCLIP)
00169 return qtrue;
00170 else
00171 return qfalse;
00172 case LEVEL_ACTORCLIP:
00173 if (contents & CONTENTS_ACTORCLIP)
00174 return qtrue;
00175 else
00176 return qfalse;
00177 }
00178
00179
00180 if (contents & MASK_CLIP)
00181 return qfalse;
00182
00183
00184 if (level == -1)
00185 return qtrue;
00186 else if (level) {
00187 if (((contents >> 8) & 0xFF) == level)
00188 return qtrue;
00189 else
00190 return qfalse;
00191 } else {
00192 if (contents & 0xFF00)
00193 return qfalse;
00194 else
00195 return qtrue;
00196 }
00197 }
00198
00199 static bspbrush_t *AddBrushListToTail (bspbrush_t *list, bspbrush_t *tail)
00200 {
00201 bspbrush_t *walk, *next;
00202
00203
00204 for (walk = list; walk; walk = next) {
00205 next = walk->next;
00206 walk->next = NULL;
00207 tail->next = walk;
00208 tail = walk;
00209 }
00210
00211 return tail;
00212 }
00213
00220 static bspbrush_t *CullList (bspbrush_t *list, bspbrush_t *skip)
00221 {
00222 bspbrush_t *newlist;
00223 bspbrush_t *next;
00224
00225 newlist = NULL;
00226
00227 for (; list; list = next) {
00228 next = list->next;
00229 if (list == skip) {
00230 FreeBrush(list);
00231 continue;
00232 }
00233 list->next = newlist;
00234 newlist = list;
00235 }
00236 return newlist;
00237 }
00238
00242 static inline qboolean BrushGE (bspbrush_t *b1, bspbrush_t *b2)
00243 {
00244
00245 if ((b1->original->contentFlags & CONTENTS_DETAIL)
00246 && !(b2->original->contentFlags & CONTENTS_DETAIL))
00247 return qfalse;
00248 if (b1->original->contentFlags & CONTENTS_SOLID)
00249 return qtrue;
00250 return qfalse;
00251 }
00252
00266 int MapBrushesBounds (const int startbrush, const int endbrush, const int level, const vec3_t clipmins, const vec3_t clipmaxs, vec3_t mins, vec3_t maxs)
00267 {
00268 int i, j, num;
00269
00270 ClearBounds(mins, maxs);
00271 num = 0;
00272
00273 for (i = startbrush; i < endbrush; i++) {
00274 const mapbrush_t *b = &mapbrushes[i];
00275
00276
00277 if (b->finished)
00278 continue;
00279
00280 if (!IsInLevel(b->contentFlags, level))
00281 continue;
00282
00283
00284 for (j = 0; j < 3; j++)
00285 if (b->mins[j] < clipmins[j]
00286 || b->maxs[j] > clipmaxs[j])
00287 break;
00288 if (j != 3)
00289 continue;
00290
00291 num++;
00292 AddPointToBounds(b->mins, mins, maxs);
00293 AddPointToBounds(b->maxs, mins, maxs);
00294 }
00295
00296 return num;
00297 }
00298
00299 bspbrush_t *MakeBspBrushList (int startbrush, int endbrush, int level, vec3_t clipmins, vec3_t clipmaxs)
00300 {
00301 bspbrush_t *brushlist, *newbrush;
00302 int i, j, vis;
00303 int c_faces, c_brushes, numsides;
00304
00305 Verb_Printf(VERB_DUMP, "MakeBspBrushList: bounds (%f %f %f) (%f %f %f)\n",
00306 clipmins[0], clipmins[1], clipmins[2], clipmaxs[0], clipmaxs[1], clipmaxs[2]);
00307
00308 for (i = 0; i < 2; i++) {
00309 float dist;
00310 vec3_t normal = {0, 0, 0};
00311 normal[i] = 1;
00312 dist = clipmaxs[i];
00313 maxplanenums[i] = FindOrCreateFloatPlane(normal, dist);
00314 dist = clipmins[i];
00315 minplanenums[i] = FindOrCreateFloatPlane(normal, dist);
00316 }
00317
00318 brushlist = NULL;
00319 c_faces = 0;
00320 c_brushes = 0;
00321
00322 for (i = startbrush; i < endbrush; i++) {
00323 mapbrush_t *mb = &mapbrushes[i];
00324
00325 if (!IsInLevel(mb->contentFlags, level)){
00326 Verb_Printf(VERB_DUMP, "Rejected brush %i: wrong level.\n", i);
00327 continue;
00328 }
00329
00330 if (mb->finished){
00331 Verb_Printf(VERB_DUMP, "Rejected brush %i: already finished.\n", i);
00332 continue;
00333 }
00334
00335 numsides = mb->numsides;
00336 if (!numsides) {
00337 Verb_Printf(VERB_DUMP, "Rejected brush %i: no sides.\n", i);
00338 continue;
00339 }
00340
00341
00342 vis = 0;
00343 for (j = 0; j < numsides; j++)
00344 if (mb->original_sides[j].visible && mb->original_sides[j].winding)
00345 vis++;
00346
00347
00348 for (j = 0; j < 3; j++)
00349 if (mb->mins[j] < clipmins[j] || mb->maxs[j] > clipmaxs[j])
00350 break;
00351 if (j != 3)
00352 continue;
00353
00354 mb->finished = qtrue;
00355
00356
00357 newbrush = AllocBrush(mb->numsides);
00358 newbrush->original = mb;
00359 newbrush->numsides = mb->numsides;
00360 memcpy(newbrush->sides, mb->original_sides, numsides * sizeof(side_t));
00361 for (j = 0; j < numsides; j++) {
00362 if (newbrush->sides[j].winding)
00363 newbrush->sides[j].winding = CopyWinding(newbrush->sides[j].winding);
00364 if (newbrush->sides[j].surfaceFlags & SURF_HINT)
00365 newbrush->sides[j].visible = qtrue;
00366 }
00367 VectorCopy(mb->mins, newbrush->mins);
00368 VectorCopy(mb->maxs, newbrush->maxs);
00369
00370
00371 newbrush = ClipBrushToBox(newbrush, clipmins, clipmaxs);
00372 if (!newbrush) {
00373 Verb_Printf(VERB_DUMP, "Rejected brush %i: cannot clip to box.\n", i);
00374 continue;
00375 }
00376
00377 c_faces += vis;
00378 c_brushes++;
00379
00380 newbrush->next = brushlist;
00381 brushlist = newbrush;
00382 Verb_Printf(VERB_DUMP, "Added brush %i.\n", i);
00383 }
00384
00385 return brushlist;
00386 }
00387
00391 bspbrush_t *ChopBrushes (bspbrush_t *head)
00392 {
00393 bspbrush_t *b1, *b2, *next;
00394 bspbrush_t *tail;
00395 bspbrush_t *keep;
00396 bspbrush_t *sub, *sub2;
00397 int c1, c2;
00398 const int originalBrushes = CountBrushList(head);
00399 int keepBrushes;
00400
00401 Verb_Printf(VERB_EXTRA, "---- ChopBrushes ----\n");
00402
00403 keep = NULL;
00404
00405 newlist:
00406
00407 if (!head)
00408 return NULL;
00409
00410 for (tail = head; tail->next; tail = tail->next);
00411
00412 for (b1 = head; b1; b1 = next) {
00413 next = b1->next;
00414 for (b2 = b1->next; b2; b2 = b2->next) {
00415 if (BrushesDisjoint(b1, b2))
00416 continue;
00417
00418 sub = sub2 = NULL;
00419 c1 = c2 = 999999;
00420
00421 if (BrushGE(b2, b1)) {
00422 sub = SubtractBrush(b1, b2);
00423 if (sub == b1)
00424 continue;
00425 if (!sub) {
00426 head = CullList(b1, b1);
00427 goto newlist;
00428 }
00429 c1 = CountBrushList(sub);
00430 }
00431
00432 if (BrushGE(b1, b2)) {
00433 sub2 = SubtractBrush(b2, b1);
00434 if (sub2 == b2)
00435 continue;
00436 if (!sub2) {
00437 FreeBrushList(sub);
00438 head = CullList(b1, b2);
00439 goto newlist;
00440 }
00441 c2 = CountBrushList(sub2);
00442 }
00443
00444 if (!sub && !sub2)
00445 continue;
00446
00447
00448
00449 if (c1 > 1 && c2 > 1) {
00450 if (sub2)
00451 FreeBrushList(sub2);
00452 if (sub)
00453 FreeBrushList(sub);
00454 continue;
00455 }
00456
00457 if (c1 < c2) {
00458 if (sub2)
00459 FreeBrushList(sub2);
00460 tail = AddBrushListToTail(sub, tail);
00461 head = CullList(b1, b1);
00462 goto newlist;
00463 } else {
00464 if (sub)
00465 FreeBrushList(sub);
00466 tail = AddBrushListToTail(sub2, tail);
00467 head = CullList(b1, b2);
00468 goto newlist;
00469 }
00470 }
00471
00472
00473 if (!b2) {
00474 b1->next = keep;
00475 keep = b1;
00476 }
00477 }
00478
00479 keepBrushes = CountBrushList(keep);
00480 if (keepBrushes != originalBrushes) {
00481 Verb_Printf(VERB_EXTRA, "original brushes: %i\n", originalBrushes);
00482 Verb_Printf(VERB_EXTRA, "output brushes: %i\n", keepBrushes);
00483 }
00484 return keep;
00485 }