Skip to content

Conversation

@ThePagi
Copy link
Contributor

@ThePagi ThePagi commented Aug 5, 2025

A feature handling seasonal snow cover, also usable for ash and similar materials that cover large areas. The feature blends a snow texture into the original rendered textures based on the configured criteria. The snow textures are always projected from the top (with parallax shifting the uv to avoid lines on vertical surfaces) and foliage optionally has snow only around the edges.

  • A json config is used to control snow cover for each worldspace or cell.
  • A main and optionally an alternative set of textures (by default marsh ice) define the look of the snow.
  • There are additional material properties and tints for the textures.
  • Surface angles at which the main and alternative textures appear are configurable.
  • Snow cover is controlled based on altitude and weather.
  • Snowy weather creates temporary snow, rain dissolves it.
  • The altitude the snow appears at (no matter the weather) can be configured to change based on game months.
  • Rain temporarily changes 'permanent' snow to the alternative set of textures.
  • An optional grayscale texture can be used to offset the altitude snow appears at. By default a texture mimicking vanilla snow placement is used.
  • Optionally the hue of foliage is shifted towards brown based on the altitude.

Summary by CodeRabbit

  • New Features

    • Realistic Snow Cover: dynamic accumulation/melting, seasonal timing, slope-based coverage, foliage tinting, PBR and VR-aware behavior, in-app UI with per-world presets (Tamriel, Whiterun, Markarth, Riften, Solitude, Windhelm) and per-world toggles.
  • Documentation

    • Added per-world configuration presets, whitelist/blacklist entries, and UI controls for tuning snow, textures, and foliage.
  • Chores

    • Integrated Snow Cover into rendering/features pipeline, resource loading/reload, persistent config, and improved ID-list parsing for whitelist/blacklist.

Exist and others added 30 commits September 8, 2024 09:30
Copy link
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: 3

♻️ Duplicate comments (1)
src/Globals.h (1)

54-90: Optional: normalize feature extern order (alphabetical) for consistency.

Prior reviews asked for alphabetical ordering in this block; consider reordering to reduce future merge conflicts.

🧹 Nitpick comments (7)
features/Snow Cover/Shaders/SnowCover/RiftenWorld.json (4)

12-12: Normalize path separators for MapTexture.

You used "Shaders\SnowCover\Skyrim". Other configs often use forward slashes. For consistency and fewer escape sequences, prefer "Shaders/SnowCover/Skyrim" unless the loader specifically requires backslashes.

-    "MapTexture": "Shaders\\SnowCover\\Skyrim",
+    "MapTexture": "Shaders/SnowCover/Skyrim",

19-21: Month bounds: confirm indices and seasonal intent for Riften.

MaxSummerMonth = 6 and MaxWinterMonth = 0. If months are 0–11, this sets winter to only month 0. Confirm this aligns with desired climate; otherwise consider a broader winter window (e.g., 10–2) or document rationale.


21-21: Snowing/Melting speeds both 1.0 — ensure transitions aren’t too abrupt/subtle.

If other worlds bias melting > snowing or vice‑versa, consider tuning to match Riften’s climate feel.

Also applies to: 27-27


4-6: Precision nit: trim float literals for readability.

Values like 0.019999999552965164 and 0.996880292892456 can be shortened (e.g., 0.02, 0.9969) without material impact and reduce churn in diffs.

Example:

-    "MainSpec": 0.019999999552965164,
+    "MainSpec": 0.02,
-    "AltSpec": 0.019999999552965164,
+    "AltSpec": 0.02,
-    "MainTint": [1.0, 0.996880292892456, 0.996880292892456, 1.0],
+    "MainTint": [1.0, 0.9969, 0.9969, 1.0],
-    "AltTint": [1.0, 1.0, 1.0, 0.6078431606292725],
+    "AltTint": [1.0, 1.0, 1.0, 0.6078],

Also applies to: 15-17, 22-22

package/Shaders/DistantTree.hlsl (1)

229-241: Minor HLSL fixes in foliage block.

  • Use uint outputs for GetDimensions to match the intrinsic signature.
  • Clamp computed skylight.
-    float rx;
-    float ry;
-    TexDiffuse.GetDimensions(rx, ry);
-    skylight = 1 - TexDiffuse.Sample(SampDiffuse, input.TexCoord.xy - float2(0, 2. / ry)).a;
+    uint rx, ry;
+    TexDiffuse.GetDimensions(rx, ry);
+    skylight = saturate(1.0 - TexDiffuse.Sample(SampDiffuse, input.TexCoord.xy - float2(0.0, 2.0 / (float)ry)).a);

Avoid recomputing CameraView mul; cache once and reuse its .z for depth and later code paths.

-    SnowCover::ApplySnowFoliage(baseColor.xyz, normal, input.WorldPosition.xyz + FrameBuffer::CameraPosAdjust[eyeIndex].xyz, skylight, mul(FrameBuffer::CameraView[eyeIndex], float4(input.WorldPosition.xyz, 1)).z);
+    float3 viewPosCached = mul(FrameBuffer::CameraView[eyeIndex], float4(input.WorldPosition.xyz, 1)).xyz;
+    SnowCover::ApplySnowFoliage(baseColor.xyz, normal, input.WorldPosition.xyz + FrameBuffer::CameraPosAdjust[eyeIndex].xyz, skylight, viewPosCached.z);
src/Features/SnowCover.h (2)

12-25: Fix constant name typos (maintainability).

Several constant names are misspelled: DEFAULT_FOLIGE_EFFECT_OFFSETDEFAULT_FOLIAGE_EFFECT_OFFSET, and DEFULAT_*DEFAULT_*. These propagate into member names (mapZscale) and can confuse future maintainers.

-	static constexpr float DEFAULT_FOLIGE_EFFECT_OFFSET = -2048.0;
+	static constexpr float DEFAULT_FOLIAGE_EFFECT_OFFSET = -2048.0;
@@
-	static constexpr float DEFULAT_MAIN_SPEC = 0.02;
-	static constexpr float DEFULAT_ALT_SPEC = 0.02;
-	static constexpr float DEFULAT_MAP_ZSCALE = 75000.0f;
-	static constexpr float DEFULAT_GLINT_1 = 1.2f;
-	static constexpr float DEFULAT_GLINT_2 = 33.f;
-	static constexpr float DEFULAT_GLINT_3 = .15f;
-	static constexpr float DEFULAT_GLINT_4 = 2.f;
+	static constexpr float DEFAULT_MAIN_SPEC = 0.02f;
+	static constexpr float DEFAULT_ALT_SPEC = 0.02f;
+	static constexpr float DEFAULT_MAP_ZSCALE = 75000.0f;
+	static constexpr float DEFAULT_GLINT_1 = 1.2f;
+	static constexpr float DEFAULT_GLINT_2 = 33.0f;
+	static constexpr float DEFAULT_GLINT_3 = 0.15f;
+	static constexpr float DEFAULT_GLINT_4 = 2.0f;

Remember to update uses (e.g., FoliageHeightOffset, mapZscale, glint defaults).


56-85: WorldSettings defaults: keep naming consistent with constants.

FoliageHeightOffset references DEFAULT_FOLIGE_EFFECT_OFFSET and mapZscale references a misspelled default. After renaming constants, align these initializers. Also consider PascalCase consistently or snake_case consistently; the file mixes both (mapZscale vs PeakMainAngle).

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a990816 and a8eb39e.

📒 Files selected for processing (20)
  • features/Snow Cover/Shaders/SnowCover/MarkarthWorld.json (1 hunks)
  • features/Snow Cover/Shaders/SnowCover/RiftenWorld.json (1 hunks)
  • features/Snow Cover/Shaders/SnowCover/SnowCover.hlsli (1 hunks)
  • features/Snow Cover/Shaders/SnowCover/SolitudeWorld.json (1 hunks)
  • features/Snow Cover/Shaders/SnowCover/Tamriel.json (1 hunks)
  • features/Snow Cover/Shaders/SnowCover/WhiterunWorld.json (1 hunks)
  • features/Snow Cover/Shaders/SnowCover/WindhelmWorld.json (1 hunks)
  • package/Shaders/Common/Permutation.hlsli (1 hunks)
  • package/Shaders/Common/SharedData.hlsli (3 hunks)
  • package/Shaders/DistantTree.hlsl (2 hunks)
  • package/Shaders/Lighting.hlsl (8 hunks)
  • package/Shaders/RunGrass.hlsl (2 hunks)
  • src/Feature.cpp (2 hunks)
  • src/FeatureBuffer.cpp (2 hunks)
  • src/Features/SnowCover.cpp (1 hunks)
  • src/Features/SnowCover.h (1 hunks)
  • src/Globals.cpp (2 hunks)
  • src/Globals.h (2 hunks)
  • src/State.h (2 hunks)
  • src/Utils/UI.cpp (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • features/Snow Cover/Shaders/SnowCover/Tamriel.json
🚧 Files skipped from review as they are similar to previous changes (9)
  • features/Snow Cover/Shaders/SnowCover/WhiterunWorld.json
  • package/Shaders/Common/Permutation.hlsli
  • features/Snow Cover/Shaders/SnowCover/SolitudeWorld.json
  • src/Utils/UI.cpp
  • features/Snow Cover/Shaders/SnowCover/SnowCover.hlsli
  • src/Features/SnowCover.cpp
  • features/Snow Cover/Shaders/SnowCover/MarkarthWorld.json
  • features/Snow Cover/Shaders/SnowCover/WindhelmWorld.json
  • package/Shaders/RunGrass.hlsl
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{cpp,cxx,cc,c,h,hpp,hxx,hlsl,hlsli,fx,fxh,py}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Do not include TODO/FIXME placeholders; provide complete, working solutions

Files:

  • src/State.h
  • package/Shaders/Lighting.hlsl
  • package/Shaders/DistantTree.hlsl
  • src/Globals.h
  • src/FeatureBuffer.cpp
  • src/Feature.cpp
  • package/Shaders/Common/SharedData.hlsli
  • src/Features/SnowCover.h
  • src/Globals.cpp
src/**/*.{cpp,cxx,cc,h,hpp,hxx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{cpp,cxx,cc,h,hpp,hxx}: Ensure SE/AE/VR runtime compatibility; use runtime detection patterns (e.g., REL::RelocateMember())
Include robust error handling and resource management with graceful degradation in the plugin code

Files:

  • src/State.h
  • src/Globals.h
  • src/FeatureBuffer.cpp
  • src/Feature.cpp
  • src/Features/SnowCover.h
  • src/Globals.cpp
🧠 Learnings (10)
📓 Common learnings
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#0
File: :0-0
Timestamp: 2025-06-24T07:17:36.604Z
Learning: When reviewing PRs, always clarify the scope if there are multiple related features or dependencies. WeatherPicker was a separate PR that was already merged, while this PR focuses specifically on WetnessEffects climate preset system enhancements.
Learnt from: ThePagi
PR: doodlum/skyrim-community-shaders#1369
File: src/Features/SnowCover.cpp:277-293
Timestamp: 2025-08-05T18:22:40.578Z
Learning: In the skyrim-community-shaders SnowCover feature, the wstrtostr and strtowstr utility functions defined in src/Features/SnowCover.cpp are unused and should be removed rather than fixed, as confirmed by the original author ThePagi.
Learnt from: ThePagi
PR: doodlum/skyrim-community-shaders#1369
File: src/Features/SnowCover.cpp:260-260
Timestamp: 2025-08-05T18:13:03.123Z
Learning: In the skyrim-community-shaders SnowCover feature, the time calculation uses division by 61.0 instead of 60.0 for seconds conversion in the perFrame.Month calculation. The original author ThePagi indicated this was intentional and makes no discernible difference to the snow cover functionality, suggesting it may be related to game-specific timing mechanics or balance considerations.
📚 Learning: 2025-08-03T18:37:19.690Z
Learnt from: jiayev
PR: doodlum/skyrim-community-shaders#0
File: :0-0
Timestamp: 2025-08-03T18:37:19.690Z
Learning: ISReflectionsRayTracing.hlsl and ISWorldMap.hlsl in the skyrim-community-shaders repository are image-space post-processing shaders that perform color sampling and blending operations that need proper linear color space handling for the linear lighting system. ISReflectionsRayTracing handles screen-space reflections and should use conditional Color::IrradianceToLinear/Gamma conversions similar to ISCompositeLensFlareVolumetricLighting.hlsl. ISWorldMap performs 7x7 color accumulation that should be done in linear space similar to the pattern used in ISSAOComposite.hlsl.

Applied to files:

  • package/Shaders/Lighting.hlsl
  • package/Shaders/DistantTree.hlsl
📚 Learning: 2025-08-05T17:40:44.828Z
Learnt from: ThePagi
PR: doodlum/skyrim-community-shaders#1369
File: package/Shaders/Lighting.hlsl:0-0
Timestamp: 2025-08-05T17:40:44.828Z
Learning: In the skyrim-community-shaders repository, ultra trees (object LOD trees) are detected using a compound shader define condition `defined(DO_ALPHA_TEST) && defined(LOD_BLENDING) && defined(RIM_LIGHTING) && defined(SOFT_LIGHTING)` because "they have no define" according to the comment. The `ExtraFlags::IsTree` flag is used for different tree handling (AO removal in skylighting) and may not apply to ultra trees specifically. Before replacing the compound condition with `IsTree`, verification is needed to ensure the flag covers ultra trees.

Applied to files:

  • package/Shaders/Lighting.hlsl
  • package/Shaders/DistantTree.hlsl
📚 Learning: 2025-07-01T18:01:07.079Z
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#0
File: :0-0
Timestamp: 2025-07-01T18:01:07.079Z
Learning: In the skyrim-community-shaders project, simple scalar constants in HLSL shaders use #define (e.g., #define NTHREADS 128), while more complex constants use static const within namespaces (e.g., Math namespace in Math.hlsli). For epsilon standardization, #define is the appropriate choice since epsilon values are simple scalar constants.

Applied to files:

  • package/Shaders/Lighting.hlsl
📚 Learning: 2025-06-08T11:25:14.536Z
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#577
File: src/Features/WetnessEffects.h:36-36
Timestamp: 2025-06-08T11:25:14.536Z
Learning: In the skyrim-community-shaders project, boolean flags in C++ structs that interface with HLSL shaders use `uint` type instead of `bool` for compatibility reasons. This ensures consistent 4-byte size, proper 16-byte alignment in constant buffers, and cross-platform compatibility when passing data between C++ and HLSL shaders.

Applied to files:

  • package/Shaders/Lighting.hlsl
📚 Learning: 2025-06-08T11:25:14.536Z
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#577
File: src/Features/WetnessEffects.h:36-36
Timestamp: 2025-06-08T11:25:14.536Z
Learning: In the skyrim-community-shaders project, boolean flags in C++ structs that interface with HLSL shaders use `uint` type instead of `bool` for compatibility reasons. This ensures consistent size, alignment, and cross-platform compatibility when passing data to shader constant buffers.

Applied to files:

  • package/Shaders/Lighting.hlsl
📚 Learning: 2025-07-05T05:20:45.823Z
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#0
File: :0-0
Timestamp: 2025-07-05T05:20:45.823Z
Learning: In the skyrim-community-shaders repository, file deletion error handling improvements that replace existence checks and try-catch blocks with std::filesystem::remove error-code-based approaches are considered bug fixes rather than refactoring, as they address inadequate error handling and misleading log messages.

Applied to files:

  • package/Shaders/Lighting.hlsl
📚 Learning: 2025-08-17T18:37:35.839Z
Learnt from: CR
PR: doodlum/skyrim-community-shaders#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-17T18:37:35.839Z
Learning: Applies to features/*/Shaders/**/*.{hlsl,hlsli,fx,fxh} : Avoid GPU register/buffer conflicts in HLSL; verify register usage (e.g., with hlslkit buffer scanning)

Applied to files:

  • package/Shaders/Lighting.hlsl
📚 Learning: 2025-08-17T18:37:35.839Z
Learnt from: CR
PR: doodlum/skyrim-community-shaders#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-17T18:37:35.839Z
Learning: Applies to features/**/*.{cpp,cxx,cc,h,hpp,hxx} : Register new features in the globals::features namespace

Applied to files:

  • src/Globals.h
  • src/Feature.cpp
  • src/Globals.cpp
📚 Learning: 2025-08-05T18:22:40.578Z
Learnt from: ThePagi
PR: doodlum/skyrim-community-shaders#1369
File: src/Features/SnowCover.cpp:277-293
Timestamp: 2025-08-05T18:22:40.578Z
Learning: In the skyrim-community-shaders SnowCover feature, the wstrtostr and strtowstr utility functions defined in src/Features/SnowCover.cpp are unused and should be removed rather than fixed, as confirmed by the original author ThePagi.

Applied to files:

  • src/Globals.cpp
🪛 GitHub Actions: Build Community Shaders and addons
src/Globals.h

[error] 64-64: Compilation failed: C2059 syntax error: '<<' in src/Globals.h:64 during MSVC build (cmake --build ALL).

🔇 Additional comments (18)
features/Snow Cover/Shaders/SnowCover/RiftenWorld.json (4)

18-25: Angle thresholds look plausible; confirm intended ordering and semantics.

MinAngle < PeakMainAngle < MaxAngle and PeakAltAngle = 1.0. Verify these match shader expectations (e.g., dot(N,Up) vs. angle in radians, inclusive bounds). Misinterpretation could swap main/alt coverage on steep vs. flat surfaces.


13-13: Height offsets: validate with in‑game sampling.

FoliageHeightOffset = -3000, WinterHeightOffset = -20000, SummerHeightOffset = 20000. Sanity‑check these against Tamriel/nearby worlds to avoid sudden coverage cliffs at cell borders.

Also applies to: 29-30


1-3: Tint toggles: intentional to affect grass but not trees.

AffectGrassTint = 1, AffectTreeTint = 0 — calling out as an intentional artistic choice for Riften’s look. No action needed if by design.

If trees should pick up edge snow tinting similar to other worlds, flip AffectTreeTint to 1.


10-11: Confirm MapMin/MapMax ordering (Y inverted)

MapMin Y = 208896.0 > MapMax Y = -176128.0 in features/Snow Cover/Shaders/SnowCover/RiftenWorld.json (lines 10–11); if the loader expects min≤max per axis this will invert/distort UV projection or cull the region.

-    "MapMax": [253952.0, -176128.0],
-    "MapMin": [-233472.0, 208896.0],
+    "MapMin": [-233472.0, -176128.0],
+    "MapMax": [253952.0, 208896.0],

Runner’s repo-wide check returned no output — re-run the checker (ensure paths with spaces are handled) to find other inverted configs.

src/FeatureBuffer.cpp (2)

13-13: SnowCover wiring include — LGTM.

Header inclusion aligns with later use. No issues.


39-53: Feature buffer packing order changed — ensure it exactly matches HLSL FeatureData

  • The byte layout produced by _GetFeatureBufferData(...) must exactly match the GPU FeatureData struct (SharedData.hlsli); reordering or switching .settings/GetCommonBufferData() will corrupt downstream fields.
  • I could not find package/Shaders/Common/SharedData.hlsli or src/FeatureBuffer.cpp in this checkout — provide those file paths or paste the FeatureData struct and the FeatureBuffer packing snippet so I can re-verify.
  • Replace any type‑punning writes into (unsigned char*) buffers with std::memcpy(data + offset, &feat_datas, sizeof(feat_datas)); offset += sizeof(feat_datas); to avoid undefined behavior.
src/Feature.cpp (2)

22-22: SnowCover include — LGTM.

Header inclusion aligns with globals and buffer usage.


203-230: Fix pointer bitwise-AND in feature list (src/Feature.cpp:203-230)

&globals::features::upscaling & globals::features::volumetricLighting performs a bitwise AND on pointers — split into two entries.

-    &globals::features::upscaling & globals::features::volumetricLighting,
+    &globals::features::upscaling,
+    &globals::features::volumetricLighting,

Search found only HLSL usages of SnowCover and no FeatureVersions header or SnowCover C++ symbols in the repo; confirm SnowCover is present in FeatureVersions::FEATURE_MINIMAL_VERSIONS and that SnowCover::SupportsVR() exists.

src/Globals.cpp (2)

21-21: SnowCover include — LGTM.

Matches new global declaration below.


56-79: Globals feature instances — verify types and externs.

SnowCover snowCover{} addition and reorder look fine; I couldn't locate src/Globals.h or the feature headers in the checked-out workspace — confirm that src/Globals.h (or the repo's Globals header) declares:
extern SnowCover snowCover;
and that InteriorSunShadows is declared in the header you include (e.g. src/Features/InteriorSun.h).

src/State.h (2)

183-186: Including VertexShaderDescriptor in equality is correct — audit hashes/memcmp

Good addition. The provided repo search produced no hits for custom hashes or memcmp-based comparisons of PermutationCB; manually verify there are no std::hash specializations, unordered_map keys, or memcmp comparisons that must be updated to include VertexShaderDescriptor. Location: src/State.h (lines 183–186)


153-155: NoSnow bit added — HLSL uses it; confirm C++ definition & reserve next bit for UI.

  • package/Shaders/Lighting.hlsl:2250 checks Permutation::ExtraShaderDescriptor & Permutation::ExtraFlags::NoSnow — ensure ExtraShaderDescriptors::NoSnow = 1 << 6 in C++ matches that bit and any serialization/UI that inspects this mask.
  • I could not locate src/State.h or the C++ enum in this checkout; verify the C++ definition exists and that 1 << 7 is unused in both C++ and HLSL before adding InventoryUI (InventoryUI = 1 << 7).
package/Shaders/DistantTree.hlsl (2)

181-189: SNOW_COVER gating is clean and avoids macro collisions. Undefining SNOW/PROJECTED_UV/SPARKLE and aliasing SampColorSampler prevent conflicts; BASIC_SNOW_COVER is intentionally defined in package/Shaders/DistantTree.hlsl:185 and package/Shaders/RunGrass.hlsl:455.


225-228: Normal from ddx/ddy — single normal path here; verify winding.

Normal is computed once as -normalize(cross(ddx_coarse(input.WorldPosition.xyz), ddy_coarse(input.WorldPosition.xyz))) (lines 225–227) and encoded via FrameBuffer::WorldToView(...)->GBuffer::EncodeNormal (line 274). There is no alternate forward/deferred normal in this shader, so the “both paths” part of the original comment is incorrect — still confirm the leading - produces the intended winding/lighting (compare to previous commit or other shaders).

Likely an incorrect or invalid review comment.

package/Shaders/Lighting.hlsl (1)

1019-1024: Vertex-normal flip exclusion looks correct.

Excluding LOD alpha-tested soft-lighting permutations from the double-sided normal fix prevents artifacts on ultra trees.

If you want to replace the ultra-tree compound condition elsewhere, confirm ExtraFlags::IsTree also applies to object LOD trees before changing it.

package/Shaders/Common/SharedData.hlsli (2)

140-175: SnowCoverSettings layout looks CB-friendly; flags correctly use uint.

Good use of uint for booleans and padding to maintain 16-byte alignment across C++/HLSL. No register pressure added (still in b6).

Please confirm FeatureBuffer packing on the C++ side matches this exact field order (especially the two pad blocks and trailing uint3), to avoid subtle misbinds.


234-251: Reordered FeatureData entries may destabilize other features.

Reordering entries (e.g., moving cloudShadowsSettings and inserting snowCoverSettings earlier) changes offsets for every consumer. If the C++ side updated the same order for all features, you're fine; otherwise, consider appending new blocks to the end to minimize blast radius.

I can provide a quick map of sizeof/offsets from the C++ structs to cross-check against this HLSL layout if helpful.

src/Features/SnowCover.h (1)

133-158: Seasonal altitude math: OK; follows author’s intent.

Using game calendar with fractional month is fine. Header uses / 60.0; the .cpp’s / 61.0 note was intentional per author—just ensure both places are consistent with the chosen behavior.

Copy link
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

Caution

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

⚠️ Outside diff range comments (1)
package/Shaders/Common/SharedData.hlsli (1)

39-49: Ensure C++ side binding for ExtendedMaterialSettings
Search found no references to either CPMSettings or ExtendedMaterialSettings in the C++ codebase. You must add or update the CPU-side code that populates the shader constant buffer to use the new ExtendedMaterialSettings struct name and verify its memory layout matches the HLSL definition.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a8eb39e and bd4d3f0.

📒 Files selected for processing (4)
  • package/Shaders/Common/SharedData.hlsli (3 hunks)
  • src/Feature.cpp (2 hunks)
  • src/Globals.cpp (2 hunks)
  • src/Globals.h (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{cpp,cxx,cc,c,h,hpp,hxx,hlsl,hlsli,fx,fxh,py}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Do not include TODO/FIXME placeholders; provide complete, working solutions

Files:

  • src/Globals.h
  • src/Globals.cpp
  • src/Feature.cpp
  • package/Shaders/Common/SharedData.hlsli
src/**/*.{cpp,cxx,cc,h,hpp,hxx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{cpp,cxx,cc,h,hpp,hxx}: Ensure SE/AE/VR runtime compatibility; use runtime detection patterns (e.g., REL::RelocateMember())
Include robust error handling and resource management with graceful degradation in the plugin code

Files:

  • src/Globals.h
  • src/Globals.cpp
  • src/Feature.cpp
🧠 Learnings (1)
📚 Learning: 2025-08-17T18:37:35.839Z
Learnt from: CR
PR: doodlum/skyrim-community-shaders#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-17T18:37:35.839Z
Learning: Applies to features/**/*.{cpp,cxx,cc,h,hpp,hxx} : Register new features in the globals::features namespace

Applied to files:

  • src/Globals.cpp
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Validate shader compilation (VR, .github/configs/shader-validation-vr.yaml)
  • GitHub Check: Validate shader compilation (Flatrim, .github/configs/shader-validation.yaml)
  • GitHub Check: Build plugin and addons
🔇 Additional comments (7)
src/Feature.cpp (1)

22-22: LGTM: SnowCover header included.

The include follows the established pattern for feature headers and is necessary for the SnowCover integration.

src/Globals.cpp (2)

21-21: LGTM: SnowCover header included.

The include is necessary for the SnowCover feature registration and follows the established pattern.


56-78: LGTM: Feature instances properly registered.

The new feature instances (ExtendedTranslucency, PerformanceOverlay, SnowCover, Upscaling) and reordered declarations follow the established registration pattern in the globals::features namespace. Default initialization is appropriate.

Based on learnings.

src/Globals.h (2)

6-28: LGTM: Forward declarations properly added.

All forward declarations for the new and reordered features (ExtendedTranslucency, LODBlending, LightLimitFix, PerformanceOverlay, Skylighting, SnowCover, TerrainVariation, Upscaling, VolumetricLighting) are necessary and follow the established pattern.


59-81: LGTM: Extern declarations consistent with definitions.

All extern declarations for the new and reordered features match their definitions in Globals.cpp. No duplicates or merge conflict artifacts detected.

package/Shaders/Common/SharedData.hlsli (2)

234-250: Critical: Confirm CPU-side FeatureData struct and buffer update logic matches HLSL cbuffer layout.
Ensure the C++ definition (or generated code) and buffer update calls reflect the new field order and added settings from SharedData.hlsli.


140-175: Verify C++ SnowCoverSettings definition and 16-byte alignment
Ensure the HLSL struct at package/Shaders/Common/SharedData.hlsli (lines 140–175) is mirrored exactly in C++—same field order, types and padding—and add a static_assert(sizeof(SnowCoverSettings) % 16 == 0) to validate GPU constant buffer layout.

Copy link
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

♻️ Duplicate comments (2)
package/Shaders/RunGrass.hlsl (1)

454-454: Use Math::PI; remove local PI macro

PI is already provided in Common/Math.hlsli with higher precision. Drop the local macro and reference Math::PI.

-#       define PI 3.1415927
package/Shaders/Lighting.hlsl (1)

2229-2235: GetDimensions type mismatch — use uint and cast

Match DXC/FXC semantics.

-    float rx;
-    float ry;
-    TexColorSampler.GetDimensions(rx, ry);
+    uint rx, ry;
+    TexColorSampler.GetDimensions(rx, ry);
@@
-    snowOcclusion = 1 - TexColorSampler.Sample(SampColorSampler, uv - float2(0, 2. / ry)).a;
+    snowOcclusion = 1.0 - TexColorSampler.Sample(SampColorSampler, uv - float2(0.0, 2.0 / float(ry))).a;
🧹 Nitpick comments (6)
src/Globals.h (1)

64-66: Consider alphabetical ordering for consistency.

The extern declarations lodBlending and lightLimitFix are not in alphabetical order. For consistency with the rest of the file and based on past review feedback, consider reordering them alphabetically (lightLimitFix before lodBlending).

Apply this diff to reorder alphabetically:

-		extern LODBlending lodBlending;
 		extern LightLimitFix lightLimitFix;
+		extern LODBlending lodBlending;
-		extern LightLimitFix lightLimitFix;
 		extern PerformanceOverlay performanceOverlay;
package/Shaders/Common/SharedData.hlsli (1)

140-176: Consider consistent naming convention.

The SnowCoverSettings struct mixes PascalCase (e.g., EnableSnowCover, AffectGrassTint) and camelCase (e.g., peakMainAngle, mapZscale) for member names. For better maintainability, consider using a consistent naming convention throughout the struct.

src/Utils/UI.cpp (4)

278-286: Restore previous ImGui window font scale (avoid clobbering nested scales)

Currently resets to 1.0f, which can break callers that changed scale earlier. Save/restore the previous window scale instead.

-    // Apply scale if needed
-    if (scale != 1.0f) {
-      ImGui::SetWindowFontScale(scale);
-    }
+    // Apply scale if needed, preserving previous scale
+    float _prevScale = 1.0f;
+    if (scale != 1.0f) {
+      ImGuiWindow* _w = ImGui::GetCurrentWindow();
+      _prevScale = _w->FontWindowScale;
+      ImGui::SetWindowFontScale(scale);
+    }
@@
-    // Restore original scale if needed
-    if (scale != 1.0f)
-      ImGui::SetWindowFontScale(1.0f);
+    // Restore previous window scale if changed
+    if (scale != 1.0f) {
+      ImGui::SetWindowFontScale(_prevScale);
+    }

315-323: Same issue here: don’t hard-reset font scale to 1.0f

Preserve and restore the previous window font scale.

-    ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
-    ImGui::SetWindowFontScale(textScale);
+    ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
+    float _prevScale = 1.0f;
+    {
+      ImGuiWindow* _w = ImGui::GetCurrentWindow();
+      _prevScale = _w->FontWindowScale;
+    }
+    ImGui::SetWindowFontScale(textScale);
@@
-    ImGui::SetWindowFontScale(1.0f);
+    ImGui::SetWindowFontScale(_prevScale);

79-86: Guard against null/empty filename before logging/IO

Avoid logging a null C-string and calling stbi_load with null/empty paths.

   // Validate input parameters
-  if (!device || !out_srv) {
+  if (!device || !out_srv) {
     logger::warn("LoadTextureFromFile: Invalid parameters - device: {}, out_srv: {}",
       device ? "valid" : "null", out_srv ? "valid" : "null");
     return false;
   }
+  if (!filename || filename[0] == '\0') {
+    logger::warn("LoadTextureFromFile: Invalid filename (null/empty)");
+    *out_srv = nullptr;
+    return false;
+  }

715-718: Avoid UB with tolower on signed char; use unsigned char wrapper

::tolower on ‘char’ is UB for negative values. Use std::tolower with unsigned char.

-    std::transform(shortName.begin(), shortName.end(), shortName.begin(), ::tolower);
-    std::transform(displayName.begin(), displayName.end(), displayName.begin(), ::tolower);
-    std::transform(query.begin(), query.end(), query.begin(), ::tolower);
+    auto _toLower = [](unsigned char c) { return static_cast<char>(std::tolower(c)); };
+    std::transform(shortName.begin(), shortName.end(), shortName.begin(), _toLower);
+    std::transform(displayName.begin(), displayName.end(), displayName.begin(), _toLower);
+    std::transform(query.begin(), query.end(), query.begin(), _toLower);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bd4d3f0 and 417657d.

📒 Files selected for processing (7)
  • package/Shaders/Common/SharedData.hlsli (3 hunks)
  • package/Shaders/DistantTree.hlsl (2 hunks)
  • package/Shaders/Lighting.hlsl (8 hunks)
  • package/Shaders/RunGrass.hlsl (2 hunks)
  • src/Globals.cpp (2 hunks)
  • src/Globals.h (2 hunks)
  • src/Utils/UI.cpp (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{cpp,cxx,cc,c,h,hpp,hxx,hlsl,hlsli,fx,fxh,py}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Do not include TODO/FIXME placeholders; provide complete, working solutions

Files:

  • package/Shaders/DistantTree.hlsl
  • src/Utils/UI.cpp
  • src/Globals.h
  • package/Shaders/RunGrass.hlsl
  • package/Shaders/Lighting.hlsl
  • src/Globals.cpp
  • package/Shaders/Common/SharedData.hlsli
src/**/*.{cpp,cxx,cc,h,hpp,hxx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{cpp,cxx,cc,h,hpp,hxx}: Ensure SE/AE/VR runtime compatibility; use runtime detection patterns (e.g., REL::RelocateMember())
Include robust error handling and resource management with graceful degradation in the plugin code

Files:

  • src/Utils/UI.cpp
  • src/Globals.h
  • src/Globals.cpp
🧠 Learnings (2)
📓 Common learnings
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#0
File: :0-0
Timestamp: 2025-06-24T07:17:36.604Z
Learning: When reviewing PRs, always clarify the scope if there are multiple related features or dependencies. WeatherPicker was a separate PR that was already merged, while this PR focuses specifically on WetnessEffects climate preset system enhancements.
📚 Learning: 2025-08-05T17:40:44.828Z
Learnt from: ThePagi
PR: doodlum/skyrim-community-shaders#1369
File: package/Shaders/Lighting.hlsl:0-0
Timestamp: 2025-08-05T17:40:44.828Z
Learning: In the skyrim-community-shaders repository, ultra trees (object LOD trees) are detected using a compound shader define condition `defined(DO_ALPHA_TEST) && defined(LOD_BLENDING) && defined(RIM_LIGHTING) && defined(SOFT_LIGHTING)` because "they have no define" according to the comment. The `ExtraFlags::IsTree` flag is used for different tree handling (AO removal in skylighting) and may not apply to ultra trees specifically. Before replacing the compound condition with `IsTree`, verification is needed to ensure the flag covers ultra trees.

Applied to files:

  • package/Shaders/Lighting.hlsl
🔇 Additional comments (13)
package/Shaders/DistantTree.hlsl (2)

185-192: Good SNOW_COVER gating/integration

Header hygiene looks correct: SNOW/PROJECTED_UV/SPARKLE are sanitized; include path is consistent. No issues.


229-232: Geometric normal orientation — please verify

Using -normalize(cross(ddx, ddy)) centralizes normal calc, but the sign convention must match other foliage/distant tree passes. Please sanity-check against sun lighting and shadows for flipped highlights.

package/Shaders/RunGrass.hlsl (1)

455-462: SnowCover include/gating looks correct

Macro hygiene matches pattern used elsewhere; no issues.

src/Globals.cpp (1)

21-21: Feature wiring OK; confirm UI/initialization ordering

SnowCover/ExtendedTranslucency additions and reordering look fine. Please verify menu ordering/init side-effects are intended (some code reads features sequentially).

Also applies to: 55-77

package/Shaders/Lighting.hlsl (4)

30-38: Pragmatic SNOW_COVER gating for characters

Undefining SNOW_COVER for SKINNED/SKIN/EYE/HAIR/!EXTENDED_MATERIALS is sensible to avoid unintended overlays.


1866-1877: LOD land noise skip when snow active — good guard

Skipping LOD noise darkening when SnowCover is enabled avoids double darkening. Looks good.


3046-3049: Nice touch: vertexColor blended by snowFactor

This preserves tint while adding snow — safe and visually coherent.


2228-2237: Incorrect assumption about RIM_LIGHTING in ultra-tree detection
No occurrence of defined(DO_ALPHA_TEST) && defined(LOD_BLENDING) && defined(RIM_LIGHTING) && defined(SOFT_LIGHTING) exists in Lighting.hlsl—historically the guard has never included RIM_LIGHTING. This change retains existing behavior; only add RIM_LIGHTING if you need to narrow the match.

Likely an incorrect or invalid review comment.

src/Globals.h (1)

6-28: LGTM! Forward declarations are well-organized.

The new forward declarations for ExtendedTranslucency, PerformanceOverlay, SnowCover, TerrainVariation, Upscaling, and VolumetricLighting follow a logical alphabetical ordering, making the codebase easier to navigate.

package/Shaders/Common/SharedData.hlsli (2)

39-39: LGTM! Descriptive struct rename.

Renaming CPMSettings to ExtendedMaterialSettings improves code clarity and is consistently applied in the cbuffer declaration at line 238.


246-246: Verify cbuffer placement does not break existing features.

Based on past review discussions, placing new feature settings in the middle of the cbuffer (rather than at the end) can potentially break other features if there are padding or alignment issues. While the struct appears properly aligned, please confirm that this placement of snowCoverSettings has been tested with all existing features to avoid unexpected issues.

Based on learnings from past reviews about cbuffer ordering concerns.

src/Utils/UI.cpp (2)

1196-1196: LGTM: newline at EOF

Thanks for fixing the trailing newline/brace formatting. No behavioral changes.


17-27: Unable to locate UI.cpp; please verify includes
I couldn’t find src/Utils/UI.cpp—confirm the correct file path and ensure you add #include <array> for std::array usage and #include <cctype> if you refactor to use std::tolower.

Copy link
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

♻️ Duplicate comments (1)
src/Features/SnowCover.cpp (1)

217-217: Remove commented-out dead code.

Delete this commented function rather than leaving it in the source.

-//void SnowCover::Draw(const RE::BSShader*, const uint32_t){}

As per coding guidelines

🧹 Nitpick comments (5)
src/Features/SnowCover.cpp (5)

113-113: Replace fixed buffer with imgui_stdlib::InputText.

Using a fixed 128-byte buffer with ImGui::InputText is error-prone. Use imgui_stdlib::InputText with std::string instead.

-ImGui::InputText("Map texture", mapbuf, 128);
+ImGui::InputText("Map texture", &map_tex);

Then remove the manual buffer copy at line 134.

As per coding guidelines


154-154: Replace fixed buffer with imgui_stdlib::InputText.

Using a fixed 128-byte buffer with ImGui::InputText is error-prone. Use imgui_stdlib::InputText with std::string instead.

-ImGui::InputText("Main texture", tbuf, 128);
+ImGui::InputText("Main texture", &main_tex);

Then remove the manual string assignment at line 158.

As per coding guidelines


159-159: Replace fixed buffer with imgui_stdlib::InputText.

Using a fixed 128-byte buffer with ImGui::InputText is error-prone. Use imgui_stdlib::InputText with std::string instead.

-ImGui::InputText("Alt texture", altbuf, 128);
+ImGui::InputText("Alt texture", &alt_tex);

Then remove the manual string assignment at line 163.

As per coding guidelines


422-427: Consider using ComPtr for safer COM resource management.

Raw pointer management with manual Release() calls is error-prone. Consider using Microsoft::WRL::ComPtr or similar RAII wrapper for the texture views.

Example:

std::array<ComPtr<ID3D11ShaderResourceView>, 7> views;
// No manual Release() needed - automatic cleanup

This prevents resource leaks and double-free issues.

As per coding guidelines


15-19: Centralize safe string-copy helper

No existing safe string-copy function was found; copyString is acceptable here, but consider creating a string_utils module to house it for future reuse.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 417657d and 56ddd84.

📒 Files selected for processing (1)
  • src/Features/SnowCover.cpp (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{cpp,cxx,cc,c,h,hpp,hxx,hlsl,hlsli,fx,fxh,py}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Do not include TODO/FIXME placeholders; provide complete, working solutions

Files:

  • src/Features/SnowCover.cpp
src/**/*.{cpp,cxx,cc,h,hpp,hxx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{cpp,cxx,cc,h,hpp,hxx}: Ensure SE/AE/VR runtime compatibility; use runtime detection patterns (e.g., REL::RelocateMember())
Include robust error handling and resource management with graceful degradation in the plugin code

Files:

  • src/Features/SnowCover.cpp
🧠 Learnings (4)
📚 Learning: 2025-08-05T18:13:03.123Z
Learnt from: ThePagi
PR: doodlum/skyrim-community-shaders#1369
File: src/Features/SnowCover.cpp:260-260
Timestamp: 2025-08-05T18:13:03.123Z
Learning: In the skyrim-community-shaders SnowCover feature, the time calculation uses division by 61.0 instead of 60.0 for seconds conversion in the perFrame.Month calculation. The original author ThePagi indicated this was intentional and makes no discernible difference to the snow cover functionality, suggesting it may be related to game-specific timing mechanics or balance considerations.

Applied to files:

  • src/Features/SnowCover.cpp
📚 Learning: 2025-08-05T18:22:40.578Z
Learnt from: ThePagi
PR: doodlum/skyrim-community-shaders#1369
File: src/Features/SnowCover.cpp:277-293
Timestamp: 2025-08-05T18:22:40.578Z
Learning: In the skyrim-community-shaders SnowCover feature, the wstrtostr and strtowstr utility functions defined in src/Features/SnowCover.cpp are unused and should be removed rather than fixed, as confirmed by the original author ThePagi.

Applied to files:

  • src/Features/SnowCover.cpp
📚 Learning: 2025-06-24T07:17:36.604Z
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#0
File: :0-0
Timestamp: 2025-06-24T07:17:36.604Z
Learning: When reviewing PRs, always clarify the scope if there are multiple related features or dependencies. WeatherPicker was a separate PR that was already merged, while this PR focuses specifically on WetnessEffects climate preset system enhancements.

Applied to files:

  • src/Features/SnowCover.cpp
📚 Learning: 2025-07-05T05:20:45.823Z
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#0
File: :0-0
Timestamp: 2025-07-05T05:20:45.823Z
Learning: In the skyrim-community-shaders repository, file deletion error handling improvements that replace existence checks and try-catch blocks with std::filesystem::remove error-code-based approaches are considered bug fixes rather than refactoring, as they address inadequate error handling and misleading log messages.

Applied to files:

  • src/Features/SnowCover.cpp
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Validate shader compilation (Flatrim, .github/configs/shader-validation.yaml)
  • GitHub Check: Validate shader compilation (VR, .github/configs/shader-validation-vr.yaml)
  • GitHub Check: Build plugin and addons

@alandtse
Copy link
Collaborator

alandtse commented Oct 1, 2025

Please review rabbit suggestions and resolve once reviewed.

Copy link
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

♻️ Duplicate comments (8)
src/Features/SnowCover.cpp (8)

113-113: Consider using ImGui::InputText from imgui_stdlib.

Instead of managing char buffers manually, consider using ImGui::InputText with std::string from imgui_stdlib.h for cleaner code and automatic memory management.

Based on learnings


204-208: Simplify formatted text output.

ImGui::Text supports formatting directly via ImGui::Text("Month: %.2f", perFrame.Month). Using fmt::format and .c_str() adds unnecessary overhead.

Based on learnings


345-347: Add explicit file operation success checks.

While the try-catch block handles std::system_error, explicitly checking file.is_open() before writing and file.good() after writing provides better error detection and clearer diagnostics.

As per coding guidelines

 	auto path = (Util::PathHelpers::GetFeatureShaderPath("SnowCover") / curr_worldspace).replace_extension(std::filesystem::path(".json"));
 	std::ofstream file(path);
+	if (!file.is_open()) {
+		logger::error("[Snow Cover] Failed to open file for writing: {}", path.generic_string());
+		return;
+	}
 	file << config.dump(4);
+	if (!file.good()) {
+		logger::error("[Snow Cover] Failed to write config to file: {}", path.generic_string());
+	}

27-27: Define magic numbers as named constants.

The altitude range values (-20000.0f, 20000.0f) and other magic numbers (buffer sizes 128/256, clamp range -2.0f/2.0f) should be defined as named constants in the header file for maintainability.

Based on learnings


217-217: Remove commented-out dead code.

The commented-out Draw function should be removed rather than left in the codebase.

Based on learnings


228-245: Potential stale snowingDensity when weather data unavailable.

When EnableSnowCover is true but precipitationData is null (lines 231-235), snowingDensity is never set and may retain a stale value from previous frames. Initialize snowingDensity = 0.0f at the start of the EnableSnowCover block to ensure clean state.

As per coding guidelines

 	bool snowing = false;
 	bool raining = false;
 	if (wsettings.EnableSnowCover) {
+		snowingDensity = 0.0f;
 		if (auto sky = RE::Sky::GetSingleton()) {

469-472: Critical: Pointer aliasing causes double-free on subsequent Reload().

When alt textures are not provided, views[3-5] are aliased to views[0-2] without incrementing reference counts. On the next Reload() call, lines 423-427 and 445-450 will Release the same texture views twice, causing double-free.

As per coding guidelines

Solution: Increment reference count when aliasing:

 		} else {
 			views[3] = views[0];
+			views[3]->AddRef();
 			views[4] = views[1];
+			views[4]->AddRef();
 			views[5] = views[2];
+			views[5]->AddRef();
 		}

Alternative solution: Track aliases and skip Release:

Maintain a std::set<size_t> of aliased indices and check before calling Release.


546-546: Critical: Potential null pointer dereference in animation check.

Line 546 calls userData->GetObjectReference()->IsBoundAnimObject() without verifying that GetObjectReference() returns a non-null pointer. This can cause a null pointer dereference.

As per coding guidelines

-	if ((a_pass->geometry->HasAnimation() || (userData && (userData->GetObjectReference()->IsBoundAnimObject() || userData->CanBeMoved()))) && !whitelist.contains(FormIdParser::fnv_hash(name))) {
+	auto objRef = userData ? userData->GetObjectReference() : nullptr;
+	if ((a_pass->geometry->HasAnimation() || (userData && ((objRef && objRef->IsBoundAnimObject()) || userData->CanBeMoved()))) && !whitelist.contains(FormIdParser::fnv_hash(name))) {
🧹 Nitpick comments (1)
src/Features/SnowCover.cpp (1)

15-19: copyString is unique—consider moving to a shared utilities module. No existing string-copy helper was found in Util.h or other utility files; relocate this helper to a common utilities header for discoverability and future reuse.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 56ddd84 and 62db6fa.

📒 Files selected for processing (1)
  • src/Features/SnowCover.cpp (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{cpp,cxx,cc,c,h,hpp,hxx,hlsl,hlsli,fx,fxh,py}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Do not include TODO/FIXME placeholders; provide complete, working solutions

Files:

  • src/Features/SnowCover.cpp
src/**/*.{cpp,cxx,cc,h,hpp,hxx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{cpp,cxx,cc,h,hpp,hxx}: Ensure SE/AE/VR runtime compatibility; use runtime detection patterns (e.g., REL::RelocateMember())
Include robust error handling and resource management with graceful degradation in the plugin code

Files:

  • src/Features/SnowCover.cpp
🧠 Learnings (5)
📓 Common learnings
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#0
File: :0-0
Timestamp: 2025-06-24T07:17:36.604Z
Learning: When reviewing PRs, always clarify the scope if there are multiple related features or dependencies. WeatherPicker was a separate PR that was already merged, while this PR focuses specifically on WetnessEffects climate preset system enhancements.
📚 Learning: 2025-08-05T18:13:03.123Z
Learnt from: ThePagi
PR: doodlum/skyrim-community-shaders#1369
File: src/Features/SnowCover.cpp:260-260
Timestamp: 2025-08-05T18:13:03.123Z
Learning: In the skyrim-community-shaders SnowCover feature, the time calculation uses division by 61.0 instead of 60.0 for seconds conversion in the perFrame.Month calculation. The original author ThePagi indicated this was intentional and makes no discernible difference to the snow cover functionality, suggesting it may be related to game-specific timing mechanics or balance considerations.

Applied to files:

  • src/Features/SnowCover.cpp
📚 Learning: 2025-08-05T18:22:40.578Z
Learnt from: ThePagi
PR: doodlum/skyrim-community-shaders#1369
File: src/Features/SnowCover.cpp:277-293
Timestamp: 2025-08-05T18:22:40.578Z
Learning: In the skyrim-community-shaders SnowCover feature, the wstrtostr and strtowstr utility functions defined in src/Features/SnowCover.cpp are unused and should be removed rather than fixed, as confirmed by the original author ThePagi.

Applied to files:

  • src/Features/SnowCover.cpp
📚 Learning: 2025-06-24T07:17:36.604Z
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#0
File: :0-0
Timestamp: 2025-06-24T07:17:36.604Z
Learning: When reviewing PRs, always clarify the scope if there are multiple related features or dependencies. WeatherPicker was a separate PR that was already merged, while this PR focuses specifically on WetnessEffects climate preset system enhancements.

Applied to files:

  • src/Features/SnowCover.cpp
📚 Learning: 2025-07-05T05:20:45.823Z
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#0
File: :0-0
Timestamp: 2025-07-05T05:20:45.823Z
Learning: In the skyrim-community-shaders repository, file deletion error handling improvements that replace existence checks and try-catch blocks with std::filesystem::remove error-code-based approaches are considered bug fixes rather than refactoring, as they address inadequate error handling and misleading log messages.

Applied to files:

  • src/Features/SnowCover.cpp
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build plugin and addons
  • GitHub Check: Validate shader compilation (Flatrim, .github/configs/shader-validation.yaml)
  • GitHub Check: Validate shader compilation (VR, .github/configs/shader-validation-vr.yaml)
🔇 Additional comments (4)
src/Features/SnowCover.cpp (4)

10-13: LGTM!

The JSON serialization macro correctly includes both EnableExpensiveFoliage and SnowHeightOffset fields for complete UserSettings serialization.


276-281: LGTM!

The initialization logic correctly calls Reload() and sets up the initial lastHour value.


283-296: LGTM!

The worldspace retrieval logic correctly handles both interior cells and worldspaces, returning the appropriate editor ID.


514-531: LGTM!

The serialization and reset functions are correctly implemented. The empty Reset() appears intentional as resource cleanup happens elsewhere.

Exist and others added 2 commits October 2, 2025 00:20
Automated formatting by clang-format, prettier, and other hooks.
See https://pre-commit.ci for details.
Copy link
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: 0

♻️ Duplicate comments (7)
src/Features/SnowCover.cpp (7)

32-32: Define altitude range constants in the header.

The hardcoded altitude range values -20000.0f and 20000.0f appear multiple times. Define these as named constants in SnowCover.h for maintainability.

Based on learnings

Add to SnowCover.h:

static constexpr float ALTITUDE_RANGE_MIN = -20000.0f;
static constexpr float ALTITUDE_RANGE_MAX = 20000.0f;

Then update these lines:

-	ImGui::SliderFloat("Snow Offset", &settings.SnowHeightOffset, -20000.0f, 20000.0f);
+	ImGui::SliderFloat("Snow Offset", &settings.SnowHeightOffset, ALTITUDE_RANGE_MIN, ALTITUDE_RANGE_MAX);

Also applies to: 98-98, 102-102


222-222: Remove commented dead code.

Delete the commented-out function declaration for better code hygiene.

-//void SnowCover::Draw(const RE::BSShader*, const uint32_t){}

515-515: Define texture slot as a named constant.

The shader resource slot number 38 should be defined as a named constant (e.g., SNOW_TEXTURE_SLOT) in the header file for clarity and maintainability.

Based on learnings

Add to SnowCover.h:

static constexpr uint32_t SNOW_TEXTURE_SLOT = 38;

Then update:

-		context->PSSetShaderResources(38, (uint)views.size(), views.data());
+		context->PSSetShaderResources(SNOW_TEXTURE_SLOT, (uint)views.size(), views.data());

233-250: Initialize snowingDensity to prevent stale data.

When EnableSnowCover is true but weather/precipitation data is unavailable (lines 234-246), snowingDensity is never set and may retain a stale value from previous frames.

As per coding guidelines

Apply this diff:

 SnowCover::PerFrame SnowCover::GetCommonBufferData()
 {
 	Reload();
 
+	snowingDensity = 0.0f;
 	static float delta = 0;

348-356: Add file open and write success checks.

The code doesn't verify that the file opened successfully before writing or check if the write operation succeeded.

As per coding guidelines

Apply this diff:

 	try {
 		auto curr_worldspace = GetWorldspace();
 		auto path = (Util::PathHelpers::GetFeatureShaderPath("SnowCover") / curr_worldspace).replace_extension(std::filesystem::path(".json"));
 		std::ofstream file(path);
+		if (!file.is_open()) {
+			logger::error("[Snow Cover] Failed to open file for writing: {}", path.generic_string());
+			return;
+		}
 		file << config.dump(4);
+		if (!file.good()) {
+			logger::error("[Snow Cover] Failed to write config to file: {}", path.generic_string());
+		}
 	} catch (const std::system_error& e) {

458-478: Pointer aliasing risk with texture view assignment.

Lines 461, 466, 471, 475-477: Assigning views[3] = views[0] (and similar) creates pointer aliasing. If these views are Released independently later (e.g., lines 427-432, 450-455, 480-481), this causes a double-free.

As per coding guidelines

Consider one of these approaches:

  1. AddRef when aliasing: views[3] = views[0]; views[3]->AddRef();
  2. Track aliases: Use a boolean map to skip Release on aliased views
  3. Duplicate textures: Create distinct view objects for defaults

Apply approach 1 (simplest):

 			if (hr != S_OK) {
 				logger::warn("Snow Cover: Error loading {}.dds texture: {}", alt_tex.generic_string(), hr);
 				views[3] = views[0];
+				if (views[3]) views[3]->AddRef();
 			}
 			hr = DirectX::CreateDDSTextureFromFile(device, context, (data_path / alt_tex).concat("_n.dds").native().c_str(), nullptr, &views.at(4));
 			if (hr != S_OK) {
 				logger::warn("Snow Cover: Error loading {}_n.dds texture: {}", alt_tex.generic_string(), hr);
 				views[4] = views[1];
+				if (views[4]) views[4]->AddRef();
 			}
 			hr = DirectX::CreateDDSTextureFromFile(device, context, (data_path / alt_tex).concat("_rmaos.dds").native().c_str(), nullptr, &views.at(5));
 			if (hr != S_OK) {
 				logger::warn("Snow Cover: Error loading {}_rmaos.dds texture: {}", alt_tex.generic_string(), hr);
 				views[5] = views[2];
+				if (views[5]) views[5]->AddRef();
 			}
 
 		} else {
 			views[3] = views[0];
+			if (views[3]) views[3]->AddRef();
 			views[4] = views[1];
+			if (views[4]) views[4]->AddRef();
 			views[5] = views[2];
+			if (views[5]) views[5]->AddRef();
 		}

546-568: Potential null pointer dereference in animation check.

Line 551: GetObjectReference() may return null, but the code calls IsBoundAnimObject() without checking.

As per coding guidelines

Apply this diff:

-	if ((a_pass->geometry->HasAnimation() || (userData && (userData->GetObjectReference()->IsBoundAnimObject() || userData->CanBeMoved()))) && !whitelist.contains(FormIdParser::fnv_hash(name))) {
+	auto objRef = userData ? userData->GetObjectReference() : nullptr;
+	if ((a_pass->geometry->HasAnimation() || (userData && ((objRef && objRef->IsBoundAnimObject()) || userData->CanBeMoved()))) && !whitelist.contains(FormIdParser::fnv_hash(name))) {
🧹 Nitpick comments (1)
src/Features/SnowCover.h (1)

12-12: Fix typos in constant names.

Line 12: DEFAULT_FOLIGE_EFFECT_OFFSET should be DEFAULT_FOLIAGE_EFFECT_OFFSET
Lines 18-19: DEFULAT_MAIN_SPEC and DEFULAT_ALT_SPEC should be DEFAULT_MAIN_SPEC and DEFAULT_ALT_SPEC

Apply this diff:

-	static constexpr float DEFAULT_FOLIGE_EFFECT_OFFSET = -2048.0;  // color foliage earlier/later than snow appears
+	static constexpr float DEFAULT_FOLIAGE_EFFECT_OFFSET = -2048.0;  // color foliage earlier/later than snow appears
-	static constexpr float DEFULAT_MAIN_SPEC = 0.02;        // specular for main material
-	static constexpr float DEFULAT_ALT_SPEC = 0.02;         // specular for alt material
+	static constexpr float DEFAULT_MAIN_SPEC = 0.02;        // specular for main material
+	static constexpr float DEFAULT_ALT_SPEC = 0.02;         // specular for alt material

Also update references in lines 60, 68-69:

-		float FoliageHeightOffset = DEFAULT_FOLIGE_EFFECT_OFFSET;
+		float FoliageHeightOffset = DEFAULT_FOLIAGE_EFFECT_OFFSET;
-		float MainSpec = DEFULAT_MAIN_SPEC;
-		float AltSpec = DEFULAT_ALT_SPEC;
+		float MainSpec = DEFAULT_MAIN_SPEC;
+		float AltSpec = DEFAULT_ALT_SPEC;

Also applies to: 18-19

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 62db6fa and 9f37ae2.

📒 Files selected for processing (3)
  • features/Snow Cover/Shaders/SnowCover/whitelist.txt (1 hunks)
  • src/Features/SnowCover.cpp (1 hunks)
  • src/Features/SnowCover.h (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • features/Snow Cover/Shaders/SnowCover/whitelist.txt
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{cpp,cxx,cc,c,h,hpp,hxx,hlsl,hlsli,fx,fxh,py}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Do not include TODO/FIXME placeholders; provide complete, working solutions

Files:

  • src/Features/SnowCover.h
  • src/Features/SnowCover.cpp
src/**/*.{cpp,cxx,cc,h,hpp,hxx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{cpp,cxx,cc,h,hpp,hxx}: Ensure SE/AE/VR runtime compatibility; use runtime detection patterns (e.g., REL::RelocateMember())
Include robust error handling and resource management with graceful degradation in the plugin code

Files:

  • src/Features/SnowCover.h
  • src/Features/SnowCover.cpp
🧠 Learnings (5)
📓 Common learnings
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#0
File: :0-0
Timestamp: 2025-06-24T07:17:36.604Z
Learning: When reviewing PRs, always clarify the scope if there are multiple related features or dependencies. WeatherPicker was a separate PR that was already merged, while this PR focuses specifically on WetnessEffects climate preset system enhancements.
📚 Learning: 2025-08-05T18:13:03.123Z
Learnt from: ThePagi
PR: doodlum/skyrim-community-shaders#1369
File: src/Features/SnowCover.cpp:260-260
Timestamp: 2025-08-05T18:13:03.123Z
Learning: In the skyrim-community-shaders SnowCover feature, the time calculation uses division by 61.0 instead of 60.0 for seconds conversion in the perFrame.Month calculation. The original author ThePagi indicated this was intentional and makes no discernible difference to the snow cover functionality, suggesting it may be related to game-specific timing mechanics or balance considerations.

Applied to files:

  • src/Features/SnowCover.cpp
📚 Learning: 2025-08-05T18:22:40.578Z
Learnt from: ThePagi
PR: doodlum/skyrim-community-shaders#1369
File: src/Features/SnowCover.cpp:277-293
Timestamp: 2025-08-05T18:22:40.578Z
Learning: In the skyrim-community-shaders SnowCover feature, the wstrtostr and strtowstr utility functions defined in src/Features/SnowCover.cpp are unused and should be removed rather than fixed, as confirmed by the original author ThePagi.

Applied to files:

  • src/Features/SnowCover.cpp
📚 Learning: 2025-06-24T07:17:36.604Z
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#0
File: :0-0
Timestamp: 2025-06-24T07:17:36.604Z
Learning: When reviewing PRs, always clarify the scope if there are multiple related features or dependencies. WeatherPicker was a separate PR that was already merged, while this PR focuses specifically on WetnessEffects climate preset system enhancements.

Applied to files:

  • src/Features/SnowCover.cpp
📚 Learning: 2025-07-05T05:20:45.823Z
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#0
File: :0-0
Timestamp: 2025-07-05T05:20:45.823Z
Learning: In the skyrim-community-shaders repository, file deletion error handling improvements that replace existence checks and try-catch blocks with std::filesystem::remove error-code-based approaches are considered bug fixes rather than refactoring, as they address inadequate error handling and misleading log messages.

Applied to files:

  • src/Features/SnowCover.cpp
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Validate shader compilation (Flatrim, .github/configs/shader-validation.yaml)
  • GitHub Check: Build plugin and addons
  • GitHub Check: Validate shader compilation (VR, .github/configs/shader-validation-vr.yaml)
  • GitHub Check: Feature Version Audit (PR)
🔇 Additional comments (7)
src/Features/SnowCover.h (3)

134-159: LGTM! Robust seasonal altitude calculation.

The method correctly handles null calendar with a fallback value and implements proper seasonal interpolation between summer and winter heights.


176-193: LGTM! Proper hook installation pattern.

The vtable patching follows the project's standard pattern using REL::Relocation for SE/AE/VR runtime compatibility.


101-175: LGTM! Well-structured feature class interface.

The public API is comprehensive and properly exposes all necessary controls for the SnowCover feature, including settings, resource management, and lifecycle hooks.

src/Features/SnowCover.cpp (4)

1-20: LGTM! Safe string copy implementation.

The copyString helper correctly uses strncpy with proper null-termination to prevent buffer overflows.


281-301: LGTM! Proper worldspace/cell detection.

The GetWorldspace utility correctly handles null checks for TES singleton and provides appropriate fallbacks for both interior cells and exterior worldspaces.


359-390: LGTM! Robust file loading with proper error handling.

The file opening logic correctly checks for existence and open success, with appropriate error logging and early returns.


523-536: LGTM! Clean serialization implementation.

The Load/Save methods correctly delegate to the JSON macro, and RestoreDefaultSettings properly resets state.

Copy link
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: 0

♻️ Duplicate comments (7)
package/Shaders/RunGrass.hlsl (1)

560-570: Fix GetDimensions type mismatch.

GetDimensions writes uint but rx and ry are declared as float, which can break compilation with DXC/FXC.

Apply this diff to fix the type mismatch:

-            float rx;
-            float ry;
-            TexBaseSampler.GetDimensions(rx, ry);
+            uint rx, ry;
+            TexBaseSampler.GetDimensions(rx, ry);
@@
-                snowOcclusion = max(snowOcclusion, 1 - TexBaseSampler.SampleBias(SampBaseSampler, float2(input.TexCoord.x, input.TexCoord.y * 0.5 - 0.5 / ry), SharedData::MipBias).a);
+                snowOcclusion = max(snowOcclusion, 1.0 - TexBaseSampler.SampleBias(SampBaseSampler, float2(input.TexCoord.x, input.TexCoord.y * 0.5 - 0.5 / float(ry)), SharedData::MipBias).a);
@@
-                snowOcclusion = max(snowOcclusion, 1 - TexBaseSampler.SampleBias(SampBaseSampler, input.TexCoord.xy - float2(0, 1. / ry), SharedData::MipBias).a);
+                snowOcclusion = max(snowOcclusion, 1.0 - TexBaseSampler.SampleBias(SampBaseSampler, input.TexCoord.xy - float2(0.0, 1.0 / float(ry)), SharedData::MipBias).a);
package/Shaders/Lighting.hlsl (2)

2221-2226: Avoid implicit bool→float cast.

At line 2225, inWorld (bool) is assigned directly to snowOcclusion (float), causing an implicit cast.

Apply this diff to make the cast explicit:

-#       else
-    float snowOcclusion = inWorld;
-#       endif
+#       else
+    float snowOcclusion = inWorld ? 1.0 : 0.0;
+#       endif

2228-2236: Fix GetDimensions type mismatch.

GetDimensions writes uint but rx and ry are declared as float, which can break compilation with DXC/FXC.

Apply this diff to fix the type mismatch:

-    float rx;
-    float ry;
-    TexColorSampler.GetDimensions(rx, ry);
+    uint rx, ry;
+    TexColorSampler.GetDimensions(rx, ry);
@@
-    snowOcclusion = 1 - TexColorSampler.Sample(SampColorSampler, uv - float2(0, 2. / ry)).a;
+    snowOcclusion = 1.0 - TexColorSampler.Sample(SampColorSampler, uv - float2(0.0, 2.0 / float(ry))).a;
src/Features/SnowCover.cpp (4)

118-118: Use ImGui::InputText from imgui_stdlib for type safety.

The current approach uses raw char buffers with ImGui::InputText. Consider using imgui_stdlib.h's InputText overload that accepts std::string* directly, eliminating buffer management and size constraints.

Based on learnings


209-213: Remove redundant fmt::format wrapper.

ImGui::Text() already supports format strings directly via ImGui::Text("%s", fmt::format(...).c_str()) pattern, or you can use ImGui::Text() with format specifiers. The current pattern adds unnecessary string construction.

-		ImGui::Text(fmt::format("Month: {}", perFrame.Month).c_str());
-		ImGui::Text(fmt::format("TimeSnowing: {}", perFrame.TimeSnowing).c_str());
-		ImGui::Text(fmt::format("SnowingDensity: {}", perFrame.SnowingDensity).c_str());
+		ImGui::Text("Month: %.2f", perFrame.Month);
+		ImGui::Text("TimeSnowing: %.2f", perFrame.TimeSnowing);
+		ImGui::Text("SnowingDensity: %.2f", perFrame.SnowingDensity);

Based on learnings


222-222: Remove commented-out dead code.

This commented function serves no purpose and should be deleted to keep the codebase clean.

Based on learnings


460-473: Missing AddRef() on fallback texture aliasing causes double-free risk.

When texture loading fails at lines 462, 467, and 472, the code assigns views[3/4/5] = views[0/1/2] without calling AddRef(). Later, when views are released (lines 451-456, 484-485, and presumably in cleanup), this creates a double-free condition.

Lines 476-481 correctly call AddRef() before aliasing. Apply the same pattern to the error fallback cases:

 			if (hr != S_OK) {
 				logger::warn("Snow Cover: Error loading {}.dds texture: {}", alt_tex.generic_string(), hr);
+				views[0]->AddRef();
 				views[3] = views[0];
 			}
 			hr = DirectX::CreateDDSTextureFromFile(device, context, (data_path / alt_tex).concat("_n.dds").native().c_str(), nullptr, &views.at(4));
 			if (hr != S_OK) {
 				logger::warn("Snow Cover: Error loading {}_n.dds texture: {}", alt_tex.generic_string(), hr);
+				views[1]->AddRef();
 				views[4] = views[1];
 			}
 			hr = DirectX::CreateDDSTextureFromFile(device, context, (data_path / alt_tex).concat("_rmaos.dds").native().c_str(), nullptr, &views.at(5));
 			if (hr != S_OK) {
 				logger::warn("Snow Cover: Error loading {}_rmaos.dds texture: {}", alt_tex.generic_string(), hr);
+				views[2]->AddRef();
 				views[5] = views[2];
 			}

As per coding guidelines

🧹 Nitpick comments (2)
package/Shaders/Lighting.hlsl (1)

2272-2274: Remove confusing comment.

The comment "why is glossiness not just a float anyway?" is misleading because glossiness is already a float scalar in this context. Consider removing it to avoid confusion.

Apply this diff to remove the comment:

-        snowFactor = SnowCover::ApplySnow(snowedColor, snowNormal, glossiness, shininess, disp, adjustedWorldPos, snowOcclusion, input.WorldPosition.z - waterHeight, viewPosition.z, uv - uvOriginal);
-        // why is glossiness not just a float anyway?
+        snowFactor = SnowCover::ApplySnow(snowedColor, snowNormal, glossiness, shininess, disp, adjustedWorldPos, snowOcclusion, input.WorldPosition.z - waterHeight, viewPosition.z, uv - uvOriginal);
src/Features/SnowCover.cpp (1)

16-20: Move copyString to utility module or use existing helper.

This helper duplicates functionality that likely exists in the codebase's utility module. Per review feedback, custom string utilities should be placed in utils rather than feature-specific files.

Consider checking if Util already provides a similar function, or move this to Util if it's needed project-wide.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9f37ae2 and 4b84f13.

📒 Files selected for processing (4)
  • package/Shaders/Lighting.hlsl (14 hunks)
  • package/Shaders/RunGrass.hlsl (2 hunks)
  • src/Features/SnowCover.cpp (1 hunks)
  • src/Features/SnowCover.h (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/Features/SnowCover.h
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{cpp,cxx,cc,c,h,hpp,hxx,hlsl,hlsli,fx,fxh,py}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Do not include TODO/FIXME placeholders; provide complete, working solutions

Files:

  • package/Shaders/Lighting.hlsl
  • src/Features/SnowCover.cpp
  • package/Shaders/RunGrass.hlsl
src/**/*.{cpp,cxx,cc,h,hpp,hxx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{cpp,cxx,cc,h,hpp,hxx}: Ensure SE/AE/VR runtime compatibility; use runtime detection patterns (e.g., REL::RelocateMember())
Include robust error handling and resource management with graceful degradation in the plugin code

Files:

  • src/Features/SnowCover.cpp
🧠 Learnings (9)
📓 Common learnings
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#0
File: :0-0
Timestamp: 2025-06-24T07:17:36.604Z
Learning: When reviewing PRs, always clarify the scope if there are multiple related features or dependencies. WeatherPicker was a separate PR that was already merged, while this PR focuses specifically on WetnessEffects climate preset system enhancements.
📚 Learning: 2025-08-05T17:40:44.828Z
Learnt from: ThePagi
PR: doodlum/skyrim-community-shaders#1369
File: package/Shaders/Lighting.hlsl:0-0
Timestamp: 2025-08-05T17:40:44.828Z
Learning: In the skyrim-community-shaders repository, ultra trees (object LOD trees) are detected using a compound shader define condition `defined(DO_ALPHA_TEST) && defined(LOD_BLENDING) && defined(RIM_LIGHTING) && defined(SOFT_LIGHTING)` because "they have no define" according to the comment. The `ExtraFlags::IsTree` flag is used for different tree handling (AO removal in skylighting) and may not apply to ultra trees specifically. Before replacing the compound condition with `IsTree`, verification is needed to ensure the flag covers ultra trees.

Applied to files:

  • package/Shaders/Lighting.hlsl
📚 Learning: 2025-06-08T11:25:14.536Z
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#577
File: src/Features/WetnessEffects.h:36-36
Timestamp: 2025-06-08T11:25:14.536Z
Learning: In the skyrim-community-shaders project, boolean flags in C++ structs that interface with HLSL shaders use `uint` type instead of `bool` for compatibility reasons. This ensures consistent 4-byte size, proper 16-byte alignment in constant buffers, and cross-platform compatibility when passing data between C++ and HLSL shaders.

Applied to files:

  • package/Shaders/Lighting.hlsl
📚 Learning: 2025-06-08T11:25:14.536Z
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#577
File: src/Features/WetnessEffects.h:36-36
Timestamp: 2025-06-08T11:25:14.536Z
Learning: In the skyrim-community-shaders project, boolean flags in C++ structs that interface with HLSL shaders use `uint` type instead of `bool` for compatibility reasons. This ensures consistent size, alignment, and cross-platform compatibility when passing data to shader constant buffers.

Applied to files:

  • package/Shaders/Lighting.hlsl
📚 Learning: 2025-08-05T18:13:03.123Z
Learnt from: ThePagi
PR: doodlum/skyrim-community-shaders#1369
File: src/Features/SnowCover.cpp:260-260
Timestamp: 2025-08-05T18:13:03.123Z
Learning: In the skyrim-community-shaders SnowCover feature, the time calculation uses division by 61.0 instead of 60.0 for seconds conversion in the perFrame.Month calculation. The original author ThePagi indicated this was intentional and makes no discernible difference to the snow cover functionality, suggesting it may be related to game-specific timing mechanics or balance considerations.

Applied to files:

  • src/Features/SnowCover.cpp
📚 Learning: 2025-08-05T18:22:40.578Z
Learnt from: ThePagi
PR: doodlum/skyrim-community-shaders#1369
File: src/Features/SnowCover.cpp:277-293
Timestamp: 2025-08-05T18:22:40.578Z
Learning: In the skyrim-community-shaders SnowCover feature, the wstrtostr and strtowstr utility functions defined in src/Features/SnowCover.cpp are unused and should be removed rather than fixed, as confirmed by the original author ThePagi.

Applied to files:

  • src/Features/SnowCover.cpp
📚 Learning: 2025-06-24T07:17:36.604Z
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#0
File: :0-0
Timestamp: 2025-06-24T07:17:36.604Z
Learning: When reviewing PRs, always clarify the scope if there are multiple related features or dependencies. WeatherPicker was a separate PR that was already merged, while this PR focuses specifically on WetnessEffects climate preset system enhancements.

Applied to files:

  • src/Features/SnowCover.cpp
📚 Learning: 2025-07-05T05:20:45.823Z
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#0
File: :0-0
Timestamp: 2025-07-05T05:20:45.823Z
Learning: In the skyrim-community-shaders repository, file deletion error handling improvements that replace existence checks and try-catch blocks with std::filesystem::remove error-code-based approaches are considered bug fixes rather than refactoring, as they address inadequate error handling and misleading log messages.

Applied to files:

  • src/Features/SnowCover.cpp
📚 Learning: 2025-10-02T14:20:33.417Z
Learnt from: ThePagi
PR: doodlum/skyrim-community-shaders#1369
File: src/Features/SnowCover.cpp:515-515
Timestamp: 2025-10-02T14:20:33.417Z
Learning: In the Community Shaders codebase (skyrim-community-shaders repository), hardcoded shader resource slot numbers are used directly in code rather than being defined as named constants. This is the established convention and should not be flagged as an issue.

Applied to files:

  • src/Features/SnowCover.cpp
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Validate shader compilation (Flatrim, .github/configs/shader-validation.yaml)
  • GitHub Check: Validate shader compilation (VR, .github/configs/shader-validation-vr.yaml)
  • GitHub Check: Build plugin and addons
🔇 Additional comments (10)
package/Shaders/RunGrass.hlsl (1)

454-460: LGTM!

The SNOW_COVER scaffolding correctly undefines conflicting macros and includes the SnowCover feature for grass shading.

package/Shaders/Lighting.hlsl (8)

30-39: LGTM!

The SNOW_COVER gating correctly disables the feature for incompatible shader paths and enables GLINT for TRUE_PBR+SNOW_COVER.


967-970: LGTM!

The SnowCover.hlsli inclusion is properly guarded and SNOW is undefined to prevent conflicts with the new SNOW_COVER feature.


1062-1066: LGTM!

The sh0 initialization values (0 for LANDSCAPE, 0.5 for non-LANDSCAPE) are appropriate for their respective displacement contexts.


1410-1410: LGTM!

The fallback RMAOS assignments correctly compute roughness as 1 - glossiness for non-PBR landscape tiles.

Also applies to: 1491-1491, 1571-1571, 1651-1651, 1732-1732, 1812-1812


1866-1876: LGTM!

The SNOW_COVER guard correctly prevents the LOD noise multiplier from being applied to baseColor when snow cover is enabled, since snow will override it later.


2294-2299: LGTM!

The glint precomputation is properly guarded by the GLINT define and only executes when GlintLogMicrofacetDensity > 1.1, which is appropriate.


3045-3047: LGTM!

The vertex color adjustment correctly blends toward white based on snowFactor, which is appropriate for snow-covered surfaces.


1015-1015: Ultra tree detection remains fragile.

The compound condition !(defined(DO_ALPHA_TEST) && defined(LOD_BLENDING) && defined(SOFT_LIGHTING)) for ultra trees is fragile and could break with shader permutation changes. However, this is necessary because ultra trees have no dedicated define, and ExtraFlags::IsTree may not apply to them (based on learnings).

Based on learnings

src/Features/SnowCover.cpp (1)

550-572: LGTM! Null-safety checks are correctly implemented.

The conditional at line 555 properly guards GetObjectReference() before calling IsBoundAnimObject() using short-circuit evaluation. The animation/havok object detection and whitelist/blacklist logic are correctly implemented.

Copy link
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: 0

🧹 Nitpick comments (1)
package/Shaders/Lighting.hlsl (1)

2250-2250: Consider simplifying nested max() for readability.

The nested max() calls for computing disp in LANDSCAPE mode are functionally correct but could be more readable. Consider introducing a helper or loop if HLSL permits, or using intermediate variables.

Current:

float disp = sh0 * max(displacementParams[0].HeightScale * input.LandBlendWeights1.x, max(...));

Alternative (if supported):

float maxHeight = displacementParams[0].HeightScale * input.LandBlendWeights1.x;
maxHeight = max(maxHeight, displacementParams[1].HeightScale * input.LandBlendWeights1.y);
maxHeight = max(maxHeight, displacementParams[2].HeightScale * input.LandBlendWeights1.z);
maxHeight = max(maxHeight, displacementParams[3].HeightScale * input.LandBlendWeights1.w);
maxHeight = max(maxHeight, displacementParams[4].HeightScale * input.LandBlendWeights2.x);
maxHeight = max(maxHeight, displacementParams[5].HeightScale * input.LandBlendWeights2.y);
float disp = sh0 * maxHeight;

This improves readability without changing behavior.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4b84f13 and 68fd9d9.

📒 Files selected for processing (1)
  • package/Shaders/Lighting.hlsl (13 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{cpp,cxx,cc,c,h,hpp,hxx,hlsl,hlsli,fx,fxh,py}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Do not include TODO/FIXME placeholders; provide complete, working solutions

Files:

  • package/Shaders/Lighting.hlsl
🧠 Learnings (4)
📓 Common learnings
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#0
File: :0-0
Timestamp: 2025-06-24T07:17:36.604Z
Learning: When reviewing PRs, always clarify the scope if there are multiple related features or dependencies. WeatherPicker was a separate PR that was already merged, while this PR focuses specifically on WetnessEffects climate preset system enhancements.
📚 Learning: 2025-08-05T17:40:44.828Z
Learnt from: ThePagi
PR: doodlum/skyrim-community-shaders#1369
File: package/Shaders/Lighting.hlsl:0-0
Timestamp: 2025-08-05T17:40:44.828Z
Learning: In the skyrim-community-shaders repository, ultra trees (object LOD trees) are detected using a compound shader define condition `defined(DO_ALPHA_TEST) && defined(LOD_BLENDING) && defined(RIM_LIGHTING) && defined(SOFT_LIGHTING)` because "they have no define" according to the comment. The `ExtraFlags::IsTree` flag is used for different tree handling (AO removal in skylighting) and may not apply to ultra trees specifically. Before replacing the compound condition with `IsTree`, verification is needed to ensure the flag covers ultra trees.

Applied to files:

  • package/Shaders/Lighting.hlsl
📚 Learning: 2025-06-08T11:25:14.536Z
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#577
File: src/Features/WetnessEffects.h:36-36
Timestamp: 2025-06-08T11:25:14.536Z
Learning: In the skyrim-community-shaders project, boolean flags in C++ structs that interface with HLSL shaders use `uint` type instead of `bool` for compatibility reasons. This ensures consistent 4-byte size, proper 16-byte alignment in constant buffers, and cross-platform compatibility when passing data between C++ and HLSL shaders.

Applied to files:

  • package/Shaders/Lighting.hlsl
📚 Learning: 2025-06-08T11:25:14.536Z
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#577
File: src/Features/WetnessEffects.h:36-36
Timestamp: 2025-06-08T11:25:14.536Z
Learning: In the skyrim-community-shaders project, boolean flags in C++ structs that interface with HLSL shaders use `uint` type instead of `bool` for compatibility reasons. This ensures consistent size, alignment, and cross-platform compatibility when passing data to shader constant buffers.

Applied to files:

  • package/Shaders/Lighting.hlsl
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build plugin and addons
  • GitHub Check: Validate shader compilation (Flatrim, .github/configs/shader-validation.yaml)
  • GitHub Check: Validate shader compilation (VR, .github/configs/shader-validation-vr.yaml)
🔇 Additional comments (8)
package/Shaders/Lighting.hlsl (8)

30-39: LGTM: Preprocessor gating is correct.

The SNOW_COVER feature is appropriately disabled for character-related shaders (SKINNED, SKIN, EYE, HAIR) and when EXTENDED_MATERIALS is not available. The conditional GLINT definition under TRUE_PBR for snow materials is reasonable.


967-970: LGTM: Conditional include is correct.

Undefining SNOW when SNOW_COVER is defined prevents conflicts between the legacy snow system and the new SnowCover feature. The conditional include of SnowCover.hlsli is appropriate.


1062-1066: LGTM: sh0 initialization is explicit and correct.

The explicit initialization of sh0 to 0 for LANDSCAPE and 0.5 for non-LANDSCAPE paths prepares for subsequent parallax/displacement calculations. The different values are intentional for the different rendering paths.


1410-1410: LGTM: Fallback RMAOS assignments are correct.

The fallback RMAOS values for non-PBR landscape tiles are correctly computed. The pattern float4(1 - glossiness, 0, 1, 0) appropriately sets roughness from glossiness, with zero metallic, full AO, and zero specular. The scalar glossiness is correctly multiplied by the weight and the float4 vector.

Also applies to: 1491-1491, 1571-1571, 1651-1651, 1732-1732, 1812-1812


1870-1873: LGTM: Snow cover correctly bypasses LOD noise.

The SNOW_COVER guard ensures that when snow is active, the LOD land noise multiplier doesn't affect baseColor, allowing the snow system to fully control the appearance. This is the correct behavior.


2241-2289: LGTM: Snow application logic is comprehensive.

The main snow cover implementation correctly:

  • Gates snow application on EnableSnowCover and appropriate shader flags
  • Computes displacement from parallax/height data for different rendering paths
  • Applies snow to color, normal, and material properties via SnowCover::ApplySnow / ApplySnowPBR
  • Conditionally affects foliage tint when AffectTreeTint is enabled
  • Blends snow normals with surface normals
  • Adjusts LOD land colors and fade factors when snow is present

The conditional branches correctly handle TRUE_PBR, LANDSCAPE, EMAT, LODLANDNOISE, and LOD_LAND_BLEND permutations.


2293-2298: LGTM: GLINT precomputation is correctly positioned.

The GLINT precomputation is correctly placed after the SNOW_COVER block, ensuring that snow-modified glint parameters are used. The conditional check on GlintLogMicrofacetDensity > 1.1 appropriately skips precomputation when glint is disabled or negligible.


3044-3046: LGTM: Snow vertex color adjustment is correct.

The vertex color adjustment vertexColor.rgb = snowFactor + (1 - snowFactor) * vertexColor.rgb correctly brightens the vertex color toward white based on the snow coverage factor. This is equivalent to lerp(vertexColor.rgb, 1.0, snowFactor) and is the expected behavior for snow-covered surfaces.

Copy link
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

Caution

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

⚠️ Outside diff range comments (1)
package/Shaders/Lighting.hlsl (1)

1411-1814: Avoid double-multiplying landscape blend weights in fallback RMA.

Inside each LandTile*PBR == 0 branch we now multiply by the blend weight twice: once explicitly (input.LandBlendWeights*.? * …) and again when adding to blendedRMAOS (* weight). That squares the layer contribution, so mixed tiles report far too little roughness/occlusion. Drop the explicit weight factor in the RMAOS initialisers (same fix applies to all six layers).

-			landRMAOS1 = input.LandBlendWeights1.x * float4(1 - glossiness, 0, 1, 0);
+			landRMAOS1 = float4(1 - glossiness, 0, 1, 0);

(Repeat for landRMAOS2, landRMAOS3, landRMAOS4, landRMAOS5, and landRMAOS6.)

♻️ Duplicate comments (1)
package/Shaders/Lighting.hlsl (1)

2229-2235: Use uint outputs with GetDimensions to keep the shader compiling.

Texture2D::GetDimensions writes uints. Declaring rx/ry as float mis-matches the signature and fails under DXC/FXC. Declare them as uint (or uint2) and cast when you need a float divisor.

-	float rx;
-	float ry;
-	TexColorSampler.GetDimensions(rx, ry);
+	uint rx;
+	uint ry;
+	TexColorSampler.GetDimensions(rx, ry);
@@
-		snowOcclusion = 1 - TexColorSampler.Sample(SampColorSampler, uv - float2(0, 2. / ry)).a;
+		snowOcclusion = 1 - TexColorSampler.Sample(SampColorSampler, uv - float2(0.0, 2.0 / float(ry))).a;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 68fd9d9 and 0efdc3a.

📒 Files selected for processing (2)
  • features/Snow Cover/Shaders/SnowCover/SnowCover.hlsli (1 hunks)
  • package/Shaders/Lighting.hlsl (13 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{cpp,cxx,cc,c,h,hpp,hxx,hlsl,hlsli,fx,fxh,py}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Do not include TODO/FIXME placeholders; provide complete, working solutions

Files:

  • features/Snow Cover/Shaders/SnowCover/SnowCover.hlsli
  • package/Shaders/Lighting.hlsl
features/*/Shaders/**/*.{hlsl,hlsli,fx,fxh}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

features/*/Shaders/**/*.{hlsl,hlsli,fx,fxh}: Place all feature shaders under features/YourFeature/Shaders/
Avoid GPU register/buffer conflicts in HLSL; verify register usage (e.g., with hlslkit buffer scanning)

Files:

  • features/Snow Cover/Shaders/SnowCover/SnowCover.hlsli
🧠 Learnings (5)
📓 Common learnings
Learnt from: ThePagi
PR: doodlum/skyrim-community-shaders#1369
File: src/Features/SnowCover.cpp:277-293
Timestamp: 2025-08-05T18:22:40.578Z
Learning: In the skyrim-community-shaders SnowCover feature, the wstrtostr and strtowstr utility functions defined in src/Features/SnowCover.cpp are unused and should be removed rather than fixed, as confirmed by the original author ThePagi.
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#0
File: :0-0
Timestamp: 2025-06-24T07:17:36.604Z
Learning: When reviewing PRs, always clarify the scope if there are multiple related features or dependencies. WeatherPicker was a separate PR that was already merged, while this PR focuses specifically on WetnessEffects climate preset system enhancements.
📚 Learning: 2025-08-03T18:37:19.690Z
Learnt from: jiayev
PR: doodlum/skyrim-community-shaders#0
File: :0-0
Timestamp: 2025-08-03T18:37:19.690Z
Learning: ISReflectionsRayTracing.hlsl and ISWorldMap.hlsl in the skyrim-community-shaders repository are image-space post-processing shaders that perform color sampling and blending operations that need proper linear color space handling for the linear lighting system. ISReflectionsRayTracing handles screen-space reflections and should use conditional Color::IrradianceToLinear/Gamma conversions similar to ISCompositeLensFlareVolumetricLighting.hlsl. ISWorldMap performs 7x7 color accumulation that should be done in linear space similar to the pattern used in ISSAOComposite.hlsl.

Applied to files:

  • features/Snow Cover/Shaders/SnowCover/SnowCover.hlsli
📚 Learning: 2025-08-05T17:40:44.828Z
Learnt from: ThePagi
PR: doodlum/skyrim-community-shaders#1369
File: package/Shaders/Lighting.hlsl:0-0
Timestamp: 2025-08-05T17:40:44.828Z
Learning: In the skyrim-community-shaders repository, ultra trees (object LOD trees) are detected using a compound shader define condition `defined(DO_ALPHA_TEST) && defined(LOD_BLENDING) && defined(RIM_LIGHTING) && defined(SOFT_LIGHTING)` because "they have no define" according to the comment. The `ExtraFlags::IsTree` flag is used for different tree handling (AO removal in skylighting) and may not apply to ultra trees specifically. Before replacing the compound condition with `IsTree`, verification is needed to ensure the flag covers ultra trees.

Applied to files:

  • package/Shaders/Lighting.hlsl
📚 Learning: 2025-06-08T11:25:14.536Z
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#577
File: src/Features/WetnessEffects.h:36-36
Timestamp: 2025-06-08T11:25:14.536Z
Learning: In the skyrim-community-shaders project, boolean flags in C++ structs that interface with HLSL shaders use `uint` type instead of `bool` for compatibility reasons. This ensures consistent 4-byte size, proper 16-byte alignment in constant buffers, and cross-platform compatibility when passing data between C++ and HLSL shaders.

Applied to files:

  • package/Shaders/Lighting.hlsl
📚 Learning: 2025-06-08T11:25:14.536Z
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#577
File: src/Features/WetnessEffects.h:36-36
Timestamp: 2025-06-08T11:25:14.536Z
Learning: In the skyrim-community-shaders project, boolean flags in C++ structs that interface with HLSL shaders use `uint` type instead of `bool` for compatibility reasons. This ensures consistent size, alignment, and cross-platform compatibility when passing data to shader constant buffers.

Applied to files:

  • package/Shaders/Lighting.hlsl
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Validate shader compilation (VR, .github/configs/shader-validation-vr.yaml)
  • GitHub Check: Validate shader compilation (Flatrim, .github/configs/shader-validation.yaml)
  • GitHub Check: Build plugin and addons

Copy link
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

♻️ Duplicate comments (2)
src/Utils/FormIdParser.h (1)

8-13: Complete the documentation for all utility methods.

The previous review requested comments for these methods. Documentation has been added for parseHexFile (line 9) and parseTriNameFile (line 11), but trim (line 8) and fnv_hash (line 13) still lack explanatory comments. For consistency and maintainability, all public methods should be documented.

Apply this diff to add the missing documentation:

+	// Removes leading and trailing whitespace from a string.
 	static std::string trim(const std::string& str);
 	// Parses a text file of numbers in hexadecimal format into a set. One number per line. A # symbol can be used for one-line comments.
 	static std::unordered_set<std::uint32_t> parseHexFile(const std::filesystem::path&);
 	// Parses a text file of any line of text without surrounding whitespace into a set. Used to parse Trishape node names. A # symbol can be used for one-line comments.
 	static std::unordered_set<std::uint64_t> parseTriNameFile(const std::filesystem::path&);
+	// Computes a 64-bit FNV-1a hash of the given null-terminated string.
 	static std::uint64_t fnv_hash(const char* key);

Based on the previous review feedback.

package/Shaders/Lighting.hlsl (1)

1015-1019: Duplicate ultra-tree detection pattern — centralize.

This compound define guard repeats elsewhere. Consider a single helper macro/flag (e.g., IS_ULTRA_TREE) to avoid drift and ease future changes. Reference the similar condition around the snow occlusion block.

🧹 Nitpick comments (3)
package/Shaders/Lighting.hlsl (1)

2218-2236: Ultra-tree occlusion sampling: consider stricter types and casts.

Prefer uint2 for GetDimensions and explicit casts in UV math for DXC portability. Also consider hoisting the alpha-threshold (0.001) to a named const for reuse.

-    float rx;
-    float ry;
-    TexColorSampler.GetDimensions(rx, ry);
+    uint rx, ry;
+    TexColorSampler.GetDimensions(rx, ry);
@@
-        snowOcclusion = 1 - TexColorSampler.Sample(SampColorSampler, uv - float2(0, 2. / ry)).a;
+        snowOcclusion = 1.0 - TexColorSampler.Sample(SampColorSampler, uv - float2(0.0, 2.0 / float(ry))).a;
features/Snow Cover/Shaders/SnowCover/SnowCover.hlsli (2)

31-38: Height/environment multipliers: OK; consider naming/units clarity.

Works as written. Minor: consider renaming height_tresh -> height_thresh and documenting units/scales (mapZscale, BlendSmoothness).

Also applies to: 40-43


147-174: Non-PBR path OK; constants are magic — consider centralizing.

The 25*500 factor for shininess is opaque. Consider moving such scalars into SharedData::snowCoverSettings for easier tuning.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0efdc3a and 3385c20.

📒 Files selected for processing (4)
  • features/Snow Cover/Shaders/SnowCover/SnowCover.hlsli (1 hunks)
  • package/Shaders/Common/Color.hlsli (1 hunks)
  • package/Shaders/Lighting.hlsl (13 hunks)
  • src/Utils/FormIdParser.h (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{cpp,cxx,cc,c,h,hpp,hxx,hlsl,hlsli,fx,fxh,py}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Do not include TODO/FIXME placeholders; provide complete, working solutions

Files:

  • package/Shaders/Common/Color.hlsli
  • features/Snow Cover/Shaders/SnowCover/SnowCover.hlsli
  • package/Shaders/Lighting.hlsl
  • src/Utils/FormIdParser.h
features/*/Shaders/**/*.{hlsl,hlsli,fx,fxh}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

features/*/Shaders/**/*.{hlsl,hlsli,fx,fxh}: Place all feature shaders under features/YourFeature/Shaders/
Avoid GPU register/buffer conflicts in HLSL; verify register usage (e.g., with hlslkit buffer scanning)

Files:

  • features/Snow Cover/Shaders/SnowCover/SnowCover.hlsli
src/**/*.{cpp,cxx,cc,h,hpp,hxx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{cpp,cxx,cc,h,hpp,hxx}: Ensure SE/AE/VR runtime compatibility; use runtime detection patterns (e.g., REL::RelocateMember())
Include robust error handling and resource management with graceful degradation in the plugin code

Files:

  • src/Utils/FormIdParser.h
🧠 Learnings (5)
📓 Common learnings
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#0
File: :0-0
Timestamp: 2025-06-24T07:17:36.604Z
Learning: When reviewing PRs, always clarify the scope if there are multiple related features or dependencies. WeatherPicker was a separate PR that was already merged, while this PR focuses specifically on WetnessEffects climate preset system enhancements.
📚 Learning: 2025-08-03T18:37:19.690Z
Learnt from: jiayev
PR: doodlum/skyrim-community-shaders#0
File: :0-0
Timestamp: 2025-08-03T18:37:19.690Z
Learning: ISReflectionsRayTracing.hlsl and ISWorldMap.hlsl in the skyrim-community-shaders repository are image-space post-processing shaders that perform color sampling and blending operations that need proper linear color space handling for the linear lighting system. ISReflectionsRayTracing handles screen-space reflections and should use conditional Color::IrradianceToLinear/Gamma conversions similar to ISCompositeLensFlareVolumetricLighting.hlsl. ISWorldMap performs 7x7 color accumulation that should be done in linear space similar to the pattern used in ISSAOComposite.hlsl.

Applied to files:

  • features/Snow Cover/Shaders/SnowCover/SnowCover.hlsli
📚 Learning: 2025-08-05T17:40:44.828Z
Learnt from: ThePagi
PR: doodlum/skyrim-community-shaders#1369
File: package/Shaders/Lighting.hlsl:0-0
Timestamp: 2025-08-05T17:40:44.828Z
Learning: In the skyrim-community-shaders repository, ultra trees (object LOD trees) are detected using a compound shader define condition `defined(DO_ALPHA_TEST) && defined(LOD_BLENDING) && defined(RIM_LIGHTING) && defined(SOFT_LIGHTING)` because "they have no define" according to the comment. The `ExtraFlags::IsTree` flag is used for different tree handling (AO removal in skylighting) and may not apply to ultra trees specifically. Before replacing the compound condition with `IsTree`, verification is needed to ensure the flag covers ultra trees.

Applied to files:

  • package/Shaders/Lighting.hlsl
📚 Learning: 2025-06-08T11:25:14.536Z
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#577
File: src/Features/WetnessEffects.h:36-36
Timestamp: 2025-06-08T11:25:14.536Z
Learning: In the skyrim-community-shaders project, boolean flags in C++ structs that interface with HLSL shaders use `uint` type instead of `bool` for compatibility reasons. This ensures consistent 4-byte size, proper 16-byte alignment in constant buffers, and cross-platform compatibility when passing data between C++ and HLSL shaders.

Applied to files:

  • package/Shaders/Lighting.hlsl
📚 Learning: 2025-06-08T11:25:14.536Z
Learnt from: alandtse
PR: doodlum/skyrim-community-shaders#577
File: src/Features/WetnessEffects.h:36-36
Timestamp: 2025-06-08T11:25:14.536Z
Learning: In the skyrim-community-shaders project, boolean flags in C++ structs that interface with HLSL shaders use `uint` type instead of `bool` for compatibility reasons. This ensures consistent size, alignment, and cross-platform compatibility when passing data to shader constant buffers.

Applied to files:

  • package/Shaders/Lighting.hlsl
🧬 Code graph analysis (1)
src/Utils/FormIdParser.h (1)
src/Utils/FormIdParser.cpp (4)
  • parseHexFile (16-51)
  • parseHexFile (16-16)
  • parseTriNameFile (53-77)
  • parseTriNameFile (53-53)
🪛 Clang (14.0.6)
src/Utils/FormIdParser.h

[error] 3-3: 'string' file not found

(clang-diagnostic-error)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Validate shader compilation (VR, .github/configs/shader-validation-vr.yaml)
  • GitHub Check: Validate shader compilation (Flatrim, .github/configs/shader-validation.yaml)
  • GitHub Check: Build plugin and addons
🔇 Additional comments (9)
package/Shaders/Common/Color.hlsli (1)

68-76: HSV utilities look correct; good addition.

Formulas match established patterns; guards avoid div-by-zero when V=0. No issues spotted.

Also applies to: 77-81, 82-103

package/Shaders/Lighting.hlsl (3)

30-38: Snow Cover gating is sensible.

Undefining SNOW_COVER for SKINNED/SKIN/EYE/HAIR or when EXTENDED_MATERIALS is off prevents accidental enablement on unsupported paths.


2271-2281: Glossiness scalar usage fixed — good.

Passing glossiness as a float and removing swizzles resolves the earlier compile-time/type issue.


3045-3047: Vertex color snow tint blend is fine.

Simple, branch-free blend; matches feature intent.

features/Snow Cover/Shaders/SnowCover/SnowCover.hlsli (5)

19-25: Normal reorientation implementation looks correct.

Matches reoriented normal mapping for s=(0,0,1). No issues.


45-55: Foliage HSV tinting: consistent with new Color utilities.

Logic reads clean; no correctness concerns.


79-108: ApplySnowBase math looks sound after clamp fix.

The corrected clamp argument order prevents underflow/overflow in weatherMult. Early-out threshold is appropriate.


110-144: PBR path integration is coherent; glint params blended correctly.

F0/roughness/metallic/AO and glint fields are lerped by mult; good separation of main vs alt sets.


9-16: Texture register assignments verified as collision-free.

Verification confirms that t38–t44 registers are used exclusively by SnowCover and do not collide with any other features or Common modules. The assignments are safe.

Comment on lines 1409 to 1411
{
landRMAOS1 = input.LandBlendWeights1.x * float4(1 - glossiness.x, 0, 1, 0);
landRMAOS1 = input.LandBlendWeights1.x * float4(1 - glossiness, 0, 1, 0);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix double application of layer weights in PBR terrain RMAOS fallback.

In the non-PBR-tile fallback branches you multiply by the layer weight inside landRMAOSN and again when accumulating, effectively squaring weights. Drop the inner factor.

Apply this diff:

-            landRMAOS1 = input.LandBlendWeights1.x * float4(1 - glossiness, 0, 1, 0);
+            landRMAOS1 = float4(1 - glossiness, 0, 1, 0);
@@
-            landRMAOS2 = input.LandBlendWeights1.y * float4(1 - glossiness, 0, 1, 0);
+            landRMAOS2 = float4(1 - glossiness, 0, 1, 0);
@@
-            landRMAOS3 = input.LandBlendWeights1.z * float4(1 - glossiness, 0, 1, 0);
+            landRMAOS3 = float4(1 - glossiness, 0, 1, 0);
@@
-            landRMAOS4 = input.LandBlendWeights1.w * float4(1 - glossiness, 0, 1, 0);
+            landRMAOS4 = float4(1 - glossiness, 0, 1, 0);
@@
-            landRMAOS5 = input.LandBlendWeights2.x * float4(1 - glossiness, 0, 1, 0);
+            landRMAOS5 = float4(1 - glossiness, 0, 1, 0);
@@
-            landRMAOS6 = input.LandBlendWeights2.y * float4(1 - glossiness, 0, 1, 0);
+            landRMAOS6 = float4(1 - glossiness, 0, 1, 0);

Also applies to: 1491-1492, 1571-1572, 1651-1652, 1732-1733, 1812-1813

🤖 Prompt for AI Agents
In package/Shaders/Lighting.hlsl around lines 1409-1411 (and similarly at
1491-1492, 1571-1572, 1651-1652, 1732-1733, 1812-1813), the non-PBR-tile
fallback branches multiply layer weights twice by applying the layer weight
inside the landRMAOSN assignment and again during accumulation; remove the inner
multiplication so landRMAOSN is assigned without the layer weight (leave the
accumulation step to apply the weight once) for each of these occurrences.

Comment on lines +3 to +4
#include <string>
#include <unordered_set>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Missing required header: <filesystem>.

The methods parseHexFile and parseTriNameFile on lines 10 and 12 use std::filesystem::path, but <filesystem> is not included. This will cause compilation failure.

Apply this diff to add the missing include:

 #include <string>
 #include <unordered_set>
+#include <filesystem>

Note: The static analysis error about the missing 'string' file is a false positive from the analysis environment.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#include <string>
#include <unordered_set>
#include <string>
#include <unordered_set>
#include <filesystem>
🧰 Tools
🪛 Clang (14.0.6)

[error] 3-3: 'string' file not found

(clang-diagnostic-error)

🤖 Prompt for AI Agents
In src/Utils/FormIdParser.h around lines 3 to 4, the header is missing the
required <filesystem> include used by parseHexFile and parseTriNameFile which
reference std::filesystem::path; add #include <filesystem> alongside the
existing includes (e.g., after <string>) so the file compiles successfully with
std::filesystem types available.

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.

4 participants