#include #include #include #include #include // // TODO - Replace this with a real variable setting // #define DEV_NUM_BINS 1024 /////////////////////////////////////////////////////////////////////////////////////////// // External Functions // // Used in sorting process for centroids // Subtracting 1 is compensation for integral truncation in conversion /////////////////////////////////////////////////////////////////////////////////////////// // // TODO - inline it! // inline int CompareCellN( Cell* ipCell1, Cell* ipCell2, int iIndex ) { // // Is there anyway to preserve non-zero sign faster for wholly fractional differences? // If not, you can always accept truncation loss // float Diff = ((Cell*)ipCell1)->Centroid(iIndex) - ((Cell*)ipCell2)->Centroid(iIndex); if( Diff > 0.0f ) return 1; if( Diff < 0.0f ) return -1; return 0; //Lossy version // return (int)( ((Cell*)ipCell1)->Centroid(iIndex) - ((Cell*)ipCell2)->Centroid(iIndex) -1); // } int CompareCellXs( const void* ipCell1, const void* ipCell2) { return CompareCellN( ((Cell*)ipCell1), ((Cell*)ipCell2), 0); } int CompareCellYs( const void* ipCell1, const void* ipCell2) { return CompareCellN( ((Cell*)ipCell1), ((Cell*)ipCell2), 1); } int CompareCellZs( const void* ipCell1, const void* ipCell2) { return CompareCellN( ((Cell*)ipCell1), ((Cell*)ipCell2), 2); } /////////////////////////////////////////////////////////////////////////////////////////// // Data List // // int mSize; // int mWeightedSize; // Cell* mpCellList; // Bounds3f mBounds; /////////////////////////////////////////////////////////////////////////////////////////// CoordSubList::CoordSubList( Cell* ipCellList, int iSize, int iWeightedSize, Bounds3f& irBounds ) { mpCellList = ipCellList; mSize = iSize; mWeightedSize = iWeightedSize; mSpans.SetToSpan( irBounds.mMin, irBounds.mMax ); } CoordSubList::CoordSubList( Cell* ipCellList, int iSize, Vector3i iSpans ) { mpCellList = ipCellList; mSize = iSize; mSpans = iSpans; GenWeightedSize(); } CoordSubList::CoordSubList( Cell* ipCellList, int iSize ) { mpCellList = ipCellList; mSize = iSize; GenerateMembers(); } CoordSubList::CoordSubList() { mpCellList = NULL; mSize = 0; } CoordSubList::~CoordSubList() { } // // Generate deterministic members // // WeightedSize // Spans // void CoordSubList::GenerateMembers() { GenWeightedSize(); GenSpans(); } void CoordSubList::GenWeightedSize() { int i; mWeightedSize = 0; for( i=0; i-1 && i 1 ) { for( int iAxis=0; iAxis<3; iAxis++ ) { for( int i=1; i= mSize || List1Size <= 0 ) { bool fuckedUp = true; iorAxis = -1; List1Size = FindSplitIndex( iorAxis, 0 ); } SeekMinPlane( orPlanePosn, List1Size, iorAxis ); *opList1 = new(GMA_TEMP) CoordSubList( mpCellList, List1Size); *opList2 = new(GMA_TEMP) CoordSubList( &(mpCellList[List1Size]), mSize - List1Size); MEMTRACK_POP_GROUP("CoortSubList"); } // // SubDivide the List // void CoordSubList::SubDivideUniform( int iAxis, CoordSubList** opList1, CoordSubList** opList2 ) { rAssert( mpCellList ); rAssert( false ); // not implemented if( iAxis == -1 ) { iAxis = ChooseAxis(); } } // // TODO -rename these GetWeightedMedian's to reflect what the second one does; distinguish // int CoordSubList::GetWeightedMedian( int iAxis ) { int MedianWeightCount = mWeightedSize / 2; int WeightCount = 0; int i=-1; // for( i = 0; (i < mSize) && (WeightCount < MedianWeightCount); i++ ) // { // WeightCount += mpCellList[i].RenderWeight(); // } do { i++; WeightCount += mpCellList[i].RenderWeight(); } while( (i MedianWeightCount ) { if(i-1>=0) { i--; } } return i; } int CoordSubList::GetWeightedMedian( float& orPlanePosn, int iAxis ) { int i = GetWeightedMedian( iAxis ); return GetPlanarDivision( orPlanePosn, iAxis, i ); } int CoordSubList::GetPlanarDivision( float& orPlanePosn, int iAxis, int iIndex ) { int DivisionIndex = mpCellList[iIndex].BlockIndex(iAxis); orPlanePosn = mpCellList[iIndex].MaxPlane(iAxis); for( iIndex++; (iIndex 0 ) { BinCount( MedianDeviation[ioAxis], MedianBin[ioAxis], ioAxis ); if( MedianDeviation[ioAxis] <= iDeviationThreshold ) { return BinSort( MedianBin[ioAxis], ioAxis ); } } else { //Don't consider this axis MedianDeviation[ioAxis] = mWeightedSize; MedianBin[ioAxis] = mSize+1; } } /* BinCount( MedianDeviation.mY, MedianBin.mY, 1 ); if( MedianDeviation.mY < iDeviationThreshold ) { return BinSort( MedianBin.mY, 1 ); } BinCount( MedianDeviation.mZ, MedianBin.mZ, 2 ); if( MedianDeviation.mZ < iDeviationThreshold ) { return BinSort( MedianBin.mZ, 2 ); } */ ioAxis = MedianDeviation.MinIndex(); return BinSort( MedianBin[ioAxis], ioAxis ); } else { BinCount( MedianDeviation[ioAxis], MedianBin[ioAxis], ioAxis ); return BinSort( MedianBin[ioAxis], ioAxis ); } } /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// void CoordSubList::BinCount( int& oMedianDeviation, int& oMedianBin, int iAxis ) { int i, Count=0, nNonEmptyBins=0; SubArray Bins; theCullCache().Acquire( Bins, DEV_NUM_BINS ); Bins.SetAll(Count); //Get Total, Bin Count List for( i=0; i0); i++ ) { Count -= Bins[i]; } i--; //Find the best approximate median if( Count < Bins[i]/-2 ) { Count += Bins[i]; oMedianBin = i; } else { Count = rmt::Abs( Count ); oMedianBin = i+1; } oMedianDeviation = Count; theCullCache().Release( Bins ); } /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// int CoordSubList::BinSort( int iMedianBin, int iAxis ) { int RightIndex = mSize-1; Cell temp; Cell* left = &(mpCellList[0]); Cell* right = &(mpCellList[RightIndex]); while( left!=right ) { if( left->BlockIndex(iAxis) < iMedianBin ) { left++; } else { //left > MedianBin; //left needs to be swapped with a right < Median if( right->BlockIndex(iAxis) < iMedianBin ) { temp = *right; *right = *left; *left = temp; left++; if( left!=right ) { right--; RightIndex--; } } else { right--; RightIndex--; /* //In the case where they overlap, ensure right ends on GT if( left == right ) { if( right->BlockIndex(iAxis) < iMedianBin ) { RightIndex++; } } */ } } } //Debug if( right->BlockIndex(iAxis) < iMedianBin ) { rAssert( (right+1)->BlockIndex(iAxis) >= iMedianBin ); RightIndex++; } float minPlane; SeekMinPlane( minPlane, RightIndex, iAxis ); return RightIndex; } /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// void CoordSubList::SeekMinPlane( float& oPlanePosn, int i, int iAxis ) { //Debug float LTMaxPlane; SeekMaxPlane( LTMaxPlane, 0, i, iAxis); //Debug oPlanePosn = mpCellList[i].MinPlane(iAxis); for( i++; i oPlanePosn ) { oPlanePosn = mpCellList[iCur].MaxPlane(iAxis); } } } /* int CoordSubList::GetPlanarDivision( float& orPlanePosn, int iAxis, int iIndex ) { orPlanePosn = mpCellList[iIndex].MaxPlane(iAxis); for( iIndex++; (iIndex= mSpans[1] ) { if( mSpans[0] >= mSpans[2] ) { return 0; } else { return 2; } } else { if( mSpans[1] >= mSpans[2] ) { return 1; } else { return 2; } } */ } /* char CoordSubList::BestSpreadAxis() { int i, i_plane, weightCount, MedianWeight = mWeightedSize/2; Vector3i LTCounts, GTCounts; qsort( mpCellList, mSize, sizeof(Cell), CompareCellXs ); for( i=0, weightCount=0; (i MedianWeight ) { if(i-1>=0) { i--; } } i_plane = GetPlanarDivision( junkedPlane, 0, i ); qsort( mpCellList, mSize, sizeof(Cell), CompareCellYs ); qsort( mpCellList, mSize, sizeof(Cell), CompareCellZs ); mpCellList.mpData[i]. } */