// ImGuiTexInspect, a texture inspector widget for dear imgui #pragma once #include "imgui.h" #include "imgui_internal.h" #include "imgui_tex_inspect.h" namespace ImGuiTexInspect { //------------------------------------------------------------------------- // [SECTION] UTILITIES //------------------------------------------------------------------------- // Returns true if a flag is set template static inline bool HasFlag(TSet set, TFlag flag) { return (set & flag) == flag; } // Set flag or flags in set template static inline void SetFlag(TSet &set, TFlag flags) { set = static_cast(set | flags); } // Clear flag or flags in set template static inline void ClearFlag(TSet &set, TFlag flag) { set = static_cast(set & ~flag); } static inline float ImFloorSigned(float f) { return (float)((f >= 0 || (int)f == f) ? (int)f : (int)f - 1); } // Proper modulus operator, as opposed to remainder as calculated by % template static inline T Modulus(T a, T b) { return a - b * ImFloorSigned(a / b); } // Defined in recent versions of imgui_internal.h. Included here in case user is on older // imgui version. static inline float Round(float f) { return ImFloorSigned(f + 0.5f); } static inline ImVec2 Abs(ImVec2 v) { return ImVec2(ImAbs(v.x), ImAbs(v.y)); } //------------------------------------------------------------------------- // [SECTION] STRUCTURES //------------------------------------------------------------------------- struct ShaderOptions { float ColorTransform[16] = {}; // See CurrentInspector_SetColorMatrix for details float ColorOffset[4] = {}; ImVec4 BackgroundColor = {0,0,0,0}; // Color used for alpha blending float PremultiplyAlpha = 0; // If 1 then color will be multiplied by alpha in shader, before blend stage float DisableFinalAlpha = 0; // If 1 then fragment shader will always output alpha = 1 bool ForceNearestSampling = false; // If true fragment shader will always sample from texel centers ImVec2 GridWidth = {0,0}; // Width in UV coords of grid line ImVec4 GridColor = {0,0,0,0}; void ResetColorTransform(); ShaderOptions(); }; struct Inspector { ImGuiID ID; bool Initialized = false; // Texture ImTextureID Texture = ImTextureID{}; ImVec2 TextureSize = {0, 0}; // Size in texels of texture float PixelAspectRatio = 1; // Values other than 1 not supported yet // View State bool IsDragging = false; // Is user currently dragging to pan view ImVec2 PanPos = {0.5f, 0.5f}; // The UV value at the center of the current view ImVec2 Scale = {1, 1}; // 1 pixel is 1 texel ImVec2 PanelTopLeftPixel = {0, 0}; // Top left of view in ImGui pixel coordinates ImVec2 PanelSize = {0, 0}; // Size of area allocated to drawing the image in pixels. ImVec2 ViewTopLeftPixel = {0, 0}; // Position in ImGui pixel coordinates ImVec2 ViewSize = {0, 0}; // Rendered size of current image. This could be smaller than panel size if user has zoomed out. ImVec2 ViewSizeUV = {0, 0}; // Visible region of the texture in UV coordinates /* Conversion transforms to go back and forth between screen pixels (what ImGui considers screen pixels) and texels*/ Transform2D TexelsToPixels; Transform2D PixelsToTexels; // Cached pixel data bool HaveCurrentTexelData = false; BufferDesc Buffer; /* We don't actually access texel data through this pointer. We just * manage its lifetime. The backend might have asked us to allocated a * buffer, or it might not. The pointer we actually use to access texel * data is in the Buffer object above (which depending on what the backend * did might point to the same memory as this pointer) */ ImU8 *DataBuffer = nullptr; size_t DataBufferSize = 0; // Configuration InspectorFlags Flags = 0; // Background mode InspectorAlphaMode AlphaMode = InspectorAlphaMode_ImGui; ImVec4 CustomBackgroundColor = {0, 0, 0, 1}; // Scaling limits ImVec2 ScaleMin = {0.02f, 0.02f}; ImVec2 ScaleMax = {500, 500}; // Grid float MinimumGridSize = 4; // Don't draw the grid if lines would be closer than MinimumGridSize pixels // Annotations ImU32 MaxAnnotatedTexels = 0; // Color transformation ShaderOptions ActiveShaderOptions; ShaderOptions CachedShaderOptions; ~Inspector(); }; //------------------------------------------------------------------------- // [SECTION] INTERNAL FUNCTIONS //------------------------------------------------------------------------- Inspector *GetByKey(const Context *ctx, ImGuiID key); Inspector *GetOrAddByKey(Context *ctx, ImGuiID key); void SetPanPos(Inspector *inspector, ImVec2 pos); void SetScale(Inspector *inspector, ImVec2 scale); void SetScale(Inspector *inspector, float scaleY); void RoundPanPos(Inspector *inspector); ImU8 *GetBuffer(Inspector *inspector, size_t bytes); /* GetTexelsToPixels * Calculate a transform to convert from texel coordinates to screen pixel coordinates * */ Transform2D GetTexelsToPixels(ImVec2 screenTopLeft, ImVec2 screenViewSize, ImVec2 uvTopLeft, ImVec2 uvViewSize, ImVec2 textureSize); //------------------------------------------------------------------------- // [SECTION] IMGUI UTILS //------------------------------------------------------------------------- /* TextVector * Draws a single-column ImGui table with one row for each provided string */ void TextVector(const char *title, const char *const *strings, int n); /* PushDisabled & PopDisabled * Push and Pop and ImGui styles that disable and "grey out" ImGui elements * by making them non interactive and transparent*/ void PushDisabled(); void PopDisabled(); //------------------------------------------------------------------------- // [SECTION] BACKEND FUNCTIONS //------------------------------------------------------------------------- void BackEnd_SetShader(const ImDrawList *drawList, const ImDrawCmd *cmd, const Inspector *inspector); bool BackEnd_GetData(Inspector *inspector, ImTextureID texture, int x, int y, int width, int height, BufferDesc *buffer); } // namespace ImGuiTexInspect