pixelformats.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860
  1. /*
  2. * Copyright 2022-2022 Sandy Carter. All rights reserved.
  3. * License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE
  4. */
  5. #include "common.h"
  6. #include "bgfx_utils.h"
  7. #include "imgui/imgui.h"
  8. #include <bx/allocator.h>
  9. #include <bx/math.h>
  10. #include <bimg/decode.h>
  11. #include <tinystl/string.h>
  12. #include <tinystl/vector.h>
  13. namespace stl = tinystl;
  14. namespace
  15. {
  16. constexpr int32_t kCheckerboardSize = 128;
  17. constexpr int32_t kFirstUncompressedFormatIndex = bgfx::TextureFormat::Unknown + 1;
  18. constexpr int32_t kNumCompressedFormats = bgfx::TextureFormat::Unknown;
  19. constexpr int32_t kNumUncompressedFormats = bgfx::TextureFormat::UnknownDepth - kFirstUncompressedFormatIndex;
  20. constexpr int32_t kNumFormats = kNumCompressedFormats + kNumUncompressedFormats;
  21. constexpr int32_t kNumFormatsInRow = 10;
  22. int32_t formatToIndex(bimg::TextureFormat::Enum _format)
  23. {
  24. int32_t index = _format;
  25. if (index >= kFirstUncompressedFormatIndex)
  26. {
  27. --index;
  28. }
  29. return index;
  30. }
  31. bimg::TextureFormat::Enum indexToFormat(int32_t _index)
  32. {
  33. if (_index < kNumCompressedFormats)
  34. {
  35. return bimg::TextureFormat::Enum(_index);
  36. }
  37. if (_index >= kNumCompressedFormats
  38. && _index < kNumFormats)
  39. {
  40. return bimg::TextureFormat::Enum(_index + 1);
  41. }
  42. return bimg::TextureFormat::Unknown;
  43. }
  44. struct TextureStatus
  45. {
  46. enum Enum
  47. {
  48. Ok,
  49. NotInitialized,
  50. FormatNotSupported,
  51. ConversionNotSupported,
  52. FormatIgnored
  53. };
  54. static const char* getDescription(Enum _value)
  55. {
  56. switch (_value)
  57. {
  58. case Ok: return "Ok";
  59. case NotInitialized: return "Texture was not initialized";
  60. case FormatNotSupported: return "Format not supported by GPU/backend";
  61. case ConversionNotSupported: return "Conversion from RGBA8 not supported";
  62. case FormatIgnored: return "Format is ignored by this example";
  63. default:
  64. break;
  65. }
  66. return "Unknown";
  67. }
  68. static bool isError(Enum _value)
  69. {
  70. return false
  71. || _value == FormatNotSupported
  72. || _value == ConversionNotSupported
  73. ;
  74. }
  75. };
  76. struct Texture
  77. {
  78. uint16_t m_width = 0;
  79. uint16_t m_height = 0;
  80. TextureStatus::Enum m_status = TextureStatus::NotInitialized;
  81. bgfx::TextureHandle m_texture = BGFX_INVALID_HANDLE;
  82. };
  83. struct TextureSet
  84. {
  85. stl::string m_name;
  86. uint16_t m_maxWidth = 0;
  87. uint16_t m_maxHeight = 0;
  88. bool m_hasCompressedTextures = false;
  89. Texture m_textures[kNumFormats];
  90. };
  91. static bimg::ImageContainer* generateHueWheelImage()
  92. {
  93. constexpr int32_t kTextureSize = 256;
  94. constexpr int32_t kHalfTextureSize = kTextureSize / 2;
  95. bimg::ImageContainer* image = bimg::imageAlloc(
  96. entry::getAllocator(),
  97. bimg::TextureFormat::RGBA32F,
  98. kTextureSize,
  99. kTextureSize,
  100. 1,
  101. 1,
  102. false,
  103. false,
  104. NULL
  105. );
  106. if (NULL == image)
  107. {
  108. return NULL;
  109. }
  110. float* rgbaf32Pixels = (float*)image->m_data;
  111. for (int32_t yy = 0 ; yy < kTextureSize; ++yy)
  112. {
  113. for (int32_t xx = 0; xx < kTextureSize; ++xx)
  114. {
  115. float relX = (xx - kHalfTextureSize) / (float) kHalfTextureSize;
  116. float relY = (yy - kHalfTextureSize) / (float) kHalfTextureSize;
  117. float distance = bx::min(1.0f, bx::sqrt(relX * relX + relY * relY) );
  118. float angle = bx::atan2(relY, relX);
  119. float* pixel = &rgbaf32Pixels[(xx + yy * kTextureSize) * 4];
  120. float hsv[3] = {angle / (2.0f * bx::kPi), 1.0f, 1.0f - distance};
  121. bx::hsvToRgb(pixel, hsv);
  122. pixel[3] = 1.0f - distance;
  123. }
  124. }
  125. for (int32_t yy = 0; yy < 16; ++yy)
  126. {
  127. for (int32_t xx = 0; xx < 16; ++xx)
  128. {
  129. float* rr = &rgbaf32Pixels[(xx + (kTextureSize - 36 + yy) * kTextureSize) * 4];
  130. rr[0] = 1.0f;
  131. rr[1] = 0.0f;
  132. rr[2] = 0.0f;
  133. rr[3] = 1.0f;
  134. float* gg = &rgbaf32Pixels[(xx + 16 + (kTextureSize - 36 + yy) * kTextureSize) * 4];
  135. gg[0] = 0.0f;
  136. gg[1] = 1.0f;
  137. gg[2] = 0.0f;
  138. gg[3] = 1.0f;
  139. float* bb = &rgbaf32Pixels[(xx + 32 + (kTextureSize - 36 + yy) * kTextureSize) * 4];
  140. bb[0] = 0.0f;
  141. bb[1] = 0.0f;
  142. bb[2] = 1.0f;
  143. bb[3] = 1.0f;
  144. }
  145. }
  146. for (int32_t yy = 0; yy < 16; ++yy)
  147. {
  148. for (int32_t xx = 0; xx < 48; ++xx)
  149. {
  150. float* aa = &rgbaf32Pixels[(xx + (kTextureSize - 20 + yy) * kTextureSize) * 4];
  151. aa[0] = 1.0f;
  152. aa[1] = 1.0f;
  153. aa[2] = 1.0f;
  154. aa[3] = 1.0f - (float)xx / 48.0f;
  155. }
  156. }
  157. return image;
  158. }
  159. static void textureSetPopulateCompressedFormat(TextureSet& textureSet, bimg::ImageContainer* source, bool freeImage = true)
  160. {
  161. if (NULL == source)
  162. {
  163. return;
  164. }
  165. uint32_t textureIndex = indexToFormat(source->m_format);
  166. Texture& texture = textureSet.m_textures[textureIndex];
  167. if (bgfx::isValid(texture.m_texture) || texture.m_status == TextureStatus::FormatNotSupported)
  168. {
  169. if (freeImage)
  170. {
  171. bimg::imageFree(source);
  172. }
  173. return;
  174. }
  175. bimg::ImageMip mip0;
  176. bimg::imageGetRawData(
  177. *source
  178. , 0
  179. , 0
  180. , source->m_data
  181. , source->m_size
  182. , mip0
  183. );
  184. texture.m_width = uint16_t(mip0.m_width);
  185. texture.m_height = uint16_t(mip0.m_height);
  186. texture.m_status = TextureStatus::Ok;
  187. texture.m_texture = bgfx::createTexture2D(
  188. uint16_t(mip0.m_width)
  189. , uint16_t(mip0.m_height)
  190. , false
  191. , 1
  192. , bgfx::TextureFormat::Enum(mip0.m_format)
  193. , BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT
  194. , bgfx::copy(mip0.m_data, mip0.m_size)
  195. );
  196. bgfx::setName(texture.m_texture, bimg::getName(source->m_format) );
  197. if (freeImage)
  198. {
  199. bimg::imageFree(source);
  200. }
  201. textureSet.m_maxWidth = bx::max(textureSet.m_maxWidth, texture.m_width);
  202. textureSet.m_maxHeight = bx::max(textureSet.m_maxHeight, texture.m_height);
  203. }
  204. static void textureSetPopulateUncompressedFormats(TextureSet& textureSet, bimg::ImageContainer* source, bool freeImage = true)
  205. {
  206. if (NULL == source)
  207. {
  208. return;
  209. }
  210. const uint32_t flags = 0
  211. | BGFX_SAMPLER_MIN_POINT
  212. | BGFX_SAMPLER_MAG_POINT
  213. ;
  214. for (int32_t ii = 0; ii < kNumUncompressedFormats; ++ii)
  215. {
  216. int32_t textureIndex = kNumCompressedFormats + ii;
  217. Texture& texture = textureSet.m_textures[textureIndex];
  218. if (bgfx::isValid(texture.m_texture)
  219. || texture.m_status == TextureStatus::FormatNotSupported)
  220. {
  221. continue;
  222. }
  223. bimg::TextureFormat::Enum format = indexToFormat(textureIndex);
  224. const char* formatName = bimg::getName(format);
  225. int32_t formatNameLen = bx::strLen(formatName);
  226. if (!bimg::imageConvert(format, source->m_format) )
  227. {
  228. texture.m_status = TextureStatus::ConversionNotSupported;
  229. continue;
  230. }
  231. if (formatName[formatNameLen - 1] == 'I'
  232. || formatName[formatNameLen - 1] == 'U')
  233. {
  234. texture.m_status = TextureStatus::FormatIgnored;
  235. continue;
  236. }
  237. bimg::TextureInfo info;
  238. bimg::imageGetSize(
  239. &info
  240. , uint16_t(source->m_width)
  241. , uint16_t(source->m_height)
  242. , 1
  243. , false
  244. , false
  245. , 1
  246. , format
  247. );
  248. const bgfx::Memory* mem = bgfx::alloc(info.storageSize);
  249. bimg::imageConvert(
  250. entry::getAllocator()
  251. , mem->data
  252. , info.format
  253. , source->m_data
  254. , source->m_format
  255. , source->m_width
  256. , source->m_height
  257. , 1
  258. );
  259. texture.m_width = info.width;
  260. texture.m_height = info.height;
  261. texture.m_status = TextureStatus::Ok;
  262. texture.m_texture = bgfx::createTexture2D(
  263. info.width
  264. , info.height
  265. , info.numMips > 1
  266. , info.numLayers
  267. , bgfx::TextureFormat::Enum(info.format)
  268. , flags
  269. , mem
  270. );
  271. bgfx::setName(texture.m_texture, formatName);
  272. textureSet.m_maxWidth = bx::max(textureSet.m_maxWidth, texture.m_width);
  273. textureSet.m_maxHeight = bx::max(textureSet.m_maxHeight, texture.m_height);
  274. }
  275. if (freeImage)
  276. {
  277. bimg::imageFree(source);
  278. }
  279. }
  280. static TextureSet makeEmptyTextureSet(const char* name)
  281. {
  282. TextureSet textureSet;
  283. textureSet.m_name = name;
  284. for (int32_t ii = 0; ii < kNumFormats; ++ii)
  285. {
  286. bimg::TextureFormat::Enum format = indexToFormat(ii);
  287. if (!bgfx::isTextureValid(
  288. 1
  289. , false
  290. , 1
  291. , bgfx::TextureFormat::Enum(format)
  292. , BGFX_TEXTURE_NONE
  293. ) )
  294. {
  295. textureSet.m_textures[ii].m_status = TextureStatus::FormatNotSupported;
  296. }
  297. }
  298. return textureSet;
  299. }
  300. static TextureSet generateTextureSetFromImage(const char* name, bimg::ImageContainer* source, bool freeImage = true)
  301. {
  302. TextureSet textureSet = makeEmptyTextureSet(name);
  303. if (NULL == source)
  304. {
  305. return textureSet;
  306. }
  307. textureSetPopulateUncompressedFormats(textureSet, source, freeImage);
  308. return textureSet;
  309. }
  310. static TextureSet generateTextureSetFromFileSet(const char* name, const char* filePaths[])
  311. {
  312. TextureSet textureSet = makeEmptyTextureSet(name);
  313. while (NULL != *filePaths)
  314. {
  315. const char* filePath = *filePaths++;
  316. uint32_t size;
  317. void* data = load(filePath, &size);
  318. if (NULL == data)
  319. {
  320. continue;
  321. }
  322. bimg::ImageContainer* image = bimg::imageParse(entry::getAllocator(), data, size);
  323. if (NULL == image)
  324. {
  325. unload(data);
  326. continue;
  327. }
  328. if (bimg::isCompressed(image->m_format) )
  329. {
  330. textureSet.m_hasCompressedTextures = true;
  331. textureSetPopulateCompressedFormat(textureSet, image);
  332. }
  333. else
  334. {
  335. textureSetPopulateUncompressedFormats(textureSet, image);
  336. }
  337. }
  338. return textureSet;
  339. }
  340. static TextureSet generateTextureSetFromFile(const char* filePath)
  341. {
  342. const char* filePaths[] =
  343. {
  344. filePath,
  345. NULL
  346. };
  347. return generateTextureSetFromFileSet(bx::FilePath(filePath).getFileName().getPtr(), filePaths);
  348. }
  349. class ExamplePixelFormats : public entry::AppI
  350. {
  351. public:
  352. ExamplePixelFormats(const char* _name, const char* _description, const char* _url)
  353. : entry::AppI(_name, _description, _url)
  354. {
  355. }
  356. void init(int32_t _argc, const char* const* _argv, uint32_t _width, uint32_t _height) override
  357. {
  358. Args args(_argc, _argv);
  359. m_width = _width;
  360. m_height = _height;
  361. m_debug = BGFX_DEBUG_TEXT;
  362. m_reset = BGFX_RESET_VSYNC;
  363. bgfx::Init init;
  364. init.type = args.m_type;
  365. init.vendorId = args.m_pciId;
  366. init.platformData.nwh = entry::getNativeWindowHandle(entry::kDefaultWindowHandle);
  367. init.platformData.ndt = entry::getNativeDisplayHandle();
  368. init.platformData.type = entry::getNativeWindowHandleType();
  369. init.resolution.width = m_width;
  370. init.resolution.height = m_height;
  371. init.resolution.reset = m_reset;
  372. bgfx::init(init);
  373. // Enable debug text.
  374. bgfx::setDebug(m_debug);
  375. // Set view 0 clear state.
  376. bgfx::setViewClear(0
  377. , BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH
  378. , 0x303030ff
  379. , 1.0f
  380. , 0
  381. );
  382. const bgfx::Memory* checkerboardImageMemory = bgfx::alloc(kCheckerboardSize * kCheckerboardSize * 4);
  383. bimg::imageCheckerboard(
  384. checkerboardImageMemory->data
  385. , kCheckerboardSize
  386. , kCheckerboardSize
  387. , 16
  388. , 0xFF909090
  389. , 0xFF707070
  390. );
  391. m_checkerboard = bgfx::createTexture2D(
  392. kCheckerboardSize
  393. , kCheckerboardSize
  394. , false
  395. , 1
  396. , bgfx::TextureFormat::RGBA8
  397. , BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT
  398. , checkerboardImageMemory
  399. );
  400. m_textureSets.push_back(generateTextureSetFromImage("Hue Wheel", generateHueWheelImage() ) );
  401. m_textureSets.push_back(generateTextureSetFromFile("textures/pf_alpha_test.dds") );
  402. m_textureSets.push_back(generateTextureSetFromFile("textures/pf_uv_filtering_test.dds") );
  403. const char* textureCompressionSetFiles[] =
  404. {
  405. "textures/texture_compression_astc_4x4.dds",
  406. "textures/texture_compression_astc_5x4.dds",
  407. "textures/texture_compression_astc_5x5.dds",
  408. "textures/texture_compression_astc_6x5.dds",
  409. "textures/texture_compression_astc_6x6.dds",
  410. "textures/texture_compression_astc_8x5.dds",
  411. "textures/texture_compression_astc_8x6.dds",
  412. "textures/texture_compression_astc_8x8.dds",
  413. "textures/texture_compression_astc_10x5.dds",
  414. "textures/texture_compression_astc_10x6.dds",
  415. "textures/texture_compression_astc_10x8.dds",
  416. "textures/texture_compression_astc_10x10.dds",
  417. "textures/texture_compression_astc_12x10.dds",
  418. "textures/texture_compression_astc_12x12.dds",
  419. "textures/texture_compression_atc.dds",
  420. "textures/texture_compression_atce.dds",
  421. "textures/texture_compression_atci.dds",
  422. "textures/texture_compression_bc1.ktx",
  423. "textures/texture_compression_bc2.ktx",
  424. "textures/texture_compression_bc3.ktx",
  425. "textures/texture_compression_bc7.ktx",
  426. "textures/texture_compression_etc1.ktx",
  427. "textures/texture_compression_etc2.ktx",
  428. "textures/texture_compression_ptc12.pvr",
  429. "textures/texture_compression_ptc14.pvr",
  430. "textures/texture_compression_ptc22.pvr",
  431. "textures/texture_compression_ptc24.pvr",
  432. "textures/texture_compression_rgba8.dds",
  433. NULL
  434. };
  435. m_textureSets.push_back(generateTextureSetFromFileSet("texture_compression_* set", textureCompressionSetFiles) );
  436. m_currentTextureSet = &m_textureSets[0];
  437. for (auto& textureSet : m_textureSets)
  438. {
  439. m_largestTextureSize = bx::max(m_largestTextureSize, float(bx::max(textureSet.m_maxWidth, textureSet.m_maxHeight) ) );
  440. }
  441. imguiCreate();
  442. }
  443. int32_t shutdown() override
  444. {
  445. imguiDestroy();
  446. for (auto& textureSet : m_textureSets)
  447. {
  448. for (auto texture : textureSet.m_textures)
  449. {
  450. if (bgfx::isValid(texture.m_texture) )
  451. {
  452. bgfx::destroy(texture.m_texture);
  453. }
  454. }
  455. }
  456. if (bgfx::isValid(m_checkerboard) )
  457. {
  458. bgfx::destroy(m_checkerboard);
  459. }
  460. // Shutdown bgfx.
  461. bgfx::shutdown();
  462. return 0;
  463. }
  464. void imguiTextBoxUnformatted(const ImVec2& size, const char* text) const
  465. {
  466. ImVec2 textSize = ImGui::CalcTextSize(text);
  467. ImVec2 textOffset = ImVec2(
  468. size.x >= 0.0f ? bx::max( (size.x - textSize.x) / 2, 0.0f) : 0.0f
  469. , size.y >= 0.0f ? bx::max( (size.y - textSize.y) / 2, 0.0f) : 0.0f
  470. );
  471. ImGui::SetCursorPos(ImVec2(
  472. ImGui::GetCursorPosX() + textOffset.x
  473. , ImGui::GetCursorPosY() + textOffset.y
  474. ) );
  475. ImGui::TextUnformatted(text);
  476. };
  477. void imguiStrikethroughItem()
  478. {
  479. ImVec2 itemSize = ImGui::GetItemRectSize();
  480. if (itemSize.x <= 0.0f || itemSize.y <= 0.0f)
  481. return;
  482. ImVec2 p0 = ImGui::GetItemRectMin();
  483. ImVec2 p1 = ImGui::GetItemRectMax();
  484. p0.y = p1.y = p0.y + itemSize.y * 0.5f;
  485. ImGui::GetWindowDrawList()->AddLine(p0, p1, ImGui::GetColorU32(ImGuiCol_Text) );
  486. }
  487. void imguiTexturePreview(const ImVec2& size, bgfx::TextureHandle texture, const ImVec2& previewSizeHint = ImVec2(-1.0f, -1.0f) ) const
  488. {
  489. ImVec2 origin = ImGui::GetCursorScreenPos();
  490. ImVec2 previewSize = ImVec2(
  491. previewSizeHint.x >= 0.0f ? previewSizeHint.x : size.x
  492. , previewSizeHint.y >= 0.0f ? previewSizeHint.y : size.y
  493. );
  494. ImVec2 previewPos = ImVec2(
  495. origin.x + bx::max(0.0f, (size.x - previewSize.x) / 2)
  496. , origin.y + bx::max(0.0f, (size.y - previewSize.y) / 2)
  497. );
  498. if (bgfx::isValid(texture) )
  499. {
  500. if (bgfx::isValid(m_checkerboard) )
  501. {
  502. static int64_t timeOffset = bx::getHPCounter();
  503. const float time = float( (bx::getHPCounter()-timeOffset)/double(bx::getHPFrequency() ) );
  504. const float animate = float(m_animate)*0.5f;
  505. const float xx = bx::sin(time * 0.37f) * animate;
  506. const float yy = bx::cos(time * 0.43f) * animate;
  507. const float uTile = bx::max(1.0f, previewSize.x / kCheckerboardSize);
  508. const float vTile = bx::max(1.0f, previewSize.y / kCheckerboardSize);
  509. ImGui::SetCursorScreenPos(previewPos);
  510. ImGui::Image(m_checkerboard, previewSize, ImVec2(xx, yy), ImVec2(xx+uTile, yy+vTile) );
  511. }
  512. ImGui::SetCursorScreenPos(previewPos);
  513. ImGui::Image(texture, m_useAlpha ? IMGUI_FLAGS_ALPHA_BLEND : IMGUI_FLAGS_NONE, 0, previewSize);
  514. }
  515. else
  516. {
  517. ImU32 color = ImGui::GetColorU32(ImGuiCol_Text, 0.25f);
  518. ImDrawList* drawList = ImGui::GetWindowDrawList();
  519. ImVec2 p0 = previewPos;
  520. ImVec2 p1 = ImVec2(p0.x + previewSize.x, p0.y + previewSize.y);
  521. drawList->AddRect(p0, p1, color);
  522. drawList->AddLine(p0, p1, color);
  523. }
  524. ImGui::SetCursorScreenPos(origin);
  525. ImGui::Dummy(size);
  526. };
  527. bool update() override
  528. {
  529. if (!entry::processEvents(m_width, m_height, m_debug, m_reset, &m_mouseState) )
  530. {
  531. imguiBeginFrame(m_mouseState.m_mx
  532. , m_mouseState.m_my
  533. , (m_mouseState.m_buttons[entry::MouseButton::Left ] ? IMGUI_MBUT_LEFT : 0)
  534. | (m_mouseState.m_buttons[entry::MouseButton::Right ] ? IMGUI_MBUT_RIGHT : 0)
  535. | (m_mouseState.m_buttons[entry::MouseButton::Middle] ? IMGUI_MBUT_MIDDLE : 0)
  536. , m_mouseState.m_mz
  537. , uint16_t(m_width)
  538. , uint16_t(m_height)
  539. );
  540. showExampleDialog(this);
  541. ImGui::SetNextWindowPos(ImVec2(340.0f, 10.0f), ImGuiCond_FirstUseEver);
  542. ImGui::Begin("Formats", NULL, ImGuiWindowFlags_None);
  543. ImVec2 previewSize = ImVec2(m_previewSize, m_previewSize);
  544. if (m_currentTextureSet->m_maxWidth > m_currentTextureSet->m_maxHeight)
  545. {
  546. previewSize.y /= float(m_currentTextureSet->m_maxWidth) / m_currentTextureSet->m_maxHeight;
  547. }
  548. else if (m_currentTextureSet->m_maxWidth < m_currentTextureSet->m_maxHeight)
  549. {
  550. previewSize.x *= float(m_currentTextureSet->m_maxWidth) / m_currentTextureSet->m_maxHeight;
  551. }
  552. float cellWidth = previewSize.x;
  553. for (int32_t ii = 0; ii < kNumFormats; ++ii)
  554. {
  555. int32_t format = indexToFormat(ii);
  556. ImVec2 textSize = ImGui::CalcTextSize(bimg::getName(bimg::TextureFormat::Enum(format) ) );
  557. cellWidth = bx::max(cellWidth, textSize.x);
  558. }
  559. ImDrawList* drawList = ImGui::GetWindowDrawList();
  560. if (ImGui::BeginCombo("Sample", m_currentTextureSet ? m_currentTextureSet->m_name.c_str() : NULL) )
  561. {
  562. for (auto& textureSet : m_textureSets)
  563. {
  564. bool isSelected = (&textureSet == m_currentTextureSet);
  565. if (ImGui::Selectable(textureSet.m_name.c_str(), &isSelected) )
  566. {
  567. m_currentTextureSet = &textureSet;
  568. if (!m_currentTextureSet->m_hasCompressedTextures && formatToIndex(m_selectedFormat) < kNumCompressedFormats)
  569. {
  570. m_selectedFormat = bimg::TextureFormat::RGBA8;
  571. }
  572. }
  573. }
  574. ImGui::EndCombo();
  575. }
  576. ImGui::DragFloat("Preview Size", &m_previewSize, 1.0f, 10.0f, m_largestTextureSize, "%.0f px");
  577. ImGui::SameLine();
  578. ImGui::Checkbox("Alpha", &m_useAlpha);
  579. ImGui::SameLine();
  580. ImGui::Checkbox("Animate", &m_animate);
  581. ImGui::BeginTable("Formats", kNumFormatsInRow, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit);
  582. for (int32_t ii = m_currentTextureSet->m_hasCompressedTextures ? 0 : kNumCompressedFormats; ii < kNumFormats; ++ii)
  583. {
  584. ImGui::TableNextColumn();
  585. bimg::TextureFormat::Enum format = indexToFormat(ii);
  586. const Texture& texture = m_currentTextureSet->m_textures[ii];
  587. bool isSelected = (m_selectedFormat == format);
  588. const bool isFormatSupported = texture.m_status == TextureStatus::Ok;
  589. const bool isError = TextureStatus::isError(texture.m_status);
  590. ImU32 labelColor = isError
  591. ? IM_COL32(255, 96, 96, 255)
  592. : ImGui::GetColorU32(isFormatSupported ? ImGuiCol_Text : ImGuiCol_TextDisabled)
  593. ;
  594. ImDrawListSplitter splitter;
  595. splitter.Split(drawList, 2);
  596. splitter.SetCurrentChannel(drawList, 1);
  597. ImGui::BeginGroup();
  598. ImGuiTextBuffer label;
  599. label.append(bimg::getName(bimg::TextureFormat::Enum(format) ) );
  600. ImGui::PushStyleColor(ImGuiCol_Text, labelColor);
  601. imguiTextBoxUnformatted(ImVec2(cellWidth, 0.0f), label.c_str() );
  602. if (TextureStatus::isError(texture.m_status) )
  603. {
  604. imguiStrikethroughItem();
  605. }
  606. imguiTexturePreview(ImVec2(cellWidth, previewSize.y), m_currentTextureSet->m_textures[ii].m_texture, previewSize );
  607. ImGui::PopStyleColor();
  608. ImGui::EndGroup();
  609. if (!isFormatSupported && ImGui::IsItemHovered() )
  610. {
  611. ImGui::SetTooltip("%s", TextureStatus::getDescription(texture.m_status) );
  612. }
  613. splitter.SetCurrentChannel(drawList, 0);
  614. ImGui::SetCursorScreenPos(ImGui::GetItemRectMin() );
  615. ImGui::PushID(ii);
  616. if (ImGui::Selectable(
  617. "##selectable"
  618. , &isSelected
  619. , ImGuiSelectableFlags_AllowOverlap
  620. , ImGui::GetItemRectSize()
  621. ) )
  622. {
  623. m_selectedFormat = format;
  624. }
  625. ImGui::PopID();
  626. splitter.Merge(drawList);
  627. }
  628. ImGui::EndTable();
  629. ImGui::End();
  630. {
  631. int32_t selectedTextureIndex = formatToIndex(m_selectedFormat);
  632. const Texture& texture = m_currentTextureSet->m_textures[selectedTextureIndex];
  633. ImGui::SetNextWindowPos(ImVec2(10.0f, 280.0f), ImGuiCond_FirstUseEver);
  634. ImGui::Begin("Selected Format", NULL, ImGuiWindowFlags_AlwaysAutoResize);
  635. ImGui::Text("Format: %s", bimg::getName(m_selectedFormat) );
  636. ImGui::Text("Status: %s", TextureStatus::getDescription(texture.m_status) );
  637. const bgfx::Caps* caps = bgfx::getCaps();
  638. const uint32_t formatFlags = caps->formats[m_selectedFormat];
  639. {
  640. bool emulated = 0 != (formatFlags & (0
  641. | BGFX_CAPS_FORMAT_TEXTURE_2D_EMULATED
  642. | BGFX_CAPS_FORMAT_TEXTURE_3D_EMULATED
  643. | BGFX_CAPS_FORMAT_TEXTURE_CUBE_EMULATED
  644. ) );
  645. ImGui::BeginDisabled(true);
  646. ImGui::Checkbox("Emu", &emulated);
  647. ImGui::EndDisabled();
  648. if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) )
  649. {
  650. ImGui::SetTooltip("Texture format is%s emulated.", emulated ? "" : " not");
  651. }
  652. ImGui::SameLine();
  653. bool framebuffer = 0 != (formatFlags & BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER);
  654. ImGui::BeginDisabled(true);
  655. ImGui::Checkbox("FB", &framebuffer);
  656. ImGui::EndDisabled();
  657. if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) )
  658. {
  659. ImGui::SetTooltip("Texture format can%s be used as frame buffer.", framebuffer ? "" : "not");
  660. }
  661. ImGui::SameLine();
  662. bool msaa = 0 != (formatFlags & BGFX_CAPS_FORMAT_TEXTURE_MSAA);
  663. ImGui::BeginDisabled(true);
  664. ImGui::Checkbox("MSAA", &msaa);
  665. ImGui::EndDisabled();
  666. if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) )
  667. {
  668. ImGui::SetTooltip("Texture can%s be sampled as MSAA.", msaa ? "" : "not");
  669. }
  670. }
  671. ImVec2 size = ImVec2(float(m_currentTextureSet->m_maxWidth), float(m_currentTextureSet->m_maxHeight) );
  672. ImVec2 selectedPreviewSize = bgfx::isValid(texture.m_texture) ? ImVec2(float(texture.m_width), float(texture.m_height) ) : size;
  673. imguiTexturePreview(size, texture.m_texture, selectedPreviewSize);
  674. ImGui::End();
  675. }
  676. imguiEndFrame();
  677. // Set view 0 default viewport.
  678. bgfx::setViewRect(0, 0, 0, uint16_t(m_width), uint16_t(m_height) );
  679. // This dummy draw call is here to make sure that view 0 is cleared
  680. // if no other draw calls are submitted to viewZ 0.
  681. bgfx::touch(0);
  682. // Advance to next frame. Rendering thread will be kicked to
  683. // process submitted rendering primitives.
  684. bgfx::frame();
  685. return true;
  686. }
  687. return false;
  688. }
  689. entry::MouseState m_mouseState;
  690. uint32_t m_width;
  691. uint32_t m_height;
  692. uint32_t m_debug;
  693. uint32_t m_reset;
  694. float m_largestTextureSize = 256.0f;
  695. float m_previewSize = 75.0f;
  696. bool m_useAlpha = true;
  697. bool m_animate = true;
  698. bimg::TextureFormat::Enum m_selectedFormat = bimg::TextureFormat::RGBA8;
  699. bgfx::TextureHandle m_checkerboard = BGFX_INVALID_HANDLE;
  700. stl::vector<TextureSet> m_textureSets;
  701. TextureSet* m_currentTextureSet = NULL;
  702. };
  703. } // namespace
  704. ENTRY_IMPLEMENT_MAIN(
  705. ExamplePixelFormats
  706. , "47-pixelformats"
  707. , "Texture formats."
  708. , "https://bkaradzic.github.io/bgfx/examples.html#pixelformats"
  709. );