// DragonX Wallet - ImGui Edition // Copyright 2024-2026 The Hush Developers // Released under the GPLv3 #include "imgui_acrylic.h" #include "../schema/ui_schema.h" #include "../../util/noise_texture.h" #ifdef DRAGONX_HAS_GLAD #include #endif #include #include #include "../../util/logger.h" // ============================================================================ // Frosted scrim — shared between GLAD and non-GLAD builds. // Drawn on the popup's draw list as the first command so it appears behind // the popup content but over the rest of the UI. Replaces ImGui's default // solid-colour ModalWindowDimBg with a translucent frosted overlay + noise. // ============================================================================ namespace dragonx { namespace ui { namespace effects { namespace ImGuiAcrylic { static void DrawFrostedScrim(ImDrawList* dl) { const auto& S = ui::schema::UI(); auto sde = [&](const char* key, float fb) -> float { float v = S.drawElement("components.modal-scrim", key).size; return v >= 0.0f ? v : fb; }; ImGuiViewport* vp = ImGui::GetMainViewport(); ImVec2 vpMin = vp->Pos; ImVec2 vpMax(vp->Pos.x + vp->Size.x, vp->Pos.y + vp->Size.y); // Semi-transparent white fill (the "frost") int fillAlpha = (int)sde("fill-alpha", 12.0f); dl->AddRectFilled(vpMin, vpMax, IM_COL32(255, 255, 255, fillAlpha)); // Noise grain overlay — single draw call via pre-tiled texture { int noiseAlpha = (int)sde("noise-alpha", 14.0f); ImU32 noiseTint = IM_COL32(255, 255, 255, noiseAlpha); dragonx::util::DrawTiledNoiseRect(dl, vpMin, vpMax, noiseTint); } } } } } } // namespace dragonx::ui::effects::ImGuiAcrylic // ============================================================================ // Preset table — shared by all backends // ============================================================================ namespace dragonx { namespace ui { namespace effects { namespace ImGuiAcrylic { struct PresetDef { const char* label; AcrylicQuality quality; float blur; }; static const PresetDef kPresets[kPresetCount] = { { "Off", AcrylicQuality::Off, 0.0f }, { "Subtle", AcrylicQuality::Low, 0.6f }, { "Light", AcrylicQuality::Medium, 1.0f }, { "Standard", AcrylicQuality::Medium, 1.5f }, { "Strong", AcrylicQuality::High, 2.5f }, { "Frosted", AcrylicQuality::High, 4.0f }, }; const char* GetPresetLabel(int preset) { if (preset < 0 || preset >= kPresetCount) return "?"; return kPresets[preset].label; } AcrylicQuality PresetQuality(int preset) { if (preset < 0 || preset >= kPresetCount) return AcrylicQuality::Medium; return kPresets[preset].quality; } float PresetBlur(int preset) { if (preset < 0 || preset >= kPresetCount) return 1.0f; return kPresets[preset].blur; } // Find closest preset matching given quality + blur int MatchPreset(AcrylicQuality q, float blur) { // Exact match first for (int i = 0; i < kPresetCount; ++i) { if (kPresets[i].quality == q && std::abs(kPresets[i].blur - blur) < 0.01f) return i; } // Closest blur within same quality int best = 3; // Standard fallback float bestDist = 999.f; for (int i = 0; i < kPresetCount; ++i) { if (kPresets[i].quality == q) { float d = std::abs(kPresets[i].blur - blur); if (d < bestDist) { bestDist = d; best = i; } } } return best; } } } } } // namespace dragonx::ui::effects::ImGuiAcrylic #ifdef DRAGONX_HAS_GLAD namespace dragonx { namespace ui { namespace effects { namespace ImGuiAcrylic { // ============================================================================ // Static State // ============================================================================ static bool s_initialized = false; static int s_viewportWidth = 0; static int s_viewportHeight = 0; static bool s_backgroundCaptured = false; // Track window state for acrylic rendering struct AcrylicWindowState { ImVec2 windowPos; ImVec2 windowSize; AcrylicParams params; bool active; }; static AcrylicWindowState s_currentWindow = {}; // ============================================================================ // Initialization // ============================================================================ bool Init() { if (s_initialized) { return true; } AcrylicMaterial& acrylic = getAcrylicMaterial(); if (!acrylic.init()) { DEBUG_LOGF("ImGuiAcrylic: Failed to initialize acrylic material\n"); return false; } s_initialized = true; DEBUG_LOGF("ImGuiAcrylic: Initialized successfully\n"); return true; } void Shutdown() { if (!s_initialized) { return; } getAcrylicMaterial().shutdown(); s_initialized = false; DEBUG_LOGF("ImGuiAcrylic: Shut down\n"); } bool IsAvailable() { return s_initialized && getAcrylicMaterial().isInitialized(); } // ============================================================================ // Frame Operations // ============================================================================ void BeginFrame(int width, int height) { if (!s_initialized) { return; } // Update viewport dimensions if changed if (width != s_viewportWidth || height != s_viewportHeight) { s_viewportWidth = width; s_viewportHeight = height; getAcrylicMaterial().resize(width, height); } // Capture the first few frames to ensure a clean initial blur, // then stop. The background (gradient/image/noise) is static; // re-capturing + re-blurring every frame causes a subtle flicker // from GPU floating-point non-determinism in the blur shader. // Resize / theme change already sets dirtyFrames_ via markBackgroundDirty(). static int s_warmupFrames = 3; if (s_warmupFrames > 0) { getAcrylicMaterial().markBackgroundDirty(); --s_warmupFrames; } s_backgroundCaptured = false; } void CaptureBackground() { if (!s_initialized || s_backgroundCaptured) { return; } getAcrylicMaterial().captureBackground(); s_backgroundCaptured = true; } void InvalidateCapture() { if (!s_initialized) return; getAcrylicMaterial().markBackgroundDirty(); } // Draw callback: captures framebuffer 0 (which at this point during // RenderDrawData() contains only the rasterized BackgroundDrawList — // no UI windows yet) into the acrylic capture buffer. static void BackgroundCaptureCallback(const ImDrawList*, const ImDrawCmd*) { if (!s_initialized) return; getAcrylicMaterial().captureBackgroundDirect(); s_backgroundCaptured = true; } ImDrawCallback GetBackgroundCaptureCallback() { return BackgroundCaptureCallback; } // ============================================================================ // Drawing Functions // ============================================================================ void DrawAcrylicRect(ImDrawList* drawList, const ImVec2& pMin, const ImVec2& pMax, const AcrylicParams& params, float rounding) { if (!drawList) { return; } // If acrylic not available or disabled, draw fallback if (!IsAvailable() || !IsEnabled() || !params.enabled) { drawList->AddRectFilled(pMin, pMax, ImGui::ColorConvertFloat4ToU32(params.fallbackColor), rounding); return; } // Background capture is now handled by a draw callback inserted // into the BackgroundDrawList (see GetBackgroundCaptureCallback()). // On the very first frame the callback hasn't fired yet, so // drawRect() will fall back to a tinted fill automatically. // Draw using acrylic material getAcrylicMaterial().drawRect(drawList, pMin, pMax, params, rounding); } void DrawAcrylicRect(ImDrawList* drawList, const ImVec2& pMin, const ImVec2& pMax, float rounding) { DrawAcrylicRect(drawList, pMin, pMax, AcrylicMaterial::getDarkPreset(), rounding); } // ============================================================================ // Window Wrappers // ============================================================================ bool BeginAcrylicWindow(const char* name, bool* p_open, ImGuiWindowFlags flags, const AcrylicParams& params) { // Store params for use in EndAcrylicWindow s_currentWindow.params = params; s_currentWindow.active = true; // Ensure dialog windows stay above background windows (MainContent, StatusBar, MenuBar) if (!(flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ImGui::SetNextWindowFocus(); // Make window background transparent so acrylic shows through ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0)); bool result = ImGui::Begin(name, p_open, flags); if (result) { // Get window bounds for acrylic rendering s_currentWindow.windowPos = ImGui::GetWindowPos(); s_currentWindow.windowSize = ImGui::GetWindowSize(); // Draw acrylic background ImDrawList* drawList = ImGui::GetWindowDrawList(); ImVec2 pMin = s_currentWindow.windowPos; ImVec2 pMax = ImVec2(pMin.x + s_currentWindow.windowSize.x, pMin.y + s_currentWindow.windowSize.y); // Get window rounding from style float rounding = ImGui::GetStyle().WindowRounding; DrawAcrylicRect(drawList, pMin, pMax, params, rounding); } return result; } void EndAcrylicWindow() { ImGui::End(); ImGui::PopStyleColor(); // WindowBg s_currentWindow.active = false; } // ============================================================================ // Child Region Wrappers // ============================================================================ bool BeginAcrylicChild(const char* str_id, const ImVec2& size, const AcrylicParams& params, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags) { // Make child background transparent ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0, 0, 0, 0)); bool result = ImGui::BeginChild(str_id, size, child_flags, window_flags); if (result) { // Get child bounds ImVec2 childPos = ImGui::GetWindowPos(); ImVec2 childSize = ImGui::GetWindowSize(); // Draw acrylic background ImDrawList* drawList = ImGui::GetWindowDrawList(); ImVec2 pMin = childPos; ImVec2 pMax = ImVec2(pMin.x + childSize.x, pMin.y + childSize.y); float rounding = ImGui::GetStyle().ChildRounding; DrawAcrylicRect(drawList, pMin, pMax, params, rounding); } return result; } void EndAcrylicChild() { ImGui::EndChild(); ImGui::PopStyleColor(); // ChildBg } // ============================================================================ // Popup Wrappers // ============================================================================ bool BeginAcrylicPopup(const char* str_id, ImGuiWindowFlags flags, const AcrylicParams& params) { ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0, 0, 0, 0)); bool result = ImGui::BeginPopup(str_id, flags); if (result) { ImVec2 popupPos = ImGui::GetWindowPos(); ImVec2 popupSize = ImGui::GetWindowSize(); ImDrawList* drawList = ImGui::GetWindowDrawList(); ImVec2 pMin = popupPos; ImVec2 pMax = ImVec2(pMin.x + popupSize.x, pMin.y + popupSize.y); float rounding = ImGui::GetStyle().PopupRounding; DrawAcrylicRect(drawList, pMin, pMax, params, rounding); } else { ImGui::PopStyleColor(); // Only pop if not opened } return result; } void EndAcrylicPopup() { ImGui::EndPopup(); ImGui::PopStyleColor(); // PopupBg } bool BeginAcrylicPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags, const AcrylicParams& params) { // Suppress ImGui's built-in dark scrim — we draw our own frosted one ImGui::PushStyleColor(ImGuiCol_ModalWindowDimBg, ImVec4(0, 0, 0, 0)); ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0, 0, 0, 0)); bool result = ImGui::BeginPopupModal(name, p_open, flags); ImGui::PopStyleColor(); // ModalWindowDimBg (only needed during Begin) if (result) { // Draw frosted scrim behind the popup on its own draw list ImDrawList* drawList = ImGui::GetWindowDrawList(); DrawFrostedScrim(drawList); ImVec2 popupPos = ImGui::GetWindowPos(); ImVec2 popupSize = ImGui::GetWindowSize(); ImVec2 pMin = popupPos; ImVec2 pMax = ImVec2(pMin.x + popupSize.x, pMin.y + popupSize.y); float rounding = ImGui::GetStyle().PopupRounding; DrawAcrylicRect(drawList, pMin, pMax, params, rounding); } else { ImGui::PopStyleColor(); } return result; } // ============================================================================ // Context Menu Helpers // ============================================================================ bool BeginAcrylicContextItem(const char* str_id, ImGuiPopupFlags popup_flags, const AcrylicParams& params) { ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0, 0, 0, 0)); bool result = ImGui::BeginPopupContextItem(str_id, popup_flags); if (result) { ImVec2 popupPos = ImGui::GetWindowPos(); ImVec2 popupSize = ImGui::GetWindowSize(); ImDrawList* drawList = ImGui::GetWindowDrawList(); ImVec2 pMin = popupPos; ImVec2 pMax = ImVec2(pMin.x + popupSize.x, pMin.y + popupSize.y); float rounding = ImGui::GetStyle().PopupRounding; DrawAcrylicRect(drawList, pMin, pMax, params, rounding); } else { ImGui::PopStyleColor(); } return result; } bool BeginAcrylicContextWindow(const char* str_id, ImGuiPopupFlags popup_flags, const AcrylicParams& params) { ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0, 0, 0, 0)); bool result = ImGui::BeginPopupContextWindow(str_id, popup_flags); if (result) { ImVec2 popupPos = ImGui::GetWindowPos(); ImVec2 popupSize = ImGui::GetWindowSize(); ImDrawList* drawList = ImGui::GetWindowDrawList(); ImVec2 pMin = popupPos; ImVec2 pMax = ImVec2(pMin.x + popupSize.x, pMin.y + popupSize.y); float rounding = ImGui::GetStyle().PopupRounding; DrawAcrylicRect(drawList, pMin, pMax, params, rounding); } else { ImGui::PopStyleColor(); } return result; } // ============================================================================ // Sidebar Helper // ============================================================================ void DrawSidebarBackground(float width, const AcrylicParams& params) { ImGuiViewport* viewport = ImGui::GetMainViewport(); // Sidebar starts below menu bar float menuBarHeight = ImGui::GetFrameHeight(); ImVec2 pMin = ImVec2(viewport->WorkPos.x, viewport->WorkPos.y + menuBarHeight); ImVec2 pMax = ImVec2(pMin.x + width, viewport->WorkPos.y + viewport->WorkSize.y); // Draw to background draw list ImDrawList* drawList = ImGui::GetBackgroundDrawList(); DrawAcrylicRect(drawList, pMin, pMax, params, 0.0f); } // ============================================================================ // Settings // ============================================================================ void SetQuality(AcrylicQuality quality) { if (s_initialized) { getAcrylicMaterial().setQuality(quality); } } AcrylicQuality GetQuality() { if (s_initialized) { return getAcrylicMaterial().getQuality(); } return AcrylicQuality::Off; } void SetEnabled(bool enabled) { if (s_initialized) { getAcrylicMaterial().setEnabled(enabled); } } bool IsEnabled() { if (s_initialized) { return getAcrylicMaterial().isEnabled(); } return false; } void SetBlurMultiplier(float multiplier) { if (s_initialized) { getAcrylicMaterial().setBlurMultiplier(multiplier); } } float GetBlurMultiplier() { if (s_initialized) { return getAcrylicMaterial().getBlurMultiplier(); } return 1.0f; } void SetReducedTransparency(bool reduced) { if (s_initialized) { getAcrylicMaterial().setReducedTransparency(reduced); } } bool GetReducedTransparency() { if (s_initialized) { return getAcrylicMaterial().getReducedTransparency(); } return false; } void SetUIOpacity(float opacity) { if (s_initialized) { getAcrylicMaterial().setUIOpacity(opacity); } } float GetUIOpacity() { if (s_initialized) { return getAcrylicMaterial().getUIOpacity(); } return 1.0f; } void SetNoiseOpacity(float multiplier) { if (s_initialized) { getAcrylicMaterial().setNoiseOpacityMultiplier(multiplier); } } float GetNoiseOpacity() { if (s_initialized) { return getAcrylicMaterial().getNoiseOpacityMultiplier(); } return 1.0f; } const AcrylicSettings& GetSettings() { return getAcrylicMaterial().getSettings(); } void SetSettings(const AcrylicSettings& settings) { if (s_initialized) { getAcrylicMaterial().setSettings(settings); } } void SetPreset(int preset) { if (preset < 0 || preset >= kPresetCount) preset = 3; SetEnabled(preset != 0); SetQuality(PresetQuality(preset)); SetBlurMultiplier(PresetBlur(preset)); } int GetPreset() { return MatchPreset(GetQuality(), GetBlurMultiplier()); } void ApplyBlurAmount(float blur) { if (blur < 0.001f) { SetEnabled(false); SetQuality(AcrylicQuality::Off); SetBlurMultiplier(0.0f); } else { SetEnabled(true); SetQuality(AcrylicQuality::Low); SetBlurMultiplier(blur); } } } // namespace ImGuiAcrylic } // namespace effects } // namespace ui } // namespace dragonx #endif // DRAGONX_HAS_GLAD // ============================================================================ // Stub Implementations (No GLAD) // ============================================================================ #ifndef DRAGONX_HAS_GLAD #ifdef DRAGONX_USE_DX11 // ============================================================================ // DX11 Implementation — mirrors the GLAD version above, delegating to // AcrylicMaterial which now has a full DX11 backend. // ============================================================================ namespace dragonx { namespace ui { namespace effects { namespace ImGuiAcrylic { static bool s_initialized = false; static int s_viewportWidth = 0; static int s_viewportHeight = 0; static bool s_backgroundCaptured = false; struct AcrylicWindowState { ImVec2 windowPos; ImVec2 windowSize; AcrylicParams params; bool active; }; static AcrylicWindowState s_currentWindow = {}; bool Init() { if (s_initialized) return true; AcrylicMaterial& acrylic = getAcrylicMaterial(); if (!acrylic.init()) { DEBUG_LOGF("ImGuiAcrylic DX11: Failed to initialize acrylic material\n"); return false; } s_initialized = true; DEBUG_LOGF("ImGuiAcrylic DX11: Initialized successfully\n"); return true; } void Shutdown() { if (!s_initialized) return; getAcrylicMaterial().shutdown(); s_initialized = false; } bool IsAvailable() { return s_initialized && getAcrylicMaterial().isInitialized(); } void BeginFrame(int width, int height) { if (!s_initialized) return; if (width != s_viewportWidth || height != s_viewportHeight) { s_viewportWidth = width; s_viewportHeight = height; getAcrylicMaterial().resize(width, height); } // Capture the first few frames to ensure a clean initial blur, // then stop. Resize / theme change already sets dirtyFrames_ via markBackgroundDirty(). static int s_warmupFrames = 3; if (s_warmupFrames > 0) { getAcrylicMaterial().markBackgroundDirty(); --s_warmupFrames; } s_backgroundCaptured = false; } void CaptureBackground() { if (!s_initialized || s_backgroundCaptured) return; getAcrylicMaterial().captureBackground(); s_backgroundCaptured = true; } void InvalidateCapture() { if (!s_initialized) return; getAcrylicMaterial().markBackgroundDirty(); } static void BackgroundCaptureCallback(const ImDrawList*, const ImDrawCmd*) { if (!s_initialized) return; getAcrylicMaterial().captureBackgroundDirect(); s_backgroundCaptured = true; } ImDrawCallback GetBackgroundCaptureCallback() { return BackgroundCaptureCallback; } void DrawAcrylicRect(ImDrawList* drawList, const ImVec2& pMin, const ImVec2& pMax, const AcrylicParams& params, float rounding) { if (!drawList) return; if (!IsAvailable() || !IsEnabled() || !params.enabled) { drawList->AddRectFilled(pMin, pMax, ImGui::ColorConvertFloat4ToU32(params.fallbackColor), rounding); return; } getAcrylicMaterial().drawRect(drawList, pMin, pMax, params, rounding); } void DrawAcrylicRect(ImDrawList* drawList, const ImVec2& pMin, const ImVec2& pMax, float rounding) { DrawAcrylicRect(drawList, pMin, pMax, AcrylicMaterial::getDarkPreset(), rounding); } bool BeginAcrylicWindow(const char* name, bool* p_open, ImGuiWindowFlags flags, const AcrylicParams& params) { s_currentWindow.params = params; s_currentWindow.active = true; if (!(flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ImGui::SetNextWindowFocus(); ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0)); bool result = ImGui::Begin(name, p_open, flags); if (result) { s_currentWindow.windowPos = ImGui::GetWindowPos(); s_currentWindow.windowSize = ImGui::GetWindowSize(); ImDrawList* drawList = ImGui::GetWindowDrawList(); ImVec2 pMin = s_currentWindow.windowPos; ImVec2 pMax = ImVec2(pMin.x + s_currentWindow.windowSize.x, pMin.y + s_currentWindow.windowSize.y); float rounding = ImGui::GetStyle().WindowRounding; DrawAcrylicRect(drawList, pMin, pMax, params, rounding); } return result; } void EndAcrylicWindow() { ImGui::End(); ImGui::PopStyleColor(); s_currentWindow.active = false; } bool BeginAcrylicChild(const char* str_id, const ImVec2& size, const AcrylicParams& params, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags) { ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0, 0, 0, 0)); bool result = ImGui::BeginChild(str_id, size, child_flags, window_flags); if (result) { ImVec2 childPos = ImGui::GetWindowPos(); ImVec2 childSize = ImGui::GetWindowSize(); ImDrawList* drawList = ImGui::GetWindowDrawList(); ImVec2 pMin = childPos; ImVec2 pMax = ImVec2(pMin.x + childSize.x, pMin.y + childSize.y); float rounding = ImGui::GetStyle().ChildRounding; DrawAcrylicRect(drawList, pMin, pMax, params, rounding); } return result; } void EndAcrylicChild() { ImGui::EndChild(); ImGui::PopStyleColor(); } bool BeginAcrylicPopup(const char* str_id, ImGuiWindowFlags flags, const AcrylicParams& params) { ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0, 0, 0, 0)); bool result = ImGui::BeginPopup(str_id, flags); if (result) { ImVec2 popupPos = ImGui::GetWindowPos(); ImVec2 popupSize = ImGui::GetWindowSize(); ImDrawList* drawList = ImGui::GetWindowDrawList(); ImVec2 pMin = popupPos; ImVec2 pMax = ImVec2(pMin.x + popupSize.x, pMin.y + popupSize.y); float rounding = ImGui::GetStyle().PopupRounding; DrawAcrylicRect(drawList, pMin, pMax, params, rounding); } else { ImGui::PopStyleColor(); } return result; } void EndAcrylicPopup() { ImGui::EndPopup(); ImGui::PopStyleColor(); } bool BeginAcrylicPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags, const AcrylicParams& params) { ImGui::PushStyleColor(ImGuiCol_ModalWindowDimBg, ImVec4(0, 0, 0, 0)); ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0, 0, 0, 0)); bool result = ImGui::BeginPopupModal(name, p_open, flags); ImGui::PopStyleColor(); // ModalWindowDimBg if (result) { ImDrawList* drawList = ImGui::GetWindowDrawList(); DrawFrostedScrim(drawList); ImVec2 popupPos = ImGui::GetWindowPos(); ImVec2 popupSize = ImGui::GetWindowSize(); ImVec2 pMin = popupPos; ImVec2 pMax = ImVec2(pMin.x + popupSize.x, pMin.y + popupSize.y); float rounding = ImGui::GetStyle().PopupRounding; DrawAcrylicRect(drawList, pMin, pMax, params, rounding); } else { ImGui::PopStyleColor(); } return result; } bool BeginAcrylicContextItem(const char* str_id, ImGuiPopupFlags popup_flags, const AcrylicParams& params) { ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0, 0, 0, 0)); bool result = ImGui::BeginPopupContextItem(str_id, popup_flags); if (result) { ImVec2 popupPos = ImGui::GetWindowPos(); ImVec2 popupSize = ImGui::GetWindowSize(); ImDrawList* drawList = ImGui::GetWindowDrawList(); ImVec2 pMin = popupPos; ImVec2 pMax = ImVec2(pMin.x + popupSize.x, pMin.y + popupSize.y); float rounding = ImGui::GetStyle().PopupRounding; DrawAcrylicRect(drawList, pMin, pMax, params, rounding); } else { ImGui::PopStyleColor(); } return result; } bool BeginAcrylicContextWindow(const char* str_id, ImGuiPopupFlags popup_flags, const AcrylicParams& params) { ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0, 0, 0, 0)); bool result = ImGui::BeginPopupContextWindow(str_id, popup_flags); if (result) { ImVec2 popupPos = ImGui::GetWindowPos(); ImVec2 popupSize = ImGui::GetWindowSize(); ImDrawList* drawList = ImGui::GetWindowDrawList(); ImVec2 pMin = popupPos; ImVec2 pMax = ImVec2(pMin.x + popupSize.x, pMin.y + popupSize.y); float rounding = ImGui::GetStyle().PopupRounding; DrawAcrylicRect(drawList, pMin, pMax, params, rounding); } else { ImGui::PopStyleColor(); } return result; } void DrawSidebarBackground(float width, const AcrylicParams& params) { ImGuiViewport* viewport = ImGui::GetMainViewport(); float menuBarHeight = ImGui::GetFrameHeight(); ImVec2 pMin = ImVec2(viewport->WorkPos.x, viewport->WorkPos.y + menuBarHeight); ImVec2 pMax = ImVec2(pMin.x + width, viewport->WorkPos.y + viewport->WorkSize.y); ImDrawList* drawList = ImGui::GetBackgroundDrawList(); DrawAcrylicRect(drawList, pMin, pMax, params, 0.0f); } void SetQuality(AcrylicQuality quality) { if (s_initialized) getAcrylicMaterial().setQuality(quality); } AcrylicQuality GetQuality() { if (s_initialized) return getAcrylicMaterial().getQuality(); return AcrylicQuality::Off; } void SetEnabled(bool enabled) { if (s_initialized) getAcrylicMaterial().setEnabled(enabled); } bool IsEnabled() { if (s_initialized) return getAcrylicMaterial().isEnabled(); return false; } void SetBlurMultiplier(float multiplier) { if (s_initialized) getAcrylicMaterial().setBlurMultiplier(multiplier); } float GetBlurMultiplier() { if (s_initialized) return getAcrylicMaterial().getBlurMultiplier(); return 1.0f; } void SetReducedTransparency(bool reduced) { if (s_initialized) getAcrylicMaterial().setReducedTransparency(reduced); } bool GetReducedTransparency() { if (s_initialized) return getAcrylicMaterial().getReducedTransparency(); return false; } void SetUIOpacity(float opacity) { if (s_initialized) getAcrylicMaterial().setUIOpacity(opacity); } float GetUIOpacity() { if (s_initialized) return getAcrylicMaterial().getUIOpacity(); return 1.0f; } void SetNoiseOpacity(float multiplier) { if (s_initialized) getAcrylicMaterial().setNoiseOpacityMultiplier(multiplier); } float GetNoiseOpacity() { if (s_initialized) return getAcrylicMaterial().getNoiseOpacityMultiplier(); return 1.0f; } const AcrylicSettings& GetSettings() { return getAcrylicMaterial().getSettings(); } void SetSettings(const AcrylicSettings& settings) { if (s_initialized) getAcrylicMaterial().setSettings(settings); } void SetPreset(int preset) { if (preset < 0 || preset >= kPresetCount) preset = 3; SetEnabled(preset != 0); SetQuality(PresetQuality(preset)); SetBlurMultiplier(PresetBlur(preset)); } int GetPreset() { return MatchPreset(GetQuality(), GetBlurMultiplier()); } void ApplyBlurAmount(float blur) { if (blur < 0.001f) { SetEnabled(false); SetQuality(AcrylicQuality::Off); SetBlurMultiplier(0.0f); } else { SetEnabled(true); SetQuality(AcrylicQuality::Low); SetBlurMultiplier(blur); } } } // namespace ImGuiAcrylic } // namespace effects } // namespace ui } // namespace dragonx #else // neither GLAD nor DX11 namespace dragonx { namespace ui { namespace effects { namespace ImGuiAcrylic { bool Init() { return false; } void Shutdown() {} bool IsAvailable() { return false; } void BeginFrame(int, int) {} void CaptureBackground() {} void InvalidateCapture() {} ImDrawCallback GetBackgroundCaptureCallback() { return nullptr; } void DrawAcrylicRect(ImDrawList* drawList, const ImVec2& pMin, const ImVec2& pMax, const AcrylicParams& params, float rounding) { if (drawList) { drawList->AddRectFilled(pMin, pMax, ImGui::ColorConvertFloat4ToU32(params.fallbackColor), rounding); } } void DrawAcrylicRect(ImDrawList* drawList, const ImVec2& pMin, const ImVec2& pMax, float rounding) { if (drawList) { AcrylicParams params; drawList->AddRectFilled(pMin, pMax, ImGui::ColorConvertFloat4ToU32(params.fallbackColor), rounding); } } bool BeginAcrylicWindow(const char* name, bool* p_open, ImGuiWindowFlags flags, const AcrylicParams&) { if (!(flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ImGui::SetNextWindowFocus(); return ImGui::Begin(name, p_open, flags); } void EndAcrylicWindow() { ImGui::End(); } bool BeginAcrylicChild(const char* str_id, const ImVec2& size, const AcrylicParams&, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags) { return ImGui::BeginChild(str_id, size, child_flags, window_flags); } void EndAcrylicChild() { ImGui::EndChild(); } bool BeginAcrylicPopup(const char* str_id, ImGuiWindowFlags flags, const AcrylicParams&) { return ImGui::BeginPopup(str_id, flags); } void EndAcrylicPopup() { ImGui::EndPopup(); } bool BeginAcrylicPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags, const AcrylicParams&) { ImGui::PushStyleColor(ImGuiCol_ModalWindowDimBg, ImVec4(0, 0, 0, 0)); bool result = ImGui::BeginPopupModal(name, p_open, flags); ImGui::PopStyleColor(); if (result) { DrawFrostedScrim(ImGui::GetWindowDrawList()); } return result; } bool BeginAcrylicContextItem(const char* str_id, ImGuiPopupFlags popup_flags, const AcrylicParams&) { return ImGui::BeginPopupContextItem(str_id, popup_flags); } bool BeginAcrylicContextWindow(const char* str_id, ImGuiPopupFlags popup_flags, const AcrylicParams&) { return ImGui::BeginPopupContextWindow(str_id, popup_flags); } void DrawSidebarBackground(float, const AcrylicParams&) {} void SetQuality(AcrylicQuality) {} AcrylicQuality GetQuality() { return AcrylicQuality::Off; } void SetEnabled(bool) {} bool IsEnabled() { return false; } void SetBlurMultiplier(float) {} float GetBlurMultiplier() { return 1.0f; } void SetReducedTransparency(bool) {} bool GetReducedTransparency() { return false; } void SetUIOpacity(float) {} float GetUIOpacity() { return 1.0f; } void SetNoiseOpacity(float) {} float GetNoiseOpacity() { return 1.0f; } static AcrylicSettings s_stubSettings; const AcrylicSettings& GetSettings() { return s_stubSettings; } void SetSettings(const AcrylicSettings&) {} void SetPreset(int) {} int GetPreset() { return 0; } void ApplyBlurAmount(float) {} } // namespace ImGuiAcrylic } // namespace effects } // namespace ui } // namespace dragonx #endif // DRAGONX_USE_DX11 #endif // !DRAGONX_HAS_GLAD