imgui_tex_inspect.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. // ImGuiTexInspect, a texture inspector widget for dear imgui
  2. #pragma once
  3. #include "imgui.h"
  4. namespace ImGuiTexInspect
  5. {
  6. struct Context;
  7. struct Transform2D;
  8. //-------------------------------------------------------------------------
  9. // [SECTION] INIT & SHUTDOWN
  10. //-------------------------------------------------------------------------
  11. void Init();
  12. void Shutdown();
  13. Context *CreateContext();
  14. void DestroyContext(Context *);
  15. void SetCurrentContext(Context *);
  16. //-------------------------------------------------------------------------
  17. // [SECTION] BASIC USAGE
  18. //-------------------------------------------------------------------------
  19. enum InspectorAlphaMode
  20. {
  21. InspectorAlphaMode_ImGui, // Alpha is transparency so you see the ImGui panel background behind image
  22. InspectorAlphaMode_Black, // Alpha is used to blend over a black background
  23. InspectorAlphaMode_White, // Alpha is used to blend over a white background
  24. InspectorAlphaMode_CustomColor // Alpha is used to blend over a custom colour.
  25. };
  26. typedef ImU64 InspectorFlags;
  27. enum InspectorFlags_
  28. {
  29. InspectorFlags_ShowWrap = 1 << 0, // Draw beyong the [0,1] uv range. What you see will depend on API
  30. InspectorFlags_NoForceFilterNearest = 1 << 1, // Normally we force nearest neighbour sampling when zoomed in. Set to disable this.
  31. InspectorFlags_NoGrid = 1 << 2, // By default a grid is shown at high zoom levels
  32. InspectorFlags_NoTooltip = 1 << 3, // Disable tooltip on hover
  33. InspectorFlags_FillHorizontal = 1 << 4, // Scale to fill available space horizontally
  34. InspectorFlags_FillVertical = 1 << 5, // Scale to fill available space vertically
  35. InspectorFlags_NoAutoReadTexture = 1 << 6, // By default texture data is read to CPU every frame for tooltip and annotations
  36. InspectorFlags_FlipX = 1 << 7, // Horizontally flip the way the texture is displayed
  37. InspectorFlags_FlipY = 1 << 8, // Vertically flip the way the texture is displayed
  38. };
  39. /* Use one of these Size structs if you want to specify an exact size for the inspector panel.
  40. * E.g.
  41. * BeginInspectorPanel("MyPanel", texture_1K, ImVec2(1024,1024), 0, SizeExcludingBorder(ImVec2(1024,1024)));
  42. *
  43. * However, most of the time the default size will be fine. E.g.
  44. *
  45. * BeginInspectorPanel("MyPanel", texture_1K, ImVec2(1024,1024));
  46. */
  47. struct SizeIncludingBorder {ImVec2 Size; SizeIncludingBorder(ImVec2 size):Size(size){}};
  48. struct SizeExcludingBorder {ImVec2 size; SizeExcludingBorder(ImVec2 size):size(size){}};
  49. /* BeginInspectorPanel
  50. * Returns true if panel is drawn. Note that flags will only be considered on the first call */
  51. bool BeginInspectorPanel(const char *name, ImTextureID, ImVec2 textureSize, InspectorFlags flags = 0);
  52. bool BeginInspectorPanel(const char *name, ImTextureID, ImVec2 textureSize, InspectorFlags flags, SizeIncludingBorder size);
  53. bool BeginInspectorPanel(const char *name, ImTextureID, ImVec2 textureSize, InspectorFlags flags, SizeExcludingBorder size);
  54. /* EndInspectorPanel
  55. * Always call after BeginInspectorPanel and after you have drawn any required annotations*/
  56. void EndInspectorPanel();
  57. /* ReleaseInspectorData
  58. * ImGuiTexInspect keeps texture data cached in memory. If you know you won't
  59. * be displaying a particular panel for a while you can call this to release
  60. * the memory. It won't be allocated again until next time you call
  61. * BeginInspectorPanel. If id is NULL then the current (most recent) inspector
  62. * will be affected. Unless you have a lot of different Inspector instances
  63. * you can probably not worry about this. Call CurrentInspector_GetID to get
  64. * the ID of an inspector.
  65. */
  66. void ReleaseInspectorData(ImGuiID id);
  67. //-------------------------------------------------------------------------
  68. // [SECTION] CURRENT INSPECTOR MANIPULATORS
  69. //-------------------------------------------------------------------------
  70. /* All the functions starting with CurrentInspector_ can be used after calling
  71. * BeginInspector until the end of the frame. It is not necessary to call them
  72. * before the matching EndInspectorPanel
  73. */
  74. /* CurrentInspector_SetColorMatrix
  75. * colorMatrix and colorOffset describe the transform which happens to the
  76. * color of each texel.
  77. * The calculation is finalColor = colorMatrix * originalColor + colorOffset.
  78. * Where finalColor, originalColor and colorOffset are column vectors with
  79. * components (r,g,b,a) and colorMatrix is a column-major matrix.
  80. */
  81. void CurrentInspector_SetColorMatrix(const float (&colorMatrix)[16], const float (&colorOffset)[4]);
  82. void CurrentInspector_ResetColorMatrix();
  83. /* CurrentInspector_SetAlphaMode - see enum comments for details*/
  84. void CurrentInspector_SetAlphaMode(InspectorAlphaMode);
  85. void CurrentInspector_SetFlags(InspectorFlags toSet, InspectorFlags toClear = 0);
  86. inline void CurrentInspector_ClearFlags(InspectorFlags toClear) {CurrentInspector_SetFlags(0, toClear);}
  87. void CurrentInspector_SetGridColor(ImU32 color);
  88. void CurrentInspector_SetMaxAnnotations(int maxAnnotations);
  89. /* CurrentInspector_InvalidateTextureCache
  90. * If using the InspectorFlags_NoAutoReadTexture flag then call this to
  91. * indicate your texture has changed context.
  92. */
  93. void CurrentInspector_InvalidateTextureCache();
  94. /* CurrentInspector_SetCustomBackgroundColor
  95. * If using InspectorAlphaMode_CustomColor then this is the color that will be
  96. * blended as the background where alpha is less than one.
  97. */
  98. void CurrentInspector_SetCustomBackgroundColor(ImVec4 color);
  99. void CurrentInspector_SetCustomBackgroundColor(ImU32 color);
  100. /* CurrentInspector_GetID
  101. * Get the ID of the current inspector. Currently only used for calling
  102. * ReleaseInspectorData.
  103. */
  104. ImGuiID CurrentInspector_GetID();
  105. /* Some convenience functions for drawing ImGui controls for the current Inspector */
  106. void DrawColorMatrixEditor(); // ColorMatrix editor. See comments on ColorMatrix below.
  107. void DrawGridEditor(); // Grid editor. Enable/Disable grid. Set Grid Color.
  108. void DrawColorChannelSelector(); // For toggling R,G,B channels
  109. void DrawAlphaModeSelector(); // A combo box for selecting the alpha mode
  110. //-------------------------------------------------------------------------
  111. // [SECTION] CONTEXT-WIDE SETTINGS
  112. //-------------------------------------------------------------------------
  113. /* SetZoomRate
  114. * factor should be greater than 1. A value of 1.5 means one mouse wheel
  115. * scroll will increase zoom level by 50%. The factor used for zooming out is
  116. * 1/factor. */
  117. void SetZoomRate(float factor);
  118. //-------------------------------------------------------------------------
  119. // [SECTION] ANNOTATION TOOLS
  120. //-------------------------------------------------------------------------
  121. /* DrawAnnotationLine
  122. * Convenience function to add a line to draw list using texel coordinates.
  123. */
  124. void DrawAnnotationLine(ImDrawList *drawList, ImVec2 fromTexel, ImVec2 toTexel, Transform2D texelsToPixels, ImU32 color);
  125. //-------------------------------------------------------------------------
  126. // [SECTION] Annotation Classes
  127. //-------------------------------------------------------------------------
  128. /* To draw annotations call DrawAnnotions in between BeginInspectorPanel and
  129. * EndInspectorPanel. Example usage:
  130. * DrawAnnotations(ValueText(ValueText::HexString));
  131. *
  132. * To provide your own Annotation drawing class just define a class that
  133. * implements the DrawAnnotation method. See imgui_tex_inspect_demo.cpp
  134. * for an example.
  135. */
  136. template <typename T>
  137. void DrawAnnotations(T drawer, ImU64 maxAnnotatedTexels = 0);
  138. /* ValueText
  139. * An annoation class that draws text inside each texel when zoom level is high enough for it to fit.
  140. * The text shows the value of the texel. E.g. "R:255, G: 128, B:0, A:255"
  141. */
  142. class ValueText
  143. {
  144. protected:
  145. int TextRowCount;
  146. int TextColumnCount;
  147. const char *TextFormatString;
  148. bool FormatAsFloats;
  149. public:
  150. enum Format
  151. {
  152. HexString, // E.g. #EF97B9FF
  153. BytesHex, // E.g. R:#EF G:#97 B:#B9 A:#FF (split over 4 lines)
  154. BytesDec, // E.g. R:239 G: 151 B:185 A:255 (split over 4 lines)
  155. Floats // E.g. 0.937 0.592 0.725 1.000 (split over 4 lines)
  156. };
  157. ValueText(Format format = HexString);
  158. void DrawAnnotation(ImDrawList *drawList, ImVec2 texel, Transform2D texelsToPixels, ImVec4 value);
  159. };
  160. /* Arrow
  161. * An annotation class that draws an arrow inside each texel when zoom level is
  162. * high enough. The direction and length of the arrow are determined by texel
  163. * values.
  164. * The X and Y components of the arrow is determined by the VectorIndex_x, and
  165. * VectorIndex_y channels of the texel value. Examples:
  166. * VectorIndex_x = 0, VectorIndex_y = 1 means X component is red and Y component is green
  167. * VectorIndex_x = 1, VectorIndex_y = 2 means X component is green and Y component is blue
  168. * VectorIndex_x = 0, VectorIndex_y = 3 means X component is red and Y component is alpha
  169. *
  170. * ZeroPoint is the texel value which corresponds to a zero length vector. E.g.
  171. * ZeroPoint = (0.5, 0.5) means (0.5, 0.5) will be drawn as a zero length arrow
  172. *
  173. * All public properties can be directly manipulated. There are also presets that can be set
  174. * by calling UsePreset.
  175. */
  176. class Arrow
  177. {
  178. public:
  179. int VectorIndex_x;
  180. int VectorIndex_y;
  181. ImVec2 LineScale;
  182. ImVec2 ZeroPoint = {0, 0};
  183. enum Preset
  184. {
  185. NormalMap, // For normal maps. I.e. Arrow is in (R,G) channels. 128, 128 is zero point
  186. NormalizedFloat // Arrow in (R,G) channels. 0,0 is zero point, (1,0) will draw an arrow exactly to
  187. // right edge of texture. (0,-1) will draw exactly to the bottom etc.
  188. };
  189. Arrow(int xVectorIndex = 0, int yVectorIndex = 1, ImVec2 lineScale = ImVec2(1, 1));
  190. Arrow &UsePreset(Preset);
  191. void DrawAnnotation(ImDrawList *drawList, ImVec2 texel, Transform2D texelsToPixels, ImVec4 value);
  192. };
  193. //-------------------------------------------------------------------------
  194. // [SECTION] INTERNAL
  195. //-------------------------------------------------------------------------
  196. struct Transform2D
  197. {
  198. ImVec2 Scale;
  199. ImVec2 Translate;
  200. /* Transform a vector by this transform. Scale is applied first */
  201. ImVec2 operator*(const ImVec2 &rhs) const
  202. {
  203. return ImVec2(Scale.x * rhs.x + Translate.x, Scale.y * rhs.y + Translate.y);
  204. }
  205. /* Return an inverse transform such that transform.Inverse() * transform * vector == vector*/
  206. Transform2D Inverse() const
  207. {
  208. ImVec2 inverseScale(1 / Scale.x, 1 / Scale.y);
  209. return {inverseScale, ImVec2(-inverseScale.x * Translate.x, -inverseScale.y * Translate.y)};
  210. }
  211. };
  212. struct BufferDesc
  213. {
  214. float *Data_float = nullptr; // Only one of these
  215. ImU8 *Data_uint8_t = nullptr; // two pointers should be non NULL
  216. size_t BufferByteSize = 0; // Size of buffer pointed to by one of above pointers
  217. int Stride = 0; // Measured in size of data type, not bytes!
  218. int LineStride = 0; // Measured in size of data type, not bytes!
  219. int StartX = 0; // Texel coordinates of data start
  220. int StartY = 0;
  221. int Width = 0; // Size of block of texels which are in data
  222. int Height = 0;
  223. unsigned char ChannelCount = 0; // Number of color channels in data. E.g. 2 means just red and green
  224. /* These 4 values describe where each color is stored relative to the beginning of the texel in memory
  225. * E.g. the float containing the red value would be at:
  226. * Data_float[texelIndex + bufferDesc.Red]
  227. */
  228. unsigned char Red = 0;
  229. unsigned char Green = 0;
  230. unsigned char Blue = 0;
  231. unsigned char Alpha = 0;
  232. };
  233. /* We use this struct for annotations rather than the Inspector struct so that
  234. * the whole Inspector struct doesn't have to be exposed in this header.
  235. */
  236. struct AnnotationsDesc
  237. {
  238. ImDrawList *DrawList;
  239. ImVec2 TexelViewSize; // How many texels are visible for annotating
  240. ImVec2 TexelTopLeft; // Coordinated in texture space of top left visible texel
  241. BufferDesc Buffer; // Description of cache texel data
  242. Transform2D TexelsToPixels; // Transform to go from texel space to screen pixel space
  243. };
  244. //-------------------------------------------------------------------------
  245. // [SECTION] FORWARD DECLARATIONS FOR TEMPLATE IMPLEMENTATION - Do not call directly
  246. //-------------------------------------------------------------------------
  247. ImVec4 GetTexel(const BufferDesc *bd, int x, int y);
  248. bool GetAnnotationDesc(AnnotationsDesc *, ImU64 maxAnnotatedTexels);
  249. //-------------------------------------------------------------------------
  250. // [SECTION] TEMPLATE IMPLEMENTATION
  251. //-------------------------------------------------------------------------
  252. template <typename T>
  253. void DrawAnnotations(T drawer, ImU64 maxAnnotatedTexels)
  254. {
  255. AnnotationsDesc ad;
  256. if (GetAnnotationDesc(&ad, maxAnnotatedTexels))
  257. {
  258. ImVec2 texelBottomRight = ImVec2(ad.TexelTopLeft.x + ad.TexelViewSize.x, ad.TexelTopLeft.y + ad.TexelViewSize.y);
  259. for (int ty = (int)ad.TexelTopLeft.y; ty < (int)texelBottomRight.y; ++ty)
  260. {
  261. for (int tx = (int)ad.TexelTopLeft.x; tx < (int)texelBottomRight.x; ++tx)
  262. {
  263. ImVec4 color = GetTexel(&ad.Buffer, tx, ty);
  264. ImVec2 center = {(float)tx + 0.5f, (float)ty + 0.5f};
  265. drawer.DrawAnnotation(ad.DrawList, center, ad.TexelsToPixels, color);
  266. }
  267. }
  268. }
  269. }
  270. } // namespace ImGuiTexInspect