rectpacker.bmx 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. ' Copyright (c) 2024 Bruce A Henderson
  2. '
  3. ' This software is provided 'as-is', without any express or implied
  4. ' warranty. In no event will the authors be held liable for any damages
  5. ' arising from the use of this software.
  6. '
  7. ' Permission is granted to anyone to use this software for any purpose,
  8. ' including commercial applications, and to alter it and redistribute it
  9. ' freely, subject to the following restrictions:
  10. '
  11. ' 1. The origin of this software must not be misrepresented; you must not
  12. ' claim that you wrote the original software. If you use this software
  13. ' in a product, an acknowledgment in the product documentation would be
  14. ' appreciated but is not required.
  15. ' 2. Altered source versions must be plainly marked as such, and must not be
  16. ' misrepresented as being the original software.
  17. ' 3. This notice may not be removed or altered from any source distribution.
  18. '
  19. SuperStrict
  20. Rem
  21. bbdoc: A module for packing rectangles into sheets.
  22. about: Useful for creating texture atlases, sprite sheets, and other similar things.
  23. End Rem
  24. Module BRL.RectPacker
  25. ModuleInfo "Version: 1.00"
  26. ModuleInfo "License: zlib/libpng"
  27. ModuleInfo "Copyright: 2024 Bruce A Henderson"
  28. ModuleInfo "rect_pack: Albert Kalchmair 2021, Sean Barrett 2014, Jukka Jylänki"
  29. ModuleInfo "History: 1.00 Initial Release"
  30. ModuleInfo "CPP_OPTS: -std=c++11"
  31. Import BRL.Collections
  32. Import "source.bmx"
  33. Rem
  34. bbdoc: Packs rectangles into sheets.
  35. about: The packer provides a number of settings that can be used to control how the rectangles are packed.
  36. The rectangles are added to the packer using the #Add method, and then the #Pack method is called to pack them into sheets.
  37. The packer will return an array of #TPackedSheet objects, each of which contains the rectangles that have been packed into it.
  38. An @id can be assigned to each rectangle, which can be used to identify the rectangle in the packed sheets.
  39. End Rem
  40. Type TRectPacker
  41. Rem
  42. bbdoc: The packing method to use.
  43. End Rem
  44. Field packingMethod:EPackingMethod = EPackingMethod.Best
  45. Rem
  46. bbdoc: The maximum number of sheets to produce.
  47. about: If the packer is unable to fit all the rectangles into the specified number of sheets, those that don't fit will be discarded.
  48. End Rem
  49. Field maxSheets:Int = 1
  50. Rem
  51. bbdoc: Whether to pack into power-of-two sized sheets.
  52. about: If this is set to #True, the width and height of the sheets will be rounded up to the nearest power of two.
  53. This is useful for creating sheets that are intended to be used for creating textures.
  54. End Rem
  55. Field powerOfTwo:Int = True
  56. Rem
  57. bbdoc: Whether to pack into square sheets.
  58. about: If this is set to #True, the width and height of the sheets will be the same.
  59. End Rem
  60. Field square:Int = False
  61. Rem
  62. bbdoc: Whether to allow rectangles to be rotated.
  63. about: If this is set to #True, the packer may attempt to rotate rectangles to help fit them into the sheets.
  64. End Rem
  65. Field allowRotate:Int = False
  66. Rem
  67. bbdoc: Whether to align the width of the rectangles.
  68. about: If this is set to #True, the packer will attempt to align the width of the rectangles to the width of the sheet.
  69. This can help to reduce the amount of wasted space in the sheet.
  70. End Rem
  71. Field alignWidth:Int = False
  72. Rem
  73. bbdoc: The amount of padding to add.
  74. End Rem
  75. Field borderPadding:Int
  76. Rem
  77. bbdoc: The amount to over-allocate the sheet by.
  78. about: This is useful if you want to add a border around the sheet, or if you want to add some padding around the rectangles.
  79. End Rem
  80. Field overAllocate:Int
  81. Rem
  82. bbdoc: The minimum width of the sheets.
  83. End Rem
  84. Field minWidth:Int
  85. Rem
  86. bbdoc: The minimum height of the sheets.
  87. End Rem
  88. Field minHeight:Int
  89. Rem
  90. bbdoc: The maximum width of the sheets.
  91. End Rem
  92. Field maxWidth:Int
  93. Rem
  94. bbdoc: The maximum height of the sheets.
  95. End Rem
  96. Field maxHeight:Int
  97. Field sizes:TArrayList<SRectSize> = New TArrayList<SRectSize>
  98. Rem
  99. bbdoc: Adds a rectangle with the given @id to the packer.
  100. End Rem
  101. Method Add(width:Int, height:Int, id:Int)
  102. Local size:SRectSize = New SRectSize(width, height, id)
  103. sizes.Add(size)
  104. End Method
  105. Rem
  106. bbdoc: Packs the rectangles into sheets, based on the settings of the packer.
  107. about: This method will return an array of #TPackedSheet objects, each of which contains the rectangles that have been packed into it.
  108. Any rectangles that don't fit into the sheets will be discarded, and not be included in the returned array.
  109. End Rem
  110. Method Pack:TPackedSheet[]()
  111. Return bmx_rectpacker_pack(Self, packingMethod, maxSheets, powerOfTwo, square, allowRotate, alignWidth, borderPadding, overAllocate, minWidth, minHeight, maxWidth, maxHeight, sizes.Count())
  112. End Method
  113. Private
  114. Function _GetSize(packer:TRectPacker, index:Int, width:Int Var, height:Int Var, id:Int Var) { nomangle }
  115. Local size:SRectSize = packer.sizes[index]
  116. width = size.width
  117. height = size.height
  118. id = size.id
  119. End Function
  120. Function _NewSheetArray:TPackedSheet[](size:Int) { nomangle }
  121. Return New TPackedSheet[size]
  122. End Function
  123. Function _SetSheet(sheets:TPackedSheet[], index:Int, sheet:TPackedSheet) { nomangle }
  124. sheets[index] = sheet
  125. End Function
  126. End Type
  127. Struct SRectSize
  128. Field width:Int
  129. Field height:Int
  130. Field id:Int
  131. Method New(width:Int, height:Int, id:Int)
  132. Self.width = width
  133. Self.height = height
  134. Self.id = id
  135. End Method
  136. Method Operator=:Int(other:SRectSize)
  137. Return width = other.width And height = other.height And id = other.id
  138. End Method
  139. End Struct
  140. Rem
  141. bbdoc: The packing method to use.
  142. about: The packing method determines how the rectangles are packed into the sheets.
  143. | Value | Description |
  144. |-------------------------------|----------------------------------------------|
  145. | #Best | The best fitting from all of the available methods. |
  146. | #BestSkyline | The best available skyline method. |
  147. | #BestMaxRects | The best available max rects method. |
  148. | #SkylineBottomLeft | The skyline bottom-left method. |
  149. | #SkylineBestFit | The skyline best-fit method. |
  150. | #MaxRectsBestShortSideFit | The max rects best short-side fit method. |
  151. | #MaxRectsBestLongSideFit | The max rects best long-side fit method. |
  152. | #MaxRectsBestAreaFit | The max rects best area fit method. |
  153. | #MaxRectsBottomLeftRule | The max rects bottom-left rule method. |
  154. | #MaxRectsContactPointRule | The max rects contact-point rule method. |
  155. End Rem
  156. Enum EPackingMethod
  157. Best
  158. BestSkyline
  159. BestMaxRects
  160. SkylineBottomLeft
  161. SkylineBestFit
  162. MaxRectsBestShortSideFit
  163. MaxRectsBestLongSideFit
  164. MaxRectsBestAreaFit
  165. MaxRectsBottomLeftRule
  166. MaxRectsContactPointRule
  167. End Enum
  168. Rem
  169. bbdoc: Represents a rectangle that has been packed into a sheet.
  170. End Rem
  171. Struct SPackedRect
  172. Rem
  173. bbdoc: The ID of the rectangle.
  174. End Rem
  175. Field id:Int
  176. Rem
  177. bbdoc: The X position of the rectangle.
  178. End Rem
  179. Field x:Int
  180. Rem
  181. bbdoc: The Y position of the rectangle.
  182. End Rem
  183. Field y:Int
  184. Rem
  185. bbdoc: The width of the rectangle.
  186. End Rem
  187. Field width:Int
  188. Rem
  189. bbdoc: The height of the rectangle.
  190. End Rem
  191. Field height:Int
  192. Rem
  193. bbdoc: Whether the rectangle has been rotated.
  194. End Rem
  195. Field rotated:Int
  196. Method New(id:Int, x:Int, y:Int, width:Int, height:Int, rotated:Int)
  197. Self.id = id
  198. Self.x = x
  199. Self.y = y
  200. Self.width = width
  201. Self.height = height
  202. Self.rotated = rotated
  203. End Method
  204. End Struct
  205. Rem
  206. bbdoc: Represents a sheet that has been packed with rectangles.
  207. End Rem
  208. Type TPackedSheet
  209. Rem
  210. bbdoc: The width of the sheet.
  211. End Rem
  212. Field width:Int
  213. Rem
  214. bbdoc: The height of the sheet.
  215. End Rem
  216. Field height:Int
  217. Rem
  218. bbdoc: The rectangles that have been packed into the sheet.
  219. End Rem
  220. Field rects:SPackedRect[]
  221. Private
  222. Function _Create:TPackedSheet(width:Int, height:Int, size:Int) { nomangle }
  223. Local sheet:TPackedSheet = New TPackedSheet
  224. sheet.width = width
  225. sheet.height = height
  226. sheet.rects = New SPackedRect[size]
  227. Return sheet
  228. End Function
  229. Function _SetRect(sheet:TPackedSheet, index:Int, id:Int, x:Int, y:Int, width:Int, height:Int, rotated:Int) { nomangle }
  230. Local rect:SPackedRect = New SPackedRect(id, x, y, width, height, rotated)
  231. sheet.rects[index] = rect
  232. End Function
  233. End Type
  234. Extern
  235. Function bmx_rectpacker_pack:TPackedSheet[](packer:TRectPacker, packingMethod:EPackingMethod, maxSheets:Int, powerOfTwo:Int, square:Int, allowRotate:Int, alignWidth:Int, borderPadding:Int, overAllocate:Int, minWidth:Int, minHeight:Int, maxWidth:Int, maxHeight:Int, count:Int)
  236. End Extern