cube_atlas.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. /* Copyright 2013 Jeremie Roy. All rights reserved.
  2. * License: http://www.opensource.org/licenses/BSD-2-Clause
  3. */
  4. #pragma once
  5. #include "cube_atlas.h"
  6. #include <bx/bx.h>
  7. #include <bgfx.h>
  8. #include <vector>
  9. //********** Rectangle packer implementation ************
  10. class RectanglePacker
  11. {
  12. public:
  13. RectanglePacker();
  14. RectanglePacker(uint32_t _width, uint32_t _height);
  15. /// non constructor initialization
  16. void init(uint32_t _width, uint32_t _height);
  17. /// find a suitable position for the given rectangle
  18. /// @return true if the rectangle can be added, false otherwise
  19. bool addRectangle(uint16_t _width, uint16_t _height, uint16_t& _outX, uint16_t& _outY );
  20. /// return the used surface in squared unit
  21. uint32_t getUsedSurface() { return m_usedSpace; }
  22. /// return the total available surface in squared unit
  23. uint32_t getTotalSurface() { return m_width*m_height; }
  24. /// return the usage ratio of the available surface [0:1]
  25. float getUsageRatio();
  26. /// reset to initial state
  27. void clear();
  28. private:
  29. int32_t fit(uint32_t _skylineNodeIndex, uint16_t _width, uint16_t _height);
  30. /// Merges all skyline nodes that are at the same level.
  31. void merge();
  32. struct Node
  33. {
  34. Node(int16_t _x, int16_t _y, int16_t _width):m_x(_x), m_y(_y), m_width(_width) {}
  35. /// The starting x-coordinate (leftmost).
  36. int16_t m_x;
  37. /// The y-coordinate of the skyline level line.
  38. int16_t m_y;
  39. /// The line _width. The ending coordinate (inclusive) will be x+width-1.
  40. int32_t m_width; //32bit to avoid padding
  41. };
  42. /// width (in pixels) of the underlying texture
  43. uint32_t m_width;
  44. /// height (in pixels) of the underlying texture
  45. uint32_t m_height;
  46. /// Surface used in squared pixel
  47. uint32_t m_usedSpace;
  48. /// node of the skyline algorithm
  49. std::vector<Node> m_skyline;
  50. };
  51. RectanglePacker::RectanglePacker(): m_width(0), m_height(0), m_usedSpace(0)
  52. {
  53. }
  54. RectanglePacker::RectanglePacker(uint32_t _width, uint32_t _height):m_width(_width), m_height(_height), m_usedSpace(0)
  55. {
  56. // We want a one pixel border around the whole atlas to avoid any artefact when
  57. // sampling texture
  58. m_skyline.push_back(Node(1,1, _width-2));
  59. }
  60. void RectanglePacker::init(uint32_t _width, uint32_t _height)
  61. {
  62. BX_CHECK(_width > 2, "_width must be > 2");
  63. BX_CHECK(_height > 2, "_height must be > 2");
  64. m_width = _width;
  65. m_height = _height;
  66. m_usedSpace = 0;
  67. m_skyline.clear();
  68. // We want a one pixel border around the whole atlas to avoid any artifact when
  69. // sampling texture
  70. m_skyline.push_back(Node(1,1, _width-2));
  71. }
  72. bool RectanglePacker::addRectangle(uint16_t _width, uint16_t _height, uint16_t& _outX, uint16_t& _outY)
  73. {
  74. int y, best_height, best_index;
  75. int32_t best_width;
  76. Node* node;
  77. Node* prev;
  78. _outX = 0;
  79. _outY = 0;
  80. uint32_t ii;
  81. best_height = INT_MAX;
  82. best_index = -1;
  83. best_width = INT_MAX;
  84. for( ii = 0; ii < m_skyline.size(); ++ii )
  85. {
  86. y = fit( ii, _width, _height );
  87. if( y >= 0 )
  88. {
  89. node = &m_skyline[ii];
  90. if( ( (y + _height) < best_height ) ||
  91. ( ((y + _height) == best_height) && (node->m_width < best_width)) )
  92. {
  93. best_height = y + _height;
  94. best_index = ii;
  95. best_width = node->m_width;
  96. _outX = node->m_x;
  97. _outY = y;
  98. }
  99. }
  100. }
  101. if( best_index == -1 )
  102. {
  103. return false;
  104. }
  105. Node newNode(_outX, _outY + _height, _width);
  106. m_skyline.insert(m_skyline.begin() + best_index, newNode);
  107. for(ii = best_index+1; ii < m_skyline.size(); ++ii)
  108. {
  109. node = &m_skyline[ii];
  110. prev = &m_skyline[ii-1];
  111. if (node->m_x < (prev->m_x + prev->m_width) )
  112. {
  113. int shrink = prev->m_x + prev->m_width - node->m_x;
  114. node->m_x += shrink;
  115. node->m_width -= shrink;
  116. if (node->m_width <= 0)
  117. {
  118. m_skyline.erase(m_skyline.begin() + ii);
  119. --ii;
  120. }
  121. else
  122. {
  123. break;
  124. }
  125. }
  126. else
  127. {
  128. break;
  129. }
  130. }
  131. merge();
  132. m_usedSpace += _width * _height;
  133. return true;
  134. }
  135. float RectanglePacker::getUsageRatio()
  136. {
  137. uint32_t total = m_width*m_height;
  138. if(total > 0)
  139. return (float) m_usedSpace / (float) total;
  140. else
  141. return 0.0f;
  142. }
  143. void RectanglePacker::clear()
  144. {
  145. m_skyline.clear();
  146. m_usedSpace = 0;
  147. // We want a one pixel border around the whole atlas to avoid any artefact when
  148. // sampling texture
  149. m_skyline.push_back(Node(1,1, m_width-2));
  150. }
  151. int32_t RectanglePacker::fit(uint32_t _skylineNodeIndex, uint16_t _width, uint16_t _height)
  152. {
  153. int32_t width = _width;
  154. int32_t height = _height;
  155. const Node& baseNode = m_skyline[_skylineNodeIndex];
  156. int32_t x = baseNode.m_x, y;
  157. int32_t _width_left = width;
  158. int32_t i = _skylineNodeIndex;
  159. if ( (x + width) > (int32_t)(m_width-1) )
  160. {
  161. return -1;
  162. }
  163. y = baseNode.m_y;
  164. while( _width_left > 0 )
  165. {
  166. const Node& node = m_skyline[i];
  167. if( node.m_y > y )
  168. {
  169. y = node.m_y;
  170. }
  171. if( (y + height) > (int32_t)(m_height-1) )
  172. {
  173. return -1;
  174. }
  175. _width_left -= node.m_width;
  176. ++i;
  177. }
  178. return y;
  179. }
  180. void RectanglePacker::merge()
  181. {
  182. Node* node;
  183. Node* next;
  184. uint32_t ii;
  185. for( ii=0; ii < m_skyline.size()-1; ++ii )
  186. {
  187. node = (Node *) &m_skyline[ii];
  188. next = (Node *) &m_skyline[ii+1];
  189. if( node->m_y == next->m_y )
  190. {
  191. node->m_width += next->m_width;
  192. m_skyline.erase(m_skyline.begin() + ii + 1);
  193. --ii;
  194. }
  195. }
  196. }
  197. //********** Cube Atlas implementation ************
  198. struct Atlas::PackedLayer
  199. {
  200. RectanglePacker packer;
  201. AtlasRegion faceRegion;
  202. };
  203. Atlas::Atlas(uint16_t _textureSize, uint16_t _maxRegionsCount )
  204. {
  205. BX_CHECK(_textureSize >= 64 && _textureSize <= 4096, "suspicious texture size" );
  206. BX_CHECK(_maxRegionsCount >= 64 && _maxRegionsCount <= 32000, "suspicious _regions count" );
  207. m_layers = new PackedLayer[24];
  208. for(int ii=0; ii<24;++ii)
  209. {
  210. m_layers[ii].packer.init(_textureSize, _textureSize);
  211. }
  212. m_usedLayers = 0;
  213. m_usedFaces = 0;
  214. m_textureSize = _textureSize;
  215. m_regionCount = 0;
  216. m_maxRegionCount = _maxRegionsCount;
  217. m_regions = new AtlasRegion[_maxRegionsCount];
  218. m_textureBuffer = new uint8_t[ _textureSize * _textureSize * 6 * 4 ];
  219. memset(m_textureBuffer, 0, _textureSize * _textureSize * 6 * 4);
  220. //BGFX_TEXTURE_MIN_POINT|BGFX_TEXTURE_MAG_POINT|BGFX_TEXTURE_MIP_POINT;
  221. //BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT
  222. //BGFX_TEXTURE_U_CLAMP|BGFX_TEXTURE_V_CLAMP
  223. uint32_t flags = 0;// BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT;
  224. //Uncomment this to debug atlas
  225. //const bgfx::Memory* mem = bgfx::alloc(textureSize*textureSize * 6 * 4);
  226. //memset(mem->data, 255, mem->size);
  227. const bgfx::Memory* mem = NULL;
  228. m_textureHandle = bgfx::createTextureCube(6
  229. , _textureSize
  230. , 1
  231. , bgfx::TextureFormat::BGRA8
  232. , flags
  233. ,mem
  234. );
  235. }
  236. Atlas::Atlas(uint16_t _textureSize, const uint8_t* _textureBuffer , uint16_t _regionCount, const uint8_t* _regionBuffer, uint16_t _maxRegionsCount)
  237. {
  238. BX_CHECK(_regionCount <= 64 && _maxRegionsCount <= 4096, "suspicious initialization");
  239. //layers are frozen
  240. m_usedLayers = 24;
  241. m_usedFaces = 6;
  242. m_textureSize = _textureSize;
  243. m_regionCount = _regionCount;
  244. //regions are frozen
  245. if(_regionCount < _maxRegionsCount)
  246. m_maxRegionCount = _regionCount;
  247. else
  248. m_maxRegionCount = _maxRegionsCount;
  249. m_regions = new AtlasRegion[_regionCount];
  250. m_textureBuffer = new uint8_t[getTextureBufferSize()];
  251. //BGFX_TEXTURE_MIN_POINT|BGFX_TEXTURE_MAG_POINT|BGFX_TEXTURE_MIP_POINT;
  252. //BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT
  253. //BGFX_TEXTURE_U_CLAMP|BGFX_TEXTURE_V_CLAMP
  254. uint32_t flags = 0;//BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT;
  255. memcpy(m_regions, _regionBuffer, _regionCount * sizeof(AtlasRegion));
  256. memcpy(m_textureBuffer, _textureBuffer, getTextureBufferSize());
  257. m_textureHandle = bgfx::createTextureCube(6
  258. , _textureSize
  259. , 1
  260. , bgfx::TextureFormat::BGRA8
  261. , flags
  262. , bgfx::makeRef(m_textureBuffer, getTextureBufferSize())
  263. );
  264. }
  265. Atlas::~Atlas()
  266. {
  267. delete[] m_layers;
  268. delete[] m_regions;
  269. delete[] m_textureBuffer;
  270. }
  271. uint16_t Atlas::addRegion(uint16_t _width, uint16_t _height, const uint8_t* _bitmapBuffer, AtlasRegion::Type _type, uint16_t outline)
  272. {
  273. if (m_regionCount >= m_maxRegionCount)
  274. {
  275. return UINT16_MAX;
  276. }
  277. uint16_t x=0,y=0;
  278. // We want each bitmap to be separated by at least one black pixel
  279. // TODO manage mipmaps
  280. uint32_t idx = 0;
  281. while(idx<m_usedLayers)
  282. {
  283. if(m_layers[idx].faceRegion.getType() == _type)
  284. {
  285. if(m_layers[idx].packer.addRectangle(_width+1,_height+1,x,y)) break;
  286. }
  287. idx++;
  288. }
  289. if(idx >= m_usedLayers)
  290. {
  291. //do we have still room to add layers ?
  292. if( (idx + _type) > 24 || m_usedFaces>=6)
  293. {
  294. return UINT16_MAX;
  295. }
  296. //create new layers
  297. for(int ii=0; ii < _type; ++ii)
  298. {
  299. m_layers[idx+ii].faceRegion.setMask(_type, m_usedFaces, ii);
  300. }
  301. m_usedLayers += _type;
  302. m_usedFaces++;
  303. //add it to the created layer
  304. if(!m_layers[idx].packer.addRectangle(_width+1, _height+1, x, y))
  305. {
  306. return UINT16_MAX;
  307. }
  308. }
  309. AtlasRegion& region = m_regions[m_regionCount];
  310. region.m_x = x ;
  311. region.m_y = y ;
  312. region.m_width = _width;
  313. region.m_height = _height;
  314. region.m_mask = m_layers[idx].faceRegion.m_mask;
  315. updateRegion(region, _bitmapBuffer);
  316. region.m_x += outline;
  317. region.m_y += outline;
  318. region.m_width -= (outline*2);
  319. region.m_height -= (outline*2);
  320. return m_regionCount++;
  321. }
  322. void Atlas::updateRegion(const AtlasRegion& _region, const uint8_t* _bitmapBuffer)
  323. {
  324. const bgfx::Memory* mem = bgfx::alloc(_region.m_width * _region.m_height * 4);
  325. //BAD!
  326. memset(mem->data,0, mem->size);
  327. if(_region.getType() == AtlasRegion::TYPE_BGRA8)
  328. {
  329. const uint8_t* inLineBuffer = _bitmapBuffer;
  330. uint8_t* outLineBuffer = m_textureBuffer + _region.getFaceIndex() * (m_textureSize*m_textureSize*4) + (((_region.m_y *m_textureSize)+_region.m_x)*4);
  331. //update the cpu buffer
  332. for(int yy = 0; yy < _region.m_height; ++yy)
  333. {
  334. memcpy(outLineBuffer, inLineBuffer, _region.m_width * 4);
  335. inLineBuffer += _region.m_width*4;
  336. outLineBuffer += m_textureSize*4;
  337. }
  338. //update the GPU buffer
  339. memcpy(mem->data, _bitmapBuffer, mem->size);
  340. }else
  341. {
  342. uint32_t layer = _region.getComponentIndex();
  343. //uint32_t face = _region.getFaceIndex();
  344. const uint8_t* inLineBuffer = _bitmapBuffer;
  345. uint8_t* outLineBuffer = (m_textureBuffer + _region.getFaceIndex() * (m_textureSize*m_textureSize*4) + (((_region.m_y *m_textureSize)+_region.m_x)*4));
  346. //update the cpu buffer
  347. for(int yy = 0; yy<_region.m_height; ++yy)
  348. {
  349. for(int xx = 0; xx<_region.m_width; ++xx)
  350. {
  351. outLineBuffer[(xx*4) + layer] = inLineBuffer[xx];
  352. }
  353. //update the GPU buffer
  354. memcpy(mem->data + yy*_region.m_width*4, outLineBuffer, _region.m_width*4);
  355. inLineBuffer += _region.m_width;
  356. outLineBuffer += m_textureSize*4;
  357. }
  358. }
  359. bgfx::updateTextureCube(m_textureHandle, (uint8_t)_region.getFaceIndex(), 0, _region.m_x, _region.m_y, _region.m_width, _region.m_height, mem);
  360. }
  361. void Atlas::packFaceLayerUV(uint32_t _idx, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride )
  362. {
  363. packUV(m_layers[_idx].faceRegion, _vertexBuffer, _offset, _stride);
  364. }
  365. void Atlas::packUV( uint16_t handle, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride )
  366. {
  367. const AtlasRegion& region = m_regions[handle];
  368. packUV(region, _vertexBuffer, _offset, _stride);
  369. }
  370. void Atlas::packUV( const AtlasRegion& _region, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride )
  371. {
  372. float texMult = 65535.0f / ((float)(m_textureSize));
  373. static const int16_t minVal = -32768;
  374. static const int16_t maxVal = 32767;
  375. int16_t x0 = (int16_t)(_region.m_x * texMult)-32768;
  376. int16_t y0 = (int16_t)(_region.m_y * texMult)-32768;
  377. int16_t x1 = (int16_t)((_region.m_x + _region.m_width)* texMult)-32768;
  378. int16_t y1 = (int16_t)((_region.m_y + _region.m_height)* texMult)-32768;
  379. int16_t w = (int16_t) ((32767.0f/4.0f) * _region.getComponentIndex());
  380. _vertexBuffer+=_offset;
  381. switch(_region.getFaceIndex())
  382. {
  383. case 0: // +X
  384. x0= -x0;
  385. x1= -x1;
  386. y0= -y0;
  387. y1= -y1;
  388. writeUV(_vertexBuffer, maxVal, y0, x0, w); _vertexBuffer+=_stride;
  389. writeUV(_vertexBuffer, maxVal, y1, x0, w); _vertexBuffer+=_stride;
  390. writeUV(_vertexBuffer, maxVal, y1, x1, w); _vertexBuffer+=_stride;
  391. writeUV(_vertexBuffer, maxVal, y0, x1, w); _vertexBuffer+=_stride;
  392. break;
  393. case 1: // -X
  394. y0= -y0;
  395. y1= -y1;
  396. writeUV(_vertexBuffer, minVal, y0, x0, w); _vertexBuffer+=_stride;
  397. writeUV(_vertexBuffer, minVal, y1, x0, w); _vertexBuffer+=_stride;
  398. writeUV(_vertexBuffer, minVal, y1, x1, w); _vertexBuffer+=_stride;
  399. writeUV(_vertexBuffer, minVal, y0, x1, w); _vertexBuffer+=_stride;
  400. break;
  401. case 2: // +Y
  402. writeUV(_vertexBuffer, x0, maxVal, y0, w); _vertexBuffer+=_stride;
  403. writeUV(_vertexBuffer, x0, maxVal, y1, w); _vertexBuffer+=_stride;
  404. writeUV(_vertexBuffer, x1, maxVal, y1, w); _vertexBuffer+=_stride;
  405. writeUV(_vertexBuffer, x1, maxVal, y0, w); _vertexBuffer+=_stride;
  406. break;
  407. case 3: // -Y
  408. y0= -y0;
  409. y1= -y1;
  410. writeUV(_vertexBuffer, x0, minVal, y0, w); _vertexBuffer+=_stride;
  411. writeUV(_vertexBuffer, x0, minVal, y1, w); _vertexBuffer+=_stride;
  412. writeUV(_vertexBuffer, x1, minVal, y1, w); _vertexBuffer+=_stride;
  413. writeUV(_vertexBuffer, x1, minVal, y0, w); _vertexBuffer+=_stride;
  414. break;
  415. case 4: // +Z
  416. y0= -y0;
  417. y1= -y1;
  418. writeUV(_vertexBuffer, x0, y0, maxVal, w); _vertexBuffer+=_stride;
  419. writeUV(_vertexBuffer, x0, y1, maxVal, w); _vertexBuffer+=_stride;
  420. writeUV(_vertexBuffer, x1, y1, maxVal, w); _vertexBuffer+=_stride;
  421. writeUV(_vertexBuffer, x1, y0, maxVal, w); _vertexBuffer+=_stride;
  422. break;
  423. case 5: // -Z
  424. x0= -x0;
  425. x1= -x1;
  426. y0= -y0;
  427. y1= -y1;
  428. writeUV(_vertexBuffer, x0, y0, minVal, w); _vertexBuffer+=_stride;
  429. writeUV(_vertexBuffer, x0, y1, minVal, w); _vertexBuffer+=_stride;
  430. writeUV(_vertexBuffer, x1, y1, minVal, w); _vertexBuffer+=_stride;
  431. writeUV(_vertexBuffer, x1, y0, minVal, w); _vertexBuffer+=_stride;
  432. break;
  433. }
  434. }