23 void init(uint32_t _width, uint32_t _height);
27 bool addRectangle(uint16_t _width, uint16_t _height, uint16_t& _outX, uint16_t& _outY);
38 return m_width * m_height;
48 int32_t fit(uint32_t _skylineNodeIndex, uint16_t _width, uint16_t _height);
55 Node(int16_t _x, int16_t _y, int16_t _width) : x(_x), y(_y), width(_width)
67 std::vector<Node> m_skyline;
78 m_skyline.push_back(Node(1, 1, uint16_t(_width - 2)));
83 BX_ASSERT(_width > 2,
"_width must be > 2");
84 BX_ASSERT(_height > 2,
"_height must be > 2");
92 m_skyline.push_back(Node(1, 1, uint16_t(_width - 2)));
97 int best_height, best_index;
104 best_height = INT_MAX;
106 best_width = INT_MAX;
107 for(uint16_t ii = 0, num = uint16_t(m_skyline.size()); ii < num; ++ii)
109 int32_t yy = fit(ii, _width, _height);
112 node = &m_skyline[ii];
113 if(((yy + _height) < best_height) || (((yy + _height) == best_height) && (node->width < best_width)))
115 best_height = uint16_t(yy) + _height;
117 best_width = node->width;
119 _outY = uint16_t(yy);
129 Node newNode(_outX, _outY + _height, _width);
130 m_skyline.insert(m_skyline.begin() + best_index, newNode);
132 for(uint16_t ii = uint16_t(best_index + 1), num = uint16_t(m_skyline.size()); ii < num; ++ii)
134 node = &m_skyline[ii];
135 prev = &m_skyline[ii - 1];
136 if(node->x < (prev->x + prev->width))
138 uint16_t shrink = uint16_t(prev->x + prev->width - node->x);
140 node->width -= shrink;
143 m_skyline.erase(m_skyline.begin() + ii);
159 m_usedSpace += _width * _height;
165 uint32_t total = m_width * m_height;
168 return (
float)m_usedSpace / (float)total;
181 m_skyline.push_back(Node(1, 1, uint16_t(m_width - 2)));
184int32_t RectanglePacker::fit(uint32_t _skylineNodeIndex, uint16_t _width, uint16_t _height)
186 int32_t
width = _width;
189 const Node& baseNode = m_skyline[_skylineNodeIndex];
191 int32_t xx = baseNode.x, yy;
192 int32_t widthLeft =
width;
193 int32_t ii = _skylineNodeIndex;
195 if((xx +
width) > (int32_t)(m_width - 1))
203 const Node& node = m_skyline[ii];
209 if((yy +
height) > (int32_t)(m_height - 1))
214 widthLeft -= node.width;
221void RectanglePacker::merge()
227 for(ii = 0; ii < m_skyline.size() - 1; ++ii)
229 node = (Node*)&m_skyline[ii];
230 next = (Node*)&m_skyline[ii + 1];
231 if(node->y ==
next->y)
233 node->width +=
next->width;
234 m_skyline.erase(m_skyline.begin() + ii + 1);
249 , m_textureSize(_textureSize)
251 , m_maxRegionCount(_maxRegionsCount)
253 BX_ASSERT(_textureSize >= 64 && _textureSize <= 4096,
"Invalid _textureSize %d.", _textureSize);
254 BX_ASSERT(_maxRegionsCount >= 64 && _maxRegionsCount <= 32000,
"Invalid _maxRegionsCount %d.", _maxRegionsCount);
256 m_texelSize = float(UINT16_MAX) / float(m_textureSize);
259 for(
int ii = 0; ii < 6; ++ii)
261 m_layers[ii].
packer.
init(_textureSize, _textureSize);
265 m_textureBuffer =
new uint8_t[_textureSize * _textureSize * 6 * 4];
266 bx::memSet(m_textureBuffer, 0, _textureSize * _textureSize * 6 * 4);
268 m_textureHandle = bgfx::createTextureCube(_textureSize,
false, 1, bgfx::TextureFormat::BGRA8);
272 const uint8_t* _textureBuffer,
273 uint16_t _regionCount,
274 const uint8_t* _regionBuffer,
275 uint16_t _maxRegionsCount)
278 , m_textureSize(_textureSize)
279 , m_regionCount(_regionCount)
280 , m_maxRegionCount(_regionCount < _maxRegionsCount ? _regionCount : _maxRegionsCount)
282 BX_ASSERT(_regionCount <= 64 && _maxRegionsCount <= 4096,
283 "_regionCount %d, _maxRegionsCount %d",
287 m_texelSize = float(UINT16_MAX) / float(m_textureSize);
292 bx::memCopy(m_regions, _regionBuffer, _regionCount *
sizeof(
AtlasRegion));
295 m_textureHandle = bgfx::createTextureCube(_textureSize,
298 bgfx::TextureFormat::BGRA8,
305 bgfx::destroy(m_textureHandle);
309 delete[] m_textureBuffer;
314 const uint8_t* _bitmapBuffer,
318 if(m_regionCount >= m_maxRegionCount)
326 while(idx < m_usedLayers)
328 if(m_layers[idx].faceRegion.getType() == _type &&
337 if(idx >= m_usedLayers)
339 if((idx + _type) > 24 || m_usedFaces >= 6)
350 region.
width = m_textureSize;
351 region.
height = m_textureSize;
352 region.
setMask(_type, m_usedFaces, ii);
358 if(!m_layers[idx].packer.addRectangle(_width + 1, _height + 1, xx, yy))
367 region.
width = _width;
375 region.
width -= (outline * 2);
376 region.
height -= (outline * 2);
378 return m_regionCount++;
386 const bgfx::Memory* mem = bgfx::alloc(
size);
387 bx::memSet(mem->data, 0, mem->size);
390 const uint8_t* inLineBuffer = _bitmapBuffer;
391 uint8_t* outLineBuffer = m_textureBuffer + _region.
getFaceIndex() * (m_textureSize * m_textureSize * 4) +
392 (((_region.
y * m_textureSize) + _region.
x) * 4);
394 for(
int yy = 0; yy < _region.
height; ++yy)
396 bx::memCopy(outLineBuffer, inLineBuffer, _region.
width * 4);
397 inLineBuffer += _region.
width * 4;
398 outLineBuffer += m_textureSize * 4;
401 bx::memCopy(mem->data, _bitmapBuffer, mem->size);
406 const uint8_t* inLineBuffer = _bitmapBuffer;
407 uint8_t* outLineBuffer = (m_textureBuffer + _region.
getFaceIndex() * (m_textureSize * m_textureSize * 4) +
408 (((_region.
y * m_textureSize) + _region.
x) * 4));
410 for(
int yy = 0; yy < _region.
height; ++yy)
412 for(
int xx = 0; xx < _region.
width; ++xx)
414 outLineBuffer[(xx * 4) + layer] = inLineBuffer[xx];
417 bx::memCopy(mem->data + yy * _region.
width * 4, outLineBuffer, _region.
width * 4);
418 inLineBuffer += _region.
width;
419 outLineBuffer += m_textureSize * 4;
423 bgfx::updateTextureCube(m_textureHandle,
437 packUV(m_layers[_idx].faceRegion, _vertexBuffer, _offset, _stride);
440void Atlas::packUV(uint16_t _regionHandle, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride)
const
442 const AtlasRegion& region = m_regions[_regionHandle];
443 packUV(region, _vertexBuffer, _offset, _stride);
446static void writeUV(uint8_t* _vertexBuffer, int16_t _x, int16_t _y, int16_t _z, int16_t _w)
448 uint16_t* xyzw = (uint16_t*)_vertexBuffer;
457 int16_t
x0 = (int16_t)(((
float)_region.
x * m_texelSize) -
float(INT16_MAX));
458 int16_t
y0 = (int16_t)(((
float)_region.
y * m_texelSize) -
float(INT16_MAX));
459 int16_t
x1 = (int16_t)((((
float)_region.
x + _region.
width) * m_texelSize) -
float(INT16_MAX));
460 int16_t
y1 = (int16_t)((((
float)_region.
y + _region.
height) * m_texelSize) -
float(INT16_MAX));
461 int16_t ww = (int16_t)((
float(INT16_MAX) / 4.0f) * (
float)_region.
getComponentIndex());
463 _vertexBuffer += _offset;
472 _vertexBuffer += _stride;
474 _vertexBuffer += _stride;
476 _vertexBuffer += _stride;
478 _vertexBuffer += _stride;
485 _vertexBuffer += _stride;
487 _vertexBuffer += _stride;
489 _vertexBuffer += _stride;
491 _vertexBuffer += _stride;
496 _vertexBuffer += _stride;
498 _vertexBuffer += _stride;
500 _vertexBuffer += _stride;
502 _vertexBuffer += _stride;
509 _vertexBuffer += _stride;
511 _vertexBuffer += _stride;
513 _vertexBuffer += _stride;
515 _vertexBuffer += _stride;
522 _vertexBuffer += _stride;
524 _vertexBuffer += _stride;
526 _vertexBuffer += _stride;
528 _vertexBuffer += _stride;
537 _vertexBuffer += _stride;
539 _vertexBuffer += _stride;
541 _vertexBuffer += _stride;
543 _vertexBuffer += _stride;
void updateRegion(const AtlasRegion &_region, const uint8_t *_bitmapBuffer)
update a preallocated region
uint16_t addRegion(uint16_t _width, uint16_t _height, const uint8_t *_bitmapBuffer, AtlasRegion::Type _type=AtlasRegion::TYPE_BGRA8, uint16_t outline=0)
add a region to the atlas, and copy the content of mem to the underlying texture
uint32_t getTextureBufferSize() const
retrieve the byte size of the texture
void packFaceLayerUV(uint32_t _idx, uint8_t *_vertexBuffer, uint32_t _offset, uint32_t _stride) const
Same as packUV but pack a whole face of the atlas cube, mostly used for debugging and visualizing atl...
void packUV(uint16_t _regionHandle, uint8_t *_vertexBuffer, uint32_t _offset, uint32_t _stride) const
Atlas(uint16_t _textureSize, uint16_t _maxRegionsCount=4096)
float getUsageRatio()
return the usage ratio of the available surface [0:1]
void clear()
reset to initial state
void init(uint32_t _width, uint32_t _height)
non constructor initialization
bool addRectangle(uint16_t _width, uint16_t _height, uint16_t &_outX, uint16_t &_outY)
uint32_t getTotalSurface()
return the total available surface in squared unit
uint32_t getUsedSurface()
return the used surface in squared unit
static void writeUV(uint8_t *_vertexBuffer, int16_t _x, int16_t _y, int16_t _z, int16_t _w)
utfchar32_t next(octet_iterator &it, octet_iterator end)
void setMask(Type _type, uint32_t _faceIndex, uint32_t _componentIndex)
uint32_t getFaceIndex() const
uint32_t getComponentIndex() const