cube_atlas.cpp 13 KB

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