From 2ba3c3e9fd1c4bd2de883eabb21135feddd3e020 Mon Sep 17 00:00:00 2001 From: Dlizzio <77717521+Dlizzio@users.noreply.github.com> Date: Tue, 24 Mar 2026 03:04:25 -0700 Subject: [PATCH 1/2] init --- .../Shaders/Menu/BackgroundBlurComposite.hlsl | 23 ++++---- src/Features/WeatherEditor.cpp | 8 ++- src/Menu.cpp | 2 +- src/Menu/BackgroundBlur.cpp | 21 +++++++- src/Menu/BackgroundBlur.h | 4 ++ src/Menu/OverlayRenderer.cpp | 7 +-- src/WeatherEditor/EditorWindow.cpp | 53 +++++++++++++++++-- src/WeatherEditor/EditorWindow.h | 9 ++++ 8 files changed, 100 insertions(+), 27 deletions(-) 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/Menu.cpp b/src/Menu.cpp index b85abe8571..cf54ee1a5c 100644 --- a/src/Menu.cpp +++ b/src/Menu.cpp @@ -1043,7 +1043,7 @@ void Menu::ProcessInputEventQueue() { settings.ShaderBlockPrevKey, [this, shaderCache]() { if (settings.EnableShaderBlocking) shaderCache->IterateShaderBlock(); } }, { settings.ShaderBlockNextKey, [this, shaderCache]() { if (settings.EnableShaderBlocking) shaderCache->IterateShaderBlock(false); } }, { settings.OverlayToggleKey, []() { Menu::GetSingleton()->overlayVisible = !Menu::GetSingleton()->overlayVisible; } }, - { settings.WeatherEditorToggleKey, []() { auto p = RE::PlayerCharacter::GetSingleton(); if (p && p->parentCell) EditorWindow::GetSingleton()->open = !EditorWindow::GetSingleton()->open; } }, + { settings.WeatherEditorToggleKey, []() { if (EditorWindow::CanBeOpen()) EditorWindow::GetSingleton()->open = !EditorWindow::GetSingleton()->open; } }, }; for (const auto& ka : keyActions) { // Check if key matches last key in combo and all modifiers are held (exact match) 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 503ec06569..c8a037f640 100644 --- a/src/Menu/OverlayRenderer.cpp +++ b/src/Menu/OverlayRenderer.cpp @@ -52,13 +52,10 @@ 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; - } + editorWindow->UpdateOpenState(); if (editorWindow->open) { ImGui::GetIO().MouseDrawCursor = true; editorWindow->Draw(); diff --git a/src/WeatherEditor/EditorWindow.cpp b/src/WeatherEditor/EditorWindow.cpp index 642a6aad0d..5f902bc5c5 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() io.FontGlobalScale = 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)) { @@ -1315,6 +1317,7 @@ void EditorWindow::OpenWeatherFeatureSetting(RE::TESWeather* weather, const std: EditorWindow::~EditorWindow() { + ShowGameMenus(); delete tempTexture; weatherWidgets.clear(); lightingTemplateWidgets.clear(); @@ -1347,23 +1350,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(); @@ -1841,6 +1848,13 @@ void EditorWindow::DrawTimeControls() ImGui::Text("Adjust how fast time passes (vanilla: %.1fx)", kVanillaTimeScale); } +bool EditorWindow::CanBeOpen() +{ + auto player = RE::PlayerCharacter::GetSingleton(); + auto* state = globals::state; + return player && player->parentCell && !state->isLoadingMenuOpen && !state->isMainMenuOpen; +} + void EditorWindow::DisableVanityCamera() { if (vanityCameraDisabled) @@ -1868,6 +1882,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"); + } +} + bool EditorWindow::ShouldHandleEscapeKey() const { return !ImGui::IsPopupOpen("", ImGuiPopupFlags_AnyPopupId | ImGuiPopupFlags_AnyPopupLevel); diff --git a/src/WeatherEditor/EditorWindow.h b/src/WeatherEditor/EditorWindow.h index 2ad7505865..36b4683f97 100644 --- a/src/WeatherEditor/EditorWindow.h +++ b/src/WeatherEditor/EditorWindow.h @@ -65,6 +65,9 @@ class EditorWindow bool vanityCameraDisabled = false; float savedVanityCameraDelay = 180.0f; + // Game HUD hiding (tm equivalent) + bool gameMenusHidden = false; + void ShowObjectsWindow(); void ShowViewportWindow(); @@ -101,8 +104,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 From 0f63accb5f8ae98ffc55988dee29a1128ebbc469 Mon Sep 17 00:00:00 2001 From: Dlizzio <77717521+Dlizzio@users.noreply.github.com> Date: Fri, 27 Mar 2026 09:15:44 -0700 Subject: [PATCH 2/2] global --- src/Globals.cpp | 2 ++ src/Globals.h | 1 + src/WeatherEditor/EditorWindow.cpp | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Globals.cpp b/src/Globals.cpp index e90c3bf4ce..d33e3dd3bb 100644 --- a/src/Globals.cpp +++ b/src/Globals.cpp @@ -106,6 +106,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; @@ -202,6 +203,7 @@ namespace globals void OnDataLoaded() { using namespace game; + player = RE::PlayerCharacter::GetSingleton(); sky = RE::Sky::GetSingleton(); utilityShader = RE::BSUtilityShader::GetSingleton(); diff --git a/src/Globals.h b/src/Globals.h index fa96446891..74a80986f3 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/WeatherEditor/EditorWindow.cpp b/src/WeatherEditor/EditorWindow.cpp index 88af59fec1..e0f19c744c 100644 --- a/src/WeatherEditor/EditorWindow.cpp +++ b/src/WeatherEditor/EditorWindow.cpp @@ -1923,7 +1923,7 @@ void EditorWindow::DrawTimeControls() bool EditorWindow::CanBeOpen() { - auto player = RE::PlayerCharacter::GetSingleton(); + auto* player = globals::game::player; auto* state = globals::state; return player && player->parentCell && !state->isLoadingMenuOpen && !state->isMainMenuOpen; }