tb_bitmap_fragment.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. // ================================================================================
  2. // == This file is a part of Turbo Badger. (C) 2011-2014, Emil Segerås ==
  3. // == See tb_core.h for more information. ==
  4. // ================================================================================
  5. #include "tb_bitmap_fragment.h"
  6. #include "tb_renderer.h"
  7. #include "tb_system.h"
  8. namespace tb {
  9. int TBGetNearestPowerOfTwo(int val)
  10. {
  11. int i;
  12. for(i = 31; i >= 0; i--)
  13. if ((val - 1) & (1<<i))
  14. break;
  15. return (1<<(i + 1));
  16. }
  17. // == TBSpaceAllocator ======================================================================================
  18. bool TBSpaceAllocator::HasSpace(int needed_w) const
  19. {
  20. if (needed_w > m_available_space)
  21. return false;
  22. if (IsAllAvailable())
  23. return true;
  24. for (Space *fs = m_free_space_list.GetFirst(); fs; fs = fs->GetNext())
  25. {
  26. if (needed_w <= fs->width)
  27. return true;
  28. }
  29. return false;
  30. }
  31. TBSpaceAllocator::Space *TBSpaceAllocator::AllocSpace(int needed_w)
  32. {
  33. if (Space *available_space = GetSmallestAvailableSpace(needed_w))
  34. {
  35. if (Space *new_space = new Space)
  36. {
  37. new_space->x = available_space->x;
  38. new_space->width = needed_w;
  39. m_used_space_list.AddLast(new_space);
  40. // Consume the used space from the available space
  41. available_space->x += needed_w;
  42. available_space->width -= needed_w;
  43. m_available_space -= needed_w;
  44. // Remove it if empty
  45. if (!available_space->width)
  46. m_free_space_list.Delete(available_space);
  47. return new_space;
  48. }
  49. }
  50. return nullptr;
  51. }
  52. TBSpaceAllocator::Space *TBSpaceAllocator::GetSmallestAvailableSpace(int needed_w)
  53. {
  54. assert(needed_w > 0);
  55. // Add free space covering all available space if empty.
  56. if (!m_free_space_list.HasLinks() && IsAllAvailable())
  57. {
  58. if (Space *fs = new Space)
  59. {
  60. fs->x = 0;
  61. fs->width = m_available_space;
  62. m_free_space_list.AddLast(fs);
  63. }
  64. }
  65. // Check for the smallest space where we fit
  66. Space *best_fs = nullptr;
  67. for (Space *fs = m_free_space_list.GetFirst(); fs; fs = fs->GetNext())
  68. {
  69. if (needed_w == fs->width)
  70. return fs; // It can't be better than a perfect match!
  71. if (needed_w < fs->width)
  72. if (!best_fs || fs->width < best_fs->width)
  73. best_fs = fs;
  74. }
  75. return best_fs;
  76. }
  77. void TBSpaceAllocator::FreeSpace(Space *space)
  78. {
  79. m_used_space_list.Remove(space);
  80. m_available_space += space->width;
  81. // Find where in m_free_space_list we should insert the space,
  82. // or which existing space we can extend.
  83. Space *preceeding = nullptr;
  84. Space *succeeding = nullptr;
  85. for (Space *fs = m_free_space_list.GetFirst(); fs; fs = fs->GetNext())
  86. {
  87. if (fs->x < space->x)
  88. preceeding = fs;
  89. if (fs->x > space->x)
  90. {
  91. succeeding = fs;
  92. break;
  93. }
  94. }
  95. if (preceeding && preceeding->x + preceeding->width == space->x)
  96. {
  97. preceeding->width += space->width;
  98. delete space;
  99. }
  100. else if (succeeding && succeeding->x == space->x + space->width)
  101. {
  102. succeeding->x -= space->width;
  103. succeeding->width += space->width;
  104. delete space;
  105. }
  106. else
  107. {
  108. if (preceeding)
  109. m_free_space_list.AddAfter(space, preceeding);
  110. else if (succeeding)
  111. m_free_space_list.AddBefore(space, succeeding);
  112. else
  113. {
  114. assert(!m_free_space_list.HasLinks());
  115. m_free_space_list.AddLast(space);
  116. }
  117. }
  118. // Merge free spaces
  119. Space *fs = m_free_space_list.GetFirst();
  120. while (fs)
  121. {
  122. Space *next_fs = fs->GetNext();
  123. if (!next_fs)
  124. break;
  125. if (fs->x + fs->width == next_fs->x)
  126. {
  127. fs->width += next_fs->width;
  128. m_free_space_list.Delete(next_fs);
  129. continue;
  130. }
  131. fs = next_fs;
  132. }
  133. #ifdef TB_RUNTIME_DEBUG_INFO
  134. // Check that free space is in order
  135. Space *tmp = m_free_space_list.GetFirst();
  136. int x = 0;
  137. while (tmp)
  138. {
  139. assert(tmp->x >= x);
  140. x = tmp->x + tmp->width;
  141. tmp = tmp->GetNext();
  142. }
  143. #endif // TB_RUNTIME_DEBUG_INFO
  144. }
  145. // == TBBitmapFragmentMap ===================================================================================
  146. TBBitmapFragmentMap::TBBitmapFragmentMap()
  147. : m_bitmap_w(0)
  148. , m_bitmap_h(0)
  149. , m_bitmap_data(nullptr)
  150. , m_bitmap(nullptr)
  151. , m_need_update(false)
  152. , m_allocated_pixels(0)
  153. {
  154. }
  155. bool TBBitmapFragmentMap::Init(int bitmap_w, int bitmap_h)
  156. {
  157. m_bitmap_data = new uint32[bitmap_w * bitmap_h];
  158. m_bitmap_w = bitmap_w;
  159. m_bitmap_h = bitmap_h;
  160. #ifdef TB_RUNTIME_DEBUG_INFO
  161. if (m_bitmap_data)
  162. memset(m_bitmap_data, 0x88, bitmap_w * bitmap_h * sizeof(uint32));
  163. #endif
  164. return m_bitmap_data ? true : false;
  165. }
  166. TBBitmapFragmentMap::~TBBitmapFragmentMap()
  167. {
  168. delete m_bitmap;
  169. delete [] m_bitmap_data;
  170. }
  171. TBBitmapFragment *TBBitmapFragmentMap::CreateNewFragment(int frag_w, int frag_h, int data_stride, uint32 *frag_data, bool add_border)
  172. {
  173. // Finding available space works like this:
  174. // The map size is sliced up horizontally in rows (initially just one row covering
  175. // the entire map). When adding a new fragment, put it in the row with smallest height.
  176. // If the smallest row is empty, it may slice the row to make a even smaller row.
  177. // When a image is stretched up to a larger size, the filtering will read
  178. // pixels closest (but outside) of the src_rect. When we pack images together
  179. // those pixels would be read from neighbour images, so we must add border space
  180. // around each image to avoid artifacts. We must also fill in that border with
  181. // the "clamp" of the image itself so we don't get any filtering artifacts at all.
  182. // Allways add border except when we're using the entire map for one fragment.
  183. int border = 0;
  184. int needed_w = frag_w;
  185. int needed_h = frag_h;
  186. if (add_border)
  187. {
  188. if (needed_w != m_bitmap_w || needed_h != m_bitmap_h)
  189. {
  190. border = 1;
  191. needed_w += 2;
  192. needed_h += 2;
  193. }
  194. }
  195. // Snap the fragments to a certain granularity. This could maybe ease the stress
  196. // on the space allocator when allocating & deallocating lots of small fragments.
  197. // I'm not sure there is any performance issue though and it would be better to
  198. // optimize the algorithm instead (so disabled it for now).
  199. //const int granularity = 8;
  200. //needed_w = (needed_w + granularity - 1) / granularity * granularity;
  201. //needed_h = (needed_h + granularity - 1) / granularity * granularity;
  202. if (!m_rows.GetNumItems())
  203. {
  204. // Create a row covering the entire bitmap.
  205. TBFragmentSpaceAllocator *row;
  206. if (!m_rows.GrowIfNeeded() || !(row = new TBFragmentSpaceAllocator(0, m_bitmap_w, m_bitmap_h)))
  207. return nullptr;
  208. m_rows.Add(row);
  209. }
  210. // Get the smallest row where we fit
  211. int best_row_index = -1;
  212. TBFragmentSpaceAllocator *best_row = nullptr;
  213. for (int i = 0; i < m_rows.GetNumItems(); i++)
  214. {
  215. TBFragmentSpaceAllocator *row = m_rows[i];
  216. if (!best_row || row->height < best_row->height)
  217. {
  218. // This is the best row so far, if we fit
  219. if (needed_h <= row->height && row->HasSpace(needed_w))
  220. {
  221. best_row = row;
  222. best_row_index = i;
  223. if (needed_h == row->height)
  224. break; // We can't find a smaller line, so we're done
  225. }
  226. }
  227. }
  228. // Return if we're full
  229. if (!best_row)
  230. return nullptr;
  231. // If the row is unused, create a smaller row to only consume needed height for fragment
  232. if (best_row->IsAllAvailable() && needed_h < best_row->height)
  233. {
  234. TBFragmentSpaceAllocator *row;
  235. if (!m_rows.GrowIfNeeded() || !(row = new TBFragmentSpaceAllocator(best_row->y + needed_h, m_bitmap_w, best_row->height - needed_h)))
  236. return nullptr;
  237. // Keep the rows sorted from top to bottom
  238. m_rows.Add(row, best_row_index + 1);
  239. best_row->height = needed_h;
  240. }
  241. // Allocate the fragment and copy the fragment data into the map data.
  242. if (TBFragmentSpaceAllocator::Space *space = best_row->AllocSpace(needed_w))
  243. {
  244. if (TBBitmapFragment *frag = new TBBitmapFragment)
  245. {
  246. frag->m_map = this;
  247. frag->m_row = best_row;
  248. frag->m_space = space;
  249. frag->m_rect.Set(space->x + border, best_row->y + border, frag_w, frag_h);
  250. frag->m_row_height = best_row->height;
  251. frag->m_batch_id = 0xffffffff;
  252. CopyData(frag, data_stride, frag_data, border);
  253. m_need_update = true;
  254. m_allocated_pixels += frag->m_space->width * frag->m_row->height;
  255. return frag;
  256. }
  257. else
  258. best_row->FreeSpace(space);
  259. }
  260. return nullptr;
  261. }
  262. void TBBitmapFragmentMap::FreeFragmentSpace(TBBitmapFragment *frag)
  263. {
  264. if (!frag)
  265. return;
  266. assert(frag->m_map == this);
  267. #ifdef TB_RUNTIME_DEBUG_INFO
  268. // Debug code to clear the area in debug builds so it's easier to
  269. // see & debug the allocation & deallocation of fragments in maps.
  270. if (uint32 *data32 = new uint32[frag->m_space->width * frag->m_row->height])
  271. {
  272. static int c = 0;
  273. memset(data32, (c++) * 32, sizeof(uint32) * frag->m_space->width * frag->m_row->height);
  274. CopyData(frag, frag->m_space->width, data32, false);
  275. m_need_update = true;
  276. delete [] data32;
  277. }
  278. #endif // TB_RUNTIME_DEBUG_INFO
  279. m_allocated_pixels -= frag->m_space->width * frag->m_row->height;
  280. frag->m_row->FreeSpace(frag->m_space);
  281. frag->m_space = nullptr;
  282. frag->m_row_height = 0;
  283. // If the row is now empty, merge empty rows so larger fragments
  284. // have a chance of allocating the space.
  285. if (frag->m_row->IsAllAvailable())
  286. {
  287. for (int i = 0; i < m_rows.GetNumItems() - 1; i++)
  288. {
  289. assert(i >= 0);
  290. assert(i < m_rows.GetNumItems() - 1);
  291. TBFragmentSpaceAllocator *row = m_rows.Get(i);
  292. TBFragmentSpaceAllocator *next_row = m_rows.Get(i + 1);
  293. if (row->IsAllAvailable() && next_row->IsAllAvailable())
  294. {
  295. row->height += next_row->height;
  296. m_rows.Delete(i + 1);
  297. i--;
  298. }
  299. }
  300. }
  301. }
  302. void TBBitmapFragmentMap::CopyData(TBBitmapFragment *frag, int data_stride, uint32 *frag_data, int border)
  303. {
  304. // Copy the bitmap data
  305. uint32 *dst = m_bitmap_data + frag->m_rect.x + frag->m_rect.y * m_bitmap_w;
  306. uint32 *src = frag_data;
  307. for (int i = 0; i < frag->m_rect.h; i++)
  308. {
  309. memcpy(dst, src, frag->m_rect.w * sizeof(uint32));
  310. dst += m_bitmap_w;
  311. src += data_stride;
  312. }
  313. // Copy the bitmap data to the border around the fragment
  314. if (border)
  315. {
  316. TBRect rect = frag->m_rect.Expand(border, border);
  317. // Copy vertical edges
  318. dst = m_bitmap_data + rect.x + (rect.y + 1) * m_bitmap_w;
  319. src = frag_data;
  320. for (int i = 0; i < frag->m_rect.h; i++)
  321. {
  322. dst[0] = src[0] & 0x00ffffff;
  323. dst[rect.w - 1] = src[frag->m_rect.w - 1] & 0x00ffffff;
  324. dst += m_bitmap_w;
  325. src += data_stride;
  326. }
  327. // Copy horizontal edges
  328. dst = m_bitmap_data + rect.x + 1 + rect.y * m_bitmap_w;
  329. src = frag_data;
  330. for (int i = 0; i < frag->m_rect.w; i++)
  331. dst[i] = src[i] & 0x00ffffff;
  332. dst = m_bitmap_data + rect.x + 1 + (rect.y + rect.h - 1) * m_bitmap_w;
  333. src = frag_data + (frag->m_rect.h - 1) * data_stride;
  334. for (int i = 0; i < frag->m_rect.w; i++)
  335. dst[i] = src[i] & 0x00ffffff;
  336. }
  337. }
  338. TBBitmap *TBBitmapFragmentMap::GetBitmap(TB_VALIDATE_TYPE validate_type)
  339. {
  340. if (m_bitmap && validate_type == TB_VALIDATE_FIRST_TIME)
  341. return m_bitmap;
  342. ValidateBitmap();
  343. return m_bitmap;
  344. }
  345. bool TBBitmapFragmentMap::ValidateBitmap()
  346. {
  347. if (m_need_update)
  348. {
  349. if (m_bitmap)
  350. m_bitmap->SetData(m_bitmap_data);
  351. else
  352. m_bitmap = g_renderer->CreateBitmap(m_bitmap_w, m_bitmap_h, m_bitmap_data);
  353. m_need_update = false;
  354. }
  355. return m_bitmap ? true : false;
  356. }
  357. void TBBitmapFragmentMap::DeleteBitmap()
  358. {
  359. delete m_bitmap;
  360. m_bitmap = nullptr;
  361. m_need_update = true;
  362. }
  363. // == TBBitmapFragmentManager =============================================================================
  364. TBBitmapFragmentManager::TBBitmapFragmentManager()
  365. : m_num_maps_limit(0)
  366. , m_add_border(false)
  367. , m_default_map_w(512)
  368. , m_default_map_h(512)
  369. {
  370. }
  371. TBBitmapFragmentManager::~TBBitmapFragmentManager()
  372. {
  373. Clear();
  374. }
  375. TBBitmapFragment *TBBitmapFragmentManager::GetFragmentFromFile(const char *filename, bool dedicated_map)
  376. {
  377. TBID id(filename);
  378. // If we already have a fragment for this filename, return that
  379. TBBitmapFragment *frag = m_fragments.Get(id);
  380. if (frag)
  381. return frag;
  382. // Load the file
  383. TBImageLoader *img = TBImageLoader::CreateFromFile(filename);
  384. if (!img)
  385. return nullptr;
  386. frag = CreateNewFragment(id, dedicated_map, img->Width(), img->Height(), img->Width(), img->Data());
  387. delete img;
  388. return frag;
  389. }
  390. TBBitmapFragment *TBBitmapFragmentManager::CreateNewFragment(const TBID &id, bool dedicated_map,
  391. int data_w, int data_h, int data_stride,
  392. uint32 *data)
  393. {
  394. assert(!GetFragment(id));
  395. TBBitmapFragment *frag = nullptr;
  396. // Create a fragment in any of the fragment maps. Doing it in the reverse order
  397. // would be faster since it's most likely to succeed, but we want to maximize
  398. // the amount of fragments per map, so do it in the creation order.
  399. if (!dedicated_map)
  400. {
  401. for (int i = 0; i < m_fragment_maps.GetNumItems(); i++)
  402. {
  403. if ((frag = m_fragment_maps[i]->CreateNewFragment(data_w, data_h, data_stride, data, m_add_border)))
  404. break;
  405. }
  406. }
  407. // If we couldn't create the fragment in any map, create a new map where we know it will fit.
  408. bool allow_another_map = (m_num_maps_limit == 0 || m_fragment_maps.GetNumItems() < m_num_maps_limit);
  409. if (!frag && allow_another_map && m_fragment_maps.GrowIfNeeded())
  410. {
  411. int po2w = TBGetNearestPowerOfTwo(MAX(data_w, m_default_map_w));
  412. int po2h = TBGetNearestPowerOfTwo(MAX(data_h, m_default_map_h));
  413. if (dedicated_map)
  414. {
  415. po2w = TBGetNearestPowerOfTwo(data_w);
  416. po2h = TBGetNearestPowerOfTwo(data_h);
  417. }
  418. TBBitmapFragmentMap *fm = new TBBitmapFragmentMap();
  419. if (fm && fm->Init(po2w, po2h))
  420. {
  421. m_fragment_maps.Add(fm);
  422. frag = fm->CreateNewFragment(data_w, data_h, data_stride, data, m_add_border);
  423. }
  424. else
  425. delete fm;
  426. }
  427. // Finally, add the new fragment to the hash.
  428. if (frag && m_fragments.Add(id, frag))
  429. {
  430. frag->m_id = id;
  431. return frag;
  432. }
  433. delete frag;
  434. return nullptr;
  435. }
  436. void TBBitmapFragmentManager::FreeFragment(TBBitmapFragment *frag)
  437. {
  438. if (frag)
  439. {
  440. g_renderer->FlushBitmapFragment(frag);
  441. TBBitmapFragmentMap *map = frag->m_map;
  442. frag->m_map->FreeFragmentSpace(frag);
  443. m_fragments.Delete(frag->m_id);
  444. // If the map is now empty, delete it.
  445. if (map->m_allocated_pixels == 0)
  446. m_fragment_maps.Delete(m_fragment_maps.Find(map));
  447. }
  448. }
  449. TBBitmapFragment *TBBitmapFragmentManager::GetFragment(const TBID &id) const
  450. {
  451. return m_fragments.Get(id);
  452. }
  453. void TBBitmapFragmentManager::Clear()
  454. {
  455. m_fragment_maps.DeleteAll();
  456. m_fragments.DeleteAll();
  457. }
  458. bool TBBitmapFragmentManager::ValidateBitmaps()
  459. {
  460. bool success = true;
  461. for (int i = 0; i < m_fragment_maps.GetNumItems(); i++)
  462. if (!m_fragment_maps[i]->ValidateBitmap())
  463. success = false;
  464. return success;
  465. }
  466. void TBBitmapFragmentManager::DeleteBitmaps()
  467. {
  468. for (int i = 0; i < m_fragment_maps.GetNumItems(); i++)
  469. m_fragment_maps[i]->DeleteBitmap();
  470. }
  471. void TBBitmapFragmentManager::SetNumMapsLimit(int num_maps_limit)
  472. {
  473. m_num_maps_limit = num_maps_limit;
  474. }
  475. void TBBitmapFragmentManager::SetDefaultMapSize(int w, int h)
  476. {
  477. assert(TBGetNearestPowerOfTwo(w) == w);
  478. assert(TBGetNearestPowerOfTwo(h) == h);
  479. m_default_map_w = w;
  480. m_default_map_h = h;
  481. }
  482. int TBBitmapFragmentManager::GetUseRatio() const
  483. {
  484. int used = 0;
  485. int total = 0;
  486. for (int i = 0; i < m_fragment_maps.GetNumItems(); i++)
  487. {
  488. used += m_fragment_maps[i]->m_allocated_pixels;
  489. total += m_fragment_maps[i]->m_bitmap_w * m_fragment_maps[i]->m_bitmap_h;
  490. }
  491. return total ? (used * 100) / total : 0;
  492. }
  493. #ifdef TB_RUNTIME_DEBUG_INFO
  494. void TBBitmapFragmentManager::Debug()
  495. {
  496. int x = 0;
  497. for (int i = 0; i < m_fragment_maps.GetNumItems(); i++)
  498. {
  499. TBBitmapFragmentMap *fm = m_fragment_maps[i];
  500. if (TBBitmap *bitmap = fm->GetBitmap())
  501. g_renderer->DrawBitmap(TBRect(x, 0, fm->m_bitmap_w, fm->m_bitmap_h), TBRect(0, 0, fm->m_bitmap_w, fm->m_bitmap_h), bitmap);
  502. x += fm->m_bitmap_w + 5;
  503. }
  504. }
  505. #endif // TB_RUNTIME_DEBUG_INFO
  506. }; // namespace tb