This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/common/bsplib/facebsp.c

339 lines
6.9 KiB
C

//=======================================================================
// Copyright XashXT Group 2007 ©
// facebsp.c - generate bsp faces
//=======================================================================
#include "bsplib.h"
#include "const.h"
#define BLOCK_SIZE 1024
int hintsplit;
int c_faceleafs;
bspface_t *AllocBspFace( void )
{
return BSP_Malloc(sizeof( bspface_t ));
}
void FreeBspFace( bspface_t *f )
{
if( f->w ) FreeWinding( f->w );
Mem_Free( f );
}
/*
================
SelectSplitPlaneNum
================
*/
int SelectSplitPlaneNum( node_t *node, bspface_t *list )
{
bspface_t *split;
bspface_t *check;
bspface_t *bestSplit;
int splits, facing, front, back;
int side;
plane_t *plane;
int i, value, bestValue;
vec3_t normal;
float dist;
int planenum;
hintsplit = false;
// if it is crossing a 1k block boundary, force a split
for( i = 0 ; i < 2 ; i++ )
{
dist = BLOCK_SIZE * ( floor( node->mins[i] / BLOCK_SIZE ) + 1 );
if( node->maxs[i] > dist )
{
VectorClear( normal );
normal[i] = 1;
planenum = FindFloatPlane( normal, dist );
return planenum;
}
}
// pick one of the face planes
bestValue = -99999;
bestSplit = list;
for( split = list; split; split = split->next )
split->checked = false;
for( split = list; split; split = split->next )
{
if( split->checked ) continue;
plane = &mapplanes[split->planenum];
splits = facing = front = back = 0;
for( check = list ; check ; check = check->next )
{
if( check->planenum == split->planenum )
{
facing++;
check->checked = true; // won't need to test this plane again
continue;
}
side = WindingOnPlaneSide( check->w, plane->normal, plane->dist );
if( side == SIDE_CROSS ) splits++;
else if( side == SIDE_FRONT ) front++;
else if( side == SIDE_BACK ) back++;
}
value = 5 * facing - 5 * splits; // - abs( front - back );
if( plane->type < 3 ) value += 5; // axial is better
value += split->priority; // prioritize hints higher
if( value > bestValue )
{
bestValue = value;
bestSplit = split;
}
}
if( bestValue == -99999 )
return -1;
if( bestSplit->hint )
hintsplit = true;
return bestSplit->planenum;
}
int CountFaceList( bspface_t *list )
{
int c;
for( c = 0; list; list = list->next )
c++;
return c;
}
/*
================
BuildFaceTree_r
================
*/
void BuildFaceTree_r( node_t *node, bspface_t *list )
{
bspface_t *split;
bspface_t *next;
int i, side;
plane_t *plane;
bspface_t *newFace;
bspface_t *childLists[2];
winding_t *frontWinding, *backWinding;
int splitPlaneNum;
i = CountFaceList( list );
splitPlaneNum = SelectSplitPlaneNum( node, list );
// if we don't have any more faces, this is a node
if( splitPlaneNum == -1 )
{
node->planenum = PLANENUM_LEAF;
c_faceleafs++;
return;
}
// partition the list
node->planenum = splitPlaneNum;
node->hint = hintsplit;
plane = &mapplanes[splitPlaneNum];
childLists[0] = NULL;
childLists[1] = NULL;
for( split = list; split; split = next )
{
next = split->next;
if( split->planenum == node->planenum )
{
FreeBspFace( split );
continue;
}
side = WindingOnPlaneSide( split->w, plane->normal, plane->dist );
if( side == SIDE_CROSS )
{
ClipWindingEpsilon( split->w, plane->normal, plane->dist, ON_EPSILON * 2, &frontWinding, &backWinding );
if( frontWinding )
{
newFace = AllocBspFace();
newFace->w = frontWinding;
newFace->next = childLists[0];
newFace->planenum = split->planenum;
newFace->priority = split->priority;
newFace->hint = split->hint;
childLists[0] = newFace;
}
if( backWinding )
{
newFace = AllocBspFace();
newFace->w = backWinding;
newFace->next = childLists[1];
newFace->planenum = split->planenum;
newFace->priority = split->priority;
newFace->hint = split->hint;
childLists[1] = newFace;
}
FreeBspFace( split );
}
else if( side == SIDE_FRONT )
{
split->next = childLists[0];
childLists[0] = split;
}
else if( side == SIDE_BACK )
{
split->next = childLists[1];
childLists[1] = split;
}
}
// recursively process children
for( i = 0; i < 2; i++ )
{
node->children[i] = AllocNode();
node->children[i]->parent = node;
VectorCopy( node->mins, node->children[i]->mins );
VectorCopy( node->maxs, node->children[i]->maxs );
}
for( i = 0; i < 3; i++ )
{
if( plane->normal[i] == 1 )
{
node->children[0]->mins[i] = plane->dist;
node->children[1]->maxs[i] = plane->dist;
break;
}
}
for( i = 0; i < 2; i++ ) BuildFaceTree_r( node->children[i], childLists[i] );
}
/*
================
FaceBSP
List will be freed before returning
================
*/
tree_t *FaceBSP( bspface_t *list )
{
tree_t *tree;
bspface_t *face;
int i, count = 0;
Msg( "--- FaceBSP ---\n" );
tree = AllocTree();
for( face = list; face; face = face->next )
{
count++;
for( i = 0; i < face->w->numpoints; i++ )
AddPointToBounds( face->w->p[i], tree->mins, tree->maxs );
}
Msg( "%5i faces\n", count );
tree->headnode = AllocNode();
VectorCopy( tree->mins, tree->headnode->mins );
VectorCopy( tree->maxs, tree->headnode->maxs );
c_faceleafs = 0;
BuildFaceTree_r( tree->headnode, list );
Msg( "%5i leafs\n", c_faceleafs );
return tree;
}
/*
=================
BspFaceForPortal
=================
*/
bspface_t *BspFaceForPortal( portal_t *p )
{
bspface_t *f;
f = AllocBspFace();
f->w = CopyWinding( p->winding );
f->planenum = p->onnode->planenum & ~1;
return f;
}
/*
=================
MakeStructuralBspFaceList
=================
*/
bspface_t *MakeStructuralBspFaceList( bspbrush_t *list )
{
bspbrush_t *b;
int i;
side_t *s;
winding_t *w;
bspface_t *f, *flist = NULL;
for( b = list; b; b = b->next )
{
if( b->detail ) continue;
for( i = 0; i < b->numsides; i++ )
{
s = &b->sides[i];
w = s->winding;
if( !w ) continue;
f = AllocBspFace();
f->w = CopyWinding( w );
f->planenum = s->planenum & ~1;
f->next = flist;
if( s->surfaceFlags & SURF_HINT )
f->hint = true;
flist = f;
}
}
return flist;
}
/*
=================
MakeVisibleBspFaceList
=================
*/
bspface_t *MakeVisibleBspFaceList( bspbrush_t *list )
{
bspbrush_t *b;
int i;
side_t *s;
winding_t *w;
bspface_t *f, *flist = NULL;
for( b = list; b; b = b->next )
{
if( b->detail ) continue;
for( i = 0; i < b->numsides; i++ )
{
s = &b->sides[i];
w = s->visibleHull;
if( !w ) continue;
f = AllocBspFace();
f->w = CopyWinding( w );
f->planenum = s->planenum & ~1;
f->next = flist;
if( s->surfaceFlags & SURF_HINT )
f->hint = true;
flist = f;
}
}
return flist;
}