Counter Strike : Global Offensive Source Code
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.

273 lines
6.6 KiB

  1. //=========== Copyright � Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Mesh class UV parameterization operations.
  4. //
  5. //===========================================================================//
  6. #include "mesh.h"
  7. class CPackNode
  8. {
  9. public:
  10. CPackNode* m_child[2];
  11. Rect_t m_rect;
  12. AtlasChart_t* m_pChart;
  13. float m_flTotalW;
  14. float m_flTotalH;
  15. public:
  16. CPackNode( Rect_t rect, float flTotalW, float flTotalH );
  17. ~CPackNode();
  18. CPackNode *InsertChart( AtlasChart_t* pTexture );
  19. };
  20. class CAtlasPacker
  21. {
  22. private:
  23. int m_nWidth;
  24. int m_nHeight;
  25. CPackNode *m_pRootNode;
  26. public:
  27. CAtlasPacker();
  28. ~CAtlasPacker();
  29. void Init( int nWidth, int nHeight );
  30. bool InsertChart( AtlasChart_t *pTexture );
  31. };
  32. int SortAtlasCharts( AtlasChart_t* const *pOne, AtlasChart_t* const *pTwo )
  33. {
  34. int nSizeOne = MAX( (*pOne)->m_vMaxTextureSize.x, (*pOne)->m_vMaxTextureSize.y );
  35. int nSizeTwo = MAX( (*pTwo)->m_vMaxTextureSize.x, (*pTwo)->m_vMaxTextureSize.y );
  36. if ( nSizeOne < nSizeTwo )
  37. return -1;
  38. else if ( nSizeOne > nSizeTwo )
  39. return 1;
  40. return 0;
  41. }
  42. //--------------------------------------------------------------------------------------
  43. // Pack charts into an atlas. If nAtlasGrow is non-zero, we will attempt to create an atlas
  44. // starting at nAtlasTextureSizeX and growing by nAtlasGrow every time until we eventually
  45. // get an atlas. If nAtlasGrow is 0, then we return the number of charts that didn't
  46. // get atlased.
  47. //--------------------------------------------------------------------------------------
  48. int PackChartsIntoAtlas( AtlasChart_t *pCharts, int nCharts, int nAtlasTextureSizeX, int nAtlasTextureSizeY, int nAtlasGrow )
  49. {
  50. // Create a duplicate vector to sort so that the input remains in the same order
  51. CUtlVector<AtlasChart_t*> chartVector;
  52. CUtlVector<bool> chartUsed;
  53. chartVector.EnsureCount( nCharts );
  54. chartUsed.EnsureCount( nCharts );
  55. for ( int c=0; c<nCharts; ++c )
  56. {
  57. chartVector[ c ] = &pCharts[ c ];
  58. chartUsed[ c ] = false;
  59. }
  60. chartVector.Sort( SortAtlasCharts );
  61. // Try to get the most out of our texture space
  62. bool bTryGrow = ( nAtlasGrow > 0 );
  63. bool bHaveAtlas = false;
  64. int nAtlasSizeX = nAtlasTextureSizeX;
  65. int nAtlasSizeY = nAtlasTextureSizeY;
  66. int nAttempt = 0;
  67. int nUnatlased = 0;
  68. while ( !bHaveAtlas )
  69. {
  70. Msg( "Atlas Attempt: %d\n", nAttempt );
  71. // assume we have an atlas
  72. bHaveAtlas = true;
  73. // increment and try again
  74. nAtlasSizeX += nAtlasGrow;
  75. nAtlasSizeY += nAtlasGrow;
  76. CAtlasPacker m_packer;
  77. m_packer.Init( nAtlasSizeX, nAtlasSizeY );
  78. // insert largest first
  79. for ( int t=nCharts-1; t>=0; --t )
  80. {
  81. AtlasChart_t *pChart = chartVector[ t ];
  82. if ( !pChart->m_bAtlased )
  83. {
  84. if ( m_packer.InsertChart( pChart ) )
  85. {
  86. pChart->m_bAtlased = true;
  87. }
  88. else
  89. {
  90. if ( bTryGrow )
  91. {
  92. bHaveAtlas = false;
  93. nAttempt++;
  94. break;
  95. }
  96. else
  97. {
  98. nUnatlased++;
  99. }
  100. }
  101. }
  102. }
  103. }
  104. return nUnatlased;
  105. }
  106. //CPackNode
  107. CPackNode::CPackNode( Rect_t rect, float flTotalW, float flTotalH ) :
  108. m_pChart( NULL ),
  109. m_flTotalW( flTotalW ),
  110. m_flTotalH( flTotalH )
  111. {
  112. m_child[0] = NULL;
  113. m_child[1] = NULL;
  114. m_rect = rect;
  115. }
  116. CPackNode::~CPackNode()
  117. {
  118. if ( m_child[ 0 ] ) { delete m_child[ 0 ]; }
  119. if ( m_child[ 1 ] ) { delete m_child[ 1 ]; }
  120. }
  121. CPackNode* CPackNode::InsertChart( AtlasChart_t *pChart )
  122. {
  123. int texWidth = (int)ceil( pChart->m_vMaxTextureSize.x );
  124. int texHeight = (int)ceil( pChart->m_vMaxTextureSize.y );
  125. //if we have children, that means we can't insert into this node, try the kids
  126. if ( NULL != m_child[ 0 ] && NULL != m_child[ 1 ] )
  127. {
  128. //try the first child
  129. CPackNode* pNewNode = m_child[ 0 ]->InsertChart( pChart );
  130. if(pNewNode)
  131. return pNewNode;
  132. //if that didn't work, try the second
  133. pNewNode = m_child[ 1 ]->InsertChart( pChart );
  134. return pNewNode; //if this didn't work it will return NULL
  135. }
  136. else //else, see if we can fit it in
  137. {
  138. //if we are a leaf of the tree (m_child[0] and m_child[1] have textures in them,
  139. //then make sure we don't have texture already in here
  140. if ( m_pChart )
  141. return NULL; //if we already have a texture, return NULL
  142. //else, see if we can even fit the lightmap
  143. int width = m_rect.width;// + 1;
  144. int height = m_rect.height;// + 1;
  145. if ( width < texWidth || height < texHeight )
  146. return NULL; //we don't fit!!!
  147. //if we're just the right size, then add the lightmap and we're done
  148. if ( width == texWidth && height == texHeight )
  149. {
  150. m_pChart = pChart; //mark this as the texture for the current node
  151. //get the new texture coordinates and put them in the texture
  152. {
  153. m_pChart->m_vAtlasMin.x = m_rect.x / m_flTotalW;
  154. m_pChart->m_vAtlasMin.y = m_rect.y / m_flTotalH;
  155. m_pChart->m_vAtlasMax.x = ( m_rect.x + m_rect.width ) / m_flTotalW;
  156. m_pChart->m_vAtlasMax.y = ( m_rect.y + m_rect.height ) / m_flTotalH;
  157. }
  158. return this; //return us, since we're the right size
  159. }
  160. //if we're not the right size, but we're big enough to hold the lightmap,
  161. //split us up into two nodes
  162. Rect_t rect0,rect1;
  163. int dw = width - texWidth;
  164. int dh = height - texHeight;
  165. if( dw > dh ) //split left, right
  166. {
  167. //left rect
  168. rect0.x = m_rect.x;
  169. rect0.width = texWidth;// - 1;
  170. rect0.y = m_rect.y;
  171. rect0.height = m_rect.height;
  172. //right rect
  173. rect1.x = m_rect.x + rect0.width;
  174. rect1.width = m_rect.width - rect0.width;
  175. rect1.y = m_rect.y;
  176. rect1.height = m_rect.height;
  177. }
  178. else //split up, down
  179. {
  180. //top rect
  181. rect0.x = m_rect.x;
  182. rect0.width = m_rect.width;
  183. rect0.y = m_rect.y;
  184. rect0.height = texHeight;// - 1;
  185. //bottom rect
  186. rect1.x = m_rect.x;
  187. rect1.width = m_rect.width;
  188. rect1.y = m_rect.y + rect0.height;
  189. rect1.height = m_rect.height - rect0.height;
  190. }
  191. m_child[ 0 ] = new CPackNode( rect0, m_flTotalW, m_flTotalH );
  192. m_child[ 1 ] = new CPackNode( rect1, m_flTotalW, m_flTotalH );
  193. //since we made the first child the size we needed, insert into him.
  194. //this should never fail
  195. return m_child[ 0 ]->InsertChart( pChart );
  196. }
  197. }
  198. //clightmappacker class
  199. CAtlasPacker::CAtlasPacker()
  200. {
  201. m_nWidth = 0;
  202. m_nHeight = 0;
  203. m_pRootNode = NULL;
  204. }
  205. CAtlasPacker::~CAtlasPacker()
  206. {
  207. if ( m_pRootNode ) delete m_pRootNode;
  208. }
  209. void CAtlasPacker::Init( int nWidth, int nHeight )
  210. {
  211. m_nWidth = nWidth;
  212. m_nHeight = nHeight;
  213. Rect_t rect;
  214. rect.x = 0; rect.width = nWidth;
  215. rect.y = 0; rect.height = nHeight;
  216. m_pRootNode = new CPackNode( rect, (float)nWidth, (float)nHeight );
  217. }
  218. bool CAtlasPacker::InsertChart( AtlasChart_t *pChart )
  219. {
  220. if( !m_pRootNode )
  221. return false;
  222. CPackNode* pNode = m_pRootNode->InsertChart( pChart );
  223. if(pNode)
  224. {
  225. return true;
  226. }
  227. return false;
  228. }