pixelformats.cpp 22 KB

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