2
0

pixelformats.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  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. namespace
  11. {
  12. constexpr int32_t kTextureSize = 256;
  13. constexpr int32_t kHalfTextureSize = kTextureSize / 2;
  14. constexpr int32_t kNumFormats = bgfx::TextureFormat::UnknownDepth - bgfx::TextureFormat::Unknown - 1;
  15. const int32_t kNumFormatsInRow = (int32_t)bx::ceil(bx::sqrt(kNumFormats) );
  16. class ExamplePixelFormats : public entry::AppI
  17. {
  18. public:
  19. ExamplePixelFormats(const char* _name, const char* _description, const char* _url)
  20. : entry::AppI(_name, _description, _url)
  21. {
  22. }
  23. void init(int32_t _argc, const char* const* _argv, uint32_t _width, uint32_t _height) override
  24. {
  25. Args args(_argc, _argv);
  26. m_width = _width;
  27. m_height = _height;
  28. m_debug = BGFX_DEBUG_TEXT;
  29. m_reset = BGFX_RESET_VSYNC;
  30. bgfx::Init init;
  31. init.type = args.m_type;
  32. init.vendorId = args.m_pciId;
  33. init.resolution.width = m_width;
  34. init.resolution.height = m_height;
  35. init.resolution.reset = m_reset;
  36. bgfx::init(init);
  37. // Enable debug text.
  38. bgfx::setDebug(m_debug);
  39. // Set view 0 clear state.
  40. bgfx::setViewClear(0
  41. , BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH
  42. , 0x303030ff
  43. , 1.0f
  44. , 0
  45. );
  46. const uint32_t flags = 0
  47. | BGFX_SAMPLER_MIN_POINT
  48. | BGFX_SAMPLER_MAG_POINT
  49. ;
  50. float* rgbaf32Pixels = (float*)BX_ALLOC(entry::getAllocator(), kTextureSize * kTextureSize * 4 * sizeof(float) );
  51. for (int32_t y = 0 ; y < kTextureSize; ++y)
  52. {
  53. for (int32_t x = 0; x < kTextureSize; ++x)
  54. {
  55. float relX = (x - kHalfTextureSize) / (float) kHalfTextureSize;
  56. float relY = (y - kHalfTextureSize) / (float) kHalfTextureSize;
  57. float distance = bx::min(1.0f, bx::sqrt(relX * relX + relY * relY) );
  58. float angle = bx::atan2(relY, relX);
  59. float* pixel = &rgbaf32Pixels[(x + y * kTextureSize) * 4];
  60. float hsv[3] = {angle / (2.0f * bx::kPi), 1.0f, 1.0f - distance};
  61. bx::hsvToRgb(pixel, hsv);
  62. pixel[3] = 1.0f - distance;
  63. }
  64. }
  65. for (int32_t y = 0; y < 16; ++y)
  66. {
  67. for (int32_t x = 0; x < 16; ++x)
  68. {
  69. float* r = &rgbaf32Pixels[(x + (kTextureSize - 36 + y) * kTextureSize) * 4];
  70. r[0] = 1.0f;
  71. r[1] = 0.0f;
  72. r[2] = 0.0f;
  73. r[3] = 1.0f;
  74. float* g = &rgbaf32Pixels[(x + 16 + (kTextureSize - 36 + y) * kTextureSize) * 4];
  75. g[0] = 0.0f;
  76. g[1] = 1.0f;
  77. g[2] = 0.0f;
  78. g[3] = 1.0f;
  79. float* b = &rgbaf32Pixels[(x + 32 + (kTextureSize - 36 + y) * kTextureSize) * 4];
  80. b[0] = 0.0f;
  81. b[1] = 0.0f;
  82. b[2] = 1.0f;
  83. b[3] = 1.0f;
  84. }
  85. }
  86. for (int32_t y = 0; y < 16; ++y)
  87. {
  88. for (int32_t x = 0; x < 48; ++x)
  89. {
  90. float* a = &rgbaf32Pixels[(x + (kTextureSize - 20 + y) * kTextureSize) * 4];
  91. a[0] = 1.0f;
  92. a[1] = 1.0f;
  93. a[2] = 1.0f;
  94. a[3] = 1.0f - (float)x / 48.0f;
  95. }
  96. }
  97. for (int32_t i = 0; i < kNumFormats; ++i)
  98. {
  99. int32_t format = (int32_t)bgfx::TextureFormat::Unknown + 1 + i;
  100. const char* formatName = bimg::getName(bimg::TextureFormat::Enum(format) );
  101. int32_t formatNameLen = bx::strLen(formatName);
  102. if (!bimg::imageConvert(bimg::TextureFormat::Enum(format), bimg::TextureFormat::RGBA32F)
  103. || formatName[formatNameLen - 1] == 'I'
  104. || formatName[formatNameLen - 1] == 'U'
  105. )
  106. {
  107. m_textures[i] = BGFX_INVALID_HANDLE;
  108. continue;
  109. }
  110. bimg::TextureInfo info;
  111. bimg::imageGetSize(
  112. &info
  113. , kTextureSize
  114. , kTextureSize
  115. , 1
  116. , false
  117. , false
  118. , 1
  119. , bimg::TextureFormat::Enum(format)
  120. );
  121. const bgfx::Memory* mem = bgfx::alloc(info.storageSize);
  122. bimg::imageConvert(
  123. entry::getAllocator()
  124. , mem->data
  125. , info.format
  126. , rgbaf32Pixels
  127. , bimg::TextureFormat::RGBA32F
  128. , kTextureSize
  129. , kTextureSize
  130. , 1
  131. );
  132. m_textures[i] = bgfx::createTexture2D(
  133. info.width
  134. , info.height
  135. , info.numMips > 1
  136. , info.numLayers
  137. , bgfx::TextureFormat::Enum(info.format)
  138. , flags
  139. , mem
  140. );
  141. bgfx::setName(m_textures[i], formatName);
  142. bgfx::setViewName(bgfx::ViewId(i + 1), formatName);
  143. }
  144. const bgfx::Memory* checkerboardImageMemory = bgfx::alloc(kTextureSize * kTextureSize * 4);
  145. bimg::imageCheckerboard(
  146. checkerboardImageMemory->data
  147. , kTextureSize
  148. , kTextureSize
  149. , 16
  150. , 0xFF909090
  151. , 0xFF707070
  152. );
  153. m_checkerboard = bgfx::createTexture2D(
  154. kTextureSize
  155. , kTextureSize
  156. , false
  157. , 1
  158. , bgfx::TextureFormat::RGBA8
  159. , flags
  160. , checkerboardImageMemory
  161. );
  162. BX_FREE(entry::getAllocator(), rgbaf32Pixels);
  163. imguiCreate();
  164. }
  165. int32_t shutdown() override
  166. {
  167. imguiDestroy();
  168. for (auto texture : m_textures)
  169. {
  170. if (bgfx::isValid(texture) )
  171. {
  172. bgfx::destroy(texture);
  173. }
  174. }
  175. if (bgfx::isValid(m_checkerboard) )
  176. {
  177. bgfx::destroy(m_checkerboard);
  178. }
  179. // Shutdown bgfx.
  180. bgfx::shutdown();
  181. return 0;
  182. }
  183. void imguiTextBoxUnformatted(const ImVec2& size, const char* text) const
  184. {
  185. ImVec2 textSize = ImGui::CalcTextSize(text);
  186. ImVec2 textOffset = ImVec2(
  187. size.x >= 0.0f ? bx::max( (size.x - textSize.x) / 2, 0.0f) : 0.0f
  188. , size.y >= 0.0f ? bx::max( (size.y - textSize.y) / 2, 0.0f) : 0.0f
  189. );
  190. ImGui::SetCursorPos(ImVec2(
  191. ImGui::GetCursorPosX() + textOffset.x
  192. , ImGui::GetCursorPosY() + textOffset.y
  193. ) );
  194. ImGui::TextUnformatted(text);
  195. };
  196. void imguiTexturePreview(const ImVec2& size, bgfx::TextureHandle texture, const ImVec2& previewSizeHint = ImVec2(-1.0f, -1.0f) ) const
  197. {
  198. ImVec2 origin = ImGui::GetCursorScreenPos();
  199. ImVec2 previewSize = ImVec2(
  200. previewSizeHint.x >= 0.0f ? previewSizeHint.x : size.x
  201. , previewSizeHint.y >= 0.0f ? previewSizeHint.y : size.y
  202. );
  203. ImVec2 previewPos = ImVec2(
  204. origin.x + bx::max(0.0f, (size.x - previewSize.x) / 2)
  205. , origin.y + bx::max(0.0f, (size.y - previewSize.y) / 2)
  206. );
  207. if (bgfx::isValid(texture) )
  208. {
  209. if (bgfx::isValid(m_checkerboard) )
  210. {
  211. static int64_t timeOffset = bx::getHPCounter();
  212. const float time = float( (bx::getHPCounter()-timeOffset)/double(bx::getHPFrequency() ) );
  213. const float xx = bx::sin(time * 0.17f);
  214. const float yy = bx::cos(time * 0.13f);
  215. ImGui::SetCursorScreenPos(previewPos);
  216. ImGui::Image(m_checkerboard, previewSize, ImVec2(xx, yy), ImVec2(xx+1.0f, yy+1.0f) );
  217. }
  218. ImGui::SetCursorScreenPos(previewPos);
  219. ImGui::Image(texture, m_useAlpha ? IMGUI_FLAGS_ALPHA_BLEND : IMGUI_FLAGS_NONE, 0, previewSize);
  220. }
  221. else
  222. {
  223. ImU32 color = ImGui::GetColorU32(ImGuiCol_TextDisabled, 0.25f);
  224. ImDrawList* drawList = ImGui::GetWindowDrawList();
  225. ImVec2 p0 = previewPos;
  226. ImVec2 p1 = ImVec2(p0.x + previewSize.x, p0.y + previewSize.y);
  227. drawList->AddRect(p0, p1, color);
  228. drawList->AddLine(p0, p1, color);
  229. }
  230. ImGui::SetCursorScreenPos(origin);
  231. ImGui::Dummy(size);
  232. };
  233. bool update() override
  234. {
  235. if (!entry::processEvents(m_width, m_height, m_debug, m_reset, &m_mouseState) )
  236. {
  237. imguiBeginFrame(m_mouseState.m_mx
  238. , m_mouseState.m_my
  239. , (m_mouseState.m_buttons[entry::MouseButton::Left ] ? IMGUI_MBUT_LEFT : 0)
  240. | (m_mouseState.m_buttons[entry::MouseButton::Right ] ? IMGUI_MBUT_RIGHT : 0)
  241. | (m_mouseState.m_buttons[entry::MouseButton::Middle] ? IMGUI_MBUT_MIDDLE : 0)
  242. , m_mouseState.m_mz
  243. , uint16_t(m_width)
  244. , uint16_t(m_height)
  245. );
  246. showExampleDialog(this);
  247. ImGui::SetNextWindowPos(ImVec2(360.0f, 40.0f), ImGuiCond_FirstUseEver);
  248. ImGui::Begin("Formats", NULL, ImGuiWindowFlags_AlwaysAutoResize);
  249. float cellWidth = m_previewSize;
  250. for (int32_t i = 0; i < kNumFormats; ++i)
  251. {
  252. int32_t format = (int32_t)bgfx::TextureFormat::Unknown + 1 + i;
  253. ImVec2 textSize = ImGui::CalcTextSize(bimg::getName(bimg::TextureFormat::Enum(format) ) );
  254. cellWidth = bx::max(cellWidth, textSize.x);
  255. }
  256. ImDrawList* drawList = ImGui::GetWindowDrawList();
  257. ImGui::DragFloat("Preview Size", &m_previewSize, 1.0f, 10.0f, kTextureSize);
  258. ImGui::SameLine();
  259. ImGui::Checkbox("Alpha", &m_useAlpha);
  260. ImGui::BeginTable("Formats", kNumFormatsInRow, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit);
  261. for (int32_t i = 0; i < kNumFormats; ++i)
  262. {
  263. ImGui::TableNextColumn();
  264. int32_t format = (int32_t)bgfx::TextureFormat::Unknown + 1 + i;
  265. bool isSelected = (m_selectedFormat == format);
  266. ImDrawListSplitter splitter;
  267. splitter.Split(drawList, 2);
  268. splitter.SetCurrentChannel(drawList, 1);
  269. ImGui::BeginGroup();
  270. ImGuiTextBuffer label;
  271. label.append(bimg::getName(bimg::TextureFormat::Enum(format) ) );
  272. imguiTextBoxUnformatted(ImVec2(cellWidth, 0.0f), label.c_str() );
  273. imguiTexturePreview(ImVec2(cellWidth, m_previewSize), m_textures[i], ImVec2(m_previewSize, m_previewSize) );
  274. ImGui::EndGroup();
  275. splitter.SetCurrentChannel(drawList, 0);
  276. ImGui::SetCursorScreenPos(ImGui::GetItemRectMin() );
  277. ImGui::PushID(i);
  278. if (ImGui::Selectable(
  279. "##selectable"
  280. , &isSelected
  281. , ImGuiSelectableFlags_AllowItemOverlap
  282. , ImGui::GetItemRectSize()
  283. ) )
  284. {
  285. m_selectedFormat = bimg::TextureFormat::Enum(format);
  286. }
  287. ImGui::PopID();
  288. splitter.Merge(drawList);
  289. }
  290. ImGui::EndTable();
  291. ImGui::End();
  292. {
  293. ImGui::SetNextWindowPos(ImVec2(40.0f, 300.0f), ImGuiCond_FirstUseEver);
  294. ImGui::Begin("Selected Format", NULL, ImGuiWindowFlags_AlwaysAutoResize);
  295. ImGui::Text("Format: %s", bimg::getName(m_selectedFormat) );
  296. const bgfx::Caps* caps = bgfx::getCaps();
  297. if (caps->formats[m_selectedFormat] == BGFX_CAPS_FORMAT_TEXTURE_NONE)
  298. {
  299. ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 10.0f));
  300. ImGui::Text("Not supported!");
  301. ImGui::PopStyleVar();
  302. }
  303. else
  304. {
  305. const uint32_t formatFlags = caps->formats[m_selectedFormat];
  306. bool emulated = 0 != (formatFlags & (0
  307. | BGFX_CAPS_FORMAT_TEXTURE_2D_EMULATED
  308. | BGFX_CAPS_FORMAT_TEXTURE_3D_EMULATED
  309. | BGFX_CAPS_FORMAT_TEXTURE_CUBE_EMULATED
  310. ) );
  311. ImGui::PushEnabled(false);
  312. ImGui::Checkbox("Emu", &emulated);
  313. ImGui::PopEnabled();
  314. if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
  315. {
  316. ImGui::SetTooltip("Texture format is emulated.");
  317. }
  318. ImGui::SameLine();
  319. bool framebuffer = 0 != (formatFlags & BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER);
  320. ImGui::PushEnabled(false);
  321. ImGui::Checkbox("FB", &framebuffer);
  322. ImGui::PopEnabled();
  323. if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
  324. {
  325. ImGui::SetTooltip("Texture format can be used as frame buffer.");
  326. }
  327. ImGui::SameLine();
  328. bool msaa = 0 != (formatFlags & BGFX_CAPS_FORMAT_TEXTURE_MSAA);
  329. ImGui::PushEnabled(false);
  330. ImGui::Checkbox("MSAA", &msaa);
  331. ImGui::PopEnabled();
  332. if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
  333. {
  334. ImGui::SetTooltip("Texture can be sampled as MSAA.");
  335. }
  336. }
  337. int32_t selectedTextureIndex = m_selectedFormat - 1 - (int32_t)bimg::TextureFormat::Unknown;
  338. bgfx::TextureHandle selectedTexture = BGFX_INVALID_HANDLE;
  339. if (m_selectedFormat != bimg::TextureFormat::Unknown)
  340. {
  341. selectedTexture = m_textures[selectedTextureIndex];
  342. }
  343. imguiTexturePreview(ImVec2(kTextureSize, kTextureSize), selectedTexture);
  344. ImGui::End();
  345. }
  346. imguiEndFrame();
  347. // Set view 0 default viewport.
  348. bgfx::setViewRect(0, 0, 0, uint16_t(m_width), uint16_t(m_height) );
  349. // This dummy draw call is here to make sure that view 0 is cleared
  350. // if no other draw calls are submitted to viewZ 0.
  351. bgfx::touch(0);
  352. // Advance to next frame. Rendering thread will be kicked to
  353. // process submitted rendering primitives.
  354. bgfx::frame();
  355. return true;
  356. }
  357. return false;
  358. }
  359. entry::MouseState m_mouseState;
  360. uint32_t m_width;
  361. uint32_t m_height;
  362. uint32_t m_debug;
  363. uint32_t m_reset;
  364. float m_previewSize = 50.0f;
  365. bool m_useAlpha = true;
  366. bimg::TextureFormat::Enum m_selectedFormat = bimg::TextureFormat::RGBA8;
  367. bgfx::TextureHandle m_checkerboard = BGFX_INVALID_HANDLE;
  368. bgfx::TextureHandle m_textures[kNumFormats];
  369. };
  370. } // namespace
  371. ENTRY_IMPLEMENT_MAIN(
  372. ExamplePixelFormats
  373. , "47-pixelformats"
  374. , "Texture formats."
  375. , "https://bkaradzic.github.io/bgfx/examples.html#pixelformats"
  376. );