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.

274 lines
8.1 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #if IS_WINDOWS_PC
  8. #define WIN32_LEAN_AND_MEAN
  9. #include <windows.h>
  10. #endif
  11. #include "bitmap/texturepacker.h"
  12. // memdbgon must be the last include file in a .cpp file!!!
  13. #include "tier0/memdbgon.h"
  14. //-----------------------------------------------------------------------------
  15. // Purpose: Constructor
  16. //-----------------------------------------------------------------------------
  17. CTexturePacker::CTexturePacker( int texWidth, int texHeight, int pixelGap )
  18. {
  19. m_PageWidth = texWidth;
  20. m_PageHeight = texHeight;
  21. m_PixelGap = pixelGap;
  22. Clear();
  23. }
  24. //-----------------------------------------------------------------------------
  25. // Purpose: Destructor
  26. //-----------------------------------------------------------------------------
  27. CTexturePacker::~CTexturePacker()
  28. {
  29. // remove all existing data
  30. m_Tree.RemoveAll();
  31. }
  32. //-----------------------------------------------------------------------------
  33. // Purpose: Resets the tree
  34. //-----------------------------------------------------------------------------
  35. void CTexturePacker::Clear()
  36. {
  37. // remove all existing data
  38. m_Tree.RemoveAll();
  39. // Add root item, everything else is procedurally generated
  40. int rootIndex = m_Tree.InsertChildAfter( m_Tree.InvalidIndex(), m_Tree.InvalidIndex() );
  41. TreeEntry_t &topNode = m_Tree[rootIndex];
  42. topNode.rc.x = 0;
  43. topNode.rc.y = 0;
  44. topNode.rc.width = m_PageWidth;
  45. topNode.rc.height = m_PageHeight;
  46. topNode.bInUse = false;
  47. }
  48. //-----------------------------------------------------------------------------
  49. //
  50. //-----------------------------------------------------------------------------
  51. bool CTexturePacker::IsLeaf( int nodeIndex )
  52. {
  53. int leftChildIndex = m_Tree.FirstChild( nodeIndex );
  54. if ( leftChildIndex == m_Tree.InvalidIndex() )
  55. {
  56. return true;
  57. }
  58. else if ( m_Tree.NextSibling( leftChildIndex ) == m_Tree.InvalidIndex() )
  59. {
  60. return true;
  61. }
  62. return false;
  63. }
  64. //-----------------------------------------------------------------------------
  65. //
  66. //-----------------------------------------------------------------------------
  67. bool CTexturePacker::IsLeftChild( int nodeIndexParent, int nodeIndexChild )
  68. {
  69. int leftChildIndex = m_Tree.FirstChild( nodeIndexParent );
  70. if ( leftChildIndex == nodeIndexChild )
  71. {
  72. return true;
  73. }
  74. else
  75. {
  76. return false;
  77. }
  78. }
  79. //-----------------------------------------------------------------------------
  80. //
  81. //-----------------------------------------------------------------------------
  82. bool CTexturePacker::IsRightChild( int nodeIndexParent, int nodeIndexChild )
  83. {
  84. return !IsLeftChild( nodeIndexParent, nodeIndexChild );
  85. }
  86. #ifdef _PS3
  87. // Remove some annoying GCC warnings by specializing these template functions to remove a redundant (i>=0) clause
  88. template <>
  89. inline bool CUtlNTree<CTexturePacker::TreeEntry_t,short unsigned int>::IsValidIndex( short unsigned int i ) const
  90. {
  91. return (i < m_MaxElementIndex);
  92. }
  93. template <>
  94. inline bool CUtlNTree<CTexturePacker::TreeEntry_t,short unsigned int>::IsInTree( short unsigned int i ) const
  95. {
  96. return (i < m_MaxElementIndex) && (InternalNode(i).m_PrevSibling != i);
  97. }
  98. #endif // _PS3
  99. //-----------------------------------------------------------------------------
  100. //
  101. //-----------------------------------------------------------------------------
  102. int CTexturePacker::InsertRect( const Rect_t& texRect, int nodeIndex )
  103. {
  104. if ( nodeIndex == -1 )
  105. {
  106. nodeIndex = m_Tree.Root();
  107. Assert( nodeIndex != m_Tree.InvalidIndex() );
  108. }
  109. if ( !IsLeaf( nodeIndex) ) // not a leaf
  110. {
  111. // try inserting under left child
  112. int leftChildIndex = m_Tree.FirstChild( nodeIndex );
  113. int newIndex = InsertRect( texRect, leftChildIndex );
  114. if ( m_Tree.IsValidIndex( newIndex ) )
  115. {
  116. return newIndex;
  117. }
  118. // no room, insert under right child
  119. int rightChildIndex = m_Tree.NextSibling( leftChildIndex );
  120. return InsertRect( texRect, rightChildIndex );
  121. }
  122. else
  123. {
  124. if ( m_Tree[nodeIndex].bInUse ) // there is already a glpyh here
  125. {
  126. return -1;
  127. }
  128. int cacheSlotWidth = m_Tree[nodeIndex].rc.width;
  129. int cacheSlotHeight = m_Tree[nodeIndex].rc.height;
  130. if ( ( texRect.width > cacheSlotWidth ) ||
  131. ( texRect.height > cacheSlotHeight ) )
  132. {
  133. // if this node's box is too small, return
  134. return -1;
  135. }
  136. if ( ( texRect.width == cacheSlotWidth) &&
  137. ( texRect.height == cacheSlotHeight ) )
  138. {
  139. // if we're just right, accept
  140. m_Tree[nodeIndex].bInUse = true;
  141. return nodeIndex;
  142. }
  143. // otherwise, gotta split this node and create some kids
  144. // decide which way to split
  145. int dw = cacheSlotWidth - texRect.width;
  146. int dh = cacheSlotHeight - texRect.height;
  147. int leftChildIndex;
  148. if ( dw > dh ) // split along x
  149. {
  150. leftChildIndex = m_Tree.InsertChildAfter( nodeIndex, m_Tree.InvalidIndex() );
  151. Assert( IsLeftChild( nodeIndex, leftChildIndex ) );
  152. TreeEntry_t &leftChild = m_Tree[leftChildIndex];
  153. leftChild.rc.x = m_Tree[nodeIndex].rc.x;
  154. leftChild.rc.y = m_Tree[nodeIndex].rc.y;
  155. leftChild.rc.width = texRect.width;
  156. leftChild.rc.height = cacheSlotHeight;
  157. leftChild.bInUse = false;
  158. int rightChildIndex = m_Tree.InsertChildAfter( nodeIndex, leftChildIndex );
  159. Assert( IsRightChild( nodeIndex, rightChildIndex ) );
  160. TreeEntry_t &rightChild = m_Tree[rightChildIndex];
  161. rightChild.rc.x = m_Tree[nodeIndex].rc.x + texRect.width + m_PixelGap;
  162. rightChild.rc.y = m_Tree[nodeIndex].rc.y;
  163. rightChild.rc.width = dw - m_PixelGap;
  164. rightChild.rc.height = cacheSlotHeight;
  165. rightChild.bInUse = false;
  166. Assert( m_Tree.Parent( leftChildIndex ) == m_Tree.Parent( rightChildIndex ) );
  167. Assert( m_Tree.Parent( leftChildIndex ) == nodeIndex );
  168. }
  169. else // split along y
  170. {
  171. leftChildIndex = m_Tree.InsertChildAfter( nodeIndex, m_Tree.InvalidIndex() );
  172. Assert( IsLeftChild( nodeIndex, leftChildIndex ) );
  173. TreeEntry_t &leftChild = m_Tree[leftChildIndex];
  174. leftChild.rc.x = m_Tree[nodeIndex].rc.x;
  175. leftChild.rc.y = m_Tree[nodeIndex].rc.y;
  176. leftChild.rc.width = cacheSlotWidth;
  177. leftChild.rc.height = texRect.height;
  178. leftChild.bInUse = false;
  179. int rightChildIndex = m_Tree.InsertChildAfter( nodeIndex, leftChildIndex );
  180. Assert( IsRightChild( nodeIndex, rightChildIndex ) );
  181. TreeEntry_t &rightChild = m_Tree[rightChildIndex];
  182. rightChild.rc.x = m_Tree[nodeIndex].rc.x;
  183. rightChild.rc.y = m_Tree[nodeIndex].rc.y + texRect.height + m_PixelGap;
  184. rightChild.rc.width = cacheSlotWidth;
  185. rightChild.rc.height = dh - m_PixelGap;
  186. rightChild.bInUse = false;
  187. Assert( m_Tree.Parent( leftChildIndex ) == m_Tree.Parent( rightChildIndex ) );
  188. Assert( m_Tree.Parent( leftChildIndex ) == nodeIndex );
  189. }
  190. // insert into first child we created
  191. return InsertRect( texRect, leftChildIndex );
  192. }
  193. }
  194. //-----------------------------------------------------------------------------
  195. //
  196. //-----------------------------------------------------------------------------
  197. bool CTexturePacker::RemoveRect( int nodeIndex )
  198. {
  199. if ( !m_Tree.IsInTree( nodeIndex ) )
  200. {
  201. return false;
  202. }
  203. m_Tree[nodeIndex].bInUse = false;
  204. // If its a leaf, see if its peer is empty, if it is the split can go away.
  205. if ( IsLeaf( nodeIndex) ) // a leaf
  206. {
  207. int parentIndex = m_Tree.Parent( nodeIndex );
  208. // Is this node the left child?
  209. if ( nodeIndex == m_Tree.FirstChild( parentIndex ) )
  210. {
  211. // Get the index of the right child
  212. int peerIndex = m_Tree.NextSibling( nodeIndex );
  213. if ( IsLeaf( peerIndex ) && !m_Tree[peerIndex].bInUse )
  214. {
  215. // Both children are leaves and neither is in use, remove the split here.
  216. m_Tree.Remove( nodeIndex );
  217. m_Tree.Remove( peerIndex );
  218. }
  219. }
  220. else // Its the right child
  221. {
  222. // Get the index of the left child
  223. int peerIndex = m_Tree.FirstChild( parentIndex );
  224. Assert( nodeIndex == m_Tree.NextSibling( peerIndex ) );
  225. if ( IsLeaf( peerIndex ) && !m_Tree[peerIndex].bInUse )
  226. {
  227. // Both children are leaves and neither is in use, remove the split here.
  228. m_Tree.Remove( nodeIndex );
  229. m_Tree.Remove( peerIndex );
  230. }
  231. }
  232. }
  233. return true;
  234. }