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.

169 lines
4.0 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=====================================================================================//
  6. #include "imagepacker.h"
  7. #include "materialsystem_global.h"
  8. #include "IHardwareConfigInternal.h"
  9. // NOTE: This has to be the last file included
  10. #include "tier0/memdbgon.h"
  11. float CImagePacker::GetEfficiency( void )
  12. {
  13. return ( float )m_AreaUsed / ( float )( m_MaxLightmapWidth * CeilPow2( m_MinimumHeight ) );
  14. }
  15. bool CImagePacker::Reset( int nSortId, int maxLightmapWidth, int maxLightmapHeight )
  16. {
  17. int i;
  18. Assert( maxLightmapWidth <= MAX_MAX_LIGHTMAP_WIDTH );
  19. m_MaxLightmapWidth = maxLightmapWidth;
  20. m_MaxLightmapHeight = maxLightmapHeight;
  21. m_MaxBlockWidth = maxLightmapWidth + 1;
  22. m_MaxBlockHeight = maxLightmapHeight + 1;
  23. m_nSortID = nSortId;
  24. m_AreaUsed = 0;
  25. m_MinimumHeight = -1;
  26. for( i = 0; i < m_MaxLightmapWidth; i++ )
  27. {
  28. m_pLightmapWavefront[i] = -1;
  29. }
  30. return true;
  31. }
  32. inline int CImagePacker::GetMaxYIndex( int firstX, int width )
  33. {
  34. int maxY = -1;
  35. int maxYIndex = 0;
  36. for( int x = firstX; x < firstX + width; ++x )
  37. {
  38. // NOTE: Want the equals here since we'll never be able to fit
  39. // in between the multiple instances of maxY
  40. if( m_pLightmapWavefront[x] >= maxY )
  41. {
  42. maxY = m_pLightmapWavefront[x];
  43. maxYIndex = x;
  44. }
  45. }
  46. return maxYIndex;
  47. }
  48. //#define ADD_ONE_TEXEL_BORDER
  49. bool CImagePacker::AddBlock( int width, int height,
  50. int *returnX, int *returnY )
  51. {
  52. #ifdef ADD_ONE_TEXEL_BORDER
  53. width += 2;
  54. height += 2;
  55. width = clamp( width, m_MaxLightmapWidth );
  56. height = clamp( height, m_MaxLightmapHeight );
  57. #endif
  58. // If we've already determined that a block this big couldn't fit
  59. // then blow off checking again...
  60. if ( ( width >= m_MaxBlockWidth ) && ( height >= m_MaxBlockHeight ) )
  61. return false;
  62. int bestX = -1;
  63. int maxYIdx;
  64. int outerX = 0;
  65. int outerMinY = m_MaxLightmapHeight;
  66. int lastX = m_MaxLightmapWidth - width;
  67. int lastMaxYVal = -2;
  68. while (outerX <= lastX)
  69. {
  70. // Skip all tiles that have the last Y value, these
  71. // aren't going to change our min Y value
  72. if (m_pLightmapWavefront[outerX] == lastMaxYVal)
  73. {
  74. ++outerX;
  75. continue;
  76. }
  77. maxYIdx = GetMaxYIndex( outerX, width );
  78. lastMaxYVal = m_pLightmapWavefront[maxYIdx];
  79. if (outerMinY > lastMaxYVal)
  80. {
  81. outerMinY = lastMaxYVal;
  82. bestX = outerX;
  83. // Early out for the first row...
  84. // if (outerMinY == -1)
  85. // break;
  86. }
  87. outerX = maxYIdx + 1;
  88. }
  89. if( bestX == -1 )
  90. {
  91. // If we failed to add it, remember the block size that failed
  92. // *only if both dimensions are smaller*!!
  93. // Just because a 1x10 block failed, doesn't mean a 10x1 block will fail
  94. if ( ( width <= m_MaxBlockWidth ) && ( height <= m_MaxBlockHeight ) )
  95. {
  96. m_MaxBlockWidth = width;
  97. m_MaxBlockHeight = height;
  98. }
  99. return false;
  100. }
  101. // Set the return positions for the block.
  102. *returnX = bestX;
  103. *returnY = outerMinY + 1;
  104. // Check if it actually fit height-wise.
  105. // hack
  106. // if( *returnY + height > maxLightmapHeight )
  107. if( *returnY + height >= m_MaxLightmapHeight - 1 )
  108. {
  109. if ( ( width <= m_MaxBlockWidth ) && ( height <= m_MaxBlockHeight ) )
  110. {
  111. m_MaxBlockWidth = width;
  112. m_MaxBlockHeight = height;
  113. }
  114. return false;
  115. }
  116. // It fit!
  117. // Keep up with the smallest possible size for the image so far.
  118. if( *returnY + height > m_MinimumHeight )
  119. m_MinimumHeight = *returnY + height;
  120. // Update the wavefront info.
  121. int x;
  122. for( x = bestX; x < bestX + width; x++ )
  123. {
  124. m_pLightmapWavefront[x] = outerMinY + height;
  125. }
  126. // AddBlockToLightmapImage( *returnX, *returnY, width, height );
  127. m_AreaUsed += width * height;
  128. #ifdef ADD_ONE_TEXEL_BORDER
  129. *returnX++;
  130. *returnY++;
  131. #endif
  132. return true;
  133. }
  134. void CImagePacker::GetMinimumDimensions( int *pReturnWidth, int *pReturnHeight )
  135. {
  136. *pReturnWidth = CeilPow2( m_MaxLightmapWidth );
  137. *pReturnHeight = CeilPow2( m_MinimumHeight );
  138. int aspect = *pReturnWidth / *pReturnHeight;
  139. if (aspect > HardwareConfig()->MaxTextureAspectRatio())
  140. {
  141. *pReturnHeight = *pReturnWidth / HardwareConfig()->MaxTextureAspectRatio();
  142. }
  143. }