2
0

ImageViewerMain.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/AnKi.h>
  6. using namespace anki;
  7. class TextureViewerUiNode : public SceneNode
  8. {
  9. public:
  10. ImageResourcePtr m_imageResource;
  11. TextureViewerUiNode(CString name)
  12. : SceneNode(name)
  13. {
  14. UiComponent* uic = newComponent<UiComponent>();
  15. uic->init(
  16. [](CanvasPtr& canvas, void* ud) {
  17. static_cast<TextureViewerUiNode*>(ud)->draw(canvas);
  18. },
  19. this);
  20. ANKI_CHECK_AND_IGNORE(UiManager::getSingleton().newInstance(m_font, "EngineAssets/UbuntuMonoRegular.ttf", Array<U32, 1>{16}));
  21. ANKI_CHECK_AND_IGNORE(ResourceManager::getSingleton().loadResource("ShaderBinaries/UiVisualizeImage.ankiprogbin", m_imageProgram));
  22. }
  23. void frameUpdate([[maybe_unused]] Second prevUpdateTime, [[maybe_unused]] Second crntTime) override
  24. {
  25. if(!m_imageIdExtra.m_textureView.isValid())
  26. {
  27. m_imageIdExtra.m_textureView = TextureView(&m_imageResource->getTexture(), TextureSubresourceDesc::all());
  28. }
  29. }
  30. private:
  31. FontPtr m_font;
  32. ShaderProgramResourcePtr m_imageProgram;
  33. ShaderProgramPtr m_imageGrProgram;
  34. UiImageIdData m_imageIdExtra;
  35. U32 m_crntMip = 0;
  36. F32 m_zoom = 1.0f;
  37. F32 m_depth = 0.0f;
  38. Bool m_pointSampling = true;
  39. Array<Bool, 4> m_colorChannel = {true, true, true, true};
  40. F32 m_maxColorValue = 1.0f;
  41. void draw(CanvasPtr& canvas)
  42. {
  43. const Texture& grTex = m_imageResource->getTexture();
  44. const U32 colorComponentCount = getFormatInfo(grTex.getFormat()).m_componentCount;
  45. ANKI_ASSERT(grTex.getTextureType() == TextureType::k2D || grTex.getTextureType() == TextureType::k3D);
  46. if(!m_imageGrProgram.isCreated())
  47. {
  48. ShaderProgramResourceVariantInitInfo variantInit(m_imageProgram);
  49. variantInit.addMutation("TEXTURE_TYPE", (grTex.getTextureType() == TextureType::k2D) ? 0 : 1);
  50. const ShaderProgramResourceVariant* variant;
  51. m_imageProgram->getOrCreateVariant(variantInit, variant);
  52. m_imageGrProgram.reset(&variant->getProgram());
  53. }
  54. ImGui::Begin("Console", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove);
  55. canvas->pushFont(m_font, 16);
  56. ImGui::SetWindowPos(Vec2(0.0f, 0.0f));
  57. ImGui::SetWindowSize(Vec2(F32(canvas->getWidth()), F32(canvas->getHeight())));
  58. ImGui::BeginChild("Tools", Vec2(-1.0f, 30.0f), false, ImGuiWindowFlags_AlwaysAutoResize);
  59. // Zoom
  60. if(ImGui::Button("-"))
  61. {
  62. m_zoom -= 0.1f;
  63. }
  64. ImGui::SameLine();
  65. ImGui::DragFloat("##Zoom", &m_zoom, 0.01f, 0.1f, 20.0f, "Zoom %.3f");
  66. ImGui::SameLine();
  67. if(ImGui::Button("+"))
  68. {
  69. m_zoom += 0.1f;
  70. }
  71. ImGui::SameLine();
  72. ImGui::Spacing();
  73. ImGui::SameLine();
  74. // Sampling
  75. ImGui::Checkbox("Point sampling", &m_pointSampling);
  76. ImGui::SameLine();
  77. ImGui::Spacing();
  78. ImGui::SameLine();
  79. // Colors
  80. ImGui::Checkbox("Red", &m_colorChannel[0]);
  81. ImGui::SameLine();
  82. ImGui::Checkbox("Green", &m_colorChannel[1]);
  83. ImGui::SameLine();
  84. ImGui::Checkbox("Blue", &m_colorChannel[2]);
  85. ImGui::SameLine();
  86. if(colorComponentCount == 4)
  87. {
  88. ImGui::Checkbox("Alpha", &m_colorChannel[3]);
  89. ImGui::SameLine();
  90. }
  91. ImGui::Spacing();
  92. ImGui::SameLine();
  93. // Mips combo
  94. {
  95. UiStringList mipLabels;
  96. for(U32 mip = 0; mip < grTex.getMipmapCount(); ++mip)
  97. {
  98. mipLabels.pushBackSprintf("Mip %u (%u x %u)", mip, grTex.getWidth() >> mip, grTex.getHeight() >> mip);
  99. }
  100. const U32 lastCrntMip = m_crntMip;
  101. if(ImGui::BeginCombo("##Mipmap", (mipLabels.getBegin() + m_crntMip)->cstr(), ImGuiComboFlags_HeightLarge))
  102. {
  103. for(U32 mip = 0; mip < grTex.getMipmapCount(); ++mip)
  104. {
  105. const Bool isSelected = (m_crntMip == mip);
  106. if(ImGui::Selectable((mipLabels.getBegin() + mip)->cstr(), isSelected))
  107. {
  108. m_crntMip = mip;
  109. }
  110. if(isSelected)
  111. {
  112. ImGui::SetItemDefaultFocus();
  113. }
  114. }
  115. ImGui::EndCombo();
  116. }
  117. if(lastCrntMip != m_crntMip)
  118. {
  119. // Re-create the image view
  120. m_imageIdExtra.m_textureView = TextureView(&m_imageResource->getTexture(), TextureSubresourceDesc::surface(m_crntMip, 0, 0));
  121. }
  122. ImGui::SameLine();
  123. }
  124. // Depth
  125. if(grTex.getTextureType() == TextureType::k3D)
  126. {
  127. UiStringList labels;
  128. for(U32 d = 0; d < grTex.getDepth(); ++d)
  129. {
  130. labels.pushBackSprintf("Depth %u", d);
  131. }
  132. if(ImGui::BeginCombo("##Depth", (labels.getBegin() + U32(m_depth))->cstr(), ImGuiComboFlags_HeightLarge))
  133. {
  134. for(U32 d = 0; d < grTex.getDepth(); ++d)
  135. {
  136. const Bool isSelected = (m_depth == F32(d));
  137. if(ImGui::Selectable((labels.getBegin() + d)->cstr(), isSelected))
  138. {
  139. m_depth = F32(d);
  140. }
  141. if(isSelected)
  142. {
  143. ImGui::SetItemDefaultFocus();
  144. }
  145. }
  146. ImGui::EndCombo();
  147. }
  148. ImGui::SameLine();
  149. }
  150. // Max color slider
  151. ImGui::SliderFloat("##Max color", &m_maxColorValue, 0.0f, 5.0f, "Max color = %.3f");
  152. ImGui::SameLine();
  153. // Next
  154. ImGui::EndChild();
  155. ImGui::BeginChild("Image", Vec2(-1.0f, -1.0f), false, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_HorizontalScrollbar);
  156. // Image
  157. {
  158. // Center image
  159. const Vec2 imageSize = Vec2(F32(grTex.getWidth()), F32(grTex.getHeight())) * m_zoom;
  160. class ExtraPushConstants
  161. {
  162. public:
  163. Vec4 m_colorScale;
  164. Vec4 m_depth;
  165. } pc;
  166. pc.m_colorScale.x() = F32(m_colorChannel[0]) / m_maxColorValue;
  167. pc.m_colorScale.y() = F32(m_colorChannel[1]) / m_maxColorValue;
  168. pc.m_colorScale.z() = F32(m_colorChannel[2]) / m_maxColorValue;
  169. pc.m_colorScale.w() = F32(m_colorChannel[3]);
  170. pc.m_depth = Vec4((m_depth + 0.5f) / F32(grTex.getDepth()));
  171. m_imageIdExtra.m_customProgram = m_imageGrProgram;
  172. m_imageIdExtra.m_extraFastConstantsSize = U8(sizeof(pc));
  173. m_imageIdExtra.setExtraFastConstants(&pc, sizeof(pc));
  174. m_imageIdExtra.m_pointSampling = m_pointSampling;
  175. ImGui::Image(UiImageId(&m_imageIdExtra), imageSize, Vec2(0.0f, 1.0f), Vec2(1.0f, 0.0f), Vec4(1.0f), Vec4(0.0f, 0.0f, 0.0f, 1.0f));
  176. if(ImGui::IsItemHovered())
  177. {
  178. if(ImGui::GetIO().KeyCtrl)
  179. {
  180. // Zoom
  181. const F32 zoomSpeed = 0.05f;
  182. if(ImGui::GetIO().MouseWheel > 0.0f)
  183. {
  184. m_zoom *= 1.0f + zoomSpeed;
  185. }
  186. else if(ImGui::GetIO().MouseWheel < 0.0f)
  187. {
  188. m_zoom *= 1.0f - zoomSpeed;
  189. }
  190. // Pan
  191. if(ImGui::GetIO().MouseDown[0])
  192. {
  193. const Vec2 velocity = toAnki(ImGui::GetIO().MouseDelta);
  194. if(velocity.x() != 0.0f)
  195. {
  196. ImGui::SetScrollX(ImGui::GetScrollX() - velocity.x());
  197. }
  198. if(velocity.y() != 0.0f)
  199. {
  200. ImGui::SetScrollY(ImGui::GetScrollY() - velocity.y());
  201. }
  202. }
  203. }
  204. }
  205. }
  206. ImGui::EndChild();
  207. canvas->popFont();
  208. ImGui::End();
  209. }
  210. };
  211. class MyApp : public App
  212. {
  213. public:
  214. MyApp(AllocAlignedCallback allocCb, void* allocCbUserData)
  215. : App(allocCb, allocCbUserData)
  216. {
  217. }
  218. Error init(int argc, char** argv, [[maybe_unused]] CString appName)
  219. {
  220. if(argc < 2)
  221. {
  222. ANKI_LOGE("Wrong number of arguments");
  223. return Error::kUserData;
  224. }
  225. g_windowFullscreenCVar = 0;
  226. g_dataPathsCVar = ANKI_SOURCE_DIRECTORY;
  227. ANKI_CHECK(CVarSet::getSingleton().setFromCommandLineArguments(argc - 2, argv + 2));
  228. ANKI_CHECK(App::init());
  229. // Load the texture
  230. ImageResourcePtr image;
  231. ANKI_CHECK(ResourceManager::getSingleton().loadResource(argv[1], image, false));
  232. // Change window name
  233. String title;
  234. title.sprintf("%s %u x %u Mips %u Format %s", argv[1], image->getWidth(), image->getHeight(), image->getTexture().getMipmapCount(),
  235. getFormatInfo(image->getTexture().getFormat()).m_name);
  236. NativeWindow::getSingleton().setWindowTitle(title);
  237. // Create the node
  238. TextureViewerUiNode* node = SceneGraph::getSingleton().newSceneNode<TextureViewerUiNode>("TextureViewer");
  239. node->m_imageResource = std::move(image);
  240. return Error::kNone;
  241. }
  242. Error userMainLoop(Bool& quit, [[maybe_unused]] Second elapsedTime) override
  243. {
  244. Input& input = Input::getSingleton();
  245. if(input.getKey(KeyCode::kEscape))
  246. {
  247. quit = true;
  248. }
  249. return Error::kNone;
  250. }
  251. };
  252. ANKI_MAIN_FUNCTION(myMain)
  253. int myMain(int argc, char* argv[])
  254. {
  255. Error err = Error::kNone;
  256. MyApp* app = new MyApp(allocAligned, nullptr);
  257. err = app->init(argc, argv, "Texture Viewer");
  258. if(!err)
  259. {
  260. err = app->mainLoop();
  261. }
  262. delete app;
  263. if(err)
  264. {
  265. ANKI_LOGE("Error reported. Bye!!");
  266. }
  267. else
  268. {
  269. ANKI_LOGI("Bye!!");
  270. }
  271. return 0;
  272. }