Example #1
0
/**
 * @brief Using a heuristic, choses one of the sides out of the brushlist
 * to partition the brushes with.
 * @return nullptr if there are no valid planes to split with..
 */
side_t* SelectSplitSide (bspbrush_t* brushes, bspbrush_t* volume)
{
	int value, bestvalue;
	bspbrush_t* brush, *test;
	side_t* bestside;
	int i, j, pass, numpasses;
	int front, back, both, facing, splits;
	int bsplits, epsilonbrush;
	bool hintsplit;

	if (!volume)
		return nullptr; /* can't split empty brush */

	bestside = nullptr;
	bestvalue = -99999;

	/**
	 * 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 = 4;
	for (pass = 0; pass < numpasses; pass++) {
		for (brush = brushes; brush; brush = brush->next) {
			if ((pass & 1) && !(brush->original->contentFlags & CONTENTS_DETAIL))
				continue;
			if (!(pass & 1) && (brush->original->contentFlags & CONTENTS_DETAIL))
				continue;
			for (i = 0; i < brush->numsides; i++) {
				uint16_t pnum;
				side_t* side = &brush->sides[i];
				if (side->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;	/* already a node splitter */
				if (side->tested)
					continue;	/* we already have metrics for this plane */
				if (side->surfaceFlags & SURF_SKIP)
					continue;	/* skip surfaces are never chosen */
				if (side->visible ^ (pass < 2))
					continue;	/* only check visible faces on first pass */

				pnum = side->planenum;
				pnum &= ~1;	/* always use positive facing plane */

				if (!CheckPlaneAgainstVolume(pnum, volume))
					continue;	/* would produce a tiny volume */

				front = 0;
				back = 0;
				both = 0;
				facing = 0;
				splits = 0;
				epsilonbrush = 0;
				hintsplit = false;

				for (test = brushes; test; test = test->next) {
					const int s = TestBrushToPlanenum(test, pnum, &bsplits, &hintsplit, &epsilonbrush);

					splits += bsplits;
					if (bsplits && (s & PSIDE_FACING))
						Sys_Error("PSIDE_FACING with splits");

					test->testside = s;
					/* if the brush shares this face, don't bother
					 * testing that facenum as a splitter again */
					if (s & PSIDE_FACING) {
						facing++;
						for (j = 0; j < test->numsides; j++) {
							if ((test->sides[j].planenum &~ 1) == pnum)
								test->sides[j].tested = true;
						}
					}
					if (s & PSIDE_FRONT)
						front++;
					if (s & PSIDE_BACK)
						back++;
					if (s == PSIDE_BOTH)
						both++;
				}

				/* give a value estimate for using this plane */

				value = 5 * facing - 5 * splits - abs(front - back);
				if (AXIAL(&mapplanes[pnum]))
					value += 5;		/* axial is better */
				value -= epsilonbrush * 1000;	/* avoid! */

				/* never split a hint side except with another hint */
				if (hintsplit && !(side->surfaceFlags & 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;
					for (test = brushes; test; test = test->next)
						test->side = test->testside;
				}
			}
		}

		/* if we found a good plane, don't bother trying any other passes */
		if (bestside) {
			if (pass > 1) {
				if (threadstate.numthreads == 1)
					c_nonvis++;
			}
			break;
		}
	}

	/* clear all the tested flags we set */
	for (brush = brushes; brush; brush = brush->next) {
		for (i = 0; i < brush->numsides; i++)
			brush->sides[i].tested = false;
	}

	return bestside;
}
Example #2
0
/**
 * @brief Using a heuristic, chooses one of the sides out of the brush list
 * to partition the brushes with.
 * Returns NULL if there are no valid planes to split with..
 */
static side_t *SelectSplitSide(brush_t *brushes, node_t *node) {
	int32_t value, bestvalue;
	brush_t *brush, *test;
	side_t *side, *bestside;
	int32_t i, j, pass, numpasses;
	int32_t pnum;
	int32_t s;
	int32_t front, back, both, facing, splits;
	int32_t bsplits;
	int32_t epsilonbrush;
	_Bool hintsplit;

	bestside = NULL;
	bestvalue = -99999;

	// 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 = 4;
	for (pass = 0; pass < numpasses; pass++) {
		for (brush = brushes; brush; brush = brush->next) {
			if ((pass & 1) && !(brush->original->contents & CONTENTS_DETAIL)) {
				continue;
			}
			if (!(pass & 1) && (brush->original->contents & CONTENTS_DETAIL)) {
				continue;
			}
			for (i = 0; i < brush->num_sides; i++) {
				side = brush->sides + i;
				if (side->bevel) {
					continue;    // never use a bevel as a splitter
				}
				if (!side->winding) {
					continue;    // nothing visible, so it can't split
				}
				if (side->texinfo == TEXINFO_NODE) {
					continue;    // already a node splitter
				}
				if (side->tested) {
					continue;    // we already have metrics for this plane
				}
				if (side->surf & SURF_SKIP) {
					continue;    // skip surfaces are never chosen
				}
				if (side->visible ^ (pass < 2)) {
					continue;    // only check visible faces on first pass
				}

				pnum = side->plane_num;
				pnum &= ~1; // always 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;
				hintsplit = false;

				for (test = brushes; test; test = test->next) {
					s = TestBrushToPlanenum(test, pnum, &bsplits, &hintsplit, &epsilonbrush);

					splits += bsplits;
					if (bsplits && (s & SIDE_FACING)) {
						Com_Error(ERROR_FATAL, "SIDE_FACING with splits\n");
					}

					test->test_side = s;
					// if the brush shares this face, don't bother
					// testing that facenum as a splitter again
					if (s & SIDE_FACING) {
						facing++;
						for (j = 0; j < test->num_sides; j++) {
							if ((test->sides[j].plane_num & ~1) == pnum) {
								test->sides[j].tested = true;
							}
						}
					}
					if (s & SIDE_FRONT) {
						front++;
					}
					if (s & SIDE_BACK) {
						back++;
					}
					if (s == SIDE_BOTH) {
						both++;
					}
				}

				// give a value estimate for using this plane

				value = 5 * facing - 5 * splits - abs(front - back);
				if (AXIAL(&map_planes[pnum])) {
					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;
					for (test = brushes; test; test = test->next) {
						test->side = test->test_side;
					}
				}
			}
		}

		// if we found a good plane, don't bother trying any other passes
		if (bestside) {
			if (pass > 1) {
				if (debug) {
					SDL_SemPost(semaphores.nonvis_nodes);
				}
			}
			if (pass > 0) {
				node->detail_seperator = true;    // not needed for vis
			}
			break;
		}
	}

	// clear all the tested flags we set
	for (brush = brushes; brush; brush = brush->next) {
		for (i = 0; i < brush->num_sides; i++) {
			brush->sides[i].tested = false;
		}
	}

	return bestside;
}
side_t *SelectSplitSide (bspbrush_t *brushes, node_t *node)
{
	int			value, bestvalue;
	bspbrush_t	*brush, *test;
	side_t		*side, *bestside;
	int			i, j, 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, nonvisible-structural
	// 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)
		{
			for (i=0 ; i<brush->numsides ; i++)
			{
				side = brush->sides + i;

				if (side->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->tested)
					continue;	// we allready have metrics for this plane
				if (side->surf & SURF_SKIP)
					continue;	// skip surfaces are never chosen
				if ( side->visible ^ (pass<1) )
					continue;	// only check visible faces on first 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;

				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 the brush shares this face, don't bother
					// testing that facenum as a splitter again
					if (s & PSIDE_FACING)
					{
						facing++;
						for (j=0 ; j<test->numsides ; j++)
						{
							if ( (test->sides[j].planenum&~1) == pnum)
								test->sides[j].tested = true;
						}
					}
					if (s & PSIDE_FRONT)
						front++;
					if (s & PSIDE_BACK)
						back++;
					if (s == PSIDE_BOTH)
						both++;
				}

				// 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 (g_MainMap->mapplanes[pnum].type < 3)
					value+=5;		// axial is better
				value -= epsilonbrush*1000;	// avoid!

				// trans should split last
				if ( side->surf & SURF_TRANS )
				{
					value -= 500;
				}

				// never split a hint side except with another hint
				if (hintsplit && !(side->surf & SURF_HINT) )
					value = -9999999;

				// water should split first
				if (side->contents & (CONTENTS_WATER | CONTENTS_SLIME))
					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;
				}
			}
		}

		// if we found a good plane, don't bother trying any
		// other passes
		if (bestside)
		{
			if (pass > 0)
			{
				if (numthreads == 1)
					c_nonvis++;
			}
			break;
		}
	}

	//
	// clear all the tested flags we set
	//
	for (brush = brushes ; brush ; brush=brush->next)
	{
		for (i=0 ; i<brush->numsides ; i++)
			brush->sides[i].tested = false;
	}

	return bestside;
}
Example #4
0
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			j;
	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 on 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