diff --git a/package/Shaders/Menu/BackgroundBlurComposite.hlsl b/package/Shaders/Menu/BackgroundBlurComposite.hlsl index 3326a63dd3..fc51fae145 100644 --- a/package/Shaders/Menu/BackgroundBlurComposite.hlsl +++ b/package/Shaders/Menu/BackgroundBlurComposite.hlsl @@ -4,7 +4,7 @@ cbuffer WindowBuffer : register(b1) { float4 WindowRect; // x = minX, y = minY, z = maxX, w = maxY (in pixels) - float4 WindowParams; // x = cornerRadius, y = screenWidth, z = screenHeight, w = unused + float4 WindowParams; // x = cornerRadius, y = screenWidth, z = screenHeight, w = fullscreen (1.0 = skip SDF) }; SamplerState LinearSampler : register(s0); @@ -102,17 +102,20 @@ float4 PS_Main(VS_OUTPUT input) : float2 rectMax = WindowRect.zw; float cornerRadius = WindowParams.x; - // Calculate signed distance to rounded rectangle - float sdf = RoundedRectSDF(pixelPos, rectMin, rectMax, cornerRadius); + float alpha = 1.0f; + if (WindowParams.w < 0.5f) { + // Calculate signed distance to rounded rectangle + float sdf = RoundedRectSDF(pixelPos, rectMin, rectMax, cornerRadius); - // Create smooth edge (anti-aliased) - // Negative = inside, positive outside - // Use 1.0 pixel transition for smooth edge - float alpha = saturate(-sdf); + // Create smooth edge (anti-aliased) + // Negative = inside, positive outside + // Use 1.0 pixel transition for smooth edge + alpha = saturate(-sdf); - // Early out if completely outside - if (alpha <= 0.0f) { - discard; + // Early out if completely outside + if (alpha <= 0.0f) { + discard; + } } float2 blurTexelSize = DOWNSAMPLE_FACTOR / float2(WindowParams.y, WindowParams.z); diff --git a/src/Features/WeatherEditor.cpp b/src/Features/WeatherEditor.cpp index 1da583b7e2..15a22d3a75 100644 --- a/src/Features/WeatherEditor.cpp +++ b/src/Features/WeatherEditor.cpp @@ -63,12 +63,10 @@ void LerpDirectional(RE::BGSDirectionalAmbientLightingColors::Directional& oldCo void WeatherEditor::DrawSettings() { - auto player = RE::PlayerCharacter::GetSingleton(); - bool hasCell = player && player->parentCell; - ImGui::BeginDisabled(!hasCell); - if (ImGui::Button(hasCell ? "Open Editor" : "Open Editor (no active cell)", { -1, 0 })) { + bool canOpen = EditorWindow::CanBeOpen(); + ImGui::BeginDisabled(!canOpen); + if (ImGui::Button("Open Editor", { -1, 0 })) EditorWindow::GetSingleton()->open = true; - } ImGui::EndDisabled(); // Time controls diff --git a/src/Globals.cpp b/src/Globals.cpp index a3c12569a9..8bd10fabce 100644 --- a/src/Globals.cpp +++ b/src/Globals.cpp @@ -107,6 +107,7 @@ namespace globals float* cameraFar = nullptr; float* deltaTime = nullptr; RE::BSUtilityShader* utilityShader = nullptr; + RE::PlayerCharacter* player = nullptr; RE::Sky* sky = nullptr; RE::UI* ui = nullptr; RE::Calendar* calendar = nullptr; @@ -204,6 +205,7 @@ namespace globals void OnDataLoaded() { using namespace game; + player = RE::PlayerCharacter::GetSingleton(); sky = RE::Sky::GetSingleton(); utilityShader = RE::BSUtilityShader::GetSingleton(); waterSystem = RE::TESWaterSystem::GetSingleton(); diff --git a/src/Globals.h b/src/Globals.h index d7c85eff14..b7ef68db63 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -221,6 +221,7 @@ namespace globals extern float* cameraFar; extern float* deltaTime; extern RE::BSUtilityShader* utilityShader; + extern RE::PlayerCharacter* player; extern RE::Sky* sky; extern RE::UI* ui; extern RE::Calendar* calendar; diff --git a/src/Menu.cpp b/src/Menu.cpp index 8d58a825ef..069f022194 100644 --- a/src/Menu.cpp +++ b/src/Menu.cpp @@ -1080,10 +1080,8 @@ void Menu::ProcessInputEventQueue() } else if (ew->IsInPreviewMode()) { // Locked or PlayMode → fully exit preview ew->ExitPreviewMode(); - } else { - auto p = RE::PlayerCharacter::GetSingleton(); - if (p && p->parentCell) - ew->open = !ew->open; + } else if (EditorWindow::CanBeOpen()) { + ew->open = !ew->open; } } }, }; diff --git a/src/Menu/BackgroundBlur.cpp b/src/Menu/BackgroundBlur.cpp index d425124cea..6bbe93eb1a 100644 --- a/src/Menu/BackgroundBlur.cpp +++ b/src/Menu/BackgroundBlur.cpp @@ -46,6 +46,7 @@ namespace BackgroundBlur { std::mutex resourceMutex; bool enabled = false; + bool weatherEditorActive = false; // DirectX resources (RAII managed) winrt::com_ptr vertexShader; @@ -411,7 +412,7 @@ namespace BackgroundBlur windowConstants.windowParams[0] = cornerRadius; windowConstants.windowParams[1] = static_cast(sourceDesc.Width); windowConstants.windowParams[2] = static_cast(sourceDesc.Height); - windowConstants.windowParams[3] = 0.0f; + windowConstants.windowParams[3] = weatherEditorActive ? 1.0f : 0.0f; context->UpdateSubresource(windowConstantBuffer.get(), 0, nullptr, &windowConstants, 0, 0); auto windowConstantBufferPtr = windowConstantBuffer.get(); context->PSSetConstantBuffers(1, 1, &windowConstantBufferPtr); @@ -484,6 +485,16 @@ namespace BackgroundBlur enabled = enable; } + void SetWeatherEditorActive(bool active) + { + weatherEditorActive = active; + } + + bool IsWeatherEditorActive() + { + return weatherEditorActive; + } + void RenderBackgroundBlur() { if (!enabled) { @@ -575,6 +586,14 @@ namespace BackgroundBlur CreateBlurTextures(texDesc.Width, texDesc.Height, texDesc.Format); } + // Weather editor mode: single fullscreen blur pass (better perf than per-window) + if (weatherEditorActive) { + ImVec2 screenMin = { 0, 0 }; + ImVec2 screenMax = { static_cast(texDesc.Width), static_cast(texDesc.Height) }; + PerformBlur(currentTexture.get(), sourceSRV, currentRTV.get(), screenMin, screenMax, 0.0f, uiBufferSRV, uiBufferRTV); + return; + } + // Find ImGui windows that need blur ImGuiContext* ctx = ImGui::GetCurrentContext(); if (!ctx || ctx->Windows.Size == 0) { diff --git a/src/Menu/BackgroundBlur.h b/src/Menu/BackgroundBlur.h index 6ff24bb60f..0919fe7a90 100644 --- a/src/Menu/BackgroundBlur.h +++ b/src/Menu/BackgroundBlur.h @@ -27,4 +27,8 @@ namespace BackgroundBlur void SetEnabled(bool enable); + /// When true, a single fullscreen blur replaces per-window blur (weather editor mode) + void SetWeatherEditorActive(bool active); + bool IsWeatherEditorActive(); + } // namespace BackgroundBlur diff --git a/src/Menu/OverlayRenderer.cpp b/src/Menu/OverlayRenderer.cpp index d959ed4564..c80bf97bed 100644 --- a/src/Menu/OverlayRenderer.cpp +++ b/src/Menu/OverlayRenderer.cpp @@ -52,15 +52,13 @@ void OverlayRenderer::RenderOverlay( RenderShaderCompilationStatus(keyIdToString); RenderShaderBlockingStatus(); - // Draw weather editor independently of main menu state - // Auto-close editor if player leaves valid game space (e.g., loading screen) auto* editorWindow = EditorWindow::GetSingleton(); - auto player = RE::PlayerCharacter::GetSingleton(); - if (editorWindow->open && !(player && player->parentCell)) { + if (editorWindow->open && !EditorWindow::CanBeOpen()) { editorWindow->open = false; if (editorWindow->IsInPreviewMode()) editorWindow->ExitPreviewMode(); } + editorWindow->UpdateOpenState(); if (editorWindow->open) { bool flying = editorWindow->IsPreviewFlying(); auto& io = ImGui::GetIO(); diff --git a/src/WeatherEditor/EditorWindow.cpp b/src/WeatherEditor/EditorWindow.cpp index 83b7cef12f..7fb633bf37 100644 --- a/src/WeatherEditor/EditorWindow.cpp +++ b/src/WeatherEditor/EditorWindow.cpp @@ -1,8 +1,10 @@ #include "EditorWindow.h" +#include "Features/Upscaling.h" #include "Features/WeatherEditor.h" #include "InteriorOnlyPanel.h" #include "Menu.h" +#include "Menu/BackgroundBlur.h" #include "PaletteWindow.h" #include "State.h" #include "Utils/UI.h" @@ -877,7 +879,6 @@ void EditorWindow::RenderUI() ImGui::GetStyle().FontScaleMain = settings.editorUIScale; if (settings.showViewport) { - // Dim the game scene using the theme's modal dim background color ImGui::GetBackgroundDrawList()->AddRectFilled({ 0, 0 }, io.DisplaySize, ImGui::GetColorU32(ImGuiCol_ModalWindowDimBg)); } @@ -1010,6 +1011,7 @@ void EditorWindow::RenderUI() } if (ImGui::BeginMenu("Window")) { if (ImGui::Checkbox("Viewport", &settings.showViewport)) { + BackgroundBlur::SetWeatherEditorActive(settings.showViewport); Save(); } if (ImGui::Checkbox("Palette", &PaletteWindow::GetSingleton()->open)) { @@ -1388,6 +1390,7 @@ void EditorWindow::OpenWeatherFeatureSetting(RE::TESWeather* weather, const std: EditorWindow::~EditorWindow() { + ShowGameMenus(); delete tempTexture; weatherWidgets.clear(); lightingTemplateWidgets.clear(); @@ -1420,23 +1423,27 @@ void EditorWindow::SetupResources() WidgetFactory::PopulateSimpleWidgets(effectShaderWidgets); } -void EditorWindow::Draw() +void EditorWindow::UpdateOpenState() { - // Track editor open state for vanity camera management static bool wasOpen = false; if (open && !wasOpen) { - // Editor just opened - disable vanity camera and restore session DisableVanityCamera(); + HideGameMenus(); + BackgroundBlur::SetWeatherEditorActive(settings.showViewport); RestoreSessionWidgets(); } else if (!open && wasOpen) { - // Editor just closed - restore vanity camera and save session RestoreVanityCamera(); + ShowGameMenus(); + BackgroundBlur::SetWeatherEditorActive(false); SaveSessionWidgets(); } wasOpen = open; +} +void EditorWindow::Draw() +{ // Re-enforce weather lock if active (handles time changes) if (weatherLockActive && lockedWeather) { auto sky = RE::Sky::GetSingleton(); @@ -1914,6 +1921,13 @@ void EditorWindow::DrawTimeControls() ImGui::Text("Adjust how fast time passes (vanilla: %.1fx)", kVanillaTimeScale); } +bool EditorWindow::CanBeOpen() +{ + auto* player = globals::game::player; + auto* state = globals::state; + return player && player->parentCell && !state->isLoadingMenuOpen && !state->isMainMenuOpen; +} + void EditorWindow::DisableVanityCamera() { if (vanityCameraDisabled) @@ -1941,6 +1955,35 @@ void EditorWindow::RestoreVanityCamera() } } +void EditorWindow::HideGameMenus() +{ + if (gameMenusHidden) + return; + + // ShowMenus(false) stops the game from rendering to the back buffer. + // Without d3d12SwapChain, blur reads directly from that buffer and would freeze. + if (!globals::features::upscaling.d3d12SwapChainActive) + return; + + if (auto ui = RE::UI::GetSingleton()) { + ui->ShowMenus(false); + gameMenusHidden = true; + logger::info("Game menus hidden for weather editor"); + } +} + +void EditorWindow::ShowGameMenus() +{ + if (!gameMenusHidden) + return; + + if (auto ui = RE::UI::GetSingleton()) { + ui->ShowMenus(true); + gameMenusHidden = false; + logger::info("Game menus restored after weather editor"); + } +} + void EditorWindow::EnterPreviewMode(PreviewMode mode) { if (mode == PreviewMode::None) diff --git a/src/WeatherEditor/EditorWindow.h b/src/WeatherEditor/EditorWindow.h index 251507ac69..d531e60cfb 100644 --- a/src/WeatherEditor/EditorWindow.h +++ b/src/WeatherEditor/EditorWindow.h @@ -96,6 +96,9 @@ class EditorWindow bool vanityCameraDisabled = false; float savedVanityCameraDelay = 180.0f; + // Game HUD hiding (tm equivalent) + bool gameMenusHidden = false; + void ShowObjectsWindow(); void ShowViewportWindow(); @@ -132,8 +135,14 @@ class EditorWindow // Check if ESC key should close the editor (no popups open) bool ShouldHandleEscapeKey() const; + static bool CanBeOpen(); void DisableVanityCamera(); void RestoreVanityCamera(); + void HideGameMenus(); + void ShowGameMenus(); + + /// Call every frame from the overlay renderer to track open/close transitions. + void UpdateOpenState(); // Undo system struct UndoState