mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-15 15:51:07 +02:00
dmap now contains path tracing optimizations stored in iceproc files.
This commit is contained in:
@@ -39,6 +39,33 @@ int numInterAreaPortals;
|
||||
int c_active_portals;
|
||||
int c_peak_portals;
|
||||
|
||||
static int c_autoAreaRefineSplits;
|
||||
static int c_autoAreaRefinePortals;
|
||||
static int c_autoAreaRefineFlood;
|
||||
|
||||
#define AUTO_AREA_REFINE_MIN_LEAFS 12
|
||||
#define AUTO_AREA_REFINE_MIN_SPLIT_LEAFS 4
|
||||
#define AUTO_AREA_REFINE_MAX_SPLITS 256
|
||||
#define AUTO_AREA_REFINE_MIN_PORTAL_AREA 64.0f
|
||||
#define AUTO_AREA_REFINE_MAX_PORTAL_AREA 65536.0f
|
||||
|
||||
/*
|
||||
=============
|
||||
ClearInterAreaPortals
|
||||
=============
|
||||
*/
|
||||
void ClearInterAreaPortals( void ) {
|
||||
for ( int i = 0 ; i < numInterAreaPortals ; i++ ) {
|
||||
if ( interAreaPortals[i].generated && interAreaPortals[i].winding ) {
|
||||
delete interAreaPortals[i].winding;
|
||||
}
|
||||
interAreaPortals[i].side = NULL;
|
||||
interAreaPortals[i].winding = NULL;
|
||||
interAreaPortals[i].generated = false;
|
||||
}
|
||||
numInterAreaPortals = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
AllocPortal
|
||||
@@ -824,10 +851,244 @@ void ClearAreas_r( node_t *node ) {
|
||||
return;
|
||||
}
|
||||
node->area = -1;
|
||||
node->originalArea = -1;
|
||||
node->areaRefineFlood = 0;
|
||||
}
|
||||
|
||||
//=============================================================
|
||||
|
||||
static void MarkOriginalAreas_r( node_t *node ) {
|
||||
if ( node->planenum != PLANENUM_LEAF ) {
|
||||
MarkOriginalAreas_r( node->children[0] );
|
||||
MarkOriginalAreas_r( node->children[1] );
|
||||
return;
|
||||
}
|
||||
node->originalArea = node->area;
|
||||
}
|
||||
|
||||
static void CollectAreaLeaves_r( node_t *node, int area, idList<node_t *> &leaves ) {
|
||||
if ( node->planenum != PLANENUM_LEAF ) {
|
||||
CollectAreaLeaves_r( node->children[0], area, leaves );
|
||||
CollectAreaLeaves_r( node->children[1], area, leaves );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !node->opaque && node->area == area ) {
|
||||
leaves.Append( node );
|
||||
}
|
||||
}
|
||||
|
||||
static void FloodAreaComponent_r( node_t *node, int area, const uPortal_t *blockedPortal, int floodNum, idList<node_t *> &component ) {
|
||||
uPortal_t *p;
|
||||
int s;
|
||||
|
||||
if ( node->planenum != PLANENUM_LEAF || node->opaque || node->area != area ) {
|
||||
return;
|
||||
}
|
||||
if ( node->areaRefineFlood == floodNum ) {
|
||||
return;
|
||||
}
|
||||
|
||||
node->areaRefineFlood = floodNum;
|
||||
component.Append( node );
|
||||
|
||||
for ( p = node->portals ; p ; p = p->next[s] ) {
|
||||
s = ( p->nodes[1] == node );
|
||||
|
||||
if ( p == blockedPortal ) {
|
||||
continue;
|
||||
}
|
||||
if ( !Portal_Passable( p ) ) {
|
||||
continue;
|
||||
}
|
||||
FloodAreaComponent_r( p->nodes[!s], area, blockedPortal, floodNum, component );
|
||||
}
|
||||
}
|
||||
|
||||
static uPortal_t *FindBestAutoAreaPortal( int area, const idList<node_t *> &leaves ) {
|
||||
uPortal_t *bestPortal;
|
||||
float bestScore;
|
||||
|
||||
bestPortal = NULL;
|
||||
bestScore = 0.0f;
|
||||
|
||||
for ( int i = 0 ; i < leaves.Num() ; i++ ) {
|
||||
node_t *node = leaves[i];
|
||||
int s;
|
||||
|
||||
for ( uPortal_t *p = node->portals ; p ; p = p->next[s] ) {
|
||||
s = ( p->nodes[1] == node );
|
||||
|
||||
if ( p->nodes[0] != node ) {
|
||||
continue; // evaluate each portal once
|
||||
}
|
||||
if ( !Portal_Passable( p ) ) {
|
||||
continue;
|
||||
}
|
||||
if ( p->nodes[1]->area != area ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float portalArea = p->winding->GetArea();
|
||||
if ( portalArea < AUTO_AREA_REFINE_MIN_PORTAL_AREA || portalArea > AUTO_AREA_REFINE_MAX_PORTAL_AREA ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
idList<node_t *> component;
|
||||
FloodAreaComponent_r( p->nodes[0], area, p, ++c_autoAreaRefineFlood, component );
|
||||
|
||||
int frontLeafs = component.Num();
|
||||
int backLeafs = leaves.Num() - frontLeafs;
|
||||
if ( frontLeafs < AUTO_AREA_REFINE_MIN_SPLIT_LEAFS || backLeafs < AUTO_AREA_REFINE_MIN_SPLIT_LEAFS ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int smaller = frontLeafs < backLeafs ? frontLeafs : backLeafs;
|
||||
int larger = frontLeafs > backLeafs ? frontLeafs : backLeafs;
|
||||
float balance = (float)smaller / (float)larger;
|
||||
float score = balance * 100000.0f / portalArea;
|
||||
|
||||
if ( score > bestScore ) {
|
||||
bestScore = score;
|
||||
bestPortal = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bestPortal;
|
||||
}
|
||||
|
||||
static bool SplitAreaWithGeneratedPortal( uEntity_t *e, int area ) {
|
||||
idList<node_t *> leaves;
|
||||
idList<node_t *> component;
|
||||
|
||||
CollectAreaLeaves_r( e->tree->headnode, area, leaves );
|
||||
if ( leaves.Num() < AUTO_AREA_REFINE_MIN_LEAFS ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uPortal_t *portal = FindBestAutoAreaPortal( area, leaves );
|
||||
if ( !portal ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int floodNum = ++c_autoAreaRefineFlood;
|
||||
FloodAreaComponent_r( portal->nodes[0], area, portal, floodNum, component );
|
||||
if ( component.Num() <= 0 || component.Num() >= leaves.Num() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int newArea = e->numAreas;
|
||||
e->numAreas++;
|
||||
|
||||
// Keep the larger partition on the original area number so repeated
|
||||
// refinement tends to continue from the broadest remaining space.
|
||||
if ( component.Num() <= leaves.Num() / 2 ) {
|
||||
for ( int i = 0 ; i < component.Num() ; i++ ) {
|
||||
component[i]->area = newArea;
|
||||
}
|
||||
} else {
|
||||
for ( int i = 0 ; i < leaves.Num() ; i++ ) {
|
||||
if ( leaves[i]->areaRefineFlood != floodNum ) {
|
||||
leaves[i]->area = newArea;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c_autoAreaRefineSplits++;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void AutoRefineAreas( uEntity_t *e ) {
|
||||
int startingAreas;
|
||||
|
||||
if ( !dmapGlobals.autoAreaRefine ) {
|
||||
return;
|
||||
}
|
||||
if ( e != &dmapGlobals.uEntities[0] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
startingAreas = e->numAreas;
|
||||
c_autoAreaRefineSplits = 0;
|
||||
c_autoAreaRefinePortals = 0;
|
||||
c_autoAreaRefineFlood = 0;
|
||||
|
||||
for ( int area = 0 ; area < e->numAreas && c_autoAreaRefineSplits < AUTO_AREA_REFINE_MAX_SPLITS ; area++ ) {
|
||||
while ( c_autoAreaRefineSplits < AUTO_AREA_REFINE_MAX_SPLITS ) {
|
||||
if ( !SplitAreaWithGeneratedPortal( e, area ) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( c_autoAreaRefineSplits > 0 ) {
|
||||
common->Printf( "%5i auto area refinement splits (%i -> %i areas)\n", c_autoAreaRefineSplits, startingAreas, e->numAreas );
|
||||
} else {
|
||||
common->Printf( "%5i auto area refinement splits\n", 0 );
|
||||
}
|
||||
}
|
||||
|
||||
static void AddGeneratedInterAreaPortal( uPortal_t *p ) {
|
||||
if ( numInterAreaPortals >= MAX_INTER_AREA_PORTALS ) {
|
||||
common->Warning( "MAX_INTER_AREA_PORTALS hit while adding generated area portals" );
|
||||
return;
|
||||
}
|
||||
if ( !p->winding || p->winding->IsTiny() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
interAreaPortal_t *iap = &interAreaPortals[numInterAreaPortals];
|
||||
numInterAreaPortals++;
|
||||
|
||||
iap->area0 = p->nodes[0]->area;
|
||||
iap->area1 = p->nodes[1]->area;
|
||||
iap->side = NULL;
|
||||
iap->winding = p->winding->Copy();
|
||||
iap->generated = true;
|
||||
c_autoAreaRefinePortals++;
|
||||
}
|
||||
|
||||
static void FindGeneratedInterAreaPortals_r( node_t *node ) {
|
||||
uPortal_t *p;
|
||||
int s;
|
||||
|
||||
if ( node->planenum != PLANENUM_LEAF ) {
|
||||
FindGeneratedInterAreaPortals_r( node->children[0] );
|
||||
FindGeneratedInterAreaPortals_r( node->children[1] );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( node->opaque ) {
|
||||
return;
|
||||
}
|
||||
|
||||
for ( p = node->portals ; p ; p = p->next[s] ) {
|
||||
node_t *other;
|
||||
|
||||
s = ( p->nodes[1] == node );
|
||||
other = p->nodes[!s];
|
||||
|
||||
if ( other->opaque ) {
|
||||
continue;
|
||||
}
|
||||
if ( !Portal_Passable( p ) ) {
|
||||
continue;
|
||||
}
|
||||
if ( other->area <= node->area ) {
|
||||
continue;
|
||||
}
|
||||
if ( other->originalArea != node->originalArea ) {
|
||||
continue; // authored areaportal boundary
|
||||
}
|
||||
if ( FindSideForPortal( p ) ) {
|
||||
continue; // designer-authored portal, already emitted
|
||||
}
|
||||
|
||||
AddGeneratedInterAreaPortal( p );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
@@ -895,6 +1156,11 @@ static void FindInterAreaPortals_r( node_t *node ) {
|
||||
continue; // already emited
|
||||
}
|
||||
|
||||
if ( numInterAreaPortals >= MAX_INTER_AREA_PORTALS ) {
|
||||
common->Warning( "MAX_INTER_AREA_PORTALS hit while adding designer area portals" );
|
||||
continue;
|
||||
}
|
||||
|
||||
iap = &interAreaPortals[numInterAreaPortals];
|
||||
numInterAreaPortals++;
|
||||
if ( side->planenum == p->onnode->planenum ) {
|
||||
@@ -905,6 +1171,8 @@ static void FindInterAreaPortals_r( node_t *node ) {
|
||||
iap->area1 = p->nodes[0]->area;
|
||||
}
|
||||
iap->side = side;
|
||||
iap->winding = NULL;
|
||||
iap->generated = false;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -934,13 +1202,20 @@ void FloodAreas( uEntity_t *e ) {
|
||||
common->Printf ("%5i areas\n", c_areas);
|
||||
e->numAreas = c_areas;
|
||||
|
||||
MarkOriginalAreas_r( e->tree->headnode );
|
||||
AutoRefineAreas( e );
|
||||
|
||||
// make sure we got all of them
|
||||
CheckAreas_r( e->tree->headnode );
|
||||
|
||||
// identify all portals between areas if this is the world
|
||||
if ( e == &dmapGlobals.uEntities[0] ) {
|
||||
numInterAreaPortals = 0;
|
||||
ClearInterAreaPortals();
|
||||
FindInterAreaPortals_r( e->tree->headnode );
|
||||
if ( dmapGlobals.autoAreaRefine ) {
|
||||
FindGeneratedInterAreaPortals_r( e->tree->headnode );
|
||||
common->Printf( "%5i generated inter-area portals\n", c_autoAreaRefinePortals );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user