ImageViewerMain.cpp 8.1 KB

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