178 lines
3.3 KiB
C++
178 lines
3.3 KiB
C++
/*
|
|
* Copyright 2011-2017 Branimir Karadzic. All rights reserved.
|
|
* License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
|
|
*/
|
|
|
|
#ifndef RECTPACK_H_HEADER_GUARD
|
|
#define RECTPACK_H_HEADER_GUARD
|
|
|
|
#include <bx/uint32_t.h>
|
|
|
|
struct Pack2D
|
|
{
|
|
uint16_t m_x;
|
|
uint16_t m_y;
|
|
uint16_t m_width;
|
|
uint16_t m_height;
|
|
};
|
|
|
|
struct PackCube
|
|
{
|
|
Pack2D m_rect;
|
|
uint8_t m_side;
|
|
};
|
|
|
|
template <uint16_t numBlocks>
|
|
class RectPackCubeT;
|
|
|
|
template <uint16_t numBlocks>
|
|
class RectPack2DT
|
|
{
|
|
public:
|
|
RectPack2DT(uint16_t _width, uint16_t _height)
|
|
{
|
|
reset(_width, _height);
|
|
}
|
|
|
|
void reset(uint16_t _width, uint16_t _height)
|
|
{
|
|
m_bw = _width/64;
|
|
m_bh = _height/numBlocks;
|
|
bx::memSet(m_mem, 0xff, sizeof(m_mem) );
|
|
}
|
|
|
|
bool find(uint16_t _width, uint16_t _height, Pack2D& _pack)
|
|
{
|
|
uint16_t width = bx::uint16_min(64, (_width + m_bw - 1) / m_bw);
|
|
uint16_t height = bx::uint16_min(numBlocks, (_height + m_bh - 1) / m_bh);
|
|
uint16_t numx = 64-width;
|
|
uint16_t numy = numBlocks-height;
|
|
|
|
const uint64_t scan = width == 64 ? UINT64_MAX : (UINT64_C(1)<<width)-1;
|
|
|
|
for (uint16_t starty = 0; starty <= numy; ++starty)
|
|
{
|
|
uint64_t mem = m_mem[starty];
|
|
uint16_t ntz = (uint16_t)bx::uint64_cnttz(mem);
|
|
uint64_t mask = scan<<ntz;
|
|
|
|
for (uint16_t xx = ntz; xx <= numx; ++xx, mask <<= 1)
|
|
{
|
|
uint16_t yy = starty;
|
|
if ( (mem&mask) == mask)
|
|
{
|
|
uint16_t endy = starty + height;
|
|
while (yy < endy && (m_mem[yy]&mask) == mask)
|
|
{
|
|
++yy;
|
|
}
|
|
|
|
if (yy == endy)
|
|
{
|
|
uint64_t cmask = ~mask;
|
|
for (yy = starty; yy < endy; ++yy)
|
|
{
|
|
m_mem[yy] &= cmask;
|
|
}
|
|
|
|
_pack.m_x = xx * m_bw;
|
|
_pack.m_y = starty * m_bh;
|
|
_pack.m_width = width * m_bw;
|
|
_pack.m_height = height * m_bh;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void clear(const Pack2D& _pack)
|
|
{
|
|
uint16_t startx = bx::uint16_min(63, _pack.m_x / m_bw);
|
|
uint16_t starty = bx::uint16_min(numBlocks-1, _pack.m_y / m_bh);
|
|
uint16_t endx = bx::uint16_min(64, (_pack.m_width + m_bw - 1) / m_bw + startx);
|
|
uint16_t endy = bx::uint16_min(numBlocks, (_pack.m_height + m_bh - 1) / m_bh + starty);
|
|
uint16_t width = endx - startx;
|
|
|
|
const uint64_t mask = (width == 64 ? UINT64_MAX : (UINT64_C(1)<<width)-1 )<<startx;
|
|
|
|
for (uint16_t yy = starty; yy < endy; ++yy)
|
|
{
|
|
m_mem[yy] |= mask;
|
|
}
|
|
}
|
|
|
|
private:
|
|
friend class RectPackCubeT<numBlocks>;
|
|
|
|
RectPack2DT()
|
|
{
|
|
}
|
|
|
|
uint64_t m_mem[numBlocks];
|
|
uint16_t m_bw;
|
|
uint16_t m_bh;
|
|
};
|
|
|
|
template <uint16_t numBlocks>
|
|
class RectPackCubeT
|
|
{
|
|
public:
|
|
RectPackCubeT(uint16_t _side)
|
|
{
|
|
reset(_side);
|
|
}
|
|
|
|
void reset(uint16_t _side)
|
|
{
|
|
for (uint8_t ii = 0; ii < 6; ++ii)
|
|
{
|
|
m_mru[ii] = ii;
|
|
m_ra[ii].reset(_side, _side);
|
|
}
|
|
}
|
|
|
|
bool find(uint16_t _width, uint16_t _height, PackCube& _pack)
|
|
{
|
|
bool found = false;
|
|
for (uint32_t ii = 0; ii < 6; ++ii)
|
|
{
|
|
uint8_t side = m_mru[ii];
|
|
found = m_ra[side].find(_width, _height, _pack.m_rect);
|
|
|
|
if (found)
|
|
{
|
|
_pack.m_side = side;
|
|
m_mru[ii] = m_mru[0];
|
|
m_mru[0] = side;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void clear(const PackCube& _pack)
|
|
{
|
|
uint8_t side = _pack.m_side;
|
|
|
|
uint32_t ii = 0;
|
|
for (; ii < 6 && m_mru[ii] != side; ++ii) {};
|
|
|
|
m_mru[ii] = m_mru[0];
|
|
m_mru[0] = side;
|
|
|
|
m_ra[side].clear(_pack.m_rect);
|
|
}
|
|
|
|
private:
|
|
RectPackCubeT();
|
|
|
|
RectPack2DT<numBlocks> m_ra[6];
|
|
uint8_t m_mru[6];
|
|
};
|
|
|
|
#endif // RECTPACK_H_HEADER_GUARD
|