pixelformats.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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. const int TEXTURE_SIZE = 256;
  13. const int HALF_TEXTURE_SIZE = TEXTURE_SIZE / 2;
  14. const int NUM_FORMATS = bgfx::TextureFormat::UnknownDepth - bgfx::TextureFormat::Unknown - 1;
  15. const int NUM_FORMATS_IN_ROW = (int)bx::ceil(bx::sqrt(NUM_FORMATS));
  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_U_CLAMP
  48. | BGFX_SAMPLER_V_CLAMP
  49. | BGFX_SAMPLER_MIN_POINT
  50. | BGFX_SAMPLER_MAG_POINT
  51. ;
  52. float* rgbaf32Pixels = (float*)BX_ALLOC(entry::getAllocator(), TEXTURE_SIZE * TEXTURE_SIZE * 4 * sizeof(float));
  53. int x, y;
  54. for (y = 0 ; y < TEXTURE_SIZE; ++y)
  55. {
  56. for (x = 0; x < TEXTURE_SIZE; ++x)
  57. {
  58. float relX = (x - HALF_TEXTURE_SIZE) / (float) HALF_TEXTURE_SIZE;
  59. float relY = (y - HALF_TEXTURE_SIZE) / (float) HALF_TEXTURE_SIZE;
  60. float distance = bx::min(1.0f, bx::sqrt(relX * relX + relY * relY));
  61. float angle = bx::atan2(relY, relX);
  62. float* pixel = &rgbaf32Pixels[(x + y * TEXTURE_SIZE) * 4];
  63. float hsv[3] = {angle / (2.0f * bx::kPi), 1.0f, 1.0f - distance};
  64. bx::hsvToRgb(pixel, hsv);
  65. pixel[3] = 1.0f - distance;
  66. }
  67. }
  68. for (y = 0; y < 16; ++y)
  69. {
  70. for (x = 0; x < 16; ++x)
  71. {
  72. float* r = &rgbaf32Pixels[(x + (TEXTURE_SIZE - 36 + y) * TEXTURE_SIZE) * 4];
  73. r[0] = 1.0f;
  74. r[1] = 0.0f;
  75. r[2] = 0.0f;
  76. r[3] = 1.0f;
  77. float* g = &rgbaf32Pixels[(x + 16 + (TEXTURE_SIZE - 36 + y) * TEXTURE_SIZE) * 4];
  78. g[0] = 0.0f;
  79. g[1] = 1.0f;
  80. g[2] = 0.0f;
  81. g[3] = 1.0f;
  82. float* b = &rgbaf32Pixels[(x + 32 + (TEXTURE_SIZE - 36 + y) * TEXTURE_SIZE) * 4];
  83. b[0] = 0.0f;
  84. b[1] = 0.0f;
  85. b[2] = 1.0f;
  86. b[3] = 1.0f;
  87. }
  88. }
  89. for (y = 0; y < 16; ++y)
  90. {
  91. for (x = 0; x < 48; ++x)
  92. {
  93. float* a = &rgbaf32Pixels[(x + (TEXTURE_SIZE - 20 + y) * TEXTURE_SIZE) * 4];
  94. a[0] = 1.0f;
  95. a[1] = 1.0f;
  96. a[2] = 1.0f;
  97. a[3] = 1.0f - (float)x / 48.0f;
  98. }
  99. }
  100. bimg::TextureInfo info;
  101. for (int i = 0; i < NUM_FORMATS; ++i)
  102. {
  103. int format = (int)bgfx::TextureFormat::Unknown + 1 + i;
  104. const char* formatName = bimg::getName(bimg::TextureFormat::Enum(format));
  105. int32_t formatNameLen = bx::strLen(formatName);
  106. if (!bimg::imageConvert(bimg::TextureFormat::Enum(format), bimg::TextureFormat::RGBA32F)
  107. || formatName[formatNameLen - 1] == 'I'
  108. || formatName[formatNameLen - 1] == 'U'
  109. )
  110. {
  111. m_textures[i] = BGFX_INVALID_HANDLE;
  112. continue;
  113. }
  114. bimg::imageGetSize(&info, TEXTURE_SIZE, TEXTURE_SIZE, 1, false, false, 1, bimg::TextureFormat::Enum(format));
  115. const bgfx::Memory* mem = bgfx::alloc(info.storageSize);
  116. bimg::imageConvert(entry::getAllocator(), mem->data, info.format, rgbaf32Pixels, bimg::TextureFormat::RGBA32F, TEXTURE_SIZE, TEXTURE_SIZE, 1);
  117. m_textures[i] = bgfx::createTexture2D(info.width, info.height, info.numMips > 1, info.numLayers, bgfx::TextureFormat::Enum(info.format), flags, mem);
  118. bgfx::setName(m_textures[i], formatName);
  119. bgfx::setViewName(bgfx::ViewId(i + 1), formatName);
  120. }
  121. const bgfx::Memory* checkerboardImageMemory = bgfx::alloc(TEXTURE_SIZE * TEXTURE_SIZE * 4);
  122. bimg::imageCheckerboard(checkerboardImageMemory->data, TEXTURE_SIZE, TEXTURE_SIZE, 16, 0xFF909090, 0xFF707070);
  123. m_checkerboard = bgfx::createTexture2D(TEXTURE_SIZE, TEXTURE_SIZE, false, 1, bgfx::TextureFormat::RGBA8, flags, checkerboardImageMemory);
  124. BX_FREE(entry::getAllocator(), rgbaf32Pixels);
  125. imguiCreate();
  126. }
  127. int shutdown() override
  128. {
  129. imguiDestroy();
  130. for (auto texture: m_textures)
  131. {
  132. if (bgfx::isValid(texture))
  133. bgfx::destroy(texture);
  134. }
  135. if (bgfx::isValid(m_checkerboard))
  136. bgfx::destroy(m_checkerboard);
  137. // Shutdown bgfx.
  138. bgfx::shutdown();
  139. return 0;
  140. }
  141. void imguiTextBoxUnformatted(const ImVec2& size, const char* text) const
  142. {
  143. ImVec2 textSize = ImGui::CalcTextSize(text);
  144. ImVec2 textOffset = ImVec2(
  145. size.x >= 0.0f ? bx::max((size.x - textSize.x) / 2, 0.0f) : 0.0f,
  146. size.y >= 0.0f ? bx::max((size.y - textSize.y) / 2, 0.0f) : 0.0f
  147. );
  148. ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPosX() + textOffset.x, ImGui::GetCursorPosY() + textOffset.y));
  149. ImGui::TextUnformatted(text);
  150. };
  151. void imguiTexturePreview(const ImVec2& size, bgfx::TextureHandle texture, const ImVec2& previewSizeHint = ImVec2(-1.0f, -1.0f)) const
  152. {
  153. ImVec2 origin = ImGui::GetCursorScreenPos();
  154. ImVec2 previewSize = ImVec2(
  155. previewSizeHint.x >= 0.0f ? previewSizeHint.x : size.x,
  156. previewSizeHint.y >= 0.0f ? previewSizeHint.y : size.y
  157. );
  158. ImVec2 previewPos = ImVec2(
  159. origin.x + bx::max(0.0f, (size.x - previewSize.x) / 2),
  160. origin.y + bx::max(0.0f, (size.y - previewSize.y) / 2)
  161. );
  162. if (bgfx::isValid(texture))
  163. {
  164. if (bgfx::isValid(m_checkerboard))
  165. {
  166. ImGui::SetCursorScreenPos(previewPos);
  167. ImGui::Image(m_checkerboard, previewSize);
  168. }
  169. ImGui::SetCursorScreenPos(previewPos);
  170. ImGui::Image(texture, previewSize);
  171. }
  172. else
  173. {
  174. ImU32 color = ImGui::GetColorU32(ImGuiCol_TextDisabled, 0.25f);
  175. ImDrawList* drawList = ImGui::GetWindowDrawList();
  176. ImVec2 p0 = previewPos;
  177. ImVec2 p1 = ImVec2(p0.x + previewSize.x, p0.y + previewSize.y);
  178. drawList->AddRect(p0, p1, color);
  179. drawList->AddLine(p0, p1, color);
  180. // imguiTextBoxUnformatted(size, "INVALID");
  181. }
  182. ImGui::SetCursorScreenPos(origin);
  183. ImGui::Dummy(size);
  184. };
  185. bool update() override
  186. {
  187. if (!entry::processEvents(m_width, m_height, m_debug, m_reset, &m_mouseState) )
  188. {
  189. imguiBeginFrame(m_mouseState.m_mx
  190. , m_mouseState.m_my
  191. , (m_mouseState.m_buttons[entry::MouseButton::Left ] ? IMGUI_MBUT_LEFT : 0)
  192. | (m_mouseState.m_buttons[entry::MouseButton::Right ] ? IMGUI_MBUT_RIGHT : 0)
  193. | (m_mouseState.m_buttons[entry::MouseButton::Middle] ? IMGUI_MBUT_MIDDLE : 0)
  194. , m_mouseState.m_mz
  195. , uint16_t(m_width)
  196. , uint16_t(m_height)
  197. );
  198. showExampleDialog(this);
  199. ImGui::SetNextWindowPos(ImVec2(360.0f, 40.0f), ImGuiCond_FirstUseEver);
  200. ImGui::Begin("Formats", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
  201. float cellWidth = m_previewSize;
  202. for (int i = 0; i < NUM_FORMATS; ++i)
  203. {
  204. int format = (int)bgfx::TextureFormat::Unknown + 1 + i;
  205. ImVec2 textSize = ImGui::CalcTextSize(bimg::getName(bimg::TextureFormat::Enum(format)));
  206. cellWidth = bx::max(cellWidth, textSize.x);
  207. }
  208. ImDrawList* drawList = ImGui::GetWindowDrawList();
  209. ImGui::DragFloat("Preview Size", &m_previewSize, 1.0f, 10.0f, TEXTURE_SIZE);
  210. ImGui::BeginTable("Formats", NUM_FORMATS_IN_ROW, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit);
  211. for (int i = 0; i < NUM_FORMATS; ++i)
  212. {
  213. ImGui::TableNextColumn();
  214. int format = (int)bgfx::TextureFormat::Unknown + 1 + i;
  215. bool isSelected = (m_selectedFormat == format);
  216. ImDrawListSplitter splitter;
  217. splitter.Split(drawList, 2);
  218. splitter.SetCurrentChannel(drawList, 1);
  219. ImGui::BeginGroup();
  220. ImGuiTextBuffer label;
  221. label.append(bimg::getName(bimg::TextureFormat::Enum(format)));
  222. imguiTextBoxUnformatted(ImVec2(cellWidth, 0.0f), label.c_str());
  223. imguiTexturePreview(ImVec2(cellWidth, m_previewSize), m_textures[i], ImVec2(m_previewSize, m_previewSize));
  224. ImGui::EndGroup();
  225. splitter.SetCurrentChannel(drawList, 0);
  226. ImGui::SetCursorScreenPos(ImGui::GetItemRectMin());
  227. ImGui::PushID(i);
  228. if (ImGui::Selectable("##selectable", &isSelected, ImGuiSelectableFlags_AllowItemOverlap, ImGui::GetItemRectSize()))
  229. m_selectedFormat = bimg::TextureFormat::Enum(format);
  230. ImGui::PopID();
  231. splitter.Merge(drawList);
  232. }
  233. ImGui::EndTable();
  234. ImGui::End();
  235. ImGui::SetNextWindowPos(ImVec2(40.0f, 300.0f), ImGuiCond_FirstUseEver);
  236. ImGui::Begin("Selected Format", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
  237. ImGui::Text("Format: %s", bimg::getName(m_selectedFormat));
  238. int selectedTextureIndex = m_selectedFormat - 1 - (int)bimg::TextureFormat::Unknown;
  239. bgfx::TextureHandle selectedTexture = BGFX_INVALID_HANDLE;
  240. if (m_selectedFormat != bimg::TextureFormat::Unknown)
  241. selectedTexture = m_textures[selectedTextureIndex];
  242. imguiTexturePreview(ImVec2(TEXTURE_SIZE, TEXTURE_SIZE), selectedTexture);
  243. ImGui::End();
  244. imguiEndFrame();
  245. // Set view 0 default viewport.
  246. bgfx::setViewRect(0, 0, 0, uint16_t(m_width), uint16_t(m_height) );
  247. // This dummy draw call is here to make sure that view 0 is cleared
  248. // if no other draw calls are submitted to viewZ 0.
  249. bgfx::touch(0);
  250. // Advance to next frame. Rendering thread will be kicked to
  251. // process submitted rendering primitives.
  252. bgfx::frame();
  253. return true;
  254. }
  255. return false;
  256. }
  257. entry::MouseState m_mouseState;
  258. uint32_t m_width;
  259. uint32_t m_height;
  260. uint32_t m_debug;
  261. uint32_t m_reset;
  262. float m_previewSize = 50.0f;
  263. bimg::TextureFormat::Enum m_selectedFormat = bimg::TextureFormat::Unknown;
  264. bgfx::TextureHandle m_checkerboard = BGFX_INVALID_HANDLE;
  265. bgfx::TextureHandle m_textures[NUM_FORMATS];
  266. };
  267. } // namespace
  268. ENTRY_IMPLEMENT_MAIN(
  269. ExamplePixelFormats
  270. , "47-pixelformats"
  271. , "Texture formats."
  272. , "https://bkaradzic.github.io/bgfx/examples.html#pixelformats"
  273. );