Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=====================================================================================//
#include "imagepacker.h"
#include "materialsystem_global.h"
#include "IHardwareConfigInternal.h"
// NOTE: This has to be the last file included
#include "tier0/memdbgon.h"
float CImagePacker::GetEfficiency( void ) { return ( float )m_AreaUsed / ( float )( m_MaxLightmapWidth * CeilPow2( m_MinimumHeight ) ); }
bool CImagePacker::Reset( int nSortId, int maxLightmapWidth, int maxLightmapHeight ) { int i; Assert( maxLightmapWidth <= MAX_MAX_LIGHTMAP_WIDTH ); m_MaxLightmapWidth = maxLightmapWidth; m_MaxLightmapHeight = maxLightmapHeight; m_MaxBlockWidth = maxLightmapWidth + 1; m_MaxBlockHeight = maxLightmapHeight + 1;
m_nSortID = nSortId;
m_AreaUsed = 0; m_MinimumHeight = -1; for( i = 0; i < m_MaxLightmapWidth; i++ ) { m_pLightmapWavefront[i] = -1; } return true; }
inline int CImagePacker::GetMaxYIndex( int firstX, int width ) { int maxY = -1; int maxYIndex = 0; for( int x = firstX; x < firstX + width; ++x ) { // NOTE: Want the equals here since we'll never be able to fit
// in between the multiple instances of maxY
if( m_pLightmapWavefront[x] >= maxY ) { maxY = m_pLightmapWavefront[x]; maxYIndex = x; } } return maxYIndex; }
//#define ADD_ONE_TEXEL_BORDER
bool CImagePacker::AddBlock( int width, int height, int *returnX, int *returnY ) { #ifdef ADD_ONE_TEXEL_BORDER
width += 2; height += 2; width = clamp( width, m_MaxLightmapWidth ); height = clamp( height, m_MaxLightmapHeight ); #endif
// If we've already determined that a block this big couldn't fit
// then blow off checking again...
if ( ( width >= m_MaxBlockWidth ) && ( height >= m_MaxBlockHeight ) ) return false;
int bestX = -1; int maxYIdx; int outerX = 0; int outerMinY = m_MaxLightmapHeight; int lastX = m_MaxLightmapWidth - width; int lastMaxYVal = -2; while (outerX <= lastX) { // Skip all tiles that have the last Y value, these
// aren't going to change our min Y value
if (m_pLightmapWavefront[outerX] == lastMaxYVal) { ++outerX; continue; }
maxYIdx = GetMaxYIndex( outerX, width ); lastMaxYVal = m_pLightmapWavefront[maxYIdx]; if (outerMinY > lastMaxYVal) { outerMinY = lastMaxYVal; bestX = outerX;
// Early out for the first row...
// if (outerMinY == -1)
// break;
} outerX = maxYIdx + 1; } if( bestX == -1 ) { // If we failed to add it, remember the block size that failed
// *only if both dimensions are smaller*!!
// Just because a 1x10 block failed, doesn't mean a 10x1 block will fail
if ( ( width <= m_MaxBlockWidth ) && ( height <= m_MaxBlockHeight ) ) { m_MaxBlockWidth = width; m_MaxBlockHeight = height; }
return false; } // Set the return positions for the block.
*returnX = bestX; *returnY = outerMinY + 1; // Check if it actually fit height-wise.
// hack
// if( *returnY + height > maxLightmapHeight )
if( *returnY + height >= m_MaxLightmapHeight - 1 ) { if ( ( width <= m_MaxBlockWidth ) && ( height <= m_MaxBlockHeight ) ) { m_MaxBlockWidth = width; m_MaxBlockHeight = height; }
return false; } // It fit!
// Keep up with the smallest possible size for the image so far.
if( *returnY + height > m_MinimumHeight ) m_MinimumHeight = *returnY + height; // Update the wavefront info.
int x; for( x = bestX; x < bestX + width; x++ ) { m_pLightmapWavefront[x] = outerMinY + height; } // AddBlockToLightmapImage( *returnX, *returnY, width, height );
m_AreaUsed += width * height; #ifdef ADD_ONE_TEXEL_BORDER
*returnX++; *returnY++; #endif
return true; }
void CImagePacker::GetMinimumDimensions( int *pReturnWidth, int *pReturnHeight ) { *pReturnWidth = CeilPow2( m_MaxLightmapWidth ); *pReturnHeight = CeilPow2( m_MinimumHeight );
int aspect = *pReturnWidth / *pReturnHeight; if (aspect > HardwareConfig()->MaxTextureAspectRatio()) { *pReturnHeight = *pReturnWidth / HardwareConfig()->MaxTextureAspectRatio(); } }
|