Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

brushbsp.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 
00023 #include "qbsp.h"
00024 #include "l_mem.h"
00025 #include "../botlib/aasfile.h"
00026 #include "aas_store.h"
00027 #include "aas_cfg.h"
00028 
00029 #include <assert.h>
00030 
00031 /*
00032 each side has a count of the other sides it splits
00033 
00034 the best split will be the one that minimizes the total split counts
00035 of all remaining sides
00036 
00037 precalc side on plane table
00038 
00039 evaluate split side
00040 {
00041 cost = 0
00042 for all sides
00043     for all sides
00044         get 
00045         if side splits side and splitside is on same child
00046             cost++;
00047 }
00048 */
00049 
00050 int c_nodes;
00051 int c_nonvis;
00052 int c_active_brushes;
00053 int c_solidleafnodes;
00054 int c_totalsides;
00055 int c_brushmemory;
00056 int c_peak_brushmemory;
00057 int c_nodememory;
00058 int c_peak_totalbspmemory;
00059 
00060 // if a brush just barely pokes onto the other side,
00061 // let it slide by without chopping
00062 #define PLANESIDE_EPSILON   0.001
00063 //0.1
00064 
00065 //#ifdef DEBUG
00066 typedef struct cname_s
00067 {
00068     int value;
00069     char *name;
00070 } cname_t;
00071 
00072 cname_t contentnames[] =
00073 {
00074     {CONTENTS_SOLID,"CONTENTS_SOLID"},
00075     {CONTENTS_WINDOW,"CONTENTS_WINDOW"},
00076     {CONTENTS_AUX,"CONTENTS_AUX"},
00077     {CONTENTS_LAVA,"CONTENTS_LAVA"},
00078     {CONTENTS_SLIME,"CONTENTS_SLIME"},
00079     {CONTENTS_WATER,"CONTENTS_WATER"},
00080     {CONTENTS_MIST,"CONTENTS_MIST"},
00081     {LAST_VISIBLE_CONTENTS,"LAST_VISIBLE_CONTENTS"},
00082 
00083     {CONTENTS_AREAPORTAL,"CONTENTS_AREAPORTAL"},
00084     {CONTENTS_PLAYERCLIP,"CONTENTS_PLAYERCLIP"},
00085     {CONTENTS_MONSTERCLIP,"CONTENTS_MONSTERCLIP"},
00086     {CONTENTS_CURRENT_0,"CONTENTS_CURRENT_0"},
00087     {CONTENTS_CURRENT_90,"CONTENTS_CURRENT_90"},
00088     {CONTENTS_CURRENT_180,"CONTENTS_CURRENT_180"},
00089     {CONTENTS_CURRENT_270,"CONTENTS_CURRENT_270"},
00090     {CONTENTS_CURRENT_UP,"CONTENTS_CURRENT_UP"},
00091     {CONTENTS_CURRENT_DOWN,"CONTENTS_CURRENT_DOWN"},
00092     {CONTENTS_ORIGIN,"CONTENTS_ORIGIN"},
00093     {CONTENTS_MONSTER,"CONTENTS_MONSTER"},
00094     {CONTENTS_DEADMONSTER,"CONTENTS_DEADMONSTER"},
00095     {CONTENTS_DETAIL,"CONTENTS_DETAIL"},
00096     {CONTENTS_Q2TRANSLUCENT,"CONTENTS_TRANSLUCENT"},
00097     {CONTENTS_LADDER,"CONTENTS_LADDER"},
00098     {0, 0}
00099 };
00100 
00101 void PrintContents(int contents)
00102 {
00103     int i;
00104 
00105     for (i = 0; contentnames[i].value; i++)
00106     {
00107         if (contents & contentnames[i].value)
00108         {
00109             Log_Write("%s,", contentnames[i].name);
00110         } //end if
00111     } //end for
00112 } //end of the function PrintContents
00113 
00114 //#endif DEBUG
00115 
00116 //===========================================================================
00117 //
00118 // Parameter:           -
00119 // Returns:             -
00120 // Changes Globals:     -
00121 //===========================================================================
00122 void ResetBrushBSP(void)
00123 {
00124     c_nodes = 0;
00125     c_nonvis = 0;
00126     c_active_brushes = 0;
00127     c_solidleafnodes = 0;
00128     c_totalsides = 0;
00129     c_brushmemory = 0;
00130     c_peak_brushmemory = 0;
00131     c_nodememory = 0;
00132     c_peak_totalbspmemory = 0;
00133 } //end of the function ResetBrushBSP
00134 //===========================================================================
00135 //
00136 // Parameter:           -
00137 // Returns:             -
00138 // Changes Globals:     -
00139 //===========================================================================
00140 void FindBrushInTree (node_t *node, int brushnum)
00141 {
00142     bspbrush_t  *b;
00143 
00144     if (node->planenum == PLANENUM_LEAF)
00145     {
00146         for (b=node->brushlist ; b ; b=b->next)
00147             if (b->original->brushnum == brushnum)
00148                 Log_Print ("here\n");
00149         return;
00150     }
00151     FindBrushInTree(node->children[0], brushnum);
00152     FindBrushInTree(node->children[1], brushnum);
00153 } //end of the function FindBrushInTree
00154 //===========================================================================
00155 //
00156 // Parameter:           -
00157 // Returns:             -
00158 // Changes Globals:     -
00159 //===========================================================================
00160 void DrawBrushList (bspbrush_t *brush, node_t *node)
00161 {
00162     int     i;
00163     side_t  *s;
00164 
00165     GLS_BeginScene ();
00166     for ( ; brush ; brush=brush->next)
00167     {
00168         for (i=0 ; i<brush->numsides ; i++)
00169         {
00170             s = &brush->sides[i];
00171             if (!s->winding)
00172                 continue;
00173             if (s->texinfo == TEXINFO_NODE)
00174                 GLS_Winding (s->winding, 1);
00175             else if (!(s->flags & SFL_VISIBLE))
00176                 GLS_Winding (s->winding, 2);
00177             else
00178                 GLS_Winding (s->winding, 0);
00179         }
00180     }
00181     GLS_EndScene ();
00182 } //end of the function DrawBrushList
00183 //===========================================================================
00184 //
00185 // Parameter:           -
00186 // Returns:             -
00187 // Changes Globals:     -
00188 //===========================================================================
00189 void WriteBrushList (char *name, bspbrush_t *brush, qboolean onlyvis)
00190 {
00191     int     i;
00192     side_t  *s;
00193     FILE    *f;
00194 
00195     qprintf ("writing %s\n", name);
00196     f = SafeOpenWrite (name);
00197 
00198     for ( ; brush ; brush=brush->next)
00199     {
00200         for (i=0 ; i<brush->numsides ; i++)
00201         {
00202             s = &brush->sides[i];
00203             if (!s->winding)
00204                 continue;
00205             if (onlyvis && !(s->flags & SFL_VISIBLE))
00206                 continue;
00207             OutputWinding (brush->sides[i].winding, f);
00208         }
00209     }
00210 
00211     fclose (f);
00212 } //end of the function WriteBrushList
00213 //===========================================================================
00214 //
00215 // Parameter:           -
00216 // Returns:             -
00217 // Changes Globals:     -
00218 //===========================================================================
00219 void PrintBrush (bspbrush_t *brush)
00220 {
00221     int     i;
00222 
00223     printf ("brush: %p\n", brush);
00224     for (i=0;i<brush->numsides ; i++)
00225     {
00226         pw(brush->sides[i].winding);
00227         printf ("\n");
00228     } //end for
00229 } //end of the function PrintBrush
00230 //===========================================================================
00231 // Sets the mins/maxs based on the windings
00232 //
00233 // Parameter:           -
00234 // Returns:             -
00235 // Changes Globals:     -
00236 //===========================================================================
00237 void BoundBrush (bspbrush_t *brush)
00238 {
00239     int         i, j;
00240     winding_t   *w;
00241 
00242     ClearBounds (brush->mins, brush->maxs);
00243     for (i=0 ; i<brush->numsides ; i++)
00244     {
00245         w = brush->sides[i].winding;
00246         if (!w)
00247             continue;
00248         for (j=0 ; j<w->numpoints ; j++)
00249             AddPointToBounds (w->p[j], brush->mins, brush->maxs);
00250     }
00251 } //end of the function BoundBrush
00252 //===========================================================================
00253 //
00254 // Parameter:           -
00255 // Returns:             -
00256 // Changes Globals:     -
00257 //===========================================================================
00258 void CreateBrushWindings (bspbrush_t *brush)
00259 {
00260     int         i, j;
00261     winding_t   *w;
00262     side_t      *side;
00263     plane_t     *plane;
00264 
00265     for (i=0 ; i<brush->numsides ; i++)
00266     {
00267         side = &brush->sides[i];
00268         plane = &mapplanes[side->planenum];
00269         w = BaseWindingForPlane (plane->normal, plane->dist);
00270         for (j=0 ; j<brush->numsides && w; j++)
00271         {
00272             if (i == j)
00273                 continue;
00274             if (brush->sides[j].flags & SFL_BEVEL)
00275                 continue;
00276             plane = &mapplanes[brush->sides[j].planenum^1];
00277             ChopWindingInPlace (&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
00278         }
00279 
00280         side->winding = w;
00281     }
00282 
00283     BoundBrush (brush);
00284 } //end of the function CreateBrushWindings
00285 //===========================================================================
00286 // Creates a new axial brush
00287 //
00288 // Parameter:           -
00289 // Returns:             -
00290 // Changes Globals:     -
00291 //===========================================================================
00292 bspbrush_t  *BrushFromBounds (vec3_t mins, vec3_t maxs)
00293 {
00294     bspbrush_t *b;
00295     int i;
00296     vec3_t normal;
00297     vec_t dist;
00298 
00299     b = AllocBrush (6);
00300     b->numsides = 6;
00301     for (i=0 ; i<3 ; i++)
00302     {
00303         VectorClear (normal);
00304         normal[i] = 1;
00305         dist = maxs[i];
00306         b->sides[i].planenum = FindFloatPlane (normal, dist);
00307 
00308         normal[i] = -1;
00309         dist = -mins[i];
00310         b->sides[3+i].planenum = FindFloatPlane (normal, dist);
00311     }
00312 
00313     CreateBrushWindings (b);
00314 
00315     return b;
00316 } //end of the function BrushFromBounds
00317 //===========================================================================
00318 //
00319 // Parameter:           -
00320 // Returns:             -
00321 // Changes Globals:     -
00322 //===========================================================================
00323 int BrushOutOfBounds(bspbrush_t *brush, vec3_t mins, vec3_t maxs, float epsilon)
00324 {
00325     int i, j, n;
00326     winding_t *w;
00327     side_t *side;
00328 
00329     for (i = 0; i < brush->numsides; i++)
00330     {
00331         side = &brush->sides[i];
00332         w = side->winding;
00333         for (j = 0; j < w->numpoints; j++)
00334         {
00335             for (n = 0; n < 3; n++)
00336             {
00337                 if (w->p[j][n] < (mins[n] + epsilon) || w->p[j][n] > (maxs[n] - epsilon)) return true;
00338             } //end for
00339         } //end for
00340     } //end for
00341     return false;
00342 } //end of the function BrushOutOfBounds
00343 //===========================================================================
00344 //
00345 // Parameter:           -
00346 // Returns:             -
00347 // Changes Globals:     -
00348 //===========================================================================
00349 vec_t BrushVolume (bspbrush_t *brush)
00350 {
00351     int i;
00352     winding_t *w;
00353     vec3_t corner;
00354     vec_t d, area, volume;
00355     plane_t *plane;
00356 
00357     if (!brush) return 0;
00358 
00359     // grab the first valid point as the corner
00360     w = NULL;
00361     for (i = 0; i < brush->numsides; i++)
00362     {
00363         w = brush->sides[i].winding;
00364         if (w) break;
00365     } //end for
00366     if (!w) return 0;
00367     VectorCopy (w->p[0], corner);
00368 
00369     // make tetrahedrons to all other faces
00370     volume = 0;
00371     for ( ; i < brush->numsides; i++)
00372     {
00373         w = brush->sides[i].winding;
00374         if (!w) continue;
00375         plane = &mapplanes[brush->sides[i].planenum];
00376         d = -(DotProduct (corner, plane->normal) - plane->dist);
00377         area = WindingArea(w);
00378         volume += d * area;
00379     } //end for
00380 
00381     volume /= 3;
00382     return volume;
00383 } //end of the function BrushVolume
00384 //===========================================================================
00385 //
00386 // Parameter:           -
00387 // Returns:             -
00388 // Changes Globals:     -
00389 //===========================================================================
00390 int CountBrushList (bspbrush_t *brushes)
00391 {
00392     int c;
00393 
00394     c = 0;
00395     for ( ; brushes; brushes = brushes->next) c++;
00396     return c;
00397 } //end of the function CountBrushList
00398 //===========================================================================
00399 //
00400 // Parameter:           -
00401 // Returns:             -
00402 // Changes Globals:     -
00403 //===========================================================================
00404 node_t *AllocNode (void)
00405 {
00406     node_t  *node;
00407 
00408     node = GetMemory(sizeof(*node));
00409     memset (node, 0, sizeof(*node));
00410     if (numthreads == 1)
00411     {
00412         c_nodememory += MemorySize(node);
00413     } //end if
00414     return node;
00415 } //end of the function AllocNode
00416 //===========================================================================
00417 //
00418 // Parameter:           -
00419 // Returns:             -
00420 // Changes Globals:     -
00421 //===========================================================================
00422 bspbrush_t *AllocBrush (int numsides)
00423 {
00424     bspbrush_t  *bb;
00425     int         c;
00426 
00427     c = (int)&(((bspbrush_t *)0)->sides[numsides]);
00428     bb = GetMemory(c);
00429     memset (bb, 0, c);
00430     if (numthreads == 1)
00431     {
00432         c_active_brushes++;
00433         c_brushmemory += MemorySize(bb);
00434         if (c_brushmemory > c_peak_brushmemory)
00435                 c_peak_brushmemory = c_brushmemory;
00436     } //end if
00437     return bb;
00438 } //end of the function AllocBrush
00439 //===========================================================================
00440 //
00441 // Parameter:           -
00442 // Returns:             -
00443 // Changes Globals:     -
00444 //===========================================================================
00445 void FreeBrush (bspbrush_t *brushes)
00446 {
00447     int         i;
00448 
00449     for (i=0 ; i<brushes->numsides ; i++)
00450         if (brushes->sides[i].winding)
00451             FreeWinding(brushes->sides[i].winding);
00452     if (numthreads == 1)
00453     {
00454         c_active_brushes--;
00455         c_brushmemory -= MemorySize(brushes);
00456         if (c_brushmemory < 0) c_brushmemory = 0;
00457     } //end if
00458     FreeMemory(brushes);
00459 } //end of the function FreeBrush
00460 //===========================================================================
00461 //
00462 // Parameter:           -
00463 // Returns:             -
00464 // Changes Globals:     -
00465 //===========================================================================
00466 void FreeBrushList (bspbrush_t *brushes)
00467 {
00468     bspbrush_t  *next;
00469 
00470     for ( ; brushes; brushes = next)
00471     {
00472         next = brushes->next;
00473 
00474         FreeBrush(brushes);
00475     } //end for
00476 } //end of the function FreeBrushList
00477 //===========================================================================
00478 // Duplicates the brush, the sides, and the windings
00479 //
00480 // Parameter:           -
00481 // Returns:             -
00482 // Changes Globals:     -
00483 //===========================================================================
00484 bspbrush_t *CopyBrush (bspbrush_t *brush)
00485 {
00486     bspbrush_t *newbrush;
00487     int         size;
00488     int         i;
00489     
00490     size = (int)&(((bspbrush_t *)0)->sides[brush->numsides]);
00491 
00492     newbrush = AllocBrush (brush->numsides);
00493     memcpy (newbrush, brush, size);
00494 
00495     for (i=0 ; i<brush->numsides ; i++)
00496     {
00497         if (brush->sides[i].winding)
00498             newbrush->sides[i].winding = CopyWinding (brush->sides[i].winding);
00499     }
00500 
00501     return newbrush;
00502 } //end of the function CopyBrush
00503 //===========================================================================
00504 //
00505 // Parameter:           -
00506 // Returns:             -
00507 // Changes Globals:     -
00508 //===========================================================================
00509 node_t *PointInLeaf (node_t *node, vec3_t point)
00510 {
00511     vec_t       d;
00512     plane_t     *plane;
00513 
00514     while (node->planenum != PLANENUM_LEAF)
00515     {
00516         plane = &mapplanes[node->planenum];
00517         d = DotProduct (point, plane->normal) - plane->dist;
00518         if (d > 0)
00519             node = node->children[0];
00520         else
00521             node = node->children[1];
00522     }
00523 
00524     return node;
00525 } //end of the function PointInLeaf
00526 //===========================================================================
00527 // Returns PSIDE_FRONT, PSIDE_BACK, or PSIDE_BOTH
00528 //
00529 // Parameter:           -
00530 // Returns:             -
00531 // Changes Globals:     -
00532 //===========================================================================
00533 #if 0
00534 int BoxOnPlaneSide (vec3_t mins, vec3_t maxs, plane_t *plane)
00535 {
00536     int     side;
00537     int     i;
00538     vec3_t  corners[2];
00539     vec_t   dist1, dist2;
00540 
00541     // axial planes are easy
00542     if (plane->type < 3)
00543     {
00544         side = 0;
00545         if (maxs[plane->type] > plane->dist+PLANESIDE_EPSILON)
00546             side |= PSIDE_FRONT;
00547         if (mins[plane->type] < plane->dist-PLANESIDE_EPSILON)
00548             side |= PSIDE_BACK;
00549         return side;
00550     }
00551 
00552     // create the proper leading and trailing verts for the box
00553 
00554     for (i=0 ; i<3 ; i++)
00555     {
00556         if (plane->normal[i] < 0)
00557         {
00558             corners[0][i] = mins[i];
00559             corners[1][i] = maxs[i];
00560         }
00561         else
00562         {
00563             corners[1][i] = mins[i];
00564             corners[0][i] = maxs[i];
00565         }
00566     }
00567 
00568     dist1 = DotProduct (plane->normal, corners[0]) - plane->dist;
00569     dist2 = DotProduct (plane->normal, corners[1]) - plane->dist;
00570     side = 0;
00571     if (dist1 >= PLANESIDE_EPSILON)
00572         side = PSIDE_FRONT;
00573     if (dist2 < PLANESIDE_EPSILON)
00574         side |= PSIDE_BACK;
00575 
00576     return side;
00577 }
00578 #else
00579 int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, plane_t *p)
00580 {
00581     float   dist1, dist2;
00582     int sides;
00583 
00584     // axial planes are easy
00585     if (p->type < 3)
00586     {
00587         sides = 0;
00588         if (emaxs[p->type] > p->dist+PLANESIDE_EPSILON) sides |= PSIDE_FRONT;
00589         if (emins[p->type] < p->dist-PLANESIDE_EPSILON) sides |= PSIDE_BACK;
00590         return sides;
00591     } //end if
00592     
00593 // general case
00594     switch (p->signbits)
00595     {
00596     case 0:
00597         dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
00598         dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
00599         break;
00600     case 1:
00601         dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
00602         dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
00603         break;
00604     case 2:
00605         dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
00606         dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
00607         break;
00608     case 3:
00609         dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
00610         dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
00611         break;
00612     case 4:
00613         dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
00614         dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
00615         break;
00616     case 5:
00617         dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
00618         dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
00619         break;
00620     case 6:
00621         dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
00622         dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
00623         break;
00624     case 7:
00625         dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
00626         dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
00627         break;
00628     default:
00629         dist1 = dist2 = 0;      // shut up compiler
00630 //      assert( 0 );
00631         break;
00632     }
00633 
00634     sides = 0;
00635     if (dist1 - p->dist >= PLANESIDE_EPSILON) sides = PSIDE_FRONT;
00636     if (dist2 - p->dist < PLANESIDE_EPSILON) sides |= PSIDE_BACK;
00637 
00638 //  assert(sides != 0);
00639 
00640     return sides;
00641 }
00642 #endif
00643 //===========================================================================
00644 //
00645 // Parameter:           -
00646 // Returns:             -
00647 // Changes Globals:     -
00648 //===========================================================================
00649 int QuickTestBrushToPlanenum (bspbrush_t *brush, int planenum, int *numsplits)
00650 {
00651     int i, num;
00652     plane_t *plane;
00653     int s;
00654 
00655     *numsplits = 0;
00656 
00657     plane = &mapplanes[planenum];
00658 
00659 #ifdef ME
00660     //fast axial cases
00661     if (plane->type < 3)
00662     {
00663         if (plane->dist + PLANESIDE_EPSILON < brush->mins[plane->type])
00664             return PSIDE_FRONT;
00665         if (plane->dist - PLANESIDE_EPSILON > brush->maxs[plane->type])
00666             return PSIDE_BACK;
00667     } //end if
00668 #endif //ME*/
00669 
00670     // if the brush actually uses the planenum,
00671     // we can tell the side for sure
00672     for (i = 0; i < brush->numsides; i++)
00673     {
00674         num = brush->sides[i].planenum;
00675         if (num >= MAX_MAPFILE_PLANES)
00676             Error ("bad planenum");
00677         if (num == planenum)
00678             return PSIDE_BACK|PSIDE_FACING;
00679         if (num == (planenum ^ 1) )
00680             return PSIDE_FRONT|PSIDE_FACING;
00681 
00682     }
00683 
00684     // box on plane side
00685     s = BoxOnPlaneSide (brush->mins, brush->maxs, plane);
00686 
00687     // if both sides, count the visible faces split
00688     if (s == PSIDE_BOTH)
00689     {
00690         *numsplits += 3;
00691     }
00692 
00693     return s;
00694 } //end of the function QuickTestBrushToPlanenum
00695 //===========================================================================
00696 //
00697 // Parameter:           -
00698 // Returns:             -
00699 // Changes Globals:     -
00700 //===========================================================================
00701 int TestBrushToPlanenum (bspbrush_t *brush, int planenum,
00702                          int *numsplits, qboolean *hintsplit, int *epsilonbrush)
00703 {
00704     int i, j, num;
00705     plane_t *plane;
00706     int s = 0;
00707     winding_t *w;
00708     vec_t d, d_front, d_back;
00709     int front, back;
00710     int type;
00711     float dist;
00712 
00713     *numsplits = 0;
00714     *hintsplit = false;
00715 
00716     plane = &mapplanes[planenum];
00717 
00718 #ifdef ME
00719     //fast axial cases
00720     type = plane->type;
00721     if (type < 3)
00722     {
00723         dist = plane->dist;
00724         if (dist + PLANESIDE_EPSILON < brush->mins[type]) return PSIDE_FRONT;
00725         if (dist - PLANESIDE_EPSILON > brush->maxs[type]) return PSIDE_BACK;
00726         if (brush->mins[type] < dist - PLANESIDE_EPSILON &&
00727                     brush->maxs[type] > dist + PLANESIDE_EPSILON) s = PSIDE_BOTH;
00728     } //end if
00729 
00730     if (s != PSIDE_BOTH)
00731 #endif //ME
00732     {
00733         // if the brush actually uses the planenum,
00734         // we can tell the side for sure
00735         for (i = 0; i < brush->numsides; i++)
00736         {
00737             num = brush->sides[i].planenum;
00738             if (num >= MAX_MAPFILE_PLANES) Error ("bad planenum");
00739             if (num == planenum)
00740             {
00741                 //we don't need to test this side plane again
00742                 brush->sides[i].flags |= SFL_TESTED;
00743                 return PSIDE_BACK|PSIDE_FACING;
00744             } //end if
00745             if (num == (planenum ^ 1) )
00746             {
00747                 //we don't need to test this side plane again
00748                 brush->sides[i].flags |= SFL_TESTED;
00749                 return PSIDE_FRONT|PSIDE_FACING;
00750             } //end if
00751         } //end for
00752 
00753         // box on plane side
00754         s = BoxOnPlaneSide (brush->mins, brush->maxs, plane);
00755 
00756         if (s != PSIDE_BOTH) return s;
00757     } //end if
00758 
00759     // if both sides, count the visible faces split
00760     d_front = d_back = 0;
00761 
00762     for (i = 0; i < brush->numsides; i++)
00763     {
00764         if (brush->sides[i].texinfo == TEXINFO_NODE)
00765             continue;       // on node, don't worry about splits
00766         if (!(brush->sides[i].flags & SFL_VISIBLE))
00767             continue;       // we don't care about non-visible
00768         w = brush->sides[i].winding;
00769         if (!w) continue;
00770         front = back = 0;
00771         for (j = 0; j < w->numpoints; j++)
00772         {
00773             d = DotProduct(w->p[j], plane->normal) - plane->dist;
00774             if (d > d_front) d_front = d;
00775             if (d < d_back) d_back = d;
00776             if (d > 0.1) // PLANESIDE_EPSILON)
00777                 front = 1;
00778             if (d < -0.1) // PLANESIDE_EPSILON)
00779                 back = 1;
00780         } //end for
00781         if (front && back)
00782         {
00783             if ( !(brush->sides[i].surf & SURF_SKIP) )
00784             {
00785                 (*numsplits)++;
00786                 if (brush->sides[i].surf & SURF_HINT)
00787                 {
00788                     *hintsplit = true;
00789                 } //end if
00790             } //end if
00791         } //end if
00792     } //end for
00793 
00794     if ( (d_front > 0.0 && d_front < 1.0)
00795         || (d_back < 0.0 && d_back > -1.0) )
00796         (*epsilonbrush)++;
00797 
00798 #if 0
00799     if (*numsplits == 0)
00800     {   //  didn't really need to be split
00801         if (front) s = PSIDE_FRONT;
00802         else if (back) s = PSIDE_BACK;
00803         else s = 0;
00804     }
00805 #endif
00806 
00807     return s;
00808 } //end of the function TestBrushToPlanenum
00809 //===========================================================================
00810 // Returns true if the winding would be crunched out of
00811 // existance by the vertex snapping.
00812 //
00813 // Parameter:           -
00814 // Returns:             -
00815 // Changes Globals:     -
00816 //===========================================================================
00817 #define EDGE_LENGTH 0.2
00818 qboolean WindingIsTiny (winding_t *w)
00819 {
00820 #if 0
00821     if (WindingArea (w) < 1)
00822         return true;
00823     return false;
00824 #else
00825     int     i, j;
00826     vec_t   len;
00827     vec3_t  delta;
00828     int     edges;
00829 
00830     edges = 0;
00831     for (i=0 ; i<w->numpoints ; i++)
00832     {
00833         j = i == w->numpoints - 1 ? 0 : i+1;
00834         VectorSubtract (w->p[j], w->p[i], delta);
00835         len = VectorLength (delta);
00836         if (len > EDGE_LENGTH)
00837         {
00838             if (++edges == 3)
00839                 return false;
00840         }
00841     }
00842     return true;
00843 #endif
00844 } //end of the function WindingIsTiny
00845 //===========================================================================
00846 // Returns true if the winding still has one of the points
00847 // from basewinding for plane
00848 //
00849 // Parameter:           -
00850 // Returns:             -
00851 // Changes Globals:     -
00852 //===========================================================================
00853 qboolean WindingIsHuge (winding_t *w)
00854 {
00855     int     i, j;
00856 
00857     for (i=0 ; i<w->numpoints ; i++)
00858     {
00859         for (j=0 ; j<3 ; j++)
00860             if (w->p[i][j] < -BOGUS_RANGE+1 || w->p[i][j] > BOGUS_RANGE-1)
00861                 return true;
00862     }
00863     return false;
00864 } //end of the function WindingIsHuge
00865 //===========================================================================
00866 // creates a leaf out of the given nodes with the given brushes
00867 //
00868 // Parameter:           -
00869 // Returns:             -
00870 // Changes Globals:     -
00871 //===========================================================================
00872 void LeafNode(node_t *node, bspbrush_t *brushes)
00873 {
00874     bspbrush_t *b;
00875     int i;
00876 
00877     node->side = NULL;
00878     node->planenum = PLANENUM_LEAF;
00879     node->contents = 0;
00880 
00881     for (b = brushes; b; b = b->next)
00882     {
00883         // if the brush is solid and all of its sides are on nodes,
00884         // it eats everything
00885         if (b->original->contents & CONTENTS_SOLID)
00886         {
00887             for (i=0 ; i<b->numsides ; i++)
00888                 if (b->sides[i].texinfo != TEXINFO_NODE)
00889                     break;
00890             if (i == b->numsides)
00891             {
00892                 node->contents = CONTENTS_SOLID;
00893                 break;
00894             } //end if
00895         } //end if
00896         node->contents |= b->original->contents;
00897     } //end for
00898 
00899     if (create_aas)
00900     {
00901         node->expansionbboxes = 0;
00902         node->contents = 0;
00903         for (b = brushes; b; b = b->next)
00904         {
00905             node->expansionbboxes |= b->original->expansionbbox;
00906             node->contents |= b->original->contents;
00907             if (b->original->modelnum)
00908                 node->modelnum = b->original->modelnum;
00909         } //end for
00910         if (node->contents & CONTENTS_SOLID)
00911         {
00912             if (node->expansionbboxes != cfg.allpresencetypes)
00913             {
00914                 node->contents &= ~CONTENTS_SOLID;
00915             } //end if
00916         } //end if
00917     } //end if
00918 
00919     node->brushlist = brushes;
00920 } //end of the function LeafNode
00921 //===========================================================================
00922 //
00923 // Parameter:           -
00924 // Returns:             -
00925 // Changes Globals:     -
00926 //===========================================================================
00927 void CheckPlaneAgainstParents (int pnum, node_t *node)
00928 {
00929     node_t  *p;
00930 
00931     for (p = node->parent; p; p = p->parent)
00932     {
00933         if (p->planenum == pnum) Error("Tried parent");
00934     } //end for
00935 } //end of the function CheckPlaneAgainstParants
00936 //===========================================================================
00937 //
00938 // Parameter:           -
00939 // Returns:             -
00940 // Changes Globals:     -
00941 //===========================================================================
00942 qboolean CheckPlaneAgainstVolume (int pnum, node_t *node)
00943 {
00944     bspbrush_t  *front, *back;
00945     qboolean    good;
00946 
00947     SplitBrush (node->volume, pnum, &front, &back);
00948 
00949     good = (front && back);
00950 
00951     if (front) FreeBrush (front);
00952     if (back) FreeBrush (back);
00953 
00954     return good;
00955 } //end of the function CheckPlaneAgaintsVolume
00956 //===========================================================================
00957 // Using a hueristic, choses one of the sides out of the brushlist
00958 // to partition the brushes with.
00959 // Returns NULL if there are no valid planes to split with..
00960 //
00961 // Parameter:           -
00962 // Returns:             -
00963 // Changes Globals:     -
00964 //===========================================================================
00965 side_t *SelectSplitSide (bspbrush_t *brushes, node_t *node)
00966 {
00967     int         value, bestvalue;
00968     bspbrush_t  *brush, *test;
00969     side_t      *side, *bestside;
00970     int         i, pass, numpasses;
00971     int         pnum;
00972     int         s;
00973     int         front, back, both, facing, splits;
00974     int         bsplits;
00975     int         bestsplits;
00976     int         epsilonbrush;
00977     qboolean    hintsplit = false;
00978 
00979     bestside = NULL;
00980     bestvalue = -99999;
00981     bestsplits = 0;
00982 
00983     // the search order goes: visible-structural, visible-detail,
00984     // nonvisible-structural, nonvisible-detail.
00985     // If any valid plane is available in a pass, no further
00986     // passes will be tried.
00987     numpasses = 2;
00988     for (pass = 0; pass < numpasses; pass++)
00989     {
00990         for (brush = brushes; brush; brush = brush->next)
00991         {
00992             // only check detail the second pass
00993 //          if ( (pass & 1) && !(brush->original->contents & CONTENTS_DETAIL) )
00994 //              continue;
00995 //          if ( !(pass & 1) && (brush->original->contents & CONTENTS_DETAIL) )
00996 //              continue;
00997             for (i = 0; i < brush->numsides; i++)
00998             {
00999                 side = brush->sides + i;
01000 //              if (side->flags & SFL_BEVEL)
01001 //                  continue;   // never use a bevel as a spliter
01002                 if (!side->winding)
01003                     continue;   // nothing visible, so it can't split
01004                 if (side->texinfo == TEXINFO_NODE)
01005                     continue;   // allready a node splitter
01006                 if (side->flags & SFL_TESTED)
01007                     continue;   // we allready have metrics for this plane
01008 //              if (side->surf & SURF_SKIP)
01009 //                  continue;   // skip surfaces are never chosen
01010 
01011 //              if (!(side->flags & SFL_VISIBLE) && (pass < 2))
01012 //                  continue;   // only check visible faces on first pass
01013 
01014                 if ((side->flags & SFL_CURVE) && (pass < 1))
01015                     continue;   // only check curves the second pass
01016 
01017                 pnum = side->planenum;
01018                 pnum &= ~1; // allways use positive facing plane
01019 
01020                 CheckPlaneAgainstParents (pnum, node);
01021 
01022                 if (!CheckPlaneAgainstVolume (pnum, node))
01023                     continue;   // would produce a tiny volume
01024 
01025                 front = 0;
01026                 back = 0;
01027                 both = 0;
01028                 facing = 0;
01029                 splits = 0;
01030                 epsilonbrush = 0;
01031 
01032                  //inner loop: optimize
01033                 for (test = brushes; test; test = test->next)
01034                 {
01035                     s = TestBrushToPlanenum (test, pnum, &bsplits, &hintsplit, &epsilonbrush);
01036 
01037                     splits += bsplits;
01038 //                  if (bsplits && (s&PSIDE_FACING) )
01039 //                      Error ("PSIDE_FACING with splits");
01040 
01041                     test->testside = s;
01042                     //
01043                     if (s & PSIDE_FACING) facing++;
01044                     if (s & PSIDE_FRONT) front++;
01045                     if (s & PSIDE_BACK) back++;
01046                     if (s == PSIDE_BOTH) both++;
01047                 } //end for
01048 
01049                 // give a value estimate for using this plane
01050                 value =  5*facing - 5*splits - abs(front-back);
01051 //                  value =  -5*splits;
01052 //                  value =  5*facing - 5*splits;
01053                 if (mapplanes[pnum].type < 3)
01054                     value+=5;       // axial is better
01055 
01056                 value -= epsilonbrush * 1000;   // avoid!
01057 
01058                 // never split a hint side except with another hint
01059                 if (hintsplit && !(side->surf & SURF_HINT) )
01060                     value = -9999999;
01061 
01062                 // save off the side test so we don't need
01063                 // to recalculate it when we actually seperate
01064                 // the brushes
01065                 if (value > bestvalue)
01066                 {
01067                     bestvalue = value;
01068                     bestside = side;
01069                     bestsplits = splits;
01070                     for (test = brushes; test ; test = test->next)
01071                         test->side = test->testside;
01072                 } //end if
01073             } //end for
01074         } //end for (brush = brushes;
01075 
01076         // if we found a good plane, don't bother trying any
01077         // other passes
01078         if (bestside)
01079         {
01080             if (pass > 1)
01081             {
01082                 if (numthreads == 1) c_nonvis++;
01083             }
01084             if (pass > 0) node->detail_seperator = true;    // not needed for vis
01085             break;
01086         } //end if
01087     } //end for (pass = 0;
01088 
01089     //
01090     // clear all the tested flags we set
01091     //
01092     for (brush = brushes ; brush ; brush=brush->next)
01093     {
01094         for (i = 0; i < brush->numsides; i++)
01095         {
01096             brush->sides[i].flags &= ~SFL_TESTED;
01097         } //end for
01098     } //end for
01099 
01100     return bestside;
01101 } //end of the function SelectSplitSide
01102 //===========================================================================
01103 //
01104 // Parameter:           -
01105 // Returns:             -
01106 // Changes Globals:     -
01107 //===========================================================================
01108 int BrushMostlyOnSide (bspbrush_t *brush, plane_t *plane)
01109 {
01110     int         i, j;
01111     winding_t   *w;
01112     vec_t       d, max;
01113     int         side;
01114 
01115     max = 0;
01116     side = PSIDE_FRONT;
01117     for (i=0 ; i<brush->numsides ; i++)
01118     {
01119         w = brush->sides[i].winding;
01120         if (!w)
01121             continue;
01122         for (j=0 ; j<w->numpoints ; j++)
01123         {
01124             d = DotProduct (w->p[j], plane->normal) - plane->dist;
01125             if (d > max)
01126             {
01127                 max = d;
01128                 side = PSIDE_FRONT;
01129             }
01130             if (-d > max)
01131             {
01132                 max = -d;
01133                 side = PSIDE_BACK;
01134             }
01135         }
01136     }
01137     return side;
01138 } //end of the function BrushMostlyOnSide
01139 //===========================================================================
01140 // Generates two new brushes, leaving the original
01141 // unchanged
01142 //
01143 // Parameter:           -
01144 // Returns:             -
01145 // Changes Globals:     -
01146 //===========================================================================
01147 void SplitBrush (bspbrush_t *brush, int planenum,
01148     bspbrush_t **front, bspbrush_t **back)
01149 {
01150     bspbrush_t  *b[2];
01151     int         i, j;
01152     winding_t   *w, *cw[2], *midwinding;
01153     plane_t     *plane, *plane2;
01154     side_t      *s, *cs;
01155     float d, d_front, d_back;
01156 
01157     *front = *back = NULL;
01158     plane = &mapplanes[planenum];
01159 
01160     // check all points
01161     d_front = d_back = 0;
01162     for (i=0 ; i<brush->numsides ; i++)
01163     {
01164         w = brush->sides[i].winding;
01165         if (!w)
01166             continue;
01167         for (j=0 ; j<w->numpoints ; j++)
01168         {
01169             d = DotProduct (w->p[j], plane->normal) - plane->dist;
01170             if (d > 0 && d > d_front)
01171                 d_front = d;
01172             if (d < 0 && d < d_back)
01173                 d_back = d;
01174         }
01175     }
01176 
01177     if (d_front < 0.2) // PLANESIDE_EPSILON)
01178     {   // only on back
01179         *back = CopyBrush (brush);
01180         return;
01181     }
01182     if (d_back > -0.2) // PLANESIDE_EPSILON)
01183     {   // only on front
01184         *front = CopyBrush (brush);
01185         return;
01186     }
01187 
01188     // create a new winding from the split plane
01189 
01190     w = BaseWindingForPlane (plane->normal, plane->dist);
01191     for (i=0 ; i<brush->numsides && w ; i++)
01192     {
01193         plane2 = &mapplanes[brush->sides[i].planenum ^ 1];
01194         ChopWindingInPlace (&w, plane2->normal, plane2->dist, 0); // PLANESIDE_EPSILON);
01195     }
01196 
01197     if (!w || WindingIsTiny(w))
01198     {   // the brush isn't really split
01199         int     side;
01200 
01201         side = BrushMostlyOnSide (brush, plane);
01202         if (side == PSIDE_FRONT)
01203             *front = CopyBrush (brush);
01204         if (side == PSIDE_BACK)
01205             *back = CopyBrush (brush);
01206         //free a possible winding
01207         if (w) FreeWinding(w);
01208         return;
01209     }
01210 
01211     if (WindingIsHuge (w))
01212     {
01213         Log_Write("WARNING: huge winding\n");
01214     }
01215 
01216     midwinding = w;
01217 
01218     // split it for real
01219 
01220     for (i=0 ; i<2 ; i++)
01221     {
01222         b[i] = AllocBrush (brush->numsides+1);
01223         b[i]->original = brush->original;
01224     }
01225 
01226     // split all the current windings
01227 
01228     for (i=0 ; i<brush->numsides ; i++)
01229     {
01230         s = &brush->sides[i];
01231         w = s->winding;
01232         if (!w)
01233             continue;
01234         ClipWindingEpsilon (w, plane->normal, plane->dist,
01235             0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]);
01236         for (j=0 ; j<2 ; j++)
01237         {
01238             if (!cw[j])
01239                 continue;
01240 #if 0
01241             if (WindingIsTiny (cw[j]))
01242             {
01243                 FreeWinding (cw[j]);
01244                 continue;
01245             }
01246 #endif
01247             cs = &b[j]->sides[b[j]->numsides];
01248             b[j]->numsides++;
01249             *cs = *s;
01250 //          cs->planenum = s->planenum;
01251 //          cs->texinfo = s->texinfo;
01252 //          cs->original = s->original;
01253             cs->winding = cw[j];
01254             cs->flags &= ~SFL_TESTED;
01255         }
01256     }
01257 
01258 
01259     // see if we have valid polygons on both sides
01260 
01261     for (i=0 ; i<2 ; i++)
01262     {
01263         BoundBrush (b[i]);
01264         for (j=0 ; j<3 ; j++)
01265         {
01266             if (b[i]->mins[j] < -MAX_MAP_BOUNDS || b[i]->maxs[j] > MAX_MAP_BOUNDS)
01267             {
01268                 Log_Write("bogus brush after clip");
01269                 break;
01270             }
01271         }
01272 
01273         if (b[i]->numsides < 3 || j < 3)
01274         {
01275             FreeBrush (b[i]);
01276             b[i] = NULL;
01277         }
01278     }
01279 
01280     if ( !(b[0] && b[1]) )
01281     {
01282         if (!b[0] && !b[1])
01283             Log_Write("split removed brush\r\n");
01284         else
01285             Log_Write("split not on both sides\r\n");
01286         if (b[0])
01287         {
01288             FreeBrush (b[0]);
01289             *front = CopyBrush (brush);
01290         }
01291         if (b[1])
01292         {
01293             FreeBrush (b[1]);
01294             *back = CopyBrush (brush);
01295         }
01296         return;
01297     }
01298 
01299     // add the midwinding to both sides
01300     for (i=0 ; i<2 ; i++)
01301     {
01302         cs = &b[i]->sides[b[i]->numsides];
01303         b[i]->numsides++;
01304 
01305         cs->planenum = planenum^i^1;
01306         cs->texinfo = TEXINFO_NODE; //never use these sides as splitters
01307         cs->flags &= ~SFL_VISIBLE;
01308         cs->flags &= ~SFL_TESTED;
01309         if (i==0)
01310             cs->winding = CopyWinding (midwinding);
01311         else
01312             cs->winding = midwinding;
01313     }
01314 
01315 {
01316     vec_t   v1;
01317     int i;
01318 
01319     for (i = 0; i < 2; i++)
01320     {
01321         v1 = BrushVolume (b[i]);
01322         if (v1 < 1.0)
01323         {
01324             FreeBrush(b[i]);
01325             b[i] = NULL;
01326             //Log_Write("tiny volume after clip");
01327         }
01328     }
01329     if (!b[0] && !b[1])
01330     {
01331         Log_Write("two tiny brushes\r\n");
01332     } //end if
01333 }
01334 
01335     *front = b[0];
01336     *back = b[1];
01337 } //end of the function SplitBrush
01338 //===========================================================================
01339 //
01340 // Parameter:           -
01341 // Returns:             -
01342 // Changes Globals:     -
01343 //===========================================================================
01344 void SplitBrushList (bspbrush_t *brushes, 
01345     node_t *node, bspbrush_t **front, bspbrush_t **back)
01346 {
01347     bspbrush_t  *brush, *newbrush, *newbrush2;
01348     side_t      *side;
01349     int         sides;
01350     int         i;
01351 
01352     *front = *back = NULL;
01353 
01354     for (brush = brushes; brush; brush = brush->next)
01355     {
01356         sides = brush->side;
01357 
01358         if (sides == PSIDE_BOTH)
01359         {   // split into two brushes
01360             SplitBrush (brush, node->planenum, &newbrush, &newbrush2);
01361             if (newbrush)
01362             {
01363                 newbrush->next = *front;
01364                 *front = newbrush;
01365             } //end if
01366             if (newbrush2)
01367             {
01368                 newbrush2->next = *back;
01369                 *back = newbrush2;
01370             } //end if
01371             continue;
01372         } //end if
01373 
01374         newbrush = CopyBrush (brush);
01375 
01376         // if the planenum is actualy a part of the brush
01377         // find the plane and flag it as used so it won't be tried
01378         // as a splitter again
01379         if (sides & PSIDE_FACING)
01380         {
01381