dl
dl_texture_pack.h
浏览该文件的文档.
1
16#pragma once
17
18#include <list>
19#include <map>
20
21#include "dl_type.h"
22#include "dl_align.h"
23
26{
27
29template<unsigned DH>
31{
32public:
34 struct Line
35 {
36 unsigned _y;
37 unsigned _h;
38 unsigned _x;
39 bool _free;
40 };
41
46 void Reset(const Size& size)
47 {
48 _size = size;
49 _regY = 0;
50 _bFull = false;
51
52 _vecLine.clear();
53 }
54
60 bool Add(const Size& size, RectU& rect)
61 {
62 if (_bFull)
63 return false;
64
65 unsigned w = size[0];
66 unsigned h = size[1];
67 //找到一个h比自己大的,但又不能超过DH(然后还能放得下x)
68 auto iter = find_if(_vecLine.begin(), _vecLine.end(), [&](Line& line)
69 {
70 if (line._free
71 && line._h >= h // 30 >= 28
72 && line._h <= h + DH) // 30 <= 28 + 2 {28,29,30}
73 {
74 if (line._x + w > _size[0])
75 {
76 line._free = false;
77 return false;
78 }
79 else
80 return true;
81 }
82 return false;
83 });
84
85 if (iter == _vecLine.end())
86 {//没有就创建一个
87 if (h + _regY > _size[1])
88 {
89 _bFull = true;
90 return false;
91 }
92
93 Line line;
94 line._h = h;
95 line._y = _regY;
96 line._x = 0;
97 line._free = true;
98
99 _regY += h;
100 _vecLine.push_back(line);
101
102 iter = _vecLine.end() - 1;
103 }
104
105 rect = { iter->_x, iter->_y, iter->_x + w , iter->_y + h };
106
107 iter->_x += w;
108
109 //越界检查
110 assert(rect[2] <= _size[0] && rect[3] <= _size[1]);
111
112 return true;
113 }
114
115private:
116 Size _size;
117 unsigned _regY;//当前y
118 bool _bFull;//满了标记
119 std::vector<Line> _vecLine;
120};
121
124{
125public:
130 void SetSize(const Size& size)
131 {
132 _size = size;
133 }
134
141 template<typename T, typename FS, typename F>
142 void Calc(std::list<T>& all_box, FS get_size, F call_back)
143 {
144 //维护一个按h排序的剩余空间
145 std::multimap<unsigned, RectU> map_remain;
146 //初始空间
147 map_remain.insert( { _size[1], createRectU(_size) });
148
149 //按面积大小排序(list的sort本身就是稳定的)
150 all_box.sort([get_size](const T& box0, const T& box1)
151 {
152 return Accumulate::Mul(get_size(box0))
153 > Accumulate::Mul(get_size(box1));
154 });
155
156 for (auto iter = all_box.begin(); iter != all_box.end();)
157 {
158 //获取大小
159 Size size = get_size(*iter);
160 //寻找一个比自己h大的剩余空间
161 bool failed = true;
162 auto iter_remain = map_remain.begin();
163 for (; iter_remain != map_remain.end(); ++iter_remain)
164 {
165 if (iter_remain->first >= size[1]
166 && Align::GetWidth(iter_remain->second) >= size[0])
167 {//并且w也要更大
168 //放入自己,并将加入到的剩余空间拆分为新的两个剩余空间,加入到map_remain
169 PointU lt = Align::GetLT(iter_remain->second);
170 call_back(*iter, lt);
171
172 //在世界坐标里的 rect
173 RectU rect_parent = createRectU(lt, size);
174
175 //right rect
176 if (iter_remain->second[1] != rect_parent[3])
177 {//高度过小的剩余空间丢弃
178 RectU rect_right = { rect_parent[2], iter_remain->second[1], iter_remain->second[2], rect_parent[3] };
179 map_remain.insert({ Align::GetHeight(rect_right), rect_right });
180 }
181
182 //buttom rect
183 if (rect_parent[3] != iter_remain->second[3])
184 {//高度过小的剩余空间丢弃
185 RectU rect_buttom = { iter_remain->second[0], rect_parent[3], iter_remain->second[2], iter_remain->second[3] };
186 map_remain.insert({ Align::GetHeight(rect_buttom), rect_buttom });
187 }
188
189 //还需删除加入到的剩余空间
190 map_remain.erase(iter_remain);
191 //标记加入成功
192 failed = false;
193 break;
194 }
195 }
196 //成功则移除
197 if (!failed)
198 all_box.erase(iter++);
199 else
200 ++iter;
201 }
202 }
203private:
204 Size _size;
205};
206
207}
动态装箱(DH为2时,32、31、30会放到同一行)
void Reset(const Size &size)
清空初始化 或 再次使用
bool Add(const Size &size, RectU &rect)
添加一个,失败返回false
void SetSize(const Size &size)
设置箱子大小
void Calc(std::list< T > &all_box, FS get_size, F call_back)
加入一堆箱子(会重建自身)
方向和对齐定义
通用类型
constexpr auto Mul(const C &container)
求积product
constexpr Array< T, 2 > GetLT(const Array< T, 4 > &rect)
constexpr T GetWidth(const Array< T, 4 > &rect)
计算返回 矩形 右下角坐标x 减去 左上角坐标x
constexpr T GetHeight(const Array< T, 4 > &rect)
计算返回 矩形 右下角坐标y 减去 左上角坐标y
纹理打包算法
Point2U PointU
constexpr RectU createRectU(const Size &size)
创建一个RectU,依据大小
Point4U RectU
PointU Size