Skip to content

feat(vr): add OpenComposite VR menu#1880

Merged
alandtse merged 11 commits into
community-shaders:devfrom
alandtse:open_composite
Feb 15, 2026
Merged

feat(vr): add OpenComposite VR menu#1880
alandtse merged 11 commits into
community-shaders:devfrom
alandtse:open_composite

Conversation

@alandtse
Copy link
Copy Markdown
Collaborator

@alandtse alandtse commented Feb 15, 2026

Implements VR menu overlay rendering using IVRCompositor::Submit hook, providing full compatibility with OpenComposite and SteamVR.

Key Features:

  • In-scene overlay rendering via submit hook (replaces OpenVR overlay API)
  • IPD-based stereo convergence with asymmetric projection correction
  • Multiple attach modes: HMD-relative, Controller-attached, Fixed World, None
  • VR controller input with customizable button mappings
  • Grip-to-drag positioning with depth control via thumbstick
  • Backface culling for controller-attached overlays
  • Proper HLSL shader deployment (InSceneOverlay.vs/ps.hlsl)

Technical Implementation:

  • Fixed OpenVR GetProjectionRaw top/bottom swap bug (Valve issue #110)
  • DirectX row-major matrix conversion in HmdMatrix34ToMatrix
  • Proper aspect ratio handling throughout rendering pipeline
  • Migration system for legacy settings (Keyboard deserialization fix)
  • Input guards prevent VR controls from interfering with gameplay
  • Production-ready logging (debug level for diagnostics)

User Experience:

  • Welcome screen with auto-hide timer and usage instructions
  • VR-optimized default overlay positions (user-tested)
  • Comprehensive settings UI with live controller diagnostics
  • Keyboard-style button combo recording system
  • Visual feedback during drag operations

OpenVR Detection:

  • Runtime interface probing via VR_IsInterfaceVersionValid
  • Removed file-based whitelist (obsolete)
  • Compatible with OpenComposite and SteamVR

Fixes:

  • Settings now properly loaded from SettingsUser.json
  • Drag highlight cleared when menu closes
  • All VR inputs guarded by menu open state
  • Controller convergence improved with better default offsets

Summary by CodeRabbit

  • New Features

    • In‑scene VR overlay with HMD/Controller/Fixed‑world attach modes, stereo rendering and new shaders
    • Wand pointing, manual wand intersection, thumbstick cursor/scroll, expanded VR input/event handling
    • OpenVR/OpenComposite runtime detection with richer runtime diagnostics and plugin probing
    • Comprehensive VR settings UI, combo recording, and controller diagnostics
  • Improvements

    • Depth‑aware grip+thumbstick drag controls, fixed‑world auto‑reset and persistent placement
    • Unified shared menu texture, consolidated submission/render flow, robustness and logging enhancements
  • Chores

    • Removed legacy overlay helper utilities and public APIs

…ering

Implements VR menu overlay rendering using IVRCompositor::Submit hook,
providing full compatibility with OpenComposite and SteamVR.

Key Features:
- In-scene overlay rendering via submit hook (replaces OpenVR overlay API)
- IPD-based stereo convergence with asymmetric projection correction
- Multiple attach modes: HMD-relative, Controller-attached, Fixed World, None
- VR controller input with customizable button mappings
- Grip-to-drag positioning with depth control via thumbstick
- Backface culling for controller-attached overlays
- Proper HLSL shader deployment (InSceneOverlay.vs/ps.hlsl)

Technical Implementation:
- Fixed OpenVR GetProjectionRaw top/bottom swap bug (Valve issue community-shaders#110)
- DirectX row-major matrix conversion in HmdMatrix34ToMatrix
- Proper aspect ratio handling throughout rendering pipeline
- Migration system for legacy settings (Keyboard deserialization fix)
- Input guards prevent VR controls from interfering with gameplay
- Production-ready logging (debug level for diagnostics)

User Experience:
- Welcome screen with auto-hide timer and usage instructions
- VR-optimized default overlay positions (user-tested)
- Comprehensive settings UI with live controller diagnostics
- Keyboard-style button combo recording system
- Visual feedback during drag operations

OpenVR Detection:
- Runtime interface probing via VR_IsInterfaceVersionValid
- Removed file-based whitelist (obsolete)
- Compatible with OpenComposite and SteamVR

Fixes:
- Settings now properly loaded from SettingsUser.json
- Drag highlight cleared when menu closes
- All VR inputs guarded by menu open state
- Controller convergence improved with better default offsets

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 15, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a complete in‑scene VR overlay system: new shaders, IVRCompositor Submit hook, D3D in‑scene renderer, wand‑pointing and thumbstick/input integration, grip+thumbstick depth drag, fixed‑world positioning, OpenVR runtime detection, and a new VR settings UI.

Changes

Cohort / File(s) Summary
Shaders
package/Shaders/VR/InSceneOverlay.vs.hlsl, package/Shaders/VR/InSceneOverlay.ps.hlsl
New vertex and pixel shaders for an in‑scene overlay quad (WVP transform, UV passthrough, texture sampling).
In‑scene overlay renderer & hook
src/Features/VR/InSceneOverlay.cpp
Adds IVRCompositor::Submit hook and full in‑scene renderer: shader compilation, input layout, vertex/index buffers, constant buffers, render states, per‑eye RTV/viewport handling, IPD/convergence math, and robust state preservation/restoration.
Core VR integration & API
src/Features/VR.cpp, src/Features/VR.h
Refactors overlay sizing to Config constants; exposes IsOpenVRCompatible, ComputeWandIntersection(Manual), SubmitOverlayFrame, UpdateFixedWorldPositioning, InitInSceneResources/Render/InstallSubmitHook; consolidates shared menu texture, expands drag/depth controls, and surfaces OpenVR probing/state.
Wand pointing & input
src/Features/VR/WandPointing.cpp, src/Features/VR/Input.cpp
Adds wand‑ray intersection APIs, UpdateCursorFromWandPointing, VR event processing, thumbstick→scroll handling, controller state updates, and ImGui input binding.
Overlay drag & positioning
src/Features/VR/OverlayDrag.cpp
New drag subsystem supporting Controller / FixedWorld / HMD modes: grip detection, drag lifecycle, depth control via thumbstick, haptics, auto‑reset, and fixed‑world persistence.
Settings UI
src/Features/VR/SettingsUI.cpp
New VR settings UI: General/Menu/Input/Drag panels, combo recording for bindings, diagnostics, and detailed OpenVR info display.
OpenVR detection
src/Features/VR/OpenVRDetection.h, src/Features/VR/OpenVRDetection.cpp
New VRDetection API: DLL metadata gathering, runtime heuristics (SteamVR/OpenComposite/Unknown), and probing for Overlay/System/Compositor interfaces with Detect() entrypoint.
Utilities (API removals & additions)
src/Utils/VRUtils.h, src/Utils/VRUtils.cpp
Removed legacy helper APIs (CreateControllerOverlayTransform, SetOverlayInputFlags, GetControllerDeviceColor, ComputeWandIntersection). Updated HmdMatrix34↔4x4 conversions and added Util::GetIPDFromHMD().
Menu lifecycle
src/Menu.cpp
Removed VR overlay destruction and conditional overlay init/shutdown from Menu; lifecycle now handled in VR subsystem.
Multiple VR modules
src/Features/VR/*.cpp, src/Features/VR/*.h
Many new/modified VR subsystems (Input, WandPointing, OverlayDrag, InSceneOverlay, SettingsUI, OpenVRDetection) and public API extensions across VR headers/impls.

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant Comp as OpenVR Compositor
    participant Hook as Submit Hook
    participant VR as In‑Scene Renderer
    participant D3D as Direct3D
    participant Input as VR Input

    App->>Comp: Submit(eye, texture, bounds)
    Comp->>Hook: IVRCompositor_Submit thunk invoked
    Hook->>VR: Validate overlay enabled & attach mode, request poses
    Input->>VR: Provide HMD/controller poses and wand intersections
    VR->>D3D: Create/locate RTV/SRV, set shaders, constant buffers, viewport, states
    VR->>D3D: Draw overlay quad per‑eye (apply WVP/IPD/convergence)
    VR->>D3D: Restore device state
    Hook-->>Comp: Forward Submit to original compositor
    Comp-->>App: Submit completes
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Suggested reviewers

  • doodlum
  • jiayev

Poem

🐇 I hopped through shaders, matrices, and light,
I nudged the menu farther with a thumbstick bite,
Rays find UVs, cursors dance on cue,
Haptics hum — the drag begins anew,
I nibble code, then vanish into night.

🚥 Pre-merge checks | ✅ 2 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (47 files):

⚔️ features/Dynamic Cubemaps/Shaders/DynamicCubemaps/DynamicCubemaps.hlsli (content)
⚔️ package/Shaders/Common/SharedData.hlsli (content)
⚔️ package/Shaders/DistantTree.hlsl (content)
⚔️ package/Shaders/Effect.hlsl (content)
⚔️ package/Shaders/ISSAOComposite.hlsl (content)
⚔️ package/Shaders/Lighting.hlsl (content)
⚔️ package/Shaders/RunGrass.hlsl (content)
⚔️ package/Shaders/Water.hlsl (content)
⚔️ src/Feature.cpp (content)
⚔️ src/FeatureBuffer.cpp (content)
⚔️ src/Features/GrassLighting.h (content)
⚔️ src/Features/LightLimitFix.cpp (content)
⚔️ src/Features/LightLimitFix.h (content)
⚔️ src/Features/VR.cpp (content)
⚔️ src/Features/VR.h (content)
⚔️ src/Features/WeatherEditor.cpp (content)
⚔️ src/Features/WeatherEditor.h (content)
⚔️ src/Globals.cpp (content)
⚔️ src/Globals.h (content)
⚔️ src/Hooks.cpp (content)
⚔️ src/Menu.cpp (content)
⚔️ src/Menu/OverlayRenderer.cpp (content)
⚔️ src/ShaderCache.cpp (content)
⚔️ src/ShaderCache.h (content)
⚔️ src/Utils/VRUtils.cpp (content)
⚔️ src/Utils/VRUtils.h (content)
⚔️ src/WeatherEditor/EditorWindow.cpp (content)
⚔️ src/WeatherEditor/EditorWindow.h (content)
⚔️ src/WeatherEditor/Weather/CellLightingWidget.cpp (content)
⚔️ src/WeatherEditor/Weather/CellLightingWidget.h (content)
⚔️ src/WeatherEditor/Weather/ImageSpaceWidget.cpp (content)
⚔️ src/WeatherEditor/Weather/ImageSpaceWidget.h (content)
⚔️ src/WeatherEditor/Weather/LensFlareWidget.cpp (content)
⚔️ src/WeatherEditor/Weather/LensFlareWidget.h (content)
⚔️ src/WeatherEditor/Weather/LightingTemplateWidget.cpp (content)
⚔️ src/WeatherEditor/Weather/LightingTemplateWidget.h (content)
⚔️ src/WeatherEditor/Weather/PrecipitationWidget.cpp (content)
⚔️ src/WeatherEditor/Weather/PrecipitationWidget.h (content)
⚔️ src/WeatherEditor/Weather/ReferenceEffectWidget.cpp (content)
⚔️ src/WeatherEditor/Weather/ReferenceEffectWidget.h (content)
⚔️ src/WeatherEditor/Weather/VolumetricLightingWidget.cpp (content)
⚔️ src/WeatherEditor/Weather/VolumetricLightingWidget.h (content)
⚔️ src/WeatherEditor/Weather/WeatherWidget.cpp (content)
⚔️ src/WeatherEditor/Weather/WeatherWidget.h (content)
⚔️ src/WeatherEditor/Widget.cpp (content)
⚔️ src/WeatherEditor/Widget.h (content)
⚔️ src/XSEPlugin.cpp (content)

These conflicts must be resolved before merging into dev.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'feat(vr): add OpenComposite VR menu' accurately captures the primary change—adding VR menu support for OpenComposite. However, it omits significant scope details (in-scene overlay rendering, wand pointing, drag functionality, input handling) that are part of the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
⚔️ Resolve merge conflicts (beta)
  • Auto-commit resolved conflicts to branch open_composite
  • Post resolved changes as copyable diffs in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Feb 15, 2026

Using provided base ref: eca8716
Using base ref: eca8716
Base commit date: 2026-02-14T18:29:27-08:00 (Saturday, February 14, 2026 06:29 PM)
No actionable suggestions for changed features.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/Utils/VRUtils.h (1)

189-225: ⚠️ Potential issue | 🔴 Critical

MatrixToHmdMatrix34 is not the inverse of HmdMatrix34ToMatrix — round-trip conversions will fail.

HmdMatrix34ToMatrix transposes the rotation and places translation in row 4 (correct for OpenVR column-vector → DirectX row-vector conversion). However, MatrixToHmdMatrix34 (lines 209–225) performs a direct element copy without transposing back. Since this function is actively used in src/Features/VR.cpp to convert matrices back to OpenVR format for overlay transforms, a round-trip HmdMatrix34_t → Matrix → HmdMatrix34_t produces incorrect results: the rotation is transposed twice and translation is lost.

Proposed fix
 inline vr::HmdMatrix34_t MatrixToHmdMatrix34(const Matrix& mat)
 {
     vr::HmdMatrix34_t m{};
-    m.m[0][0] = mat._11;
-    m.m[0][1] = mat._12;
-    m.m[0][2] = mat._13;
-    m.m[0][3] = mat._14;
-    m.m[1][0] = mat._21;
-    m.m[1][1] = mat._22;
-    m.m[1][2] = mat._23;
-    m.m[1][3] = mat._24;
-    m.m[2][0] = mat._31;
-    m.m[2][1] = mat._32;
-    m.m[2][2] = mat._33;
-    m.m[2][3] = mat._34;
+    // Transpose rotation back (row-vector → column-vector) and extract translation from row 4
+    m.m[0][0] = mat._11; m.m[0][1] = mat._21; m.m[0][2] = mat._31; m.m[0][3] = mat._41;
+    m.m[1][0] = mat._12; m.m[1][1] = mat._22; m.m[1][2] = mat._32; m.m[1][3] = mat._42;
+    m.m[2][0] = mat._13; m.m[2][1] = mat._23; m.m[2][2] = mat._33; m.m[2][3] = mat._43;
     return m;
 }
🤖 Fix all issues with AI agents
In `@src/Features/VR_InSceneOverlay.cpp`:
- Around line 46-57: The thunk in IVRCompositor_Submit unsafely casts
pTexture->handle to ID3D11Texture2D* without checking the texture type; modify
IVRCompositor_Submit::thunk to first verify pTexture and pTexture->eType ==
vr::TextureType_DirectX before casting, only call
globals::features::vr.RenderInSceneOverlay(eEye, (ID3D11Texture2D*)..., pBounds)
when that check passes, and otherwise skip the DirectX-specific call (still
forward to func) to avoid UB for OpenGL/Vulkan textures.
- Around line 449-452: The code currently calls
globals::d3d::device->CreateShaderResourceView(menuTexture.get(), ...) inside
drawOverlayQuad every frame; instead add members to InSceneResources (e.g.,
winrt::com_ptr<ID3D11ShaderResourceView> menuSRV and ID3D11Texture2D*
cachedMenuTexture) and move SRV creation to RenderInSceneOverlay so you only
call CreateShaderResourceView when menuTexture.get() !=
inSceneResources.cachedMenuTexture (set menuSRV = nullptr, create new SRV into
inSceneResources.menuSRV, update cachedMenuTexture), and then change
drawOverlayQuad to use inSceneResources.menuSRV (bind its .get() to
PSSetShaderResources) rather than creating a temp SRV per draw.
- Around line 109-184: All D3D Create* calls (device->CreateInputLayout,
CreateBuffer for vertex/index/constant buffers, CreateBlendState,
CreateDepthStencilState, CreateRasterizerState, CreateSamplerState) must have
their HRESULT checked immediately; if any fail, set the object's initialized
flag to false (or return/bail early) and avoid later dereferencing in
RenderInSceneOverlay, and log the error; update each call that writes into
inSceneResources (inSceneResources.inputLayout, vb, ib, cb, blendState,
depthState, rasterizerState, sampler) to validate the returned HRESULT and
handle the failure path consistently.
- Around line 68-89: The code currently compiles the vertex shader twice
(Util::CompileShader and D3DCompileFromFile) and leaks blobs and errors; change
the flow to compile once with D3DCompileFromFile into vsBlob (and handle/release
errorBlob if non-null), then create the ID3D11VertexShader from vsBlob and
attach it via inSceneResources.vs.attach, and use that same vsBlob for
CreateInputLayout; ensure you Release vsBlob after creating both the shader and
input layout; add an HRESULT check for CreateInputLayout and log and clean up
(release attached shader/input layout) if it fails so initialization cannot
silently continue with a bad layout.

In `@src/Features/VR.cpp`:
- Around line 2653-2654: The wand hit-test uses a uniform scale (overlayWorld =
Matrix::CreateScale(settings.VRMenuScale)) but rendering uses an
aspect-corrected scale from CreateOverlayScaleMatrix, causing vertical
misalignment; update the scaling here to match rendering by applying the same
non-uniform scale (scale, scale * kOverlayAspect, scale) used in
CreateOverlayScaleMatrix (or move CreateOverlayScaleMatrix into a shared header
and call it here) so overlayWorld uses the identical aspect-corrected transform
(referencing overlayWorld, Matrix::CreateScale, CreateOverlayScaleMatrix,
settings.VRMenuScale, kOverlayAspect, and RenderInSceneOverlay).
🧹 Nitpick comments (6)
src/VR/OpenVRDetection.cpp (1)

93-116: Hardcoded heuristics for runtime detection are fragile.

The detection relies on a fixed version string ("1.0.10.0"), file size threshold (< 700000), and path substrings. These will silently misclassify if OpenComposite ships a new version or changes its DLL size. The interface probing in ProbeRuntimeInterfaces is the robust signal — consider making DetectRuntimeType a secondary hint rather than a primary classifier, or at least logging when heuristics disagree with probing results so users can report misdetections.

That said, this is pragmatic for the VR modding ecosystem and non-blocking.

package/Shaders/VR/InSceneOverlay.vs.hlsl (1)

1-27: Add row_major qualifier to match project convention.

The shader's matrix handling is functionally correct (the C++ code transposes before upload), but inconsistent with the codebase. All other shaders in the project explicitly declare matrices as row_major float4x4, which aligns with how SimpleMath matrices are handled elsewhere. Change cbuffer MatrixBuffer to use row_major matrix wvp; and remove the transpose operations in VR_InSceneOverlay.cpp for consistency with project conventions.

src/Features/VR_InSceneOverlay.cpp (3)

230-267: Repetitive perf->EndEvent() cleanup on every early return is fragile.

There are 6+ early-return sites that each manually call perf->EndEvent(). Missing one (or adding a new return without it) corrupts GPU profiler state. Use an RAII scope guard to guarantee the call.

Suggested scope guard
+	// Ensure EndEvent is called regardless of return path
+	auto perfGuard = [&perf]() {
+		if (perf) perf->EndEvent();
+	};
+	// Use a simple RAII wrapper
+	struct ScopeGuard {
+		std::function<void()> fn;
+		~ScopeGuard() { fn(); }
+	} guard{ perfGuard };
+
 	if (!inSceneResources.initialized)
 		InitInSceneResources();
 	if (!inSceneResources.initialized) {
-		if (perf)
-			perf->EndEvent();
 		return;
 	}

Then remove all other perf->EndEvent() + return blocks and just return; directly.


359-624: Incomplete D3D state save/restore — blend, depth-stencil, shaders, etc. are not restored.

The function saves/restores RTVs, DSV, viewports, and rasterizer state, but leaves the pipeline modified for: VS, PS, blend state, depth-stencil state, constant buffers, vertex/index buffers, input layout, topology, SRVs, and samplers. Since this runs in the Submit hook (end of frame), the corruption likely doesn't affect rendering. However, if any code path executes after Submit (diagnostics, other hooks), it will encounter unexpected state.

Consider using ID3DUserDefinedAnnotation already obtained, or a full state block save/restore via ID3D11DeviceContext1::SwapDeviceContextState or manual save/restore of the remaining states for robustness.


321-321: force2D is hardcoded false — the entire if (force2D) block (lines 464–576) is dead code.

Over 100 lines of the stereo-convergence / screen-space overlay path are unreachable. If this is intentionally preserved for future use, consider guarding it with a #if 0 or removing it and keeping a comment pointing to the git history.

Also applies to: 464-576

src/Features/VR.cpp (1)

2544-2551: Fragile identity-matrix check for "uninitialized" state.

Testing specific float members (_41 == 0.0f && _42 == 0.0f && _43 == 0.0f && _11 == 1.0f) to detect an uninitialized overlay position is brittle — exact float comparisons and the possibility (however unlikely) that a valid pose has zero translation. A dedicated bool fixedWorldInitialized = false; flag on OverlayWorldPosition would be more robust.

Comment thread src/Features/VR/InSceneOverlay.cpp
Comment thread src/Features/VR_InSceneOverlay.cpp Outdated
Comment thread src/Features/VR_InSceneOverlay.cpp Outdated
Comment thread src/Features/VR_InSceneOverlay.cpp Outdated
Comment thread src/Features/VR.cpp Outdated
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Feb 15, 2026

✅ A pre-release build is available for this PR:
Download

alandtse and others added 3 commits February 14, 2026 18:04
…ze structure

Critical Bug Fix:
- Fixed MatrixToHmdMatrix34 transpose bug (CodeRabbit PR#1880 review)
  - Function was not inverting HmdMatrix34ToMatrix transformation
  - Now properly transposes rotation and extracts translation from row 4
  - Round-trip conversions (HmdMatrix34 -> Matrix -> HmdMatrix34) now work correctly
  - This affected overlay positioning when using Fixed World and drag operations

Code Organization:
- Removed IsEffectivelyCompatible() function (unnecessary churn)
  - Reverted all call sites back to IsOpenVRCompatible()
  - Removed obsolete developer mode override (no longer needed without whitelist)
  - Simplified compatibility UI code
- Removed unused HmdMatrix44ToMatrix() dead code (never called)
- Reorganized VR feature into proper subdirectory structure:
  - Moved src/VR/ -> src/Features/VR/ (follows project pattern)
  - Renamed VR_InSceneOverlay.cpp -> VR/InSceneOverlay.cpp
  - Now matches architecture used by PerformanceOverlay/, Upscaling/, etc.

Files affected:
- src/Utils/VRUtils.h (CRITICAL matrix fix)
- src/Features/VR.{cpp,h} (removed IsEffectivelyCompatible, dead code)
- src/Features/VR/InSceneOverlay.cpp (moved from VR_InSceneOverlay.cpp)
- src/Features/VR/OpenVRDetection.{cpp,h} (moved from src/VR/)
- src/Hooks.cpp, src/Menu.cpp, src/Menu/OverlayRenderer.cpp (call site updates)

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
All CodeRabbit PR#1880 Review Fixes Applied:
1. Texture type checking: Submit hook now verifies eType == TextureType_DirectX
2. HRESULT error checking: All D3D Create* calls now check and log errors
3. SRV caching: menuSRV cached in InSceneResources, only recreated when texture changes
4. Removed duplicate shader compilation: compile once, create shader from bytecode
5. Eliminated duplicate constants: moved kOverlayWidth/Height/Aspect to VR::Config
6. Moved GetIPDFromHMD to VRUtils.h: general utility, not overlay-specific

Changes:
- InSceneOverlay submit hook guards against non-DirectX textures (prevents UB)
- All device->CreateInputLayout/Buffer/BlendState/etc now have HRESULT checks
- Performance: SRV creation reduced from every frame to only when texture changes
- DRY: Single source of truth for overlay dimensions in VR::Config struct
- Code organization: GetIPDFromHMD now in Util namespace (proper utility location)

Files:
- src/Utils/VRUtils.h (added GetIPDFromHMD utility function)
- src/Features/VR.h (added overlay constants to Config, SRV caching members)
- src/Features/VR.cpp (use Config:: prefix, removed duplicates)
- src/Features/VR/InSceneOverlay.cpp (all fixes, removed GetIPDFromHMD duplicate)

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/Features/VR/InSceneOverlay.cpp`:
- Around line 46-232: The function InitInSceneResources can leave
inSceneResources partially populated and subsequent calls will assert because
winrt::com_ptr::put() requires a null internal pointer; fix by resetting all COM
members at the start (or build into a local InSceneResources and only assign to
inSceneResources on full success). Specifically, before any D3D calls, call
reset() (or equivalent) on inSceneResources.inputLayout, inSceneResources.vb,
inSceneResources.ib, inSceneResources.cb, inSceneResources.vs,
inSceneResources.ps, inSceneResources.blendState, inSceneResources.depthState,
inSceneResources.rasterizerState, inSceneResources.sampler (or construct/operate
on a local temp InSceneResources and move it into inSceneResources only if
initialization reaches the end), then proceed with the existing shader/
buffer/state creation and set inSceneResources.initialized = true only after all
resources are created successfully.

In `@src/Features/VR/OpenVRDetection.cpp`:
- Around line 52-54: GetModuleFileNameA's current check only treats 0 as failure
and misses buffer truncation; call GetModuleFileNameA into a DWORD (e.g., len)
and treat it as an error if len == 0 OR if len == MAX_PATH and GetLastError() ==
ERROR_INSUFFICIENT_BUFFER, then bail out. Update the check around dllPath and
hModule to use this len+GetLastError logic so truncated paths are detected and
handled.
🧹 Nitpick comments (9)
src/Features/VR/OpenVRDetection.cpp (1)

93-116: Heuristic runtime detection may produce false positives as OpenComposite evolves.

The version/size check ("1.0.10.0" && fileSize < 700000) and the broad "steam" substring match are fragile — a user directory containing "steam" in the path would trigger SteamVR classification, and OpenComposite version bumps would break detection. Since runtimeType appears informational (actual compatibility is determined by ProbeRuntimeInterfaces), this is acceptable, but worth noting for future maintenance.

src/Features/VR/InSceneOverlay.cpp (3)

33-43: Prefer static_cast over C-style cast for pTexture->handle.

The texture type guard on line 37 makes the cast safe, but static_cast<ID3D11Texture2D*>(pTexture->handle) is the idiomatic C++ form and communicates intent more clearly.


333-367: RTV is created per eye per frame — consider caching.

CreateRenderTargetView on line 359 is called every frame for each eye. If the target texture doesn't change between frames (or only changes once per session), caching the RTV keyed by the texture pointer and descriptor would avoid repeated D3D device calls on the hot path.


280-283: Large stack allocation in per-frame render path.

vr::TrackedDevicePose_t renderPose[vr::k_unMaxTrackedDeviceCount] allocates ~6.4 KB on the stack every frame. Only the HMD and at most 2 controller poses are needed. Consider using a smaller fixed-size array or a static/member buffer.

src/Features/VR.h (1)

485-492: Misleading public: access specifier with "PRIVATE IMPLEMENTATION" comment.

Line 485 declares public: but the section header on lines 486-488 says "PRIVATE IMPLEMENTATION". DetectOpenVRInfo() and IsOpenVRCompatible() are exposed as public API despite the comment. If these are intended to be private, use private: instead.

Suggested fix
-public:
 	//=============================================================================
 	// PRIVATE IMPLEMENTATION
 	//=============================================================================
+private:
 
 	void DetectOpenVRInfo();
+
+public:
 	bool IsOpenVRCompatible() const;
src/Features/VR.cpp (4)

1599-1635: SubmitOverlayFrame saves/restores only 1 RTV — potential state leak.

Line 1619 saves only a single RTV (OMGetRenderTargets(1, &oldRTV, nullptr)), but if multiple RTVs are bound at this point, the rest will be unbound after the restore on line 1626. The InSceneOverlay code correctly saves all D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT RTVs. Consider matching that approach here for safety, or document why a single RTV is sufficient at this call site.


2526-2559: "Uninitialized" detection for fixed world position is fragile.

Lines 2532-2535 detect an uninitialized overlay position by checking _41 == 0 && _42 == 0 && _43 == 0 && _11 == 1. An overlay legitimately placed at the world origin with default rotation would match this check. A dedicated bool isInitialized flag in OverlayWorldPosition would be more robust.

Suggested approach
 struct OverlayWorldPosition
 {
 	Matrix m = Matrix::Identity;
+	bool isInitialized = false;
 } fixedWorldOverlayPosition;

Then in UpdateFixedWorldPositioning:

-	bool isUninitialized = (fixedWorldOverlayPosition.m._41 == 0.0f &&
-							fixedWorldOverlayPosition.m._42 == 0.0f &&
-							fixedWorldOverlayPosition.m._43 == 0.0f &&
-							fixedWorldOverlayPosition.m._11 == 1.0f);
-	if (isUninitialized) {
+	if (!fixedWorldOverlayPosition.isInitialized) {
 		SetFixedOverlayToCurrentHMD();
+		fixedWorldOverlayPosition.isInitialized = true;

1862-1862: Unnecessary (void)event;event is used on the very next lines.

event is referenced on lines 1863–1864 (event.device), so the void cast to suppress unused-variable warnings is misleading. Remove it.

Suggested fix
 	ImGuiIO& io = ImGui::GetIO();
-	(void)event;
 	bool isPrimary = RE::BSOpenVRControllerDevice::IsPrimaryController(event.device);

2565-2582: DetectOpenVRInfo manually copies every field — consider direct assignment.

The field-by-field copy from VRDetection::OpenVRDetectionResult to OpenVRInfo is verbose and error-prone if fields are added to one struct but not the other. Since the structs have nearly identical fields, consider either reusing OpenVRDetectionResult directly or adding a conversion constructor/operator.

Comment thread src/Features/VR/InSceneOverlay.cpp
Comment thread src/Features/VR/OpenVRDetection.cpp
Removed obsolete OpenVR overlay creation/positioning code (~280 lines) that became
unnecessary after switching to submit hook rendering. Submit hook renders directly
into eye buffers without using OpenVR overlay API.

Changes:
- Removed UpdateVROverlayPosition() - 160 lines
- Removed UpdateVROverlayControllerPosition() - 42 lines
- Removed EnsureOverlayInitialized() - 60 lines
- Removed DestroyOverlay() - 18 lines
- Removed menuControllerTexture/RTV (only menuTexture needed)
- Simplified wand pointing: renamed ComputeManualWandIntersection -> ComputeWandIntersectionForOverlayType
- Fixed wand pointing to work without overlay handles (was checking invalid handles)

Wand pointing now works correctly using ray-quad intersection math instead of
relying on OpenVR overlay handles.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/Features/VR.cpp`:
- Around line 2360-2361: Replace the unqualified abs call with std::abs for the
float comparison on localDir.z (i.e., change abs(localDir.z) to
std::abs(localDir.z)); ensure the translation unit includes <cmath> (or
otherwise brings std::abs into scope) so the overload for floats is used and the
existing 1e-6f threshold remains unchanged, keeping consistency with other float
comparisons in this file.
🧹 Nitpick comments (7)
src/Features/VR.h (2)

450-469: Raw cachedMenuTexture pointer — document the non-owning intent.

cachedMenuTexture is a raw pointer used solely for cache-invalidation comparison, while menuSRV holds the actual resource. This is acceptable, but a brief comment clarifying it's non-owning would prevent future contributors from accidentally releasing it.

Suggested clarification
 		// Cached SRV to avoid creating every frame
 		winrt::com_ptr<ID3D11ShaderResourceView> menuSRV;
-		ID3D11Texture2D* cachedMenuTexture = nullptr;
+		ID3D11Texture2D* cachedMenuTexture = nullptr;  // Non-owning; used only for stale-check against menuTexture

480-487: Misleading public: label and comment mismatch.

Line 480 has public: and the comment on Line 482 says "PRIVATE IMPLEMENTATION", but DetectOpenVRInfo() and IsOpenVRCompatible() are declared public. If these are intended to be private, use private: instead. If public is intentional, update the comment.

src/Features/VR.cpp (5)

2248-2253: Fragile identity-matrix check for "uninitialized" state.

Checking specific matrix components (_41 == 0, _11 == 1) to detect an uninitialized identity matrix is brittle — a legitimately placed overlay could coincidentally have these values (e.g., at the world origin looking forward). Consider using a dedicated bool initialized = false; flag in OverlayWorldPosition instead.

Suggested approach

In VR.h, add an initialized flag:

 struct OverlayWorldPosition
 {
     Matrix m = Matrix::Identity;
+    bool initialized = false;
 } fixedWorldOverlayPosition;

Then in UpdateFixedWorldPositioning:

-	bool isUninitialized = (fixedWorldOverlayPosition.m._41 == 0.0f &&
-							fixedWorldOverlayPosition.m._42 == 0.0f &&
-							fixedWorldOverlayPosition.m._43 == 0.0f &&
-							fixedWorldOverlayPosition.m._11 == 1.0f);
-	if (isUninitialized) {
+	if (!fixedWorldOverlayPosition.initialized) {
+		fixedWorldOverlayPosition.initialized = true;

1636-1639: O(n) erase from front of std::vector on every event.

vrControllerEventLog.erase(vrControllerEventLog.begin()) shifts all elements each time the log exceeds 32 entries. With frequent VR controller events, this is wasteful. Consider using std::deque (O(1) pop_front) or a ring buffer.

Also applies to: 1667-1670


424-451: Duplicated combo-accept logic across Enter, ESC, and timeout handlers.

The switch-case block that applies recordedCombo to the correct settings vector and the state-reset sequence are copy-pasted three times (Enter at lines 426–451, timeout at lines 470–496, and ESC shares the reset). Extract a helper to reduce duplication.

Sketch
// Private helper
void VR::FinishComboRecording(bool accept) {
    if (accept && !recordedCombo.empty()) {
        switch (currentComboType) {
        case ComboType::MenuOpen:    settings.VRMenuOpenKeys = recordedCombo; break;
        case ComboType::MenuClose:   settings.VRMenuCloseKeys = recordedCombo; break;
        case ComboType::OverlayOpen: settings.VROverlayOpenKeys = recordedCombo; break;
        case ComboType::OverlayClose:settings.VROverlayCloseKeys = recordedCombo; break;
        default: break;
        }
    }
    isCapturingCombo = false;
    currentComboType = ComboType::None;
    currentComboName = nullptr;
    recordedCombo.clear();
    comboStartTime = 0.0;
    recordingButtonControllers.clear();
    ImGui::CloseCurrentPopup();
}

Also applies to: 466-497


1317-1352: SubmitOverlayFrame — render target leak if early-return before Release.

If the code enters the if block on line 1331 but hits an exception or early code path between saving oldRTV (line 1337) and the Release (line 1351), the old RTV leaks. The existing OverlayRenderContext RAII pattern (defined in VR.h lines 276–310) already handles save/restore. Consider using it here for consistency, or wrap oldRTV in a scope guard.


1954-1981: Debug logging with static locals in UpdateActiveDrag — multiple rate-limiters in one function.

There are two independent rate-limited log blocks (lines 1956–1961 and 1975–1981) that both fire every 500ms. The first logs local delta values and the second logs offset/scale. They could be consolidated into a single throttled log call to reduce clutter and static state.

Comment thread src/Features/VR.cpp Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Fix all issues with AI agents
In `@src/Features/VR.h`:
- Line 131: IsOverlayVisible() can dereference globals::menu before it's
initialized; update the return expression in IsOverlayVisible to first check
globals::menu is non-null (e.g., ensure globals::menu != nullptr) before reading
IsEnabled, while preserving the existing IsOpenVRCompatible() and
settings.kAutoHideSeconds checks so the method returns something like:
IsOpenVRCompatible() && settings.kAutoHideSeconds > 0 && globals::menu &&
!globals::menu->IsEnabled.

In `@src/Features/VR/Input.cpp`:
- Around line 353-364: The code in the usingCursorStick block unconditionally
calls io.AddMouseButtonEvent(ImGuiMouseButton_Left, false) which can override a
real trigger press handled in ProcessVRButtonEvent and swallow clicks; change
the logic to only emit the left-button release when the trigger is actually not
pressed (or when your VR trigger state indicates released) — e.g., query the
trigger/left-click state used by ProcessVRButtonEvent (or track an
isTriggerPressed flag) and only call AddMouseButtonEvent(ImGuiMouseButton_Left,
false) when that state is false (or when you detect a transition to released) so
stick movement won’t cancel an active press.
- Line 179: Remove the dead suppression "(void)event;" because the
parameter/event variable is actually used later in the function; locate the
occurrence of "(void)event;" in src/Features/VR/Input.cpp (the function that
takes the event parameter) and delete that line so the real usage of the event
variable is no longer masked.

In `@src/Features/VR/SettingsUI.cpp`:
- Around line 562-582: The polygon vertices passed to
drawList->AddConvexPolyFilled are wound incorrectly causing self-intersection;
in the quad handling after computing q1, q2, q3 (and center, radius) reorder the
ImVec2 poly array so the center is followed by the correct outward vertices
(e.g. {center, q2, q1, q3} or {center, q3, q1, q2}) instead of {center, q1, q2,
q3}; update the line that constructs ImVec2 poly[4] and keep the same call to
drawList->AddConvexPolyFilled(poly, 4, highlightCol).
- Around line 511-525: The "Reset to Defaults" handler sets VRMenuOpenKeys using
InputCombo::Primary but the canonical defaults use Secondary; update the reset
block that assigns settings.VRMenuOpenKeys to use InputCombo::Secondary for both
kXA and kBY (matching the VR.h default ButtonCombo::Secondary initialization) so
the reset restores the true defaults.

In `@src/Features/VR/WandPointing.cpp`:
- Around line 56-57: The check using abs(localDir.z) in WandPointing.cpp should
use the floating overload to avoid integer truncation; replace abs(localDir.z)
with std::abs(localDir.z) (or std::fabs(localDir.z)) and ensure <cmath> is
included so the correct float overload is picked; update the condition that
returns false to use std::abs(localDir.z) < 1e-6f.
🧹 Nitpick comments (7)
src/Features/VR.h (1)

480-488: "PRIVATE HELPERS" section is actually public.

VR is a struct (default public), and there's no private: specifier before these methods. The comment says "PRIVATE HELPERS" but GetGripPressed, ResetComboRecording, and ApplyRecordedCombo are publicly accessible. Similarly, line 488 re-declares public: for a section labeled "PRIVATE IMPLEMENTATION".

If these are intended to be internal, add private: before line 480.

Suggested fix
-	//=============================================================================
-	// PRIVATE HELPERS
-	//=============================================================================
+private:
+	//=============================================================================
+	// PRIVATE HELPERS
+	//=============================================================================
 
 	bool GetGripPressed(bool isLeft, bool isRight) const;
 	void ResetComboRecording();
 	void ApplyRecordedCombo();
 
-public:
 	//=============================================================================
 	// PRIVATE IMPLEMENTATION
 	//=============================================================================
src/Features/VR/WandPointing.cpp (1)

125-135: Redundant cursor position setting.

io.MousePos is set directly on line 132, then io.AddMousePosEvent is called on line 133. The AddMousePosEvent path is the modern ImGui input API and internally sets MousePos. Setting both is harmless but unnecessary.

Suggested simplification
 	if (intersected) {
 		float screenX = uv.x * io.DisplaySize.x;
 		float screenY = uv.y * io.DisplaySize.y;
 
 		screenX = std::clamp(screenX, 0.0f, io.DisplaySize.x);
 		screenY = std::clamp(screenY, 0.0f, io.DisplaySize.y);
 
-		io.MousePos = ImVec2(screenX, screenY);
 		io.AddMousePosEvent(screenX, screenY);
 		io.MouseDrawCursor = true;
 		io.WantSetMousePos = true;
src/Features/VR/Input.cpp (2)

220-234: Consider a fixed-size circular buffer for event logs instead of vector::erase(begin()).

Both ProcessVRButtonEvent and UpdateControllerState append to vrControllerEventLog and trim via erase(begin()), which is O(n) on each event for a std::vector. Since this is a diagnostic log capped at 32 entries, a std::deque (O(1) pop_front) or a ring buffer would be more efficient. Not critical since n=32, but it's a quick improvement.

Also applies to: 250-263


10-113: UpdateOverlayMenuStateFromInput — heap allocations every frame.

MenuStateMapping uses std::function (potential heap allocation) and the mappings vector is rebuilt every call. Since this is called per-frame, it contributes to allocation pressure. For a "Chill" review this is fine to defer, but converting to a static/stack-based dispatch table would be cleaner.

src/Features/VR/OverlayDrag.cpp (2)

340-344: isPrimary/isSecondary stores physical hand, not controller role — misleading.

overlayDragState.isPrimary is set to isLeft (left hand) and isSecondary to isRight (right hand). But these field names imply primary/secondary controller role, which is the opposite when left-handed mode is active. This causes confusing indirection in UpdateActiveDrag (lines 179–195) where handedness must be re-applied to map back.

Consider renaming the fields to isLeftHand/isRightHand for clarity, or storing the actual physical hand directly.


375-392: Fragile "uninitialized" detection heuristic for the identity matrix.

Checking _41 == 0 && _42 == 0 && _43 == 0 && _11 == 1.0f to detect an uninitialized overlay position will also match if the user deliberately places the overlay at the world origin. This could cause an unexpected position reset.

A more robust approach would be to use a dedicated bool isInitialized = false flag in OverlayWorldPosition.

Suggested approach (in VR.h)
 struct OverlayWorldPosition
 {
     Matrix m = Matrix::Identity;
+    bool isInitialized = false;
 } fixedWorldOverlayPosition;

Then in UpdateFixedWorldPositioning:

-	bool isUninitialized = (fixedWorldOverlayPosition.m._41 == 0.0f &&
-							fixedWorldOverlayPosition.m._42 == 0.0f &&
-							fixedWorldOverlayPosition.m._43 == 0.0f &&
-							fixedWorldOverlayPosition.m._11 == 1.0f);
-
-	if (isUninitialized) {
+	if (!fixedWorldOverlayPosition.isInitialized) {
+		fixedWorldOverlayPosition.isInitialized = true;
src/Features/VR/SettingsUI.cpp (1)

438-441: Fragile selectedComboIndex + 1 to ComboType cast.

static_cast<VR::ComboType>(selectedComboIndex + 1) relies on the ComboType enum values being contiguous starting from 1 and matching the comboTypes array order. If the enum is reordered or a value is inserted, this silently produces wrong mappings.

Consider using an explicit lookup array:

Suggested fix
+		static constexpr VR::ComboType kComboTypeMap[] = {
+			VR::ComboType::MenuOpen,
+			VR::ComboType::MenuClose,
+			VR::ComboType::OverlayOpen,
+			VR::ComboType::OverlayClose
+		};
 		if (ImGui::Button("Record Selected Combo")) {
 			vr.isCapturingCombo = true;
-			vr.currentComboType = static_cast<VR::ComboType>(selectedComboIndex + 1);
+			vr.currentComboType = kComboTypeMap[selectedComboIndex];

Comment thread src/Features/VR.h Outdated
Comment thread src/Features/VR/Input.cpp Outdated
Comment thread src/Features/VR/Input.cpp
Comment thread src/Features/VR/SettingsUI.cpp
Comment thread src/Features/VR/SettingsUI.cpp
Comment thread src/Features/VR/WandPointing.cpp Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/Utils/VRUtils.h`:
- Around line 229-243: The sanity-check ranges for the two IPD methods are
inconsistent; update the eye-transform branch so eyeSeparation uses the same
bounds as the property branch (match the ipd check) — replace the condition on
eyeSeparation in the GetEyeToHeadTransform branch (variables leftEye, rightEye,
eyeSeparation) with the same tolerance used earlier (e.g., eyeSeparation > 0.0f
&& eyeSeparation < 0.1f) so valid wide IPDs (e.g., ~0.085 m) are accepted
instead of falling through to the default.
- Around line 222-231: Initialize the vr::ETrackedPropertyError variable before
calling GetFloatTrackedDeviceProperty to avoid reading indeterminate memory;
change the declaration of error (currently "vr::ETrackedPropertyError error;")
to a defensive default (for example: "vr::ETrackedPropertyError error =
static_cast<vr::ETrackedPropertyError>(-1);") immediately before calling
vr::IVRSystem::GetFloatTrackedDeviceProperty with vr::Prop_UserIpdMeters_Float
and then keep the existing check against vr::TrackedProp_Success to decide
whether to return the ipd.

Comment thread src/Utils/VRUtils.h
Comment thread src/Utils/VRUtils.h
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In `@src/Features/VR/Input.cpp`:
- Around line 300-309: VR::ProcessControllerInputForImGui dereferences
globals::menu->IsEnabled without checking globals::menu for null; add a null
check at the start of the function (e.g., if (!globals::menu ||
!globals::menu->IsEnabled) return;) so the function returns early when
globals::menu is null, preserving existing behavior when the menu exists; modify
the guard that currently only checks IsEnabled to also verify globals::menu is
non-null before accessing IsEnabled.
- Around line 10-26: The function VR::UpdateOverlayMenuStateFromInput currently
takes references to globals::menu->IsEnabled and globals::menu->overlayVisible
without ensuring globals::menu is valid; add a null-check for globals::menu
(e.g., if (globals::menu == nullptr) return;) immediately after the
isCapturingCombo early return so you don't dereference a null pointer, then
proceed to create the bool& isEnabled and bool& overlayEnabled references and
the existing logic using settings.VRMenuControllerDiagnosticsTestMode and
isCapturingCombo unchanged.

In `@src/Features/VR/OverlayDrag.cpp`:
- Around line 53-71: In CanPerformDrag(), avoid dereferencing globals::menu
without a null check: add a guard that returns false if globals::menu is null
before accessing globals::menu->IsEnabled (same pattern used in IsOverlayVisible
and DrawSettings). Update the function to check globals::menu != nullptr (or
equivalent) immediately prior to testing IsEnabled so the subsequent logic
(including VR::CanPerformDrag and the settings checks) is executed only when
globals::menu is valid.

In `@src/Features/VR/WandPointing.cpp`:
- Around line 99-102: In VR::UpdateCursorFromWandPointing the code dereferences
globals::menu->IsEnabled without verifying globals::menu is non-null; add a null
check for globals::menu before accessing IsEnabled (same pattern used in
CanPerformDrag) so the early-return condition becomes guarded by checking
globals::menu != nullptr and settings.EnableWandPointing, ensuring you reference
the function name UpdateCursorFromWandPointing and the symbol
globals::menu->IsEnabled when making the fix.
- Around line 86-96: ComputeWandIntersection never sets wandState.rayOrigin or
wandState.rayDirection so the debug UI shows zeros; after you compute the
picking ray (e.g., in ComputeWandIntersectionForOverlayType where the ray is
generated) or immediately in ComputeWandIntersection when a hit occurs, assign
the computed ray origin and direction into wandState.rayOrigin and
wandState.rayDirection (using the same vector types used for outUV/outRay) so
the debug UI reflects the actual ray; reference
ComputeWandIntersectionForOverlayType and ComputeWandIntersection and update
wandState.rayOrigin and wandState.rayDirection alongside
wandState.isIntersecting/uvCoordinates/controllerIndex.
🧹 Nitpick comments (3)
src/Features/VR.h (1)

64-71: Widened scale range (0.1–5.0) — verify downstream consumers handle extremes gracefully.

The range was widened significantly from [0.5, 2.0] to [0.1, 5.0]. At 0.1× scale the overlay may become unusably small, and at 5× it could cover excessive screen area or cause rendering artifacts. This is fine if the slider UX makes it hard to land on extremes accidentally, but worth confirming the rendering path handles these bounds without issues.

src/Features/VR/OverlayDrag.cpp (1)

340-344: Misleading field names: isPrimary/isSecondary store left/right hand, not controller role.

overlayDragState.isPrimary is assigned isLeft and overlayDragState.isSecondary is assigned isRight. This works because GetGripPressed takes (isLeft, isRight) parameters, but the naming is confusing — "primary" typically means the dominant-hand controller in this codebase, not the physical left hand.

Consider renaming to isLeftHand/isRightHand for clarity.

src/Features/VR/Input.cpp (1)

219-233: Consider extracting the repeated event-log-append-and-trim pattern.

The same log entry construction + push_back + size-check + erase(begin()) pattern appears in both ProcessVRButtonEvent (Lines 219–233) and UpdateControllerState (Lines 249–262). A small helper (or switching to a bounded ring buffer / std::deque) would reduce duplication.

Also applies to: 249-262

Comment thread src/Features/VR/Input.cpp
Comment thread src/Features/VR/Input.cpp
Comment thread src/Features/VR/OverlayDrag.cpp
Comment thread src/Features/VR/WandPointing.cpp
Comment thread src/Features/VR/WandPointing.cpp
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/Features/VR.h (1)

414-414: ⚠️ Potential issue | 🟠 Major

Duplicate comboTimeout member shadows settings.comboTimeout.

VR::comboTimeout (Line 414, double, default 3.0) is a separate field from Settings::comboTimeout (Line 206, float, default 3.0f). The settings UI slider modifies settings.comboTimeout, but the combo recording logic in SettingsUI.cpp reads this->comboTimeout. This means the slider has no effect on recording behavior.

Remove this member and use settings.comboTimeout throughout, or sync them in LoadSettings().

🤖 Fix all issues with AI agents
In `@src/Features/VR/Input.cpp`:
- Around line 142-161: The loop over kVRButtons uses predicate functions
(desc.isButton(event.keyCode)) which causes Grip/GripAlt and
TouchpadClick/TouchpadAlt to collide because they share the same predicate;
change the matching to compare event.keyCode directly against the descriptor key
(e.g., replace desc.isButton(event.keyCode) with event.keyCode == desc.keyCode)
so each VRButtonDescriptor in kVRButtons is matched by its unique desc.keyCode
and the correct controller state
(primaryControllerState/secondaryControllerState) is updated via
state->OnEvent(...).

In `@src/Features/VR/InSceneOverlay.cpp`:
- Around line 256-260: The code dereferences globals::menu without checking for
null in the Submit hook; add a null check before accessing
globals::menu->IsEnabled and globals::menu->overlayVisible (e.g., treat
globals::menu == nullptr as menu disabled/hidden) so the if condition becomes
safe, and ensure perf->EndEvent() still runs when returning early; update the
condition around globals::menu, IsEnabled, overlayVisible and
settings.kAutoHideSeconds in the function handling IVRCompositor::Submit to
avoid crashes when the menu system is uninitialized.

In `@src/Features/VR/OverlayDrag.cpp`:
- Around line 175-210: The thumbstick depth adjustments on
overlayDragState.initialHMDOffset.z and initialControllerOffset.z are unbounded;
after computing depthDelta in the joystick depth control block inside
OverlayDrag.cpp (the section that checks overlayDragState.dragging and uses
gripController/thumbY), clamp the updated z to a safe range (e.g.,
minDepth/maxDepth or settings-provided limits) so neither
overlayDragState.initialHMDOffset.z nor
overlayDragState.initialControllerOffset.z can grow without bound; implement the
clamp immediately after the addition for both OverlayDragState::DragMode::HMD
and ::Controller cases.

In `@src/Features/VR/SettingsUI.cpp`:
- Around line 936-940: The recording popup computes remainingTime using the VR
member comboTimeout (this->comboTimeout) so the UI slider modifying
settings.comboTimeout has no effect; change the calculation in SettingsUI.cpp to
use settings.comboTimeout (and keep using this->comboStartTime) so remainingTime
uses the user-configured timeout, e.g., replace references to this->comboTimeout
with settings.comboTimeout in the block that sets remainingTime, timerColor, and
the ImGui::TextColored call.
🧹 Nitpick comments (9)
src/Features/VR/OpenVRDetection.cpp (1)

96-119: Runtime type heuristics are fragile and may misclassify future versions.

The detection logic relies on hardcoded constants (version "1.0.10.0", file size < 700000) and broad path substring matches ("steam" could match unrelated paths). If OpenComposite updates its version number or DLL size, it will be misclassified as SteamVR.

Consider logging when detection falls through to the version-based heuristic (Line 115) so users can report misclassification, and/or adding a comment noting that these heuristics should be revisited periodically.

src/Features/VR/OverlayDrag.cpp (2)

343-344: Misleading field names: isPrimary/isSecondary actually store isLeft/isRight.

overlayDragState.isPrimary is assigned isLeft and overlayDragState.isSecondary is assigned isRight. The names suggest they track primary/secondary controller identity, but they actually track physical left/right hand. While the downstream code in GetGripPressed and the joystick depth logic compensates correctly, this is confusing and error-prone for future maintainers.

Consider renaming these fields to isLeft/isRight, or adding a clarifying comment.


225-233: Per-frame heap allocations for drag mode dispatch.

TryStartNewDrag is called every frame when the menu is open and the user isn't dragging. It creates a std::vector<DragMode> with std::function members (heap-allocated captures) each frame. Consider using a small fixed-size array (e.g., std::array<DragMode, 3>) or caching the drag modes to avoid repeated allocations on the hot path.

src/Features/VR/SettingsUI.cpp (1)

948-951: Unnecessary copy loop — can directly assign the vector.

Lines 948-951 manually copy recordedCombo element-by-element into sortedRecordedCombos. This is equivalent to a simple copy construction.

Proposed fix
-				std::vector<ButtonCombo> sortedRecordedCombos;
-				for (size_t i = 0; i < this->recordedCombo.size(); ++i) {
-					sortedRecordedCombos.push_back(this->recordedCombo[i]);
-				}
+				std::vector<ButtonCombo> sortedRecordedCombos(this->recordedCombo);
src/Features/VR/Input.cpp (2)

10-116: Per-call std::vector and std::function heap allocations in UpdateOverlayMenuStateFromInput.

This function is called every frame. Lines 39-43 define a MenuStateMapping with std::function members, and Line 75 creates a std::vector<MenuStateMapping>. Each call incurs multiple heap allocations. Since the mappings are structurally fixed, consider refactoring to avoid dynamic dispatch (e.g., a sequence of if/else-if checks or a static array of function pointers).


268-301: Scroll accumulation is frame-rate-dependent.

Lines 282-283 accumulate thumbstick * 0.1f every frame. At higher frame rates the accumulator grows faster, resulting in faster scrolling. Consider scaling by delta time for consistent scroll speed across frame rates.

src/Features/VR/InSceneOverlay.cpp (2)

334-334: force2D is hardcoded to false — ~110 lines of dead code.

force2D is unconditionally false on Line 334, making the entire 2D SBS rendering path (Lines 484–596) unreachable. If this code path is planned for future use, consider guarding it behind a config flag. If it's no longer needed, remove it to reduce maintenance burden and cognitive load.

Also applies to: 484-596


56-105: Raw ID3DBlob* pointers with manual Release() across multiple error paths.

vsBlob, psBlob, and errorBlob are managed manually with multiple early-return paths. While the current cleanup logic appears correct, using winrt::com_ptr (already used elsewhere in this function for other resources) would eliminate the risk of leaks from future code changes.

src/Features/VR.h (1)

341-388: Large public surface area — consider tightening visibility.

Controller states (primaryControllerState, secondaryControllerState), overlayDragState, vrControllerEventLog, lastKnownLeftHandedMode, etc. are all public. This appears necessary for the anonymous-namespace UI functions in SettingsUI.cpp, but it exposes internal state broadly. Consider using friend declarations or a dedicated diagnostics accessor to limit the surface area.

Comment thread src/Features/VR/Input.cpp
Comment thread src/Features/VR/InSceneOverlay.cpp Outdated
Comment thread src/Features/VR/OverlayDrag.cpp
Comment thread src/Features/VR/SettingsUI.cpp Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/Features/VR/WandPointing.cpp`:
- Around line 53-55: Guard against a zero/near-zero VRMenuScale before
creating/inverting overlayWorld: check settings.VRMenuScale and if its absolute
value is below a small epsilon (e.g. 1e-6) replace it with a safe fallback (1.0
or a clamped epsilon) before calling Matrix::CreateScale and recomputing
overlayWorld, then call overlayWorld.Invert() to produce worldToOverlay;
reference overlayWorld, Matrix::CreateScale, settings.VRMenuScale,
overlayWorld.Invert(), and worldToOverlay when locating the change.
🧹 Nitpick comments (1)
src/Features/VR/WandPointing.cpp (1)

135-138: Redundant mouse position update — both legacy and event API used.

io.MousePos assignment (legacy path) and io.AddMousePosEvent (new input-queue API, ImGui 1.87+) both set the cursor position. Using both is harmless but redundant. Consider keeping only AddMousePosEvent if your ImGui version supports it, or only the direct assignment if targeting older versions.

Comment thread src/Features/VR/WandPointing.cpp
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/Features/VR/InSceneOverlay.cpp`:
- Around line 603-604: The vtable index used for hooking IVRCompositor::Submit
is incorrect; change the detour template instantiation from stl::detour_vfunc<5,
IVRCompositor_Submit>(RE::BSOpenVR::GetIVRCompositor()) to use index 6
(stl::detour_vfunc<6, IVRCompositor_Submit>(RE::BSOpenVR::GetIVRCompositor()))
and update the adjacent comment to state that IVRCompositor::Submit is index 6
(and that index 5 is GetSubmitTexture) so the hook targets the correct method.
🧹 Nitpick comments (6)
src/Features/VR/InSceneOverlay.cpp (6)

37-38: Prefer static_cast over C-style cast.

The eType guard makes this safe, but C-style casts bypass type checking and are harder to grep for. Consider static_cast<ID3D11Texture2D*>(pTexture->handle).


56-88: Raw ID3DBlob* management is fragile — consider winrt::com_ptr.

The manual Release() calls on vsBlob, psBlob, and errorBlob across multiple error paths work but are easy to get wrong in future edits. Wrapping them in winrt::com_ptr<ID3DBlob> (same as other resources in this function) would make the cleanup automatic.


333-367: RTV is recreated every frame per eye — consider caching.

CreateRenderTargetView is called on every Submit (twice per frame, once per eye). Since the compositor typically reuses the same textures, you could cache the RTV keyed on the targetTexture pointer, similar to the menuSRV caching pattern at line 460. This avoids a device call on every frame in a latency-sensitive VR path.


369-379: Incomplete pipeline state save/restore — blend and depth-stencil states not restored.

The code saves and restores RTVs, DSV, viewports, and rasterizer state, but sets blend state (line 455) and depth-stencil state (line 456) without saving/restoring them. If any other DX11 hook (ReShade, ENB, etc.) chains after this Submit hook, it will see modified blend/depth state.

Since this fires at Submit time, the game's own rendering is done, so the practical risk is limited to hook interop. Worth addressing if compatibility with other overlay tools is a goal.

Also applies to: 528-539


240-245: Per-frame heap allocations in latency-sensitive Submit hook.

std::wstring construction (line 243) and QueryInterface (line 241) run every frame per eye. In a VR Submit path where latency matters, consider hoisting the ID3DUserDefinedAnnotation query to init time and using a static/pre-built event name (or skipping annotations in release builds).


163-163: Use uint32_t instead of unsigned long for index buffer data.

unsigned long is 32-bit on Windows but 64-bit on some platforms. Using uint32_t makes the DXGI_FORMAT_R32_UINT contract explicit.

Comment thread src/Features/VR/InSceneOverlay.cpp
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/Features/VR/OverlayDrag.cpp`:
- Around line 96-118: The code is using
GetDeviceToAbsoluteTrackingPoseCompatible(..., 0, 1) which returns only the HMD
pose, so controllerPose actually contains the HMD transform; update the logic to
fetch the attached controller's pose instead by either calling
Util::GetControllerWorldMatrix(attachedControllerIndex, attachM) and use attachM
to compute worldToLocal, or call
Util::GetDeviceToAbsoluteTrackingPoseCompatible(vr::TrackingUniverseStanding, 0,
poses, vr::k_unMaxTrackedDeviceCount) and then read
poses[attachedControllerIndex] into controllerPose before converting with
Util::HmdMatrix34ToMatrix; replace uses of
controllerPose/mDeviceToAbsoluteTracking accordingly (references:
attachedControllerIndex, controllerPose, Util::GetControllerWorldMatrix,
Util::GetDeviceToAbsoluteTrackingPoseCompatible, Util::HmdMatrix34ToMatrix).
🧹 Nitpick comments (6)
src/Features/VR/SettingsUI.cpp (1)

948-957: Simplify vector copy.

The loop manually copies elements one at a time into sortedRecordedCombos. You can initialize directly from the source vector.

Suggested simplification
-			std::vector<ButtonCombo> sortedRecordedCombos;
-			for (size_t i = 0; i < this->recordedCombo.size(); ++i) {
-				sortedRecordedCombos.push_back(this->recordedCombo[i]);
-			}
+			std::vector<ButtonCombo> sortedRecordedCombos(this->recordedCombo.begin(), this->recordedCombo.end());
src/Features/VR/OverlayDrag.cpp (2)

228-236: Per-frame heap allocations from std::vector<DragMode> and std::function captures.

TryStartNewDrag runs every frame when not dragging. Each call constructs a std::vector of DragMode structs containing std::function objects, causing heap allocations. Consider using a small fixed-size array (e.g., std::array or static storage) and function pointers or a simpler dispatch to avoid allocation churn.


343-348: Misleading field names: isPrimary/isSecondary actually represent physical hand (left/right).

isPrimary is set from isLeft (physical left hand) and isSecondary from isRight, but the field names suggest they refer to the primary/secondary controller designation (which flips with handedness). This inconsistency could confuse maintainers. Consider renaming to isLeftHand/isRightHand in the OverlayDragState struct.

src/Features/VR/InSceneOverlay.cpp (3)

163-173: Use uint32_t instead of unsigned long for index buffer data.

unsigned long is 4 bytes on Windows/MSVC but 8 bytes on 64-bit Linux. Since the index buffer uses DXGI_FORMAT_R32_UINT (line 451), uint32_t communicates the intent more clearly and avoids any portability ambiguity.

Suggested fix
-	unsigned long indices[6] = { 0, 1, 2, 0, 2, 3 };
+	uint32_t indices[6] = { 0, 1, 2, 0, 2, 3 };
 	D3D11_BUFFER_DESC indexBufferDesc = {};
 	indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
-	indexBufferDesc.ByteWidth = sizeof(unsigned long) * 6;
+	indexBufferDesc.ByteWidth = sizeof(uint32_t) * 6;

369-379: Incomplete D3D state save/restore — blend state and depth-stencil state not preserved.

Only RTVs, DSV, viewports, and rasterizer state are saved/restored. The function also sets blend state (line 455), depth-stencil state (line 456), shaders, IA state, samplers, and SRVs — none of which are restored. Since this runs from the Submit hook between eye submissions, any state the compositor or game engine reads between calls could see stale values.

In practice the risk is low (Submit typically just copies the texture), but consider also saving/restoring at least the blend and depth-stencil states for robustness.

Minimal addition to save/restore blend + depth-stencil state
+	// Save additional pipeline state
+	ID3D11BlendState* oldBlendState = nullptr;
+	FLOAT oldBlendFactor[4];
+	UINT oldSampleMask;
+	context->OMGetBlendState(&oldBlendState, oldBlendFactor, &oldSampleMask);
+
+	ID3D11DepthStencilState* oldDepthState = nullptr;
+	UINT oldStencilRef;
+	context->OMGetDepthStencilState(&oldDepthState, &oldStencilRef);
+
 	ID3D11RasterizerState* oldRS = nullptr;
 	context->RSGetState(&oldRS);

And in the restore section:

+	context->OMSetBlendState(oldBlendState, oldBlendFactor, oldSampleMask);
+	if (oldBlendState) oldBlendState->Release();
+	context->OMSetDepthStencilState(oldDepthState, oldStencilRef);
+	if (oldDepthState) oldDepthState->Release();
 	if (oldRS) {
 		context->RSSetState(oldRS);
 		oldRS->Release();
 	}

Also applies to: 528-539


243-245: Per-frame std::wstring allocation in render path.

eventName is constructed every frame per eye, allocating on the heap. Since the eye value is only 0 or 1, consider using a static lookup:

Suggested fix
-	std::wstring eventName = L"VR In-Scene Overlay (Eye " + std::to_wstring((int)eye) + L")";
-	if (perf)
-		perf->BeginEvent(eventName.c_str());
+	if (perf) {
+		static const wchar_t* eventNames[] = { L"VR In-Scene Overlay (Eye 0)", L"VR In-Scene Overlay (Eye 1)" };
+		perf->BeginEvent(eventNames[(int)eye]);
+	}

Comment thread src/Features/VR/OverlayDrag.cpp
@alandtse alandtse changed the title feat(vr): add OpenComposite VR menu support feat(vr): add OpenComposite VR menu Feb 15, 2026
@alandtse alandtse merged commit cf28c87 into community-shaders:dev Feb 15, 2026
18 checks passed
alandtse added a commit that referenced this pull request Feb 15, 2026
alandtse added a commit to alandtse/open-shaders that referenced this pull request Feb 15, 2026
davo0411 added a commit to davo0411/skyrim-community-shaders that referenced this pull request Mar 28, 2026
* fix(weather overrides): ensure json format for features (community-shaders#1748)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>

* perf(terrain blending): tweak defaults (community-shaders#1771)

* fix(lighting): vanilla envcolor mult the correct value (community-shaders#1775)

* fix(water): remove final colour saturate (community-shaders#1778)

* fix(unified-water): LOD water cache mismatch (community-shaders#1779)

* fix(weather editor): override desync with weather transitions (community-shaders#1782)

* fix(weather editor): no-override weather file deletion (community-shaders#1777)

* fix(weather editor): apply weather settings post-load (community-shaders#1776)

* fix(weather editor): handling of weathers without overrides (community-shaders#1773)

* feat(UI): feature headings (community-shaders#1786)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat(VR): add wand pointing (community-shaders#1790)

* chore(UI): theme consistency (community-shaders#1787)

* fix(upscaling): warn about max nvidia resolution (community-shaders#1795)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* chore(linear lighting): UI settings changes (community-shaders#1785)

Co-authored-by: Jiaye <l936249247@hotmail.com>

* fix(grass-lighting) better basic grass brightness default (community-shaders#1780)

* chore(UI): remove settings and about tabs (community-shaders#1794)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* fix(terrain shadows): fix compiler warnings (community-shaders#1798)

* fix: fix flickering particles (community-shaders#1791)

* fix(terrain blending): disable vr support (community-shaders#1799)

* refactor(upscaling): standardize behavior and tune settings (community-shaders#1783)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat(UI): add auto-hide featurelist option (community-shaders#1793)

* fix: match grass brightness of vanilla (community-shaders#1801)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* refactor(perfoverlay): remove color from "Other" and "Total" (community-shaders#1806)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* fix(unified water): fix for mesh water jitter (community-shaders#1809)

* fix: clear shader cache on plugin version change (community-shaders#1739)

* feat(filewatcher): add hlsli tracking (community-shaders#1796)

* feat(linear lighting): add ambient multiplier (community-shaders#1805)

* fix(unified-water): underwater fog flicker (community-shaders#1807)

* fix(UI): conflicting esc key on welcome hotkey dialogue (community-shaders#1811)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* chore(UI): add subtext font to tooltips (community-shaders#1810)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* build: bump streamline to 2.10.3 (community-shaders#1813)

* build: resolve shader warnings (community-shaders#1818)

* feat(ui): add combo hotkey support (community-shaders#1808)

* feat: add feature constraints (community-shaders#1804)

* build: update version to 1.4.8 (community-shaders#1802)

* fix(VR): apply per eye upscaling (community-shaders#1819)

- Split upscaling across each eye for correctness and to avoid DLSS failing over 8k x 8k limit
- Changes HMD mask color to black to hide artifacts with fast movement

* build: bump common lib to 4.2.0 (community-shaders#1821)

Co-authored-by: doodlum <15017472+doodlum@users.noreply.github.com>

* fix(grass collision): catch trashed actor pointers (community-shaders#1765)

* fix(weather editor): desynced override transitions (community-shaders#1820)

* fix(upscaling): fix preset and allocation handling (community-shaders#1824)

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* build: remove linear lighting from core whilst in development (community-shaders#1826)

* chore: bump version to 1.4.9 (community-shaders#1827)

* fix: add back LLF core file and remove LL core file (community-shaders#1828)

* fix: dont save shader debug toggles (community-shaders#1831)

* fix: remove IBL from core, unfinished (community-shaders#1830)

* chore: update version to 1.4.10 (community-shaders#1832)

* chore(dynamic cubemaps): lessen normalisation darkening (community-shaders#1833)

* chore(llf): remove LightsVisualisationMode settings loading (community-shaders#1834)

* revert: "fix: dont save shader debug toggles (community-shaders#1831)"

This reverts commit f55f195.

* revert: "chore(llf): remove LightsVisualisationMode settings loading (community-shaders#1834)"

This reverts commit b3db5a7.

* fix: default enabledClasses true

* build: bump version

* feat(upscaling): custom DLSS preset (community-shaders#1837)

* fix(weather editor): sync UI for full transition (community-shaders#1822)

* fix(linearlighting): return correct buffer when ll feature off (community-shaders#1838)

* fix(PBR): skip IrradianceToLinear on specular in vanilla (community-shaders#1839)

* feat(weather editor): adjust slider ranges (community-shaders#1847)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>

* feat(weather editor): replace volumetric Lighting RGB sliders with color picker (community-shaders#1846)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>

* fix(grass collision): collision radius math  (community-shaders#1849)

* chore: move new feature information into docs (community-shaders#1848)

Co-authored-by: doodlum <15017472+doodlum@users.noreply.github.com>

* fix(ui): background blur with upscaling (community-shaders#1815)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* refactor: move some features to core (community-shaders#1852)

* fix: fix blown out water specular (community-shaders#1853)

* feat(weather editor): toggle hotkey (community-shaders#1856)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat(color picker): add an original color reference to all color pickers (community-shaders#1857)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>

* perf(emat): alternate tweaks (community-shaders#1850)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat(weather-editor): merge weather picker and editor (community-shaders#1845)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* chore(llf): remove LLF settings loading (community-shaders#1859)

* feat: exponential height fog (community-shaders#1708)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat(weather editor): block editor access in loading screens (community-shaders#1871)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>

* feat(weather editor): improve weather picker UI and functionality (community-shaders#1863)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat(weather editor): repurpose unsaved changes tracking (community-shaders#1860)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* fix: sync grass lighting defaults to match ENB (community-shaders#1844)

* fix: stop shader compilation on game exit (community-shaders#1867)

closes community-shaders#1130

* fix(weather editor): prevent inputs when editor is open (community-shaders#1872)

* fix(weather editor): add ctd guards (community-shaders#1864)

* feat(weather editor): remove WorldSpace widget and associated code (community-shaders#1878)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>

* feat(vr): add OpenComposite menu support (community-shaders#1880)

* revert: "feat(vr): add OpenComposite VR menu" (community-shaders#1881)

* revert: "fix: stop shader compilation on game exit" (community-shaders#1882)

* feat(vr): add OpenComposite menu support (community-shaders#1883)

* feat(weather editor): add time controls (community-shaders#1877)

* feat: add shadowmap rasterizer override (community-shaders#1690)

* fix(weather editor): clear feature overrides with revert (community-shaders#1884)

* feat(UI): Interior Only (community-shaders#1854)

* fix(VR): fix Shadowmap Cascade Rasterizer (community-shaders#1888)

* fix(unified water): distance calculation for raindrops & LOD fade (community-shaders#1890)

* refactor: clarify core feature version mismatch text (community-shaders#1886)

* fix: stop shader compilation on game exit (community-shaders#1885)

* build: exclude hlsl tests from packaging (community-shaders#1894)

* chore: disable feature constraints in dev mode (community-shaders#1893)

* fix(vr): improve stereo UV handling (community-shaders#1899)

* fix(weather editor): move esc key to native input system (community-shaders#1897)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>

* fix: move ResolveMonoUVForEye outside VR guard (community-shaders#1906)

* fix(grass collision): validate actor  (community-shaders#1905)

Co-authored-by: doodlum <15017472+doodlum@users.noreply.github.com>

* fix(terrain shadows): height map regression (community-shaders#1911)

* fix: util vertical fov math (community-shaders#1904)

Co-authored-by: doodlum <15017472+doodlum@users.noreply.github.com>

* test: add float4 overload test (community-shaders#1902)

* refactor: move all features to globals::game::calendar (community-shaders#1909)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* fix(UI): resolution based font (community-shaders#1907)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat(weather editor): make objects window be independently scrollable (community-shaders#1908)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat(UI): consolidate searchbar to util and add to weather editor (community-shaders#1898)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat(weather editor): add filled star for favourites. (community-shaders#1913)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>

* feat(weather editor): add delete json button to objects window (community-shaders#1914)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* fix(VR): resolution-based font (community-shaders#1923)

* refactor: use depthbuffer helper (community-shaders#1925)

* refactor: move TurboColormap into Color.hlsli (community-shaders#1924)

* fix(weather editor): expand clickable area of feature override (community-shaders#1921)

* feat(weather editor): enable snapping to viewport (community-shaders#1917)

* feat(weather editor): highlight enabled cloud layers (community-shaders#1916)

* fix(VR): SSGI discrepancies (community-shaders#1926)

* feat: volumetric shadows (community-shaders#1874)

* ci: enhance feature version audit (community-shaders#1927)

* feat(weather editor): add filter options for objects window (community-shaders#1922)

* feat(weather editor): sticky headers and scrollable content (community-shaders#1930)

* fix(UI): ImGui scaling for borderless mode (community-shaders#1929)

* ci: don't fail on feature audits (community-shaders#1934)

* fix(pbr): use scrap heap allocation (community-shaders#1928)

* chore(UI): add subsurface scattering to Interior Only (community-shaders#1932)

* fix(weather editor): align highlights, fix tooltip (community-shaders#1918)

* fix(ssgi): guard VR only compilation (community-shaders#1938)

* build: update template to avoid extra directory (community-shaders#1812)

* style: fix hlsl formatting (community-shaders#1939)

* fix(UI): improve theme management UI flow (community-shaders#1933)

closes community-shaders#1919

* build(deps): update pre-commit hooks (community-shaders#1768)

* feat(UI): delete theme button (community-shaders#1940)

* feat(UI): open log file button (community-shaders#1942)

* fix(hair): marschner volumetric shadow tint (community-shaders#1944)

* fix(VR): screen space shadows desync (community-shaders#1946)

closes community-shaders#1840

* fix(VR): depth culling during upscaling/Terrain Blending (community-shaders#1858)

* feat(VR): add edge detection for stereo blending (community-shaders#1948)

* refactor: allocate trampoline once (community-shaders#1951)

* fix(UI): PBR MATO color scale RGB settings corrected (community-shaders#1957)

* fix(weather editor): guard against loadorder changes (community-shaders#1953)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: davo0411 <davidkehoe0411@outlook.com>

* fix(UI): feature description text wrapping (community-shaders#1960)

* fix(VR): exponential height fog stereo mismatch (community-shaders#1961)

* chore: pbr consistency changes (community-shaders#1841)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: jiayev <l936249247@hotmail.com>

* fix(skylighting): remove PBR lighting scale (community-shaders#1963)

* fix(skysync): effect mesh blackout during shadow caster transitions (community-shaders#1965)

* ci: fix wiki deletion with buffer update (community-shaders#1967)

* feat(weather-editor): option to hide viewport (community-shaders#1970)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* test(shader): fallback to warp on invalidarg (community-shaders#1956)

Co-authored-by: LukeFrankio <loren@example.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat: triplanar projected materials (community-shaders#1950)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* fix(ao): better ao calculations (community-shaders#1968)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* fix(pbr): fix improper kD terms (community-shaders#1971)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* perf(emat): tweak fade and shadow intensity (community-shaders#1892)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat(ibl): revamp ibl and dalc sh (community-shaders#1947)

* build: bump commonlib to 4.7.1 (community-shaders#1977)

* fix: upscaling monitor detection fixes (community-shaders#1978)

* fix(weather editor): prevent overrides resetting settings (community-shaders#1980)

* fix(VR): bad llf offset (community-shaders#1984)

* perf: cache frequent ui checks (community-shaders#1985)

* fix: preserve vanilla water TAA when no upscaler is active (community-shaders#1986)

Co-authored-by: jturnley <jturnley@users.noreply.github.com>

* fix(UI): first-time dialog fade affects all overlays (community-shaders#1976)

* fix(skysync): remove sunlight fade and volumetric lighting overrides (community-shaders#1966)

* refactor(HLSL): standardize epsilon constants (community-shaders#1992)

closes community-shaders#1227

* feat(UI): require Shift to dock windows (community-shaders#1989)

* fix(UI): input spam after alt-tab (community-shaders#1993)

* fix(sky sync): early return for invalid cells (community-shaders#1991)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: jiayev <l936249247@hotmail.com>

* fix(sky sync): remove undeclared variable (community-shaders#1994)

* refactor(pbr): clear up semantics (community-shaders#1995)

* fix(UI): scale layout values for high-DPI (community-shaders#1987)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* fix(water): hdr water taa blend (community-shaders#1988)

* refactor(color): clarify gamma conversion functions (community-shaders#1996)

* feat(ISL-editor): add light counters and fix filtering (community-shaders#1997)

* fix(UI): DPI-aware window layouts (community-shaders#2000)

* fix(weather-editor): save color palette window (community-shaders#2001)

* refactor: centralize feature category names (community-shaders#2007)

closes community-shaders#1265

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* chore: bump versions (community-shaders#2010)

* fix(water): sample history mask from current mask (community-shaders#2011)

* chore(wetness-effects): set default MaxPuddleWetness to 1.5 (community-shaders#1981)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>

* feat(weather-editor): add free camera and play mode (community-shaders#2008)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* build: bump versions and reduce false positives (community-shaders#2013)

* fix(VR): LLF cluster building and culling (community-shaders#2012)

* build: update to VS 2026 (community-shaders#1990)

* ci: fix preset in vs2022 mode (community-shaders#2015)

* ci: remove v2022 from shader jobs (community-shaders#2016)

* feat(upscaling): integrate Streamline Reflex controls (community-shaders#1958)

* fix(unified-water): BSWaterShaderProperty.plane (community-shaders#1998)

---------

Co-authored-by: Skrubby Skrub In A Shrub <87662196+SkrubbySkrubInAShrub@users.noreply.github.com>
Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: doodlum <15017472+doodlum@users.noreply.github.com>
Co-authored-by: jiayev <l936249247@hotmail.com>
Co-authored-by: Dlizzio <77717521+Dlizzio@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Alan Tse <alandtse@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Bruce <44987693+brucenguyen@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Dawntic <197450198+Dawntic@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Alan Tse <alandtse@gmail.com>
Co-authored-by: Vanni Giachin <vanni.giachin@qlik.com>
Co-authored-by: zxcvbn <66063766+zndxcvbn@users.noreply.github.com>
Co-authored-by: ParticleTroned <248299730+ParticleTroned@users.noreply.github.com>
Co-authored-by: soda <130315225+soda3000@users.noreply.github.com>
Co-authored-by: YtzyFvra <59631290+YtzyFvra@users.noreply.github.com>
Co-authored-by: LukeFrankio <lorenzogrutzmann@gmail.com>
Co-authored-by: LukeFrankio <loren@example.com>
Co-authored-by: jturnley <32892261+jturnley@users.noreply.github.com>
Co-authored-by: jturnley <jturnley@users.noreply.github.com>
Co-authored-by: Igor Alan Albuquerque de Sousa <50077829+IgorAlanAlbuquerque@users.noreply.github.com>
Co-authored-by: Matt Van Horn <mvanhorn@users.noreply.github.com>
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
davo0411 added a commit to davo0411/skyrim-community-shaders that referenced this pull request Mar 29, 2026
* fix(weather overrides): ensure json format for features (community-shaders#1748)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>

* perf(terrain blending): tweak defaults (community-shaders#1771)

* fix(lighting): vanilla envcolor mult the correct value (community-shaders#1775)

* fix(water): remove final colour saturate (community-shaders#1778)

* fix(unified-water): LOD water cache mismatch (community-shaders#1779)

* fix(weather editor): override desync with weather transitions (community-shaders#1782)

* fix(weather editor): no-override weather file deletion (community-shaders#1777)

* fix(weather editor): apply weather settings post-load (community-shaders#1776)

* fix(weather editor): handling of weathers without overrides (community-shaders#1773)

* feat(UI): feature headings (community-shaders#1786)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat(VR): add wand pointing (community-shaders#1790)

* chore(UI): theme consistency (community-shaders#1787)

* fix(upscaling): warn about max nvidia resolution (community-shaders#1795)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* chore(linear lighting): UI settings changes (community-shaders#1785)

Co-authored-by: Jiaye <l936249247@hotmail.com>

* fix(grass-lighting) better basic grass brightness default (community-shaders#1780)

* chore(UI): remove settings and about tabs (community-shaders#1794)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* fix(terrain shadows): fix compiler warnings (community-shaders#1798)

* fix: fix flickering particles (community-shaders#1791)

* fix(terrain blending): disable vr support (community-shaders#1799)

* refactor(upscaling): standardize behavior and tune settings (community-shaders#1783)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat(UI): add auto-hide featurelist option (community-shaders#1793)

* fix: match grass brightness of vanilla (community-shaders#1801)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* refactor(perfoverlay): remove color from "Other" and "Total" (community-shaders#1806)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* fix(unified water): fix for mesh water jitter (community-shaders#1809)

* fix: clear shader cache on plugin version change (community-shaders#1739)

* feat(filewatcher): add hlsli tracking (community-shaders#1796)

* feat(linear lighting): add ambient multiplier (community-shaders#1805)

* fix(unified-water): underwater fog flicker (community-shaders#1807)

* fix(UI): conflicting esc key on welcome hotkey dialogue (community-shaders#1811)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* chore(UI): add subtext font to tooltips (community-shaders#1810)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* build: bump streamline to 2.10.3 (community-shaders#1813)

* build: resolve shader warnings (community-shaders#1818)

* feat(ui): add combo hotkey support (community-shaders#1808)

* feat: add feature constraints (community-shaders#1804)

* build: update version to 1.4.8 (community-shaders#1802)

* fix(VR): apply per eye upscaling (community-shaders#1819)

- Split upscaling across each eye for correctness and to avoid DLSS failing over 8k x 8k limit
- Changes HMD mask color to black to hide artifacts with fast movement

* build: bump common lib to 4.2.0 (community-shaders#1821)

Co-authored-by: doodlum <15017472+doodlum@users.noreply.github.com>

* fix(grass collision): catch trashed actor pointers (community-shaders#1765)

* fix(weather editor): desynced override transitions (community-shaders#1820)

* fix(upscaling): fix preset and allocation handling (community-shaders#1824)

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* build: remove linear lighting from core whilst in development (community-shaders#1826)

* chore: bump version to 1.4.9 (community-shaders#1827)

* fix: add back LLF core file and remove LL core file (community-shaders#1828)

* fix: dont save shader debug toggles (community-shaders#1831)

* fix: remove IBL from core, unfinished (community-shaders#1830)

* chore: update version to 1.4.10 (community-shaders#1832)

* chore(dynamic cubemaps): lessen normalisation darkening (community-shaders#1833)

* chore(llf): remove LightsVisualisationMode settings loading (community-shaders#1834)

* revert: "fix: dont save shader debug toggles (community-shaders#1831)"

This reverts commit f55f195.

* revert: "chore(llf): remove LightsVisualisationMode settings loading (community-shaders#1834)"

This reverts commit b3db5a7.

* fix: default enabledClasses true

* build: bump version

* feat(upscaling): custom DLSS preset (community-shaders#1837)

* fix(weather editor): sync UI for full transition (community-shaders#1822)

* fix(linearlighting): return correct buffer when ll feature off (community-shaders#1838)

* fix(PBR): skip IrradianceToLinear on specular in vanilla (community-shaders#1839)

* feat(weather editor): adjust slider ranges (community-shaders#1847)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>

* feat(weather editor): replace volumetric Lighting RGB sliders with color picker (community-shaders#1846)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>

* fix(grass collision): collision radius math  (community-shaders#1849)

* chore: move new feature information into docs (community-shaders#1848)

Co-authored-by: doodlum <15017472+doodlum@users.noreply.github.com>

* fix(ui): background blur with upscaling (community-shaders#1815)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* refactor: move some features to core (community-shaders#1852)

* fix: fix blown out water specular (community-shaders#1853)

* feat(weather editor): toggle hotkey (community-shaders#1856)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat(color picker): add an original color reference to all color pickers (community-shaders#1857)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>

* perf(emat): alternate tweaks (community-shaders#1850)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat(weather-editor): merge weather picker and editor (community-shaders#1845)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* chore(llf): remove LLF settings loading (community-shaders#1859)

* feat: exponential height fog (community-shaders#1708)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat(weather editor): block editor access in loading screens (community-shaders#1871)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>

* feat(weather editor): improve weather picker UI and functionality (community-shaders#1863)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat(weather editor): repurpose unsaved changes tracking (community-shaders#1860)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* fix: sync grass lighting defaults to match ENB (community-shaders#1844)

* fix: stop shader compilation on game exit (community-shaders#1867)

closes community-shaders#1130

* fix(weather editor): prevent inputs when editor is open (community-shaders#1872)

* fix(weather editor): add ctd guards (community-shaders#1864)

* feat(weather editor): remove WorldSpace widget and associated code (community-shaders#1878)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>

* feat(vr): add OpenComposite menu support (community-shaders#1880)

* revert: "feat(vr): add OpenComposite VR menu" (community-shaders#1881)

* revert: "fix: stop shader compilation on game exit" (community-shaders#1882)

* feat(vr): add OpenComposite menu support (community-shaders#1883)

* feat(weather editor): add time controls (community-shaders#1877)

* feat: add shadowmap rasterizer override (community-shaders#1690)

* fix(weather editor): clear feature overrides with revert (community-shaders#1884)

* feat(UI): Interior Only (community-shaders#1854)

* fix(VR): fix Shadowmap Cascade Rasterizer (community-shaders#1888)

* fix(unified water): distance calculation for raindrops & LOD fade (community-shaders#1890)

* refactor: clarify core feature version mismatch text (community-shaders#1886)

* fix: stop shader compilation on game exit (community-shaders#1885)

* build: exclude hlsl tests from packaging (community-shaders#1894)

* chore: disable feature constraints in dev mode (community-shaders#1893)

* fix(vr): improve stereo UV handling (community-shaders#1899)

* fix(weather editor): move esc key to native input system (community-shaders#1897)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>

* fix: move ResolveMonoUVForEye outside VR guard (community-shaders#1906)

* fix(grass collision): validate actor  (community-shaders#1905)

Co-authored-by: doodlum <15017472+doodlum@users.noreply.github.com>

* fix(terrain shadows): height map regression (community-shaders#1911)

* fix: util vertical fov math (community-shaders#1904)

Co-authored-by: doodlum <15017472+doodlum@users.noreply.github.com>

* test: add float4 overload test (community-shaders#1902)

* refactor: move all features to globals::game::calendar (community-shaders#1909)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* fix(UI): resolution based font (community-shaders#1907)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat(weather editor): make objects window be independently scrollable (community-shaders#1908)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat(UI): consolidate searchbar to util and add to weather editor (community-shaders#1898)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat(weather editor): add filled star for favourites. (community-shaders#1913)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>

* feat(weather editor): add delete json button to objects window (community-shaders#1914)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* fix(VR): resolution-based font (community-shaders#1923)

* refactor: use depthbuffer helper (community-shaders#1925)

* refactor: move TurboColormap into Color.hlsli (community-shaders#1924)

* fix(weather editor): expand clickable area of feature override (community-shaders#1921)

* feat(weather editor): enable snapping to viewport (community-shaders#1917)

* feat(weather editor): highlight enabled cloud layers (community-shaders#1916)

* fix(VR): SSGI discrepancies (community-shaders#1926)

* feat: volumetric shadows (community-shaders#1874)

* ci: enhance feature version audit (community-shaders#1927)

* feat(weather editor): add filter options for objects window (community-shaders#1922)

* feat(weather editor): sticky headers and scrollable content (community-shaders#1930)

* fix(UI): ImGui scaling for borderless mode (community-shaders#1929)

* ci: don't fail on feature audits (community-shaders#1934)

* fix(pbr): use scrap heap allocation (community-shaders#1928)

* chore(UI): add subsurface scattering to Interior Only (community-shaders#1932)

* fix(weather editor): align highlights, fix tooltip (community-shaders#1918)

* fix(ssgi): guard VR only compilation (community-shaders#1938)

* build: update template to avoid extra directory (community-shaders#1812)

* style: fix hlsl formatting (community-shaders#1939)

* fix(UI): improve theme management UI flow (community-shaders#1933)

closes community-shaders#1919

* build(deps): update pre-commit hooks (community-shaders#1768)

* feat(UI): delete theme button (community-shaders#1940)

* feat(UI): open log file button (community-shaders#1942)

* fix(hair): marschner volumetric shadow tint (community-shaders#1944)

* fix(VR): screen space shadows desync (community-shaders#1946)

closes community-shaders#1840

* fix(VR): depth culling during upscaling/Terrain Blending (community-shaders#1858)

* feat(VR): add edge detection for stereo blending (community-shaders#1948)

* refactor: allocate trampoline once (community-shaders#1951)

* fix(UI): PBR MATO color scale RGB settings corrected (community-shaders#1957)

* fix(weather editor): guard against loadorder changes (community-shaders#1953)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: davo0411 <davidkehoe0411@outlook.com>

* fix(UI): feature description text wrapping (community-shaders#1960)

* fix(VR): exponential height fog stereo mismatch (community-shaders#1961)

* chore: pbr consistency changes (community-shaders#1841)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: jiayev <l936249247@hotmail.com>

* fix(skylighting): remove PBR lighting scale (community-shaders#1963)

* fix(skysync): effect mesh blackout during shadow caster transitions (community-shaders#1965)

* ci: fix wiki deletion with buffer update (community-shaders#1967)

* feat(weather-editor): option to hide viewport (community-shaders#1970)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* test(shader): fallback to warp on invalidarg (community-shaders#1956)

Co-authored-by: LukeFrankio <loren@example.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat: triplanar projected materials (community-shaders#1950)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* fix(ao): better ao calculations (community-shaders#1968)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* fix(pbr): fix improper kD terms (community-shaders#1971)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* perf(emat): tweak fade and shadow intensity (community-shaders#1892)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat(ibl): revamp ibl and dalc sh (community-shaders#1947)

* build: bump commonlib to 4.7.1 (community-shaders#1977)

* fix: upscaling monitor detection fixes (community-shaders#1978)

* fix(weather editor): prevent overrides resetting settings (community-shaders#1980)

* fix(VR): bad llf offset (community-shaders#1984)

* perf: cache frequent ui checks (community-shaders#1985)

* fix: preserve vanilla water TAA when no upscaler is active (community-shaders#1986)

Co-authored-by: jturnley <jturnley@users.noreply.github.com>

* fix(UI): first-time dialog fade affects all overlays (community-shaders#1976)

* fix(skysync): remove sunlight fade and volumetric lighting overrides (community-shaders#1966)

* refactor(HLSL): standardize epsilon constants (community-shaders#1992)

closes community-shaders#1227

* feat(UI): require Shift to dock windows (community-shaders#1989)

* fix(UI): input spam after alt-tab (community-shaders#1993)

* fix(sky sync): early return for invalid cells (community-shaders#1991)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: jiayev <l936249247@hotmail.com>

* fix(sky sync): remove undeclared variable (community-shaders#1994)

* refactor(pbr): clear up semantics (community-shaders#1995)

* fix(UI): scale layout values for high-DPI (community-shaders#1987)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* fix(water): hdr water taa blend (community-shaders#1988)

* refactor(color): clarify gamma conversion functions (community-shaders#1996)

* feat(ISL-editor): add light counters and fix filtering (community-shaders#1997)

* fix(UI): DPI-aware window layouts (community-shaders#2000)

* fix(weather-editor): save color palette window (community-shaders#2001)

* refactor: centralize feature category names (community-shaders#2007)

closes community-shaders#1265

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* chore: bump versions (community-shaders#2010)

* fix(water): sample history mask from current mask (community-shaders#2011)

* chore(wetness-effects): set default MaxPuddleWetness to 1.5 (community-shaders#1981)

Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>

* feat(weather-editor): add free camera and play mode (community-shaders#2008)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* build: bump versions and reduce false positives (community-shaders#2013)

* fix(VR): LLF cluster building and culling (community-shaders#2012)

* build: update to VS 2026 (community-shaders#1990)

* ci: fix preset in vs2022 mode (community-shaders#2015)

* ci: remove v2022 from shader jobs (community-shaders#2016)

* feat(upscaling): integrate Streamline Reflex controls (community-shaders#1958)

* fix(unified-water): BSWaterShaderProperty.plane (community-shaders#1998)

---------

Co-authored-by: Skrubby Skrub In A Shrub <87662196+SkrubbySkrubInAShrub@users.noreply.github.com>
Co-authored-by: SkrubbySkrubInAShrub <skrubbyskrubinashrub@gmail.com>
Co-authored-by: doodlum <15017472+doodlum@users.noreply.github.com>
Co-authored-by: jiayev <l936249247@hotmail.com>
Co-authored-by: Dlizzio <77717521+Dlizzio@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Alan Tse <alandtse@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Bruce <44987693+brucenguyen@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Dawntic <197450198+Dawntic@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Alan Tse <alandtse@gmail.com>
Co-authored-by: Vanni Giachin <vanni.giachin@qlik.com>
Co-authored-by: zxcvbn <66063766+zndxcvbn@users.noreply.github.com>
Co-authored-by: ParticleTroned <248299730+ParticleTroned@users.noreply.github.com>
Co-authored-by: soda <130315225+soda3000@users.noreply.github.com>
Co-authored-by: YtzyFvra <59631290+YtzyFvra@users.noreply.github.com>
Co-authored-by: LukeFrankio <lorenzogrutzmann@gmail.com>
Co-authored-by: LukeFrankio <loren@example.com>
Co-authored-by: jturnley <32892261+jturnley@users.noreply.github.com>
Co-authored-by: jturnley <jturnley@users.noreply.github.com>
Co-authored-by: Igor Alan Albuquerque de Sousa <50077829+IgorAlanAlbuquerque@users.noreply.github.com>
Co-authored-by: Matt Van Horn <mvanhorn@users.noreply.github.com>
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants