123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872 |
- /*
- ===========================================================================
- Copyright (C) 1999-2005 Id Software, Inc.
- This file is part of Quake III Arena source code.
- Quake III Arena source code 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.
- Quake III Arena source code 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.
- You should have received a copy of the GNU General Public License
- along with Foobar; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- ===========================================================================
- */
- #include "qbsp.h"
- #include "l_mem.h"
- #include "../botlib/aasfile.h"
- #include "aas_store.h"
- #include "aas_cfg.h"
- #include <assert.h>
- /*
- each side has a count of the other sides it splits
- the best split will be the one that minimizes the total split counts
- of all remaining sides
- precalc side on plane table
- evaluate split side
- {
- cost = 0
- for all sides
- for all sides
- get
- if side splits side and splitside is on same child
- cost++;
- }
- */
- int c_nodes;
- int c_nonvis;
- int c_active_brushes;
- int c_solidleafnodes;
- int c_totalsides;
- int c_brushmemory;
- int c_peak_brushmemory;
- int c_nodememory;
- int c_peak_totalbspmemory;
- // if a brush just barely pokes onto the other side,
- // let it slide by without chopping
- #define PLANESIDE_EPSILON 0.001
- //0.1
- //#ifdef DEBUG
- typedef struct cname_s
- {
- int value;
- char *name;
- } cname_t;
- cname_t contentnames[] =
- {
- {CONTENTS_SOLID,"CONTENTS_SOLID"},
- {CONTENTS_WINDOW,"CONTENTS_WINDOW"},
- {CONTENTS_AUX,"CONTENTS_AUX"},
- {CONTENTS_LAVA,"CONTENTS_LAVA"},
- {CONTENTS_SLIME,"CONTENTS_SLIME"},
- {CONTENTS_WATER,"CONTENTS_WATER"},
- {CONTENTS_MIST,"CONTENTS_MIST"},
- {LAST_VISIBLE_CONTENTS,"LAST_VISIBLE_CONTENTS"},
- {CONTENTS_AREAPORTAL,"CONTENTS_AREAPORTAL"},
- {CONTENTS_PLAYERCLIP,"CONTENTS_PLAYERCLIP"},
- {CONTENTS_MONSTERCLIP,"CONTENTS_MONSTERCLIP"},
- {CONTENTS_CURRENT_0,"CONTENTS_CURRENT_0"},
- {CONTENTS_CURRENT_90,"CONTENTS_CURRENT_90"},
- {CONTENTS_CURRENT_180,"CONTENTS_CURRENT_180"},
- {CONTENTS_CURRENT_270,"CONTENTS_CURRENT_270"},
- {CONTENTS_CURRENT_UP,"CONTENTS_CURRENT_UP"},
- {CONTENTS_CURRENT_DOWN,"CONTENTS_CURRENT_DOWN"},
- {CONTENTS_ORIGIN,"CONTENTS_ORIGIN"},
- {CONTENTS_MONSTER,"CONTENTS_MONSTER"},
- {CONTENTS_DEADMONSTER,"CONTENTS_DEADMONSTER"},
- {CONTENTS_DETAIL,"CONTENTS_DETAIL"},
- {CONTENTS_Q2TRANSLUCENT,"CONTENTS_TRANSLUCENT"},
- {CONTENTS_LADDER,"CONTENTS_LADDER"},
- {0, 0}
- };
- void PrintContents(int contents)
- {
- int i;
- for (i = 0; contentnames[i].value; i++)
- {
- if (contents & contentnames[i].value)
- {
- Log_Write("%s,", contentnames[i].name);
- } //end if
- } //end for
- } //end of the function PrintContents
- //#endif DEBUG
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void ResetBrushBSP(void)
- {
- c_nodes = 0;
- c_nonvis = 0;
- c_active_brushes = 0;
- c_solidleafnodes = 0;
- c_totalsides = 0;
- c_brushmemory = 0;
- c_peak_brushmemory = 0;
- c_nodememory = 0;
- c_peak_totalbspmemory = 0;
- } //end of the function ResetBrushBSP
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void FindBrushInTree (node_t *node, int brushnum)
- {
- bspbrush_t *b;
- if (node->planenum == PLANENUM_LEAF)
- {
- for (b=node->brushlist ; b ; b=b->next)
- if (b->original->brushnum == brushnum)
- Log_Print ("here\n");
- return;
- }
- FindBrushInTree(node->children[0], brushnum);
- FindBrushInTree(node->children[1], brushnum);
- } //end of the function FindBrushInTree
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void DrawBrushList (bspbrush_t *brush, node_t *node)
- {
- int i;
- side_t *s;
- GLS_BeginScene ();
- for ( ; brush ; brush=brush->next)
- {
- for (i=0 ; i<brush->numsides ; i++)
- {
- s = &brush->sides[i];
- if (!s->winding)
- continue;
- if (s->texinfo == TEXINFO_NODE)
- GLS_Winding (s->winding, 1);
- else if (!(s->flags & SFL_VISIBLE))
- GLS_Winding (s->winding, 2);
- else
- GLS_Winding (s->winding, 0);
- }
- }
- GLS_EndScene ();
- } //end of the function DrawBrushList
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void WriteBrushList (char *name, bspbrush_t *brush, qboolean onlyvis)
- {
- int i;
- side_t *s;
- FILE *f;
- qprintf ("writing %s\n", name);
- f = SafeOpenWrite (name);
- for ( ; brush ; brush=brush->next)
- {
- for (i=0 ; i<brush->numsides ; i++)
- {
- s = &brush->sides[i];
- if (!s->winding)
- continue;
- if (onlyvis && !(s->flags & SFL_VISIBLE))
- continue;
- OutputWinding (brush->sides[i].winding, f);
- }
- }
- fclose (f);
- } //end of the function WriteBrushList
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void PrintBrush (bspbrush_t *brush)
- {
- int i;
- printf ("brush: %p\n", brush);
- for (i=0;i<brush->numsides ; i++)
- {
- pw(brush->sides[i].winding);
- printf ("\n");
- } //end for
- } //end of the function PrintBrush
- //===========================================================================
- // Sets the mins/maxs based on the windings
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void BoundBrush (bspbrush_t *brush)
- {
- int i, j;
- winding_t *w;
- ClearBounds (brush->mins, brush->maxs);
- for (i=0 ; i<brush->numsides ; i++)
- {
- w = brush->sides[i].winding;
- if (!w)
- continue;
- for (j=0 ; j<w->numpoints ; j++)
- AddPointToBounds (w->p[j], brush->mins, brush->maxs);
- }
- } //end of the function BoundBrush
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void CreateBrushWindings (bspbrush_t *brush)
- {
- int i, j;
- winding_t *w;
- side_t *side;
- plane_t *plane;
- for (i=0 ; i<brush->numsides ; i++)
- {
- side = &brush->sides[i];
- plane = &mapplanes[side->planenum];
- w = BaseWindingForPlane (plane->normal, plane->dist);
- for (j=0 ; j<brush->numsides && w; j++)
- {
- if (i == j)
- continue;
- if (brush->sides[j].flags & SFL_BEVEL)
- continue;
- plane = &mapplanes[brush->sides[j].planenum^1];
- ChopWindingInPlace (&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
- }
- side->winding = w;
- }
- BoundBrush (brush);
- } //end of the function CreateBrushWindings
- //===========================================================================
- // Creates a new axial brush
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- bspbrush_t *BrushFromBounds (vec3_t mins, vec3_t maxs)
- {
- bspbrush_t *b;
- int i;
- vec3_t normal;
- vec_t dist;
- b = AllocBrush (6);
- b->numsides = 6;
- for (i=0 ; i<3 ; i++)
- {
- VectorClear (normal);
- normal[i] = 1;
- dist = maxs[i];
- b->sides[i].planenum = FindFloatPlane (normal, dist);
- normal[i] = -1;
- dist = -mins[i];
- b->sides[3+i].planenum = FindFloatPlane (normal, dist);
- }
- CreateBrushWindings (b);
- return b;
- } //end of the function BrushFromBounds
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- int BrushOutOfBounds(bspbrush_t *brush, vec3_t mins, vec3_t maxs, float epsilon)
- {
- int i, j, n;
- winding_t *w;
- side_t *side;
- for (i = 0; i < brush->numsides; i++)
- {
- side = &brush->sides[i];
- w = side->winding;
- for (j = 0; j < w->numpoints; j++)
- {
- for (n = 0; n < 3; n++)
- {
- if (w->p[j][n] < (mins[n] + epsilon) || w->p[j][n] > (maxs[n] - epsilon)) return true;
- } //end for
- } //end for
- } //end for
- return false;
- } //end of the function BrushOutOfBounds
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- vec_t BrushVolume (bspbrush_t *brush)
- {
- int i;
- winding_t *w;
- vec3_t corner;
- vec_t d, area, volume;
- plane_t *plane;
- if (!brush) return 0;
- // grab the first valid point as the corner
- w = NULL;
- for (i = 0; i < brush->numsides; i++)
- {
- w = brush->sides[i].winding;
- if (w) break;
- } //end for
- if (!w) return 0;
- VectorCopy (w->p[0], corner);
- // make tetrahedrons to all other faces
- volume = 0;
- for ( ; i < brush->numsides; i++)
- {
- w = brush->sides[i].winding;
- if (!w) continue;
- plane = &mapplanes[brush->sides[i].planenum];
- d = -(DotProduct (corner, plane->normal) - plane->dist);
- area = WindingArea(w);
- volume += d * area;
- } //end for
- volume /= 3;
- return volume;
- } //end of the function BrushVolume
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- int CountBrushList (bspbrush_t *brushes)
- {
- int c;
- c = 0;
- for ( ; brushes; brushes = brushes->next) c++;
- return c;
- } //end of the function CountBrushList
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- node_t *AllocNode (void)
- {
- node_t *node;
- node = GetMemory(sizeof(*node));
- memset (node, 0, sizeof(*node));
- if (numthreads == 1)
- {
- c_nodememory += MemorySize(node);
- } //end if
- return node;
- } //end of the function AllocNode
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- bspbrush_t *AllocBrush (int numsides)
- {
- bspbrush_t *bb;
- int c;
- c = (int)&(((bspbrush_t *)0)->sides[numsides]);
- bb = GetMemory(c);
- memset (bb, 0, c);
- if (numthreads == 1)
- {
- c_active_brushes++;
- c_brushmemory += MemorySize(bb);
- if (c_brushmemory > c_peak_brushmemory)
- c_peak_brushmemory = c_brushmemory;
- } //end if
- return bb;
- } //end of the function AllocBrush
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void FreeBrush (bspbrush_t *brushes)
- {
- int i;
- for (i=0 ; i<brushes->numsides ; i++)
- if (brushes->sides[i].winding)
- FreeWinding(brushes->sides[i].winding);
- if (numthreads == 1)
- {
- c_active_brushes--;
- c_brushmemory -= MemorySize(brushes);
- if (c_brushmemory < 0) c_brushmemory = 0;
- } //end if
- FreeMemory(brushes);
- } //end of the function FreeBrush
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void FreeBrushList (bspbrush_t *brushes)
- {
- bspbrush_t *next;
- for ( ; brushes; brushes = next)
- {
- next = brushes->next;
- FreeBrush(brushes);
- } //end for
- } //end of the function FreeBrushList
- //===========================================================================
- // Duplicates the brush, the sides, and the windings
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- bspbrush_t *CopyBrush (bspbrush_t *brush)
- {
- bspbrush_t *newbrush;
- int size;
- int i;
-
- size = (int)&(((bspbrush_t *)0)->sides[brush->numsides]);
- newbrush = AllocBrush (brush->numsides);
- memcpy (newbrush, brush, size);
- for (i=0 ; i<brush->numsides ; i++)
- {
- if (brush->sides[i].winding)
- newbrush->sides[i].winding = CopyWinding (brush->sides[i].winding);
- }
- return newbrush;
- } //end of the function CopyBrush
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- node_t *PointInLeaf (node_t *node, vec3_t point)
- {
- vec_t d;
- plane_t *plane;
- while (node->planenum != PLANENUM_LEAF)
- {
- plane = &mapplanes[node->planenum];
- d = DotProduct (point, plane->normal) - plane->dist;
- if (d > 0)
- node = node->children[0];
- else
- node = node->children[1];
- }
- return node;
- } //end of the function PointInLeaf
- //===========================================================================
- // Returns PSIDE_FRONT, PSIDE_BACK, or PSIDE_BOTH
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- #if 0
- int BoxOnPlaneSide (vec3_t mins, vec3_t maxs, plane_t *plane)
- {
- int side;
- int i;
- vec3_t corners[2];
- vec_t dist1, dist2;
- // axial planes are easy
- if (plane->type < 3)
- {
- side = 0;
- if (maxs[plane->type] > plane->dist+PLANESIDE_EPSILON)
- side |= PSIDE_FRONT;
- if (mins[plane->type] < plane->dist-PLANESIDE_EPSILON)
- side |= PSIDE_BACK;
- return side;
- }
- // create the proper leading and trailing verts for the box
- for (i=0 ; i<3 ; i++)
- {
- if (plane->normal[i] < 0)
- {
- corners[0][i] = mins[i];
- corners[1][i] = maxs[i];
- }
- else
- {
- corners[1][i] = mins[i];
- corners[0][i] = maxs[i];
- }
- }
- dist1 = DotProduct (plane->normal, corners[0]) - plane->dist;
- dist2 = DotProduct (plane->normal, corners[1]) - plane->dist;
- side = 0;
- if (dist1 >= PLANESIDE_EPSILON)
- side = PSIDE_FRONT;
- if (dist2 < PLANESIDE_EPSILON)
- side |= PSIDE_BACK;
- return side;
- }
- #else
- int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, plane_t *p)
- {
- float dist1, dist2;
- int sides;
- // axial planes are easy
- if (p->type < 3)
- {
- sides = 0;
- if (emaxs[p->type] > p->dist+PLANESIDE_EPSILON) sides |= PSIDE_FRONT;
- if (emins[p->type] < p->dist-PLANESIDE_EPSILON) sides |= PSIDE_BACK;
- return sides;
- } //end if
-
- // general case
- switch (p->signbits)
- {
- case 0:
- dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
- dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
- break;
- case 1:
- dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
- dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
- break;
- case 2:
- dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
- dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
- break;
- case 3:
- dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
- dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
- break;
- case 4:
- dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
- dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
- break;
- case 5:
- dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
- dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
- break;
- case 6:
- dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
- dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
- break;
- case 7:
- dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
- dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
- break;
- default:
- dist1 = dist2 = 0; // shut up compiler
- // assert( 0 );
- break;
- }
- sides = 0;
- if (dist1 - p->dist >= PLANESIDE_EPSILON) sides = PSIDE_FRONT;
- if (dist2 - p->dist < PLANESIDE_EPSILON) sides |= PSIDE_BACK;
- // assert(sides != 0);
- return sides;
- }
- #endif
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- int QuickTestBrushToPlanenum (bspbrush_t *brush, int planenum, int *numsplits)
- {
- int i, num;
- plane_t *plane;
- int s;
- *numsplits = 0;
- plane = &mapplanes[planenum];
- #ifdef ME
- //fast axial cases
- if (plane->type < 3)
- {
- if (plane->dist + PLANESIDE_EPSILON < brush->mins[plane->type])
- return PSIDE_FRONT;
- if (plane->dist - PLANESIDE_EPSILON > brush->maxs[plane->type])
- return PSIDE_BACK;
- } //end if
- #endif //ME*/
- // if the brush actually uses the planenum,
- // we can tell the side for sure
- for (i = 0; i < brush->numsides; i++)
- {
- num = brush->sides[i].planenum;
- if (num >= MAX_MAPFILE_PLANES)
- Error ("bad planenum");
- if (num == planenum)
- return PSIDE_BACK|PSIDE_FACING;
- if (num == (planenum ^ 1) )
- return PSIDE_FRONT|PSIDE_FACING;
- }
- // box on plane side
- s = BoxOnPlaneSide (brush->mins, brush->maxs, plane);
- // if both sides, count the visible faces split
- if (s == PSIDE_BOTH)
- {
- *numsplits += 3;
- }
- return s;
- } //end of the function QuickTestBrushToPlanenum
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- int TestBrushToPlanenum (bspbrush_t *brush, int planenum,
- int *numsplits, qboolean *hintsplit, int *epsilonbrush)
- {
- int i, j, num;
- plane_t *plane;
- int s = 0;
- winding_t *w;
- vec_t d, d_front, d_back;
- int front, back;
- int type;
- float dist;
- *numsplits = 0;
- *hintsplit = false;
- plane = &mapplanes[planenum];
- #ifdef ME
- //fast axial cases
- type = plane->type;
- if (type < 3)
- {
- dist = plane->dist;
- if (dist + PLANESIDE_EPSILON < brush->mins[type]) return PSIDE_FRONT;
- if (dist - PLANESIDE_EPSILON > brush->maxs[type]) return PSIDE_BACK;
- if (brush->mins[type] < dist - PLANESIDE_EPSILON &&
- brush->maxs[type] > dist + PLANESIDE_EPSILON) s = PSIDE_BOTH;
- } //end if
- if (s != PSIDE_BOTH)
- #endif //ME
- {
- // if the brush actually uses the planenum,
- // we can tell the side for sure
- for (i = 0; i < brush->numsides; i++)
- {
- num = brush->sides[i].planenum;
- if (num >= MAX_MAPFILE_PLANES) Error ("bad planenum");
- if (num == planenum)
- {
- //we don't need to test this side plane again
- brush->sides[i].flags |= SFL_TESTED;
- return PSIDE_BACK|PSIDE_FACING;
- } //end if
- if (num == (planenum ^ 1) )
- {
- //we don't need to test this side plane again
- brush->sides[i].flags |= SFL_TESTED;
- return PSIDE_FRONT|PSIDE_FACING;
- } //end if
- } //end for
- // box on plane side
- s = BoxOnPlaneSide (brush->mins, brush->maxs, plane);
- if (s != PSIDE_BOTH) return s;
- } //end if
- // if both sides, count the visible faces split
- d_front = d_back = 0;
- for (i = 0; i < brush->numsides; i++)
- {
- if (brush->sides[i].texinfo == TEXINFO_NODE)
- continue; // on node, don't worry about splits
- if (!(brush->sides[i].flags & SFL_VISIBLE))
- continue; // we don't care about non-visible
- w = brush->sides[i].winding;
- if (!w) continue;
- front = back = 0;
- for (j = 0; j < w->numpoints; j++)
- {
- d = DotProduct(w->p[j], plane->normal) - plane->dist;
- if (d > d_front) d_front = d;
- if (d < d_back) d_back = d;
- if (d > 0.1) // PLANESIDE_EPSILON)
- front = 1;
- if (d < -0.1) // PLANESIDE_EPSILON)
- back = 1;
- } //end for
- if (front && back)
- {
- if ( !(brush->sides[i].surf & SURF_SKIP) )
- {
- (*numsplits)++;
- if (brush->sides[i].surf & SURF_HINT)
- {
- *hintsplit = true;
- } //end if
- } //end if
- } //end if
- } //end for
- if ( (d_front > 0.0 && d_front < 1.0)
- || (d_back < 0.0 && d_back > -1.0) )
- (*epsilonbrush)++;
- #if 0
- if (*numsplits == 0)
- { // didn't really need to be split
- if (front) s = PSIDE_FRONT;
- else if (back) s = PSIDE_BACK;
- else s = 0;
- }
- #endif
- return s;
- } //end of the function TestBrushToPlanenum
- //===========================================================================
- // Returns true if the winding would be crunched out of
- // existance by the vertex snapping.
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- #define EDGE_LENGTH 0.2
- qboolean WindingIsTiny (winding_t *w)
- {
- #if 0
- if (WindingArea (w) < 1)
- return true;
- return false;
- #else
- int i, j;
- vec_t len;
- vec3_t delta;
- int edges;
- edges = 0;
- for (i=0 ; i<w->numpoints ; i++)
- {
- j = i == w->numpoints - 1 ? 0 : i+1;
- VectorSubtract (w->p[j], w->p[i], delta);
- len = VectorLength (delta);
- if (len > EDGE_LENGTH)
- {
- if (++edges == 3)
- return false;
- }
- }
- return true;
- #endif
- } //end of the function WindingIsTiny
- //===========================================================================
- // Returns true if the winding still has one of the points
- // from basewinding for plane
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- qboolean WindingIsHuge (winding_t *w)
- {
- int i, j;
- for (i=0 ; i<w->numpoints ; i++)
- {
- for (j=0 ; j<3 ; j++)
- if (w->p[i][j] < -BOGUS_RANGE+1 || w->p[i][j] > BOGUS_RANGE-1)
- return true;
- }
- return false;
- } //end of the function WindingIsHuge
- //===========================================================================
- // creates a leaf out of the given nodes with the given brushes
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void LeafNode(node_t *node, bspbrush_t *brushes)
- {
- bspbrush_t *b;
- int i;
- node->side = NULL;
- node->planenum = PLANENUM_LEAF;
- node->contents = 0;
- for (b = brushes; b; b = b->next)
- {
- // if the brush is solid and all of its sides are on nodes,
- // it eats everything
- if (b->original->contents & CONTENTS_SOLID)
- {
- for (i=0 ; i<b->numsides ; i++)
- if (b->sides[i].texinfo != TEXINFO_NODE)
- break;
- if (i == b->numsides)
- {
- node->contents = CONTENTS_SOLID;
- break;
- } //end if
- } //end if
- node->contents |= b->original->contents;
- } //end for
- if (create_aas)
- {
- node->expansionbboxes = 0;
- node->contents = 0;
- for (b = brushes; b; b = b->next)
- {
- node->expansionbboxes |= b->original->expansionbbox;
- node->contents |= b->original->contents;
- if (b->original->modelnum)
- node->modelnum = b->original->modelnum;
- } //end for
- if (node->contents & CONTENTS_SOLID)
- {
- if (node->expansionbboxes != cfg.allpresencetypes)
- {
- node->contents &= ~CONTENTS_SOLID;
- } //end if
- } //end if
- } //end if
- node->brushlist = brushes;
- } //end of the function LeafNode
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void CheckPlaneAgainstParents (int pnum, node_t *node)
- {
- node_t *p;
- for (p = node->parent; p; p = p->parent)
- {
- if (p->planenum == pnum) Error("Tried parent");
- } //end for
- } //end of the function CheckPlaneAgainstParants
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- qboolean CheckPlaneAgainstVolume (int pnum, node_t *node)
- {
- bspbrush_t *front, *back;
- qboolean good;
- SplitBrush (node->volume, pnum, &front, &back);
- good = (front && back);
- if (front) FreeBrush (front);
- if (back) FreeBrush (back);
- return good;
- } //end of the function CheckPlaneAgaintsVolume
- //===========================================================================
- // Using a hueristic, choses one of the sides out of the brushlist
- // to partition the brushes with.
- // Returns NULL if there are no valid planes to split with..
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- side_t *SelectSplitSide (bspbrush_t *brushes, node_t *node)
- {
- int value, bestvalue;
- bspbrush_t *brush, *test;
- side_t *side, *bestside;
- int i, pass, numpasses;
- int pnum;
- int s;
- int front, back, both, facing, splits;
- int bsplits;
- int bestsplits;
- int epsilonbrush;
- qboolean hintsplit = false;
- bestside = NULL;
- bestvalue = -99999;
- bestsplits = 0;
- // the search order goes: visible-structural, visible-detail,
- // nonvisible-structural, nonvisible-detail.
- // If any valid plane is available in a pass, no further
- // passes will be tried.
- numpasses = 2;
- for (pass = 0; pass < numpasses; pass++)
- {
- for (brush = brushes; brush; brush = brush->next)
- {
- // only check detail the second pass
- // if ( (pass & 1) && !(brush->original->contents & CONTENTS_DETAIL) )
- // continue;
- // if ( !(pass & 1) && (brush->original->contents & CONTENTS_DETAIL) )
- // continue;
- for (i = 0; i < brush->numsides; i++)
- {
- side = brush->sides + i;
- // if (side->flags & SFL_BEVEL)
- // continue; // never use a bevel as a spliter
- if (!side->winding)
- continue; // nothing visible, so it can't split
- if (side->texinfo == TEXINFO_NODE)
- continue; // allready a node splitter
- if (side->flags & SFL_TESTED)
- continue; // we allready have metrics for this plane
- // if (side->surf & SURF_SKIP)
- // continue; // skip surfaces are never chosen
- // if (!(side->flags & SFL_VISIBLE) && (pass < 2))
- // continue; // only check visible faces on first pass
- if ((side->flags & SFL_CURVE) && (pass < 1))
- continue; // only check curves the second pass
- pnum = side->planenum;
- pnum &= ~1; // allways use positive facing plane
- CheckPlaneAgainstParents (pnum, node);
- if (!CheckPlaneAgainstVolume (pnum, node))
- continue; // would produce a tiny volume
- front = 0;
- back = 0;
- both = 0;
- facing = 0;
- splits = 0;
- epsilonbrush = 0;
- //inner loop: optimize
- for (test = brushes; test; test = test->next)
- {
- s = TestBrushToPlanenum (test, pnum, &bsplits, &hintsplit, &epsilonbrush);
- splits += bsplits;
- // if (bsplits && (s&PSIDE_FACING) )
- // Error ("PSIDE_FACING with splits");
- test->testside = s;
- //
- if (s & PSIDE_FACING) facing++;
- if (s & PSIDE_FRONT) front++;
- if (s & PSIDE_BACK) back++;
- if (s == PSIDE_BOTH) both++;
- } //end for
- // give a value estimate for using this plane
- value = 5*facing - 5*splits - abs(front-back);
- // value = -5*splits;
- // value = 5*facing - 5*splits;
- if (mapplanes[pnum].type < 3)
- value+=5; // axial is better
- value -= epsilonbrush * 1000; // avoid!
- // never split a hint side except with another hint
- if (hintsplit && !(side->surf & SURF_HINT) )
- value = -9999999;
- // save off the side test so we don't need
- // to recalculate it when we actually seperate
- // the brushes
- if (value > bestvalue)
- {
- bestvalue = value;
- bestside = side;
- bestsplits = splits;
- for (test = brushes; test ; test = test->next)
- test->side = test->testside;
- } //end if
- } //end for
- } //end for (brush = brushes;
- // if we found a good plane, don't bother trying any
- // other passes
- if (bestside)
- {
- if (pass > 1)
- {
- if (numthreads == 1) c_nonvis++;
- }
- if (pass > 0) node->detail_seperator = true; // not needed for vis
- break;
- } //end if
- } //end for (pass = 0;
- //
- // clear all the tested flags we set
- //
- for (brush = brushes ; brush ; brush=brush->next)
- {
- for (i = 0; i < brush->numsides; i++)
- {
- brush->sides[i].flags &= ~SFL_TESTED;
- } //end for
- } //end for
- return bestside;
- } //end of the function SelectSplitSide
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- int BrushMostlyOnSide (bspbrush_t *brush, plane_t *plane)
- {
- int i, j;
- winding_t *w;
- vec_t d, max;
- int side;
- max = 0;
- side = PSIDE_FRONT;
- for (i=0 ; i<brush->numsides ; i++)
- {
- w = brush->sides[i].winding;
- if (!w)
- continue;
- for (j=0 ; j<w->numpoints ; j++)
- {
- d = DotProduct (w->p[j], plane->normal) - plane->dist;
- if (d > max)
- {
- max = d;
- side = PSIDE_FRONT;
- }
- if (-d > max)
- {
- max = -d;
- side = PSIDE_BACK;
- }
- }
- }
- return side;
- } //end of the function BrushMostlyOnSide
- //===========================================================================
- // Generates two new brushes, leaving the original
- // unchanged
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void SplitBrush (bspbrush_t *brush, int planenum,
- bspbrush_t **front, bspbrush_t **back)
- {
- bspbrush_t *b[2];
- int i, j;
- winding_t *w, *cw[2], *midwinding;
- plane_t *plane, *plane2;
- side_t *s, *cs;
- float d, d_front, d_back;
- *front = *back = NULL;
- plane = &mapplanes[planenum];
- // check all points
- d_front = d_back = 0;
- for (i=0 ; i<brush->numsides ; i++)
- {
- w = brush->sides[i].winding;
- if (!w)
- continue;
- for (j=0 ; j<w->numpoints ; j++)
- {
- d = DotProduct (w->p[j], plane->normal) - plane->dist;
- if (d > 0 && d > d_front)
- d_front = d;
- if (d < 0 && d < d_back)
- d_back = d;
- }
- }
- if (d_front < 0.2) // PLANESIDE_EPSILON)
- { // only on back
- *back = CopyBrush (brush);
- return;
- }
- if (d_back > -0.2) // PLANESIDE_EPSILON)
- { // only on front
- *front = CopyBrush (brush);
- return;
- }
- // create a new winding from the split plane
- w = BaseWindingForPlane (plane->normal, plane->dist);
- for (i=0 ; i<brush->numsides && w ; i++)
- {
- plane2 = &mapplanes[brush->sides[i].planenum ^ 1];
- ChopWindingInPlace (&w, plane2->normal, plane2->dist, 0); // PLANESIDE_EPSILON);
- }
- if (!w || WindingIsTiny(w))
- { // the brush isn't really split
- int side;
- side = BrushMostlyOnSide (brush, plane);
- if (side == PSIDE_FRONT)
- *front = CopyBrush (brush);
- if (side == PSIDE_BACK)
- *back = CopyBrush (brush);
- //free a possible winding
- if (w) FreeWinding(w);
- return;
- }
- if (WindingIsHuge (w))
- {
- Log_Write("WARNING: huge winding\n");
- }
- midwinding = w;
- // split it for real
- for (i=0 ; i<2 ; i++)
- {
- b[i] = AllocBrush (brush->numsides+1);
- b[i]->original = brush->original;
- }
- // split all the current windings
- for (i=0 ; i<brush->numsides ; i++)
- {
- s = &brush->sides[i];
- w = s->winding;
- if (!w)
- continue;
- ClipWindingEpsilon (w, plane->normal, plane->dist,
- 0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]);
- for (j=0 ; j<2 ; j++)
- {
- if (!cw[j])
- continue;
- #if 0
- if (WindingIsTiny (cw[j]))
- {
- FreeWinding (cw[j]);
- continue;
- }
- #endif
- cs = &b[j]->sides[b[j]->numsides];
- b[j]->numsides++;
- *cs = *s;
- // cs->planenum = s->planenum;
- // cs->texinfo = s->texinfo;
- // cs->original = s->original;
- cs->winding = cw[j];
- cs->flags &= ~SFL_TESTED;
- }
- }
- // see if we have valid polygons on both sides
- for (i=0 ; i<2 ; i++)
- {
- BoundBrush (b[i]);
- for (j=0 ; j<3 ; j++)
- {
- if (b[i]->mins[j] < -MAX_MAP_BOUNDS || b[i]->maxs[j] > MAX_MAP_BOUNDS)
- {
- Log_Write("bogus brush after clip");
- break;
- }
- }
- if (b[i]->numsides < 3 || j < 3)
- {
- FreeBrush (b[i]);
- b[i] = NULL;
- }
- }
- if ( !(b[0] && b[1]) )
- {
- if (!b[0] && !b[1])
- Log_Write("split removed brush\r\n");
- else
- Log_Write("split not on both sides\r\n");
- if (b[0])
- {
- FreeBrush (b[0]);
- *front = CopyBrush (brush);
- }
- if (b[1])
- {
- FreeBrush (b[1]);
- *back = CopyBrush (brush);
- }
- return;
- }
- // add the midwinding to both sides
- for (i=0 ; i<2 ; i++)
- {
- cs = &b[i]->sides[b[i]->numsides];
- b[i]->numsides++;
- cs->planenum = planenum^i^1;
- cs->texinfo = TEXINFO_NODE; //never use these sides as splitters
- cs->flags &= ~SFL_VISIBLE;
- cs->flags &= ~SFL_TESTED;
- if (i==0)
- cs->winding = CopyWinding (midwinding);
- else
- cs->winding = midwinding;
- }
- {
- vec_t v1;
- int i;
- for (i = 0; i < 2; i++)
- {
- v1 = BrushVolume (b[i]);
- if (v1 < 1.0)
- {
- FreeBrush(b[i]);
- b[i] = NULL;
- //Log_Write("tiny volume after clip");
- }
- }
- if (!b[0] && !b[1])
- {
- Log_Write("two tiny brushes\r\n");
- } //end if
- }
- *front = b[0];
- *back = b[1];
- } //end of the function SplitBrush
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void SplitBrushList (bspbrush_t *brushes,
- node_t *node, bspbrush_t **front, bspbrush_t **back)
- {
- bspbrush_t *brush, *newbrush, *newbrush2;
- side_t *side;
- int sides;
- int i;
- *front = *back = NULL;
- for (brush = brushes; brush; brush = brush->next)
- {
- sides = brush->side;
- if (sides == PSIDE_BOTH)
- { // split into two brushes
- SplitBrush (brush, node->planenum, &newbrush, &newbrush2);
- if (newbrush)
- {
- newbrush->next = *front;
- *front = newbrush;
- } //end if
- if (newbrush2)
- {
- newbrush2->next = *back;
- *back = newbrush2;
- } //end if
- continue;
- } //end if
- newbrush = CopyBrush (brush);
- // if the planenum is actualy a part of the brush
- // find the plane and flag it as used so it won't be tried
- // as a splitter again
- if (sides & PSIDE_FACING)
- {
- for (i=0 ; i<newbrush->numsides ; i++)
- {
- side = newbrush->sides + i;
- if ( (side->planenum& ~1) == node->planenum)
- side->texinfo = TEXINFO_NODE;
- } //end for
- } //end if
- if (sides & PSIDE_FRONT)
- {
- newbrush->next = *front;
- *front = newbrush;
- continue;
- } //end if
- if (sides & PSIDE_BACK)
- {
- newbrush->next = *back;
- *back = newbrush;
- continue;
- } //end if
- } //end for
- } //end of the function SplitBrushList
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void CheckBrushLists(bspbrush_t *brushlist1, bspbrush_t *brushlist2)
- {
- bspbrush_t *brush1, *brush2;
- for (brush1 = brushlist1; brush1; brush1 = brush1->next)
- {
- for (brush2 = brushlist2; brush2; brush2 = brush2->next)
- {
- assert(brush1 != brush2);
- } //end for
- } //end for
- } //end of the function CheckBrushLists
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- int numrecurse = 0;
- node_t *BuildTree_r (node_t *node, bspbrush_t *brushes)
- {
- node_t *newnode;
- side_t *bestside;
- int i, totalmem;
- bspbrush_t *children[2];
- qprintf("\r%6d", numrecurse);
- numrecurse++;
- if (numthreads == 1)
- {
- totalmem = WindingMemory() + c_nodememory + c_brushmemory;
- if (totalmem > c_peak_totalbspmemory)
- c_peak_totalbspmemory = totalmem;
- c_nodes++;
- } //endif
- if (drawflag)
- DrawBrushList(brushes, node);
- // find the best plane to use as a splitter
- bestside = SelectSplitSide (brushes, node);
- if (!bestside)
- {
- // leaf node
- node->side = NULL;
- node->planenum = -1;
- LeafNode(node, brushes);
- if (node->contents & CONTENTS_SOLID) c_solidleafnodes++;
- if (create_aas)
- {
- //free up memory!!!
- FreeBrushList(node->brushlist);
- node->brushlist = NULL;
- //free the node volume brush
- if (node->volume)
- {
- FreeBrush(node->volume);
- node->volume = NULL;
- } //end if
- } //end if
- return node;
- } //end if
- // this is a splitplane node
- node->side = bestside;
- node->planenum = bestside->planenum & ~1; // always use front facing
- //split the brush list in two for both children
- SplitBrushList (brushes, node, &children[0], &children[1]);
- //free the old brush list
- FreeBrushList (brushes);
- // allocate children before recursing
- for (i = 0; i < 2; i++)
- {
- newnode = AllocNode ();
- newnode->parent = node;
- node->children[i] = newnode;
- } //end for
- //split the volume brush of the node for the children
- SplitBrush (node->volume, node->planenum, &node->children[0]->volume,
- &node->children[1]->volume);
- if (create_aas)
- {
- //free the volume brush
- if (node->volume)
- {
- FreeBrush(node->volume);
- node->volume = NULL;
- } //end if
- } //end if
- // recursively process children
- for (i = 0; i < 2; i++)
- {
- node->children[i] = BuildTree_r(node->children[i], children[i]);
- } //end for
- return node;
- } //end of the function BuildTree_r
- //===========================================================================
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- node_t *firstnode; //first node in the list
- node_t *lastnode; //last node in the list
- int nodelistsize; //number of nodes in the list
- int use_nodequeue = 0; //use nodequeue, otherwise a node stack is used
- int numwaiting = 0;
- void (*AddNodeToList)(node_t *node);
- //add the node to the front of the node list
- //(effectively using a node stack)
- void AddNodeToStack(node_t *node)
- {
- ThreadLock();
- node->next = firstnode;
- firstnode = node;
- if (!lastnode) lastnode = node;
- nodelistsize++;
- ThreadUnlock();
- //
- ThreadSemaphoreIncrease(1);
- } //end of the function AddNodeToStack
- //add the node to the end of the node list
- //(effectively using a node queue)
- void AddNodeToQueue(node_t *node)
- {
- ThreadLock();
- node->next = NULL;
- if (lastnode) lastnode->next = node;
- else firstnode = node;
- lastnode = node;
- nodelistsize++;
- ThreadUnlock();
- //
- ThreadSemaphoreIncrease(1);
- } //end of the function AddNodeToQueue
- //get the first node from the front of the node list
- node_t *NextNodeFromList(void)
- {
- node_t *node;
- ThreadLock();
- numwaiting++;
- if (!firstnode)
- {
- if (numwaiting >= GetNumThreads()) ThreadSemaphoreIncrease(GetNumThreads());
- } //end if
- ThreadUnlock();
- ThreadSemaphoreWait();
- ThreadLock();
- numwaiting--;
- node = firstnode;
- if (firstnode)
- {
- firstnode = firstnode->next;
- nodelistsize--;
- } //end if
- if (!firstnode) lastnode = NULL;
- ThreadUnlock();
- return node;
- } //end of the function NextNodeFromList
- //returns the size of the node list
- int NodeListSize(void)
- {
- int size;
- ThreadLock();
- size = nodelistsize;
- ThreadUnlock();
- return size;
- } //end of the function NodeListSize
- //
- void IncreaseNodeCounter(void)
- {
- ThreadLock();
- //if (verbose) printf("\r%6d", numrecurse++);
- qprintf("\r%6d", numrecurse++);
- //qprintf("\r%6d %d, %5d ", numrecurse++, GetNumThreads(), nodelistsize);
- ThreadUnlock();
- } //end of the function IncreaseNodeCounter
- //thread function, gets nodes from the nodelist and processes them
- void BuildTreeThread(int threadid)
- {
- node_t *newnode, *node;
- side_t *bestside;
- int i, totalmem;
- bspbrush_t *brushes;
- for (node = NextNodeFromList(); node; )
- {
- //if the nodelist isn't empty try to add another thread
- //if (NodeListSize() > 10) AddThread(BuildTreeThread);
- //display the number of nodes processed so far
- if (numthreads == 1)
- IncreaseNodeCounter();
- brushes = node->brushlist;
- if (numthreads == 1)
- {
- totalmem = WindingMemory() + c_nodememory + c_brushmemory;
- if (totalmem > c_peak_totalbspmemory)
- {
- c_peak_totalbspmemory = totalmem;
- } //end if
- c_nodes++;
- } //endif
- if (drawflag)
- {
- DrawBrushList(brushes, node);
- } //end if
- if (cancelconversion)
- {
- bestside = NULL;
- } //end if
- else
- {
- // find the best plane to use as a splitter
- bestside = SelectSplitSide(brushes, node);
- } //end else
- //if there's no split side left
- if (!bestside)
- {
- //create a leaf out of the node
- LeafNode(node, brushes);
- if (node->contents & CONTENTS_SOLID) c_solidleafnodes++;
- if (create_aas)
- {
- //free up memory!!!
- FreeBrushList(node->brushlist);
- node->brushlist = NULL;
- } //end if
- //free the node volume brush (it is not used anymore)
- if (node->volume)
- {
- FreeBrush(node->volume);
- node->volume = NULL;
- } //end if
- node = NextNodeFromList();
- continue;
- } //end if
- // this is a splitplane node
- node->side = bestside;
- node->planenum = bestside->planenum & ~1; //always use front facing
- //allocate children
- for (i = 0; i < 2; i++)
- {
- newnode = AllocNode();
- newnode->parent = node;
- node->children[i] = newnode;
- } //end for
- //split the brush list in two for both children
- SplitBrushList(brushes, node, &node->children[0]->brushlist, &node->children[1]->brushlist);
- CheckBrushLists(node->children[0]->brushlist, node->children[1]->brushlist);
- //free the old brush list
- FreeBrushList(brushes);
- node->brushlist = NULL;
- //split the volume brush of the node for the children
- SplitBrush(node->volume, node->planenum, &node->children[0]->volume,
- &node->children[1]->volume);
- if (!node->children[0]->volume || !node->children[1]->volume)
- {
- Error("child without volume brush");
- } //end if
- //free the volume brush
- if (node->volume)
- {
- FreeBrush(node->volume);
- node->volume = NULL;
- } //end if
- //add both children to the node list
- //AddNodeToList(node->children[0]);
- AddNodeToList(node->children[1]);
- node = node->children[0];
- } //end while
- RemoveThread(threadid);
- } //end of the function BuildTreeThread
- //===========================================================================
- // build the bsp tree using a node list
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- void BuildTree(tree_t *tree)
- {
- int i;
- firstnode = NULL;
- lastnode = NULL;
- //use a node queue or node stack
- if (use_nodequeue) AddNodeToList = AddNodeToQueue;
- else AddNodeToList = AddNodeToStack;
- //setup thread locking
- ThreadSetupLock();
- ThreadSetupSemaphore();
- numwaiting = 0;
- //
- Log_Print("%6d threads max\n", numthreads);
- if (use_nodequeue) Log_Print("breadth first bsp building\n");
- else Log_Print("depth first bsp building\n");
- qprintf("%6d splits", 0);
- //add the first node to the list
- AddNodeToList(tree->headnode);
- //start the threads
- for (i = 0; i < numthreads; i++)
- AddThread(BuildTreeThread);
- //wait for all added threads to be finished
- WaitForAllThreadsFinished();
- //shutdown the thread locking
- ThreadShutdownLock();
- ThreadShutdownSemaphore();
- } //end of the function BuildTree
- //===========================================================================
- // The incoming brush list will be freed before exiting
- //
- // Parameter: -
- // Returns: -
- // Changes Globals: -
- //===========================================================================
- tree_t *BrushBSP(bspbrush_t *brushlist, vec3_t mins, vec3_t maxs)
- {
- int i, c_faces, c_nonvisfaces, c_brushes;
- bspbrush_t *b;
- node_t *node;
- tree_t *tree;
- vec_t volume;
- // vec3_t point;
- Log_Print("-------- Brush BSP ---------\n");
- tree = Tree_Alloc();
- c_faces = 0;
- c_nonvisfaces = 0;
- c_brushes = 0;
- c_totalsides = 0;
- for (b = brushlist; b; b = b->next)
- {
- c_brushes++;
- volume = BrushVolume(b);
- if (volume < microvolume)
- {
- Log_Print("WARNING: entity %i, brush %i: microbrush\n",
- b->original->entitynum, b->original->brushnum);
- } //end if
- for (i=0 ; i<b->numsides ; i++)
- {
- if (b->sides[i].flags & SFL_BEVEL)
- continue;
- if (!b->sides[i].winding)
- continue;
- if (b->sides[i].texinfo == TEXINFO_NODE)
- continue;
- if (b->sides[i].flags & SFL_VISIBLE)
- {
- c_faces++;
- } //end if
- else
- {
- c_nonvisfaces++;
- //if (create_aas) b->sides[i].texinfo = TEXINFO_NODE;
- } //end if
- } //end for
- c_totalsides += b->numsides;
- AddPointToBounds (b->mins, tree->mins, tree->maxs);
- AddPointToBounds (b->maxs, tree->mins, tree->maxs);
- } //end for
- Log_Print("%6i brushes\n", c_brushes);
- Log_Print("%6i visible faces\n", c_faces);
- Log_Print("%6i nonvisible faces\n", c_nonvisfaces);
- Log_Print("%6i total sides\n", c_totalsides);
- c_active_brushes = c_brushes;
- c_nodememory = 0;
- c_brushmemory = 0;
- c_peak_brushmemory = 0;
- c_nodes = 0;
- c_nonvis = 0;
- node = AllocNode ();
- //volume of first node (head node)
- node->volume = BrushFromBounds (mins, maxs);
- //
- tree->headnode = node;
- //just get some statistics and the mins/maxs of the node
- numrecurse = 0;
- // qprintf("%6d splits", numrecurse);
- tree->headnode->brushlist = brushlist;
- BuildTree(tree);
- //build the bsp tree with the start node from the brushlist
- // node = BuildTree_r(node, brushlist);
- //if the conversion is cancelled
- if (cancelconversion) return tree;
- qprintf("\n");
- Log_Write("%6d splits\r\n", numrecurse);
- // Log_Print("%6i visible nodes\n", c_nodes/2 - c_nonvis);
- // Log_Print("%6i nonvis nodes\n", c_nonvis);
- // Log_Print("%6i leaves\n", (c_nodes+1)/2);
- // Log_Print("%6i solid leaf nodes\n", c_solidleafnodes);
- // Log_Print("%6i active brushes\n", c_active_brushes);
- if (numthreads == 1)
- {
- // Log_Print("%6i KB of node memory\n", c_nodememory >> 10);
- // Log_Print("%6i KB of brush memory\n", c_brushmemory >> 10);
- // Log_Print("%6i KB of peak brush memory\n", c_peak_brushmemory >> 10);
- // Log_Print("%6i KB of winding memory\n", WindingMemory() >> 10);
- // Log_Print("%6i KB of peak winding memory\n", WindingPeakMemory() >> 10);
- Log_Print("%6i KB of peak total bsp memory\n", c_peak_totalbspmemory >> 10);
- } //end if
- /*
- point[0] = 1485;
- point[1] = 956.125;
- point[2] = 352.125;
- node = PointInLeaf(tree->headnode, point);
- if (node->planenum != PLANENUM_LEAF)
- {
- Log_Print("node not a leaf\n");
- } //end if
- Log_Print("at %f %f %f:\n", point[0], point[1], point[2]);
- PrintContents(node->contents);
- Log_Print("node->expansionbboxes = %d\n", node->expansionbboxes);
- //*/
- return tree;
- } //end of the function BrushBSP
|