cube_atlas.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  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. //********** 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):x(_x), y(_y), width(_width) {}
  35. /// The starting x-coordinate (leftmost).
  36. int16_t x;
  37. /// The y-coordinate of the skyline level line.
  38. int16_t y;
  39. /// The line width. The ending coordinate (inclusive) will be x+width-1.
  40. int32_t 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. assert(width > 2);
  63. assert(height > 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. size_t i;
  81. best_height = INT_MAX;
  82. best_index = -1;
  83. best_width = INT_MAX;
  84. for( i = 0; i < m_skyline.size(); ++i )
  85. {
  86. y = fit( i, width, height );
  87. if( y >= 0 )
  88. {
  89. node = &m_skyline[i];
  90. if( ( (y + height) < best_height ) ||
  91. ( ((y + height) == best_height) && (node->width < best_width)) )
  92. {
  93. best_height = y + height;
  94. best_index = i;
  95. best_width = node->width;
  96. outX = node->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(i = best_index+1; i < m_skyline.size(); ++i)
  108. {
  109. node = &m_skyline[i];
  110. prev = &m_skyline[i-1];
  111. if (node->x < (prev->x + prev->width) )
  112. {
  113. int shrink = prev->x + prev->width - node->x;
  114. node->x += shrink;
  115. node->width -= shrink;
  116. if (node->width <= 0)
  117. {
  118. m_skyline.erase(m_skyline.begin() + i);
  119. --i;
  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.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.y;
  164. while( width_left > 0 )
  165. {
  166. const Node& node = m_skyline[i];
  167. if( node.y > y )
  168. {
  169. y = node.y;
  170. }
  171. if( (y + height) > (int32_t)(m_height-1) )
  172. {
  173. return -1;
  174. }
  175. width_left -= node.width;
  176. ++i;
  177. }
  178. return y;
  179. }
  180. void RectanglePacker::merge()
  181. {
  182. Node* node;
  183. Node* next;
  184. uint32_t i;
  185. for( i=0; i < m_skyline.size()-1; ++i )
  186. {
  187. node = (Node *) &m_skyline[i];
  188. next = (Node *) &m_skyline[i+1];
  189. if( node->y == next->y )
  190. {
  191. node->width += next->width;
  192. m_skyline.erase(m_skyline.begin() + i + 1);
  193. --i;
  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. assert(textureSize >= 64 && textureSize <= 4096 && "suspicious texture size" );
  206. assert(maxRegionsCount >= 64 && maxRegionsCount <= 32000 && "suspicious regions count" );
  207. m_layers = new PackedLayer[24];
  208. for(int i=0; i<24;++i)
  209. {
  210. m_layers[i].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. assert(regionCount <= 64 && maxRegionsCount <= 4096);
  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. m_maxRegionCount = regionCount;
  246. m_regions = new AtlasRegion[regionCount];
  247. m_textureBuffer = new uint8_t[getTextureBufferSize()];
  248. //BGFX_TEXTURE_MIN_POINT|BGFX_TEXTURE_MAG_POINT|BGFX_TEXTURE_MIP_POINT;
  249. //BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT
  250. //BGFX_TEXTURE_U_CLAMP|BGFX_TEXTURE_V_CLAMP
  251. uint32_t flags = 0;//BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT;
  252. memcpy(m_regions, regionBuffer, regionCount * sizeof(AtlasRegion));
  253. memcpy(m_textureBuffer, textureBuffer, getTextureBufferSize());
  254. m_textureHandle = bgfx::createTextureCube(6
  255. , textureSize
  256. , 1
  257. , bgfx::TextureFormat::BGRA8
  258. , flags
  259. , bgfx::makeRef(m_textureBuffer, getTextureBufferSize())
  260. );
  261. }
  262. Atlas::~Atlas()
  263. {
  264. delete[] m_layers;
  265. delete[] m_regions;
  266. delete[] m_textureBuffer;
  267. }
  268. uint16_t Atlas::addRegion(uint16_t width, uint16_t height, const uint8_t* bitmapBuffer, AtlasRegion::Type type)
  269. {
  270. if (m_regionCount >= m_maxRegionCount)
  271. {
  272. return UINT16_MAX;
  273. }
  274. uint16_t x,y;
  275. // We want each bitmap to be separated by at least one black pixel
  276. // TODO manage mipmaps
  277. uint32_t idx = 0;
  278. while(idx<m_usedLayers)
  279. {
  280. if(m_layers[idx].faceRegion.getType() == type)
  281. {
  282. if(m_layers[idx].packer.addRectangle(width+1,height+1,x,y)) break;
  283. }
  284. idx++;
  285. }
  286. if(idx >= m_usedLayers)
  287. {
  288. //do we have still room to add layers ?
  289. if( (idx + type) > 24 || m_usedFaces>=6)
  290. {
  291. return UINT16_MAX;
  292. }
  293. //create new layers
  294. for(int i=0; i < type;++i)
  295. {
  296. m_layers[idx+i].faceRegion.setMask(type, m_usedFaces, i);
  297. }
  298. m_usedLayers += type;
  299. m_usedFaces++;
  300. //add it to the created layer
  301. if(!m_layers[idx].packer.addRectangle(width+1,height+1,x,y))
  302. {
  303. return UINT16_MAX;
  304. }
  305. }
  306. AtlasRegion& region = m_regions[m_regionCount];
  307. region.x = x;
  308. region.y = y;
  309. region.width = width;
  310. region.height = height;
  311. region.mask = m_layers[idx].faceRegion.mask;
  312. updateRegion(region, bitmapBuffer);
  313. return m_regionCount++;
  314. }
  315. void Atlas::updateRegion(const AtlasRegion& region, const uint8_t* bitmapBuffer)
  316. {
  317. const bgfx::Memory* mem = bgfx::alloc(region.width * region.height * 4);
  318. //BAD!
  319. memset(mem->data,0, mem->size);
  320. if(region.getType() == AtlasRegion::TYPE_BGRA8)
  321. {
  322. const uint8_t* inLineBuffer = bitmapBuffer;
  323. uint8_t* outLineBuffer = m_textureBuffer + region.getFaceIndex() * (m_textureSize*m_textureSize*4) + (((region.y *m_textureSize)+region.x)*4);
  324. //update the cpu buffer
  325. for(int y = 0; y < region.height; ++y)
  326. {
  327. memcpy(outLineBuffer, inLineBuffer, region.width * 4);
  328. inLineBuffer += region.width*4;
  329. outLineBuffer += m_textureSize*4;
  330. }
  331. //update the GPU buffer
  332. memcpy(mem->data, bitmapBuffer, mem->size);
  333. }else
  334. {
  335. uint32_t layer = region.getComponentIndex();
  336. uint32_t face = region.getFaceIndex();
  337. const uint8_t* inLineBuffer = bitmapBuffer;
  338. uint8_t* outLineBuffer = (m_textureBuffer + region.getFaceIndex() * (m_textureSize*m_textureSize*4) + (((region.y *m_textureSize)+region.x)*4));
  339. //update the cpu buffer
  340. for(int y = 0; y<region.height; ++y)
  341. {
  342. for(int x = 0; x<region.width; ++x)
  343. {
  344. outLineBuffer[(x*4) + layer] = inLineBuffer[x];
  345. }
  346. //update the GPU buffer
  347. memcpy(mem->data + y*region.width*4, outLineBuffer, region.width*4);
  348. inLineBuffer += region.width;
  349. outLineBuffer += m_textureSize*4;
  350. }
  351. }
  352. bgfx::updateTextureCube(m_textureHandle, (uint8_t)region.getFaceIndex(), 0, region.x, region.y, region.width, region.height, mem);
  353. }
  354. void Atlas::packFaceLayerUV(uint32_t idx, uint8_t* vertexBuffer, uint32_t offset, uint32_t stride )
  355. {
  356. packUV(m_layers[idx].faceRegion, vertexBuffer, offset, stride);
  357. }
  358. void Atlas::packUV( uint16_t handle, uint8_t* vertexBuffer, uint32_t offset, uint32_t stride )
  359. {
  360. const AtlasRegion& region = m_regions[handle];
  361. packUV(region, vertexBuffer, offset, stride);
  362. }
  363. void Atlas::packUV( const AtlasRegion& region, uint8_t* vertexBuffer, uint32_t offset, uint32_t stride )
  364. {
  365. float texMult = 65535.0f / ((float)(m_textureSize));
  366. static const int16_t minVal = -32768;
  367. static const int16_t maxVal = 32767;
  368. int16_t x0 = (int16_t)(region.x * texMult)-32768;
  369. int16_t y0 = (int16_t)(region.y * texMult)-32768;
  370. int16_t x1 = (int16_t)((region.x + region.width)* texMult)-32768;
  371. int16_t y1 = (int16_t)((region.y + region.height)* texMult)-32768;
  372. int16_t w = (int16_t) ((32767.0f/4.0f) * region.getComponentIndex());
  373. vertexBuffer+=offset;
  374. switch(region.getFaceIndex())
  375. {
  376. case 0: // +X
  377. x0= -x0;
  378. x1= -x1;
  379. y0= -y0;
  380. y1= -y1;
  381. writeUV(vertexBuffer, maxVal, y0, x0, w); vertexBuffer+=stride;
  382. writeUV(vertexBuffer, maxVal, y1, x0, w); vertexBuffer+=stride;
  383. writeUV(vertexBuffer, maxVal, y1, x1, w); vertexBuffer+=stride;
  384. writeUV(vertexBuffer, maxVal, y0, x1, w); vertexBuffer+=stride;
  385. break;
  386. case 1: // -X
  387. y0= -y0;
  388. y1= -y1;
  389. writeUV(vertexBuffer, minVal, y0, x0, w); vertexBuffer+=stride;
  390. writeUV(vertexBuffer, minVal, y1, x0, w); vertexBuffer+=stride;
  391. writeUV(vertexBuffer, minVal, y1, x1, w); vertexBuffer+=stride;
  392. writeUV(vertexBuffer, minVal, y0, x1, w); vertexBuffer+=stride;
  393. break;
  394. case 2: // +Y
  395. writeUV(vertexBuffer, x0, maxVal, y0, w); vertexBuffer+=stride;
  396. writeUV(vertexBuffer, x0, maxVal, y1, w); vertexBuffer+=stride;
  397. writeUV(vertexBuffer, x1, maxVal, y1, w); vertexBuffer+=stride;
  398. writeUV(vertexBuffer, x1, maxVal, y0, w); vertexBuffer+=stride;
  399. break;
  400. case 3: // -Y
  401. y0= -y0;
  402. y1= -y1;
  403. writeUV(vertexBuffer, x0, minVal, y0, w); vertexBuffer+=stride;
  404. writeUV(vertexBuffer, x0, minVal, y1, w); vertexBuffer+=stride;
  405. writeUV(vertexBuffer, x1, minVal, y1, w); vertexBuffer+=stride;
  406. writeUV(vertexBuffer, x1, minVal, y0, w); vertexBuffer+=stride;
  407. break;
  408. case 4: // +Z
  409. y0= -y0;
  410. y1= -y1;
  411. writeUV(vertexBuffer, x0, y0, maxVal, w); vertexBuffer+=stride;
  412. writeUV(vertexBuffer, x0, y1, maxVal, w); vertexBuffer+=stride;
  413. writeUV(vertexBuffer, x1, y1, maxVal, w); vertexBuffer+=stride;
  414. writeUV(vertexBuffer, x1, y0, maxVal, w); vertexBuffer+=stride;
  415. break;
  416. case 5: // -Z
  417. x0= -x0;
  418. x1= -x1;
  419. y0= -y0;
  420. y1= -y1;
  421. writeUV(vertexBuffer, x0, y0, minVal, w); vertexBuffer+=stride;
  422. writeUV(vertexBuffer, x0, y1, minVal, w); vertexBuffer+=stride;
  423. writeUV(vertexBuffer, x1, y1, minVal, w); vertexBuffer+=stride;
  424. writeUV(vertexBuffer, x1, y0, minVal, w); vertexBuffer+=stride;
  425. break;
  426. }
  427. }