pixelformats.cpp 22 KB

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