diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 468a65847..a43f38e9c 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -10,7 +10,7 @@ permissions: contents: write env: - VCPKG_COMMIT_ID: d99b6930b920d85dd4e1edbac37ecb3f354185c0 + VCPKG_COMMIT_ID: 417119555f155f6044dec7a379cd25466e339873 jobs: compile: diff --git a/.github/workflows/lintpr.yaml b/.github/workflows/lintpr.yaml new file mode 100644 index 000000000..d54e17496 --- /dev/null +++ b/.github/workflows/lintpr.yaml @@ -0,0 +1,20 @@ +name: "Lint PR" + +on: + pull_request_target: + types: + - opened + - edited + - synchronize + +permissions: + pull-requests: read + +jobs: + main: + name: Validate PR title + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/CMakeLists.txt b/CMakeLists.txt index dd680a147..d87b923fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.21) project( CommunityShaders - VERSION 0.7.0 + VERSION 0.7.4 LANGUAGES CXX ) @@ -34,6 +34,7 @@ find_package(EASTL CONFIG REQUIRED) find_package(directxtk CONFIG REQUIRED) find_path(CLIB_UTIL_INCLUDE_DIRS "ClibUtil/utils.hpp") find_package(pystring CONFIG REQUIRED) +find_package(cppwinrt CONFIG REQUIRED) target_include_directories( ${PROJECT_NAME} @@ -47,6 +48,7 @@ target_link_libraries( PRIVATE debug ${CMAKE_CURRENT_SOURCE_DIR}/include/detours/Debug/detours.lib optimized ${CMAKE_CURRENT_SOURCE_DIR}/include/detours/Release/detours.lib + Microsoft::CppWinRT magic_enum::magic_enum xbyak::xbyak nlohmann_json::nlohmann_json @@ -79,11 +81,10 @@ endif() # ####################################################################################################################### # # Automatic deployment # ####################################################################################################################### - file(GLOB FEATURE_PATHS LIST_DIRECTORIES true ${CMAKE_SOURCE_DIR}/features/*) # Automatic deployment to CommunityShaders output directory. -if (AUTO_PLUGIN_DEPLOYMENT) +if(AUTO_PLUGIN_DEPLOYMENT) foreach(DEPLOY_TARGET $ENV{CommunityShadersOutputDir}) message("Copying package folder with dll/pdb with all features to ${DEPLOY_TARGET}") add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD @@ -91,13 +92,15 @@ if (AUTO_PLUGIN_DEPLOYMENT) COMMAND ${CMAKE_COMMAND} -E copy $ "${DEPLOY_TARGET}/SKSE/Plugins/" COMMAND ${CMAKE_COMMAND} -E copy $ "${DEPLOY_TARGET}/SKSE/Plugins/" ) + foreach(FEATURE_PATH ${FEATURE_PATHS}) add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${FEATURE_PATH} "${DEPLOY_TARGET}" ) endforeach() endforeach() - if (NOT DEFINED ENV{CommunityShadersOutputDir}) + + if(NOT DEFINED ENV{CommunityShadersOutputDir}) message("When using AUTO_PLUGIN_DEPLOYMENT option, you need to set environment variable 'CommunityShadersOutputDir'") endif() endif() diff --git a/cmake/Version.rc.in b/cmake/Version.rc.in index efbb7561a..70f09b354 100644 --- a/cmake/Version.rc.in +++ b/cmake/Version.rc.in @@ -20,7 +20,7 @@ BEGIN VALUE "FileDescription", "@PROJECT_NAME@" VALUE "FileVersion", "@PROJECT_VERSION@.0" VALUE "InternalName", "@PROJECT_NAME@" - VALUE "LegalCopyright", "MIT License" + VALUE "LegalCopyright", "GPL-3.0 License" VALUE "ProductName", "@PROJECT_NAME@" VALUE "ProductVersion", "@PROJECT_VERSION@.0" END diff --git a/cmake/XSEPlugin.cmake b/cmake/XSEPlugin.cmake index 9f3d7ecd6..8a8c1fb7b 100644 --- a/cmake/XSEPlugin.cmake +++ b/cmake/XSEPlugin.cmake @@ -13,7 +13,7 @@ elseif(BUILD_FALLOUT4) set(GameVersion "Fallout 4") else() message( - FATAL_ERROR + FATAL_ERROR "A game must be selected." ) endif() @@ -23,7 +23,7 @@ add_library("${PROJECT_NAME}" SHARED) target_compile_features( "${PROJECT_NAME}" PRIVATE - cxx_std_23 + cxx_std_23 ) set_property(GLOBAL PROPERTY USE_FOLDERS ON) @@ -46,14 +46,14 @@ configure_file( target_sources( "${PROJECT_NAME}" PRIVATE - ${CMAKE_CURRENT_BINARY_DIR}/cmake/Plugin.h - ${CMAKE_CURRENT_BINARY_DIR}/cmake/version.rc + ${CMAKE_CURRENT_BINARY_DIR}/cmake/Plugin.h + ${CMAKE_CURRENT_BINARY_DIR}/cmake/version.rc ) target_precompile_headers( "${PROJECT_NAME}" PRIVATE - include/PCH.h + include/PCH.h ) set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) @@ -62,42 +62,41 @@ set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_DEBUG OFF) set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_RUNTIME ON) -if (CMAKE_GENERATOR MATCHES "Visual Studio") +if(CMAKE_GENERATOR MATCHES "Visual Studio") add_compile_definitions(_UNICODE) target_compile_definitions(${PROJECT_NAME} PRIVATE "$<$:DEBUG>") - set(SC_RELEASE_OPTS "/Zi;/fp:fast;/GL;/Gy-;/Gm-;/Gw;/sdl-;/GS-;/guard:cf-;/O2;/Ob2;/Oi;/Ot;/Oy;/fp:except-") - + set(SC_RELEASE_OPTS "/Zi;/fp:fast;/GL;/Gy-;/Gm-;/Gw;/sdl-;/GS-;/guard:cf-;/O2;/Ob2;/Oi;/Ot;/Oy;/fp:except-") + target_compile_options( "${PROJECT_NAME}" PRIVATE - /MP - /await - /W4 - /WX - /permissive- - /Zc:alignedNew - /Zc:auto - /Zc:__cplusplus - /Zc:externC - /Zc:externConstexpr - /Zc:forScope - /Zc:hiddenFriend - /Zc:implicitNoexcept - /Zc:lambda - /Zc:noexceptTypes - /Zc:preprocessor - /Zc:referenceBinding - /Zc:rvalueCast - /Zc:sizedDealloc - /Zc:strictStrings - /Zc:ternary - /Zc:threadSafeInit - /Zc:trigraphs - /Zc:wchar_t - /wd4200 # nonstandard extension used : zero-sized array in struct/union - /arch:AVX2 + /MP + /W4 + /WX + /permissive- + /Zc:alignedNew + /Zc:auto + /Zc:__cplusplus + /Zc:externC + /Zc:externConstexpr + /Zc:forScope + /Zc:hiddenFriend + /Zc:implicitNoexcept + /Zc:lambda + /Zc:noexceptTypes + /Zc:preprocessor + /Zc:referenceBinding + /Zc:rvalueCast + /Zc:sizedDealloc + /Zc:strictStrings + /Zc:ternary + /Zc:threadSafeInit + /Zc:trigraphs + /Zc:wchar_t + /wd4200 # nonstandard extension used : zero-sized array in struct/union + /arch:AVX ) target_compile_options(${PROJECT_NAME} PUBLIC "$<$:/fp:strict>") @@ -109,9 +108,9 @@ if (CMAKE_GENERATOR MATCHES "Visual Studio") target_link_options( ${PROJECT_NAME} PRIVATE - /WX - "$<$:/INCREMENTAL;/OPT:NOREF;/OPT:NOICF>" - "$<$:/LTCG;/INCREMENTAL:NO;/OPT:REF;/OPT:ICF;/DEBUG:FULL>" + /WX + "$<$:/INCREMENTAL;/OPT:NOREF;/OPT:NOICF>" + "$<$:/LTCG;/INCREMENTAL:NO;/OPT:REF;/OPT:ICF;/DEBUG:FULL>" ) endif() @@ -122,14 +121,14 @@ find_package(spdlog CONFIG REQUIRED) target_include_directories( ${PROJECT_NAME} PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/include PRIVATE - ${CMAKE_CURRENT_BINARY_DIR}/cmake - ${CMAKE_CURRENT_SOURCE_DIR}/src + ${CMAKE_CURRENT_BINARY_DIR}/cmake + ${CMAKE_CURRENT_SOURCE_DIR}/src ) target_link_libraries( - ${PROJECT_NAME} - PUBLIC - CommonLibSSE::CommonLibSSE + ${PROJECT_NAME} + PUBLIC + CommonLibSSE::CommonLibSSE ) \ No newline at end of file diff --git a/extern/CommonLibSSE-NG b/extern/CommonLibSSE-NG index 6ccb57a73..d970ed21e 160000 --- a/extern/CommonLibSSE-NG +++ b/extern/CommonLibSSE-NG @@ -1 +1 @@ -Subproject commit 6ccb57a73fe025d441b1ed3c382710dd1fca2f4e +Subproject commit d970ed21ea09ce80e34103fab0683457ef3ecdf6 diff --git a/features/Grass Lighting/Shaders/Features/GrassLighting.ini b/features/Grass Lighting/Shaders/Features/GrassLighting.ini index 128a42497..a586c7975 100644 --- a/features/Grass Lighting/Shaders/Features/GrassLighting.ini +++ b/features/Grass Lighting/Shaders/Features/GrassLighting.ini @@ -1,2 +1,2 @@ [Info] -Version = 1-3-3 \ No newline at end of file +Version = 1-4-0 \ No newline at end of file diff --git a/features/Grass Lighting/Shaders/RunGrass.hlsl b/features/Grass Lighting/Shaders/RunGrass.hlsl index 3c2d3db95..73ed613b6 100644 --- a/features/Grass Lighting/Shaders/RunGrass.hlsl +++ b/features/Grass Lighting/Shaders/RunGrass.hlsl @@ -106,8 +106,9 @@ cbuffer PerFrame : register( float SpecularStrength; float SubsurfaceScatteringAmount; bool EnableDirLightFix; + bool OverrideComplexGrassSettings; float BasicGrassBrightness; - float pad[2]; + float pad[1]; } #ifdef VSHADER @@ -430,7 +431,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace worldNormal = normalize(mul(normalColor, CalculateTBN(worldNormal, -input.WorldPosition, input.TexCoord.xy))); } - if (!complex) + if (!complex || OverrideComplexGrassSettings) baseColor.xyz *= BasicGrassBrightness; float3 dirLightColor = DirLightColor.xyz; diff --git a/include/PCH.h b/include/PCH.h index 00e7d5cea..39f1e746a 100644 --- a/include/PCH.h +++ b/include/PCH.h @@ -119,10 +119,10 @@ namespace DX } #include +#include #include #include #include -#include #include "imgui.h" @@ -139,6 +139,7 @@ using json = nlohmann::json; #include #include #include +#include #include #include #include @@ -148,7 +149,6 @@ using json = nlohmann::json; #include #include #include -#include #include "SimpleMath.h" diff --git a/package/SKSE/Plugins/CommunityShaders.json b/package/SKSE/Plugins/CommunityShaders.json index da6ea52a0..bc23c2bc3 100644 --- a/package/SKSE/Plugins/CommunityShaders.json +++ b/package/SKSE/Plugins/CommunityShaders.json @@ -1,12 +1,12 @@ { "Complex Parallax Materials": { - "BlendRange": 0.1679999977350235, - "CRPMRange": 1.0, + "BlendRange": 0.25, + "CRPMRange": 0.5, "EnableComplexMaterial": 1, "EnableHighQuality": 0, "EnableParallax": 1, "EnableShadows": 1, - "EnableTerrain": 1, + "EnableTerrain": 0, "Height": 0.10000000149011612, "MaxDistance": 4096, "ShadowsEndFade": 1024, @@ -25,20 +25,20 @@ "Grass Lighting": { "BasicGrassBrightness": 0.6660000085830688, "EnableDirLightFix": 1, - "Glossiness": 8.524999618530273, - "SpecularStrength": 0.1899999976158142, - "SubsurfaceScatteringAmount": 2.0 + "Glossiness": 20.0, + "SpecularStrength": 0.5, + "SubsurfaceScatteringAmount": 1.0 }, "Light Limit Fix": { - "EnableContactShadows": true, - "EnableFirstPersonShadows": true, + "EnableContactShadows": false, + "EnableFirstPersonShadows": false, "EnableParticleLights": true, "EnableParticleLightsCulling": true, "EnableParticleLightsDetection": true, "EnableParticleLightsOptimization": true, "ParticleLightsBrightness": 1.0, "ParticleLightsOptimisationClusterRadius": 32, - "ParticleLightsSaturation": 2.0 + "ParticleLightsSaturation": 1.0 }, "Menu": { "Font Scale": 0.0, @@ -54,7 +54,7 @@ "ImageSpace": false, "Lighting": true, "Particle": false, - "Sky": true, + "Sky": false, "Utility": false, "Water": true }, @@ -73,7 +73,7 @@ "Tree LOD Lighting": { "EnableComplexTreeLOD": 1, "EnableDirLightFix": 1, - "SubsurfaceScatteringAmount": 0.5009999871253967 + "SubsurfaceScatteringAmount": 0.5 }, "Version": "0-7-0-0", "Water Blending": { @@ -85,14 +85,14 @@ "Wetness Effects": { "EnableWetnessEffects": 1, "MaxDarkness": 1.0, - "MaxOcclusion": 0.0, + "MaxOcclusion": 0.15000000596046448, "MaxRainWetness": 1.0, - "MaxShoreWetness": 0.5379999876022339, - "MinRoughness": 0.0, - "PuddleFlatness": 1.0, - "PuddleMaxAngle": 0.9900000095367432, - "PuddleMinWetness": 0.7009999752044678, - "PuddleRadius": 1.0049999952316284, + "MaxShoreWetness": 0.5, + "MinRoughness": 0.10000000149011612, + "PuddleFlatness": 0.949999988079071, + "PuddleMaxAngle": 0.8999999761581421, + "PuddleMinWetness": 0.699999988079071, + "PuddleRadius": 1.0, "ShoreRange": 32 } } \ No newline at end of file diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 70eb94e18..6dc14c856 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -459,7 +459,7 @@ VS_OUTPUT main(VS_INPUT input) # ifdef VR float4 r0; - float4 projSpacePosition = viewPos; + float4 projSpacePosition = vsout.Position; r0.xyzw = 0; if (0 < cb13) { r0.yz = dot(projSpacePosition, EyeClipEdge[eyeIndex]); // projSpacePosition is clipPos @@ -1058,7 +1058,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(PARALLAX) if (perPassParallax[0].EnableParallax) { mipLevel = GetMipLevel(uv, TexParallaxSampler); - uv = GetParallaxCoords(viewPosition.z, uv, mipLevel, worldSpaceViewDirection, tbnWS, TexParallaxSampler, SampParallaxSampler, 0); + uv = GetParallaxCoords(viewPosition.z, uv, mipLevel, viewDirection, tbnTr, TexParallaxSampler, SampParallaxSampler, 0); if (perPassParallax[0].EnableShadows && parallaxShadowQuality > 0.0f) sh0 = TexParallaxSampler.SampleLevel(SampParallaxSampler, uv, mipLevel).x; } @@ -1077,7 +1077,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace if (envMaskTest > (4.0f / 255.0f)) { complexMaterialParallax = true; mipLevel = GetMipLevel(uv, TexEnvMaskSampler); - uv = GetParallaxCoords(viewPosition.z, uv, mipLevel, worldSpaceViewDirection, tbnWS, TexEnvMaskSampler, SampTerrainParallaxSampler, 3); + uv = GetParallaxCoords(viewPosition.z, uv, mipLevel, viewDirection, tbnTr, TexEnvMaskSampler, SampTerrainParallaxSampler, 3); if (perPassParallax[0].EnableShadows && parallaxShadowQuality > 0.0f) sh0 = TexEnvMaskSampler.SampleLevel(SampEnvMaskSampler, uv, mipLevel).w; } @@ -1115,7 +1115,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float2 terrainUVs[6]; if (perPassParallax[0].EnableTerrainParallax && input.LandBlendWeights1.x > 0.0) { mipLevel[0] = GetMipLevel(uv, TexColorSampler); - uv = GetParallaxCoords(viewPosition.z, uv, mipLevel[0], worldSpaceViewDirection, tbnWS, TexColorSampler, SampTerrainParallaxSampler, 3, input.LandBlendWeights1.x); + uv = GetParallaxCoords(viewPosition.z, uv, mipLevel[0], viewDirection, tbnTr, TexColorSampler, SampTerrainParallaxSampler, 3, input.LandBlendWeights1.x); terrainUVs[0] = uv; if (perPassParallax[0].EnableShadows && parallaxShadowQuality > 0.0f) sh0[0] = TexColorSampler.SampleLevel(SampTerrainParallaxSampler, uv, mipLevel[0]).w; @@ -1217,7 +1217,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(CPM_AVAILABLE) if (perPassParallax[0].EnableTerrainParallax) { mipLevel[1] = GetMipLevel(uvOriginal, TexLandColor2Sampler); - uv = GetParallaxCoords(viewPosition.z, uvOriginal, mipLevel[1], worldSpaceViewDirection, tbnWS, TexLandColor2Sampler, SampTerrainParallaxSampler, 3, input.LandBlendWeights1.y); + uv = GetParallaxCoords(viewPosition.z, uvOriginal, mipLevel[1], viewDirection, tbnTr, TexLandColor2Sampler, SampTerrainParallaxSampler, 3, input.LandBlendWeights1.y); terrainUVs[1] = uv; if (perPassParallax[0].EnableShadows && parallaxShadowQuality > 0.0f) sh0[1] = TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, uv, mipLevel[1]).w; @@ -1239,7 +1239,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(CPM_AVAILABLE) if (perPassParallax[0].EnableTerrainParallax) { mipLevel[2] = GetMipLevel(uvOriginal, TexLandColor3Sampler); - uv = GetParallaxCoords(viewPosition.z, uvOriginal, mipLevel[2], worldSpaceViewDirection, tbnWS, TexLandColor3Sampler, SampTerrainParallaxSampler, 3, input.LandBlendWeights1.z); + uv = GetParallaxCoords(viewPosition.z, uvOriginal, mipLevel[2], viewDirection, tbnTr, TexLandColor3Sampler, SampTerrainParallaxSampler, 3, input.LandBlendWeights1.z); terrainUVs[2] = uv; if (perPassParallax[0].EnableShadows && parallaxShadowQuality > 0.0f) sh0[2] = TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, uv, mipLevel[2]).w; @@ -1261,7 +1261,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(CPM_AVAILABLE) if (perPassParallax[0].EnableTerrainParallax) { mipLevel[3] = GetMipLevel(uvOriginal, TexLandColor4Sampler); - uv = GetParallaxCoords(viewPosition.z, uvOriginal, mipLevel[3], worldSpaceViewDirection, tbnWS, TexLandColor4Sampler, SampTerrainParallaxSampler, 3, input.LandBlendWeights1.w); + uv = GetParallaxCoords(viewPosition.z, uvOriginal, mipLevel[3], viewDirection, tbnTr, TexLandColor4Sampler, SampTerrainParallaxSampler, 3, input.LandBlendWeights1.w); terrainUVs[3] = uv; if (perPassParallax[0].EnableShadows && parallaxShadowQuality > 0.0f) sh0[3] = TexLandColor4Sampler.SampleLevel(SampTerrainParallaxSampler, uv, mipLevel[3]).w; @@ -1283,7 +1283,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(CPM_AVAILABLE) if (perPassParallax[0].EnableTerrainParallax) { mipLevel[4] = GetMipLevel(uvOriginal, TexLandColor5Sampler); - uv = GetParallaxCoords(viewPosition.z, uvOriginal, mipLevel[4], worldSpaceViewDirection, tbnWS, TexLandColor5Sampler, SampTerrainParallaxSampler, 3, input.LandBlendWeights2.x); + uv = GetParallaxCoords(viewPosition.z, uvOriginal, mipLevel[4], viewDirection, tbnTr, TexLandColor5Sampler, SampTerrainParallaxSampler, 3, input.LandBlendWeights2.x); terrainUVs[4] = uv; if (perPassParallax[0].EnableShadows && parallaxShadowQuality > 0.0f) sh0[4] = TexLandColor5Sampler.SampleLevel(SampTerrainParallaxSampler, uv, mipLevel[4]).w; @@ -1305,7 +1305,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(CPM_AVAILABLE) if (perPassParallax[0].EnableTerrainParallax) { mipLevel[5] = GetMipLevel(uvOriginal, TexLandColor6Sampler); - uv = GetParallaxCoords(viewPosition.z, uvOriginal, mipLevel[5], worldSpaceViewDirection, tbnWS, TexLandColor6Sampler, SampTerrainParallaxSampler, 3, input.LandBlendWeights2.y); + uv = GetParallaxCoords(viewPosition.z, uvOriginal, mipLevel[5], viewDirection, tbnTr, TexLandColor6Sampler, SampTerrainParallaxSampler, 3, input.LandBlendWeights2.y); terrainUVs[5] = uv; if (perPassParallax[0].EnableShadows && parallaxShadowQuality > 0.0f) sh0[5] = TexLandColor6Sampler.SampleLevel(SampTerrainParallaxSampler, uv, mipLevel[5]).w; @@ -1995,7 +1995,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace color.xyz = vertexColor.xyz - color.xyz * FogColor.w; float3 tmpColor = color.xyz * FrameParams.yyy; - color.xyz = tmpColor.xyz + 10000; + color.xyz = tmpColor.xyz + ColourOutputClamp.xxx; color.xyz = min(vertexColor.xyz, color.xyz); # if defined(CPM_AVAILABLE) && defined(ENVMAP) @@ -2009,7 +2009,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace specularTmp = color.xyz - specularTmp.xyz * FogColor.w; tmpColor = specularTmp.xyz * FrameParams.yyy; - specularTmp.xyz = tmpColor.xyz + 10000; + specularTmp.xyz = tmpColor.xyz + ColourOutputClamp.zzz; color.xyz = min(specularTmp.xyz, color.xyz); # endif // defined (SPECULAR) || defined(SPARKLE) diff --git a/src/Features/DistantTreeLighting.cpp b/src/Features/DistantTreeLighting.cpp index 02e8aa57c..71fe593f6 100644 --- a/src/Features/DistantTreeLighting.cpp +++ b/src/Features/DistantTreeLighting.cpp @@ -16,9 +16,10 @@ void DistantTreeLighting::DrawSettings() if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::Text("Enables advanced lighting simulation on tree LOD.\n"); - ImGui::Text("Requires DynDOLOD.\n"); - ImGui::Text("See https://dyndolod.info/ for more information."); + ImGui::Text( + "Enables advanced lighting simulation on tree LOD. " + "Requires DynDOLOD. " + "See https://dyndolod.info/ for more information. "); ImGui::PopTextWrapPos(); ImGui::EndTooltip(); } @@ -48,10 +49,11 @@ void DistantTreeLighting::DrawSettings() if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::Text("Subsurface Scattering (SSS) amount\n"); - ImGui::Text("Soft lighting controls how evenly lit an object is.\n"); - ImGui::Text("Back lighting illuminates the back face of an object.\n"); - ImGui::Text("Combined to model the transport of light through the surface."); + ImGui::Text( + "Subsurface Scattering (SSS) amount. " + "Soft lighting controls how evenly lit an object is. " + "Back lighting illuminates the back face of an object. " + "Combined to model the transport of light through the surface. "); ImGui::PopTextWrapPos(); ImGui::EndTooltip(); } diff --git a/src/Features/ExtendedMaterials.cpp b/src/Features/ExtendedMaterials.cpp index 642b5a20a..cd5d73458 100644 --- a/src/Features/ExtendedMaterials.cpp +++ b/src/Features/ExtendedMaterials.cpp @@ -33,9 +33,10 @@ void ExtendedMaterials::DrawSettings() if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::Text("Enables support for the Complex Material specification which makes use of the environment mask.\n"); - ImGui::Text("This includes parallax, as well as more realistic metals and specular reflections.\n"); - ImGui::Text("May lead to some warped textures on modded content which have an invalid alpha channel in their environment mask."); + ImGui::Text( + "Enables support for the Complex Material specification which makes use of the environment mask. " + "This includes parallax, as well as more realistic metals and specular reflections. " + "May lead to some warped textures on modded content which have an invalid alpha channel in their environment mask. "); ImGui::PopTextWrapPos(); ImGui::EndTooltip(); } @@ -63,8 +64,9 @@ void ExtendedMaterials::DrawSettings() if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::Text("Enables terrain parallax using the alpha channel of each landscape texture.\n"); - ImGui::Text("Therefore, all landscape textures must support parallax for this effect to work properly."); + ImGui::Text( + "Enables terrain parallax using the alpha channel of each landscape texture. " + "Therefore, all landscape textures must support parallax for this effect to work properly. "); ImGui::PopTextWrapPos(); ImGui::EndTooltip(); } @@ -73,9 +75,10 @@ void ExtendedMaterials::DrawSettings() if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::Text("Doubles the sample count and approximates the intersection point using Parallax Occlusion Mapping.\n"); - ImGui::Text("Significantly improves the quality and removes aliasing.\n"); - ImGui::Text("TAA or the Skyrim Upscaler is recommended when using this option due to CRPM artifacts."); + ImGui::Text( + "Doubles the sample count and approximates the intersection point using Parallax Occlusion Mapping. " + "Significantly improves the quality and removes aliasing. " + "TAA or the Skyrim Upscaler is recommended when using this option due to CRPM artifacts. "); ImGui::PopTextWrapPos(); ImGui::EndTooltip(); } @@ -104,8 +107,9 @@ void ExtendedMaterials::DrawSettings() if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::Text("The range that parallax blends from Parallax Occlusion Mapping (POM) to bump mapping, and bump mapping to nothing.\n"); - ImGui::Text("This value should be set as low as possible due to the performance impact of blending POM and relief mapping."); + ImGui::Text( + "The range that parallax blends from Parallax Occlusion Mapping (POM) to bump mapping, and bump mapping to nothing. " + "This value should be set as low as possible due to the performance impact of blending POM and relief mapping. "); ImGui::PopTextWrapPos(); ImGui::EndTooltip(); } @@ -129,8 +133,9 @@ void ExtendedMaterials::DrawSettings() if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::Text("Enables cheap soft shadows when using parallax.\n"); - ImGui::Text("This applies to all directional and point lights."); + ImGui::Text( + "Enables cheap soft shadows when using parallax. " + "This applies to all directional and point lights. "); ImGui::PopTextWrapPos(); ImGui::EndTooltip(); } diff --git a/src/Features/GrassLighting.cpp b/src/Features/GrassLighting.cpp index 3cb67c95a..3bc18273d 100644 --- a/src/Features/GrassLighting.cpp +++ b/src/Features/GrassLighting.cpp @@ -9,6 +9,7 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT( SpecularStrength, SubsurfaceScatteringAmount, EnableDirLightFix, + OverrideComplexGrassSettings, BasicGrassBrightness) enum class GrassShaderTechniques @@ -48,10 +49,11 @@ void GrassLighting::DrawSettings() if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::Text("Subsurface Scattering (SSS) amount\n"); - ImGui::Text("Soft lighting controls how evenly lit an object is.\n"); - ImGui::Text("Back lighting illuminates the back face of an object.\n"); - ImGui::Text("Combined to model the transport of light through the surface."); + ImGui::Text( + "Subsurface Scattering (SSS) amount. " + "Soft lighting controls how evenly lit an object is. " + "Back lighting illuminates the back face of an object. " + "Combined to model the transport of light through the surface. "); ImGui::PopTextWrapPos(); ImGui::EndTooltip(); } @@ -71,6 +73,19 @@ void GrassLighting::DrawSettings() ImGui::EndTooltip(); } + ImGui::Checkbox("Override Complex Grass Lighting Settings", (bool*)&settings.OverrideComplexGrassSettings); + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::Text( + "Override the settings set by the grass mesh author. " + "Complex grass authors can define the brightness for their grass meshes. " + "However, some authors may not account for the extra lights available from Community Shaders. " + "This option will treat their grass settings like non-complex grass. " + "This was the default in Community Shaders < 0.7.0"); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } ImGui::Spacing(); ImGui::Spacing(); ImGui::TextWrapped("Basic Grass"); diff --git a/src/Features/GrassLighting.h b/src/Features/GrassLighting.h index f5f198aca..848e83d84 100644 --- a/src/Features/GrassLighting.h +++ b/src/Features/GrassLighting.h @@ -20,6 +20,7 @@ struct GrassLighting : Feature float SpecularStrength = 0.5f; float SubsurfaceScatteringAmount = 1.0f; uint EnableDirLightFix = true; + uint OverrideComplexGrassSettings = false; float BasicGrassBrightness = 0.666f; }; @@ -28,7 +29,7 @@ struct GrassLighting : Feature DirectX::XMFLOAT3X4 DirectionalAmbient; float SunlightScale; Settings Settings; - float pad[2]; + float pad[1]; }; Settings settings; diff --git a/src/Features/LightLimitFix.cpp b/src/Features/LightLimitFix.cpp index bcf36c3bf..fb834f001 100644 --- a/src/Features/LightLimitFix.cpp +++ b/src/Features/LightLimitFix.cpp @@ -137,9 +137,10 @@ void LightLimitFix::DrawSettings() if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::Text(" - Visualise the light limit. Red when the \"strict\" light limit is reached (portal-strict lights).\n"); - ImGui::Text(" - Visualise the number of strict lights. \n"); - ImGui::Text(" - Visualise the number of clustered lights."); + ImGui::Text( + " - Visualise the light limit. Red when the \"strict\" light limit is reached (portal-strict lights). " + " - Visualise the number of strict lights. " + " - Visualise the number of clustered lights. "); ImGui::PopTextWrapPos(); ImGui::EndTooltip(); } @@ -306,7 +307,7 @@ void LightLimitFix::BSLightingShader_SetupGeometry_GeometrySetupConstantPointLig strictLightDataTemp.PointLightPosition[i] = DirectX::SimpleMath::Vector3::Transform(worldPos, Transform); strictLightDataTemp.PointLightRadius[i] = runtimeData.radius.x / WorldScale; } else { - auto posAdjust = RE::BSGraphics::RendererShadowState::GetSingleton()->GetRuntimeData().posAdjust.getEye(); + auto posAdjust = (!REL::Module::IsVR()) ? RE::BSGraphics::RendererShadowState::GetSingleton()->GetRuntimeData().posAdjust.getEye() : RE::BSGraphics::RendererShadowState::GetSingleton()->GetVRRuntimeData().posAdjust.getEye(); strictLightDataTemp.PointLightPosition[i] = worldPos - float3(posAdjust.x, posAdjust.y, posAdjust.z); strictLightDataTemp.PointLightRadius[i] = runtimeData.radius.x; } diff --git a/src/Hooks.cpp b/src/Hooks.cpp index f67169083..41029096e 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -217,6 +217,25 @@ void hk_BSShaderRenderTargets_Create() State::GetSingleton()->Setup(); } +static void hk_PollInputDevices(RE::BSTEventSource* a_dispatcher, RE::InputEvent* const* a_events); +static inline REL::Relocation _InputFunc; + +void hk_PollInputDevices(RE::BSTEventSource* a_dispatcher, RE::InputEvent* const* a_events) +{ + auto menu = Menu::GetSingleton(); + + if (a_events) + menu->ProcessInputEvents(a_events); + + if (menu->ShouldSwallowInput()) { //the menu is open, eat all keypresses + constexpr RE::InputEvent* const dummy[] = { nullptr }; + _InputFunc(a_dispatcher, dummy); + return; + } + + _InputFunc(a_dispatcher, a_events); +} + namespace Hooks { struct BSGraphics_Renderer_Init_InitD3D @@ -281,6 +300,11 @@ namespace Hooks void Install() { + SKSE::AllocTrampoline(14); + auto& trampoline = SKSE::GetTrampoline(); + logger::info("Hooking BSInputDeviceManager::PollInputDevices"); + _InputFunc = trampoline.write_call<5>(REL::RelocationID(67315, 68617).address() + REL::Relocate(0x7B, 0x7B, 0x81), hk_PollInputDevices); //BSInputDeviceManager::PollInputDevices -> Inputfunc + logger::info("Hooking BSShader::LoadShaders"); *(uintptr_t*)&ptr_BSShader_LoadShaders = Detours::X64::DetourFunction(REL::RelocationID(101339, 108326).address(), (uintptr_t)&hk_BSShader_LoadShaders); logger::info("Hooking BSShader::BeginTechnique"); diff --git a/src/Menu.cpp b/src/Menu.cpp index acaab976e..6bddd79f5 100644 --- a/src/Menu.cpp +++ b/src/Menu.cpp @@ -100,176 +100,6 @@ void Menu::Save(json& o_json) } #define IM_VK_KEYPAD_ENTER (VK_RETURN + 256) -RE::BSEventNotifyControl Menu::ProcessEvent(RE::InputEvent* const* a_event, RE::BSTEventSource* a_eventSource) -{ - if (!a_event || !a_eventSource) - return RE::BSEventNotifyControl::kContinue; - - auto& io = ImGui::GetIO(); - - for (auto event = *a_event; event; event = event->next) { - if (event->eventType == RE::INPUT_EVENT_TYPE::kChar) { - io.AddInputCharacter(event->AsCharEvent()->keycode); - } else if (event->eventType == RE::INPUT_EVENT_TYPE::kButton) { - const auto button = static_cast(event); - if (!button || (button->IsPressed() && !button->IsDown())) - continue; - - auto scan_code = button->GetIDCode(); - uint32_t key = MapVirtualKeyEx(scan_code, MAPVK_VSC_TO_VK_EX, GetKeyboardLayout(0)); - - switch (scan_code) { - case DIK_LEFTARROW: - key = VK_LEFT; - break; - case DIK_RIGHTARROW: - key = VK_RIGHT; - break; - case DIK_UPARROW: - key = VK_UP; - break; - case DIK_DOWNARROW: - key = VK_DOWN; - break; - case DIK_DELETE: - key = VK_DELETE; - break; - case DIK_END: - key = VK_END; - break; - case DIK_HOME: - key = VK_HOME; - break; // pos1 - case DIK_PRIOR: - key = VK_PRIOR; - break; // page up - case DIK_NEXT: - key = VK_NEXT; - break; // page down - case DIK_INSERT: - key = VK_INSERT; - break; - case DIK_NUMPAD0: - key = VK_NUMPAD0; - break; - case DIK_NUMPAD1: - key = VK_NUMPAD1; - break; - case DIK_NUMPAD2: - key = VK_NUMPAD2; - break; - case DIK_NUMPAD3: - key = VK_NUMPAD3; - break; - case DIK_NUMPAD4: - key = VK_NUMPAD4; - break; - case DIK_NUMPAD5: - key = VK_NUMPAD5; - break; - case DIK_NUMPAD6: - key = VK_NUMPAD6; - break; - case DIK_NUMPAD7: - key = VK_NUMPAD7; - break; - case DIK_NUMPAD8: - key = VK_NUMPAD8; - break; - case DIK_NUMPAD9: - key = VK_NUMPAD9; - break; - case DIK_DECIMAL: - key = VK_DECIMAL; - break; - case DIK_NUMPADENTER: - key = IM_VK_KEYPAD_ENTER; - break; - case DIK_LMENU: - key = VK_LMENU; - break; // left alt - case DIK_LCONTROL: - key = VK_LCONTROL; - break; // left control - case DIK_LSHIFT: - key = VK_LSHIFT; - break; // left shift - case DIK_RMENU: - key = VK_RMENU; - break; // right alt - case DIK_RCONTROL: - key = VK_RCONTROL; - break; // right control - case DIK_RSHIFT: - key = VK_RSHIFT; - break; // right shift - case DIK_LWIN: - key = VK_LWIN; - break; // left win - case DIK_RWIN: - key = VK_RWIN; - break; // right win - case DIK_APPS: - key = VK_APPS; - break; - default: - break; - } - - switch (button->device.get()) { - case RE::INPUT_DEVICE::kKeyboard: - if (!button->IsPressed()) { - logger::trace("Detected key code {} ({})", KeyIdToString(key), key); - if (settingToggleKey) { - toggleKey = key; - settingToggleKey = false; - } else if (settingSkipCompilationKey) { - skipCompilationKey = key; - settingSkipCompilationKey = false; - } else if (settingsEffectsToggle) { - effectToggleKey = key; - settingsEffectsToggle = false; - } else if (key == toggleKey) { - IsEnabled = !IsEnabled; - } else if (key == skipCompilationKey) { - auto& shaderCache = SIE::ShaderCache::Instance(); - shaderCache.backgroundCompilation = true; - } else if (key == effectToggleKey) { - auto& shaderCache = SIE::ShaderCache::Instance(); - shaderCache.SetEnabled(!shaderCache.IsEnabled()); - } - } - - io.AddKeyEvent(VirtualKeyToImGuiKey(key), button->IsPressed()); - - if (key == VK_LCONTROL || key == VK_RCONTROL) - io.AddKeyEvent(ImGuiMod_Ctrl, button->IsPressed()); - else if (key == VK_LSHIFT || key == VK_RSHIFT) - io.AddKeyEvent(ImGuiMod_Shift, button->IsPressed()); - else if (key == VK_LMENU || key == VK_RMENU) - io.AddKeyEvent(ImGuiMod_Alt, button->IsPressed()); - break; - case RE::INPUT_DEVICE::kMouse: - logger::trace("Detect mouse scan code {} value {} pressed: {}", scan_code, button->Value(), button->IsPressed()); - if (scan_code > 7) // middle scroll - io.AddMouseWheelEvent(0, button->Value() * (scan_code == 8 ? 1 : -1)); - else { - if (scan_code > 5) - scan_code = 5; - io.AddMouseButtonEvent(scan_code, button->IsPressed()); - } - break; - default: - continue; - } - if (const auto controlMap = RE::ControlMap::GetSingleton()) { - controlMap->GetRuntimeData().ignoreKeyboardMouse = IsEnabled; - } - } - } - - return RE::BSEventNotifyControl::kContinue; -} void Menu::Init(IDXGISwapChain* swapchain, ID3D11Device* device, ID3D11DeviceContext* context) { @@ -454,7 +284,7 @@ void Menu::DrawSettings() ImGui::AlignTextToFramePadding(); ImGui::SameLine(); - if (ImGui::Button("Change##toggle")) { + if (ImGui::Button("Change##EffectToggle")) { settingsEffectsToggle = true; } } @@ -580,6 +410,23 @@ void Menu::DrawSettings() if (ImGui::Button("Dump Ini Settings", { -1, 0 })) { Util::DumpSettingsOptions(); } + if (!shaderCache.blockedKey.empty()) { + auto blockingButtonString = std::format("Stop Blocking {} Shaders", shaderCache.blockedIDs.size()); + if (ImGui::Button(blockingButtonString.c_str(), { -1, 0 })) { + shaderCache.DisableShaderBlocking(); + } + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::Text( + "Stop blocking Community Shaders shader. " + "Blocking is helpful when debugging shader errors in game to determine which shader has issues. " + "Blocking is enabled if in developer mode and pressing PAGEUP and PAGEDOWN. " + "Specific shader will be printed to logfile. "); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } + } if (ImGui::TreeNodeEx("Statistics", ImGuiTreeNodeFlags_DefaultOpen)) { ImGui::Text(std::format("Shader Compiler : {}", shaderCache.GetShaderStatsString()).c_str()); ImGui::TreePop(); @@ -653,6 +500,8 @@ void Menu::DrawSettings() void Menu::DrawOverlay() { + ProcessInputEventQueue(); //Synchronize Inputs to frame + // Start the Dear ImGui frame ImGui_ImplDX11_NewFrame(); ImGui_ImplWin32_NewFrame(); @@ -736,33 +585,6 @@ void Menu::DrawOverlay() ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); } -const char* Menu::KeyIdToString(uint32_t key) -{ - if (key >= 256) - return ""; - - static const char* keyboard_keys_international[256] = { - "", "Left Mouse", "Right Mouse", "Cancel", "Middle Mouse", "X1 Mouse", "X2 Mouse", "", "Backspace", "Tab", "", "", "Clear", "Enter", "", "", - "Shift", "Control", "Alt", "Pause", "Caps Lock", "", "", "", "", "", "", "Escape", "", "", "", "", - "Space", "Page Up", "Page Down", "End", "Home", "Left Arrow", "Up Arrow", "Right Arrow", "Down Arrow", "Select", "", "", "Print Screen", "Insert", "Delete", "Help", - "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "", "", "", "", "", "", - "", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", - "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "Left Windows", "Right Windows", "Apps", "", "Sleep", - "Numpad 0", "Numpad 1", "Numpad 2", "Numpad 3", "Numpad 4", "Numpad 5", "Numpad 6", "Numpad 7", "Numpad 8", "Numpad 9", "Numpad *", "Numpad +", "", "Numpad -", "Numpad Decimal", "Numpad /", - "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", "F16", - "F17", "F18", "F19", "F20", "F21", "F22", "F23", "F24", "", "", "", "", "", "", "", "", - "Num Lock", "Scroll Lock", "", "", "", "", "", "", "", "", "", "", "", "", "", "", - "Left Shift", "Right Shift", "Left Control", "Right Control", "Left Menu", "Right Menu", "Browser Back", "Browser Forward", "Browser Refresh", "Browser Stop", "Browser Search", "Browser Favorites", "Browser Home", "Volume Mute", "Volume Down", "Volume Up", - "Next Track", "Previous Track", "Media Stop", "Media Play/Pause", "Mail", "Media Select", "Launch App 1", "Launch App 2", "", "", "OEM ;", "OEM +", "OEM ,", "OEM -", "OEM .", "OEM /", - "OEM ~", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", "", "", "", "OEM [", "OEM \\", "OEM ]", "OEM '", "OEM 8", - "", "", "OEM <", "", "", "", "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "Attn", "CrSel", "ExSel", "Erase EOF", "Play", "Zoom", "", "PA1", "OEM Clear", "" - }; - - return keyboard_keys_international[key]; -} - const ImGuiKey Menu::VirtualKeyToImGuiKey(WPARAM vkKey) { switch (vkKey) { @@ -977,4 +799,189 @@ const ImGuiKey Menu::VirtualKeyToImGuiKey(WPARAM vkKey) default: return ImGuiKey_None; }; -} \ No newline at end of file +} + +inline const uint32_t Menu::DIKToVK(uint32_t DIK) +{ + switch (DIK) { + case DIK_LEFTARROW: + return VK_LEFT; + case DIK_RIGHTARROW: + return VK_RIGHT; + case DIK_UPARROW: + return VK_UP; + case DIK_DOWNARROW: + return VK_DOWN; + case DIK_DELETE: + return VK_DELETE; + case DIK_END: + return VK_END; + case DIK_HOME: + return VK_HOME; // pos1 + case DIK_PRIOR: + return VK_PRIOR; // page up + case DIK_NEXT: + return VK_NEXT; // page down + case DIK_INSERT: + return VK_INSERT; + case DIK_NUMPAD0: + return VK_NUMPAD0; + case DIK_NUMPAD1: + return VK_NUMPAD1; + case DIK_NUMPAD2: + return VK_NUMPAD2; + case DIK_NUMPAD3: + return VK_NUMPAD3; + case DIK_NUMPAD4: + return VK_NUMPAD4; + case DIK_NUMPAD5: + return VK_NUMPAD5; + case DIK_NUMPAD6: + return VK_NUMPAD6; + case DIK_NUMPAD7: + return VK_NUMPAD7; + case DIK_NUMPAD8: + return VK_NUMPAD8; + case DIK_NUMPAD9: + return VK_NUMPAD9; + case DIK_DECIMAL: + return VK_DECIMAL; + case DIK_NUMPADENTER: + return IM_VK_KEYPAD_ENTER; + case DIK_RMENU: + return VK_RMENU; // right alt + case DIK_RCONTROL: + return VK_RCONTROL; // right control + case DIK_LWIN: + return VK_LWIN; // left win + case DIK_RWIN: + return VK_RWIN; // right win + case DIK_APPS: + return VK_APPS; + default: + return DIK; + } +} + +void Menu::ProcessInputEventQueue() +{ + std::unique_lock mutex(_inputEventMutex); + ImGuiIO& io = ImGui::GetIO(); + + for (auto& event : _keyEventQueue) { + if (event.eventType == RE::INPUT_EVENT_TYPE::kChar) { + io.AddInputCharacter(event.keyCode); + } + + if (event.device == RE::INPUT_DEVICE::kMouse) { + logger::trace("Detect mouse scan code {} value {} pressed: {}", event.keyCode, event.value, event.IsPressed()); + if (event.keyCode > 7) { // middle scroll + io.AddMouseWheelEvent(0, event.value * (event.keyCode == 8 ? 1 : -1)); + } else { + if (event.keyCode > 5) + event.keyCode = 5; + io.AddMouseButtonEvent(event.keyCode, event.IsPressed()); + } + } + + if (event.device == RE::INPUT_DEVICE::kKeyboard) { + uint32_t key = DIKToVK(event.keyCode); + logger::trace("Detected key code {} ({})", event.keyCode, key); + if (key == event.keyCode) + key = MapVirtualKeyEx(event.keyCode, MAPVK_VSC_TO_VK_EX, GetKeyboardLayout(0)); + if (!event.IsPressed()) { + if (settingToggleKey) { + toggleKey = key; + settingToggleKey = false; + } else if (settingSkipCompilationKey) { + skipCompilationKey = key; + settingSkipCompilationKey = false; + } else if (settingsEffectsToggle) { + effectToggleKey = key; + settingsEffectsToggle = false; + } else if (key == toggleKey) { + IsEnabled = !IsEnabled; + } else if (key == skipCompilationKey) { + auto& shaderCache = SIE::ShaderCache::Instance(); + shaderCache.backgroundCompilation = true; + } else if (key == effectToggleKey) { + auto& shaderCache = SIE::ShaderCache::Instance(); + shaderCache.SetEnabled(!shaderCache.IsEnabled()); + } else if (key == priorShaderKey && State::GetSingleton()->IsDeveloperMode()) { + auto& shaderCache = SIE::ShaderCache::Instance(); + shaderCache.IterateShaderBlock(); + } else if (key == nextShaderKey && State::GetSingleton()->IsDeveloperMode()) { + auto& shaderCache = SIE::ShaderCache::Instance(); + shaderCache.IterateShaderBlock(false); + } + } + + io.AddKeyEvent(VirtualKeyToImGuiKey(key), event.IsPressed()); + + if (key == VK_LCONTROL || key == VK_RCONTROL) + io.AddKeyEvent(ImGuiMod_Ctrl, event.IsPressed()); + else if (key == VK_LSHIFT || key == VK_RSHIFT) + io.AddKeyEvent(ImGuiMod_Shift, event.IsPressed()); + else if (key == VK_LMENU || key == VK_RMENU) + io.AddKeyEvent(ImGuiMod_Alt, event.IsPressed()); + } + } + + _keyEventQueue.clear(); +} + +void Menu::addToEventQueue(KeyEvent e) +{ + std::unique_lock mutex(_inputEventMutex); + _keyEventQueue.emplace_back(e); +} + +void Menu::OnFocusLost() //todo implement wndproc hook to catch WM_KILLFOCUS +{ + std::unique_lock mutex(_inputEventMutex); + _keyEventQueue.clear(); +} + +void Menu::ProcessInputEvents(RE::InputEvent* const* a_events) +{ + for (auto it = *a_events; it; it = it->next) { + if (it->GetEventType() != RE::INPUT_EVENT_TYPE::kButton && it->GetEventType() != RE::INPUT_EVENT_TYPE::kChar) // we do not care about non button or char events + continue; + + auto event = it->GetEventType() == RE::INPUT_EVENT_TYPE::kButton ? KeyEvent(static_cast(it)) : it->GetEventType() == RE::INPUT_EVENT_TYPE::kChar ? KeyEvent(static_cast(it)) : + KeyEvent(nullptr); // last ternary operation should never be taken + addToEventQueue(event); + } +} + +bool Menu::ShouldSwallowInput() +{ + return IsEnabled; +} + +const char* Menu::KeyIdToString(uint32_t key) +{ + if (key >= 256) + return ""; + + static const char* keyboard_keys_international[256] = { + "", "Left Mouse", "Right Mouse", "Cancel", "Middle Mouse", "X1 Mouse", "X2 Mouse", "", "Backspace", "Tab", "", "", "Clear", "Enter", "", "", + "Shift", "Control", "Alt", "Pause", "Caps Lock", "", "", "", "", "", "", "Escape", "", "", "", "", + "Space", "Page Up", "Page Down", "End", "Home", "Left Arrow", "Up Arrow", "Right Arrow", "Down Arrow", "Select", "", "", "Print Screen", "Insert", "Delete", "Help", + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "", "", "", "", "", "", + "", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", + "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "Left Windows", "Right Windows", "Apps", "", "Sleep", + "Numpad 0", "Numpad 1", "Numpad 2", "Numpad 3", "Numpad 4", "Numpad 5", "Numpad 6", "Numpad 7", "Numpad 8", "Numpad 9", "Numpad *", "Numpad +", "", "Numpad -", "Numpad Decimal", "Numpad /", + "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", "F16", + "F17", "F18", "F19", "F20", "F21", "F22", "F23", "F24", "", "", "", "", "", "", "", "", + "Num Lock", "Scroll Lock", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "Left Shift", "Right Shift", "Left Control", "Right Control", "Left Menu", "Right Menu", "Browser Back", "Browser Forward", "Browser Refresh", "Browser Stop", "Browser Search", "Browser Favorites", "Browser Home", "Volume Mute", "Volume Down", "Volume Up", + "Next Track", "Previous Track", "Media Stop", "Media Play/Pause", "Mail", "Media Select", "Launch App 1", "Launch App 2", "", "", "OEM ;", "OEM +", "OEM ,", "OEM -", "OEM .", "OEM /", + "OEM ~", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "OEM [", "OEM \\", "OEM ]", "OEM '", "OEM 8", + "", "", "OEM <", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "Attn", "CrSel", "ExSel", "Erase EOF", "Play", "Zoom", "", "PA1", "OEM Clear", "" + }; + + return keyboard_keys_international[key]; +} diff --git a/src/Menu.h b/src/Menu.h index 568aa8d7b..8f0de659f 100644 --- a/src/Menu.h +++ b/src/Menu.h @@ -4,10 +4,11 @@ #include "imgui_impl_dx11.h" #include "imgui_impl_win32.h" #include +#include using namespace std::chrono; -class Menu : public RE::BSTEventSink +class Menu { public: ~Menu(); @@ -21,17 +22,21 @@ class Menu : public RE::BSTEventSink void Load(json& o_json); void Save(json& o_json); - RE::BSEventNotifyControl ProcessEvent(RE::InputEvent* const* a_event, - RE::BSTEventSource* a_eventSource) override; - void Init(IDXGISwapChain* swapchain, ID3D11Device* device, ID3D11DeviceContext* context); void DrawSettings(); void DrawOverlay(); + void ProcessInputEvents(RE::InputEvent* const* a_events); + bool ShouldSwallowInput(); + void OnFocusLost(); + private: uint32_t toggleKey = VK_END; uint32_t effectToggleKey = VK_MULTIPLY; //toggle all effects uint32_t skipCompilationKey = VK_ESCAPE; + uint32_t priorShaderKey = VK_PRIOR; // used for blocking shaders in debugging + uint32_t nextShaderKey = VK_NEXT; // used for blocking shaders in debugging + bool settingToggleKey = false; bool settingSkipCompilationKey = false; bool settingsEffectsToggle = false; @@ -45,4 +50,44 @@ class Menu : public RE::BSTEventSink Menu() {} const char* KeyIdToString(uint32_t key); const ImGuiKey VirtualKeyToImGuiKey(WPARAM vkKey); + + class CharEvent : public RE::InputEvent + { + public: + uint32_t keyCode; // 18 (ascii code) + }; + + struct KeyEvent + { + KeyEvent(const nullptr_t) {} + + KeyEvent(const RE::ButtonEvent* a_event) : + keyCode(a_event->GetIDCode()), + device(a_event->GetDevice()), + eventType(a_event->GetEventType()), + value(a_event->Value()), + heldDownSecs(a_event->HeldDuration()) {} + + KeyEvent(const CharEvent* a_event) : + keyCode(a_event->keyCode), + device(a_event->GetDevice()), + eventType(a_event->GetEventType()) {} + + [[nodiscard]] constexpr bool IsPressed() const noexcept { return value > 0.0F; } + [[nodiscard]] constexpr bool IsRepeating() const noexcept { return heldDownSecs > 0.0F; } + [[nodiscard]] constexpr bool IsDown() const noexcept { return IsPressed() && (heldDownSecs == 0.0F); } + [[nodiscard]] constexpr bool IsHeld() const noexcept { return IsPressed() && IsRepeating(); } + [[nodiscard]] constexpr bool IsUp() const noexcept { return (value == 0.0F) && IsRepeating(); } + + uint32_t keyCode; + RE::INPUT_DEVICE device; + RE::INPUT_EVENT_TYPE eventType; + float value; + float heldDownSecs; + }; + const uint32_t DIKToVK(uint32_t DIK); + mutable std::shared_mutex _inputEventMutex; + std::vector _keyEventQueue{}; + void addToEventQueue(KeyEvent e); + void ProcessInputEventQueue(); }; \ No newline at end of file diff --git a/src/ShaderCache.cpp b/src/ShaderCache.cpp index 5cb9e8be4..2b12cd080 100644 --- a/src/ShaderCache.cpp +++ b/src/ShaderCache.cpp @@ -1202,7 +1202,14 @@ namespace SIE if (!((ShaderCache::IsSupportedShader(shader) || state->IsDeveloperMode() && state->IsShaderEnabled(shader)))) { return nullptr; } - + auto key = SIE::SShaderCache::GetShaderString(ShaderClass::Vertex, shader, descriptor, true); + if (blockedKeyIndex != -1 && !blockedKey.empty() && key == blockedKey) { + if (std::find(blockedIDs.begin(), blockedIDs.end(), descriptor) == blockedIDs.end()) { + blockedIDs.push_back(descriptor); + logger::debug("Skipping blocked shader {:X}:{} total: {}", descriptor, blockedKey, blockedIDs.size()); + } + return nullptr; + } { std::lock_guard lockGuard(vertexShadersMutex); auto& typeCache = vertexShaders[static_cast(shader.shaderType.underlying())]; @@ -1229,7 +1236,14 @@ namespace SIE state->IsShaderEnabled(shader))) { return nullptr; } - + auto key = SIE::SShaderCache::GetShaderString(ShaderClass::Pixel, shader, descriptor, true); + if (blockedKeyIndex != -1 && !blockedKey.empty() && key == blockedKey) { + if (std::find(blockedIDs.begin(), blockedIDs.end(), descriptor) == blockedIDs.end()) { + blockedIDs.push_back(descriptor); + logger::debug("Skipping blocked shader {:X}:{} total: {}", descriptor, blockedKey, blockedIDs.size()); + } + return nullptr; + } { std::lock_guard lockGuard(pixelShadersMutex); auto& typeCache = pixelShaders[static_cast(shader.shaderType.underlying())]; @@ -1507,6 +1521,33 @@ namespace SIE hideError = !hideError; } + void ShaderCache::IterateShaderBlock(bool a_forward) + { + std::scoped_lock lock{ mapMutex }; + auto targetIndex = a_forward ? 0 : shaderMap.size() - 1; // default start or last element + if (blockedKeyIndex >= 0 && shaderMap.size() > blockedKeyIndex) { // grab next element + targetIndex = (blockedKeyIndex + (a_forward ? 1 : -1)) % shaderMap.size(); + } + auto index = 0; + for (auto& [key, value] : shaderMap) { + if (index++ == targetIndex) { + blockedKey = key; + blockedKeyIndex = (uint)targetIndex; + blockedIDs.clear(); + logger::debug("Blocking shader ({}/{}) {}", blockedKeyIndex + 1, shaderMap.size(), blockedKey); + return; + } + } + } + + void ShaderCache::DisableShaderBlocking() + { + blockedKey = ""; + blockedKeyIndex = (uint)-1; + blockedIDs.clear(); + logger::debug("Stopped blocking shaders"); + } + void ShaderCache::ManageCompilationSet(std::stop_token stoken) { SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL); diff --git a/src/ShaderCache.h b/src/ShaderCache.h index fe61ec33f..1719bfee0 100644 --- a/src/ShaderCache.h +++ b/src/ShaderCache.h @@ -8,7 +8,7 @@ #include #include -static constexpr REL::Version SHADER_CACHE_VERSION = { 0, 0, 0, 13 }; +static constexpr REL::Version SHADER_CACHE_VERSION = { 0, 0, 0, 15 }; using namespace std::chrono; @@ -149,6 +149,8 @@ namespace SIE uint64_t GetTotalTasks(); void IncCacheHitTasks(); void ToggleErrorMessages(); + void DisableShaderBlocking(); + void IterateShaderBlock(bool a_forward = true); bool IsHideErrors(); int32_t compilationThreadCount = std::max(static_cast(std::thread::hardware_concurrency()) - 1, 1); @@ -228,6 +230,10 @@ namespace SIE BlendNormals = 1 << 10, }; + uint blockedKeyIndex = (uint)-1; // index in shaderMap; negative value indicates disabled + std::string blockedKey = ""; + std::vector blockedIDs; // more than one descriptor could be blocked based on shader hash + private: ShaderCache(); void ManageCompilationSet(std::stop_token stoken); diff --git a/src/State.cpp b/src/State.cpp index c5454d3ad..fc6517d05 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -188,12 +188,6 @@ void State::Load(bool a_test) logger::info("Found older config for version {}; upgrading to {}", (std::string)settings["Version"], Plugin::VERSION.string()); Save(); } - - upscalerLoaded = GetModuleHandleW(L"Data\\SKSE\\Plugins\\SkyrimUpscaler.dll"); - if (upscalerLoaded) - logger::info("Skyrim Upscaler detected"); - else - logger::info("Skyrim Upscaler not detected"); } void State::Save(bool a_test) @@ -234,6 +228,15 @@ void State::Save(bool a_test) logger::info("Saving settings to {}", userConfigPath); } +void State::PostPostLoad() +{ + upscalerLoaded = GetModuleHandle(L"Data\\SKSE\\Plugins\\SkyrimUpscaler.dll"); + if (upscalerLoaded) + logger::info("Skyrim Upscaler detected"); + else + logger::info("Skyrim Upscaler not detected"); +} + bool State::ValidateCache(CSimpleIniA& a_ini) { bool valid = true; diff --git a/src/State.h b/src/State.h index 356c4da07..dd62eb348 100644 --- a/src/State.h +++ b/src/State.h @@ -34,6 +34,7 @@ class State void Load(bool a_test = false); void Save(bool a_test = false); + void PostPostLoad(); bool ValidateCache(CSimpleIniA& a_ini); void WriteDiskCacheInfo(CSimpleIniA& a_ini); diff --git a/src/XSEPlugin.cpp b/src/XSEPlugin.cpp index fcdc42cd8..072fc56b8 100644 --- a/src/XSEPlugin.cpp +++ b/src/XSEPlugin.cpp @@ -90,6 +90,7 @@ void MessageHandler(SKSE::MessagingInterface::Message* message) } if (errors.empty()) { + State::GetSingleton()->PostPostLoad(); Hooks::Install(); auto& shaderCache = SIE::ShaderCache::Instance(); @@ -113,8 +114,6 @@ void MessageHandler(SKSE::MessagingInterface::Message* message) } if (errors.empty()) { - RE::BSInputDeviceManager::GetSingleton()->AddEventSink(Menu::GetSingleton()); - auto& shaderCache = SIE::ShaderCache::Instance(); shaderCache.menuLoaded = true; while (shaderCache.IsCompiling() && !shaderCache.backgroundCompilation) { diff --git a/vcpkg.json b/vcpkg.json index fd89635f8..27fcc8a5f 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,10 +1,11 @@ { - "name": "commonlibsse-plugin", - "version-string": "1.0.0", + "name": "communityshaders", + "version-semver": "0.7.4", "description": "", - "license": "MIT", + "license": "GPL-3.0", "dependencies": [ "bshoshany-thread-pool", + "cppwinrt", "fmt", "directxtk", "rapidcsv", @@ -17,15 +18,11 @@ "pystring", { "name": "imgui", - "features": [ - "dx11-binding", - "win32-binding", - "docking-experimental" - ], + "features": ["dx11-binding", "win32-binding", "docking-experimental"], "version>=": "1.88" }, "eastl", "clib-util" ], - "builtin-baseline": "417119555f155f6044dec7a379cd25466e339873" -} \ No newline at end of file + "builtin-baseline": "e6aabd1415a1fc9f5e76deb3c5a40e27300aef2a" +}