💿🐜 Antkeeper source code https://antkeeper.com
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.

239 lines
5.3 KiB

  1. /*
  2. * Copyright (C) 2021 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #ifndef ANTKEEPER_GEOM_RECT_PACK_HPP
  20. #define ANTKEEPER_GEOM_RECT_PACK_HPP
  21. #include "geom/rect.hpp"
  22. namespace geom {
  23. /**
  24. * Node used in 2D rectangle packing.
  25. *
  26. * @see geom::rect_pack
  27. */
  28. template <class T>
  29. struct rect_pack_node
  30. {
  31. /// Scalar type.
  32. typedef T scalar_type;
  33. /// Rect type.
  34. typedef rect<T> rect_type;
  35. /// Creates a rect pack node.
  36. rect_pack_node();
  37. /// Destroys a rect pack node and its children.
  38. ~rect_pack_node();
  39. /// Pointers to the two children of the node, if any.
  40. rect_pack_node* children[2];
  41. /// Bounds of the node.
  42. rect_type bounds;
  43. /// `true` if the node is occupied, `false` otherwise.
  44. bool occupied;
  45. };
  46. template <class T>
  47. rect_pack_node<T>::rect_pack_node():
  48. bounds{T(0), T(0), T(0), T(0)},
  49. occupied(false)
  50. {
  51. children[0] = nullptr;
  52. children[1] = nullptr;
  53. }
  54. template <class T>
  55. rect_pack_node<T>::~rect_pack_node()
  56. {
  57. delete children[0];
  58. delete children[1];
  59. }
  60. /**
  61. * Packs 2D rectangles.
  62. *
  63. * @see geom::rect_pack_node
  64. *
  65. * @see http://www.blackpawn.com/texts/lightmaps/
  66. */
  67. template <class T>
  68. class rect_pack
  69. {
  70. public:
  71. /// Scalar type.
  72. typedef T scalar_type;
  73. /// Node type.
  74. typedef rect_pack_node<T> node_type;
  75. /**
  76. * Creates a rect pack and sets the bounds of the root node.
  77. *
  78. * @param w Width of the root node.
  79. * @param h Height of the root node.
  80. */
  81. rect_pack(scalar_type w, scalar_type h);
  82. /**
  83. * Creates an empty rect pack.
  84. */
  85. rect_pack();
  86. /**
  87. * Clears the pack and resizes the root node bounds.
  88. *
  89. * @param w New width of the root node.
  90. * @param h New height of the root node.
  91. *
  92. * @see rect_pack::clear()
  93. */
  94. void resize(scalar_type w, scalar_type h);
  95. /// Clear the pack, deallocating all nodes.
  96. void clear();
  97. /**
  98. * Packs a rect into the rect pack.
  99. *
  100. * @param w Width of the rect.
  101. * @param h Height of the rect.
  102. * @return Pointer to the node in which the rect was packed, or `nullptr` if the rect could not be packed.
  103. */
  104. const node_type* pack(scalar_type w, scalar_type h);
  105. /// Returns a reference to the root node.
  106. const node_type& get_root() const;
  107. private:
  108. static node_type* insert(node_type& parent, scalar_type w, scalar_type h);
  109. static void free();
  110. node_type root;
  111. };
  112. template <class T>
  113. rect_pack<T>::rect_pack(scalar_type w, scalar_type h)
  114. {
  115. root.bounds = {T(0), T(0), w, h};
  116. }
  117. template <class T>
  118. rect_pack<T>::rect_pack():
  119. rect_pack(0, 0)
  120. {}
  121. template <class T>
  122. void rect_pack<T>::resize(scalar_type w, scalar_type h)
  123. {
  124. clear();
  125. root.bounds = {T(0), T(0), w, h};
  126. }
  127. template <class T>
  128. void rect_pack<T>::clear()
  129. {
  130. delete root.children[0];
  131. delete root.children[1];
  132. root.children[0] = nullptr;
  133. root.children[1] = nullptr;
  134. root.occupied = false;
  135. }
  136. template <class T>
  137. const typename rect_pack<T>::node_type* rect_pack<T>::pack(scalar_type w, scalar_type h)
  138. {
  139. return insert(root, w, h);
  140. }
  141. template <class T>
  142. inline const typename rect_pack<T>::node_type& rect_pack<T>::get_root() const
  143. {
  144. return root;
  145. }
  146. template <class T>
  147. typename rect_pack<T>::node_type* rect_pack<T>::insert(node_type& node, scalar_type w, scalar_type h)
  148. {
  149. // If not a leaf node
  150. if (node.children[0] && node.children[1])
  151. {
  152. // Attempt to insert into first child
  153. node_type* result = insert(*node.children[0], w, h);
  154. if (result)
  155. return result;
  156. // Cannot fit in first child, attempt to insert into second child
  157. return insert(*node.children[1], w, h);
  158. }
  159. // Abort if node occupied
  160. if (node.occupied)
  161. return nullptr;
  162. // Determine node dimensions
  163. scalar_type node_w = node.bounds.max.x - node.bounds.min.x;
  164. scalar_type node_h = node.bounds.max.y - node.bounds.min.y;
  165. // Check if rect is larger than node
  166. if (w > node_w || h > node_h)
  167. return nullptr;
  168. // Check for a perfect fit
  169. if (w == node_w && h == node_h)
  170. {
  171. node.occupied = true;
  172. return &node;
  173. }
  174. // Split the node
  175. node.children[0] = new node_type();
  176. node.children[1] = new node_type();
  177. // Determine split direction
  178. scalar_type dw = node_w - w;
  179. scalar_type dh = node_h - h;
  180. if (dw > dh)
  181. {
  182. node.children[0]->bounds.min = node.bounds.min;
  183. node.children[0]->bounds.max = {node.bounds.min.x + w, node.bounds.max.y};
  184. node.children[1]->bounds.min = {node.bounds.min.x + w, node.bounds.min.y};
  185. node.children[1]->bounds.max = {node.bounds.max};
  186. }
  187. else
  188. {
  189. node.children[0]->bounds.min = node.bounds.min;
  190. node.children[0]->bounds.max = {node.bounds.max.x, node.bounds.min.y + h};
  191. node.children[1]->bounds.min = {node.bounds.min.x, node.bounds.min.y + h};
  192. node.children[1]->bounds.max = {node.bounds.max};
  193. }
  194. // Insert into first child
  195. return insert(*node.children[0], w, h);
  196. }
  197. } // namespace geom
  198. #endif // ANTKEEPER_GEOM_RECT_PACK_HPP