2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 tag all brushes with original contents
27 brushes may contain multiple contents
28 there will be no brush overlap after csg phase
33 each side has a count of the other sides it splits
35 the best split will be the one that minimizes the total split counts
36 of all remaining sides
38 precalc side on plane table
46 if side splits side and splitside is on same child
53 void SplitBrush2( bspbrush_t *brush, int planenum,
54 bspbrush_t **front, bspbrush_t **back ){
55 SplitBrush( brush, planenum, front, back );
62 Returns a list of brushes that remain after B is subtracted from A.
63 May by empty if A is contained inside B.
65 The originals are undisturbed.
68 bspbrush_t *SubtractBrush( bspbrush_t *a, bspbrush_t *b ){ // a - b = out (list)
70 bspbrush_t *front, *back;
75 for ( i = 0 ; i < b->numsides && in ; i++ )
77 SplitBrush2( in, b->sides[i].planenum, &front, &back );
81 if ( front ) { // add to list
91 { // didn't really intersect
102 Returns a single brush made up by the intersection of the
103 two provided brushes, or NULL if they are disjoint.
105 The originals are undisturbed.
108 bspbrush_t *IntersectBrush( bspbrush_t *a, bspbrush_t *b ){
110 bspbrush_t *front, *back;
114 for ( i = 0 ; i < b->numsides && in ; i++ )
116 SplitBrush2( in, b->sides[i].planenum, &front, &back );
139 Returns true if the two brushes definately do not intersect.
140 There will be false negatives for some non-axial combinations.
143 qboolean BrushesDisjoint( bspbrush_t *a, bspbrush_t *b ){
146 // check bounding boxes
147 for ( i = 0 ; i < 3 ; i++ )
148 if ( a->mins[i] >= b->maxs[i]
149 || a->maxs[i] <= b->mins[i] ) {
151 } // bounding boxes don't overlap
153 // check for opposing planes
154 for ( i = 0 ; i < a->numsides ; i++ )
156 for ( j = 0 ; j < b->numsides ; j++ )
158 if ( a->sides[i].planenum ==
159 ( b->sides[j].planenum ^ 1 ) ) {
160 return true; // opposite planes, so not touching
165 return false; // might intersect
172 Returns a content word for the intersection of two brushes.
173 Some combinations will generate a combination (water + clip),
174 but most will be the stronger of the two contents.
177 int IntersectionContents( int c1, int c2 ){
182 if ( out & CONTENTS_SOLID ) {
183 out = CONTENTS_SOLID;
197 Any planes shared with the box edge will be set to no texinfo
200 bspbrush_t *ClipBrushToBox( bspbrush_t *brush, vec3_t clipmins, vec3_t clipmaxs ){
202 bspbrush_t *front, *back;
205 for ( j = 0 ; j < 2 ; j++ )
207 if ( brush->maxs[j] > clipmaxs[j] ) {
208 SplitBrush( brush, maxplanenums[j], &front, &back );
217 if ( brush->mins[j] < clipmins[j] ) {
218 SplitBrush( brush, minplanenums[j], &front, &back );
229 // remove any colinear faces
231 for ( i = 0 ; i < brush->numsides ; i++ )
233 p = brush->sides[i].planenum & ~1;
234 if ( p == maxplanenums[0] || p == maxplanenums[1]
235 || p == minplanenums[0] || p == minplanenums[1] ) {
236 brush->sides[i].texinfo = TEXINFO_NODE;
237 brush->sides[i].visible = false;
248 bspbrush_t *MakeBspBrushList( int startbrush, int endbrush,
249 vec3_t clipmins, vec3_t clipmaxs ){
251 bspbrush_t *brushlist, *newbrush;
260 for ( i = 0 ; i < 2 ; i++ )
262 VectorClear( normal );
265 maxplanenums[i] = FindFloatPlane( normal, dist );
267 minplanenums[i] = FindFloatPlane( normal, dist );
274 for ( i = startbrush ; i < endbrush ; i++ )
278 numsides = mb->numsides;
282 // make sure the brush has at least one face showing
284 for ( j = 0 ; j < numsides ; j++ )
285 if ( mb->original_sides[j].visible && mb->original_sides[j].winding ) {
288 // if the brush is outside the clip area, skip it
289 for ( j = 0 ; j < 3 ; j++ )
290 if ( mb->mins[j] >= clipmaxs[j]
291 || mb->maxs[j] <= clipmins[j] ) {
299 // make a copy of the brush
301 newbrush = AllocBrush( mb->numsides );
302 newbrush->original = mb;
303 newbrush->numsides = mb->numsides;
304 memcpy( newbrush->sides, mb->original_sides, numsides * sizeof( side_t ) );
305 for ( j = 0 ; j < numsides ; j++ )
307 if ( newbrush->sides[j].winding ) {
308 newbrush->sides[j].winding = CopyWinding( newbrush->sides[j].winding );
310 if ( newbrush->sides[j].surf & SURF_HINT ) {
311 newbrush->sides[j].visible = true; // hints are always visible
314 VectorCopy( mb->mins, newbrush->mins );
315 VectorCopy( mb->maxs, newbrush->maxs );
318 // carve off anything outside the clip box
320 newbrush = ClipBrushToBox( newbrush, clipmins, clipmaxs );
328 newbrush->next = brushlist;
329 brushlist = newbrush;
337 AddBspBrushListToTail
340 bspbrush_t *AddBrushListToTail( bspbrush_t *list, bspbrush_t *tail ){
341 bspbrush_t *walk, *next;
343 for ( walk = list ; walk ; walk = next )
344 { // add to end of list
358 Builds a new list that doesn't hold the given brush
361 bspbrush_t *CullList( bspbrush_t *list, bspbrush_t *skip1 ){
367 for ( ; list ; list = next )
370 if ( list == skip1 ) {
374 list->next = newlist;
386 void WriteBrushMap( char *name, bspbrush_t *list ){
392 Sys_Printf( "writing %s\n", name );
393 f = fopen( name, "wb" );
395 Error( "Can't write %s\b", name );
398 fprintf( f, "{\n\"classname\" \"worldspawn\"\n" );
400 for ( ; list ; list = list->next )
403 for ( i = 0,s = list->sides ; i < list->numsides ; i++,s++ )
405 w = BaseWindingForPlane( mapplanes[s->planenum].normal, mapplanes[s->planenum].dist );
407 fprintf( f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2] );
408 fprintf( f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2] );
409 fprintf( f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2] );
411 fprintf( f, "%s 0 0 0 1 1\n", texinfo[s->texinfo].texture );
426 Returns true if b1 is allowed to bite b2
429 qboolean BrushGE( bspbrush_t *b1, bspbrush_t *b2 ){
430 // detail brushes never bite structural brushes
431 if ( ( b1->original->contents & CONTENTS_DETAIL )
432 && !( b2->original->contents & CONTENTS_DETAIL ) ) {
435 if ( b1->original->contents & CONTENTS_SOLID ) {
445 Carves any intersecting solid brushes into the minimum number
446 of non-intersecting brushes.
449 bspbrush_t *ChopBrushes( bspbrush_t *head ){
450 bspbrush_t *b1, *b2, *next;
453 bspbrush_t *sub, *sub2;
456 Sys_FPrintf( SYS_VRB, "---- ChopBrushes ----\n" );
457 Sys_FPrintf( SYS_VRB, "original brushes: %i\n", CountBrushList( head ) );
466 for ( tail = head ; tail->next ; tail = tail->next )
469 for ( b1 = head ; b1 ; b1 = next )
472 for ( b2 = b1->next ; b2 ; b2 = b2->next )
474 if ( BrushesDisjoint( b1, b2 ) ) {
483 if ( BrushGE( b2, b1 ) ) {
484 sub = SubtractBrush( b1, b2 );
486 continue; // didn't really intersect
488 if ( !sub ) { // b1 is swallowed by b2
489 head = CullList( b1, b1 );
492 c1 = CountBrushList( sub );
495 if ( BrushGE( b1, b2 ) ) {
496 sub2 = SubtractBrush( b2, b1 );
498 continue; // didn't really intersect
500 if ( !sub2 ) { // b2 is swallowed by b1
501 FreeBrushList( sub );
502 head = CullList( b1, b2 );
505 c2 = CountBrushList( sub2 );
508 if ( !sub && !sub2 ) {
509 continue; // neither one can bite
512 // only accept if it didn't fragment
513 // (commening this out allows full fragmentation)
514 if ( c1 > 1 && c2 > 1 ) {
516 FreeBrushList( sub2 );
519 FreeBrushList( sub );
526 FreeBrushList( sub2 );
528 tail = AddBrushListToTail( sub, tail );
529 head = CullList( b1, b1 );
535 FreeBrushList( sub );
537 tail = AddBrushListToTail( sub2, tail );
538 head = CullList( b1, b2 );
543 if ( !b2 ) { // b1 is no longer intersecting anything, so keep it
549 Sys_FPrintf( SYS_VRB, "output brushes: %i\n", CountBrushList( keep ) );
559 bspbrush_t *InitialBrushList( bspbrush_t *list ){
561 bspbrush_t *out, *newb;
564 // only return brushes that have visible faces
566 for ( b = list ; b ; b = b->next )
568 newb = CopyBrush( b );
572 // clear visible, so it must be set by MarkVisibleFaces_r
573 // to be used in the optimized list
574 for ( i = 0 ; i < b->numsides ; i++ )
576 newb->sides[i].original = &b->sides[i];
577 b->sides[i].visible = false;
589 bspbrush_t *OptimizedBrushList( bspbrush_t *list ){
591 bspbrush_t *out, *newb;
594 // only return brushes that have visible faces
596 for ( b = list ; b ; b = b->next )
598 for ( i = 0 ; i < b->numsides ; i++ )
599 if ( b->sides[i].visible ) {
602 if ( i == b->numsides ) {
605 newb = CopyBrush( b );
610 // WriteBrushList ("vis.gl", out, true);