/* ==================== CheckWindingInAreas_r Returns the area number that the winding is in, or -2 if it crosses multiple areas. ==================== */ static int CheckWindingInAreas_r( const idWinding* w, node_t* node ) { idWinding* front, *back; if( !w ) { return -1; } if( node->planenum != PLANENUM_LEAF ) { int a1, a2; #if 0 if( side->planenum == node->planenum ) { return CheckWindingInAreas_r( w, node->children[0] ); } if( side->planenum == ( node->planenum ^ 1 ) ) { return CheckWindingInAreas_r( w, node->children[1] ); } #endif w->Split( dmapGlobals.mapPlanes[ node->planenum ], ON_EPSILON, &front, &back ); a1 = CheckWindingInAreas_r( front, node->children[0] ); delete front; a2 = CheckWindingInAreas_r( back, node->children[1] ); delete back; if( a1 == -2 || a2 == -2 ) { return -2; // different } if( a1 == -1 ) { return a2; // one solid } if( a2 == -1 ) { return a1; // one solid } if( a1 != a2 ) { return -2; // cross areas } return a1; } return node->area; }
/* ==================== PutWindingIntoAreas_r Clips a winding down into the bsp tree, then converts the fragments to triangles and adds them to the area lists ==================== */ static void PutWindingIntoAreas_r( uEntity_t *e, const idWinding *w, side_t *side, node_t *node ) { idWinding *front, *back; int area; if ( !w ) { return; } if ( node->planenum != PLANENUM_LEAF ) { if ( side->planenum == node->planenum ) { PutWindingIntoAreas_r( e, w, side, node->children[0] ); return; } if ( side->planenum == ( node->planenum ^ 1) ) { PutWindingIntoAreas_r( e, w, side, node->children[1] ); return; } // see if we need to split it // adding the "noFragment" flag to big surfaces like sky boxes // will avoid potentially dicing them up into tons of triangles // that take forever to optimize back together if ( !dmapGlobals.fullCarve || side->material->NoFragment() ) { area = CheckWindingInAreas_r( w, node ); if ( area >= 0 ) { mapTri_t *tri; // put in single area tri = TriListForSide( side, w ); AddTriListToArea( e, tri, side->planenum, area, &side->texVec ); return; } } w->Split( dmapGlobals.mapPlanes[ node->planenum ], ON_EPSILON, &front, &back ); PutWindingIntoAreas_r( e, front, side, node->children[0] ); if ( front ) { delete front; } PutWindingIntoAreas_r( e, back, side, node->children[1] ); if ( back ) { delete back; } return; } // if opaque leaf, don't add if ( node->area >= 0 && !node->opaque ) { mapTri_t *tri; tri = TriListForSide( side, w ); AddTriListToArea( e, tri, side->planenum, node->area, &side->texVec ); } }
/* ================== AddMapTriToAreas Used for curves and inlined models ================== */ void AddMapTriToAreas( mapTri_t* tri, uEntity_t* e ) { int area; idWinding* w; // skip degenerate triangles from pinched curves if( MapTriArea( tri ) <= 0 ) { return; } if( dmapGlobals.fullCarve ) { // always fragment into areas w = WindingForTri( tri ); ClipTriIntoTree_r( w, tri, e, e->tree->headnode ); return; } w = WindingForTri( tri ); area = CheckWindingInAreas_r( w, e->tree->headnode ); delete w; if( area == -1 ) { return; } if( area >= 0 ) { mapTri_t* newTri; idPlane plane; int planeNum; textureVectors_t texVec; // put in single area newTri = CopyMapTri( tri ); newTri->next = NULL; PlaneForTri( tri, plane ); planeNum = FindFloatPlane( plane ); TexVecForTri( &texVec, newTri ); AddTriListToArea( e, newTri, planeNum, area, &texVec ); } else { // fragment into areas w = WindingForTri( tri ); ClipTriIntoTree_r( w, tri, e, e->tree->headnode ); } }